【问题标题】:How to map Win32 types to C# types when using P/Invoke?使用 P/Invoke 时如何将 Win32 类型映射到 C# 类型?
【发布时间】:2010-08-30 06:08:21
【问题描述】:

我正在尝试在 C# 中做类似this 的事情。我发现了如何使用 P/Invoke from this link 从 C# 调用 Win32 方法。但是我在实现 P/Invoke 时遇到了一些困难。

例如,我想访问的方法之一是PdhOpenQuery, 签名:

PDH_STATUS PdhOpenQuery(
  __in   LPCTSTR szDataSource,
  __in   DWORD_PTR dwUserData,
  __out  PDH_HQUERY *phQuery
);

我认为相应的 C# 声明应该是这样的

    [DllImport("Pdh.dll")]
    static extern PDH_STATUS PdhOpenQuery(LPCTSTR szDataSource, 
        DWORD_PTR dwUserData, out PDH_HQUERY *phQuery);

我的问题:

什么是 LPCTSTR,它在 C# 中映射到什么数据类型?
如何映射指针类型 DWORD_PTR? pinvoke 文章说 DWORD 映射到 UInt32,但是指针呢?
我认为 PDH_STATUS 和 PDH_HQUERY 是库的特定结构(我还不确定)。我如何映射这些?

什么是正确的方法声明,如何正确调用?

【问题讨论】:

    标签: c# winapi pinvoke performancecounter


    【解决方案1】:

    什么是 LPCTSTR,以及什么数据类型 它是用 C# 映射的吗?

    LPCTSTRconst TCHAR* 的类型定义。

    TCHAR 试图抽象出这样一个事实,即 Windows API 存在于“ANSI”(char 字符串以特定于语言环境的编码)和“Unicode”(UTF-16)版本中。没有实际的PdhOpenQuery 功能;有一个采用 ANSI 字符串的 PdhOpenQueryA 函数和采用 UTF-16 字符串的 PdhOpenQueryW 函数。

    C# 使用 UTF-16 字符串,因此您会更喜欢这些函数的“W”版本。使用PdhOpenQueryW。那么第一个参数的 C++ 类型为const wchar_t*。 C# 类型为[MarshalAs(UnmanagedType.LPWStr)] string

    如何映射一个指针类型 DWORD_PTR? pinvoke 文章说 DWORD 映射到 UInt32,但是指针呢?

    DWORD_PTR 不是指针。它是一个无符号整数,大到足以持有一个指针。等效的 C# 类型是 System.UIntPtr

    我认为 PDH_STATUS 和 PDH_HQUERY 是 库的特定结构(我是 还不确定)。我如何映射这些?

    PDH_STATUS 似乎只是一个int

    PDH_HQUERY 是一个指向句柄的指针(另一个指针),但您可以假装它是一个整数并使用IntPtr

    综合起来,你的声明应该是:

    [DllImport("Pdh.dll")]
    static extern int PdhOpenQueryW(
        [MarshalAs(UnmanagedType.LPWStr)] string szDataSource, 
        UIntPtr dwUserData,
        out IntPtr phQuery);
    

    【讨论】:

    • 更正:UIntPtr 应该是UIntPtr dwUserData?另一个问题,应该如何调用该方法?
    • LPCTSTR 是否可以映射到 IntPtr? SHGetFileInfo API(参考:msdn.microsoft.com/en-us/library/windows/desktop/…)的第一个参数是“In LPCTSTR pszPath”,大多数时候我看到人们将它用作“字符串”。但在一个例子中,我发现有人将它用作 IntPtr ..? (参考:stackoverflow.com/a/14293350/1039753
    • @ArvoBowen:是的,您可以将参数声明为IntPtr,然后将System.Runtime.InteropServices.Marshal 类中的PtrToStringAnsiPtrToStringUni 函数用于字符串。
    【解决方案2】:

    iirc LPCTSTR 分解为: LP == 长指针 // 从 16 位到 32 位 thunking 的遗物

    C == 常数

    TSTR == TStr // TString,一种占位符,可以根据不同的 C 头文件和#defines 替换不同类型的字符串

    它对你意味着什么:它是一个指向字符串的指针,对于 C# 只需使用字符串就可以了。

    PDH_STATUS 是一个指向 DH_STATUS 结构的指针,因此您需要定义一个 C# 结构来匹配。

    查看P/Invoke.Net,了解在标准 Windows 标头、结构和函数上使用 p/invoke 的一些示例。该网站有点笨拙,您只需要继续单击并展开左栏中的项目即可。

    P/Invoke 没有很好的文档记录,但是一旦你映射了结构和外部函数调用,你就应该开始工作了。

    【讨论】:

      【解决方案3】:
      [DllImport("Pdh.dll")] 静态外部 Int32 PdhOpenQuery(字符串 szDataSource, IntPtr dwUserData, ref IntPtr phQuery);

      【讨论】:

      • 它仍然无法编译,因为 PDH_STATUS 未被识别。你也能解释一下为什么是 String 和 IntPtr 吗?
      • 糟糕,抱歉,返回值应该是 IntPtr。 IntPtr 是非托管指针的 .NET 包装器。由于句柄通常是指针,或者一些与指针大小相同的数字,因此 IntPtr 也用于句柄。为什么是字符串?好吧,因为 LPCTSTR 是一个字符串。
      • 嗯,其实PDH_STATUS只是一个数字,所以最好定义为Int32。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-15
      • 1970-01-01
      • 2021-10-10
      • 1970-01-01
      • 1970-01-01
      • 2013-05-30
      相关资源
      最近更新 更多