Попытка маршалировать структуру с помощью char * data, но данные пусты


У меня есть структура в моем C# следующим образом:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct UserProfileData
{
    int userProfileRevision;
    [MarshalAs(UnmanagedType.LPStr)] 
    public String firstName;
    [MarshalAs(UnmanagedType.LPStr)] 
    public String lastName;
    [MarshalAs(UnmanagedType.LPStr)] 
    public String memberids;
    [MarshalAs(UnmanagedType.LPStr)] 
    public String emailAddress;
}

Я передаю ссылку на это

typedef struct userProfile
{
    int profileRevision;
    char *firstName;
    char *lastName;
    char *memberids;
    char *emailAddress;
} userProfile_t;

Мой C .dll имеет такую функцию

int getUserProfileData(userProfile_t *pUserProfile);

Чтобы получить значения для строк в структуре выше. Я вызываю эту функцию из кода C#, и значение int 'profileRevision' заполняется правильно. Строки типа 'firstname' правильно динамически распределяются и заполняются внутри указанной выше функции C, но когда код возвращается в среду C#, все строки в struct являются нулевыми. Как лучше всего с этим справиться?

1 4

1 ответ:

Так, как вы его написали, буферы char* распределяются на управляемой стороне. Но это не то место. Распределение происходит на неуправляемой стороне. Объявите структуру в C# следующим образом:

[StructLayout(LayoutKind.Sequential)]
public struct UserProfileData
{
    int userProfileRevision;
    public IntPtr firstName;
    public IntPtr lastName;
    public IntPtr memberids;
    public IntPtr emailAddress;
}

Затем вызовите getUserProfileData, передавая структуру в качестве параметра out. Или, возможно, параметр ref. Я не могу сказать отсюда, что это должно быть.

Ваш DllImport будет выглядеть следующим образом (с правильным указанным соглашением о вызове):

[DllImport(@"mydll.dll", CallingConvention=CallingConvention.???)]
private static extern int getUserProfileData(out UserProfileData userProfile);

Затем преобразуйте возвращенные указатели в строки, подобные этой:

string firstName = Marshal.PtrToStringAnsi(userProfile.firstName);

И так далее для других полей.

Предположительно, неуправляемый код также предоставляет функцию, которая освобождает память, возвращаемую в структуру. Позвоните, как только закончите со структурой.