Closed. This question needs to be more focused. It is not currently accepting answers. Learn more
想改进这个问题吗?更新问题,使其只关注一个问题editing this post
三年前关闭。
我不得不将一个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-->我可能完全错了,但这就是我所理解的)
当我进入每种类型的定义(例如:NEAR、HINSTANCE、LPCSTR等等)时,我试图在VB中找到一个等价的调用,但是。。。没用。举个例子,我在看附近,我想是为了判断两个指针是否在内存中很接近?(可能又错了,这正是我收集到的)。
最后,我的问题是,这样的呼叫是否存在于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是aHandle到aInstance。转换为.net时,句柄通常定义为IntPtr值。这并不意味着它是指向内存的指针。(即-Marshal.Read不能使用。)
LPCSTR是一种LongPointerC样式的。这是一个STR字符串,因此它意味着参数需要ANSIMarshalAsAttribute一起使用。如果这是一个out参数,事情会更复杂,您需要传递一个UnmanagedType.LPStr或使用StringBuilder/Marshal.AllocHGlobal来分配非托管内存。
Marshal.AllocCoTaskMem是aHWND到aHandle的。像Window一样,它通常被封送为HINSTANCE
IntPtr有点复杂,所以我将在下面讨论它。
DLGPROC是一个LPARAMLong。Microsoft在创建Parameter类时用于此类型的标准实现是Message。你应该效仿。
正如我上面所说的,IntPtr更复杂。它实际上是指向函数的指针(引用)。特别是有签名的:
INT_PTR CALLBACK DialogProc(
  _In_ HWND   hwndDlg,
  _In_ UINT   uMsg,
  _In_ WPARAM wParam,
  _In_ LPARAM lParam
);

我们已经看到了DLGPROCHWND,所以让我们快速查看这个签名中的其他内容。
LPARAM是一个INT_PTRInteger。如果听起来很熟悉的话,那应该是。它只是一个Pointer
IntPtr是编译器用来确定函数应该如何编译,以及使用它的人应该如何向函数发送参数的另一位信息。默认情况下,.net封送处理程序会处理此问题,因此不需要额外的配置。
CALLBACK代表WPARAMWord。在本例中,这是一个旧术语,您需要使用Param来接收值。
要封送指向IntPtr的指针,您需要创建具有适当签名的委托:
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)

在所有这些之后,您终于可以导入DLGPROC函数原型了。(耶!)看起来像是:
<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))

关于函数调用的两个注意事项:
GoModalIntPtr.Zero相同
NULL创建具有指定值的New IntPtr(100)。(有时IntPtr只是一个数字)
如果你能做到这一点,恭喜你!代码中可能有几个bug,但这应该可以让您继续。对于其他Windows API类型,您可以在pinvoke.net上找到很多信息。
如果您有很多互操作性,那么只需在项目中添加C++/CLI DLL就更容易,并在本地调用这些函数。它简单得多,你可以定义你想要的函数。此外,C++/CLI与任何.NET语言都有作用。

关于c - 在vb.net中调用winAPI函数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37616203/

10-11 04:24
查看更多