Question

  • I do not have complete access to the DLL source, only the header.
  • The names of the parameters in my actual code are more descriptive

I am trying to make a call to an unmanaged DLL that takes in all char * variables, with two of them acting as "return" values. in1-8 are the inputs, in9 and 10 are char * of length 512, and are passed in empty. Once the call completes, they should be filled with the result data.

Here's a sample definition that I'm attempting to work with:

[DllImport("mydll.dll")]
public static extern IntPtr foo(
    IntPtr in1,
    IntPtr in2,
    IntPtr in3,
    IntPtr in4,
    IntPtr in5,
    IntPtr in6,
    IntPtr in7,
    IntPtr in8,
    ref IntPtr result1,
    ref IntPtr result2);

Here's my call:

IntPtr param1 = Marshal.StringToHGlobalUni("testdata");
IntPtr param2 = Marshal.StringToHGlobalUni("testdata");
IntPtr param3 = Marshal.StringToHGlobalUni("testdata");
IntPtr param4 = Marshal.StringToHGlobalUni("testdata");
IntPtr param5 = Marshal.StringToHGlobalUni("testdata");
IntPtr param6 = Marshal.StringToHGlobalUni("testdata");
IntPtr param7 = Marshal.StringToHGlobalUni("testdata");
IntPtr param8 = Marshal.StringToHGlobalUni("testdata");
IntPtr param9 = IntPtr.Zero;
IntPtr param10 = IntPtr.Zero;

foo(param1, param2, param3, param4, param5, param6, param7, param8, ref param9, ref param10);

To print an IntPtr, I'm doing:

string str = Marshal.PtrToStringUni(param9);
Console.WriteLine(str);

In a "sample" given to me, the C++ call looks like this:

char result1[512]="";
char result2[512]="";
foo("testdata", "testdata", "testdata", "testdata", "testdata", "testdata", "testdata", "testdata", result1, result2);
printf("%s,%s\n",result1,result2);

The problem: In every way I've tried, including char[512] converted to byte[], StringBuilder size 512, IntPtr, etc. The param9 and param10 values are empty on every return. Can anyone help me figure this out? Thanks in advance.

EDIT After some helpful comments below and more google searches I patched my messy code to work. Here's the edits:

[DllImport("mydll.dll")]
public static extern IntPtr foo(
    IntPtr in1,
    IntPtr in2,
    IntPtr in3,
    IntPtr in4,
    IntPtr in5,
    IntPtr in6,
    IntPtr in7,
    IntPtr in8,
    IntPtr result1,
    IntPtr result2);

I got rid of the ref on the two result char arrays.

IntPtr param1 = Marshal.StringToHGlobalAnsi("testdata");
IntPtr param2 = Marshal.StringToHGlobalAnsi("testdata");
IntPtr param3 = Marshal.StringToHGlobalAnsi("testdata");
IntPtr param4 = Marshal.StringToHGlobalAnsi("testdata");
IntPtr param5 = Marshal.StringToHGlobalAnsi("testdata");
IntPtr param6 = Marshal.StringToHGlobalAnsi("testdata");
IntPtr param7 = Marshal.StringToHGlobalAnsi("testdata");
IntPtr param8 = Marshal.StringToHGlobalAnsi("testdata");
IntPtr param9 = Marshal.AllocHGlobal(512 * sizeof(int));
IntPtr param10 = Marshal.AllocHGlobal(512 * sizeof(int));

foo(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10);

Above I allocated param9 and 10 instead of IntPtr.Zero

//printing..
string str = Marshal.PtrToStringAnsi(param9);

Also a much simpler way using Strings, thanks to the answers below:

[DllImport("mydll.dll")]
public static extern IntPtr foo(
    string in1,
    string in2,
    string in3,
    string in4,
    string in5,
    string in6,
    string in7,
    string in8,
    StringBuilder result1,
    StringBuilder result2);

then:

StringBuilder resultA = new StringBuilder(512);
StringBuilder resultB = new StringBuilder(512);

foo("test", "test", "test", "test", "test", "test", "test", "test", resultA, resultB);

printing:

Console.WriteLine(resultA.ToString());

It looks much better now and actually works now, thanks guys! It's so easy to get confused with 50 tabs of google searches open.

Était-ce utile?

La solution

Assume you have the following c declaration

extern "C" __declspec(dllexport) {
    void foo(char * input, char * output);
}

I would define the following C# definition:

[DllImport("mydll.dll", EntryPoint="foo")]
public static extern void Foo(string input, StringBuilder output);

and the call would be like this:

string input = "input";
var output = new StringBuilder(512);
Foo(input, output);

If possible try to avoid unsafe code.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top