views:

387

answers:

2

Apologies for duplicate posting.

Hi

I am having trouble marshalling a linked list from a DLL.

------C++ Structure and Function--------

struct localeInfo { 
   WCHAR countryName[BUFFER_SIZE];
   WCHAR localeName[BUFFER_SIZE]; 
   localeInfo *next; 
}

int GetSystemLocales(localeInfo **ppList);

-----------C# Declarations-----------

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
private struct LocaleInfo { 
   public string countryName; 
   public string localeName; 
   public IntPtr next; 
};

[DllImport("systemLocales.dll")]
private static extern int GetSystemLocales(ref IntPtr ppList);


int main() 
{ 
   var pListHead = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr))); 
   try 
   { 
       GetSystemLocales(ref pListHead); 
       var deref1(IntPtr)Marshal.PtrToStructure(pListHead, typeof(IntPtr)); 
       var deref2 = (LocaleInfo)Marshal.PtrToStructure(deref1, typeof(LocaleInfo)); 
   } 
   finally 
   { 
      Marshal.FreeHGlobal(pListHead); 
   }

}

I get an FatalExecutionEngine Exception at deref2 declaration. I can't figure out how to get the linked list back and access its contents.

Here is the C++ code that I wrote to get the linked list. I want something similar to work in C#.

localeInfo *pHead = NULL; 
localeInfo *pTemp; 
GetSystemLocales(&pHead);

for(pTemp = pHead; pTemp!=NULL; pTemp = pTemp->next)
{
        wprintf(L"Display Name : %s (%s) \n", pTemp->countryName, pTemp->localeName);
}
+1  A: 

try this:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct LocaleInfo { 
   [MarshalAs(UnmanagedType.ByValTStr, SizeConst = BUFFER_SIZE)]
   public string countryName; 
   [MarshalAs(UnmanagedType.ByValTStr, SizeConst = BUFFER_SIZE)]
   public string localeName; 
   public IntPtr next; 
};
Shay Erlichmen
A: 

I answered on your other question along these lines. Shay's struct definition is part of it, but I've corrected Main also.

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct LocaleInfo
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = BUFFER_SIZE)]
    public string countryName;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = BUFFER_SIZE)]
    public string localeName;
    public IntPtr next;
};

[DllImport("systemLocales.dll")]
private static extern int GetSystemLocales(ref IntPtr ppList);

static void Main()
{ 
    IntPtr pList = IntPtr.Zero;
    GetSystemLocales(ref pList);
    while (pList != IntPtr.Zero)
    {
        var info = (LocaleInfo)Marshal.PtrToStructure(pList, typeof(LocaleInfo));
        Console.WriteLine("Display Name : {0} ({1}) ", info.countryName, info.localeName);
        Marshal.FreeHGlobal(pList);
        pList = info.next;
    }
}

You ought to close the other question really - I only noticed by luck that you had posted this one too.

Dave Cluderay
Thanks for the reply. It worked! There is no option to close/delete questions on this website... at least I couldn't find it.
Ashish