Это просто, попробуйте использовать пользовательский маршалинг (особенно, если вы хотите использовать указатели char **).
Я обнаружил, что вы не получаете строку "Memory ass dumb" из-за неправильной реализацииdoRequest (char *, char **), а также присвоение результата не обрабатываются должным образом;
Во-первых, если вы выделяете память в неуправляемом процессе и передаете ее управляемому процессу, вам потребуется объявить некоторый механизм для освобождения неуправляемой памяти.Управляемый GC ничего не знает об этой памяти, которая будет потеряна при чрезмерном размере.
Секунда, вам необходимо выделить память для результатов и передать их неуправляемому процессу, поскольку исходные области памяти можно переписать вв любое время.
Наконец, вы получаете только первую характеристику ввода только потому, что вам не выделена память для результатов, фактически передавая только указатель памяти на ячейку памяти первого выходного символа, скажем, & массив[0]
Вот код соревнования (MS VC ++ / MS C #), который устраняет все проблемы:
lib.cpp:
#include "stdafx.h"
#include "lib.h"
using namespace std;
int func1(char* input, char** output)
{
stringstream xmlInputStream, xmlOutputStream;
xmlInputStream << string(input);
int returnCode = doRequest(&xmlInputStream, &xmlOutputStream);
string xmlOutputString = xmlOutputStream.str();
//*output=const_cast<char *> (xmlOutputString.c_str());
long length = sizeof(char) * xmlOutputString.length();
char* src = const_cast<char *>(xmlOutputString.c_str());
char* dst = (char*)malloc(length+1);
memcpy_s(dst, length, src, length);
dst[length]=0; // 0 byte always ends up given ANSI string
*output = dst;
//cout << xmlOutputString;
return returnCode;
}
int func1_cleanup(char* memptr)
{
free(memptr);
return 0;
}
int doRequest(stringstream* xmlInputStream, stringstream* xmlOutputStream)
{
*xmlOutputStream << "Memory ass dumb";
return 0;
}
Program.cs:
using System;
using System.Runtime.InteropServices;
namespace test
{
class Program
{
[DllImport("lib.dll", EntryPoint = "func1", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern unsafe int func1(char* input, char** data);
[DllImport("lib.dll", EntryPoint = "func1_cleanup", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern unsafe int func1_cleanup(char* data);
static void Main(string[] args)
{
string input = "Hello, World!";
string output;
int result = func1(input, out output);
}
private const int S_OK = 0;
public static int func1(string input, out string output)
{
unsafe
{
output = null;
int result = -1;
fixed (char* parray1 = &input.ToCharArray()[0])
{
//
// if you allocating memory in a managed process, you can use this
//
//char[] array = new char[0xffffff];
//fixed(char* parray = &array[0])
{
//
// if you allocating memory in unmanaged process do not forget to cleanup the prevously allocated resources
//
char* array = (char*)0;
char** parray2 = &array;
result = func1(parray1, parray2);
if (result == S_OK)
{
//
// if your C++ code returns the ANSI string, you can skip this extraction code block (it can be useful in Unicode, UTF-8, UTF-7, UTF-32, all C# supported encodings)
//
//byte* self = (byte*)*((int*)parray2);
//byte* ptr = self;
//List<byte> bytes = new List<byte>();
//do
//{
// bytes.Add(*ptr++);
//}
//while (*ptr != (byte)0);
//output = Encoding.ASCII.GetString(bytes.ToArray());
output = Marshal.PtrToStringAnsi(new IntPtr(*parray2));
}
func1_cleanup(array);
}
}
return result;
}
}
}
}