How to map Win32 types to C# types when using P/Invoke?

风流意气都作罢 提交于 2019-11-26 22:24:25

问题


I am trying to do something like this in C#. I found out how to call Win32 methods from C# using P/Invoke from this link. However I met some difficulties in implementing P/Invoke.

For example, one of the methods that I would like to access is PdhOpenQuery, signature:

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

I figure the corresponding C# declaration should be something like this

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

My questions:

What is LPCTSTR, and to what data type does it map in C#?
How to map a pointer type DWORD_PTR? The pinvoke article says DWORD maps to UInt32, but how about pointers?
I think PDH_STATUS and PDH_HQUERY are specific struct to the library (I'm not sure yet). how do I map these?

What is the correct method declaration, and how do you call it correctly?


回答1:


What is LPCTSTR, and to what data type does it map in C#?

LPCTSTR is a typedef for const TCHAR*.

TCHAR is an attempt to abstract away the fact that the Windows API exists in both "ANSI" (char strings in a locale-specific encoding) and "Unicode" (UTF-16) versions. There is no actual PdhOpenQuery function; there is a PdhOpenQueryA function that takes an ANSI string and a PdhOpenQueryW function that takes a UTF-16 string.

C# uses UTF-16 strings, so you'll want to prefer the "W" version of these functions. Use PdhOpenQueryW. Then the first parameter has C++ type const wchar_t*. The C# type is [MarshalAs(UnmanagedType.LPWStr)] string.

How to map a pointer type DWORD_PTR? The pinvoke article says DWORD maps to UInt32, but how about pointers?

DWORD_PTR isn't a pointer. It's an unsigned integer big enough to hold a pointer. The equivalent C# type is System.UIntPtr.

I think PDH_STATUS and PDH_HQUERY are specific struct to the library (I'm not sure yet). how do I map these?

PDH_STATUS appears to be just an int.

PDH_HQUERY is a pointer to a handle (another pointer), but you can just pretend it's an integer and use IntPtr.

Putting it all together, your declaration should be:

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



回答2:


iirc LPCTSTR breaks down to: LP == Long Pointer // relic from 16- to 32-bit thunking

C == Constant

TSTR == TStr // TString, kind of a placeholder that would get substituted for different kinds of strings depending on various C headers and #defines

what it means to you: it is a pointer to a string, for C# just use string and you'll be okay.

PDH_STATUS is a pointer to a DH_STATUS struct, so you will need to define a C# structure to match.

Check out P/Invoke.Net for some examples of using p/invoke on standard Windows headers, structures, and functions. The website is kind of klunky, you just have to keep clicking and expanding items in the left column.

P/Invoke isn't well documented, but once you map the structure and the extern function call you should be in business.




回答3:


[DllImport("Pdh.dll")]
    static extern Int32 PdhOpenQuery(string szDataSource, 
        IntPtr dwUserData, ref IntPtr phQuery);


来源:https://stackoverflow.com/questions/3598226/how-to-map-win32-types-to-c-sharp-types-when-using-p-invoke

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!