web-dev-qa-db-fra.com

Les DLL non managées ne parviennent pas à se charger sur le serveur ASP.NET

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:

  • Exécuter DEPENDS pour vérifier les dépendances afin d'établir que les trois premiers se trouvent dans le répertoire System32 du chemin, le dernier se trouve dans le framework .NET 2.
  • J'ai mis les deux DLL et leurs dépendances dans System32 et redémarré le serveur, mais le site Web ne pouvait toujours pas charger ces DLL externes.
  • A donné tous les droits sur ASPNET, IIS_WPG et IUSR (pour ce serveur) sur le répertoire bin du site Web et redémarré, mais le site Web n'a toujours pas pu charger ces DLL externes.
  • Ajout des DLL externes en tant qu'éléments existants aux projets et définition de leur propriété "Copier vers la sortie" sur "Copier toujours", et le site Web ne trouve toujours pas les DLL.
  • Définissez également leur propriété "Build Action" sur "Ressource intégrée" et le site Web ne trouve toujours pas les DLL.

Toute assistance avec ce problème serait grandement appréciée!

66
Werg38

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.

22
Matt

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.

44
onedozenbagels

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.

41
Matt Woodard

Pour compléter la réponse de Matt, voici ce qui a finalement fonctionné pour moi pour le serveur 64 bits 2003/IIS 6:

  1. assurez-vous que vos dlls/asp.net sont la même version (32/64 bits)
  2. Mettez les DLL non managées dans le répertoire inetsrv (notez que dans les fenêtres 64 bits, c'est sous syswow64, même si le répertoire sys32/inetsrv est créé)
  3. Laisser les DLL gérées dans/bin
  4. Assurez-vous que les deux ensembles de DLL ont des autorisations de lecture/exécution
11
dave

Jetez un œil avec FileMon ou ProcMon et filtrez les noms des DLL problématiques. Cela vous montrera quels répertoires sont analysés à la recherche des DLL et tous les problèmes d'autorisation que vous pourriez avoir.

6
Arnout

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 .

3
yzorg

Toujours une valeur vérifier le chemin variable dans les paramètres de votre environnement aussi.

2
annakata

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.

1
Ram Chavakula

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.

1
jlew

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();
                  }
                }
          }
        }
    }
}
1
Mad Dog

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);
0
Ers