Title: Unmanaged DLLs fail to load on ASP.NET server
Tags: asp.net;dll;iis-6;unmanaged
Question: This question relates to an ASP.NET website, originally developed in VS 2005 and now in VS 2008.

This website uses two unmanaged external DLLs which are not .NET and I do not have the source code to compile them and have to use them as is.

This website runs fine from within Visual Studio, locating and accessing these external DLLs correctly. However, when the website is published on a webserver (runnning IIS6 and ASP.NET 2.0) rather than the development PC it cannot locate and access these external DLLs, and I get the following error:

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

The external DLLs are located in the bin directory of the website, along with the managed DLLs that wrap them and all the other DLLs for the website.

Searching this problem reveals that many other people seem to have the same problem accessing external non.NET DLLs from ASP.NET websites, but I haven't found a solution that works.

I have tried the following:


Running DEPENDS to check the dependencies to establish that the first three
are in System32 directory in the path, the last is in the .NET 2
framework.
I put the two DLLs and their dependencies in
System32 and rebooted the server, but website still
couldn't load these external DLLs.
Gave full rights to ASPNET, IIS_WPG and IUSR (for that server) to
the website bin directory and rebooted, but website still couldn't
load these external DLLs.
Added the external DLLs as existing items to the projects and set
their "Copy to Output" property to "Copy Always", and website
still can't find the DLLs.
Also set their "Build Action" property to "Embedded resource" and
website still can't find the DLLs.


Any assistance with this problem would be greatly appreciated!


Here is the accepted answer: Try putting the dlls in the \System32\Inetsrv directory.  This is the working directory for IIS on Windows Server.

If this doesn't work try putting the dlls in the System32 directory and the dependency files in the Inetsrv directory.

Comment for this answer: Here's an answer without needing to pollute the system32 folder: http://stackoverflow.com/a/4598747/92756
Comment for this answer: instead, you can disable ShadowCopying by adding  on the web.config, provided you are not modifying binaries in the live application.
Comment for this answer: you just saved my day, +1
Comment for this answer: I got burned by making a copy of my DLL and putting it in System32 because I forgot about it, and then I had the wrong version of Microsoft.Azure.Documents.ServiceInterop.dll getting loaded for my project which resulted in weird local queryRanges[0].isMinInclusive errors when trying to connect to the db.  My fix ended up being to make sure my local IIS DefaultAppPool Identity was my local user.  See also: https://github.com/Azure/azure-documentdb-dotnet/issues/267

Here is another answer: Аfter struggling all day over this problem and finally I found a solution which suits me. It's just a test, but the method is working.

```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();
                  }
                }
          }
        }
    }
}
```


Here is another answer: As an alternate to putting the dll in a folder that is already in the path (like system32) you can change the path value in your process by using the following code

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

Then when LoadLibrary tries to find the unmanaged DLL it will also scan searchPath.  This may be preferable to making a mess in System32 or other folders.

Comment for this answer: Only works with PInvoke. if using a mixed mode assembly, the DLLs are linked (and fail) before any code runs.

Here is another answer: This happens because the managed dlls get shadow copied to a temporary location under the .NET Framework directory.  See http://msdn.microsoft.com/en-us/library/ms366723.aspx for details.

Unfortunately, the unmanaged dlls do NOT get copied and the ASP.NET process won't be able to find them when it needs to load them.

One easy solution is to put the unmanaged dlls in a directory that is in the system path (type "path" at the command line to see the path on your machine) so that they can be found by the ASP.NET process.  The System32 directory is always in the path, so putting the unmanaged dlls there always works, but I would recommend adding some other folder to the path and then adding the dlls there to prevent polluting the System32 directory.  One big drawback to this method is you have to rename the unmanaged dlls for every version of your application and you can quickly have your own dll hell.

Comment for this answer: From my experience, when I create a new directory, add it to PATH and put the DLL in there, it is found just fine when running local. However, this is not the case when hosted on IIS - the DLL is only found when I have it in /Windows/System32. Does IIS perhaps use a different variable for the path in some cases?
Comment for this answer: This is a better answer than the accepted answer because it explains why you'd want to do this.

Here is another answer: I have come across the same issue. And I tried all above options, copying to system32, inetpub, setting path environment, etc nothing worked. 
This issue is finally resolved by copying unmanaged dll to the bin directory of web application or web service. 


Here is another answer: Another option is embedding the native DLL as a resource in the managed DLL.  This is more complicated in ASP.NET, as it requires writing to temporary nataliehaney@example.net.  The technique is explained in another SO answer.

Comment for this answer: why wouldn't you recommend this? I am considering to use this approach for Azure Functions app where I need to run native executable from the managed assembly.
Comment for this answer: I wouldn't recommend this approach for apps or libraries that might be run or used in PAAS hosts (like Azure Websites).
Comment for this answer: Azure functions didn't exist when I wrote it.  Azure Functions are so small and targeted, if you get it working then go for it!

Here is another answer: Adding to Matt's answer, this is what finally worked for me for 64-bit server 2003 / IIS 6:


make sure your dlls / asp.net are the same version (32 / 64 bit)
Put the unmanaged dlls in inetsrv dir (note that in 64 bit windows, this is under syswow64, even though the sys32/inetsrv directory is created)
Leave the managed dlls in /bin
Make sure both sets of dll's have read/execute permissions 


Comment for this answer: +1 for the location of inetsrv on 64 bit systems.  Thanks for that.
Comment for this answer: I found this to be too tedious and  won't allow for differing versions of dlls. We resolved this by using symbolic links.

Here is another answer: Run DEPENDS on XYZ.dll directly, in the location that you have deployed it to.  If that doesn't reveal anything missing, use the fuslogvw tool in the platform SDK to trace loader errors.  Also, the event logs sometimes contain information about failures to load DLLs.

Comment for this answer: Could you link to where I can get DEPENDS?

Here is another answer: Take a look with FileMon or ProcMon and filter on the names of the troublesome DLLs. This will show you what directories are scanned in search of the DLLs, and any permission issues you might have.

Comment for this answer: ProcMon is extremely useful in figuring out dependencies and what a certain DLL will not load.

Here is another answer: Always worth checking the path variable in your environment settings too.

Comment for this answer: @Ristogod: The answer is four years old and you're downvoting me because I didn't keep track to make sure the link was active? Tough crowd.
Comment for this answer: @Drax - I thought the important information was to check your path variable
Comment for this answer: @annakata You're supposed to extract the important information from the link so when it goes down this answer is still valid ;)
Comment for this answer: @annakata The answer is clear enough for me but probably not that self explanatory for all interested users :)

Here is another answer: On Application_start use this: 
(customise /bin/x64 and bin/dll/x64 folders as needed)

```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);
```


{'source': 'StackExchangeDataset', 'subset': 'stackoverflow.com', 'metadata': {'AnswerCount': 11, 'CommentCount': 0, 'ContentLicense': 'CC BY-SA 2.5', 'CreationDate': '2008:00:12/05/08', 'FavoriteCount': 27.0, 'PostTypeId': 1, 'Tags': '<asp.net><dll><iis-6><unmanaged>', 'Title': 'Unmanaged DLLs fail to load on ASP.NET server', 'ViewCount': 52667, 'id': 344608, 'user_AboutMe': 'Software Engineer specializing in modeling and simulation', 'user_AccountId': 13656.0, 'user_DisplayName': 'Werg38', 'user_Reputation': 1120.0, 'user_Views': 147.0, 'user_id': 27569.0}}