Using Platform Invoke

   


Access unmanaged code from a Windows service, a serviced component, a .NET Remoting object, and an XML Web service.

So far in this chapter, you've seen interoperability between managed code and unmanaged code by way of method calls to classes in COM libraries. There's a second way that the .NET Framework can interoperate with unmanaged code, though: through functional calls to unmanaged libraries. The platform invoke (often abbreviated as PInvoke) feature of .NET enables .NET code to call functions from unmanaged libraries such as the Windows API.

To call unmanaged functions from your .NET code, you need to provide the declarations of the function in your .NET code. There are two ways to do this. First, you can use a Declare statement, just as you could in previous versions of Visual Basic:

 Declare Auto Function GetComputerName Lib "kernel32" (_  ByVal lpBuffer As String, _  ByRef nSize As Integer) As Integer 

The Declare statement specifies that a particular function is contained in the named library. You must declare the parameters and return type of the function to be compatable with those in the library. But Declare doesn't offer you much control over the way that .NET handles an API call. For finer-grained control, you'll want to use the DllImport attribute instead.

Along with declaring the method, you can also apply a DllImport attribute of the System.Runtime.InteropServices namespace to the methods . The DllImport attribute tells the CLR where to find the implementation of the method by specifying the name of the unmanaged library. After the method is declared, you can use it in Visual Basic .NET just as you use any other method. Functions imported using DllImport must always be declared as Shared . In addition to the name of the library, the DllImport attribute also accepts other parameters (see Table 8.2).

Table 8.2. Parameters for the DllImport Attribute

Parameter

Description

CallingConvention

Defines the calling convention to use. The values are specified by the CallingConvention enumeration Cdecl , FastCall , StdCall (default value), ThisCall , and Winapi .

CharSet

Specifies the character set to use. By default it uses CharSet.Ansi . The other possible values are CharSet.Auto , CharSet.Unicode , and CharSet.None (which is obsolete and behaves as CharSet.Ansi ).

EntryPoint

Represents the name of the entry point in the DLL. If EntryPoint field is not specified, the name of the method is used as the entry point. If EntryPoint field is passed, you can provide a custom name for the method.

ExactSpelling

Specifies whether the name of the entry point should exactly match the name of the function in the unmanaged DLL. By default the value is false .

PreserveSig

Indicates whether the method signature should be preserved or can be changed. By default the value is true .

SetLastError

whether the last error of the Win32 function should be preserved. By default the value is false .

Step by Step 8.4 shows how to call GetComputerName function from kernel32.dll library by using DllImport attribute.

STEP BY STEP

8.4 Using Platform Invoke with the Windows API

  1. Add a new Web service named StepByStep8-4.asmx to your Visual Basic .NET application.

  2. Switch to the code view. Enter the following Imports directives:

     Imports System.Text Imports System.Runtime.InteropServices 
  3. Add the following lines of code in the class definition, which indicates that the GetComputerName method is implemented in kernel32.dll :

     <DllImport("kernel32.dll", CharSet:=CharSet.Auto)> _ Public Shared Function GetComputerName(_    ByVal lpBuffer As StringBuilder, _    ByRef nSize As Integer) As Integer End Function 
  4. Add the following Web method definition in the StepByStep8_4.asmx file:

     <WebMethod()> _ Public Function WebServerName() As String     Dim sbBuf As StringBuilder = New StringBuilder(128)     Dim intLen As Integer = sbBuf.Capacity     Dim intRet As Integer = 0     ' Call the Win API method     intRet = GetComputerName(sbBuf, intLen)     WebServerName = sbBuf.ToString() End Function 
  5. Set the Web service as the start page for the project.

  6. Run the project. You should see that a browser is launched showing the test page. Click on the WebServerName method link and click the Invoke button in the method test page. The code displays the name of the Web server where the Web service is run, as shown in Figure 8.3.

    Figure 8.3. The PInvoke feature of .NET enables .NET code to call functions from the Windows API.

EXAM TIP

StringBuilder Necessary In Visual Basic .NET, you should use StringBuilder object for a Windows API call that expects a string buffer to be modified by the function.


In Step by Step 8.4, note the use of the CharSet.Auto parameter in the DllImport attribute of the GetComputerName() method declaration.

You might know that many Windows API calls come in two versions, depending on the character set that you're using. For example, GetComputerName really exists as GetComputerNameA (for ANSI characters ) and GetComputerNameW (for Unicode characters). The Auto modifier instructs the .NET Framework to use the appropriate version of the API call for the platform where the code is running.

Platform invoke can also handle API calls that require structures as parameters. For example, a call to the GetSystemTime API fills in a structure that consists of eight members that together indicate the system time. Step by Step 8.5 shows how to represent this structure in .NET code and how to pass the structure to the GetSystemTime method in order to fill it with the Web server's time.

STEP BY STEP

8.5 Using Platform Invoke with a Structure Parameter

  1. Add a new Web service named StepByStep8-5.asmx to your Visual Basic .NET application.

  2. Switch to the code view. Enter the following Imports directive:

     Imports System.Runtime.InteropServices 
  3. Add the following lines of code in the class definition:

     <StructLayout(LayoutKind.Sequential)> _ Public Class SystemTime     Public year As Short     Public month As Short     Public dayOfWeek As Short     Public day As Short     Public hour As Short     Public minute As Short     Public second As Short     Public miliseconds As Short End Class <DllImport("Kernel32.dll")> _  Public Shared Sub GetSystemTime(_  ByVal time As SystemTime) End Sub 
  4. Add the following Web method definition to the Web service:

     <WebMethod()> _ Public Function WebServerTime() As SystemTime     Dim t As New SystemTime()     ' call the Win32 API method     GetSystemTime(t)     WebServerTime = t End Function 
  5. Set the Web service as the start page for the project.

  6. Run the project. You should see that a browser is launched showing the test page. Click on the WebServerTime method link and click the Invoke button in the method test page. The method returns the time of the Web server in a structure as defined by the Web service, as shown in Figure 8.4.

    Figure 8.4. Platform invoke can also handle API calls that require structures as parameters.

The tricky part of the code in Step by Step 8.5 lies in the declaration of the structure. In this case, the StructLayout attribute tells the Visual Basic .NET compiler that the location of the individual fields is sequential within the class. By using the StructLayout attribute, you can ensure that the .NET Framework constructs the same structure that the API function is expecting to receive.

Many API calls require a Rect structure, which consists of four members that are filled in with the coordinates of a rectangle.

In Visual Basic .NET, you can declare a structure with explicit byte offsets for each member, which lets you define any structure that the Windows API requires:

 <StructLayout(LayoutKind.Explicit)> _ Public Structure Rect     <FieldOffset(0)> Public left As Integer     <FieldOffset(4)> Public top As Integer     <FieldOffset(8)> Public right As Integer     <FieldOffset(12)> Public bottom As Integer End Structure 

In this case, the StructLayout attribute tells the Visual Basic .NET compiler that you'll explicitly specify the location of the individual fields within the structure. The FieldOffset attribute specifies the starting byte of each field within the structure.

REVIEW BREAK

  • You can use the .NET Framework platform invoke facility to call functions from Windows libraries, including the Windows API.

  • You should use StringBuilder object for a Windows API call that expects a string buffer to be modified by the function.


   
Top


MCAD. MCSD Training Guide (Exam 70-310. Developing XML Web Services and Server Components with Visual Basic. NET and the. NET Framework)
MCAD/MCSD Training Guide (70-310): Developing XML Web Services and Server Components with Visual Basic(R) .NET and the .NET Framework
ISBN: 0789728206
EAN: 2147483647
Year: 2002
Pages: 166

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net