Search code examples
c#c++structcasting

Equivalent in C# of converting between two struct type in C++


I have to replicate some C++ in C#. More specifically I have to create the equivalent of converting between pinit_param to pinit_param_g. The definition of pinit_param and pinit_param_g are below. C++:

typedef struct init_param {
        int     size;   
        HWND        hwnd;   
    }  init_param, *pinit_param;
typedef struct init_param_g {
        int     size;   
        HWND        hwnd;   
        GUID        appKey;
    }  init_param_g, *pinit_param_g;

extern "C" LIBRARY_API int __cdecl api_init(pinit_param param);
...
init_param_g paramg;
memset(&paramg, 0, sizeof(init_param_g));
paramg.size = sizeof(init_param_g);
paramg.hwnd = GetConsoleHwnd();//not relevant what implementation GetConsoleHwnd() has
paramg.applicationKey = APP_GUID;//not relevant what value APP_GUID has
api_init((pinit_param)&paramg);

What I've done in C#:

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 4)]
        public struct init_param
        {
            public int size;               
            public IntPtr hwnd;
        }
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 4)]
        public struct init_param_g
        {
            public int size;  
            public IntPtr hwnd;  
            public Guid appKey;
        }
[DllImport...]
public static extern Int32 api_init(ref init_param param);
.....
init_param_g paramg = new init_param_g();
paramg.size = Marshal.SizeOf(typeof(init_param_g));
paramg.hwnd = HWND;
paramg.appKey = APP_GUID;
var ret = api_init(ref (init_param)paramg);//error
.... or
init_param paramg = new init_param();
paramg.iSize = Marshal.SizeOf(typeof(init_param));
paramg.hwnd = HWND;
var ret = api_init(ref paramg);//the code compiles but initialization is not complete

I've tried to make init_param_g to inherit from init_param but you can't do that in C#. I've tried to convert using (init_param) in front of the variable or (ref init_param). Compile error both times.


Solution

  • The simplest way is to provide custom type cast operator (implicit or explicit as you like). The following example shows implicit operator

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 4)]
        public struct init_param
        {
            public int size;               
            public IntPtr hwnd;
        }
    
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 4)]
        public struct init_param_g
        {
            public int size;  
            public IntPtr hwnd;  
            public Guid appKey;
            
            public static implicit operator init_param(init_param_g self)
            {
                return new init_param()
                {
                    size =  Marshal.SizeOf(typeof(init_param_g)),
                    hwnd = self.hwnd,
                };
            }
        }
    

    Usage:

        init_param_g paramg = new init_param_g();
        paramg.size = Marshal.SizeOf(typeof(init_param_g));
        paramg.hwnd = HWND;
        paramg.appKey = APP_GUID;
        var tmp = (init_param)paramg;
        var ret = api_init(ref tmp);//ok