Return string from c++ dll - interop services

J

Jason

Hi,

I am having some trouble returning a string from a c++ dll. I tend to get
junk data back and I am not sure of the method, my code so far:

Function is declared in c++ dll 'Test' and exported like this:

extern "C" __declspec( dllexport ) BSTR getbagstr();
extern "C" __declspec( dllexport ) BSTR getbagstr() {
g.getbag()->setdisplaybag("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZ");
const char * buff = g.getbag()->getdisplaybag().c_str();
return SysAllocStringByteLen (buff , lstrlen(buff));
}

I want use the function via interop services - p/invoke - to display the
string in a simple c# program:

[DllImport("Test")]
private static extern IntPtr getbagstr();

public static string getBagString()
{
return Marshal.PtrToStringAuto(getbagstr());
}

The data I am returning is not correct. All display bag does is store and
return the string as below. I am returning int data correctly, but strings
are proving difficult. Anybody able to help?

void Bag::setdisplaybag(const string & str) {
displaybag = str;
}

string Bag::getdisplaybag() { return displaybag; }
 
M

Mattias Sjögren

public static string getBagString()
{
return Marshal.PtrToStringAuto(getbagstr());
}

SysAllocStringByteLen returns a BSTR containing ANSI characters. So
PtrToStringAuto will only work on Win9x platforms. Try changing it to

IntPtr ptr = getbagstr();
string tmp = Marshal.PtrToStringAnsi(ptr);
Marshal.FreeBSTR(ptr);
return s;


Mattias
 
J

Jason

SysAllocStringByteLen returns a BSTR containing ANSI characters. So
PtrToStringAuto will only work on Win9x platforms. Try changing it to

IntPtr ptr = getbagstr();
string tmp = Marshal.PtrToStringAnsi(ptr);
Marshal.FreeBSTR(ptr);
return s;

Thanks Mattias, this worked. I have been checking through the p/invoke
examples on your website which is an excellent resource. However, I
wondered if you could provide an example for this code:

extern "C" __declspec( dllexport ) __stdcall void setdisplaybag(LPSTR
tiles);
extern "C" __declspec( dllexport ) __stdcall void setdisplaybag(LPSTR
tiles) {
//set display bag code
}

Assuming the above is the exported c++ function, how should C# pass in the
BSTR safely? How should the BSTR be freed or should it?

[DllImport("Test")]
private static extern void setdisplaybag(IntPtr ptr);

public static void SetDisplayBag(string str)
{
IntPtr tmp = Marshal.StringToBSTR(str);
setdisplaybag(tmp);
//Marshal.FreeBSTR(tmp);
}
 
M

Mattias Sjögren

Assuming the above is the exported c++ function, how should C# pass in the
BSTR safely?

I see nothing about BSTRs in the function signatures, so I would
simply declare it as

static extern void setdisplaybag(string tiles);



Mattias
 
J

Jason

I see nothing about BSTRs in the function signatures, so I would
simply declare it as

static extern void setdisplaybag(string tiles);

Ok fine, but when I input this i get strange output:

settiles("ZZZZZZZZZYYYYYYYYYYYYYY");
Console.WriteLine(getbagstr());

console output:

v►☺YYYYYYYYYYYYYZZZZZZZZZ

Where are the extra characters coming from at the beginning and what is
needed to avoid them? Thanks in advance.
 
M

Mattias Sjögren

Jason,
Where are the extra characters coming from at the beginning and what is
needed to avoid them? Thanks in advance.

I don't know without seeing all the C++ code. It doesn't happen here.
I wrote the folowing test code and it roundtrips the string correctly.

// C++ DLL
#include <windows.h>
#pragma comment(lib, "oleaut32.lib")

char buf[100];

extern "C"
{
__declspec(dllexport) BSTR __stdcall getbagstr()
{
return SysAllocStringByteLen(buf, lstrlen(buf));
}

__declspec(dllexport) void __stdcall setdisplaybag(char *tiles)
{
lstrcpyn(buf, tiles, 100);
}

}

// C# client
using System;
using System.Runtime.InteropServices;

class Test
{
[DllImport("test.dll")]
static extern IntPtr getbagstr();

[DllImport("test.dll")]
static extern void setdisplaybag(string tiles);

static void Main()
{
setdisplaybag("ZZZZZZZZZYYYYYYYYYYYYYY");
IntPtr p = getbagstr();
Console.WriteLine(Marshal.PtrToStringAnsi(p));
Marshal.FreeBSTR(p);
}
}


Mattias
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top