关闭。这个问题需要更多 focused .它目前不接受答案。
想改进这个问题?更新问题,使其仅关注一个问题 editing this post .
5年前关闭。
Improve this question
我必须将大约 20 年前用 C 编写的程序“翻译”/更新到 VB.net,因为它的旧 SQL 连接样式不再兼容。但是,我对 C 的经验很少,对 winAPI(C 应用程序使用)的经验更少……我想知道,API 中的相同功能可以在 VB.net 中使用吗?
我已经能够添加这样的声明:
<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 --> 我可能完全错了,但这是我的理解)
当我转到每种类型的定义时(即:NEAR、HINSTANCE、LPCSTR 等),我尝试在 VB 中找到一个等效的调用,但是……它没用。例如,我正在查看 NEAR ,我想这是为了确定两个指针在内存中是否接近? (再次可能是错误的,这正是我收集的)。
最终,我的问题是,在 vb.net 中是否存在这样的调用/甚至对更现代的框架等有用吗?
最佳答案
让我们分解函数调用中的参数:
BOOL NEAR GoModal(HINSTANCE hInstance,
LPCSTR lpszTemplate,
HWND hWnd,
DLGPROC lpDlgProc,
LPARAM lParam )
BOOL
是一个 32 位整数。您可以使用 System.Boolean
输入您的代码,但它需要 MarshalAsAttribute
应用于它,指定类型为 UnmanagedType.Bool
NEAR
向编译器指定信息。翻译成 .net 时,可以忽略它。 HINSTANCE
是 Handle
到 Instance
.翻译成 .net,句柄通常定义为 IntPtr
值(value)观。这并不意味着它是指向内存的指针。 (即- Marshal.Read
不能使用。)LPCSTR
是 Long
Pointer
到 C
款式 STR
ing。这是 ANSI
字符串,所以表示该参数需要MarshalAsAttribute
与 UnmanagedType.LPStr
.如果这是一个输出参数,事情会更复杂,你要么需要传递 StringBuilder
或使用 Marshal.AllocHGlobal
/Marshal.AllocCoTaskMem
获得分配的非托管内存。 HWND
是 Handle
到 Window
.喜欢 HINSTANCE
它通常编码为 IntPtr
DLGPROC
有点复杂,所以我将在下面解决它。 LPARAM
是 Long
Parameter
. Microsoft 在创建 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
. CALLBACK
是编译器用来确定函数应该如何编译以及使用它的人应该如何将参数发送给函数的另一位信息。默认情况下,.net marshal 处理这个,所以不需要额外的配置。 WPARAM
代表 Word
Param
.在这种情况下,它是旧术语,您需要使用 IntPtr
接收值(value)。 编码指向
DLGPROC
的指针,您将需要创建一个具有适当签名的委托(delegate):Delegate Function DLGPROC(ByVal hWnd As IntPtr,
ByVal uMsg As UInt32,
ByVal wParam As IntPtr,
ByVal lParam As IntPtr) As IntPtr
然后,您需要在代码中的某处创建一个具有相同签名的函数,以接收来自 native 代码的调用。就像是:
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
然后,您可以添加一个类成员来持有该委托(delegate):
Private DialogProc As DLGPROC = New DLGPROC(AddressOf Me.MyDialogProc)
毕竟,你终于准备好导入
GoModal
了。函数原型(prototype)。 (耶!)看起来像:<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
与指定的值。 (有时 LPARAM
只是一个数字)如果你做到了这一步,恭喜!代码中可能存在一些错误,但这应该可以帮助您。对于其他 Windows API 类型,您可以在 pinvoke.net 找到很多信息。 .
如果您有很多互操作要做,只需将 C++/CLI dll 添加到您的项目并在 native 调用这些函数会更容易。这要容易得多,而且您可以准确地定义您想要的功能。此外,C++/CLI 可与任何 .net 语言一起使用。
关于在 vb.net 中调用 winAPI 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37616203/