Call unmanaged C++ VS 6.0 MFC dll from C# - 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.

Related

Blazor project can't find native dll dependencies

I have a Blazor server x86 project that requires a 32-bit native DLL (native.dll). In a class wrapper I use DllImport as follows:
[DllImport("native.dll")]
internal static extern int Method1();
[DllImport("Native.dll, CharSet=CharSet.Unicode")]
internal static extern int Method2(string countryName, string abbreviation, int i);
In a Razor component, I load the DLL as follows (the DLL is marked "Copy to output always"):
IntPtr ptr = NativeLibrary.Load("native.dll");
The DLL loads fine and the first call to Method1 works great. But when I call Method2, I get a DLLNotFoundException (Unable to load DLL 'native.dll, CharSet=CharSet.Unicode' or one of its dependencies). Using DumpBin I determined that the native.dll has three dependencies: kernel32.dll, user32.dll and advapi32.dll. These, of course, have their own dependencies.
I have tried adding Windows\SysWOW64 to the PATH, but no help, and should not have to do that anyway.
How do I tell the app to include, or find, the native dependencies?

How to correctly link a c++/CLR wrapper to an unmanged c++ dll and use it in a c# program

I'm trying to link to a dll compiled as unmanaged c++ code from another c++ dll that wraps the useful unmanaged code and is compiled with CLR. I then want to use that wrapper in a c# app.
However all attempts so far have failed for various reasons.
I'm using Visual Studio 2017 for this project.
I start by creating a c# project. File->new->project->visual c#->console app (.NET Framework)
I then create my c++/clr project by right clicking the solution and doing: add->new project->visual c++->clr->clr empty project.
I need my c++/clr project to be a dll so I go to properties->Configuration Properties->General->Configuration Type and set the value to Dynamic Library (.dll)
Now, I need my C# project to reference this one so I right click on my c# project and go to add->reference then I select my c++/clr project
(I know that everything is correct up to this point because I can call my c++/clr functions from the c# project and get the desired output. The issue comes when I continue to try and call unmanaged code.).
Now that I have that set up, I can create my unmanaged c++ project so I follow similar steps but this time I create a C++ Empty Project and again change the configuration properties to be a DLL. I then add the unmanaged c++ project as a reference to the c++/clr project by right clicking the c++/clr project and going add->reference
Now I have my 3 projects and the references that I need, I can then start adding my code so I add two files to each c++ project:
I don't think the code itself is particularly interesting to this question but I include it anyway so that anyone can quickly reproduce the problem. In the unmanaged c++ project, I have a header containing:
// UnmanagedHeader.h
#pragma once
__declspec(dllexport) void HelloDLL();
and in the source file:
#include "UnmanagedHeader.h"
#include <iostream>
void HelloDLL() { std::cout << "Hello from unmanaged dll!" << std::endl; }
Then in the c++/clr project I have a header containing:
// Header.h
#pragma once
using namespace System;
namespace Project1
{
public ref class Class1
{
public:
// contruct this class
Class1();
// Call a function from the unmanaged project
void UnmanagedWrap();
};
}
and a source file containing:
#include "Header.h"
#include "../Project2/UnmanagedHeader.h"
#include <iostream>
namespace Project1
{
Class1::Class1() { std::cout << "Hello From Class1" << std::endl; }
void Class1::UnmanagedWrap() { HelloDLL(); }
}
and finally, in my c# project I have one file containing:
using System;
using Project1;
namespace ConsoleApp3
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
Class1 c = new Class1();
c.UnmanagedWrap();
Console.ReadLine();
}
}
}
This all compiles just fine but when I go to run the application, I get a runtime error:
System.IO.FileNotFoundException: 'Could not load file or assembly 'Project1.dll' or one of its dependencies. The specified module could not be found.'
Project1.dll is the c++/clr project but I expect the issue is related to my unmanaged c++ dll not being set up correctly. I know that Project1.dll (c++/clr) exists and so does Project2.dll (unmanaged c++).
Could anyone explain to me what I need to do for my unmanaged c++ dll to be compatible with the c++/clr and c# projects?
Update: Something I just tried that may be of help, If I try to add a reference from the c++/clr project to the unmanaged dll drectly (not selecting the project but instead brwsing for the built dll and selecting that) I get: Could not add a reference to "<path>/Project2.dll" as it is not of a type or version this project can use.

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)

An attempt was made to load a program with an incorrect format

I am using C# loading C++ dll, and got this error:
"An unhandled exception of type 'System.BadImageFormatException' occurred in MyApp.exe"
"Additional information: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8057000B)
I could not figure out why. The C++ dll was generated using vs2012 wizard, win32 application, dll with pre-head. It is built with x64 option. Here is the code:
// MyNativeDLL.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
//char* pMemoryBuffer = NULL;
using namespace std;
__declspec(dllexport) long Test()
{
long a;
a = 1;
a++;
return a;
}
The C# code calling it is:
[DllImport("C:\\MyNativeDLL\\x64\\Debug\\MyNativeDLL.dll", EntryPoint = "Test")]
private extern static int Test();
void doJob()
{
long a = Test(); // exception thrown here
}
C# code is built with Any CPU option, and it is loading the x64 native dll.
I wondering where I did wrong? I have been trying long, but really get stuck here. Thanks!
UPDATE
When I compile my native dll using win 32 option, and set up correct dll path, it loads successfully. But when I compile my native dll with x64 options, load with correct path, the loading fails.
As you mentioned:
The C++ dll was generated using vs2012 wizard, win32 application, dll with pre-head. It is built with x64 option
The DLL and exe have to be both 32 bit, or both 64 bit.

C# interface C++ DLL?

How do I call functions from a C++ DLL?
The C++ DLL contains functions like this:
__declspec(dllexport) bool Setup () { return simulation.Setup (); }
The C# program does this:
[DllImport("mydll.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool Setup();
The C# program crashes with the following message when it tries to load (?) the DLL:
An unhandled exception of type 'System.BadImageFormatException' occurred in TestFrame.exe
Additional information: There was an attempt to load a file with a wrong format (exception from HRESULT: 0x8007000B)
The C++ DLL is a standard DLL (no MFC, no ATL).
This error occurs when you try to load a 32-bit DLL into a 64-bit process. (Or vice-versa)
Until VS2010, C# projects are target any CPU by default and will run as 64-bit on a 64-bit OS.
You need to go to the Build tab in Project Properties and set the C# project to x86 only.
Is it possible that your exe and dll have different bitness (i.e. one is 64 and the other 32)?
Have you tried compiling the code for x86 platform?
See this blogpost for instructions.
It may not be appropriate for you to set the CPU architecture (platform target) for the assembly, but instead you can specify an alternate path to find the correct DLL to load.
How to use the correct unmanaged DLL file according CPU architecture? (32 / 64 bits)

Categories