在vb.net中调用winAPI函数

时间:2016-06-03 13:51:27

标签: c vb.net winapi

我必须"翻译" /更新大约20年前用C语言编写的程序到VB.net,因为它的旧SQL连接风格不再兼容。但是,我对C的经验很少,甚至更少使用winAPI(C应用程序使用)...我想知道,可以在VB.net中使用API​​中的相同函数吗?

我已经能够添加这样的声明:

   <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
    Public Shared Function SetWindowText(hWnd As IntPtr, lpString As String) As Boolean
    End Function

获取一个窗口句柄作为IntPtr(在vb.net中)。但是,C程序使用如下函数:

 BOOL NEAR GoModal( HINSTANCE hInstance, LPCSTR lpszTemplate,HWND hWnd, DLGPROC lpDlgProc, LPARAM lParam )

通过导入user32.dll,我无法获得hWnd句柄,但我可以获得IntPtr(如果我理解的话,是指向窗口作为整数对吗?有点类似于hWnd - &gt;我可能完全错了,但这就是我所理解的)

当我进入每种类型的定义(即:NEAR,HINSTANCE,LPCSTR等等)时,我试图在VB中找到一个等效的调用,但......它没用。例如,我正在看NEAR,我想这是决定两个指针在内存中是否接近? (再次可能是错的,这就是我收集的内容)。

最终,我的问题是,vb.net中存在这样的调用/甚至对更现代的框架有用吗?

1 个答案:

答案 0 :(得分:2)

让我们分解函数调用中的参数:

(&(objectClass=user)(!(UserAccountControl:1.2.840.113556.1.4.803:=2)))
  • BOOL NEAR GoModal(HINSTANCE hInstance, LPCSTR lpszTemplate, HWND hWnd, DLGPROC lpDlgProc, LPARAM lParam ) 是32位整数。您可以在代码中使用BOOL类型,但需要应用System.Boolean类型,将类型指定为MarshalAsAttribute
  • UnmanagedType.Bool指定编译器的信息。转换为.net时,您可以忽略它。
  • NEARHINSTANCEHandle。转换为.net,句柄通常定义为Instance值。这并不意味着它是指向内存的指针。 (ie- IntPtr不能使用。)
  • Marshal.ReadLPCSTR LongPointer样式C。这是一个STR字符串,因此这意味着该参数需要ANSIMarshalAsAttribute。如果这是一个out参数,事情会更复杂,你需要传递UnmanagedType.LPStr或使用StringBuilder / Marshal.AllocHGlobal来分配非托管内存。
  • Marshal.AllocCoTaskMemHWNDHandle。与Window一样,它通常被编组为HINSTANCE
  • IntPtr有点复杂,所以我将在下面解决。
  • DLGPROCLPARAM Long。 Microsoft在创建Parameter类时用于此类型的标准实现是Message。你应该效仿。

正如我上面所说IntPtr更复杂。它实际上是函数的指针(引用)。特别是签名:

DLGPROC

我们已经看过INT_PTR CALLBACK DialogProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ); HWND,所以让我们快速浏览一下此签名中的其他内容。

  • LPARAMINT_PTR Integer。如果这听起来很熟悉,那应该是。这只是一个Pointer
  • IntPtr是编译器用来确定如何编译函数的另一部分信息,以及人们如何使用它将其参数发送给函数。默认情况下,.net marshal处理此问题,因此无需其他配置。
  • CALLBACK代表WPARAM Word。在这种情况下,它是旧术语,您将需要使用Param来接收值。

要编组指向IntPtr的指针,您需要创建一个具有相应签名的委托:

DLGPROC

然后,您需要在代码中的某个位置创建一个具有相同签名的函数,以接收来自本机代码的调用。类似的东西:

Delegate Function DLGPROC(ByVal hWnd As IntPtr, 
                          ByVal uMsg As UInt32, 
                          ByVal wParam As IntPtr, 
                          ByVal lParam As IntPtr) As IntPtr

然后,您可以添加一个类成员来保存该委托:

Private Function MyDialogProc(ByVal hWnd As IntPtr, 
                              ByVal uMsg As UInt32, 
                              ByVal wParam As IntPtr, 
                              ByVal lParam As IntPtr) As IntPtr
    Return IntPtr.Zero ' Put the appropriate code here.
End Function

在完成所有这些之后,您终于可以导入Private DialogProc As DLGPROC = New DLGPROC(AddressOf Me.MyDialogProc) 函数原型了。 (是的!)看起来像:

GoModal

我们现在可以从我们的代码中调用该函数:

<DllImport("DLL_NAME")>
Private Shared Function GoModal(ByVal hInstance As IntPtr,
                                <MarshalAs(UnmanagedType.LPStr)> ByVal lpszTemplate As String,
                                ByVal hWnd As IntPtr,
                                ByVal lpDlgProc As IntPtr, ' More on this below
                                ByVal lParam As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function

关于函数调用的两个注释:

  • Dim dialogProcedure As IntPtr = Marshal.GetFunctionPointerForDelegate(Me.DialogProc) Dim result As Boolean = GoModal(IntPtr.Zero, "Template", Me.Handle, dialogProcedure, New IntPtr(100)) IntPtr.Zero
  • 相同
  • NULL创建具有指定值的New IntPtr(100)。 (有时候IntPtr只是一个数字)

如果你做到这一点,恭喜!代码中可能存在一些错误,但这应该可以帮到你。对于其他Windows API类型,您可以在pinvoke.net找到大量信息。

如果你有很多互操作,那么只需在你的项目中添加一个C ++ / CLI dll并在本地调用这些函数就会更容易。它更容易,您可以根据自己的需要定义功能。此外,C ++ / CLI可与任何的.net语言一起使用。