none
Problems in passing arguments from managed code to unmanaged code RRS feed

  • Question

  • Hello,

    I am facing some issues in passing arguments from managed code to unmanaged code. I am having a C++ dll and i want to call few functions of it from a C# project (VS2010). C++ dll is not a native assembly or COM component. So i am using DllImport - P\Invoke.

    C++ function details

    typedef unsigned long UINT32;

    typedef UNIT32 ABC_RESULT; // the return code from a ABC function

    typedef UINT32 ABC_HOBJECT; // basic object handle

    typedef ABC_HOBJECT ABC_HCONTEXT; // context object handle

     

    ABC_RESULT Abc_Context_Create(

    ABC_HCONTEXT* phContext  // out

    );

    phContext - Receives the handle to the created context object.

     

    C# signature -

    public class Abc1api

    {

    [DllImport("Abc1.dll")]
    public static extern UInt32 Abc_Context_Create(UIntPtr phContext);

    }

    And i am calling it as below -

    UInt32 result = 0;

    UIntPtr hContext = new UIntPtr(sizeof(UInt32));

    result = Abc1api.Abc_Context_Create(hContext);

    I am able to build the project but while running i am getting below error -

    A call to PInvoke function 'ABCTool!ABCTool.Abc1api::Abc_Context_Create' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.

    I tried IntPtr hContext instead of UIntPtr but result is same.

    So i modified C# signature as mentioned below -

    public class Abc1api

    {

    [DllImport("Abc1.dll")]
    [return: MarshalAs(UnmanagedType.U4)]
    public static extern UInt32 Abc_Context_Create([MarshalAs(UnmanagedType.U4), Out()] IntPtr phContext);

    }

    And i am calling it as below -

    UInt32 result = 0;

    IntPtr hContext = new IntPtr(sizeof(UInt32));

    result = Abc1api.Abc_Context_Create(hContext);

    When i run it, the error is - Cannot marshal 'parameter #1': Invalid managed/unmanaged type combination (Int/UInt must be paired with SysInt or SysUInt).

    I tried UIntPtr but same result. Also tried allocating IntPtr hContext using Marshal i.e.

    IntPtr hContext = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(UInt32))); but getting same error as above.

    I could not find out the reason of this error. Can any one help me in defining C# signature and how can i pass the arguments so that i can get the required hContext from unmanaged code and use it?

    Thank you,

    Satish.

    • Moved by Leo Liu - MSFT Friday, January 21, 2011 8:20 AM Off-topic, moved for better support. (From:Visual C# General)
    Wednesday, January 19, 2011 9:11 AM

Answers

  • The "unbalanced stack" message can come from a wrong calling convention.

    Try this:

    [DllImport("Abc1.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern UInt32 Abc_Context_Create(out UInt32 phContext);
    
    

    Call it like this:

    UInt32 result;
    UInt32 hContext;
    result = Abc1api.Abc_Context_Create(out hContext);
    

    Using an IntPtr works, but passing a variable by reference is simpler.

    What is it you're trying to do with the "IntPtr hContext = new IntPtr(sizeof(UInt32));" statement? It creates a IntPtr with a value of 4 and I don't see why you're doing that.

    • Marked as answer by Cookie Luo Wednesday, January 26, 2011 9:16 AM
    Wednesday, January 19, 2011 10:42 AM