all groups > dotnet interop > october 2006 >
You're in the

dotnet interop

group:

StringBuilder & Class Library exposed to COM


StringBuilder & Class Library exposed to COM Olivier Matrot
10/25/2006 5:00:45 PM
dotnet interop:
Hello,
Maybe this problem has been discused many times here but I've spent several
hours to find the answer with no luck.
Basically, I have a c# class library exposed to COM.
The client is written in unmanaged C++.

One method of my c# class have a StringBuilder parameter. This parameter is
exposed to COM as "/*[in,out]*/ LPWSTR". This is fine. Now when calling the
library, I allocate a buffer then call the method. The problem is that the
resulting StringBuilder as a capacity of 0. Any maniplation results in an
ArgumentOutOfRangeException. I've tried to use
[MarshalAs(UnmanagedType.LPWStr, SizeParamIndex = x)] to tell the size
allocated, but this is not working.

Any help appreciated.



RE: StringBuilder & Class Library exposed to COM v-phuang NO[at]SPAM online.microsoft.com (
10/26/2006 12:00:00 AM
Hi Olivier,

I think you may take a look at the KB below which describe a similar
scenario with you.

SYMPTOMS
When you call a managed method that takes System.Text.StringBuilder as a
parameter from an unmanaged client, you may receive an
ArgumentOutOfRangeException exception error message.

FIX: Call to managed class method with StringBuilder as in or out parameter
may fail
http://support.microsoft.com/kb/317577

You may have a try.
If you still have any concern, please feel free to let me know.

Best regards,

Peter Huang

Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.
Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
(This posting is provided "AS IS", with no warranties, and confers no
rights.)
Re: StringBuilder & Class Library exposed to COM Olivier Matrot
10/26/2006 12:00:00 AM
Hello Peter,
I'm using .NET 2.0 and this KB article is for 1.0 and 1.1.

But I guess there is still a problem in .NET 2.0 ?
May be a good think to do, is to remove StringBuilder in the Interop
documentation.
Thanks for that.


[quoted text, click to view]

Re: StringBuilder & Class Library exposed to COM Olivier Matrot
10/26/2006 12:05:29 PM
To still use StringBuilder, the buffer allocated on the client should be
entirely filled with characters and the null terminating character in order
to have a correct capacity. To clean the buffer before use in server code,
just call Remove method :
sb.Remove(0, sb.Capacity);

Thanks for that.

[quoted text, click to view]

Re: StringBuilder & Class Library exposed to COM v-phuang NO[at]SPAM online.microsoft.com (
10/27/2006 9:10:41 AM
Hi Olivier,

Thanks for your quickly reply!

Based on my research, this issue should be fixed in Whidbey i.e. .NET 2.0.
Also I test the steps in the KB317577,
Steps to reproduce the behavior

But I can not reproduce the problem, I can see the dialog showed "changed
changed".

So far I think you may try to run the reproduce code in the KB to see what
is thre result you get.
If you still get the error, I think you may try to check in the class
library to see what runtime you are running.
e.g.
public void Test(StringBuilder sbString)
{
Debug.WriteLine(System.Environment.Version.ToString());
string str = "changed changeddd";
sbString.Replace(sbString.ToString(), str);
}

If you did not get the error in the reproduce code but you keep get the
error in your code.
Can you build a simple reproduce sample, so that I can reproduce at my side
and do further troubleshooting?
If this is still a problem in .NET 2.0, I can report it our product team
for you when I have reproduced the problem.

You may reach me via removing "online" from my email address.

If you still have any concern on this issue, please feel free to let me
know.


Best regards,

Peter Huang

Microsoft Online Community Support
==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
Re: StringBuilder & Class Library exposed to COM Olivier Matrot
10/27/2006 3:38:59 PM
Hi Peter,
I can confirm that the issue is fixed in .NET 2.0.
The problem was that in my original C++ code, the buffer is allocated and
filled with the null terminating character. In other words, I'm sending an
empty string. I Though that the Interop Framework will be able to determine
the "real" size of the buffer and allocate a string builder with the correct
capacity.

This is not the case. In fact, the framework allocate a stringbuilder with a
capacity based on the string length sent by the client. This is why I'm
filling the buffer with spaces that are removed on the server side.

Best regards.

[quoted text, click to view]

Re: StringBuilder & Class Library exposed to COM v-phuang NO[at]SPAM online.microsoft.com (
10/31/2006 12:00:00 AM
Hi Olivier,

Thanks I understand you write your C++ code similar as below, the string is
Null Terminated leading string.
So that the wcslen will be Zero.

try
{
ITestPtr spTest;
//wchar_t wszTestString[] = L"This is a test."; //<- This works
wchar_t wszTestString[] = L"\0A long long string for test.";
long length = 1024;//(wcslen(wszTestString) + 1) * sizeof(WCHAR);
LPWSTR lpszTestString = (LPWSTR)::CoTaskMemAlloc(length);
spTest.CreateInstance(CLSID_Class1);
wcscpy((LPWSTR)lpszTestString, wszTestString);
spTest->Test((LPWSTR)lpszTestString);
MessageBoxW(NULL, (LPWSTR)lpszTestString, L"Results", 0);
::CoTaskMemFree((LPWSTR)lpszTestString);
}

Now even if the actually wszTestString array is greater than 0, the .NET
interop layer will still consider the pass parameters as 0.
I think this is by design.
Because we are handling string here, so the \0 should mean a terminatal of
a string char array, so it make sense that .NET framework consider the
wszTestString is of 0 size. Or it is hard to .NET interop to decided which
should be the terminal of a pass parameter which is a string.

As you pointed out, the workaround is to fill space or other non-\0 in the
string.

Also if you are not handling string here, just want to represent a buffer
here, so why not handle it as a byte array and pass the byte array as
parameter.

If you still have any concern, please fee l free to let me know.


Best regards,

Peter Huang

Microsoft Online Community Support
==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
AddThis Social Bookmark Button