I need to call a function from a C api contained in a dll. Function prototype looks as follows....
int func( char* name, void* value );
where the contents of the pointer value can refer to any type dependent on the passed name. I an unsure how to set up the Dll inport to correctly marshall this void *. Ihave been experimenting with IntPtr which seems to work whe the value is an int but I cannot retrieve values correctly for floats etc.
I am trying to import the function like this...
[DllImport("dllname.dll", CharSet = CharSet.Ansi)]
public static extern int func( string name, ref IntPtr value );
pls note that value is an output. A pointer to a value of any type, i.e. the address in a global region of memory of a value of a known type (known to the caller). In a c prog the caller would then be expected to cast this void * to the desired type and dereference to get the actual value stored there. The answers given so far seem to be based around an assumption that the function will write the result to pointer location passed in. My fault as I haven't been too specific. Sorry. C# is not my bag, and I don't even know if IntPtr is the way to go here...
The best way to tackle this is to provide overloads of the function so everything is squeaky clean on the C# side. Like this:
[DllImport("dllname.dll", CharSet = CharSet.Ansi)]
public static extern int func(string name, out int value);
[DllImport("dllname.dll", CharSet = CharSet.Ansi)]
public static extern int func(string name, out float value);
// etc, one each for each type
[DllImport("dllname.dll", CharSet = CharSet.Ansi)]
public static extern int func( string name, IntPtr value );
...
// n - number of bytes which is enough to keep any type used by function
IntPtr ptr = Marshal.AllocHGlobal(n);
func(name, ptr);
// Use Marshal.ReadByte, Marshal.ReadInt32 ... or Marshal.Copy
// to copy from ptr filled by func to managed variable. For example:
byte b = Marshal.ReadByte(ptr);
Marshal.FreeHGlobal(IntPtr);
You do not need the ref - IntPtr is the way to pass void* to native code.
[DllImport("dllname.dll", CharSet = CharSet.Ansi)]
public static extern int func( string name, IntPtr value );
EDIT:
The C code can use the input to write to the required memory. The problem you face is for the managed code to know how much memory to allocate for each possible return value type. Then an appropriate sized block can be allocated using Marshal.AllocHGlobal or Marshal.AllocCoTaskMem, freed (according to which allocation method you use) use via FreeHGlobal or FreeCoTaskMem, once managed code is done with the output value.
See answer from #Alex Farber for an example.
Sometimes, it might be easier to use this approach.
Declaration:
[DllImport("dllname.dll", CharSet = CharSet.Ansi)]
public static extern int func([MarshalAs(UnmanagedType.LPTStr)] string name, [MarshalAs(UnmanagedType.AsAny)] object value);
Example usage to pass a value:
func("some string", (int)12);
func("some string", (double)12);
Example usage to pass a string:
func("some string", "test");
Example usage to pass a variable:
int value = 12;
func("some string", value);
Related
I am given a Delphi DLL that contains functions that I need to call in C#. One of the functions takes two char arrays, where one is an encrypted password and the other is the key.
TCString = array[0..254] of Char;
...
function Decrypt(const S, Key: TCString): TCString; stdcall;
I tried to figure out how to call this function on my own but I keep getting "Cannot marshal 'return value': Invalid managed/unmanaged type combination." I am using byte since the Char type in Delphi is AnsiChar which is 8 bits.
[DllImport("path", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
public static extern byte[] Decrypt(byte[] S, byte[] Key);
What is the correct way to call this in C#?
I think I would be inclined to wrap the fixed length array in a C# struct.
public struct CString
{
[UnmanagedType.ByValArray(SizeConst=255)]
byte[] value;
}
This allows the size to be specified in one place only.
The next hurdle is the return value. The Delphi ABI treats a return value that cannot fit into a register as an additional hidden var parameter. I'll translate that as a C# out parameter.
Finally the two input parameters are declared as const. That means that they are passed by reference.
So the function would be:
[DllImport(dllname, CallingConvention = CallingConvention.StdCall)]
public static extern void Decrypt(
[In] ref CString S,
[In] ref CString Key,
out CString Result
);
I've intentionally avoided any use of text in this because this would appear to be a function that operates on binary data. Many Delphi programmers treat AnsiChar arrays interchangeably with byte arrays in such situations which is often confusing.
I'm trying to pass string from c++ to c#.
C++:
extern "C" __declspec(dllexport) void GetSurfaceName(wchar_t* o_name);
void GetSurfaceName(wchar_t* o_name)
{
swprintf(o_name, 20, L"Surface name");
}
C#:
[DllImport("SurfaceReader.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void GetSurfaceName(StringBuilder o_name);
StringBuilder name = new StringBuilder(20);
GetSurfaceName(name);
But only first symbol is passed: name[0] == 'S'. Other symbols are nulls. Could you tell me what is wrong here?
Thanks,
Zhenya
You forgot to tell the pinvoke marshaller that the function is using a Unicode string. The default is CharSet.Ansi, you'll need to use CharSet.Unicode explicitly. Fix:
[DllImport("SurfaceReader.dll",
CallingConvention = CallingConvention.Cdecl,
CharSet = CharSet.Unicode)]
private static extern void GetSurfaceName(StringBuilder o_name);
You'll get a single "S" now because the utf-16 encoded value for "S" looks like a C string with one character.
Do in general avoid magic numbers like "20". Just add an argument that say how long the string buffer is. That way you'll never corrupt the GC heap by accident. Pass the StringBuilder.Capacity. And give the function a return value that can indicate success so you also won't ignore a buffer that's too small.
I am not sure, but instead of using StringBuilder, I would pass from C# char (wchar) array to C++, fill it and then operate with this array in C#.
I have a problem with calling a C DLL fom C#
The C function is (I don't have a c header or a good spec for this :( )
int knr12_read ( char *kn12, char *ik9, char *wok, char *wlc,
char *plz, char *ort, char *woz );
kn12 is a ref parameter
This is what I've tried in C#
[return: MarshalAs(UnmanagedType.U4)]
[DllImport("Knr12.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "knr12_read", CharSet = CharSet.Ansi)]
unsafe public static extern int knr12_read(out IntPtr buffer, string ik9, string wok, string wlc, string plz, string ort, string woz);
int knr = knr12_read(out pBuffer, knrTemp, "11111", "", "98529", "Suhl", "1");
string data = Marshal.PtrToStringAnsi(pBuffer);
The returning int is always right, how it should be, but I have problems with the ref parameter pBuffer...
Also the sting type for the other variables is working...
When I use a ref,I always get an AccessViolation error knr12_read().In case I use out I get a pointer,but the String is always empty which can't be.I even tried out String as ref for char* but I get an AccessViolation error on knr12_read().
Please guide.
StringBuilder is often a good type to use when P/Invoking to functions with string returning parameters:
static extern int knr12_read(StringBuilder kn12, ...)
You'll need to initialise the string builder before you call the function, something like:
StringBuilder outString = new StringBuilder(100);
You shouldn't need the 'unsafe', and unless the 'C' code holds onto the pointers for longer than the duration of the call, you shouldn't need to worry about pinning - the framework is doing that for you.
Here's a SO question which should help: Marshal "char *" in C#
Probably you have not pinned the buffer. here is the example of how to pin the buffer data.
GCHandle pinnedRawData = GCHandle.Alloc(rawData,
GCHandleType.Pinned);
Pinning the object makes sure that the pointer is valid cause .Net runtime can always reallocate the memory as and when it thinks fit.
Try it out and let me know if it helps you.
I need to make interop calls to a DLL written in C++. In the C++ code, there are various functions that receive and return strings. These all use a commonly defined type (struct) in C++, which comprises a pointer to a string along with an integer for its size as follows:
struct StringParam
{
int size; // 4 byte integer for the size of the string buffer
LPWSTR buff; // Pointer to a wide char buffer
}
When a string is returned from the DLL and when the string buffer is too small to store the string result, an error code is returned along with the correct size buffer that is required in the integer size field, so that the caller can provide the right size buffer.
Ignoring the struct for the moment, this could be easily accomplished through interop using the combination of a StringBuilder parameter, along with a ref int parameter for the size. However, we are using a struct and StringBuilder fields are not permitted in structs that are marshalled.
Given a C++ function that receives a string as follows:
int __stdcall DoSomethingWithString(StringParam *stringParam)
One can declare the following struct in C#:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct StringParam
{
public int Size;
[MarshalAs(UnmanagedType.LPWStr)]
public string Text;
public StringParam(string text)
{
this.Text = text;
this.Size = text.Length;
}
}
and can successfully initialize a struct and call a C++ function with the following signature:
[DllImport("Custom.dll", CharSet = CharSet.Unicode)]
public static extern int DoSomethignWithString(ref StringParam stringParam);
However, given a function that needs to return a string as follows, presents a problem:
[DllImport("Custom.dll", CharSet = CharSet.Unicode)]
public static extern int GetSomeString(ref StringParam stringParam);
When receiving a string from the interop call, we do not know the size of the string and must allocate a buffer sufficient in size for storing the string result. StringBuilder would be ideal, but cannot be used within a struct that is marshalled. We could pre-allocate the string with 2048 dummy characters, which could then be used to store the results. This is in fact recommended in the error message one gets when attempting to use the StringBuilder type:
Cannot marshal field 'Text' of type 'StringParam': Struct or class fields cannot be of type StringBuilder. The same effect can usually be achieved by using a String field and preinitializing it to a string with length matching the length of the appropriate buffer.
This seems kind of messy to pre-initialize a string with dummy values. Is there another/better way to go about this?
Hey!
I've just begun fiddling with pinvoke and have encountered a problem. I'm getting the AccessViolationException. First of all, is there some way to debug or trace out which field is causing this error? The only thing being written to is the result struct.
The c++ call looks like:
MyFunc(int var1, _tuchar *var2, _tuchar *var3, _tuchar *var4, MyStruct *Result,
_tuchar *var5, _tuchar *var6);
The c++ struct:
typedef struct MyStruct
{
_tuchar *id;
_tuchar *ErrorMessages;
int int1;
_tuchar language[3];
_tuchar *result;
int type;
int number;
int *type2;
_tuchar **blocks;
}
The C# struct:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct MyStruct
{
[MarshalAs(UnmanagedType.LPStr)]
public string Id;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=500)]
public char[] ErrorMessages;
public int int1;
[MarshalAs(UnmanagedType.LPStr)]
public string language;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)]
public char[] result;
public int type;
public int number;
public int type2;
[MarshalAs(UnmanagedType.ByValArray)]
public string[] blocks;
The C# method declaration:
[DllImport(MyPath, EntryPoint = "MyEntryPoint", SetLastError = true,
CharSet = CharSet.Unicode)]
internal static extern int MyFunc(int var1, string var2, string var3,
string var4, ref MyStruct Result, string var5, string var6);
The C# Call:
var result = new MyStruct();
MyFunc(0, "var2", "var3", "var4", ref result, "var5", "var6");
Hope I haven't left anything out.
Thanks for any help!
Ooooh, man! You've picked quite a complex case for your first fiddling experience. I recommend doing something simpler first, and then moving on to the real stuff.
Firstly, CharSet=CharSet.Ansi looks suspicious. All your strings and chars are _tuchar, and I gather the u in there means "Unicode", doesn't it? If that's the case, you need CharSet=CharSet.Unicode.
Secondly, (and this is the most likely culprit) why is the ErrorMessages field marshaled as ByValArray? You know that ByVal here means "by value", don't you? As in, not by reference. And you know that little asterisk thing in C++ means "reference", don't you? So why does your reference field ErrorMessages marshaled as a by-value array? In case you don't know, an array is generally said to be passed "by value" when all of it's content is being passed, instead of just passing a reference (pointer) to a memory location where all that content is stored. In C++ struct definition, you specify _tuchar*, which means "a reference (pointer) to some memory containing one or more of _tuchars", whereas in C# you specify [MarshalAs(UnmanagedType.ByValArray, SizeConst=500)], which means "500 _tuchars are supposed to be here, no more and no less". Seeing how a reference (pointer) usually takes 4 bytes (or 8 bytes on 64bit machines), and 500 unicode characters take 1000 bytes, you have an obvious mismatch right here.
Thirdly and fourthly, same point goes for result and blocks fields.
Fifthly, the language field is exactly reverse situation: the C++ code says "there are 3 _tuchars here", while C# code says "there is a reference (pointer) to a string here" (in case you don't know, LPStr means "Long Pointer to STRing")
And finally, after you have fixed all those problems, I recommend you execute your program and print out the result of call to Marshal.SizeOf( typeof( MyStruct ) ). That will give you exactly how big your struct is, in .NET's opinion. The go on the C++ side and print out sizeof( MyStruct ). That will give you what C++ thinks about the size.
If they turn out different, see what's wrong. Try to remove fields one by one, until they become same. This will give you the culprit field(s). Work with them.
Overall, I suggest you need a better understanding of how things work first. This case is waaaay too complex for a beginner.
Good luck!
This is a bit of a shot in the dark, but have you tried decorating the string parameters with MarshalAs(UnmanagedType.LPWStr):
[DllImport(MyPath, EntryPoint = "MyEntryPoint", SetLastError = true,
CharSet = CharSet.Unicode)]
internal static extern int MyFunc(
int var1,
[MarshalAs(UnmanagedType.LPWStr)]
string var2,
[MarshalAs(UnmanagedType.LPWStr)]
string var3,
[MarshalAs(UnmanagedType.LPWStr)]
string var4,
ref MyStruct Result,
[MarshalAs(UnmanagedType.LPWStr)]
string var5,
[MarshalAs(UnmanagedType.LPWStr)]
string var6);
I believe that the default marshaling chosen for strings is BStr and _tuchar should expand to wchar_t so I'd guess that LPWStr is the correct marshalling method (pointer to a wide character string).
Update: Various things on MyStruct don't look quite right:
ErrorMessages is marked as ByValArray, and so the .Net interop is probably expecting MyStruct to look a bit like this:
typedef struct MyStruct
{
_tuchar *id;
_tuchar ErrorMessages[500];
// Rest of MyStruct
Which is probably going to cause problems - same thing for result.
Also I think that language should be using ByValArray with a size of 3.
Finally blocks should probably be passed using LPArray - ByValArray doesn't seem right.
(This is all mostly guesswork btw - I hope this is pointing you in the right direction but I don't have that much experience with P/Invoke interop)
Another update: On MyStruct you declare the charset to be Ansi, but on MyFunc its Unicode... is the unmanaged dll compiled with Unicode or Ansi? If it uses Unicode then I believe that you should use LPWStr when marshalling strings, and with Ansi it should be LPStr.