3

I am writing a C# library to be used by native C++ application. I am using C++/CLI as the Interoperability mechanisim.

I require to pass a callback function from C++ to C# (using C++/CLI as the intermediate layer). C# library needs to call the C++ function with a zero terminated string of wide characters; i.e. the prototype of the callback function is

Func(LPCWSTR pszString);

There are other parameters but they are immaterial for this discussion.

I searched net and found Marshal.GetDelegateForFunctionPointer Method wich I can use. The problem with this is that it converts System.String from C# to char* and not wchar_t* which I am looking for.

Also, what is the best method of achieving this- code example including the C++/CLI portion, if possible. C++/CLI dll is dependent on C# dll. Method needs to be called synchronously.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Anil Padia
  • 513
  • 1
  • 6
  • 12

2 Answers2

8

GetDelegateForFunctionPointer will work, but you need to add a [MarshalAs(UnmanagedType.LPWStr)] attribute to the parameter in your delegate declaration in order for String to get converted into wchar_t*:

delegate void MyDelegate([MarshalAs(UnmanagedType.LPWStr)] string foo)

IntPtr func = ...;
MyDelegate del = (MyDelegate)Marshal.GetDelegateForFunctionPointer(func,
                                 typeof(MyDelegate));

To pass a modifiable string, give a StringBuilder. You need to explicitly reserve space for the unmanaged function to work with:

delegate void MyDelegate([MarshalAs(UnmanagedType.LPWStr)] StringBuilder foo)

StringBuilder sb = new StringBuilder(64); // reserve 64 characters.

del(sb);
Cory Nelson
  • 29,236
  • 5
  • 72
  • 110
  • +1 Out of curiosity, is there no way to declare a delegate to have `Charset=Charset.Unicode` like you do with DLLImport? – David Heffernan Jun 08 '11 at 16:56
  • Hi Cory. Many thanks. Your answer has actually solved my problem. How can I achieve the following second requirement: delegate void MyDelegate([MarshalAs(UnmanagedType.LPWStr)] string foo, out string val1, out int val2); In other words, C# calls the callback, giving a string parameter, and in C++, based on that string parameters, val1 and val2 need to be passed back to C# – Anil Padia Jun 09 '11 at 13:32
  • @Anil: For `LPSTR` and `LPWSTR` output parameters in p/invoke, use `StringBuilder`. – Ben Voigt Jun 09 '11 at 15:45
  • Hi Ben, can you please provide an example as Cory did. I am new to C# and C++/CLI world. – Anil Padia Jun 10 '11 at 13:49
  • @Anil Sorry it took me so long, I some how lost track of this question! I hope you've solved this by now but in case you haven't, I've added modifiable strings to my answer. – Cory Nelson Jul 22 '11 at 03:57
  • 1
    @David: Yes there actually is, see my answer. :-) – user541686 Jul 22 '11 at 04:00
  • Great answer, thanks. This method shows example for native method with no return value. How would you handle this (delegate declaration and initialisation) if native method would have a return value? – uerceg Jan 29 '16 at 07:53
2

See the little-known UnmanagedFunctionPointer attribute, which is like DllImport for delegates, if you'd like to use CharSet or whatnot.

user541686
  • 205,094
  • 128
  • 528
  • 886