Question

I created a wrapper for a c console application where I define a struct to pass the output to a c# windows form. The struct contains a char* variable that must be correctly interpreted in the c# code. I used the IntPtr type but I did not obtain the wanted result, only a number which I think is the possible memory address.

C Part:

struct struct_name{
int a;
char* s;
}

extern __declspec(dllexport) struct_name compute_calc(int opt, char* file_1, char* file_2)

C# Part:

[DllImport("dll_name.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern struct_name compute_calc(int opt, String file1, String file2)

[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Auto)]    
public struct struct_name{
        Int32 a;
        IntPtr s;
        }

In the application I call the function with the following code

struct_name result = levenshtein(1, filePath1, filePath2);

My problem at this point is to use the char*/IntPtr to extract the string contained in the struct. I tried to use a marshalling operation as suggested in How can I convert an unmanaged IntPtr type to a c# string? but my result is only a number. Is there any other way to convert the IntPtr to the correct string used in the c code?

edit: the integer in the struct is correctly passed. The problem is only in the char*

edit2:

struct_name result;

{..some code...}--> output int N, char* s0


result.s = (char*)malloc( sizeof(char)*n);

result.a=N;
result.s=_strdup(s0)

return result;

This is the C part code as requested in a suggestion.

Was it helpful?

Solution

Marshal.PtrToStringAnsi() is what you need to convert your IntPtr to a string. The IntPtr holds a char*, and Marshal.PtrToStringAnsi() is your guy.

However, you've already tried that without success. So I suspect that your problem is more fundamental. Perhaps you have a binary mismatch in the way the two sides of the interop boundary treat the large struct. This is one part of interop where different tools behave differently. Structs should always be returned using out parameters. Change the native code to be like this:

__declspec(dllexport) int compute_calc(int opt, const char* file_1, 
    const char* file_2, struct_name* result)

And the managed side to be:

[StructLayout(LayoutKind.Sequential)]    
public struct struct_name{
    int a;
    IntPtr s;
}

[DllImport("dll_name.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int compute_calc(int opt, string file1, string file2,
    out struct_name result);

Note that I also removed the Pack = 1 from your struct declaration. Unless the C code uses #pragma pack, and it should not do so, then this would cause a mismatch under 64 bit code.

OTHER TIPS

To convert the IntPtr to a String use the Marshal.PtrToStringAnsi method

struct_name s = compute_calc(...);
string str = Marshal.PtrToStringAnsi(s.s);

Note that if the compute_calc function allocated memory it may need to be freed in managed code as well. Can't say for sure because it depends on implementation details of compute_calc

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top