I have the following function header in a native DLL:
unsigned char* Version_String()
I'm trying to call it from a C# project, I've tried the following call (as found on other similar questions here):
[DllImport("BSL430.dll", CharSet=CharSet.Ansi)]
public extern static UIntPtr Version_String();
And I keep getting the following exception:
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
The next try was the following and I get the same exception:
[DllImport("BSL430.dll", CharSet=CharSet.Ansi)]
[return : MarshalAs(UnmanagedType.LPStr)]
public extern static string Version_String();
I can't seem to get around this issue. Any help would be greatly appreciated!
Edit:
I can't give the DLL code here, as it falls under an NDA, but the function I'm calling looks like this:
unsigned char versionString[50];
__declspec(dllexport) unsigned char* Version_String()
{
if(check_hardware_stuff())
{
strcpy((char *) versionString, "version_string_bla_bla");
versionString[5] = stuff;
}
else if (other_check())
{
//will return empty string, that should be filled with '\0'
}
else
{
strcpy( (char *) versionString, "ERROR" );
}
return versionString;
}
I'm not particularly fond of the DLL implementation, but I need to use it "as it is".
I get the exception thrown whenever I try to call VersionString()
, regardless of what I do with the return value.
Update
Having seen the updated question, the various comments, and the code of your native function, it seems likely that the exception is raised when you call check_hardware_stuff()
. It's simple enough to debug. I would replace your function with one like this:
unsigned char versionString[50];
__declspec(dllexport) unsigned char* Version_String()
{
strcpy(versionString, "testing");
return versionString;
}
If that still fails then my guess is that the error is raised in the DllMain
of your DLL. Debug that by putting the above function into a plain vanilla DLL that does nothing else.
Original answer
Calling convention is the most obvious problem. Your native code most likely uses cdecl
but the p/invoke default is stdcall
. Change your p/invoke signature to be like this:
[DllImport("BSL430.dll", CallingConvention=CallingConvention.Cdecl)]
public extern static IntPtr Version_String();
You can safely omit the CharSet
parameter since none of the parameters have text because you are treating the return value as a pointer.
Edit: Hans correctly points out in the comments that since there are no parameters, the calling convention mis-match does not matter. So this isn't the problem.
Call Marshal.PtrToStringAnsi
to convert to a .net string.
string version = Marshal.PtrToStringAnsi(Version_String());
Since PtrToStringAnsi
is expecting an IntPtr
parameter I would recommend that you use IntPtr
as the return type of you p/invoke signature.
This all assumes that the memory returned from your native function is allocated and freed in the native DLL. If it is heap allocated and you expect the caller to deallocate it then you have a small problem. How do you deallocate the memory from C# since you don't have access to the native DLL's heap?
The simple solution is to use the shared COM heap to allocate the memory. Call CoTaskMemAlloc
to allocate the buffer for the string. Then declare the return value to be of type string
and the p/invoke marshaller will deallocate with the COM allocator.
[DllImport("BSL430.dll", CallingConvention=CallingConvention.Cdecl)]
public extern static string Version_String();
...
string version = Version_String();
Of course, this only applies if you are returning heap allocated memory that you expect the caller to deallocate.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With