none
marshalling safearray of user defined struct RRS feed

  • Question

  • Hi guys i am trying to return a SafeArray containing user defined struct from unmanaged code ( c++ ) to managed .net code ( C# ). After little reading on the net i can return a SafeArray of NOT user defined types and a single instance of user defined type.
    Here is the code:
    C:
    user defined struct:
    typedef struct _song 
    {
    char * name;
    char * album;
    char * artist;

    } t_song;
    here is the c function that should fill the array. I don't know if this is the correct approach but i am trying to allocate a new song instance and then copy it to VARIANT and then put it in SafeArray.
    __declspec(dllexport) SAFEARRAY * music_library_get_songs()
    {
    USES_CONVERSION;
    HRESULT hr = S_OK;

    // safe array dim
    SAFEARRAYBOUND safeArrayDim[1];
    safeArrayDim[0].lLbound = 0;
    safeArrayDim[0].cElements = 5;

    // create safe array
    SAFEARRAY * pSafeArray = SafeArrayCreate(VT_VARIANT,1,safeArrayDim);

    // fill safe array with data
    if(pSafeArray != NULL) {
    unsigned int i;
    long index;
    pSafeArray->pvData = malloc(5*sizeof(t_song));
    for(i = safeArrayDim[0].lLbound; i < safeArrayDim[0].cElements + safeArrayDim[0].lLbound; i++) {
    VARIANT vOut;
    VariantInit(&vOut);
    t_song * song = (t_song*)malloc(sizeof(t_song));
    song->album = "album";
    song->artist = "artist";
    song->name = "name";
    /* i don't know how to connect the song structure with the VARIANT
    */
    hr = SafeArrayPutElement(pSafeArray, &index, &vOut);
    VariantClear(&vOut);
    }
    }
    return pSafeArray;
    }
    managed c# code
    // structure marshaling
    [StructLayout(LayoutKind.Sequential)]
    public class Song
    {
    [MarshalAs(UnmanagedType.LPTStr)]
    public string name;
    [MarshalAs(UnmanagedType.LPStr)]
    public string album;
    [MarshalAs(UnmanagedType.LPStr)]
    public string artist;

    }


    [DllImport(MyLibrary.dll)]
    [return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_VARIANT)]
    public static extern Song[] music_library_get_songs();
    so how can i return a safe array containing user defined struct
    Friday, October 2, 2009 1:40 PM

Answers

  • Good.  COM does not have very good support for structures, they need IRecordInfo.   Especially not the ones that contain char*, that's rather a memory management headache.  The solution is simple, the "song" should be a COM interface with properties.

    Hans Passant.
    • Marked as answer by eryang Tuesday, October 6, 2009 1:54 AM
    Saturday, October 3, 2009 11:35 PM
    Moderator
  • I'll rephrase it: don't use a struct, use a class.

    Hans Passant.
    • Marked as answer by eryang Tuesday, October 6, 2009 1:54 AM
    Monday, October 5, 2009 9:25 AM
    Moderator
  • No, a COM class.  Ask questions how to do so in ATL in the C++ General forum.

    Hans Passant.
    Monday, October 5, 2009 12:30 PM
    Moderator

All replies

  • I can tell that my answer to your previous question helped.  You forgot to mark it answered though.  I'll answer this one as soon as you take care of your old threads.

    Hans Passant.
    Friday, October 2, 2009 3:35 PM
    Moderator
  • Done and sorry for that :)
    Saturday, October 3, 2009 10:04 PM
  • Good.  COM does not have very good support for structures, they need IRecordInfo.   Especially not the ones that contain char*, that's rather a memory management headache.  The solution is simple, the "song" should be a COM interface with properties.

    Hans Passant.
    • Marked as answer by eryang Tuesday, October 6, 2009 1:54 AM
    Saturday, October 3, 2009 11:35 PM
    Moderator
  • Hi thanks for the reply,
    I am not very familiar with com stuff, after googling about IRecordInfo I found this post http://vcfaq.mvps.org/com/4.htm which seems just that i am looking for but the problem is that i can't  use library MyLibrary - it's not visible.
    What i am getting wrong :)
    Monday, October 5, 2009 9:11 AM
  • I'll rephrase it: don't use a struct, use a class.

    Hans Passant.
    • Marked as answer by eryang Tuesday, October 6, 2009 1:54 AM
    Monday, October 5, 2009 9:25 AM
    Moderator
  • unmanaged code:
    class Song
    {
    public:
    	BSTR name;
    	BSTR album;
    	BSTR artist;
    
    };
    extern "C"
    {
    __declspec(dllexport) SAFEARRAY * music_library_get_songs()
    {
    	USES_CONVERSION;
    	HRESULT hr = S_OK;
    
    	// safe array dim
    	SAFEARRAYBOUND safeArrayDim[1];
    	safeArrayDim[0].lLbound = 0;
    	safeArrayDim[0].cElements = 5;
    
    	// create safe array
    	SAFEARRAY * pSafeArray = SafeArrayCreate(VT_VARIANT,1,safeArrayDim);
    
    	// fill safe array with data
    		if(pSafeArray != NULL) {
    			unsigned int i;
    			for(i = safeArrayDim[0].lLbound; i < safeArrayDim[0].cElements + safeArrayDim[0].lLbound; i++) {
    				long index = i;
    				Song * song = new Song();
    				song->album = SysAllocString(A2W("asfd"));
    				song->artist = SysAllocString(A2W("asfd"));
    				song->name = SysAllocString(A2W("asfd"));
    
    				SafeArrayPutElement(pSafeArray,&index,song);
    				
    			}
    		}
    	
    	return pSafeArray;
    }
    }
    managed code:
    [StructLayout(LayoutKind.Sequential)]
            public class Song
            {
               [MarshalAs(UnmanagedType.LPTStr)]
               public string name;
               [MarshalAs(UnmanagedType.LPStr)]
               public string album;
               [MarshalAs(UnmanagedType.LPStr)]
               public string artist;        
    
            }
    
    
                [DllImport(Library.DLL_PATH)]
                [return: MarshalAs(UnmanagedType.SafeArray)]
                public static extern Object[] music_library_get_songs();
    if i use Song for the return type i get
    Unhandled Exception: System.Runtime.InteropServices.SafeArrayTypeMismatchExcepti
    on: Specified array was not of the expected type.
    - i object return array with length 5 but with null values
    Monday, October 5, 2009 11:05 AM
  • No, a COM class.  Ask questions how to do so in ATL in the C++ General forum.

    Hans Passant.
    Monday, October 5, 2009 12:30 PM
    Moderator