简体   繁体   English

使用C#调用C ++ dll,有时会违反内存

[英]Use C# to call C++ dll, memory violation sometimes

I have the definitions of the c++ code 我有C ++代码的定义

#define TEST_DLL_API extern "C" __declspec(dllexport)
TEST_DLL_API void __cdecl create(const char* sString, const char* sNext, int level, char* response ) ;
TEST_DLL_API void __cdecl result(const char* sString, char* response) ;

For the first few times call in my C# code, it works well, but it cause the memory violation for the fifth time. 对于我的C#代码中的前几次调用,它运行良好,但是第五次导致内存冲突。

[DllImport("TEST_DLL.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true)]
public static extern void create(string sString, string sNext, int level, StringBuilder response);

[DllImport("TEST_DLL.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true)]
public static extern void result(string sString, StringBuilder response);

I think that's the problem of not to freeing the stack memory, but I do not know how to solve it. 我认为这是不释放堆栈内存的问题,但我不知道如何解决。

To start with, forget about C# and just think about how you would call your C++ function from another C/C++ function. 首先,请忽略C#,而只是考虑如何从另一个C / C ++函数调用C ++函数。 With the export stuff stripped out, the result() function would be declared with: 除去导出内容后,将使用以下方法声明result()函数:

void result( const char* sString, char* response );

Now what about an implementation for that function? 现在该功能的实现如何? Let's suppose it merely copies the input sString to the output response string. 假设它仅将输入sString复制到输出response字符串。 Maybe the code looks like this: 也许代码看起来像这样:

void result( const char* sString, char* response ) {
    strcpy( response, sString );
}

Sweet and simple, right? 甜美而简单,对吗?

OK, now let's call that function. 好的,现在让我们调用该函数。

char buffer[10];
result( "This is my input string", buffer );

Do you see a possible problem here? 您在这里看到可能的问题吗? buffer is only 10 characters long, but the input string is 24 characters including the terminating null. buffer只有10个字符长,但输入字符串为24个字符,包括终止null。

So the result() function will copy 24 characters into a 10 character buffer. 因此, result()函数会将24个字符复制到10个字符的缓冲区中。 Oops. 哎呀。

In fact, how can the result() function ever know how much room is available in the response buffer? 事实上,如何能result()函数永远不知道多少空间在可response缓冲区? It doesn't have any way of knowing this. 它没有任何了解这一点的方法。

To make the function usable in C/C++, you would have to also pass in the maximum buffer length, and then result() could use that length to limit the length of what it copies. 为了使该函数在C / C ++中可用,您还必须传递最大缓冲区长度,然后result()可以使用该长度来限制其复制内容的长度。 It can do that by using strcpy_s() instead of strcpy() : 它可以通过使用strcpy_s()而不是strcpy()

void result( const char* sString, char* response, int cchResponse ) {
    strcpy_s( response, cchResponse, sString );
}

You could call it like this: 您可以这样称呼它:

#define elementsof( array )  ( sizeof(array) / sizeof((array)[0]) )
// ...
char buffer[10];
result( "This is my input string", buffer, elementsof(buffer) );

And even though the input string is larger than the output buffer, you will be OK because only enough of the string will be copied as fits in the buffer. 即使输入字符串大于输出缓冲区,您也可以,因为只有足够的字符串会被复制到缓冲区中。

So now you also have a function you could call from C# using StringBuilder , because you can allocate a StringBuilder and pass its length in: 因此,现在您还有一个可以使用StringBuilder从C#调用的函数,因为您可以分配 StringBuilder并将其长度传递

[DllImport(
    "TEST_DLL.dll",
    CallingConvention = CallingConvention.Cdecl,
    CharSet = CharSet.Ansi,
    SetLastError = true
)]
public static extern void result(
    string sString,
    StringBuilder response,
    int cchResponse
);

StringBuilder buffer( 10 );
result( "This is my input string", buffer, buffer.Capacity );

Like the C/C++ example above, even though the input string is larger than the buffer, the result() function will only copy the number of characters available in the buffer. 类似于上面的C / C ++示例,即使输入字符串大于缓冲区, result()函数也只会复制缓冲区中可用的字符数。

Bottom line: if you pass a StringBuilder into a C/C++ function to receive output from that function, you must preallocate it, and the C/C++ function must provide a way for you to tell it the maximum length. 底线:如果将StringBuilder传递到C / C ++函数以接收该函数的输出,则必须预先分配它,并且C / C ++函数必须为您提供一种告诉其最大长度的方法。

(I'm writing this without testing the code; there could be errors here, but you should get the general idea.) (我在编写此代码时没有测试代码;这里可能会出现错误,但是您应该了解一般想法。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM