Login | Register   
LinkedIn
Google+
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Dealing with DllImport (Part 1 of 2)  : Page 3

Although the .NET framework encapsulates a large portion of the Win32 API, it's sometimes still necessary to call the API from your managed code using the DllImport attributeand that can get complicated.


advertisement
So how would you do the same thing in Visual Basic .NET? The syntax is a little different, but the general idea is the same:

The old VB 6 Declare facility still exists, but it now maps to the new DllImport attribute.

Imports System.Runtime.InteropServices Imports System.Text Module Module1 <DllImport("advapi32.dll")> _ Public Function GetUserName( _ ByVal lpBuffer As StringBuilder, _ ByRef nSize As Integer) As Boolean End Function Sub Main() Dim b As StringBuilder = New StringBuilder(100) Dim n As Integer = b.Capacity Dim rc As Boolean = GetUserName(b, n) Console.WriteLine(b) End Sub End Module

As you can see, the square brackets for the DLLImport attribute in C# have become angle brackets in Visual Basic .NET, and the static extern declaration of the function in C# has gone away. Of course, the ref modifier in C# becomes ByRef in Visual Basic .NET, and bool becomes Boolean. The semicolons between statements are gone in Visual Basic .NET, at the expense of needing underscores for line continuations, and the curly brackets to delimit blocks have been replaced by explicit End statements.

The old VB 6 Declare facility still exists, but it now maps to the new DllImport attribute. For example, you could declare the ANSI form of GetUserName as:

Declare Ansi Function GetUserNameA Lib _ "advapi32.dll" (ByVal lpBuffer As _ StringBuilder, ByRef nSize As Integer) _ As Boolean

The existence of the Declare statement isn't as useful as you might think. The parameter passing mechanism has changed from VB 6 to Visual Basic .NET: parameters formerly defaulted to ByRef, but they now default to ByVal. Also, some of the types have changed. So, you can't blindly use the VB 6 API viewer. For example, the declaration you'll find for GetUserName in the VB 6 API viewer is:



Declare Function GetUserName _ Lib "advapi32.dll" Alias "GetUserNameA" _ (ByVal lpBuffer As String, nSize As Long) As Long

That won't work, principally for the same reasons that my original effort in C# didn't work: the first argument must be a StringBuilder, and the second argument needs to be changed to a reference.

How P/Invoke Works
P/Invoke, as you've already seen, relies on the DllImport attribute from the System.Runtime.InteropServices namespace. The DllImport attribute specifies that the target method is an export from an unmanaged shared library such as the Win32 API. In the simple case you've seen here, all you need to do is declare the name of the DLL from which you're importing the call and the parameters of the call itself.

The compiler emits the DllImport information directly into the MSIL (Microsoft Intermediate Language) executable file format. The runtime recognizes this information and uses the Marshal class of the System. Runtime.InteropServices namespace to get the parameter and return data across the boundary between managed and unmanaged code. The runtime is actually quite clever about doing the right thing when marshaling the data back and forth between managed and unmanaged types. It copies data when it needs to, pins managed data reference types in memory so that they can be used by unmanaged code, and when needed, converts strings from ANSI to Unicode or vice-versa.

Sometimes, merely declaring a DLL name and function prototype does not suffice to describe the necessary behavior for marshalling. For such cases, the DllImport attribute has additional fields to specify the imported function's calling convention and character set, among others. You can also use the MarshalAs attribute to control how specific parameters are passed, and the StructLayout attribute to define structures for marshaling. I'll discuss those in Part 2 of this article series.

What happens, though, if the API you're calling does something really weird?



Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap