使用p / Invoke在x64版本的.net应用程序中崩溃

时间:2012-10-18 00:04:19

标签: c# dll crash pinvoke 64-bit

所以,我试图以64位模式运行我的.NET应用程序。我依赖于一个dll,我可以编译为x64并正确加载。我可以调用一些调用,但是当我尝试调用特定的调用时,应用程序就完全崩溃了。没有错误或任何东西......

错误发生在两个地方之一;要么在这里:

#include "socket.h"
int SenderAddrSize = sizeof(SOCKADDR_IN);
SOCKADDR_IN CSocket::SenderAddr;

...

char* CSocket::tcpip()
{
if(sockid<0)return NULL;
if(getpeername(sockid, (SOCKADDR *)&SenderAddr, &SenderAddrSize) == SOCKET_ERROR)return NULL;
return inet_ntoa(SenderAddr.sin_addr);
}

...

或在这里:

#include "buffer.h"
char CBuffer::retval[20001];
CBuffer::CBuffer()
{
BuffSize = 30;
data = (char*)malloc(BuffSize);
count = 0;
readpos = 0;
writepos = 0;
}

...

您可以分别在HEREsocket.cpp的GitHub buffer.cpp找到完整的代码。 代码的入口点和调用上述方法的对象都位于main.cpp

p / invoke调用如下:

for socket:

[DllImport("SockLib", CallingConvention = CallingConvention.Cdecl, EntryPoint = "tcpip")]
public static extern String tcpip(Double socket);

和缓冲区:

 [DllImport("SockLib", CallingConvention = CallingConvention.Cdecl, EntryPoint = "createbuffer")]
 public static extern Double createbuffer();

代码崩溃的任何想法。这有点像x86中的魅力,而不是x64 ......

另外,作为一个附带问题...如果我在x86上运行的客户端上写入一个int并在x64服务器上接收它(反之亦然),那int会是4个字节还是8个?关键字 int 会针对特定于平台的尺寸进行更改,还是必须指定 int64 才能获得8字节整数?这适用于上述较大问题的C ++源代码部分。

1 个答案:

答案 0 :(得分:2)

不要在p / invoke调用中使用string作为返回值。这将假设使用CoTaskMemAlloc分配内存,因此将导致marshaller在返回的指针上调用CoTaskMemFree。这会导致运行时错误。

一个选项是您可以将本机代码更改为使用CoTaskMemAlloc为其分配的内存返回到C#。如果您这样做,那么您可以在p / invoke返回值中继续使用string

另一种方法是现在使用malloc,在C#端使用IntPtr,然后从您的本机代码中导出解除分配器。

要从IntPtr转换为字符串,请使用Marshal.PtrToStringAnsi()。完成后,您可以将指针传递回本机DLL,以便它可以在其上调用free()

看起来像这样:

[DllImport("SockLib", CallingConvention=CallingConvention.Cdecl)]
public static extern IntPtr tcpip(double socket);

你这样称呼它:

IntPtr strPtr = tcpip(socket);
string str = Marshal.PtrToStringAnsi(strPtr);

你需要为每个返回字符串的p / invoke调用执行类似的操作。

您是否需要释放这些指针并非100%明确。这取决于你是否在C ++代码中分配了内存。例如,tcpip映射到inet_ntoa的调用。并返回指向套接字库所拥有的缓冲区的指针。所以你的代码不能试图释放它。但是如果你返回用mallocnew[]分配的内存,那么你也必须释放它。


其他一些观察结果:

  • 您将返回在C ++代码中声明为int但在C包装器中将其键入为double的套接字。不要那样做。一直使用int
  • C#类型int是32个字节。对于64位整数,请使用long。未签名的版本为uintulong。对于机器字大小的类型,请使用IntPtrUIntPtr