DllImport vs Declare in VB.NET

Mike picture Mike · Jun 2, 2009 · Viewed 26.6k times · Source

I notice in the MSDN documentation that there are multiple ways to declare a reference to a function in an external DLL from within a VB.NET program.

The confusing thing is that MSDN claims that you can only use the DllImportAttribute class with Shared Function prototypes "in rare cases", but I couldn't find the explanation for this statement, while you can simply use the Declare keyword instead.

Why are these different, and where would I appropriately use each case?

Answer

leanne picture leanne · Jan 9, 2012

Apparently the Declare and DllImport statements are basically the same. You can use whichever you prefer.

Following is a discussion of the few points that may work a little differently in each, which may influence a preference for one over the other:

I started with an article from MSDN regarding Visual Studio 2003 titled Using the DllImport Attribute. (A bit old, but since the DllImport statement seems to have originated in .NET, it seemed appropriate to go back to the beginning.)

Given an example DllImport statement of:

[DllImport("user32.dll", EntryPoint = "MessageBox", CharSet = Unicode)]
int MessageBox(void* hWnd, wchar_t* lpText, wchar_t* lpCaption, unsigned int uType);

It says that if the EntryPoint value is left out, the CLR will look for the name of the function (MessageBox, in this case) as a default. However, in this instance, since a CharSet of Unicode was specified, the CLR would FIRST look for a function called "MessageBoxW" - the 'W' indicating a Unicode return type. (The ANSI return type version would be "MessageBoxA".) If no "MessageBoxW" were found, THEN the CLR would look for an API function actually called "MessageBox".

Current specifics about the DllImportAttribute class can be found here, where I viewed the .NET Framework 4 version: DLLImportAttribute Class

A key comment in the Remarks section of this .NET Framework 4 page is that:

You apply this attribute directly to C# and C++ method definitions; however, the Visual Basic compiler emits this attribute when you use the Declare statement.

So, at least as pertains to VB.NET, the compiler ends up with a Declare statement anyway.

There is also an important note in this page:

The DllImportAttribute does not support marshaling of generic types.

So, it would appear that if you want to use a generic type, you'd have to use a Declare statement.

Next, I headed to the Declare statement information. A Visual Studio 2010 version (Visual Basic statement info) was here: Declare Statement

A key item here was this note:

You can use Declare only at module level. This means the declaration context for an external reference must be a class, structure, or module, and cannot be a source file, namespace, interface, procedure, or block.

Apparently, if you want to set up an API call outside of a class, structure, or module, you'll have to use the DllImport statement instead of the Declare.

The example Declare statement on this page is:

Declare Function getUserName Lib "advapi32.dll" Alias "GetUserNameA" (
  ByVal lpBuffer As String, ByRef nSize As Integer) As Integer

Following that example is this little tidbit of information:

The DllImportAttribute provides an alternative way of using functions in unmanaged code. The following example declares an imported function without using a Declare statement.

followed by, of course, an example of DllImport usage.

Regarding Unicode vs ANSI results, according to this Declare page, if you specify a CharSet value (available in Declare, but not shown in the example above) the CLR will do the same type of automatic name search that DllImport does - for either Unicode or ANSI.

If you do not specify a CharSet value in the Declare statement, then you must make sure that your function name in the Declare is the same as the function name in the actual API function's header file, OR you must specifiy an Alias value that matches the actual function name in the header file (as shown in the example above).

I was not able to find any specific Microsoft documentation stating that either DllImport or Declare were preferred, or even recommended, over one another in any situation other than those noted above.

My conclusion, therefore, is:

1) Unless you need to place your definition in one of the places a Declare statement cannot be used, either technique will work fine,

and

2) if you're using DllImport, make sure you specify the CharSet value you want (Unicode or ANSI), or you may get unexpected results.