アンマネージ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とサーバーを再起動しましたが、ウェブサイトはまだ これらの外部DLLをロードできませんでした。
- ASPNET、IIS_WPG、およびIUSR(そのサーバーの)に対する完全な権利を Webサイトのbinディレクトリを再起動しましたが、Webサイトはまだできませんでした これらの外部DLLをロードします。
- 外部DLLを既存のアイテムとしてプロジェクトに追加し、設定します <!> quot;出力にコピー<!> quot;プロパティを<!> quot; Copy Always <!> quot;およびwebsite それでもDLLが見つかりません。
- また、<!> quot; Build Action <!> quot;を設定します。 <!> quot; Embedded resource <!> quot;のプロパティそして ウェブサイトはまだDLLを見つけることができません。
この問題に関する支援は大歓迎です!
解決
dllを\ System32 \ Inetsrvディレクトリに入れてみてください。これは、Windows Server上のIISの作業ディレクトリです。
これが機能しない場合は、dllをSystem32ディレクトリに、依存関係ファイルをInetsrvディレクトリに入れてみてください。
他のヒント
これは、マネージdllが.NET Frameworkディレクトリの下の一時的な場所にシャドウコピーされるために発生します。 http://msdn.microsoft.com/en-us/library/ms366723を参照してください。詳細については、aspx 。
残念ながら、アンマネージdllはコピーされず、ASP.NETプロセスはそれらをロードする必要があるときにそれらを見つけることができません。
簡単な解決策の1つは、管理されていないdllをシステムパス(<!> quot; path <!> quotと入力して、コマンドラインでマシンのパスを表示)に配置することです。 ASP.NETプロセスによって検出されます。 System32ディレクトリはパス内に常にあるので常にですので、そこにアンマネージdllを置くことは常に機能しますが、System32ディレクトリの汚染を防ぐために他のフォルダーをパスに追加し、そこにdllを追加することをお勧めします。この方法の大きな欠点の1つは、アプリケーションのすべてのバージョンのアンマネージdllの名前を変更する必要があることです。また、独自のdllヘルルをすばやく作成できます。
dllを既にパスにあるフォルダー(system32など)に配置する代わりに、次のコードを使用してプロセスのパス値を変更できます
System.Environment.SetEnvironmentVariable("Path", searchPath + ";" + oldPath)
次に、LoadLibraryがアンマネージDLLを見つけようとすると、searchPathもスキャンされます。これは、System32または他のフォルダーで混乱を起こすよりも望ましい場合があります。
Mattの答えに加えて、これが最終的に64ビットサーバー2003 / IIS 6で私にとってうまくいったことです:
- dll / asp.netが同じバージョン(32/64ビット)であることを確認してください
- 管理されていないdllをinetsrv dirに配置します(64ビットウィンドウでは、sys32 / inetsrvディレクトリが作成されているにもかかわらず、これはsyswow64の下にあることに注意してください)
- マネージDLLを/ binに残す
- dllの両方のセットに読み取り/実行権限があることを確認してください
別のオプションは、ネイティブDLLをマネージDLLのリソースとして埋め込みます。これは、実行時に一時フォルダーに書き込む必要があるため、ASP.NETではより複雑です。 この手法については、別のSOの回答で説明されています。
常に価値があるチェック環境設定のパス変数。
XYZ.dllを展開した場所で、直接DEPENDSを実行します。それでも見つからない場合は、プラットフォームSDKのfuslogvwツールを使用してローダーエラーをトレースします。また、イベントログにはDLLのロードの失敗に関する情報が含まれることがあります。
同じ問題に遭遇しました。そして、上記のすべてのオプションを試してみましたが、system32、inetpubへのコピー、パス環境の設定など何も機能しませんでした。 この問題は、アンマネージdllをWebアプリケーションまたはWebサービスのbinディレクトリにコピーすることで最終的に解決されます。
<!>#1040;この問題で終日苦労し、ようやく自分に合った解決策を見つけました。これは単なるテストですが、メソッドは機能しています。
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();
}
}
}
}
}
}
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);