6

I have an API that takes three parameters:

HANDLE  Connect(LPCSTR MachineName, LPCSTR ServerName, BOOL EnableDLLBuffering); 

How can I use this method in C#?

What is the equivalence of LPCSTR? And what should be use in place of HANDLE?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
mahua22
  • 141
  • 1
  • 4
  • 12
  • 1
    How is this question not a duplicate? It must have been asked in the 5 years of Stack Overflow's existence (approximately 5,493,950 questions). – Peter Mortensen Aug 06 '13 at 08:10
  • 1
    @PeterMortensen You should flag it as a duplicate then if you think it is. All I can [find](http://stackoverflow.com/search?q=[c%23]+lpcstr) are questions about general P/Invoke issues. – user247702 Aug 06 '13 at 08:11
  • 1
    LPCSTR is a pointer to constant char string , const char*, that is the string in C#, also HANDLE can be replaced with C# IntPtr – ahmedsafan86 Aug 06 '13 at 08:16
  • The suggested duplicate isn't very good. The accepted response points to a CodeProject article that doesn't even include the `SafeHandle`, and it doesn't speak of encoding a string manually. – xanatos Aug 06 '13 at 08:30
  • xanatos: I agree. Someone with good [Google-fu](http://en.wiktionary.org/wiki/Google-fu), step up! – Peter Mortensen Aug 06 '13 at 08:32

3 Answers3

11

The HANDLE equivalent is IntPtr (or you could use one of the subclasses of SafeHandle, many of which are defined in the namespace Microsoft.Win32.SafeHandles). The equivalent of LPCSTR is string or StringBuilder (but string is better, because you are passing the string to the method and the method won't modify it). You can even use a byte[] (as I have wrote you in the other response, but you must encode your string in the buffer, and add a \0 at the end... it's quite inconvenient). In the end an LPCSTR is a constant LPSTR that the method won't modify. It's better you set the CharSet.Ansi as in the other response.

[DllImport("YourDll.dll", CharSet = CharSet.Ansi)]
static extern IntPtr Connect(string machineName, string serverName, bool enableDLLBuffering);

and you call it as:

IntPtr ptr = Connect("MyMachine", "MyServer", true);

or, if you really want to do the encoding yourself:

[DllImport("YourDll.dll", CharSet = CharSet.Ansi)]
static extern IntPtr Connect(byte[] machineName, byte[] serverName, bool enableDLLBuffering);

and

public static byte[] GetBytesFromStringWithZero(Encoding encoding, string str)
{        
    int len = encoding.GetByteCount(str);

    // Here we leave a "space" for the ending \0
    // Note the trick to discover the length of the \0 in the encoding:
    // It could be 1 (for Ansi, Utf8, ...), 2 (for Unicode, UnicodeBE), 4 (for UTF32)
    // We simply ask the encoder how long it would be to encode it :-)
    byte[] bytes = new byte[len + encoding.GetByteCount("\0")];
    encoding.GetBytes(str, 0, str.Length, bytes, 0);
    return bytes;
}

IntPtr ptr = Connect(
                 GetBytesFromStringWithZero(Encoding.Default, "MyMachine"),
                 GetBytesFromStringWithZero(Encoding.Default, "MyServer"), 
                 true);

This variant is better if you have to call the method many many times always with the same strings, because you can cache the encoded versions of the string and gain something in speed (yes, normally it's an useless optimization)

xanatos
  • 109,618
  • 12
  • 197
  • 280
  • LPCSTR is ok but how do I use Handle? can you please tell how do I use it in my program? – mahua22 Aug 06 '13 at 08:11
  • @mahua22 An `HANDLE` is an opaque type. You pass it around other methods that use it. The library should have some methods that accept an `HANDLE`, and it should have a `CloseHandle` method to close it in the end (otherwise you cause a leak) – xanatos Aug 06 '13 at 08:18
7

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

  • LPCSTR (C) - string (C#)
  • HANDLE (C) - IntPtr (C#)
Community
  • 1
  • 1
Peopleware
  • 1,399
  • 1
  • 25
  • 42
1

I use StringBuilder:

    [DllImport("user32.dll", CharSet = CharSet.Ansi)]
    static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

    var sb = new StringBuilder();
    var ret = GetClassName(hwnd, sb, 100);
    var klass = sb.ToString();
Robin Qiu
  • 5,521
  • 1
  • 22
  • 19