5

Vistax64上のVisualStudio2008でWCFサービスライブラリを作成することは、x86DLLを参照するときに面倒です。32ビットDLLを呼び出すサービスは、64ビットOSで実行するためにx86のプラットフォームターゲットを持っている必要があります。これを行うと、サービスをデバッグしようとしたときにWcfSvcHostがBadImageFormatExceptionをスローします。MS接続に関するバグレポートがあります。私が使用した回避策は、WcfSvcHostを32ビットとしてコアフラグを立てることでした。

マニフェスト問題

私が遭遇した主な問題は、このサードパーティのネイティブ32ビットDLLが特定のWCFホストを使用してロードできないことです。サードパーティのDLLを使用するサービス操作が呼び出されると、次のエラーが発生します。

System.TypeInitializationException:''の型初期化子が例外をスローしました。

.ModuleLoadExceptionHandlerException:C++モジュールのロードに失敗する原因となったプライマリ例外の後にネストされた例外が発生しました。

System.BadImageFormatException:モジュールにアセンブリマニフェストが含まれていることが期待されていました。(HRESULTからの例外:0x80131018)

NestedException:

ハンドルが無効です。(HRESULTからの例外:0x80070006(E_HANDLE))

この例外は、WcfSvcHostの起動時に発生するのではなく、32ビットDLLを参照するサービス操作が呼び出されたときに発生します。非常に興味深いのは、コンソールアプリで同じapp.configを使用してこの同じサービスをホストすることには例外がなく、完全に機能することです。

using (ServiceHost host = new ServiceHost (typeof (MsgBrokerService))) {
    host.Open ();
    Console.WriteLine ("running");
    Console.ReadLine ();

この例外は、次の直後に発生します。

'WcfSvcHost.exe'(管理対象):ロード済み'C:\ Windows \ WinSxS \ x86_microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.3053_ none_d08d7bba442a9b36 \ msvcm80.dll '

この場合も、コンソールアプリには例外がなく、同じDLLが読み込まれます。

'ConsoleApp.vshost.exe'(管理対象):ロード済み'C:\ Windows \ WinSxS \ x86_microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.3053_ none_d08d7bba442a9b36 \ msvcm80.dll '

Microsoft製品サポートからの回答を参照してください。

更新#1:コンソールアプリケーションとWcfSvcHost.exeホストプロセスの両方が、同じセッションとログインユーザー(私)の下で実行されます。WcfSvcHost.exeをサービスのディレクトリにコピーし、手動で起動して同じ結果が得られました。また、Windowsイベントログで追加情報を確認し、sxstraceを使用しましたが、何もログに記録されませんでした。

Process Explorerを実行して、2つのプロセス間で次のことが同じであることを確認しました。

  • 画像:32ビット
  • カレントディレクトリ
  • ユーザー/SID
  • セッション
  • セキュリティ(グループが拒否され、特権が無効になります)

プロセスモニターを実行し、シンボルを構成すると、WcfSvcHostが次のレジストリとファイルを検索しますが、コンソールホストは検索しません。Process Monitorは大量のデータをログに記録しますが、何を探しているのかわかりません:(

HKLM \ SOFTWARE \ Microsoft \ Fusion \ PublisherPolicy \ Default \ policy.8.0.msvcm80__b03f5f7f11d50a3a C:\ Windows \ assembly \ GAC_32 \ msvcm80 \ 8.0.50727.3053__b03f5f7f11d50a3a C:\ Windows \ assembly \ GAC_MSIL \ msvc Windows \ assembly \ GAC \ msvcm80 \ 8.0.50727.3053__b03f5f7f11d50a3a

更新#2:これと同じ例外は、サービスがIIS 6 / WindowsServer2003の運用環境でホストされている場合に発生します。

アップデート#3:サードパーティの32ビット.NETアセンブリはStreamBase APIです:

  • sbclient.dll(管理対象)
  • monitor.netmodule(管理対象)
  • dotnetapi.dll(管理されていない)
  • pthreads-vc8.dll(管理されていない)

アップデート#4:成功せずにマニフェストを追加:

  1. dotnetapi.dllとpthreads-vc8.dllにRT_MANIFESTがあることを確認しました。sbclient.dll.NETアセンブリにマニフェストがありませんでした
  2. GACからsbclient.dllを削除しました
  3. 検証スキップ用にsbclient.dllを登録しました
  4. mt.exeを介してsbclient.dllとmonitor.netmoduleの両方にマニフェストを追加しました
  5. 検証済みのマニフェストが追加され、テスト中に予期されたファイルが読み込まれたことを確認しました(Visual Studio-デバッグモジュールウィンドウを介して)
  6. 同じBadImageFormatExceptionがBackgroundWorker.OnDoWork()の下でスローされ、呼び出しスタックはdotnetapi.dll ... DefaultDomain.Initalize()への呼び出しを示します。

msvcm80.dllにマニフェストがないことを確認しました。これが、マニフェストがないロードされた唯一のファイルだと思います:)

面白い発見

リフレクターにmonitor.netmoduleをロードすると、次のように表示されます。

'monitor.netmodule'には、アセンブリマニフェストが含まれていません。

エラーが表示されても、Reflectorはマネージコードを分解できます。

4

7 に答える 7

3

少し遅れていますが、詳細設定でアプリ プール設定の [32 ビット アプリケーションを有効にする] を true に変更することもできます。

于 2010-12-01T18:06:38.183 に答える
2

マイクロソフト製品サポートはこの質問を解決しました: これは仕様によるものです。WcfSvcHost または IIS WCF ホストを使用している場合、アンマネージ コードは既定の AppDomain に読み込まれません。

純粋なイメージは、C ランタイム ライブラリの CLR バージョンを使用します。ただし、CRT は検証できないため、/clr:safe でコンパイルする場合は CRT を使用できません。詳細については、C ランタイム ライブラリを参照してください。

http://msdn.microsoft.com/en-us/library/k8d11d4s.aspx

于 2009-06-03T00:34:09.110 に答える
0

イベントビューアに何か特別なものがありますか?
Vistaでは、明らかな問題がある場合、イベントビューアにその痕跡が表示され、SxsTraceを使用するように指示されます。

于 2009-04-15T20:00:28.613 に答える
0

mt.exeファイルを使用して、このDLLにマニフェストを手動で追加できますか?

mt.exeの使用に関するMSDNの記事

于 2009-04-18T23:49:38.753 に答える
0

これは少しばかげているように思えるかもしれません。ただし、サービスが正しいアプリケーション プールで実行されていることを確認してください。

于 2012-05-18T15:22:39.687 に答える
0

エラーの説明を提供することはできません。コードがサービスとして実行されるコンテキストと、コードをコンソール アプリケーションに配置したときに実行されるコンテキストとの間に権限の違いがあるという私の最初の疑いだけです。E_HANDLE HRESULT は、ここでの手がかりです。ログインしたユーザーとしてコンソール アプリケーションを実行すると仮定すると、そのユーザーとして開始するようにサービスを構成することもできます。その構成で機能する場合は、失敗したときに利用できない必要なリソースを絞り込むことができます。

回避策を提案できます。問題の DLL に奇妙な点があり、ホストされたサービスでの動作を妨げている場合は、犠牲プロセス アプローチを取ることができます。これは、通常、頻繁にクラッシュする DLL を分離するために使用されるため、このように名付けられました。簡単に言うと、名前付きパイプまたはその他の IPC メソッドを使用して要求と結果を渡すことで、メイン プロセスに代わって DLL をロードして呼び出すことのみを目的とするプロキシ プログラムを作成します。DLL がクラッシュした場合は、プロキシ プログラムの新しいインスタンスを開始します。あなたの場合、ラッパープログラムだけが32ビットである必要があるという追加の利点があります。

于 2009-04-15T13:39:49.790 に答える
0

自分でこの問題に遭遇しました。役立つ投稿を見つけました。他の投稿で述べたように、Microsoft は、これは仕様によるものであると述べています。基本的に、次のことを行う必要があります。

  1. WcfSvcHost.exe のバージョンを見つけます。(私と Visual Studio 2017 の場合: C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE)

  2. 開発者コマンド プロンプトを起動する

  3. cmd を実行: copy C:\SourcePath\WcfSvcHost.exe C:\DestinationPath\WcfSvcHost32.exe (宛先は関係ありません)

  4. cmd: corflags /32BIT+ /Force WcfSvcHost32.exe(DestinationPath への cd が必要な場合があります

  5. Visual Studio で、WCF プロジェクトのプロパティ > [デバッグ] タブ > [外部プログラムの開始] を開きます。C:\DestinationPath\WcfSvcHost32.exe

  6. また、コマンド ライン引数を追加します。

    /service:MyWCFProjectName.dll /config:MyWCFProjectName.dll.config

    ($ProjectDir)注:ここで使用する必要はありません

  7. アプリを起動します。これで、WcfServiceHost.exe を個別に自由に起動できます。

  8. 必要に応じて、ソリューション > スタートアップ プロジェクトの設定 > 複数のスタートアップ プロジェクト > Wcf プロジェクトとクライアント プロジェクトの選択に移動します。

于 2018-04-20T14:13:09.567 に答える