On the compact framework (3.5) I have a pinvoke as follows:
[DllImport("VAMDll.dll", SetLastError = true, EntryPoint = "openLiteSpatial")]
public static extern int OpenLiteSpatial(byte[] mode, byte[] data, byte[] capture, IntPtr callback);
For the following native function sig:
int openLiteSpatial(char *mode, char *data, char *capture, void callBack(char *, char *));
Passing parameters inwards works fine like this:
Native.OpenLiteSpatial(Encoding.UTF8.GetBytes(Mode.FunctionalLocation), Encoding.UTF8.GetBytes(functionalLocation), Encoding.UTF8.GetBytes(capture), Marshal.GetFunctionPointerForDelegate(callback));
But in my callback I have to do some strange transformations on the callback parameter strings:
public delegate void LiteSpatialCallback(string attributeData, string geoCoordinate);
public static void Callback(string attributeData, string geoCoordinate)
{
byte[] decodedAttributeData = Encoding.Unicode.GetBytes(attributeData);
byte[] decodedGeoCoordinate = Encoding.Unicode.GetBytes(geoCoordinate);
attributeData = Encoding.UTF8.GetString(decodedAttributeData, 0, decodedAttributeData.Length);
geoCoordinate = Encoding.UTF8.GetString(decodedGeoCoordinate, 0, decodedGeoCoordinate.Length);
}
I have tried specifying the Charset on the DllImport attribute, and using byte[] arrays (which causes the callback to not get called at all), and specifying various MarshalAs options.
Is there a better way?
I'd be inclined to pass IntPtrs for the delegate parameters, then use the Memory windows to see exactly what's coming back in them. Is it a pointer to data? A pointer to a pointer? The data itself? Is it Unicode or ASCII? All these could be determined by walking the addresses returned. You could then either just manually copy from that target, or you could re-work the P/Invoke and/or delegate signature based on your findings.
Related
I am a newbie on both C# WPF and C++.
Recently, I got an external .dll, which returns a char*, and I want to receive the return value in C# by using DllImport. Then, using str.Split(';') to separate the characters. To the purpose, I created a button to show the first character in the string I split on a label when I click the button.
Therefore, I use an IntPtr to receive a char*, which is from C++ .dll, and call Marshal.PtrToStringAnsi() to turn it into a string. However, when I execute the code, it sometimes works but sometimes crushes. Then error code always shows
Unhandled exception at 0x00007FFC06839269 (ntdll.dll) in UITest.exe: 0xC0000374: heap corruption (parameters: 0x00007FFC068A27F0).
I thought my code is reasonable and I couldn't find root causes. Can anyone help me? Thanks!
The below shows the content in .dll and also the code I used in C#.
C++ code in Dlltest.h:
#define DLL_EXPORT extern "C" __declspec(dllexport)
char* getRbtData = nullptr;
DLL_EXPORT char* func_getRbtData();
C++ code in Dlltest.cpp:
char* func_getRbtData()
{
getRbtData = new char(128);
memset(getRbtData, 0, strlen(getRbtData));
char* _getRbtData = "1.0;23.0;55.0;91.0;594.0;";
memcpy(getRbtData, _getRbtData, strlen(_getRbtData));
return getRbtData;
};
C# code in UITest.xaml.cs:
[DllImport("DllTest.dll",EntryPoint = "func_getRbtData", CharSet = CharSet.Ansi)]
public static extern IntPtr func_getRbtData();
string[] words;
private void btn_test_Click(object sender, RoutedEventArgs e)
{
IntPtr intptr = func_getRbtData();
string str = Marshal.PtrToStringAnsi(intptr);
words = str.Split(';');
lb_content.Content = words[1];
}
There are several problems with your code.
On the C++ side, your DLL function is implemented all wrong:
getRbtData = new char(128);
You are allocating a single char whose value is 128, not an array of 128 chars. You need to use new char[128] instead for that.
memset(getRbtData, 0, strlen(getRbtData));
getRbtData is not a pointer to a null-terminated string, so strlen(getRbtData) is undefined behavior. It reads into surrounding memory while calculating the length until it finds a random 0x00 byte in memory.
And then the subsequent memset() into getRbtData will overwrite that surrounding memory. If it doesn't just crash outright.
char* _getRbtData = "1.0;23.0;55.0;91.0;594.0;";
Prior to C++11, this assignment is OK but discouraged. In C++11 and later, this assignment is actually illegal and won't compile.
String literals are read-only data, so you need to use const char instead of char in your pointer type. You should do that even in older compilers.
memcpy(getRbtData, _getRbtData, strlen(_getRbtData));
strlen(_getRbtData) is OK since _getRbtData is a pointer to a null-terminated string.
However, since getRbtData is not allocated with enough memory to receive all of the copied chars, memcpy() into getRbtData is also undefined behavior and will trash memory, if not crash outright.
return getRbtData;
This is OK to pass the pointer to C#.
However, since the memory is being allocated with new (better, new[]), it needs to be freed with delete (delete[]), which you are not doing. So you are leaking the memory.
Marshal.PtrToStringAnsi() on the C# side will not (and cannot) free new'ed memory for you. So your C# code will need to pass the pointer back to the DLL so it can delete the memory properly.
Otherwise, you will need to allocate the memory using the Win32 API LocalAlloc() or CoTaskMemAlloc() function so that the Marshal class can be used on the C# side to free the memory directly without passing it back to the DLL at all.
On the C# side, you are using the wrong calling convention on your DllImport statement. The default is StdCall for compatibility with most Win32 API functions. But your DLL function is not specifying any calling convention at all. Most C/C++ compilers will default to __cdecl unless configured differently.
With that said, try this instead:
Dlltest.h
#define DLL_EXPORT extern "C" __declspec(dllexport)
DLL_EXPORT char* func_getRbtData();
DLL_EXPORT void func_freeRbtData(char*);
Dlltest.cpp
char* func_getRbtData()
{
const char* _getRbtData = "1.0;23.0;55.0;91.0;594.0;";
int len = strlen(_getRbtData);
char *getRbtData = new char[len+1];
// alternatively:
/*
char *getRbtData = (char*) LocalAlloc(LMEM_FIXED, len+1);
if (!getRbtData) return NULL;
*/
memcpy(getRbtData, _getRbtData, len+1);
return getRbtData;
}
void func_freeRbtData(char *p)
{
delete[] p;
// alternatively:
// LocalFree((HLOCAL)p);
}
UITest.xaml.cs
[DllImport("DllTest.dll", EntryPoint = "func_getRbtData", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr func_getRbtData();
[DllImport("DllTest.dll", EntryPoint = "func_freeRbtData", CallingConvention = CallingConvention.Cdecl)]
public static extern void func_freeRbtData(IntPtr p);
string[] words;
private void btn_test_Click(object sender, RoutedEventArgs e)
{
IntPtr intptr = func_getRbtData();
string str = Marshal.PtrToStringAnsi(intptr);
func_freeRbtData(intptr);
// alternatively:
// Marshal.FreeHGlobal(intptr);
words = str.Split(';');
lb_content.Content = words[1];
}
new char(128) returns a pointer to one character, with initial value 128.
I could tell you how to allocate 128 characters, but the chief problem with that is that you can't clean it up so that's not a useful answer. Check the existing questions about returning a string to C#.
I'm currently trying to integrate a C++ DLL into our C# application, but I'm not able to identify what's the correct way to call one of their methods. In two different places of the documentation the method definition are not equal:
ImageAndScanError GetMicrInfo(unsigned char *ptrCodeline,int* iLength)
ImageAndScanError WINAPI GetMicrInfo(char* cMicrInfo,int* iInfoLength);
/*
ImageAndScanError GetMicrInfo(unsigned char *ptrCodeline,int* iLength)
Parameters:
ptrCodeline: a pointer to the output buffer that will receive the code line read by the MICR algorithm. The ptrCodeline should allocate room for 96 characters.
iLength: the number of characters contained in the code line
Function: Read MICR line on the check. This function must be called after StartScan .
Returns: ErrorNone is returned upon success. Otherwise, an enum ImageAndScanError value that indicates the reason for failure is returned.
*/
This is how I'm including the dll method
[DllImport("ScanDll.dll", CallingConvention = CallingConvention.Winapi)]
And this are all the combinations that I've made so far
public static extern ImageAndScanError GetMicrInfo(out IntPtr cMicrInfo, out int iInfoLength);
public static extern ImageAndScanError GetMicrInfo(out byte[] cMicrInfo, out int iInfoLength);
public static extern ImageAndScanError GetMicrInfo(out string cMicrInfo, out int iInfoLength);
public static extern ImageAndScanError GetMicrInfo(out StringBuilder cMicrInfo, out int iInfoLength);
IntPtr cMicrInfoTMP;
byte[] cMicrInfoTMP= new byte[96];
string cMicrInfoTMP;
StringBuilder cMicrInfoTMP;
GetMicrInfo(out cMicrInfoTMP, out iInfoLengthTMP);
When I use IntPtr, the value that the debug gives me in VS2010 is 859256727 with a size of 4, and when I do
string myString = Marshal.PtrToStringAnsi(cMicrInfoTMP);
I always get an empty string.
When I try any of the others (byte[], string, StringBuilder) I get
The runtime has encountered a fatal error. The address of the error was at
0x53e6716a, on thread 0x1084. The error code is 0xc0000005. This error may
be a bug in the CLR or in the unsafe or non-verifiable portions of user
code. Common sources of this bug include user marshaling errors for COM-interop
or PInvoke, which may corrupt the stack.
What am I missing here?
Thanks
You can allocate a buffer, then pass to the native function.
//error handling omitted
[DllImport("your.dll", CharSet = CharSet.Ansi)]
ImageAndScanError GetMicrInfo(IntPtr ptrCodeline,ref int bytesCopied);
IntPtr ip = Marshal.AllocCoTaskMem(bufferLen);
Win32API.ZeroMemory(ip, (uint)(bufferLen));
int bytesCopied=0;
GetMicrInfo(ip, ref bytesCopied);
string info= Marshal.PtrToStringAnsi(bytesCopied);
Marshal.FreeCoTaskMem(ip);
If you do not need to reuse the buffer during multiple calls of GetMicrInfo, you can use the default marshaler for StringBuilder:
[DllImport("your.dll", CharSet = CharSet.Ansi)]
ImageAndScanError GetMicrInfo(StringBuilder ptrCodeline,ref int bytesCopied);
StringBuilder ptrCodeline(bufferLen);
int bytesCopied=0;
GetMicrInfo(ptrCodeline, ref bytesCopied);
It comes with a performance hit if you call GetMicrInfo multiple times, because on each call the default CLR marshaller creates a marshalling buffer for pinning and for unicode-ANSI conversion. This hit may be negligible if the function isn't being called frequently or does not return a lot of data.
Reference:
Default Marshaling for Strings
Marshaling between Managed and Unmanaged Code
In .NET, out parameters are used when the callee creates the object. You need to provide an existing buffer to the function so you should initialize the StringBuilder first. The marshaller then passes a pointer to object's the internal character buffer to the function.
You do have to figure out which character set and encoding is being used for the MICR string. It could be UTF-16, in which case, change the declaration to CharSet.Unicode.
Try this:
[DllImport("ScanDll.dll", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Ansi)]
private static extern ImageAndScanError GetMicrInfo(StringBuilder cMicrInfo, out int iInfoLength);
public String GetMicrInfo()
{
StringBuilder info = new StringBuilder(96);
int length;
ImageAndScanError error = GetMicrInfo(info, out length);
if (error != ImageAndScanError.ErrorNone) throw new Exception(String.Format("GetMicrInfo error: {0}", error));
return info.ToString();
}
-In my c code I have a struct which contains many unknown sized arrays in an unmanaged dll (c code)
-I need the data of one instance of this struct marshaled over to c#, which I will later on send back to the unmanaged c code
-I do not need to manipulate this data once it gets to csharp, only hold onto it/store it for a while (so it can remain in a byte array).
-I do not want to use the keyword 'unsafe' as it is a big project and this is just one small piece and I don't want to be compiling like that.
I tried marshaling it as a lpArray and everything looks fine but when i look at the contents after coming back to the csharp, it is always empty. This type of marshaling style worked for me for dynamic arrays of various types but not the struct.
Searching the web is drawing blanks and much more complicated scenarios than my own, but if anybody has seen such a link please post it here I would be very greatful!
Thanks.
--update here is more or less the structure of my code:
c#:
[DllImport("mydll.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
private static extern int W_Thread_Connect_NET(
[MarshalAs(UnmanagedType.LPStr, SizeConst = 100)] string IPAddress,
int DevicePort,
[MarshalAs(UnmanagedType.LPArray)] byte[] connectionHandle
);
//and call it like this, with an empty struc to be populated by c (can this be done? it is comming back without the data):
byte[] myStrucParam= new byte[100];
int result = W_Thread_Connect_NET(myStrucParam, myParam1, myParam2, ...);
c:
typedef struct myStructDef{
char* myArray1,
char* myArray2,
int myInt1,
...
} mystrucObj, *pMystrucObj;
//method that i am wanting to marshal the struct as a paramter here..
MYDLL_DLLIMPORT int APIENTRY W_Thread_Connect_NET(pMystrucObj strucReturn_handle, char * IPAddress, int DevicePort, ...)
{
//(omitted)
}
You say that the C# code does not need to manipulate the struct. That makes it a pretty simple problem to solve. You can treat the struct pointer as an opaque pointer, that is an IntPtr.
First of all you add a new function to your native code:
pMystrucObj CreateStruct(void)
{
pMystrucObj res = malloc(sizeof(*res));
return res;
}
Then in your C# code you call it like this:
[DllImport("mydll.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern IntPtr CreateStruct();
Now declare W_Thread_Connect_NET like this:
[DllImport("mydll.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern int W_Thread_Connect_NET(
IntPtr theStructPtr,
string IPAddress,
int DevicePort,
....
);
And call it all like this:
IntPtr theStructPtr = CreateStruct();
int res = W_Thread_Connect_NET(theStructPtr, IPAddress, DevicePort, ...);
And of course you'll want to add another function named DestroyStruct to deallocate the struct's memory once you are done with it.
I have a function made in C++ that calls a COM interface's function
Its signature:
BOOL func(LPWSTR strIn, __out LPWSTR strOut)
{
//initcom
//do something
// release pointers
}
In C#:
[DllImport("funcdll.dll")]
static extern bool func(String strIn, ref String strOut);
// use it
for(int i=0;i<10;i++)
{
if(func(strin, strout))
{
//do something with strout
}
}
I have tested my dll in a C++ console application, it works, but in C# it crashes with an unknown error.
You've got three problems that I can see.
The calling conventions don't match. Your C++ code is cdecl and your C# code is stdcall.
The C++ code uses wide strings, but the C# code marshals ANSI strings.
The second parameter doesn't match. Your C# code assumes that the C++ code returns a new pointer to a C string which the C# code then deallocates with the COM allocator. Your C++ code doesn't do this.
Now, dealing with these in more detail.
Calling conventions
This is pretty easy to fix. Simple change the C++ code to stdcall, or the C# code to cdecl. But don't do both. I'd change the C# code:
[DllImport("funcdll.dll"), CallingConvention=CallingConvention.Cdecl]
Unicode/ANSI strings
I presume you are wanting to use Unicode strings since you have explicitly selected them in the C++ code. But P/invoke defaults to marshalling ANSI strings. You can change this again in the DllImport like so:
[DllImport("funcdll.dll"), CallingConvention=CallingConvention.Cdecl,
CharSet=CharSet.Unicode]
Returning a string from C++ to C#
Your current C++ function declaration is so:
BOOL func(LPWSTR strIn, __out LPWSTR strOut)
The __out decorator has no real effect, other than documenting that you want to modify the buffer pointed to by strOut and have those modifications returned to the caller.
Your C# declaration is:
static extern bool func(String strIn, ref String strOut);
Now, ref String strOut simply does not match. A ref string parameter matches this in C++:
BOOL func(LPWSTR strIn, LPWSTR *strOut)
In other words the C# code is expecting you to return a new pointer. In fact it will then proceed to deallocate the buffer you returned in strOut by calling CoTaskMemFree. I'm confident that's not what you want.
Your original C++ code can only return a string to the C# code by modifying the buffer that was passed to it. That code would look like this:
BOOL func(LPWSTR strIn, __out LPWSTR strOut)
{
...
wcscpy(strOut, L"the returned string");
...
}
If this is what you want then you should allocate a sufficient buffer in C# in a StringBuilder object.
[DllImport("funcdll.dll"), CallingConvention=CallingConvention.Cdecl,
CharSet=CharSet.Unicode]
static extern bool func(string strIn, StringBuilder strOut);
...
StringBuilder strOutBuffer = new StringBuilder(128);
bool res = func("input string", strOutBuffer);
string strOut = StringBuilder.ToString();
If you simply cannot decide in the C# code how big a buffer you need then your best bet is to use a BSTR to marshal strOut. See this answer for details.
It's hard for me to tell without seeing the details of your C++ method... but, I've never had much luck using String with P/Invoke.
Try using IntPtr instead of String, and use Marshal.PtrToStringUni for the outgoing string, and marshal your managed string into unmanaged land with Marshal.StringToHGlobalUni and, after the function call, make sure to free the unmanaged string with Marshal.FreeHGlobal.
Also, coming from C99 land, my bools don't work with .NET bools... I don't know why. I have to use byte and check == 1. Don't know if you'll run into this with C++... but, if you want my advice on a place to start which seems least-breakable in my experience, here ya go:
[DllImport("funcdll.dll")]
static extern byte func(IntPtr strIn, out IntPtr strOut);
// use it
string myString = "Testing";
IntPtr stringOut;
IntPtr stringIn = Marshal.StringToHGlobalUni(myString);
if(func(stringIn, out stringOut) == 1)
{
//do something with strout
string stringOutValue = Marshal.PtrToStringUni(stringOut);
// Depending on how you dealt with stringOut in your
// unmanaged code, you may have to: Marshal.FreeCoTaskMem(stringOut);
// or Marshal.FreeHGlobal(stringOut) if you're returning
// an owning reference to a copied string.
}
Marshal.FreeHGlobal(stringIn);
I beleive you're having a calling convention mismatch. The default calling convention in C++ is cdecl while for .NET it's stdcall. try
[DllImport("funcdll.dll", CallingConvention = CallingConvention.Cdecl)]
static extern bool func(String strIn, ref String strOut);
Also you might have to specifically tell the marshallar that you want to marshal the strings as LPWSTR using [MarshalAs(UnmanagedType.LPWStr)] attributes.
[DllImport("funcdll.dll", CallingConvention = CallingConvention.Cdecl)]
static extern bool func([MarshalAs(UnmanagedType.LPWStr)]String strIn
,[MarshalAs(UnmanagedType.LPWStr)]ref String strOut);
have a look at http://msdn.microsoft.com/en-us/library/s9ts558h.aspx
In C++ make sure you have something like this (at least for the second argument)
extern "C" BOOL __stdcall func( BSTR * pBstr )
{
*pBstr = SysAllocString( L"Foobar" );
return 0;
}
In C# write something like this (for the second argument) :
static extern bool func( [MarshalAs(UnmanagedType.BStr)] ref String strOut);
Sorry I do not have a big answer but just remember something from my experience.. did you try to use StringBuilder eg changing your c# import function signature as
[System.Runtime.InteropServices.DllImport("funcdll.dll")]
static extern bool func(String strIn, System.Text.StringBuilder strOut);
I have a c# .net 2.0 CF application that interfaces with a native DLL implementing a function like this:
struct NATIVE_METHOD_REPLY
{
int other_irrelevant_data;
int data_size;
void* data;
}
// reply_buffer will contain an array of NATIVE_METHOD_REPLY structures
// and their data.
//
// returns an error code
int Foo(NATIVE_METHOD_REPLY* reply_buffer, int reply_size);
I've implemented it in C# like this:
[StructLayout(LayoutKind.Sequential)]
internal struct NATIVE_METHOD_REPLY
{
public Int32 OtherIrrelevantData;
public Int16 DataSize;
public IntPtr DataPtr;
}
[DllImport("my_lib.dll", SetLastError = true)]
internal static extern Int32 Foo(byte[] replyBuffer, Int32 replySize);
public byte[] void Bar()
{
// data returned to the user. May be an arbitrary size.
byte[] result_buffer = new byte[256];
// data sent to Foo()
byte[] reply_buffer =
new byte[Marshal.SizeOf(typeof(NativeMethods.NATIVE_METHOD_REPLY)) +
result_buffer.Length];
NativeMethods.Foo(reply_buffer, reply_buffer.Length);
// is there a better way of doing this?
NativeMethods.NATIVE_METHOD_REPLY reply;
GCHandle pinned_reply = GCHandle.Alloc(reply_buffer,
GCHandleType.Pinned);
try
{
reply = (NativeMethods.NATIVE_METHOD_REPLY)Marshal.PtrToStructure(
pinned_reply.AddrOfPinnedObject(),
typeof(NativeMethods.NATIVE_METHOD_REPLY));
Marshal.Copy(reply.DataPtr, result_buffer, 0, reply.DataSize);
}
finally
{
pinned_reply.Free();
}
// bonus point*: is this okay to do after the Free() call?
int test = reply.OtherIrrelevantData;
return result_buffer;
}
While this works correctly, I would like to know if this is the most efficient / most correct way of implementing this function.
Is there some method converting a managed byte array to a managed structure that doesn't involve an intermediate native handle and a copy? For instance, in C++, I would just do this:
NATIVE_METHOD_REPLY* reply = reinterpret_cast< NATIVE_METHOD_REPLY* >( reply.DataPtr );
*For a bonus point, is it okay to use data in the structure after the native handle has been freed?
Thanks,
PaulH
Edit: Updated solution
[DllImport("my_lib.dll", SetLastError = true)]
internal static extern Int32 Foo(IntPtr replyBuffer, Int32 replySize);
public byte[] void Bar()
{
byte[] result_buffer = new byte[256];
int reply_buffer_len = Marshal.SizeOf(typeof(NativeMethods.NATIVE_METHOD_REPLY)) + result_buffer.Length;
IntPtr reply_buffer = Marshal.AllocCoTaskMem(reply_buffer_len);
NativeMethods.NATIVE_METHOD_REPLY reply;
try
{
NativeMethods.Foo(reply_buffer, reply_buffer_len);
reply = (NativeMethods.NATIVE_METHOD_REPLY)Marshal.PtrToStructure(
reply_buffer,
typeof(NativeMethods.NATIVE_METHOD_REPLY));
Marshal.Copy(reply.DataPtr, result_buffer, 0, reply.DataSize);
}
finally
{
Marshal.FreeCoTaskMem(reply_buffer);
}
return result_buffer;
}
The structure has a fixed size. There's no point in passing an array, just pass the structure:
[DllImport("my_lib.dll", SetLastError = true)]
internal static extern Int32 Foo(out NATIVE_METHOD_REPLY replyBuffer, Int32 replySize);
You do have a memory management problem. Who owns the pointer?
Okay, the structure is actually variable sized and the pointer points into the array. You need nother approach. Simply allocate a chunk of unmanaged memory up front instead of letting the P/Invoke marshaller copy the data into a managed array. Which is in fact a hard requirement since the garbage collector can move the array, invalidating the pointer. Call Marshal.CoTaskMemAlloc() to reserve the memory, you'll have to free it later. And change the first argument of the function to IntPtr (not out).
You'll find that marshaling the structure a lot easier too, no need to pin the memory. Don't forget to Marshal.FreeCoTaskMem() when you're done.
In C# under the full framework, you can marshal the array directly. See Default Marshaling for Arrays. I don't know what the limitations are on the Compact Framework.