Return string from c++ dll - interop services

  • Thread starter Thread starter Jason
  • Start date Start date
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; }
 
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
 
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);
}
 
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
 
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.
 
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

Back
Top