2015-10-07 173 views
1

我想从C++ dll导出函数返回一个字符串。我从c#调用这个函数。我在互联网上看到了很多例子,我很困惑该怎么做。从C++ dll导出函数返回字符串从c#调用

我的C++代码导出功能:

extern "C" __declspec(dllexport) char* __cdecl getDataFromTable(char* tableName) 
{ 
    std::string st = getDataTableWise(statementObject, columnIndex); 
    printf(st.c_str()); 

    char *cstr = new char[st.length() + 1]; 
    strcpy(cstr, st.c_str()); 
    return cstr; 
} 

当我尝试调用从C#这样的功能:

[DllImport("\\SD Card\\ISAPI1.dll")] 
private static extern string getDataFromTable(byte[] tablename); 
static void Main(string[] args) 
{ 
    string str = getDataFromTable(byteArray); 
    Console.writeLine(str); 
} 

我同时呼吁它得到了一个错误。我给WinCE 6.0

EDITED创建这个------------------------

有什么样的,我可以通过一个空从C#缓冲区到C++和C++函数将填充数据,我可以在C#中重复使用它

+0

什么是错误? – Tobbe

+0

在console.writeLine的OutOfMemory异常(字符串值) – Rawat

+1

当然,没有人打算再次调用delete []来释放字符串缓冲区空间。最终以OOM结束。你不能这样做。首先尝试CoTaskMemAlloc()。接下来通过允许调用者提供缓冲区,如int getDataFromTable(char * tableName,char * buffer,int buflen)来实现。必须是具有足够容量的C#端的StringBuilder。 –

回答

2

这个怎么样(注意,它假定正确的长度 - 你应该通过在缓冲区长度,防止溢出等):

extern "C" __declspec(dllexport) void __cdecl getDataFromTable(char* tableName, char* buf) 
{ 
    std::string st = getDataTableWise(statementObject, columnIndex); 
    printf(st.c_str()); 

    strcpy(buf, st.c_str()); 
} 

然后在C#:

[DllImport("\\SD Card\\ISAPI1.dll")] 
private static extern string getDataFromTable(byte[] tablename, byte[] buf); 
static void Main(string[] args) 
{ 
    byte[] buf = new byte[300]; 
    getDataFromTable(byteArray, buf); 
    Console.writeLine(System.Text.Encoding.ASCII.GetString(buf)); 
} 

注意,这对C++应用程序中的字符编码做了一些假设,而不是unicode。如果它们是unicode,则使用UTF16而不是ASCII。

+0

它的工作原理!谢谢 – Rawat

3

最近我也遇到了这个问题,尽管我有一个解决方案,可惜我无法真正解释它。我还没有找到合适的解释。

我的C++用于检索的字符串编码是:

extern "C" { __declspec(dllexport) void __GetValue__(char* str, int strlen); } 

和我的C#代码:

[DllImport("MyDLL.dll", CallingConvention = CallingConvention.Cdecl)] 
    private static extern void __GetValue__(StringBuilder str, int strlen); 

因此,大家可以看到,而不是返回一个值,你可以提供一个字符串(通过使用StringBuilder)并让C++填写如下数据:

void __GetValue__(char* str, int strlen) { 
    std::string result = "Result"; 

    result = result.substr(0, strlen); 

    std::copy(result.begin(), result.end(), str); 
    str[std::min(strlen-1, (int)result.size())] = 0; 
} 

为了完整性,请求的C#代码e字符串:

public String GetValue() { 
    StringBuilder str = new StringBuilder(STRING_MAX_LENGTH); 

    __GetValue__(str, STRING_MAX_LENGTH); 

    return str.ToString(); 
} 
2

.NET运行时使用unicode(wchar_t)字符串,而不是ascii(char),所以这需要一些更改。 您还应该考虑.NET无法释放已由C/C++应用程序分配的字符串,因此,使用C#预分配并从C#传入的缓冲区是唯一安全的方法,无需内存泄漏或更差。