I have a dll that I cannot import in my vs2012 c# project. I have used dllImport before but I have never had to use Marshal or pointers before. Lucky me I guess.
This is the code that I currently have.
The function being called is fnLDA_GetDevInfo(DEVID *ActiveDevices)
DEVID is a normal unsigned integer (#define DEVID unsigned integer)
//Allocate an array big enough to hold the device ids for the number of devices present.
//Call fnLDA_GetDevInfo(DEVID *ActiveDevices), which will fill in the array with the device ids for each connected attenuator
//The function returns an integer, which is the number of devices present on the machine.
[DllImport(DLLLOCATION,CallingConvention = CallingConvention.Cdecl)]
private static extern int fnLDA_GetDevInfo([MarshalAs(UnmanagedType.LPArray)] ref uint[] ActiveDevices);
I call the function in my code this way
uint[] MyDevices;
fnLDA_GetDevInfo(ref MyDevices);
At this point I get an error:
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Now I'm pretty sure the error occurs because I don't call the pointer right or something.
Any help would be appreciated.
You have an extra level of indirection. An array is marshalled as a pointer to the array. When you declare the parameter as ref, again a pointer is passed. Thus your C# code matches uint**. Even so, you cannot use ref with an array type because you cannot expect the unmanaged code to produce a managed array.
Your p/invoke should be:
[DllImport(DLLLOCATION,CallingConvention = CallingConvention.Cdecl)]
private static extern int fnLDA_GetDevInfo([Out] uint[] ActiveDevices);
Note that this function is pretty hard to call. Since the function is not passed the length of the array, it is impossible for the function to avoid running off the end of the array if the array is not long enough. I really hope that you have some way to work out how large the array needs to be ahead of calling this function.
So perhaps you are expected to call it like this:
uint[] MyDevices = new uint[SomeLargeNumberThatYouPresumablyCanProvide];
int len = fnLDA_GetDevInfo(MyDevices);
Or perhaps like this:
int len = fnLDA_GetDevInfo(null);
uint[] MyDevices = new uint[len];
fnLDA_GetDevInfo(MyDevices);
I trust that you'll be able to work the rest out from the documentation for the DLL and/or the example C++ programs that call the DLL.
Related
I am trying to call a function that converts sql queries between dialects. I am using an open-source project's DLL to use the functions for conversion in a C# university project. The problem i am facing is that i am getting a access violation reading location.
I've read some posts here on stack overflow which suggest that there might be a bad pointer somewhere, but i cannot find where. My pointers are not corrupt
The function for the conversion is this :
int ConvertSql(void *parser, const char *input, int64_t size, const char
**output, int64_t *out_size, int64_t *lines)
{
if(parser == NULL)
return -1;
SqlParser *sql_parser = (SqlParser*)parser;
// Run conversion
sql_parser->Convert(input, size, output, out_size, lines);
return 0;
}
I am calling the function in C#
char *parentInput;
fixed(char *input = &inputStr.ToCharArray()[0])
{
parentInput = input;
}
char** output = null;
Int64 out_size = 0;
Int64 lines = 0;
Int64 size = inputStr.Length;
Console.WriteLine(new IntPtr(&out_size)+" "+ new IntPtr(&lines)+" "+new IntPtr(&parserObj)+" "+new IntPtr(output));
int result = ConvertSql(&parserObj, intputStr, size, output, &out_size, &lines);
i get my parser object from this code which works without errors:
IntPtr parserObj = CreateParserObject();
the dllimport for the funtions are using this code:
[DllImport(dllName: "PATHTODLLFOLDER\\sqlparser.dll", EntryPoint = "CreateParserObject", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr CreateParserObject();
[DllImport(dllName: "PATHTODLLFOLDER\\sqlparser.dll", EntryPoint = "ConvertSql", CallingConvention = CallingConvention.Cdecl)]
public unsafe static extern int ConvertSql(void *parser, String input, Int64 size, char **output, Int64 *out_size, Int64 *lines);
In .NET, calling an unmanaged method through P/invoke (which is what happens when you call an extern method) involves various type conversions on the parameters, which is known as "marshalling" and is done automatically by a part of the runtime known as the "marshaller".
In general, it's a terrible idea to marshal pointers. Instead, use the CLR marshaller's ability to convert certain types to pointers for you by changing the signature of your P/invoked method:
// split on multiple lines for readability
[DllImport("PATHTODLLFOLDER\\sqlparser.dll", EntryPoint = "ConvertSql", CallingConvention = CallingConvention.Cdecl)]
public static extern int ConvertSql(
IntPtr parser,
[MarshalAs(UnmanagedType.LPStr)] string input,
long size,
out IntPtr output, // see explanation below
out long out_size,
out long lines);
A few things about the above. First, I took the liberty of using the C# type aliases (string, long), because that's more idiomatic C#, but it doesn't change the behavior. Also, since there are no pointers anymore, no need for unsafe.
First, I declared parser as an IntPtr because those get converted to void* automatically if needed and that's what's already returned by CreateParserObject() anyway.
Second, out parameters can be converted to pointers to uninitialized objects, so by marking both out_size and lines as out, you fix that other problem.
The input is a string, which has a specific format in .NET. Since your function takes a const char*, you need to tell the marshaller how to convert the characters. That's where the MarshalAs attribute comes in: it's when the default conversion doesn't work for you. UnmanagedType.LPStr means char* in this case, so the string gets converted. The runtime will manage the memory for you.
But here we hit a big snag in the road: the output. When marshalling things, there's always questions about lifetime, or, specifically: who releases the memory? The fact that output is a char** implies that the parser allocates a block of memory and then returns it through that, which means the caller has to release it. From the get go, that reeks of bad C++ design because the caller doesn't know how the memory was allocated. Was it with malloc? new[]? Platform specific APIs like LocalAlloc? Is it a pointer to a block of static memory? Usually these APIs come with documentation telling precisely what to do with the pointer once you're done with it. Good C++ APIs return smart pointers, or ask that the caller pass a block of previously allocated memory that they can then play with.
But, this is the thing you're playing with, so here's how to make it work. First, you'd think that you could declare output as [MarshalAs(UnmanagedType.LPStr)] out string: the marshaller will copy the characters into a managed string and return it... but then the native string's (on the C++ side) memory will leak because the runtime doesn't know how the string was allocated, so it prefers to not do anything about it. Also, this assumes the string is null-terminated, which might not always be the case.
So, another option would be to instead declare output as out IntPtr. Then you can use Marshal.PtrToStringAnsi to convert your pointer into a string, and then release it... but you'll need to know how it was allocated first.
Putting it all together:
var parserObj = CreateParserObject();
var output = IntPtr.Zero;
try
{
long lines;
long out_size;
int result = ConvertSql(parserObj, inputStr, inputStr.Length, out output, out out_size, out lines);
var outputStr = Marshal.PtrToStringAnsi(output, (int)out_size);
// do what you want with outputStr here
}
finally
{
if (output != IntPtr.Zero)
{
// release output here
}
}
Oh, also, one final thought: whatever is returned by CreateParserObject() will probably have to be freed at one point. You're probably going to need another function for it, probably like:
[DllImport(/* ... */)]
public static extern void DestroyParserObject(IntPtr parserObject);
It might even already exist in your DLL.
Good luck!
I have this COM method signature, declared in C#:
void Next(ref int pcch,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)]
char[] pchText);
I call it like this:
int cch = 100;
var buff = new char[cch];
com.Next(ref cch, buff);
Does the .NET interop layer first copy the whole array to a temporary unmanaged memory buffer, then copy it back? Or does the array get automatically pinned and passed by reference?
For the sake of trying, I did this in the COM object (C++):
*pcch = 1;
pchText[0] = L'A';
pchText[1] = L'\x38F'; // 'Ώ'
I do get 'Ώ' back when I check buff[1] in C# upon return. But I don't think this is a strong proof that the array gets pinned, rather than copied back and forth.
It isn't always easy to tell, particularly if you use an invalid declaration of course. A char[] can't be marshaled as LPWStr, it has to be LPArray. Now the CharSet attribute plays a role, since you did not specify it, the char[] will be marshaled as an 8-bit char[], not a 16-bit wchar_t[]. The marshaled array element is not the same size (it is not "blittable") so the marshaller must copy the array.
Pretty undesirable, particularly given that your C++ code expects wchar_t. A very easy way to tell in this specific case is not getting anything back in the array. If the array is marshaled by copying then you have to tell the marshaller explicitly that the array needs to be copied back after the call. You'd have to apply the [In, Out] attribute on the argument. You'll get Chinese.
The normal way to tell if the array gets marshaled by copying is by using the debugger. Enable unmanaged debugging in your C# program. Set a breakpoint on the call as well as a breakpoint in the first statement in the native function. When the 1st breakpoint hits, use Debug + Windows + Memory + Memory 1. Put buff in the Address box and switch the display to "4-byte Integer". You'll see the address of the array object, the 4-byte type handle, the 4-byte array length and the array content itself. So you know that if the array isn't copied that the passed addressed is the displayed address plus 8.
Press F5 to continue, the breakpoint in the native function hits. Look at the pchText argument, the debugger tells you its address. If it matches then the marshaller simply passed a pointer. If not then you got a copy of the array.
Let's do a small experiment. First, let's change your COM method to look like this (in C++):
STDMETHODIMP CComObject::Next(ULONG* pcch, int* addr, OLECHAR* pbuff)
{
pbuff[0] = L'A';
pbuff[1] = L'\x38F';
*addr = (int)pbuff;
*pcch = 1;
return S_OK;
}
Then, change the C# method signature:
void Next(ref uint pcch, out IntPtr addr,
[In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)]
char[] pbuff);
Finally, test it like this:
uint cch = 10;
var buff = new char[cch];
IntPtr addr1;
unsafe
{
fixed (char* p = &buff[0])
{
addr1 = (IntPtr)p;
}
}
IntPtr addr2;
com.Next(ref cch, out addr2, buff);
Console.WriteLine(addr1 == addr2);
As expected, addr1 == addr2 is true. Thus, apparently the array does get pinned rather than copied when passed to COM.
That said, I couldn't find any documentation which would feature this as a hard requirement for a CLR implementation. E.g., this may or may not be true for Mono.
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.
I am writing C# code that call a C library and something it is not quite clear in my mind.
The C function has this signature:
double* DoSomeStuff(double* input,int numberOfElements);
I have mapped the function as:
[System.Runtime.InteropServices.DllImportAttribute("myDll.dll", EntryPoint="DoSomeStuff")]
public static extern System.IntPtr DoSomeStuff(ref double input, int numberOfElements) ;
The input value is an array, so the C function will expect a contiguous memory layout. I am more familiar with C++ than C#. In C++ I'd used a std::vector to store the data and then I would use the data() method to get the pointer and exchange the information with C code. std::vector guarantees a contiguous layout memory.
Which data structure can I used in C#? Is there anything like std::vector in C#?
I have faced before the same problem for a string (In C++ std::string is just a std::vector with some make up). And I have solve the problem using:
System.IntPtr stringExample = Marshal.StringToHGlobalAnsi("StringExample");
The static function does the job for me. There is anything like this function for other types?
I have asked already too many questions, I think the most important one is: what is the best practise to solve this kind of problem?
Thanks
1)
Define the input as IntPtr:
[System.Runtime.InteropServices.DllImportAttribute("myDll.dll", EntryPoint="DoSomeStuff")]
public static extern System.IntPtr DoSomeStuff(IntPtr input, int numberOfElements) ;
2)
Create an array in a fixed block, then create an IntPtr from the Pointer and then pass it to DoSomeStuff.
double[] input = new double[20];
IntPtr result = IntPtr.Zero;
fixed(double* d = &input[0])
{
result = DoSomeStuff(new InptPtr(d), 20);
}
...
Reason for the fixed block is so that GC does not move the array while unmanaged code is populating it.
To make your example work you should define the siganture of the extern function as follows:
[System.Runtime.InteropServices.DllImportAttribute("myDll.dll", EntryPoint="DoSomeStuff")]
public static extern System.IntPtr DoSomeStuff([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)], int numberOfElements);
The second (named) parameter of MarshalAs attaribute tells to the marshaller where the size of the array stored.
Regarding the second question, C# has List<Type> class that behaves similary to std:vector<Type>. However, I don't think you can directly provide it to the marshaller. What you can do is to use ToArray() methor of the List class, to get an array.
Im using an P/invoke on an unmanaged dll function swe_calc_ut.
int swe_calc_ut(double tjd_et, int ipl, int iflag, double *xx, char *serr)
Parameter xx is meant to be an "array of 6 doubles for storing the result", and parameter serr a "character string to return error messages"
my c# code is as follows.
[DllImport("swedll32.dll")]
private static extern int swe_calc_ut(double tjd_ut, int ipl, int iflag, out double[] xx, out char[] serr);
double jul_day_UT=22000;
int p=3;
int iflag=64 * 1024;
double[] arr;
char[] serr;
int x = swe_calc_ut(jul_day_UT, p, iflag , out arr, out serr);
Now when i execute the function swe_calc_ut function i get the error "Exception of type 'System.ExecutionEngineException' was thrown.". I'm new to P/invoke so i'm probably making a stupid mistake. I thought it must be the arrays since earlier when i passed them by value accidentally i did not get an error. I'd really appreciate your help.
You don't have to use out or ref here. In fact, lose both of them. And preallocate both arrays to the desired size in C#.
It is a convention of the C language, you pass an array by passing a pointer to the first element of the array. So a double[] is already marshaled as a double*. When you use the out or ref keyword, you tell the marshaller that the function returns a pointer to a new array, a double**.
The function does not create a new array, it requires the client to pass an array that's large enough to receive the result. Therefore, neither the out nor the ref annotation is correct. The serr argument should be declared as StringBuilder btw.
The function is very dangerous since there is no way for the client to say how large an array it created. Particularly a problem with the serr argument. A detailed error message is prone to overrun the end of the array and that will destroy the garbage collected heap. Nothing you can do but pass a very large array (i.e. StringBuilder with a large Capacity) and keep your fingers crossed. Buffer overruns are the preferred attack vector for malware authors. Not likely to be abused in a managed program, it will just crash the app with FEEE.