4

いくつかのマネージクラスを含むマネージc++dllがあり、dllに静的にリンクしているライブラリ内のネイティブc++コードを呼び出します。ただし、dllでRegAsm.exeを実行しようとすると、ツールは「登録したタイプがありません」と正しく報告しますが、ハングします。これはローダーロックの問題であり、RegAsmがロードしようとするとdllがハングすることは間違いありません。Visual Studio 2008ExpressEditionを使用しています。

ネイティブコードをdllに配置する場合はすべて正常に機能しますが、ライブラリから静的にリンクする場合は機能しないことに戸惑います。この投稿がこの質問に似ていることは承知していますが、dllにDllMainがありません。DllMainからMSILコードを実行するリスクはありません。また、個々のファイルに/clrを設定するというアドバイスに従うことは役に立ちませんでした。

/ NOENTRYを使用してdllをコンパイルすると、ロックの問題は修正されますが、Type initializer for <Module> threw exception例外が発生してアプリケーションが破損するため、.NET2003でのみ推奨されるようです。

静的メンバーの初期化が原因である可能性があると思われますが、静的ライブラリでMSILにコンパイルされるのはなぜ私を超えているのでしょうか。

明確にするために:dllでRegAsm.exeを実行する必要はありませんが、ローダーロックの問題のチェックとして使用しています。実際には、COMに表示されるクラスをほとんど実装していないac#アセンブリでdllを使用しているため、そのクラスでCOM登録を行う必要があります。最後に、COM相互運用機能の登録中にC#IDEがクラッシュし、'R6033 c ++ランタイムエラーが報告されます:ネイティブコードの初期化中にこのアセンブリのMSILコードを使用しようとしました。これは、アプリケーションにバグがあることを示しています。これは、ネイティブコンストラクターまたはDllMainからMSILコンパイル済み(/ clr)関数を呼び出した結果である可能性があります。

問題は解決しましたが、不明な点がいくつかあり、興味があります。

動作が停止したときに、静的にリンクされたlibのヘッダーファイルに2つの静的変数が追加されていることに気付きました。これは、次のようになります。

// The whole header is forced to compile as native 
#pragma managed(push, off)
....
static const std::locale commaSeparator(std::locale::classic(), 
                                        new DecimalSeparator<char>(','));;
....
#pragma managed(pop)

初期化を.cppファイルに移動する(およびに変更staticするextern)と、ローダーのロックが修正されます。イニシャライザがMSILにコンパイルされる理由を誰かが指摘できますか?

修正前は、マネージdllからヘッダーファイルを#includeしただけで、問題なく動作しました。しかし、ヘッダーを含め、libにもリンクしていると、うまくいきませんでした。libも内部でヘッダーを使用するので、静的変数の2つのインスタンスになりましたか?いずれにせよ、なぜMSILコードの実行に関する苦情があるのでしょうか。

今はうまくいきますが、どんな洞察も歓迎します。

4

2 に答える 2

1

Compiilerは、ユーザー定義のDllMainを独自のコードでラップします。このコードは、ランタイムライブラリとグローバル変数を初期化するために使用されます(ユーザー定義のDllMainは、既に作成されたグローバルオブジェクトで実行でき、標準ライブラリを使用できます)。DllMainがない場合でも、コンパイラによって生成されたものがあります。/ NOENTRYを使用して、リンカにそれを無視するように指示します。

したがって、静的変数のコンストラクターで何かを実行することは、DllMainから実行することと実質的に同じであり、ここではそうであるように思われます。

于 2011-08-18T06:40:53.193 に答える
1

次のページ(特に静的オブジェクトの初期化ヘッダーセクションでの実装)には、次のように書かれています。

/ clrを有効または無効にしたCPPファイルの両方に同じヘッダーを含めることができるか、#includeを#pragmaアンマネージブロック内にラップできるため、ヘッダーに実装を提供する関数のMSILバージョンとネイティブバージョンの両方を含めることができます。 。

Visual C ++ 2005では、ローダーロックを処理するユーザーの便宜のために、リンカーは、両方が提示されたときに、マネージよりもネイティブ実装を選択します。
...ただし、このリリースでは、コンパイラに関する2つの未解決の問題のため、このルールには2つの例外があります
。...-インライン関数の呼び出しは、グローバル静的関数ポインタを介して行われます。このシナリオは、仮想関数がグローバル関数ポインターを介して呼び出されるため、特に注目に値します。

静的変数を管理対象dll内に直接配置する場合(または\ clrを使用してコンパイルする場合)、ネイティブ静的変数の初期化のみがDllMain内で行われるため、ローダーロックは回避されます。ただし、ネイティブとしてコンパイルされた静的変数は、MSILコードを実行するとデッドロックします。この場合、MSILは、静的オブジェクトのコンストラクターによって使用されるSTLの一部に対して生成されます。これは、ネイティブ実装とMSIL実装の両方で提示された場合の驚くべきリンカーの動作が原因です。

解決策は次のとおりです。

  • すべてをコンパイルします/clr(静的ライブラリを使用する必要があるため、不可能です)
  • すべての#includedサードパーティヘッダー(STL)の前に#pragma unmanaged(複雑すぎる)が付いていることを確認してください
  • 静的変数の初期化をヘッダーから削除します(外部リンケージを介して)

    // Solved by replacing initialization in header file
    static const std::locale commaSeparator(...);
    // with 
    extern const std::locale commaSeparator;
    // and doing initialization in a cpp file
    
于 2011-08-22T08:53:45.393 に答える