Calling Win32 DLL -Data Missing

  • Thread starter Thread starter Badrinath Mohan
  • Start date Start date
B

Badrinath Mohan

Hi Guys
I am calling a simple win32 dll from a C# application.

Say the function is GetLastErrorString(BSTR *pstr)
the C#client calls it as

[DllImport("..\\..\\..\\ClientDll\\Debug\\ClientDll.dll",EntryPoint="?GetLas
tErrorString@@YAHPAPAG@Z")]
static extern int GetLastErrorString(ref string pStrErrorCode);



CLIENTDLL_API int GetLastErrorString(BSTR *pszErrorCode)
{
return gOcr.GetLastErrorString(pszErrorCode);
}

the pszErrorCode contains "Operation Success"

C# function is
string strerror=" ";
int ns = GetLastErrorString(ref strerror);

but it contains Just "O" the others are missing???

Why?
Expecting replies
Badrinath
 
Hello,

You should use the StringBuilder object for a Windows API call that accepts
a string buffer to be modified by a method.
[DllImport(@"c:\Temp\ClientDll.dll",
EntryPoint=?GetLastErrorString@@YAHPAPAG@Z)]
static extern in GetLastErrorString(StringBuilder errorCode);

Regards,
Michael Zino
 
Badrinath,
Say the function is GetLastErrorString(BSTR *pstr)
the C#client calls it as

[DllImport("..\\..\\..\\ClientDll\\Debug\\ClientDll.dll",EntryPoint="?GetLas
tErrorString@@YAHPAPAG@Z")]
static extern int GetLastErrorString(ref string pStrErrorCode);

Try it like this instead

static extern int GetLastErrorString([MarshalAs(UnmanagedType.BStr)]
ref string pStrErrorCode);



Mattias
 
Dear Michael,

String are immutable objects in managed code, and it's OK to use it as
buffers that will not be changed by the native API function.
In this particular case (static extern int GetLastErrorString(ref string
errorCode)), the API is supposed to modify the input string
but the passed string was already created and therefore cannot be changed by
the native API function.
That's the reason why using StringBuilder instead.
You can find more information about P/Invoke and C# in the following link:
http://msdn.microsoft.com/msdnmag/issues/03/07/NET/default.aspx

Regards,
Michael Zino
 
Hi Michael,
String are immutable objects in managed code, and it's OK to use it as
buffers that will not be changed by the native API function.

It is possible to get a buffer back without a string builder. Will this cause problems?

[DllImport("kernel32", EntryPoint= "GetComputerNameW")]
private static extern int GetComputerName([MarshalAs(UnmanagedType.LPWStr)] string lpBuffer, ref int nSize);
private void Form1_Load(object sender, System.EventArgs e)
{
string buffer = new string('\0', 255);
int len = buffer.Length;
GetComputerName(buffer, ref len);
buffer = buffer.Substring(0, len);
MessageBox.Show(buffer);
}
 
Michael,
It is possible to get a buffer back without a string builder. Will this cause problems?

Yes it can, so don't do it. To demonstrate, consider this code instead

// ---
string buffer = new string('\0', 255);
string someOtherString = buffer;

int len = buffer.Length;
GetComputerName(buffer, ref len);

Console.WriteLine(buffer);
Console.WriteLine(someOtherString);
// ---

Most people wouldn't expect someOtherString to be modified when buffer
is, because even though System.String is a reference type, its
immutability effectively gives it value semantics.

What you're doing here is basicly to break the immutability guarantee
of strings, which is a bad thing, since some runtime string
optimizations rely on the fact that a string can't change.

This may not seem so bad in this example, where all the code is
contained in a single method. But keep in mind the string interning
feature of the runtime, and the fact that completely separate pieces
of code may reference the same string, and it could have serious side
effects.


But in the original poster's case, where the parameter isn't an
LPWSTR, but rather a BSTR*, it's probably safe to pass a string. Since
the parameter is passed by ref, you can expect that the callee returns
a new BSTR (which the runtime then marshals to a new string object)
rather than to modify the existing string.



Mattias
 
Back
Top