メインC#アプリケーションにいくつかの機能を提供するC++ DLLがあります。ここで、ファイルを読み取ってメモリにロードし、ロードされたデータへのポインタやメモリブロックの数などの情報をc#に返します。 DLLはファイルをメモリに正常に読み取りますが、メインアプリケーションに戻ると、ヒープの破損(重大なエラーが検出されたc0000374)によりプログラムがクラッシュします。
コードは非常にシンプルで簡単であり、以前同様のことを何も問題なく行いましたが、ここで何が問題になるのかわかりませんでした。「new、malloc、GlobalAlloc」を使用してメモリを割り当てようとしましたが、どちらも助けませんでしたコードは次のとおりです。
C++ MyDll:
typedef unsigned long U32;
extern "C" __declspec(dllexport) int ReadFile(LPSTR Path, U32** DataPtr, U32* Count)
{
FILE *fp;
U32 *Data;
CString tempStr(Path);
long fSize;
if(!(fp = fopen(tempStr, "rb"))) {
return 0;
}
// Obtain File Size;
fseek(fp, 0, SEEK_END);
fSize = ftell(fp);
rewind(fp);
Data = (U32 *)GlobalAlloc(0, fSize);
if(Data == NULL) {
fclose(fp);
return -1;
}
// Copy file into the buffer.
if(!(*Count = fread(Data, sizeof(U32), fSize / sizeof(U32), fp))) {
fclose(fp);
free(Data);
return -2;
}
*DataPtr = (U32 *)Data;
return 1;
}
C#アプリケーション:
[DllImport(@"MyDll.dll", CallingConvention= CallingConvention.Cdecl)]
private static extern int ReadFile([MarshalAs(UnmanagedType.LPStr)]string Path, out IntPtr dataPtr, out uint Count);
private void readDump(string Path)
{
uint count = 0;
IntPtr Data = new IntPtr();
try{
if(ReadFile(Path, out Data, out count) == 1) //The Program crashes just right after this statement
{
//Do Something ...
}
}
catch() {}
}
プログラムは、デバッグモードとリリースモードの両方でクラッシュします。ファイルを読み込んだ後、デバッグモードでプログラムを一時停止し、「Visual Studioのイミディエイトウィンドウ」でメモリブロックを呼び出す場合を除きます。ロードするファイルのサイズは約64MBで、PCには2GB以上の未使用のRAMがあります。
PDATE:以前に動作していた一部のサードパーティプログラムが「Exception Code:c0000005」でクラッシュし、Windows 7(ホスト)でその他の奇妙なことが起こります。そのため、別のWindowsインストールでコードをテストしましたが、すべて正常に機能しているようです。それはおそらくWindows 7に関連しているのでしょう。さて、どうすれば問題を修正できますか? 「sfc/scannow」は問題を見つけることができませんでした。
実際にすべてのコードが上記に示されているものである場合、問題は表示されません。ただし、この問題が発生すると、malloc/new/whateverがヒープの破損を検出することがあるため、この破損はプログラム内で既に発生していることがよくありますが、次のnew/mallocの呼び出しまでクラッシュが遅れています。
上記が実行されてクラッシュする前に他のファイルを読んだり、他のバッファを割り当てたり解放したりする場合は、問題を探します。おそらく、バッファに書き込むすべての場所に大量のアサートをスローし、境界とオーバーランのために何を書いているかをチェックします。申し訳ありませんが、これは具体的な答えではありません。このアドバイスをコメントとして残すのに十分な担当者がいません。
出力データを2回割り当てています。 C#で新しいIntPtr
として、次にC++でGlobalAlloc
として、そしてGlobalAlloc
によって返されるポインターを返します。そのため、new intPtr
によって返されるポインターは失われました。