web-dev-qa-db-ja.com

アンマネージDLLがASP.NETサーバーにロードできない

この質問は、元はVS 2005で、現在はVS 2008で開発されたASP.NET Webサイトに関連しています。

このWebサイトは、.NETではない2つのアンマネージ外部DLLを使用しており、それらをコンパイルするソースコードがなく、そのまま使用する必要があります。

このWebサイトはVisual Studio内から正常に動作し、これらの外部DLLを正しく見つけてアクセスします。ただし、Webサイトが開発PCではなくWebサーバー(IIS6およびASP.NET 2.0を実行)で公開されると、これらの外部DLLを見つけてアクセスできず、次のエラーが表示されます。

Unable to load DLL 'XYZ.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)

外部DLLは、それらをラップするマネージDLLおよびWebサイトの他のすべてのDLLとともに、Webサイトのbinディレクトリにあります。

この問題を検索すると、他の多くの人がASP.NET Webサイトから外部の非.NET DLLにアクセスするのと同じ問題を抱えているように見えますが、有効なソリューションは見つかりませんでした。

私は次を試しました:

  • DEPENDSを実行して依存関係をチェックし、最初の3つがパスのSystem32ディレクトリにあり、最後が.NET 2フレームワークにあることを確認します。
  • 2つのDLLとそれらの依存関係をSystem32に配置してサーバーを再起動しましたが、Webサイトはこれらの外部DLLをロードできませんでした。
  • ASPNET、IIS_WPGおよびIUSR(そのサーバーの)に対する完全な権限をWebサイトのbinディレクトリに付与して再起動しましたが、Webサイトはこれらの外部DLLをロードできませんでした。
  • 既存のアイテムとして外部DLLをプロジェクトに追加し、「出力にコピー」プロパティを「常にコピー」に設定しても、WebサイトはDLLを見つけることができません。
  • また、「ビルドアクション」プロパティを「埋め込みリソース」に設定しても、WebサイトはDLLを見つけることができません。

この問題に関する支援は大歓迎です!

66
Werg38

Dllを\ System32\Inetsrvディレクトリに配置してみてください。これは、Windows Server上のIISの作業ディレクトリです。

これが機能しない場合は、dllをSystem32ディレクトリに、依存関係ファイルをInetsrvディレクトリに入れてみてください。

22
Matt

これは、マネージDLLが.NET Frameworkディレクトリの下の一時的な場所にシャドウコピーされるために発生します。詳細については、 http://msdn.Microsoft.com/en-us/library/ms366723.aspx を参照してください。

残念ながら、アンマネージdllはコピーされず、ASP.NETプロセスはそれらをロードする必要があるときにそれらを見つけることができません。

簡単な解決策の1つは、管理されていないdllをシステムパス(コマンドラインで「path」と入力してマシン上のパスを表示)にあるディレクトリに配置し、ASP.NETプロセスで見つけられるようにすることです。 System32ディレクトリはパスにalwaysであるため、そこにアンマネージdllを配置すると常に機能しますが、パスに他のフォルダーを追加してから追加することをお勧めしますSystem32ディレクトリの汚染を防ぐために、そこにあるDLL。この方法の大きな欠点の1つは、アプリケーションのすべてのバージョンのアンマネージdllの名前を変更する必要があり、独自のdllヘルルがあることです。

44
onedozenbagels

既にパス(system32など)にあるフォルダーにdllを配置する代わりに、次のコードを使用してプロセスのパス値を変更できます。

System.Environment.SetEnvironmentVariable("Path", searchPath + ";" + oldPath)

次に、LoadLibraryがアンマネージDLLを見つけようとすると、searchPathもスキャンされます。これは、System32または他のフォルダーで混乱を起こすよりも望ましい場合があります。

41
Matt Woodard

Mattの答えに加えて、これが最終的に64ビットサーバー2003で私にとってうまくいったことです/ IIS 6:

  1. dll/asp.netが同じバージョン(32/64ビット)であることを確認してください
  2. 管理されていないdllをinetsrv dirに配置します(64ビットウィンドウでは、sys32/inetsrvディレクトリが作成されていても、これはsyswow64の下にあることに注意してください)
  3. 管理されたdllを/ binに残します
  4. Dllの両方のセットに読み取り/実行権限があることを確認してください
11
dave

FileMon または ProcMon で調べて、問題のあるDLLの名前をフィルターします。これにより、DLLの検索でスキャンされるディレクトリと、発生する可能性のあるアクセス許可の問題が表示されます。

6
Arnout

別のオプションは、ネイティブDLLをマネージDLLのリソースとして埋め込むことです。これは、実行時に一時フォルダーに書き込む必要があるため、ASP.NETではより複雑です。 テクニックは別のSO answer で説明されています。

3
yzorg

常に価値がある パスをチェックする 環境設定でも変数。

2
annakata

私は同じ問題に出くわしました。そして、上記のすべてのオプションを試してみましたが、system32、inetpubへのコピー、パス環境の設定など何も機能しませんでした。この問題は、アンマネージdllをWebアプリケーションまたはWebサービスのbinディレクトリにコピーすることで最終的に解決されます。

1
Ram Chavakula

XYZ.dllを展開した場所で直接DEPENDSを実行します。見つからない場合は、プラットフォームSDKのfuslogvwツールを使用してローダーエラーをトレースします。また、イベントログには、DLLのロードの失敗に関する情報が含まれることがあります。

1
jlew

Аfterはこの問題に終日苦労し、最終的に私は自分に合った解決策を見つけました。これは単なるテストですが、メソッドは機能しています。

namespace TestDetNet
{
    static class NativeMethods
    {
        [DllImport("kernel32.dll")]
        public static extern IntPtr LoadLibrary(string dllToLoad);

        [DllImport("kernel32.dll")]
        public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);


        [DllImport("kernel32.dll")]
        public static extern bool FreeLibrary(IntPtr hModule);
    }

    public partial class _Default : System.Web.UI.Page
    {
        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
        private delegate int GetRandom();

        protected System.Web.UI.WebControls.Label Label1;
        protected void Page_Load(object sender, EventArgs e)
        {
            Label1.Text = "Hell'ou";
            Label1.Font.Italic = true;
        }

        protected void Button1_Click(object sender, EventArgs e)
        {
            if (File.Exists(System.Web.HttpContext.Current.Server.MapPath("html/bin")+"\\DelphiLibrary.dll")) {
                IntPtr pDll = NativeMethods.LoadLibrary(System.Web.HttpContext.Current.Server.MapPath("html/bin")+"\\DelphiLibrary.dll");
                if (pDll == IntPtr.Zero) { Label1.Text =  "pDll is zero"; }
                else
                {
                  IntPtr pAddressOfFunctionToCall = NativeMethods.GetProcAddress(pDll, "GetRandom");
                  if (pAddressOfFunctionToCall == IntPtr.Zero) { Label1.Text += "IntPtr is zero";   }
                  else
                  {
                    GetRandom _getRandom = (GetRandom)Marshal.GetDelegateForFunctionPointer(pAddressOfFunctionToCall,typeof(GetRandom));

                    int theResult = _getRandom();

                    bool result = NativeMethods.FreeLibrary(pDll);
                    Label1.Text = theResult.ToString();
                  }
                }
          }
        }
    }
}
1
Mad Dog

Application_startでこれを使用します(必要に応じて/ bin/x64およびbin/dll/x64フォルダーをカスタマイズします)

String _path = String.Concat(System.Environment.GetEnvironmentVariable("PATH")
                ,";"
                , System.Web.Hosting.HostingEnvironment.MapPath("~/bin/x64")
                ,";"
                , System.Web.Hosting.HostingEnvironment.MapPath("~/bin/dll/x64")
                ,";"
                );
            System.Environment.SetEnvironmentVariable("PATH", _path, EnvironmentVariableTarget.Process);
0
Ers