0

そのため、.NET アプリケーションを 64 ビット モードで実行しようとしています。x64 用にコンパイルできる dll に依存しており、正しくロードされます。一部の呼び出しを呼び出すことはできますが、特定の呼び出しを呼び出そうとすると、アプリが完全にクラッシュします。エラーなどはありません...

エラーは 2 つの場所のいずれかで発生します。ここのいずれか:

#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;
}

...

完全なコードは、私の GitHub HEREでそれぞれsocket.cppbuffer.cppにあります。上記のメソッドを呼び出すコードとオブジェクトのエントリ ポイントは、どちらも main.cpp にあります。

p/invoke 呼び出しは次のとおりです。

ソケット用:

[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();

コードがクラッシュする理由。これは、x64ではなく、x86ではすべて魅力的に機能します...

また、副次的な質問として... x86 で実行されているクライアントのバッファーに int を書き込み、x64 サーバーでそれを受信した場合 (またはその逆)、その int は 4 バイトまたは 8 になりますか? キーワードintはプラットフォーム固有のサイズで変更されますか? または、8 バイトの整数を取得するにはint64を指定する必要がありますか? これは、上記のより大きな質問の C++ ソース コード部分に当てはまります。

4

1 に答える 1

2

stringap/invoke 呼び出しの戻り値として使用しないでください。これは、メモリが を使用して割り当てられたと想定するため、返されたポインターでCoTaskMemAllocマーシャラーが呼び出されます。CoTaskMemFreeこれにより、実行時エラーが発生します。

CoTaskMemAlloc1 つのオプションは、 C# に返されるように割り当てるメモリに使用するようにネイティブ コードを変更することです。それを行った場合はstring、p/invoke の戻り値で引き続き使用できます。

別の方法として、C# 側でmalloc現在のように使用し、ネイティブ コードからデアロケーターをエクスポートすることもできます。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[]、それも解放する必要があります。


他のいくつかの観察:

  • intC++ コードの ように宣言されたソケットを返していdoubleますが、C ラッパーのように入力しています。そうしないでください。隅々まで使いintます。
  • C# 型intは 32 バイトです。64 ビット整数の場合はlong. 署名されていないバージョンはuintulongです。機械語サイズの型の場合は、IntPtrまたはを使用しますUIntPtr
于 2012-10-18T08:08:44.807 に答える