在 vb.net 中调用 winAPI 函数

标签 c vb.net winapi

关闭。这个问题需要更多 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 时,可以忽略它。
  • HINSTANCEHandleInstance .翻译成 .net,句柄通常定义为 IntPtr值(value)观。这并不意味着它是指向内存的指针。 (即- Marshal.Read 不能使用。)
  • LPCSTRLong PointerC款式 STR ing。这是 ANSI字符串,所以表示该参数需要MarshalAsAttributeUnmanagedType.LPStr .如果这是一个输出参数,事情会更复杂,你要么需要传递 StringBuilder或使用 Marshal.AllocHGlobal/Marshal.AllocCoTaskMem获得分配的非托管内存。
  • HWNDHandleWindow .喜欢 HINSTANCE它通常编码为 IntPtr
  • DLGPROC有点复杂,所以我将在下面解决它。
  • LPARAMLong Parameter . Microsoft 在创建 Message 时用于此类型的标准实现。类,是 IntPtr .你应该效仿。

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

    INT_PTR CALLBACK DialogProc(
      _In_ HWND   hwndDlg,
      _In_ UINT   uMsg,
      _In_ WPARAM wParam,
      _In_ LPARAM lParam
    );
    

    我们已经看到了HWNDLPARAM ,所以让我们快速看一下这个签名中的其他内容。
  • INT_PTRInteger 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.ZeroNULL 相同
  • 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/

    相关文章:

    c++ - BSTR 中是否有 Unicode 符号?

    c - 如何使用libcurl获取网页标题

    c - 当我创建一个新的用户空间线程时,它会出现在内核进程列表中吗?

    asp.net - 在 Entity Framework 模型中创建复合属性?

    c++ - 在服务中模拟和加载用户配置文件后,环境变量是否受到影响?

    winapi - 键盘的 SendInput() - 只有小写

    c - 解密不知道原始扩展名的文件时如何知道扩展名

    c - 有适用于 Windows 的可移植 C 编译器吗?

    c# - C# 或 VB 文档注释中的粗体或斜体?

    .net - 从 VB.NET 中的 FTP 文件夹下载所有文件和子目录