Passing strings to and from a C++ Dll

Hello I am trying to test the functionality of Unity’s plugin system. So far I can get a simple adding function, but I have having serious issues trying to send and receive string values.

My Unity C# Code looks like this:

    //GUIctrl.cs
using UnityEngine;
using System.Collections;
using System;

using System.Runtime.InteropServices;

public class GUIctrl : MonoBehaviour {
	[DllImport ("dllTest")] private static extern string  MyMathFloatCatBat(string str);
	[DllImport ("dllTest")] private static extern string  MyMathFloatThrough(string str);
	public string txInVal1;
	public string txInVal2;
	
	public string txOutval1;
	public string txOutval2;
	
	// Use this for initialization
	void Start () {
		txInVal1 = "Text1";
		txInVal2 = "Text2";
	}
	
	// Update is called once per frame
	void Update () {
	
	}
	
	/// I am the GUI Rendering function. I draw the text boxes and buttons.
	void OnGUI(){
		Rect drawPos; 
		
		// draw text boxes for input
		drawPos = new Rect(5,5,100,50);
		txInVal1 = GUI.TextField(drawPos, txInVal1);
		
		drawPos = new Rect(125,5,100,50);
		txInVal2 = GUI.TextField(drawPos, txInVal2);
		
		drawPos = new Rect(5,65,100,50);
		if(GUI.Button(drawPos, "submit")){
			txOutval1 = MyMathFloatThrough(txInVal1);
			txOutval2 = MyMathFloatCatBat(txInVal2);
			
		}
		
		// draw text boxes for output
		drawPos = new Rect(5,165,100,50);
		txOutval1 = GUI.TextField(drawPos, txOutval1);
		
		drawPos = new Rect(125,165,100,50);
		txOutval2 = GUI.TextField(drawPos, txOutval2);
	}
}

My C++ code , which is set to complie to a dll in VS 2005 looks like this:

    // myMathFunc.h
#ifndef _MY_MATH_FUNC_H_
#define _MY_MATH_FUNC_H_ 
	#include <stdio.h>
	#include <windows.h> 
	#include <string.h>

	extern "C" __declspec(dllexport) int  MyMathIntAdd(int x, int y);
	extern "C" __declspec(dllexport) BSTR MyMathFloatCatBat(BSTR inVal);
	extern "C" __declspec(dllexport) BSTR MyMathFloatThrough(BSTR inVal);
#endif


    
// myMathFunc.cpp
#include "myMathFunc.h"
#include <string.h>

extern "C" __declspec(dllexport) 
int  MyMathIntAdd(int x, int y){

	return x+y;
}

extern "C" __declspec(dllexport) 
BSTR MyMathFloatCatBat(BSTR inVal){
	
	return SysAllocString(L"Hello World");

}

extern "C" __declspec(dllexport) 
BSTR MyMathFloatThrough(BSTR inVal){
	if(inVal[0] == 'X'){

		inVal = SysAllocString(L"goodbye");

	}
	return inVal;
}

The function MyMathFloatThrough(string str) returns the entire string that was passed to it (so I know I can get a full string back from the dll), but the function MyMathFloatCatBat(string str) returns just the first letter of the string we are trying to make. I am trying to make a function that can take in a string does some computations on it then return that string. But first I need to be able to return a string that was generated in the dll.

Thanks for your help.

The short answer is that directly returning a string from a DLLImported function cannot easily be done in a way that will not crash or leak memory. The most straightforward solution is to DLLImport the function as returning an IntPtr (in the .cs, not in the .h), and use Marshal.PtrToString* to turn the returned pointer into a string. You’ll still have to manually free the returned pointer afterward.

The long answer is here.

I have figured out a very hacky solution. Instead of returning a string I save my processing to an output buffer, and then return the content of the buffer one character at a time. The resulting functions look some thing like this:

My Unity C# code looks like this:

//GUIctrl.cs

using UnityEngine;
using System.Collections;
using System;

using System.Runtime.InteropServices;

public class GUIctrl : MonoBehaviour {
[DllImport (“dllTest”)] private static extern int MyMathIntAdd(int a, int b);
[DllImport (“dllTest”)] private static extern string MyMathCatBat(string str, int len);
[DllImport (“dllTest”)] private static extern char MyMathGetStrBufOut(int index);

public string txInVal1;
public string txInVal2;

public string txOutval1;
public string txOutval2;

// Use this for initialization
void Start () {
	txInVal1 = "Text1";
	txInVal2 = "Text2";
}

// Update is called once per frame
void Update () {

}

/// I am the GUI Rendering function. I draw the text boxes and buttons.
void OnGUI(){
	Rect drawPos; 
	
	// draw text boxes for input
	drawPos = new Rect(5,5,100,50);
	txInVal1 = GUI.TextField(drawPos, txInVal1);
	
	drawPos = new Rect(125,5,100,50);
	txInVal2 = GUI.TextField(drawPos, txInVal2);
	
	drawPos = new Rect(5,65,100,50);
	if(GUI.Button(drawPos, "submit")){
		MyMathCatBat(txInVal1, txInVal1.Length);
		txOutval1 = GetDllOut();
		
		MyMathCatBat(txInVal2, txInVal2.Length);
		txOutval2 = GetDllOut();
		
	}
	
	// draw text boxes for output
	drawPos = new Rect(5,165,100,50);
	txOutval1 = GUI.TextField(drawPos, txOutval1);
	
	drawPos = new Rect(125,165,100,50);
	txOutval2 = GUI.TextField(drawPos, txOutval2);
}

private string GetDllOut(){
	string ret = "";
	for(int itor =0; itor < 128; itor++){
		char val = MyMathGetStrBufOut(itor);
		if(val == '\0'){	// exit loop on null plug
			itor = 500;
		}else{ // apend val to string
			ret += val;
		}
	}
	return ret;	// return completed string.
}

}

My Dll C++ code looks like this:

// myMathFunc.h
#ifndef MY_MATH_FUNC_H
#define MY_MATH_FUNC_H
#include <stdio.h>
#include <windows.h>
#include <string.h>

#define STRLEN 128
static char strBufIn[STRLEN];
static char strBufOut[STRLEN];

extern "C" __declspec(dllexport) int MyMathIntAdd(int val1, int val2);

extern "C" __declspec(dllexport) void MyMathCatBat(char* inVal, int len);

extern "C" __declspec(dllexport) char MyMathGetStrBufOut(int index);
	// string helper functions
void CopyToBufIn(char * inVal, int len);

#endif

// myMathFunc.cpp
#include “myMathFunc.h”
#include <string.h>

extern “C” __declspec(dllexport)
int MyMathIntAdd(int val1, int val2){
return val1+val2;
}

extern “C” __declspec(dllexport)
void MyMathCatBat(char* inVal, int len){
CopyToBufIn(inVal, len);
//strncpy(store, inVal, 50);
strncpy(strBufOut, strBufIn, STRLEN);
strncat(strBufOut, " BAT", STRLEN);
}

extern “C” __declspec(dllexport)
char MyMathGetStrBufOut(int index){
return strBufOut[index];
}

// helper function
void CopyToBufIn(char* inVal, int len){
for(int itor = 0; itor < STRLEN; itor++){
if(itor < len){
strBufIn[itor] =(char)(inVal[itor]);
}else{
strBufIn[itor] = ‘\0’;
}
} // add end cap regardless of string length
strBufIn[STRLEN-1] = ‘\0’;
}

Thanks to Ben 12 for pointing me into the right direction.

Hi marcusq, I’ve been using SIWG recently and I think it can handle “string leaking memory” problem. See this piece of code generated by SWIG:

/* Callback for returning strings to C# without leaking memory */
typedef char * (SWIGSTDCALL* SWIG_CSharpStringHelperCallback)(const char *);
static SWIG_CSharpStringHelperCallback SWIG_csharp_string_callback = NULL;