所以,我试图以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;
}
...
您可以分别在HERE和socket.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 ++源代码部分。
答案 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
的调用。并返回指向套接字库所拥有的缓冲区的指针。所以你的代码不能试图释放它。但是如果你返回用malloc
或new[]
分配的内存,那么你也必须释放它。
其他一些观察结果:
int
但在C包装器中将其键入为double
的套接字。不要那样做。一直使用int
。int
是32个字节。对于64位整数,请使用long
。未签名的版本为uint
和ulong
。对于机器字大小的类型,请使用IntPtr
或UIntPtr
。