1

I am working with a 3. party SDK, which is made up from .dll, .lib and .h files. I am using the .dll's to PInvoke against. And the .h files to see the function names and parameters. (So I am not using the .lib files).

The SDK is rather complex, so making the PInvoke wrappers have proven to be a challenge. All the functions/structs/enums is defined in the .h files.

My question is how to implement a pinvoke for a function with 2 **.

I expect it is my C# function definition that is wrong. When I call the function it simplely crashes, no exception throw or anything. The program just stops.

Function: GetInformatiuon(...)

//C Function: GetInformatiuon(...)
ERROR GetInformatiuon(
    Component comp, 
    struct Information** Info);

//C# Function: GetInformatiuon(...)
[DllImport("externalSDK.dll", EntryPoint = "GetInformatiuon", CallingConvention = CallingConvention.Cdecl)]
    public static extern ERROR GetInformatiuon(Component comp, ref Information Info);
);

Enum: ERROR

//C Enum: ERROR 
typedef enum ERROR_E {
    OK = 0, //Everything is ok
    E_ARG = 1, //Error in the Arguments 
    E_DATA = 2 //Data error
    //And more...
 } ERROR;

 //C# Enum: ERROR
 public enum ERROR
 {
    OK = 0, //Everything is ok
    E_ARG = 1, //Error in the Arguments 
    E_DATA = 2 //Data error
    //And more...
 }

Struct: Component

//C struct: Component
typedef struct Component_S
{
    void* ObjPointer;    
    unsigned long number; 
} Component;

//C# class: Component
[StructLayout(LayoutKind.Sequential)]
public class Component
{
    public IntPtr ObjPointer;
    public uint number; //uint because usigned long C is 4 bytes (32 bits) and C# ulong is 8 bytes (64 bits), where C# uint is 4 bytes(32 bits)
}

Struct: Information

 //C struct: Information
 typedef struct Information_S {
   char* language;           
   unsigned long sampleFrequency;  
   unsigned long frameShift;       
 }Information;

//C# struct: Information
[StructLayout(LayoutKind.Sequential)]
public struct Information
{
    public string language;   
    public uint sampleFrequency;  //uint because usigned long C is 4 bytes (32 bits) and C# ulong is 8 bytes (64 bits), where C# uint is 4 bytes(32 bits)
    public uint frameShift;       //uint because usigned long C is 4 bytes (32 bits) and C# ulong is 8 bytes (64 bits), where C# uint is 4 bytes(32 bits)
}
3
  • 3
    You'll have to declare it as out IntPtr. Then use Marshal.PtrToStructure() to convert it. Then fret a great deal on how you are going to get the memory that was allocated for the structure released again. It is a lousy signature, change the C code if you can. Commented Nov 21, 2013 at 16:39
  • As Hans said above, struct Information** in the signature means that you're pointing to the location in memory of another pointer and your C# extern function call doesn't get to deal with an actual Information struct unless you do some Marshalling Commented Nov 21, 2013 at 16:42
  • Sadly I cannot change the C signature. But I will try the "out IntPtr" solution Hans mentioned Commented Nov 21, 2013 at 16:50

1 Answer 1

1

I found the solution! (aka Hans Passant comment)

I changed the function to:

Function: GetInformatiuon(...)

//C Function: GetInformatiuon(...)
ERROR GetInformatiuon(
    Component comp, 
    struct Information** Info);

//C# Function: GetInformatiuon(...)
[DllImport("externalSDK.dll", EntryPoint = "GetInformatiuon", CallingConvention = CallingConvention.Cdecl)]
    public static extern ERROR GetInformatiuon(Component comp, out IntPtr InfoPtr);
);

Calling the function

IntPtr infoPtr;
lhErr = SDK.GetInformatiuon(component, out infoPtr);
Information info = (Information)Marshal.PtrToStructure(infoPtr, typeof(Information)) ;
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.