1

小さなアプリケーションを完成させ、メモリ リークやバグがないことを確認しようとしています。出力を確認した後、関数の 1 つが First-Chance 例外をスローしていることに気付きましたが、関数はうまく機能し、クラッシュしません。

この関数は、CLR C++ DLL 内の別の関数を呼び出します。テストのためだけに DLL 関数のほとんどすべてのコードを削除しましたが、それでも例外がスローされるため、EXE 関数が問題であることがわかります。

これは、EXE 関数が DLL 関数を呼び出すためのコードです。

LPCTSTR CHAXC0RDlg::Encrypt(LPCTSTR strValue)
{
    const char* Return;
    HINSTANCE hDLL = LoadLibrary(L"Library.dll");

    if(hDLL)
    {
        FARPROC hMethod = GetProcAddress(HMODULE (hDLL), "Encrypt");

        if(hMethod)
        {
            typedef const char* (*FunctionSig)(LPCTSTR);
            FunctionSig MethodCall = FunctionSig(hMethod);

            Return = MethodCall(strValue);
            FreeLibrary(hDLL);
        }
    }

    return _tcsdup(CString(Return));
}

これは DLL 関数です (ご覧のとおり、テストとして戻り値を生成するコードを除くすべてのコードを削除しました)。

const char* Encrypt(LPCTSTR strPValue)
{ 
    String^ strValue = gcnew String(strPValue);
    string strReturn = (const char*)(Marshal::StringToHGlobalAnsi(strValue)).ToPointer();

    char* csValue = new char[strReturn.size()];
    strcpy(csValue, strReturn.c_str());
    return const_cast<const char*> (csValue);
}

EXE 関数は " const char* Return = MethodCall(strValue);" で例外をスローします (私が知っている方法であるこの例外でブレークを有効にしました)。

この関数がこの例外をスローするのはなぜですか?

ありがとう!

編集

更新: 私の文字セットは UNICODE です。

更新#2:提案と回答で読んだことから、このコードは機能しないと想定していますが、機能します。すべてのバグをなくして、このプログラムを高品質にしたかったので、初回例外でのブレークを有効にしました (もちろん、初回例外が何であるかは知っています)。コードは正常に実行されます。私はより優れたプログラマーになりたいので、初回例外がスローされる理由を理解したかっただけです。ですので、これを修正したいと思います。

更新 #3: コードで hDLL と hMethod の値をチェックするようになりましたが、この関数を実行すると両方とも null ではありません。問題は、DLL への呼び出し自体にあるようです。このコードが機能するため、関数のシグネチャは 100% 正しいと想定しています。最初の例外がスローされるだけです。

更新 #4: 上記の関数に新しい変更を加え、DLL 関数コードを追加しました。DLL 関数は CLR C++ DLL です。既に述べたように、DLL 関数内のすべてのコードを削除して、それが自分の DLL でないことを確認しました。

4

5 に答える 5

4

スニペットからは明らかではありませんが、C++/CLI で記述されたマネージ関数で __declspec(dllexport) を使用したようです。String^ と Marshal クラスはそれを明確にします。

それ以外の場合は完全にネイティブなアプリケーションでマネージ コードを実行することは可能ですが、CLR を読み込んで初期化する必要があります。それを行うにはいくつかの方法がありますが、たまたま最も簡単な方法を見つけたと思います。マネージ関数で __declspec(dllexport) を使用すると、CLR が確実に初期化され、ネイティブ コードからマネージ コードへの移行が行われるようにするスタブが強制的に発行されます。

そうです、このエクスポートされた関数を初めて呼び出すと、大量のコードが背後で実行されます。これは、スタブが CLR を読み込んで初期化し、マネージ コードを含むアセンブリを読み込む必要がある時間です。このコードが例外をスローして処理するのを見ることは、一般的に心配する必要はありません。いずれにせよ、それについてできることはほとんどありません。このためのソース コードはありません。CLR を自分でホストすることで、偶発的なイベントを減らすことができます。これには COM コードのチャンクが必要であり、コストに見合うかどうかはわかりません。

これが実際に問題を引き起こさないという明確な証拠から、これは機能であり、バグではありません。この種のコードでは、未処理の実際の例外をトリガーできることに注意してください。マネージ コードがマネージ例外をスローする場合、これはマネージ コードでは一般的であり、例外コード 0xe0434f4d の Windows SEH 例外によって打撃を受けます。これは常に悪いことです。__try および __catch キーワードを使用してそれをキャッチできますが、スタックがコードに巻き戻されるまでにマネージ例外に関するすべての情報がゴンゾであるため、適切な診断を取得できません。

于 2012-04-06T18:14:04.847 に答える
1
  • 関数シグネチャは100%正しいですか?または、呼び出し規約の宣言がありませんか?(WINAPI、STDCALLなど)。問題の原因ではない可能性がありますが、それ以外の場合はoyuに問題が発生します(TONTを参照
  • 例外は何ですか?例外がスローされた場合にブレークするようにデバッガーに指示します(私のVisual Studioでは、デバッグ/例外であり、すべてに対して「スロー」を有効にします。
  • あなたはおそらくAPIを間違って使用しています(しかしそれは後でしか現れません)
  • 入力文字列は有効ですか?それはすべての値で起こりますか?

「C++例外」や「アクセス違反」などの情報と、追加の診断情報(運が良ければ)が表示されます。

この最初のチャンスの例外が「通常」である可能性はほとんどありません。つまり、有効な入力に対して常に発生します。ただし、通常の実行パスでは例外がスローされないため、これはまれです。


戻り値:

戻り値がDLL内の静的/内部バッファにある場合(解放する必要はありません)、DLLがアンロードされると無効になります。

戻り値がDLLによって動的に割り当てられる場合(たとえば、DLLがnew []、malloc、または_tcsdupを実行する場合)、DLLは文字列も解放する必要があります。そうしないと、文字列がリークします。DLLと呼び出し元が異なるヒープを使用する場合と使用しない場合があるため、呼び出し元の文字列を解放しないでください。

DLLのドキュメントを確認してください。返されたポインタを誰が解放する必要があるか、どのように、および/または返されたポインタが有効である期間が記載されている必要があります。

于 2012-04-03T06:57:44.413 に答える
1

DLL からエクスポートされた関数を初めて呼び出すときにのみ、例外がスローされます。これは CLR の初回のロード/初期化に関連しており、コードとは関係ありません (コードが実行される前に発生します)。Encrypt への後続の呼び出しでは、この例外は生成されません。無視しても安全なようです。

于 2012-04-09T21:44:41.993 に答える
0

プロジェクトで使用されている「文字セット」が明確ではありません(構成のプロパティ/一般を参照)。'LoadLibary'でLマクロを使用し、'GetProcAddress'では使用しません。

HINSTANCE hDLL = LoadLibrary(L"Library.dll");
FARPROC hMethod = GetProcAddress(HMODULE (hDLL), "Encrypt");

代わりに_Tマクロを使用してみてください。

HINSTANCE hDLL = LoadLibrary(_T("Library.dll"));
FARPROC hMethod = GetProcAddress(HMODULE (hDLL), "Encrypt");

プロジェクトの設定により、「L」が表示されます。

編集:

試す

_declspec( dllexport ) const char* Encrypt(LPCTSTR strPValue)
{
...
}

モジュール定義ファイルに次のものが含まれていることを確認してください

LIBRARY      "Library"

EXPORTS
    Encrypt @1

SECTIONS

 .data READ WRITE

また、なぜ使用しないのですか

const char* Encrypt(char* strPValue)

于 2012-04-03T06:22:27.097 に答える
0

コードを VS2010 に配置しました。呼び出し元 (EXE) は C++ コンソール アプリです。また、C++/CLI DLL は V90 ツール セットでビルドされていますが、ファースト チャンス例外がスローされることはありませんでした。

ヘッダー ファイルに _declspec( dllexport ) が含まれていることは確かですが、それをどのように定義したかはわかりません。私のはこんな感じです。

extern "C"
{
    __declspec(dllexport) const char* Encrypt(LPCTSTR strPValue);
}

また、モジュール定義ファイル (.def) はありません。出力ウィンドウに表示される内容を教えてください。

于 2012-04-08T05:48:10.340 に答える