Call dll with C ++ header from C #

I am trying to call a method in a dll for which I am using the C ++ header. I am calling a dll from C #. The input is a string, and the output is binary data. Any of the following 3 methods will probably work, I just don't know how to get any of them to work fully. C # declaration made by me, so they may be wrong

1: I can get hGlobal, but I don't know how to get data from the descriptor.

//CMBT_LL_WINAPI INT DLLPROC LlConvertStringToHGLOBALW(LPCWSTR pszText, _PHGLOBAL phMemory); [DllImport("cmll15.dll", EntryPoint = "LlConvertStringToHGLOBALW", CharSet = CharSet.Unicode, ExactSpelling = true)] private static extern int _LlConvertStringToHGlobal32(string text, ref IntPtr handle); 

2:

 [DllImport("cmll15.dll", EntryPoint = "LlConvertStringToBLOBW", CharSet = CharSet.Unicode, ExactSpelling = true)] //CMBT_LL_WINAPI INT DLLPROC LlConvertStringToBLOBW(LPCWSTR pszText, _PUINT8 pBytes, UINT nBytes); private static extern int _LlConvertStringToBLOBW(string text, ref IntPtr pBytes, UInt32 nBytes); 

3:

 [DllImport("cmll15.dll", EntryPoint = "LlConvertStringToStreamW", CharSet = CharSet.Unicode, ExactSpelling = true)] //CMBT_LL_WINAPI INT DLLPROC LlConvertStringToStreamW(LPCWSTR pszText, _PISTREAM pStream); private static extern int _LlConvertStringToStreamW(string text, ref IntPtr pStream); 

Updated, here is the code that I think will end up.

  [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] private static extern UIntPtr GlobalSize(IntPtr hMem); [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] public static extern IntPtr GlobalLock(IntPtr handle); [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] public static extern IntPtr GlobalUnlock(IntPtr handle); [DllImport("cmll15.dll", EntryPoint = "LlConvertStringToHGLOBALW", CharSet = CharSet.Unicode, ExactSpelling = true)] private static extern int _LlConvertStringToHGlobal32(string text, ref IntPtr handle); private static void Main(string[] args) { IntPtr dataHandle = IntPtr.Zero; _LlConvertStringToHGlobal32(Contents, ref dataHandle); try { var size = (uint) GlobalSize(dataHandle); var array = new byte[size]; IntPtr dataPtr = GlobalLock(dataHandle); try { Marshal.Copy(dataPtr, array, 0, array.Length); } finally { GlobalUnlock(dataPtr); } using (var fs = new FileStream("c:\\file.dat", FileMode.Create)) { fs.Write(array, 0, array.Length); } } finally { Marshal.FreeHGlobal(dataHandle); } } 
+4
source share
2 answers

The first one should be the easiest because it returns it to the called one to determine the required size. However, it is not obvious how you should know the size of the distribution. Perhaps the return value. You can always infer GlobalSize () to get the size from the HGLOBAL handle. You must pinvoke GlobalLock () to convert the handle to a pointer, and then Marshal.CopyMemory () to copy it to byte []. Cleaning by calling GlobalUnlock () and Marshal.FreeHGlobal () to free memory, put it in a finally block so that you cannot leak.

For the second, you must declare the second argument as byte [] (not ref). The problem is that you have to guess the size of the array in front. Failure mode assumes the size is too small.

The third requires COM IStream. Declare this as System.Runtime.InteropServices.ComTypes.IStream. It behaves the same as .NET Stream, you call Seek to search at the beginning and read to read data.

I would choose the first, least likely, to explode in your face.

+1
source

For 1: You must have a binary data output length, and then use the Marshal.Copy method as follows: byte [] data = new byte [length]; Marshal.Copy (handle, data, 0, length);

For 2 and 3: what is your problem?

-1
source

Source: https://habr.com/ru/post/1335214/


All Articles