Post

Tips, Tricks and Code Snippets

Below are a few tips and tricks that I’ve either created or come across that I’ve used or have just found interesting enough to store someplace for possible use later. It’s formatted in a FAQ format.

How do I determine the executing assemblies path?

If your wanting to do this with a Windows Forms application, just use:

1
Dim path As String = System.IO.Path.GetDirectoryName(Application.ExecutablePath)

Otherwise, you can use:

1
Dim path As String = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly.Location)

How do I get a list of installed printers?

Use the System.Drawing.Printing.PrinterSettings.InstalledPrinters collection.

How do I translate a Win32 error number into a human readable text message?

You have two ways (using VB.NET) to get a numeric Win32 error message. One is to use the System.Runtime.InteropServices.Marshal.GetLastWin32Error method, while the other is to use the VB.NET specific Err.LastDllError method. Now that you have the numeric representation of the Win32 error, we want to turn it into a text representation, you know, the error message in English.

There’s couple of ways to accomplish this. First, we’ll explore the Win32 P/Invoke way first. Using this method is the way that the SDK documentation is pointing out. What I’ve done is wrapped the FormatMessage API call with a VB.NET friendly wrapped version.

1
2
3
4
5
6
7
8
9
10
Private Declare Function FormatMessageA Lib "kernel32" (ByVal flags As Integer, ByRef source As Object, ByVal messageID As Integer, ByVal languageID As Integer, ByVal buffer As String, ByVal size As Integer, ByRef arguments As Integer) As Integer

Public Shared Function FormatMessage(ByVal [error] As Integer) As String
  Const FORMAT_MESSAGE_FROM_SYSTEM As Short = &H1000
  Const LANG_NEUTRAL As Short = &H0
  Dim buffer As String = Space(999)
  FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, 0, [error], LANG_NEUTRAL, buffer, 999, 0)
  buffer = Replace(Replace(buffer, Chr(13), ""), Chr(10), "")
  Return buffer.Substring(0, buffer.IndexOf(Chr(0)))
End Function 

You can then use this method as follows:

1
Throw New Exception(Marshal.GetLastWin32Error)

A more friendly .NET Framework method is to use the Win32Exception class. Normally when you want to know what the human readable version of the numeric value is, you will probably throw this so the user of your application can see the error. At the very least, so you can easily figure out what is the problem.

1
2
3
4
Imports System.ComponentModel
Imports System.Runtime.InteropServices

Throw New Win32Exception(Marshal.GetLastWin32Error)

How do I change the color of the text on a tab of the TabControl?

You’ll have to set the TabControls DrawMode property to OwnerDrawFixed and draw the text in the TabControls DrawItem procedure.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Private Sub TabControl1_DrawItem(ByVal sender As Object, ByVal e As System.Windows.Forms.DrawItemEventArgs) _
  Handles TabControl1.DrawItem

  Dim r As RectangleF = RectangleF.op_Implicit(e.Bounds)
  Dim ItemBrush As New SolidBrush(TabControl1.BackColor)

  Dim sf As New StringFormat
  sf.Alignment = StringAlignment.Center
  sf.LineAlignment = StringAlignment.Center

  If CBool(e.State And DrawItemState.Selected) Then
    e.Graphics.FillRectangle(ItemBrush, e.Bounds)
    e.Graphics.DrawString(TabControl1.TabPages(e.Index).Text, e.Font, Brushes.Red, r, sf)
  Else
    e.Graphics.DrawString(TabControl1.TabPages(e.Index).Text, e.Font, Brushes.Blue, r, sf)
  End If

End Sub

How can I determine the date for next Friday?

1
2
3
4
5
6
7
8
9
10
Public Function GetNextFriday(ByVal startDate As Date) As Date
  If startDate.DayOfWeek < DayOfWeek.Friday Then
    ' If todays day of week is less than Friday.
    ' Add the number of days till next Friday.
    Return startDate.AddDays(DayOfWeek.Friday - startDate.DayOfWeek)
  Else
    ' Otherwise, subtract the difference from 7.
    Return startDate.AddDays(7 - (startDate.DayOfWeek - DayOfWeek.Friday))
  End If
End Function

How can I ‘export’ functions from a .NET DLL to non-.NET applications?

Well, the official answer is to use COM in order to export your classes to .NET applications. But what do you do when these other applications are unable to use COM? Well, you can then possibly use a wrapper DLL written in Managed C++ to accomplish the task. But wait, there appears to be yet one more way… hack the resulting IL code of your DLL to export directly as a native Win32 type ‘export’. Export Managed Code as Unmanaged article discusses all the gory details.

How do I catch errors in ‘release’ builds, but not while debugging?

Here’s the scenario. You want to setup a global error handler (which you should) for your application. This is a good thing. However, it causes a pain when trying to develop within the debugger since now every time an error occurs, your global error handler will capture the error. Here’s a solution:

Often times, applications will have a global exception handler in the Main method that catches any exceptions that weren’t handled elsewhere. The compiler itself uses a strategy similar to this for out of memory situations – once we’ve run out of memory, the compiler’s toast, so we throw an exception indicating “out of memory” and then catch it at the top level, giving a nice “out of memory, please restart the compiler” error. (Hopefully none of you have ever seen it.) Anyway, when you’re debugging the application it can be convenient to not catch exceptions at the top level so that you immediately break into the debugger when you get a global exception. A simple way to do this is to use When to not catch the exception when a debugger is present:

1
2
3
4
5
6
7
Sub Main()
  Try
    RunApplication()
  Catch ex As Exception When Not System.Diagnostics.Debugger.IsAttached
    HandleGlobalException(ex)
  End Try
End Sub

Source: Paul Vick

How do I determine if an assembly was built for debug or release?

If you want to determine if your assembly was built using debug or release, you would think you could use the FileVersionInfo.IsDebug or IsRelease; however, the compiler doesn’t apparently set the proper bit as you would expect. Since that doesn’t work, you could use the DebuggableAttribute on the assembly by using the following code.

1
2
3
Dim assm As Reflection.Assembly = Reflection.Assembly.LoadFrom(Application.ExecutablePath)
Dim found As Boolean = assm.GetCustomAttributes(GetType(DebuggableAttribute), False).Length > 0
Me.Text = "Assembly is " & IIf(found, "debug", "release")

Source: Thanks to Jeff Key for posting this tip to his blog (you can view his post for the C# code).

How do I build a sockets (network) terminal client?

Haven’t had a chance to go through this video walk through, but I’m sure it’s excellent since it’s done by Carl Franklin. As soon as I get a chance to check it out, I’ll update this information. You can check it out here.

Holy crap!!! My application is taking up too much memory and it’s just a default form? What is going on here?

Well, this is actually normal with an application utilizing the .NET Framework. Many things are happening when you launch your application such as code access security, JIT compilation, memory management and the referencing of the actual .NET Framework library(ies). However, if you are really concerned with the amount of memory your application is reporting you can try the following to give your application and Windows a kick in the rear to more accurately report the current memory usage of your application. This tip is purely for cosmetic purposes, to help calm those irritating phone calls asking why your application uses more memory than Microsoft Word does… and it’s just a Hello World application. There is no performance gain of any kind from using this tip. See warnings below for additional information.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Public Class MemoryManagement
 
  Private Declare Function SetProcessWorkingSetSize Lib "kernel32.dll" ( _
    ByVal process As IntPtr, _
    ByVal minimumWorkingSetSize As Integer, _
    ByVal maximumWorkingSetSize As Integer) As Integer

  Public Shared Sub FlushMemory()
    GC.Collect()
    GC.WaitForPendingFinalizers()
    If (Environment.OSVersion.Platform = PlatformID.Win32NT) Then
      SetProcessWorkingSetSize(Process.GetCurrentProcess().Handle, -1, -1)
    End If
  End Sub

End Class

This will force a garbage collection to occur and if running on Windows NT, 2000, XP, or 2003, will (according to the SDK documentation):

The working set of a process is the set of memory pages currently visible to the process in physical RAM memory. These pages are resident and available for an application to use without triggering a page fault. The minimum and maximum working set sizes affect the virtual memory paging behavior of a process.

The working set of the specified process can be emptied by specifying the value -1 for both the minimum and maximum working set sizes.

Using a simple windows application, adding a command button, within the click event call upon the FlushMemory method, you will see the application go from using nearly 15meg of memory usage and a VM size of over 7meg to around 1meg (or less) of memory while the VM size stays pretty constant.

Warning: This nice little method doesn’t come without a cost. Don’t call upon this method during critical sections of your code. Forcing a garbage collection can be very time consuming. Also, don’t try to set the minimum and maximum sizes; let .NET’s memory management do it’s job.

A couple of more references (or more accurately oppinions) for you to read if you intend on using GC.Collect: Chris Brumme - ReleaseComObject and Rico Mariani - Two things to avoid for better memory usage.

How do I load an image from a file using a file stream?

1
2
3
4
5
6
7
8
Protected Shared Function GetImageFromFile(ByVal FileName As String) As Byte()
    Dim myFile As String = FileName
    Dim fs As FileStream = New FileStream(myFile, FileMode.Open, FileAccess.Read)
    Dim br As BinaryReader = New BinaryReader(fs)
    Dim bytesize As Long = fs.Length
    ReDim GetImageFromFile(bytesize)
    GetImageFromFile = br.ReadBytes(bytesize)
End Function

To use the above function:

1
2
Dim img As New Bitmap(New IO.MemoryStream(GetImageFromURL("c:\file.jpg")))
Me.BackgroundImage = img

Source: Duncan MacKenzie

How do I load an image from a URI address?

1
2
3
4
5
6
7
8
9
10
Function GetImageFromURL(ByVal url As String) As Byte()
    Dim wr As HttpWebRequest = _
       DirectCast(WebRequest.Create(url), HttpWebRequest)
    Dim wresponse As HttpWebResponse = _
       DirectCast(wr.GetResponse, HttpWebResponse)
    Dim responseStream As Stream = wresponse.GetResponseStream
    Dim br As BinaryReader = New BinaryReader(responseStream)
    Dim bytesize As Long = wresponse.ContentLength
    Return br.ReadBytes(bytesize)
End Function

To use the above function:

1
2
Dim img As New Bitmap(New IO.MemoryStream(GetImageFromURL("http://msdn.microsoft.com/longhorn/art/codenameLonghorn.JPG")))
Me.BackgroundImage = img

Source: Duncan MacKenzie

How do I use animated cursors in .NET?

Check out the Using Colored and Animated Cursors article by Dr. GUI.

How do I create a Windows Service?

MSDN has an excellent article (Walkthrough: Creating a Windows Application in the Component Designer) that shows how to create a Windows Service from start to finish. I would also recommend reading the Install a Windows Service the way you want to article available on CodeProject.com that shows how to do a few of the features that seem to have been left out; such as adding a service description and modifying the All service to interact with the desktop option.

How do I generate a GUID (Globally Unique IDentifier)?

You can use the System.Guid class.

1
Dim guid As String = System.Guid.NewGuid.ToString

You can also control how the GUID is formatted. For example, if you use ToString("N"), the dashes (“-“) will be removed.

Have any other ideas? Leave a comment.

This post is licensed under CC BY 4.0 by the author.