WCHAR array not properly marshalled
-
21-08-2019 - |
Question
I have a COM interface with a following method definition (IDL notation):
SCODE GetText( [in, out] ULONG* pcwcBuffer,
[out, size_is(*pcwcBuffer)] WCHAR* awcBuffer );
Typelib marshaling is used for COM+, the type library is registered, other methods of the interface work allright when called through COM+, but not this method.
The server side copies an array of WCHARs into the awcBuffer
and its length into pwcBuffer
, no buffer overrun ever occurs.
static const wchar_t* Text = L"Sample";
STDMETHODIMP CImpl::GetText( ULONG* bufferLength, WCHAR* buffer )
{
const int length = wcslen( Text );
*bufferLength = length;
memcpy( buffer, Text, length * sizeof( WCHAR ) );
return S_OK;
}
When the client calls this method through COM+ the buffer contents gets lost. Specifically only the first wide char is preserved - if the server copies "Sample" wide character string, the client only receives "S" string. The return value on the client size is S_OK, the buffer length returned to the client is exactly the same as what the server copied.
I finally switched to BSTR to workaround this problem but it's really interesting why the whole valid looking construct doesn't work.
What's the possible reason of the described behaviour?
Solution
IIRC, the typelib marshaller ignores the size_is attribute -- thus, only 1 char is marshaled.
OTHER TIPS
J. Passing is right. For the typelib marshaller to work, the COM interface must be OLE Automation compatible. The typelib marshaller is implemented in oleaut32.dll, so I guess there's a clue in the name.
[size_is] is perfectly valid IDL, and compiles into a valid typelib, but the typelib marshaler can only handle a subset of valid interfaces. That subset is usually referred to as OLE Automation. As an aside, VB6 clients can only speak OLE Automation, so they wouldn't be able to consume your interface either.
Try marking your interface with the [oleautomation] attribute in your IDL. It should give you a warning or error message that might point you to more information on the subject.
In "normal" COM, you could generate a proxy/stub DLL from your IDL to do the marshalling, but I'm afraid I don't remember whether COM+ would use your custom marshalling code even if you bothered to build it.
Update: in Juval Lowy's book "COM and .NET Component Services", I found this statement: "...configured components cannot use interfaces that require custom marshaling". So I guess that interface will never work in COM+. If you can, re-write to use a BSTR instead.
Couple of questions:
- Why aren't you using
BSTR
? - Do you have the sources of the
GetText
function? - What is the size of the buffer returned by the function?