views:

103

answers:

3

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?

A: 
[DllImport("Pdh.dll")]
    static extern Int32 PdhOpenQuery(string szDataSource, 
        IntPtr dwUserData, ref IntPtr phQuery);
Alex Farber
it still won't compile because PDH_STATUS is not recognized. Also can you explain why String and IntPtr?
Louis Rhys
Oops, sorry, return value should be IntPtr. IntPtr is .NET wrapper for unmanaged pointer. Since handle is usually pointer, or some number which has the same size as pointer, IntPtr is used also for handles. Why string? Well, because LPCTSTR is a string.
Alex Farber
Well, actually PDH_STATUS is just a number, so it is better to define it as Int32.
Alex Farber
A: 

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.

Jay
+5  A: 

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);
dan04
correction: `UIntPtr` should be `UIntPtr dwUserData`? Another question, how should one call the method?
Louis Rhys