5

I have a struct in my C# as follows:

[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; } 

I pass a reference to this

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

My C .dll has function like this

int getUserProfileData(userProfile_t *pUserProfile); 

to get the values for the strings in the struct above. I call this function from C# code and the int value 'profileRevision' is properly populated. The strings like 'firstname' are properly dynamically allocated and filled within the above C function but when the code returns to the C# environment all the strings in the struct are null. What's the best way to handle this?

1 Answer 1

2

The way you have written it, the char* buffers are allocated on the managed side. But that's the wrong place. The allocation happens on the unmanaged side. Declare the struct in C# like this:

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

Then call getUserProfileData, passing the struct as an out parameter. Or possibly a ref parameter. I can't tell from here which it should be.

Your DllImport will look like this (with the correct calling convention specified):

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

Then convert the returned pointers to strings like this:

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

and so on for the other fields.

Presumably the unmanaged code also exposes a function that deallocates the memory returned in the struct. Call that once you are done with the struct.

Sign up to request clarification or add additional context in comments.

6 Comments

My dll uses [DllImport("lib.dll", CallingConvention = CallingConvention.Cdecl)]. I changed my dll function to use 'out' like you have above. I am having an issue though. The firstname, memberids, and email address fields are still null but now the lastname field has the value from the email address (After converting with PtrToStringAnsi). What do you think that means?
Hmm, can't explain that. I think you'll have to dig. My answer is surely consistent with the question.
Small clarification: I have a different dll function with a 'ref' parameter to initialize the memory (in the C code) which is why I'm using 'out' in the getUserProfileData function.
Yeah I think you have me pointed in the right direction. I'm going to work on it. When I figure everything out I'll post a comment about what I did if it's anything substantial and I'll accept your answer. Thanks for your help.
Does this different dll function receive the same struct as the function in the question? If so the allocator should be out, and this Q's function ref. Anyway, I think this should head you in the right direction.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.