vb6->.NET 2.0 conversion 'ByVal sName As Any' argument for c++ 'char szName[128]' par
what would be the appropriate .NET 2005 equivalent parameter be for this vb6 pinvoke declaration?
Public Declare Function foo Lib "foo.dll" (ByVal sName As Any)
where the c++ argument for the parameter sName is is'char szName[128]'
Related question (I hope)
I am confused as to when I should use
1.<MarshalAs(UnmanagedType.LPStr)> ByValsVar as String
rather than simply
2.ByValsVar as String
for cases where the vc++ parameter ischar *sVar ?
Thank you,
-Greg
[1285 byte] By [
hazz] at [2007-12-23]
The answer again is: it depends on the particular situation and how you delcare the PInvoke function.
- If you use ByVal sVar as String in a Declare statement, the default will be for the string to be marshalled as a VB6 String (BSTR).
- If you use ByVal sVar as String in a function declared with the "DllImportAttribute()", which is functionally equivalent to the Declare statement, then the string will be marshalled as an LPTStr.
While most of the time the BSTR and TChar * Strings are compatible for simple consumption, there are semantic differences into how the strings are implemented and marshalled that might cause your application to not work as expected. Do note that this differences do show up when running your application on a different OS or platform (32bits vs 64bits).
The reason for specifying the right attributes is so that the marshaller knows the following information:
- Whether the string is length prefixed.
- Whether the string is ASCII or UNICODE.
- On which directions the string needs to be copied when crossing the managed/unmanaged interfaces.
- Whether the string is zero terminated, or it is just a fixed size buffer.
Here are some questions that you need to ask yourself to know how to marshal the string correctly:
- Is the string going to be modified inside the function?
- Is the function going to use memory beyond the null-termination mark?
If your answer is no to both questions then you can use <MarshalAs(UnmanagedType.LPStr)> ByVal sVar as String without any problems.
If that's not the case, please state how the C++ functions treats the string so that I can tell you how to marshal the String.
Hope this helps,
Thank you for your patience Abel. And this application is going to be running on a 64 bit machine rather than the 32 bit which it has been running on as a vb6 app. Thanks for pointing that out. This is a graphics intensive app.
Question # 1. In what cases does a function use memory beyond the null-termination mark? What is a real world example of that?
Question # 2. What other cases might there be other than the two you mentioned? (string modification/memory usage beyond null-termination mark?)
I'll have to look at the 50-60 c++ functions in which these strings are consumed/modified on a case by case basis.
thanks,
-greg
This was helpful for me to read.... http://msdn.microsoft.com/msdnmag/issues/03/07/NET/
Assume that you have the following C++ function:
void foo(char szName[128])
{
for (int i = 0; i < 128; i++)
{
char temp = szName[ i ];
}
}
If you call the function like this:
foo("ASimpleString")
You are only passing a string with 13 characters in it (14 with the null-terminator). However, the function assumes that the provided buffer is indeed 128 bytes long, so it happily goes and accesses random memory after position 14. If the memory past the null termination character is accessible, nothing will happen, but if it isn't you will get an access violation.
For those scenarios you will need to tell the marshaller to actually send 128 bytes, regardless of the size of the string.
Hope this helps,
How do I tell the marshaller to actually send 128 bytes.
<MarshalAs(UnmanagedType.ByValTStr,SizeConst:=128)> ByVal var as String ?
Thanks,
-g
No, ByValTStr is only used within structures when you want to declare a fixed size char array.
If you want to send the full 128 bytes as a "char *" parameter, you can either marshal it as:
- <MarshalAs(UnmanagedType.LPStr)> ByVal var as StringBuilder
- Note that the size of the StringBuilderneeds to be set to 128 characters before calling the function:
- Dim Buf As New StringBuilder(128)
- Foo(Buf)
or
- <MarshalAs(UnmanagedType.LPArray, SizeConst=128)> ByVal var() As Byte
Hope this helps,