none
Passing structures from managed code to unmanaged dll RRS feed

  • Question

  • Hi,

    I don't have a problem passing a struct to a unmanaged dll, my problem is in getting the struct populated and returned back to the managed code.

    The following is the code snippets, any and all help would be appreciated.

    First the Managed Code

        [StructLayoutAttribute(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
        public struct PersonStruct
        {
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 200)]
            public char[] name;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 150)]
            public char[] last;
            public int age;
            public int height;
        }
    
     private void InitConfigTest()
            {
                if (this.CurrentLib != IntPtr.Zero)
                {
                    PersonStruct person = new PersonStruct();
    
                    IntPtr pAddressOfFunctionToCall;
                    pAddressOfFunctionToCall = NativeMethods.GetProcAddress(this.CurrentLib, "InitConfig");
                    InitConfigDelegate proc = (InitConfigDelegate)Marshal.GetDelegateForFunctionPointer(pAddressOfFunctionToCall, typeof(InitConfigDelegate));
    
                    // Initialize unmanged memory to hold the struct.
                    IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(person));
                    // Copy the struct to unmanaged memory.
                    Marshal.StructureToPtr(person, ptr, false);
    
                    proc(ptr);
                    PersonStruct persont2 = (PersonStruct)Marshal.PtrToStructure(ptr, typeof(PersonStruct));
                    Marshal.FreeHGlobal(ptr);
    
                }
            }
    And now the unmanaged code

    struct person
    {
    	char name[200];
    	char last[150];
    	int age;
    	int height;
    };
    
    _declspec(dllexport) void InitConfig(struct person *value)
    {
    	/*struct config_tag c;
    	do_defaults(NULL, value);*/
    
    	strcpy(value->name,"Fred");
    	value->height = 6;
    	strcpy(value->last, "Jones");
    	value->age = 47;
    }

    hank voight
    Wednesday, August 5, 2009 5:09 PM

Answers

  • A char[] won't be marshaled correctly.  Make it look like this:

        [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        public struct PersonStruct {
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 200)]
            public string name;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 150)]
            public string last;
            public int age;
            public int height;
        }

    You are doing all the hard work that [DllImport] will do for you automatically:

            [DllImport("something.dll")]
            private static extern void InitConfig(out PersonStruct person);

    Hans Passant.
    • Marked as answer by hank voight Wednesday, August 5, 2009 6:57 PM
    Wednesday, August 5, 2009 6:42 PM
    Moderator

All replies

  • A char[] won't be marshaled correctly.  Make it look like this:

        [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        public struct PersonStruct {
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 200)]
            public string name;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 150)]
            public string last;
            public int age;
            public int height;
        }

    You are doing all the hard work that [DllImport] will do for you automatically:

            [DllImport("something.dll")]
            private static extern void InitConfig(out PersonStruct person);

    Hans Passant.
    • Marked as answer by hank voight Wednesday, August 5, 2009 6:57 PM
    Wednesday, August 5, 2009 6:42 PM
    Moderator
  • You are the man that worked!

    Here is the reason why I am doing it the hard way.  I would like to get your opinion on my approach....  I currently have a win32 executable the executable uses a large number of static functions and variables. 

    I want to integrate into a c# project and I don't want to make this run as it's own process, since I don't want to show in taskbar and I don't want to alter the base code since the win32 code is very stable. 

    I do want to own the executables main window and make it a child control (or at least owned by a managed form).  So...

    The road I have taken was to make the executable a DLL, wrap within a managed class and then wrap the managed class into it's own assembly, thus I can dynamically load and unload via a appdomain and gauranteeing that when the assmebly is unloaded the static variables and state go away.  If I went the route of using [DllImport] don't I run the risk of the dll being loaded for the lifetime of the assembly?  I could be wrong, but if I had 2 windows open using the same dll, they would be sharing the static data, unless its in there own appdomain, which I am thinking would give the isolation that I need. Similar to running to exe's.

    To take the isolation as far as I can go, I am running the appdomain/assembly in its own thread with an apartment state of sta.

    Any and all comments are appreciated.
    hank voight
    Wednesday, August 5, 2009 7:11 PM
  • Unmanaged code doesn't know beans about AppDomains.  Your DLL won't be unloaded when you unload an AD.
    Hans Passant.
    Wednesday, August 5, 2009 7:18 PM
    Moderator
  • Yes, that is what I thought as well.  Hence when I tear down the app domain I call freelibrary which will unload the dll.
    hank voight
    Wednesday, August 5, 2009 7:31 PM