Cette question concerne un site Web ASP.NET, initialement développé dans VS 2005 et maintenant dans VS 2008.
Ce site Web utilise deux DLL externes non gérées qui ne sont pas .NET et je n'ai pas le code source pour les compiler et je dois les utiliser telles quelles.
Ce site Web fonctionne correctement à partir de Visual Studio, localisant et accédant correctement à ces DLL externes. Cependant, lorsque le site Web est publié sur un serveur Web (exécutant IIS6 et ASP.NET 2.0) plutôt que sur le PC de développement, il ne peut pas localiser et accéder à ces DLL externes, et j'obtiens l'erreur suivante:
Unable to load DLL 'XYZ.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)
Les DLL externes se trouvent dans le répertoire bin du site Web, ainsi que les DLL gérées qui les encapsulent et toutes les autres DLL du site Web.
La recherche de ce problème révèle que de nombreuses autres personnes semblent avoir le même problème d'accès aux DLL externes non.NET à partir de sites Web ASP.NET, mais je n'ai pas trouvé de solution qui fonctionne.
J'ai essayé ce qui suit:
Toute assistance avec ce problème serait grandement appréciée!
Essayez de placer les DLL dans le répertoire\System32\Inetsrv. Il s'agit du répertoire de travail de IIS sur Windows Server.
Si cela ne fonctionne pas, essayez de placer les DLL dans le répertoire System32 et les fichiers de dépendance dans le répertoire Inetsrv.
Cela se produit car les DLL gérées sont copiées en double dans un emplacement temporaire sous le répertoire .NET Framework. Voir http://msdn.Microsoft.com/en-us/library/ms366723.aspx pour plus de détails.
Malheureusement, les DLL non gérées ne sont PAS copiées et le processus ASP.NET ne pourra pas les trouver lorsqu'il aura besoin de les charger.
Une solution simple consiste à placer les DLL non gérées dans un répertoire qui se trouve dans le chemin d'accès système (tapez "chemin d'accès" sur la ligne de commande pour voir le chemin d'accès sur votre machine) afin qu'elles puissent être trouvées par le processus ASP.NET. Le répertoire System32 est toujours dans le chemin d'accès, donc y placer les DLL non gérées fonctionne toujours, mais je recommanderais d'ajouter un autre dossier au chemin d'accès, puis d'ajouter les DLL là-bas pour éviter de polluer le répertoire System32. Un gros inconvénient de cette méthode est que vous devez renommer les DLL non gérées pour chaque version de votre application et vous pouvez rapidement avoir votre propre enfer de DLL.
Au lieu de placer la DLL dans un dossier qui se trouve déjà dans le chemin (comme system32), vous pouvez modifier la valeur du chemin dans votre processus en utilisant le code suivant
System.Environment.SetEnvironmentVariable("Path", searchPath + ";" + oldPath)
Ensuite, lorsque LoadLibrary essaie de trouver le DLL non géré), il analysera également searchPath. Cela peut être préférable à faire un gâchis dans System32 ou d'autres dossiers.
Pour compléter la réponse de Matt, voici ce qui a finalement fonctionné pour moi pour le serveur 64 bits 2003/IIS 6:
Une autre option consiste à intégrer la native DLL en tant que ressource dans la DLL managée. Ceci est plus compliqué dans ASP.NET, car cela nécessite d'écrire dans un dossier temporaire au moment de l'exécution. La technique est expliqué dans un autre SO réponse .
Toujours une valeur vérifier le chemin variable dans les paramètres de votre environnement aussi.
J'ai rencontré le même problème. Et j'ai essayé toutes les options ci-dessus, copier sur system32, inetpub, définir l'environnement du chemin, etc., rien n'a fonctionné. Ce problème est finalement résolu en copiant la DLL non gérée dans le répertoire bin de l'application Web ou du service Web.
Exécutez DEPENDS sur XYZ.dll directement, à l'emplacement où vous l'avez déployé. Si cela ne révèle rien de manquant, utilisez l'outil fuslogvw dans le SDK de la plateforme pour suivre les erreurs du chargeur. En outre, les journaux des événements contiennent parfois des informations sur les échecs de chargement des DLL.
Après avoir lutté toute la journée sur ce problème et finalement j'ai trouvé une solution qui me convient. Ce n'est qu'un test, mais la méthode fonctionne.
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();
}
}
}
}
}
}
Sur Application_start, utilisez ceci: (personnaliser les dossiers/bin/x64 et bin/dll/x64 selon les besoins)
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);