我必须"翻译" /更新大约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中存在这样的调用/甚至对更现代的框架有用吗?
答案 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时,您可以忽略它。NEAR
是HINSTANCE
到Handle
。转换为.net,句柄通常定义为Instance
值。这并不意味着它是指向内存的指针。 (ie- IntPtr
不能使用。)Marshal.Read
是LPCSTR
Long
到Pointer
样式C
。这是一个STR
字符串,因此这意味着该参数需要ANSI
和MarshalAsAttribute
。如果这是一个out参数,事情会更复杂,你需要传递UnmanagedType.LPStr
或使用StringBuilder
/ Marshal.AllocHGlobal
来分配非托管内存。Marshal.AllocCoTaskMem
是HWND
到Handle
。与Window
一样,它通常被编组为HINSTANCE
IntPtr
有点复杂,所以我将在下面解决。DLGPROC
是LPARAM
Long
。 Microsoft在创建Parameter
类时用于此类型的标准实现是Message
。你应该效仿。正如我上面所说IntPtr
更复杂。它实际上是函数的指针(引用)。特别是签名:
DLGPROC
我们已经看过INT_PTR CALLBACK DialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
和HWND
,所以让我们快速浏览一下此签名中的其他内容。
LPARAM
是INT_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语言一起使用。