FileNotFoundException: Could not load file or assembly - c#

I have a dll (Tracker.dll) compiled from C# and need to use it in native C++. I have that problem solved; since I cannot modify the C#, I am writing a managed C++ wrapper and exporting the classes accordingly. For a (simplified) example:
TrackerWrapper.h
#pragma once
#include <memory>
class __declspec(dllexport) TrackerWrapper {
public:
TrackerWrapper();
~TrackerWrapper();
void Track();
private:
struct Impl;
std::unique_ptr<Impl> pimpl;
};
TrackerWrapper.cpp
#using "Tracker.dll"
#include "TrackerWrapper.h"
#include <msclr\auto_gcroot.h>
using namespace System::Runtime::InteropServices;
struct TrackerWrapper::Impl {
msclr::auto_gcroot<Tracker^> tracker;
Impl() : tracker(gcnew Tracker()) {}
~Impl() {}
};
TrackerWrapper::TrackerWrapper() : pimpl(new Impl()) {}
TrackerWrapper::~TrackerWrapper() {}
void TrackerWrapper::Track() {
pimpl->tracker->Track();
}
Main.cpp
#include "TrackerWrapper.h"
int main() {
TrackerWrapper tracker;
tracker->Track();
return 0;
}
As long as all of the objects and binaries are in the same directory, after compiling with
cl /clr /LD TrackerWrapper.cpp
cl Main.cpp TrackerWrapper.lib,
everything runs perfectly. However, ideally we need the Tracker.dll as well as TrackerWrapper.lib and TrackerWrapper.dll to be in a separate directory, e.g. bin.
So, the directory structure might look like:
bin\
Tracker.dll
TrackerWrapper.dll
TrackerWrapper.lib
<other objects>
Main.cpp
TrackerWrapper.h
TrackerWrapper.cpp
I can get everything to compile by adding bin to my %PATH%, %LIB% and %LIBPATH% environment variables (or on the command line at compile time via /link and /AI), but when I execute the resulting executable I get the following error:
Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'Tracker, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
at TrackerWrapper.Impl.{ctor}(Impl* )
at TrackerWrapper.{ctor}(TrackerWrapper* )
I have tried changing #using "Tracker.dll" to a relative as well as an absolute path, but I get the same problem.
Any ideas?

Two things you can try:
Check if there's inner exception in FileNotFoundException, if does,
it might give you details.
Monitor the process with process monitor from System internal, it can will log all file activity of the the process, from the log, you can tell which file is missing. Remember to the set the filter to only monitor your process, other wise it will monitor all processes.

Your library is loaded by the .net infrastructure and it only searches by default at the app directory or at the GAC.
If your app were .net then you can specify a library path in the App.config but as your app is native don't know if the mixed dll will load the App.config or not, may be you can try.
From MSDN:
You can use the < probing > element in the application configuration
file to specify subdirectories the runtime should search when locating
an assembly.
If that does not work then your last option is to add the libraries to the GAC, but the library will not really be in the specified folder but copied to the GAC's folder.

Related

How can I ensure that auth.dll can be loaded?

I'm trying to use crypto++ in c++ clr class library.
The problem is that I get an error as I run the app, but it builds successfully.
Unhandled Exception: System.IO.FileLoadException: Could not load file or assembly 'auth.dll' or one of its dependencies. A dynamic link library (DLL) initialization routine failed. (Exception from HRESULT: 0x8007045A)
at ConsoleApp52.Program.Main(String[] args)
This error only occurs when I include anything from crypto++
#include "dll.h"
#include "sha.h"
#include "filters.h"
#include "hex.h"
If I remove the following lines, it works.
I've tried copying the cryptopp.dll to the bin/x64/Debug and bin/Debug, but it did not resolve the issue.
What else do I need to include? Am I Missing something?
Dependecies:
Error code 0x8007045A most often means 32/64 bit DLL incompatibility.
If you're using native DLLs with managed code, make sure to use 64-bit versions on a 64-bit OS.

C# wrapper library around unmanaged DLL requires unmanaged DLL to be in same directory during build

Usually when referencing a managed DLL that wraps an unmanaged DLL with PInvoke, you have to reference those two DLLs separately - the managed one as a standard <Reference/> in your csproj and the unmanaged one as linked <content/> (as outlined here). However, I recently came across a managed wrapper library which not only auto-copies the unmanaged DLL along with it during the build, but actually produces a build error when the unmanaged DLL is not present in the same directory! This is the Microsoft.Z3 library, which has a managed DLL (Microsoft.Z3.dll) wrapping an unmanaged DLL (libz3.dll) with PInvoke so you can use the library in C#.
If you put the two Z3 DLLs together in a directory, referencing only Microsoft.Z3.dll, then compile your project with msbuild, you'll get both DLLs in the output directory without referencing libz3.dll at all! Looking in the output produced by msbuild /verbosity:diag, I see the following references to libz3.dll:
Primary reference "Microsoft.Z3, Version=4.7.1.0, Culture=neutral, PublicKeyToken=9c8d792caae602a2". (TaskId:9)
Resolved file path is "C:\Users\ahelwer\source\test\Framework\lib\z3\Microsoft.Z3.dll". (TaskId:9)
Reference found at search path location "{HintPathFromItem}". (TaskId:9)
Found embedded scatter file "libz3.dll". (TaskId:9)
The ImageRuntimeVersion for this reference is "v4.0.30319". (TaskId:9)
...
Output Item(s):
_ReferenceScatterPaths=
C:\Users\ahelwer\source\test\Framework\lib\z3\libz3.dll
CopyLocal=true
FusionName=
HintPath=lib\z3\Microsoft.Z3.dll
OriginalItemSpec=C:\Users\ahelwer\source\test\Framework\lib\z3\Microsoft.Z3.dll
ResolvedFrom={HintPathFromItem}
Version=4.7.1.0 (TaskId:9)
Which somehow leads to it being copied:
Task "Copy" (TaskId:22)
Task Parameter:
SourceFiles=
C:\Users\ahelwer\source\test\Framework\lib\z3\Microsoft.Z3.dll
CopyLocal=true
FusionName=Microsoft.Z3, Version=4.7.1.0, Culture=neutral, PublicKeyToken=9c8d792caae602a2
HintPath=lib\z3\Microsoft.Z3.dll
ImageRuntime=v4.0.30319
OriginalItemSpec=Microsoft.Z3
ReferenceSourceTarget=ResolveAssemblyReference
ResolvedFrom={HintPathFromItem}
Version=4.7.1.0
C:\Users\ahelwer\source\test\Framework\lib\z3\libz3.dll
CopyLocal=true
FusionName=
HintPath=lib\z3\Microsoft.Z3.dll
OriginalItemSpec=C:\Users\ahelwer\source\test\Framework\lib\z3\Microsoft.Z3.dll
ResolvedFrom={HintPathFromItem}
Version=4.7.1.0 (TaskId:22)
Task Parameter:
DestinationFiles=
bin\Debug\Microsoft.Z3.dll
CopyLocal=true
FusionName=Microsoft.Z3, Version=4.7.1.0, Culture=neutral, PublicKeyToken=9c8d792caae602a2
HintPath=lib\z3\Microsoft.Z3.dll
ImageRuntime=v4.0.30319
OriginalItemSpec=Microsoft.Z3
ReferenceSourceTarget=ResolveAssemblyReference
ResolvedFrom={HintPathFromItem}
Version=4.7.1.0
bin\Debug\libz3.dll
CopyLocal=true
FusionName=
HintPath=lib\z3\Microsoft.Z3.dll
OriginalItemSpec=C:\Users\ahelwer\source\test\Framework\lib\z3\Microsoft.Z3.dll
ResolvedFrom={HintPathFromItem}
Version=4.7.1.0 (TaskId:22)
It gets more mysterious, because if I take libz3.dll out of the directory, the build fails with the following error:
"C:\Users\ahelwer\source\test\Framework\FrameworkTest.csproj" (default target) (1) ->
(_CopyFilesMarkedCopyLocal target) ->
C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\bin\Microsoft.Common.CurrentVersion.targe
ts(4358,5): error MSB3030: Could not copy the file "C:\Users\ahelwer\source\test\Framework\lib\z3\libz3.dll" because it
was not found. [C:\Users\ahelwer\source\test\Framework\FrameworkTest.csproj]
Even if I reference libz3.dll in the standard way with <content/> in my csproj!
Questions:
What is special about Microsoft.Z3.dll that enables it to require libz3.dll be in the same directory during build? Was it compiled with certain flags?
How can I add this effect to a managed wrapper library of my own?
Is there any way to remove this effect from Microsoft.Z3.dll, or would I have to recompile it in a different way?
This is what's CSC (the C# compiler) calls a "link resource". It works with any type of file.
So for example, if you have this kind of code in a DLL project:
using System.Runtime.InteropServices;
namespace Microsoft.Z3
{
public static class DoSomething
{
[DllImport("libz3.dll")]
public static extern int ReturnValue(int value);
}
}
And this C code exported from a Windows DLL:
#include "stdafx.h"
STDAPI ReturnValue(HRESULT value)
{
return value;
}
you can build the .NET DLL like this:
"<path to csc.exe>\csc.exe" DoSomething.cs -out:Microsoft.Z3.dll -target:library -linkresource:<path to libz3.dll>\libz3.dll
Now, when you reference this new Microsoft.Z3.dll, it will behave the same way as the real Z3 thing, it will copy the libz3.dll aside automatically.
Note AFAIK, Visual Studio has no support for this linkresource stuff.
Plus one other drawback is if you want to support multiple bitnesses, you'll have to ship two .NET DLL, one for x64 and one for x86, each one embedding its native counterpart (or you'll have to duplicate all DllImport stuff etc.).

Why can't my C# application load my C++ dll?

I want to use C++ code in a C# application, so I wrote a DLL in C++.
Because it's the first time that I create a C++ DLL, I started by creating a 'test' dll. Here's the code
extern "C"
{
__declspec(dllexport) void DisplayHelloFromDLL()
{
printf("Hello from DLL !\n");
}
}
Than I made a very simple C# application:
class DllTest {
[DllImport("Test.dll")]
public static extern void DisplayHelloFromDLL();
public static void UseDll() {
DisplayHelloFromDLL();
}
}
After, I built both applications and moved the executable and the dll in the same folder. But when I ran the executable, it showed the following message:
Unhandled exception: System.DllNotFoundException: Unable to load DLL 'Test.dll': The specified module could not be found
you need to store the DLL in debug folder.
and try this command to check that method is exported properly
dumpbin /exports Test.dll
you have to check the target platform of both dll and exe.
Edit: When Target are different the exception is BadImageFormatException
You will have the DllNotFoundException when the dll or one of its dependencies is not found.
For example, when you compile a debug version of the DLL with VisualStudio, it needs the debug runtimes (which are not installed on machine without the IDE).
you can check your dll dependencies using the Dependency Walker
This tools will also helps you to see the targetted system (x86/x64) and the exported functions (use it on the dll, the program will not show you the [DllImport] dependencies)

Using C# DLL in managed C++ (command line)

I've looked over a few questions with a title just like this one, but they either do not talk about command line, or don't seem to work for me for some reason. From what I have read, it seemed as if I could "simply" do the following:
The dummy code (C#):
using System;
public static class Foo {
public static void Bar() {
Console.WriteLine("o3o");
}
}
More dummy code (Visual C++):
#using <test.dll>
int main() {
Foo::Bar();
return 0;
}
C# DLL compiled using:
csc /out:test.dll /t:library src\cs\Foo.cs
Visual C++ object file compiled using:
cl /Ox /clr /AI. /c src\vc\test.cpp
Executable compiled using:
link /out:test.exe test.obj
The following exception is thrown upon running the executable:
Unhandled Exception: System.TypeLoadException: Could not load type 'Foo' from assembly 'test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.
at main()
at mainCRTStartup()
I have a strong feeling that I was supposed to also reference the DLL in the link phase, but I couldn't find any option for linking a DLL similar to GCC's -l option. Attempting to pass the DLL along with the .obj to link causes it to tell me that linking assemblies is not supported. Interestingly, though, if I build a .netmodule instead of a DLL, i.e. by:
csc /out:test.dll /t:module src\cs\Foo.cs
and changing the #using directive to
#using <test.netmodule>
the executable runs without error. This feels a bit weird, for I don't think anybody packages code in .netmodules (what are .netmodules, anyway?).
All of your steps should have worked, but one very simple issue is preventing your program from running.
Namely: Your C# DLL assembly name is test, and your C++/CLI exe assembly has the same name. They both have the same identity.
So when looking for Foo::Bar in the test assembly, the loader first checks if the assembly is loaded in the AppDomain. It is - it's your C++/CLI exe, and you can't have several assemblies with the same identity loaded simultaneously within the same AppDomain. Your C# dll wasn't even given a try.
Just change either one of them and everything will work fine:
link /out:test2.exe test.obj
As for what's a .netmodule, it's the format used for linking managed code statically, that's why you managed to link your C# code with your C++/CLI code without issues. It's roughly the equivalent of a .lib file for managed code.
And you're right, it's not used very often.

Call unmanaged C++ VS 6.0 MFC dll from C#

I have an unmanaged C++ MFC dll that was developed in VS 6.0. I would like to use it in my C# app. I'm trying to use PInvoke.
Here is the C++ code:
// testDll.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
extern "C" {
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
}
__declspec(dllexport) int test(int a)
{
return a * a;
}
}
And here is how I'm trying to invoke the method "test" from C#:
// PInvokeTest.cs
using System;
using System.Runtime.InteropServices;
class PlatformInvokeTest
{
[DllImport("TestDll.dll")]
internal static extern int test(int number);
public static void Main()
{
Console.WriteLine(test(5));
}
}
This approach works just fine when I set C++ dll to be just a regular Win32 dll.
But once I change the project type to MFC ("Use MFC in a Shared DLL") I'm getting this error:
Unhandled Exception: System.DllNotFoundException: Unable to load DLL 'TestDll.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)
at PlatformInvokeTest.test(Int32 number)
Thanks!
TestDll.dll probably can't load one of it's dependent DLL's.
Try loading your TestDll.dll file in the Depends (Dependency Walker) utility. Depends should be installed with VC 6, under Microsoft Visual Studio 6.0 Tools. That will show you what dependencies the DLL has and will flag if one of the dependencies failed.
Make sure you load the TestDll.dll from the same folder that the C# code does.
Note that Depends only works with unmanaged DLL's.
The DLL needs to be in a path where the system can pick it up. have you put it in the directory where your application starts ? (probably in a DEBUG folder of you VS solution).
The second option is to give it the absolute path of the DLL.
The third option is to place it in "c:\windows\System" but this is a '-1' approach :D
In general, when you hit errors like this you can use Assembly Binding Log Viewer to determine if the dll is failing to load because of a missing dependency.
In your particular case, the most probabl cause is that you are dynamically linking your dll to MFC and when the C# app attempts to load your dll, it is failing to load the MFC dlls.
You can either copy the required MFC dlls side-by-side or you can switch to statically linking MFC to your lib.

Categories