I am currently testing some PInvoke stuff and wrote a short C function to try some different things out. I successfully managed to pass Ints and return an addition, but I am having some trouble when it comes to strings.
Here is the C function:
__declspec(dllexport) int test(char *str, int slen){
for(int i = 0; i < slen; i++){
str[i] = 'a';
}
return slen;
}
And here is the C# function declaration and usage:
[DllImport("solver.dll", CharSet = CharSet.Ansi ,CallingConvention = CallingConvention.Cdecl)]
public static extern int test(StringBuilder sol, int len);
StringBuilder sol = new StringBuilder(15);
int ret = test(sol, sol.Capacity);
string str = sol.ToString();
I've been researching this for most of the day and I've seen several posts about simply passing a StringBuilder, filling it on the C end and it should be accessible when the function finishes. However I am currently getting an AccessViolation error in the C code as if the Memory hadn't been allocated, but I definitely allocate the Memory with new StringBuilder(15)
The C function definitely works if I allocate a piece of memory in the C code and pass it.
Is there something I am missing?
Sounds like you are missing to NUL-terminate the string buffer.
You may want to update your code like this:
for (int i = 0; i < (slen-1); i++) {
str[i] = 'a';
}
str[slen-1] = '\0'; // Add a NUL-terminator
Note that in this case I'm assuming the buffer length passed by the caller is the total length, including room for the NUL-terminator.
(Other conventions are possible as well, for example assuming the length passed by the caller excludes the NUL-terminator; the important thing is clarity of the interface documentation.)
I'd also like to add that a usual calling convention for those exported functions is __stdcall instead of __cdecl (although that's not correlated to your problem).
Related
This question already exists:
How to marshal an out string from native code [closed]
Closed 6 years ago.
Having a native function that returns a string (as char *) by parameter, what would be the best option between pre-allocating the char * via managed code and passing it by parameter and allocating the char * from inside the native code and then release it from c#?
could you kindly explain to me why should I use one over the other? Please answer only if there is a specific reason to prefer a solution over the other. If instead either solutions are ok, my question can be considered answered as well.
As bonus, I would like to know how I should allocate the char * variable from c# in the first case(using the Marshal class or with a simple new or with a StringBuilder like I often see in other answers?) and how I should delete the pointer if instead I create the char * variable from inside the native code in the second case.
It is usually not good practice to return a char* from a C function and expect it to be de-allocated by the caller. The caller may not do this (correctly or at all) and thus will leak memory. One common way to avoid this (as used by OpenGL, OpenCL and other libraries I've seen) is to declare the prototype as:
int GetString(char* str, int* len);
with an implementation like so:
int GetString(char* str, int* len)
{
if (str == NULL)
{
len = internal_get_string_length();
return 0; // No errors
}
else
{
if (len <= internal_get_string_length())
return -1; // not enough space in str
char* internal_str = internal_get_string_ptr();
strcpy(str, internal_str);
return 0;
}
}
The documentation will then state that if str is NULL, the length of the string to be returned is returned in len. Otherwise, the pointer str is expected to contain as many characters as required. In order to use it, the user calls the function twice, once with NULL for str and an int for len, then again with an allocated char array as long as len. A possibly prototype for P/Invoking this sort of function is:
// Declaration
[DllImport("myDll.dll")]
int GetString(StringBuilder sb, ref int len);
// Usage
int length;
GetString(null, length);
var sb = new StringBuilder(length); // Set capacity
GetString(sb, length);
Console.WriteLine(sb.ToString()); // Do stuff with C# string
Hope that helps!
I have the following test function set up in a C project:
__declspec(dllexport) int test(char *str, int strlen){
char* h = "Hello";
int length = 5;
for(int i = 0; i < length; i++){
str[0] = h[0];
}
return strlen;
}
And in my C# project I declare the method as follows:
[DllImport("solver.dll", CharSet = CharSet.Unicode ,CallingConvention = CallingConvention.Cdecl)]
public static extern int test(StringBuilder sol, int len);
And I try to use it in my project like so:
StringBuilder sol = new StringBuilder(15);
int t = test(sol, sol.Capacity);
string str = sol.ToString();
I'd like to pass "Hello" back to the C# code as a test, but when I run the code the StringBuilder stays empty, and even though 15 is passed to the C function as the length, when the C function returns the length it returns a 'random' large number like 125822695. What am I missing?
A number of problems:
You state CharSet.Unicode in the C#, but use ANSI in the unmanaged code.
You only write to the first character.
You ignore the value of strlen passed to the function.
You don't attempt to write a null-terminator.
As for the value returned from the function, that cannot be explained by the code that you present. There is something missing from your question that we need to see in order to explain that.
It is quite common when we see these questions, that the unmanaged code is clearly broken. It's hard enough to write correct p/invokes to correct unmanaged code. Trying to debug the p/invoke and the unmanaged code at the same time is so much harder. Test your unmanaged code in an unmanaged setting first. Only when you are confident it is correct should you move to write your p/invoke.
interoping nim dll from c# i could call and execute the code below
if i will add another function (proc) that Calls GetPacks() and try to echo on each element's buffer i could see the output in the C# console correctly
but i could not transfer the data as it is, i tried everything but i could not accomplish the task
proc GetPacksPtrNim(parSze: int, PackArrINOUT: var DataPackArr){.stdcall,exportc,dynlib.} =
PackArrINOUT.newSeq(parSze)
var dummyStr = "abcdefghij"
for i, curDataPack in PackArrINOUT.mpairs:
dummyStr[9] = char(i + int8'0')
curDataPack = DataPack(buffer:dummyStr, intVal: uint32 i)
type
DataPackArr = seq[DataPack]
DataPack = object
buffer: string
intVal: uint32
when i do same in c/c++ the type i am using is either an IntPtr or char*
that is happy to contain returned buffer member
EXPORT_API void __cdecl c_returnDataPack(unsigned int size, dataPack** DpArr)
{
unsigned int dumln, Index;dataPack* CurDp = {NULL};
char dummy[STRMAX];
*DpArr = (dataPack*)malloc( size * sizeof( dataPack ));
CurDp = *DpArr;
strncpy(dummy, "abcdefgHij", STRMAX);
dumln = sizeof(dummy);
for ( Index = 0; Index < size; Index++,CurDp++)
{
CurDp->IVal = Index;
dummy[dumln-1] = '0' + Index % (126 - '0');
CurDp->Sval = (char*) calloc (dumln,sizeof(dummy));
strcpy(CurDp->Sval, dummy);
}
}
c# signature for c code above
[DllImport(#"cdllI.dll", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
private static extern uint c_returnDataPack(uint x, DataPackg.TestC** tcdparr);
C# Struct
public unsafe static class DataPackg
{
[StructLayout(LayoutKind.Sequential)]
public struct TestC
{
public uint Id;
public IntPtr StrVal;
}
}
finally calling the function like so:
public static unsafe List<DataPackg.TestC> PopulateLstPackC(int ArrL)
{
DataPackg.TestC* PackUArrOut;
List<DataPackg.TestC> RtLstPackU = new List<DataPackg.TestC>(ArrL);
c_returnDataPack((uint)ArrL, &PackUArrOut);
DataPackg.TestC* CurrentPack = PackUArrOut;
for (int i = 0; i < ArrL; i++, CurrentPack++)
{
RtLstPackU.Add(new DataPackg.TestC() { StrVal = CurrentPack->StrVal, Id = CurrentPack->Id });
}
//Console.WriteLine("Res={0}", Marshal.PtrToStringAnsi((IntPtr)RtLstPackU[1].StrVal));//new string(RtLstPackU[0].StrVal));
return RtLstPackU;
}
how could i produce similar c code as above from Nim ?
it doesn't have to be same code, but same effect, that in c# i would be able to read the content of the string. for now, the int is readable but the string is not
Edit:
this is what i tried to make things simple
struct array of int members
Update:
it seem that the problem is to do with my settings of nim in my windows OS.
i will be updating as soon as i discover what exactly is wrong.
The string type in Nim is not equivalent to the C's const char* type. Strings in Nim are represented as pointers, pointing into a heap-allocated chunk of memory, which has the following layout:
NI length; # the length of the stored string
NI capacity; # how much room do we have for growth
NIM_CHAR data[capacity]; # the actual string, zero-terminated
Please beware that these types are architecture specific and they are really an implementation detail of the compiler that can be changed in the future. NI is the architecture-default interger type and NIM_CHAR is usually equivalent to a 8-bit char, since Nim is leaning towards the use of UTF8.
With this in mind, you have several options:
1) You can teach C# about this layout and access the string buffers at their correct location (the above caveats apply). An example implementation of this approach can be found here:
https://gist.github.com/zah/fe8f5956684abee6bec9
2) You can use a different type for the buffer field in your Nim code. Possible candidates are ptr char or the fixed size array[char]. The first one will require you to give up the automatic garbage collection and maintain a little bit of code for manual memory management. The second one will give up a little bit of space efficiency and it will put hard-limits on the size of these buffers.
EDIT:
Using cstring may also look tempting, but it's ultimately dangerous. When you assign a regular string to a cstring, the result will be a normal char * value, pointing to the data buffer of the Nim string described above. Since the Nim garbage collector handles properly interior pointers to allocated values, this will be safe as long as the cstring value is placed in a traced location like the stack. But when you place it inside an object, the cstring won't be traced and nothing prevents the GC from releasing the memory, which may create a dangling pointer in your C# code.
Try to change your struct to:
public unsafe static class DataPackg
{
[StructLayout(LayoutKind.Sequential)]
public struct TestC
{
public uint Id;
[MarshalAs(UnmanagedType.LPStr)]
public String StrVal;
}
}
I'm trying to populate an array of structures from C++ and pass the result back to C#.
I thought maybe creating a struct with an array of structures maybe the way forward as most examples I have come across use structures(but passing basic types). I have tried the following but no luck so far.
Found an example at: http://limbioliong.wordpress.com/2011/08/20/passing-a-pointer-to-a-structure-from-c-to-c-part-2/?relatedposts_exclude=542
I have the following in C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace CSharpDLLCall
{
class Program
{
[StructLayout(LayoutKind.Sequential,Pack=8)]
public struct Struct1
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public double[] d1;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public double[] d2;
}
[StructLayout(LayoutKind.Sequential)]
public struct TestStructOuter
{
public int length;
public IntPtr embedded;
}
static void Main(string[] args)
{
Program program = new Program();
program.demoArrayOfStructs();
}
public void demoArrayOfStructs()
{
TestStructOuter outer = new TestStructOuter();
testStructOuter.embedded = new Struct1[10];
outer.length = 10;
outer.embedded = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Struct1)) * 10);
Marshal.StructureToPtr(outer, outer.embedded, false);
testAPI2(ref outer);
outer = (TestStructOuter)(Marshal.PtrToStructure(outer.embedded, typeof(TestStructOuter)));
Marshal.FreeHGlobal(outer.embedded);
}
[DllImport(#"C:\CPP_Projects\DLL\DLLSample\Release\DLLSample.dll")]
static extern void testAPI2(IntPtr pTestStructOuter);
}
}
In C++ in the header i have
#ifdef DLLSAMPLE_EXPORTS
#define DLLSAMPLE_API __declspec(dllexport)
#else
#define DLLSAMPLE_API __declspec(dllimport)
#endif
#include <iostream>
using namespace std;
#pragma pack(1)
struct struct1
{
double d1[];
double d2[];
};
struct TestStructOuter
{
struct1* embedded;
};
extern "C"
{
DLLSAMPLE_API void __stdcall testAPI2(TestStructOuter* pTestStructOuter);
}
In the cpp I have:
#include "stdafx.h"
#include "DLLSample.h"
__declspec(dllexport) void __stdcall testAPI2(TestStructOuter* pTestStructOuter)
{
// not sure that this is necessary
// for (int i = 0; i < 10 ; ++i)
// {
// pTestStructOuter->embedded = new struct1;
// }
for (int i = 0; i < 10 ; ++i)
{
struct1 s1;
for (int idx = 0; idx < 10; ++idx)
{
s1.d1[i] = i+0.5;
s1.d2[i] = i+0.5;
}
pTestStructOuter->embedded[0] = s1;
}
}
This doesn't seem to work the error i get:
The parameter is incorrect.(Exception from HRESULT:0x80070057 (E_INVALIDARG))
Which probably means that its not recognizing the array of structures. Any ideas how I can do this? Thanks.
Okay, I have a working sample. I'm posting this as another answer because it's a very different approach.
So, on the C++ side, I've got this header file:
struct Struct1
{
int d1[10];
int d2[10];
};
extern "C" __declspec(dllexport) void __stdcall
TestApi2(int* pLength, Struct1 **pStructures);
And the following code:
__declspec(dllexport) void __stdcall
TestApi2(int* pLength, Struct1 **pStructures)
{
int len = 10;
*pLength = len;
*pStructures = (Struct1*)LocalAlloc(0, len * sizeof(Struct1));
Struct1 *pCur = *pStructures;
for (int i = 0; i < len; i++)
{
for (int idx = 0; idx < 10; ++idx)
{
pCur->d1[idx] = i + idx;
pCur->d2[idx] = i + idx;
}
pCur ++;
}
}
Now, the important bit is LocalAlloc. That's actually the place where I've had all the issues, since I allocated the memory wrong. LocalAlloc is the method .NET calls when it does Marshal.AllocHGlobal, which is very handy, since that means we can use the memory in the caller and dispose of it as needed.
Now, this method allows you to return an arbitrary length array of structures. The same approach can be used to eg. return a structure of an array of structures, you're just going deeper. The key is the LocalAlloc - that's memory you can easily access using the Marshal class, and it's memory that isn't thrown away.
The reason you have to also return the length of the array is because there's no way to know how much data you're "returning" otherwise. This is a common "problem" in unmanaged code, and if you've ever done any P/Invoking, you know everything about this.
And now, the C# side. I've tried hard to do this in a nice way, but the problem is that arrays of structures simply aren't blittable, which means you can't simply use MarshalAs(UnmanagedType.LPArray, ...). So, we have to go the IntPtr way.
The definitions look like this:
[StructLayout(LayoutKind.Sequential)]
public class Struct1
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public int[] d1;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public int[] d2;
}
[DllImport(#"Win32Project.dll", CallingConvention = CallingConvention.StdCall)]
static extern void TestApi2(out int length, out IntPtr structs);
Basically, we get a pointer to the length of the "array", and the pointer to the pointer to the first element of the array. That's all we need to read the data.
The code follows:
int length;
IntPtr pStructs;
TestApi2(out length, out pStructs);
// Prepare the C#-side array to copy the data to
Struct1[] structs = new Struct1[length];
IntPtr current = pStructs;
for (int i = 0; i < length; i++)
{
// Create a new struct and copy the unmanaged one to it
structs[i] = new Struct1();
Marshal.PtrToStructure(current, structs[i]);
// Clean-up
Marshal.DestroyStructure(current, typeof(Struct1));
// And move to the next structure in the array
current = (IntPtr)((long)current + Marshal.SizeOf(structs[i]));
}
// And finally, dispose of the whole block of unmanaged memory.
Marshal.FreeHGlobal(pStructs);
The only thing that changes if you want to really return a structure of an array of structures is that the method parameters move into the "wrapping" structure. The handy thing is that .NET can automatically handle the marshalling of the wrapper, the less-handy thing is that it can't handle the inner array, so you again have to use length + IntPtr to manage this manually.
First, don't use unknown-length arrays at all. You're killing any possible use of arrays between managed and unmanaged code - you can't tell the required size (Marshal.SizeOf is useless), you have to manually pass the array length etc. If it's not a fixed length array, use IntPtr:
[StructLayout(LayoutKind.Sequential,Pack=8)]
public struct Struct1
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public double[] d1;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public double[] d2;
}
[StructLayout(LayoutKind.Sequential)]
public struct TestStructOuter
{
public int length;
public IntPtr embedded;
}
(if your array of embedded is fixed length, feel free to ignore this, but do include the ByValArray, SizeConst bit. You also have to add ArraySubType=System.Runtime.InteropServices.UnmanagedType.Struct to the attribute).
As you've probably noticed, the TestStructOuter is pretty much useless in this case, it only adds complexity (and do note that marshalling is one of the most expensive operations compared to native languages, so if you're calling this often, it's probably a good idea to keep things simple).
Now, you're only allocating memory for the outer struct. Even in your code, Marshal.SizeOf has no idea how big the struct should be; with IntPtr, this is even more so (or, to be more precise, you're only requesting a single IntPtr, ie. 4-8 bytes or so + the length). Most often, you'd want to pass the IntPtr directly, rather than doing this kind of wrapping (using the same thing in C++/CLI is a different thing entirely, although for your case this is unnecessary).
The signature for your method will be something like this:
[DllImport(#"C:\CPP_Projects\DLL\DLLSample\Release\DLLSample.dll",
CallingConvention=System.Runtime.InteropServices.CallingConvention.StdCall)]
public static extern void testAPI2(ref TestStructOuter pTestStructOuter) ;
Now, if you're going with the IntPtr approach, you want to keep allocating memory manually, only you have to do it properly, eg.:
TestStructOuter outer = new TestStructOuter();
testStructOuter.length = 1;
testStructOuter.embedded = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Struct1)));
Marshal.StructureToPtr(embedded, testStructOuter.embedded, false);
And finally, you call the method:
// The marshalling is done automatically
testAPI2(ref outer);
Don't forget to release the memory, ideally in the finally clause of a try around everything since the memory allocation:
Marshal.FreeHGlobal(outer.embedded);
Now, this is overly complicated and not exactly optimal. Leaving out the TestStructOuter is one possibility, then you can simply pass the length and pointer to the embedded array directly, avoiding one unnecessary marshalling. Another option would be to use a fixed size array (if it needs to be an array at all :)) in TestStructOuter, which will cure a lot of your headaches and eliminate any need for manual marshalling. In other words, if TestStructOuter is defined as I've noted before:
[StructLayout(LayoutKind.Sequential)]
public struct TestStructOuter
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10,
ArraySubType=UnmanagedType.Struct)]
public Struct1[] embedded;
}
Suddenly, your whole call and everything becomes as simple as
testAPI2(ref outer);
The whole marshalling is done automatically, no need for manual allocations or conversions.
Hope this helps :)
Hint: Leadn C++/CLI. I had to deal with complex interop two times in my life - once with ISDN (AVM devkits make it a lot easier - sadly C++, I needed C#) and now with Nanex (great real time complex and full market ata feeds, sadl complex C++, I need C#)
Both cases I make my own wrapper in C++/CLI, talking down to C++ and exposing a real object model in C#. Allows me to make things a lot nicer and handle a lot of edge cases that our friendly Marshaller can not handle efficiently.
I have C# code that calls a C dll. The dll has the following global const array of strings:
const char *PtxEditorColumnHeaders[] = {
"Ptx#",
"Primitive",
"PtxType",
"_END_COLUMNS"
};
All I want to do is grab this text and stuff it into the Column text of a ListView control.
I have found there are several ways to do this, using Pinvoke, strcpy, etc. But, since I'm still learning c# and so far uncorrupted in my ways, what is the best practices way to do this?
Write a C function to return the pointer to the first element of the array, and the number of elements:
const char **GetPtxEditorColumnHeaders(int *count)
{
*count = 4;//or however you want to get hold of this information
return PtxEditorColumnHeaders;
}
And then declare the p/invoke:
[DllImport(#"mydll.dll", CallingConvention=CallingConvention.Cdecl)]
static extern IntPtr GetPtxEditorColumnHeaders(out int count);
Call the function like this:
int count;
IntPtr PtxEditorColumnHeaders = GetPtxEditorColumnHeaders(out count);
List<string> headers = new List<string>();
for (int i=0; i<count; i++)
{
IntPtr strPtr = Marshal.ReadIntPtr(PtxEditorColumnHeaders);
headers.Add(Marshal.PtrToStringAnsi(strPtr));
PtxEditorColumnHeaders += Marshal.SizeOf(typeof(IntPtr));
}
This stuff gets tedious pretty quickly, at which point a C++/CLI wrapper begins to look like a more attractive option.