Passing structure to unmanaged code from C#

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • JeepRubicon
    New Member
    • Oct 2011
    • 2

    Passing structure to unmanaged code from C#

    Hi all,

    I've been fighting this problem for some time now and am hoping someone can help. I'm converting a VB6 application to C#. Everything I'm about to show works perfect in VB6, but fails in C#.

    I'm making an API call into a C dll, passing a structure. The structure gets values modified in the C side and I should see the modified values in my return structure.

    Here are the C structures:

    Code:
    typedef struct
    {
    	short				vers;				
    	short				flags;				
    	short				cmd;				
    	short				objtype;			
    	DWORD				id;					
    	DWORD				client;				
    	char				buf[MAX_TOOLBUF];	
    	DWORD				toolID;				
    	NMSG				msg;				
    	DWORD				caller;				
    	CLIENTID			clientID;			
    	DWORD				ticket;				
            long				spare[4];			
    } Request;
    
    typedef struct
    {
    	DWORD		hwnd;
    	DWORD		message;
    	DWORD		wParam;
    	DWORD		lParam;
    
    } NMSG;
    In my C# code, I have the following structs defined to map to the C structs above:
    Code:
           [StructLayout(LayoutKind.Sequential)]
            public struct NMSG
            {
                [MarshalAs(UnmanagedType.U4)]
                public int hWnd;
                [MarshalAs(UnmanagedType.U4)]
                public int msg;
                [MarshalAs(UnmanagedType.U4)]
                public int wParam;
                [MarshalAs(UnmanagedType.U4)]
                public int lParam;
            }
    
    
            [StructLayout(LayoutKind.Sequential)]
            public struct Request
            {
                [MarshalAs(UnmanagedType.U4)]
                public Int32 vers;        
    
                [MarshalAs(UnmanagedType.U2)]
                public Int16 flags;        
    
                [MarshalAs(UnmanagedType.U2)]
                public Int16 cmd;         
    
                [MarshalAs(UnmanagedType.U4)]
                public int objType;     
    
                [MarshalAs(UnmanagedType.U4)]
                public int id;             
    
                [MarshalAs(UnmanagedType.U4)]
                public int Client;         
    
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
                public string buf;
    
                [MarshalAs(UnmanagedType.U4)]
                public int toolID;         
    
                [MarshalAs(UnmanagedType.Struct)]
                public NMSG msg;           
    
                [MarshalAs(UnmanagedType.U4)]
                public int caller;        
    
                [MarshalAs(UnmanagedType.U4)]
                public int clientID;       
    
                [MarshalAs(UnmanagedType.U4)]
                public int ticket;         
    
                [MarshalAs(UnmanagedType.U4)]
                public int result;         
    
                [MarshalAs(UnmanagedType.Struct)]
                public MVToolResult res;
    
                [MarshalAs(UnmanagedType.ByValArray, SizeConst= 4) ]
                public int[] spare;       
            }
    This is the method decoration in the C code:
    Code:
    SendRequest(Request PTR req)
    {
    ....
    }
    Here is my PInvoke declaration in C# for the API in C that uses these structures:
    Code:
            [DllImport("TheCDLL.dll", EntryPoint = "_Request@4", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
            public static extern IntPtr Request(ref Request req);
    And here is my C# code that fills the structure and makes the API call:
    Code:
                    Request req = new Request();
    
                    req.vers = Marshal.SizeOf(req);
    
                    req.vers = 1;
                    req.toolID = 4000;
                    req.Client = 0;
                    req.cmd = 11;
                    req.objType = 1;;
                    req.id = 1;
                    req.msg.hWnd = Hwnd;
                    req.msg.msg = msg;
                    req.msg.wParam = wParam;
                    req.msg.lParam = lParam;
                    req.spare = new int[4];
                    req.buf = new string(' ', 260);
                    req.flags = 11;
    
                    IntPtr retptr = Request(ref req);
    The problem is, in the VB6 code the structure item 'result' gets filled with a value after I make the API call. In C#, 'result' is always just 0. I'm guessing I must have something wrong with the way I'm marshaling? I've read dozens of articles and have tried lots of different ways to get this working with no success. Any help is appreciated!
    Last edited by JeepRubicon; Oct 10 '11, 05:55 PM. Reason: Added method
  • kadghar
    Recognized Expert Top Contributor
    • Apr 2007
    • 1302

    #2
    Im not sure, but VB wont let you have empty variables, so it will assign its default value when declared. Wouldn't that be the problem?

    Comment

    • JeepRubicon
      New Member
      • Oct 2011
      • 2

      #3
      Thanks for the suggestion, but all elements in the structure have a default value, so that isn't it.

      Comment

      Working...