Reputation:
int __stdcall getProps( /* [ in ] */ void * context,
/* [ in ] */ const UINT32 index,
/* [ in ] */ WCHAR * const pwszFilterPath,
/* [ in, out ]*/ UINT32 * const pFilterPathSizeInCch,
/* [ in ]*/ WCHAR * const pwszFilterName,
/* [ in, out ] */ UINT32 * const pFilterNameSizeInCch );
Is this correct C# signature for a C function whose signature is above:
[DllImport("myLib.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)]
public static extern int getProps( IntPtr context,
uint index,
[MarshalAs(UnmanagedType.LPWStr)]
out StringBuilder pwszFilterPath,
ref uint pFilterPathSizeInCch,
[MarshalAs(UnmanagedType.LPWStr)]
out StringBuilder pwszFilterName,
ref uint pFilterNameSizeInCch );
There is something wrong here and I do not know what (I do not know C#). Sometimes when I get it to work, I receive ANSI strings inside StringBuilder variables and they should contain UNICODE characters.
The idea is to call this function twice. First with pwszFilterPath and pwszFilterName set to NULL, in order to retrieve the required size, then allocate memory for these two buffers and then retrieve the values on the second call. I know how to do it in C/C++, but not in C#.
Upvotes: 2
Views: 928
Reputation: 612844
You must remove the out
keyword from StringBuilder
parameters. A plain StringBuilder
parameter is marshalled as a pointer to character array. If you want the native code to receive NULL
, pass C# null
.
[DllImport("myLib.dll", CharSet = CharSet.Unicode)]
public static extern int getProps(
IntPtr context,
uint index,
StringBuilder pwszFilterPath,
ref uint pFilterPathSizeInCch,
StringBuilder pwszFilterName,
ref uint pFilterNameSizeInCch
);
The call pattern is as follows:
null
to the StringBuilder
parameters to find out the buffer size.StringBuilder
instances using the constructor overload that receives the capacity.StringBuilder
instances.Perhaps like this:
uint filterPathLength = 0;
uint filterNameLength
int retval = getProps(
context,
index,
null,
ref filterPathLength,
null,
ref filterNameLength
);
// check retval
StringBuilder filterPath = new StringBuilder(filterPathLength);
StringBuilder filterName = new StringBuilder(filterNameLength);
int retval = getProps(
context,
index,
filterPath,
ref filterPathLength,
filterName,
ref filterNameLength
);
// check retval
And you'll need to make sure you get the length convention right for null-terminator. I cannot tell whether or not your function returns lengths that include the null-terminator.
As @Ben points out, your annotations don't match the text description.
/* [ in ] */ WCHAR * const pwszFilterPath
The [ in ] should imply that the data is flowing into the function. When that is so, the type should be const WCHAR*
. But it's not the case. This is an out parameter. So the code should read:
/* [ out ] */ WCHAR * const pwszFilterPath
Upvotes: 3