I want to develop a plugin for a program (EXE) to interop with an external C# module. The plugin is one of the three dlls needed: this dll (A) calls a wrapper dll (Native/Managed, in C++/Cli) (B) to interop with a C# dll (C).
A is supposed to be loaded by a calling program (EXE) when deployed.
In testing, a message from the C# dll is displayed, which tells me dll A is correctly loaded by a C++ tester and subsequently has made successful call to other dlls.
In deployment, dll A is loaded by EXE if it only displays a message. However, when lines of code to call dll B are added, EXE no longer recognizes dll A.
I have made sure that all files are in the right place. So I think the problem lies in the extra lines of interop code to call dll B. Any idea as to where I should look for problem?
Here is the exported function in dll A:
int WINAPI Init()
{
FILE * pConsole;
AllocConsole();
freopen_s(&pConsole, "CONOUT$", "wb", stdout);
printf("Started\n");
//These two line below call the wrapper dll B
// which serves as a middle man between dlls A and C
NativeExport_ClientWrapper* client = createMyClass();
if (client) client->Test();
return 1;
}
Here is the unmanaged side of the wrapper B:
//----------------------------------------------
//NativeExport_ClientWrapper.h
//----------------------------------------------
//#pragma once
#pragma once
#pragma unmanaged
#define THISDLL_EXPORTS
#ifdef THISDLL_EXPORTS
#define THISDLL_API __declspec(dllexport)
#else
#define THISDLL_API __declspec(dllimport)
#endif
class ILBridge_ClientWrapper;
class NativeExport_ClientWrapper {
private:
ILBridge_ClientWrapper* __bridge;
public:
NativeExport_ClientWrapper();
public:
~NativeExport_ClientWrapper();
public:
THISDLL_API void Test();
};
extern "C" THISDLL_API NativeExport_ClientWrapper* createMyClass();
And here is the managed side of the wrapper:
//----------------------------------------------
//ILBridge_ClientWrapper.h
//----------------------------------------------
#pragma once
#pragma managed
#include <vcclr.h>
class ILBridge_ClientWrapper {
private:
gcroot<Client^> __Impl;
public:
ILBridge_ClientWrapper() {
__Impl = gcnew Client;
}
void Test() {
__Impl->test();
}
};
After exhaustive search, I found nothing that helps to resolve this issue, including doing library load debugging.
My other related posting is here: Unexpected Stackoverflow exception using CLR in a dll
And finally, by doing several things, this exception is gone and everything works now:
1) In my CS project, I use the unmanagedexports package (use NuGet package manager to install it: Install-Package unmanagedexports) to export static methods using the __stdcall calling convention. In this project, you need to add these:
using System.Runtime.InteropServices;
using RGiesecke.DllExport;
2) add the path to the wrapper header files to the unmanaged C/C++ project's property page (C/C++->general->additional include directories)
3) put the managed and native wrapper into one project/dll (built with /clr option), separate them from the other two modules (one for the managed C# and one for the unmanaged C/C++)
4) optionally, I added a definition file for the unmanaged C/C++ functions
5) make sure all modules are built against the same framework and platform. In my case, I use framework 4.0 and x86 platform. In some case, you need to add an app.config file with the following:
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>"
6) set the path in the environment pointing to where the dlls are deployed
That's about it.
Related
I have x64 native C++ library that I have to pass to C# project.
I built C++/CLI wrapper, based on this tutorial, and everything was ok.
But, the project compiles only on x86 architecture.
When I tried adding that native C++ library to project, I received runetime error.
Project doesn't work on x64 architecture because wrapper for some reasons requires x86. And, on the other hand, it doesn't work on x86 because that library requires x64.
I have very little experience with C++/CLI, wrappers, and C# in general, and I don't have much idea how to go around this problem.
When tring to compile Solution, I receive runetime error
System.BadImageFormatException: Could not load file or assembly 'Wrapper, Version=1.0.7178.20781, Culture=neutral, PublicKeyToken=null' or one of its dependencies. An attempt was ma
de to load a program with an incorrect format..
Link to error documentation
Here is my Wrapper
using namespace System;
namespace CLI {
template<class T>
public ref class Wrapper
{
protected:
T* m_Instance;
public:
Wrapper(T* instance)
:m_Instance(instance)
{
}
virtual ~Wrapper()
{
if (m_Instance != nullptr)
{
delete m_Instance;
}
}
!Wrapper()
{
if (m_Instance != nullptr)
{
delete m_Instance;
}
}
T* GetInstance()
{
return m_Instance;
}
};
}
...And here is a C++/CLI class that is using this wrapper
//**********************header file***********************
#include "Wrapper.h"
#include "../Core/Core.h"
using namespace System;
namespace CLI
{
public ref class Model : public Wrapper<Core::Impl>
{
public:
Model();
bool test();
};
//**********************Implementation******************************
#include "Model.h"
namespace CLI
{
Model::Model()
:Wrapper(new Core::Impl())
{
Console::WriteLine("Creating new Impl-wrapper object!!");
}
bool Model::test()
{
return m_Instance->test();
}
}
Its pretty much exacly the same as from the tutorial that I used.
I can not modify that native C++ library, so it has to work on x64 architecture.
Can you please explain to me, why wrapper doesn't want to compile on x64, but works perfectly on x86, and is there a way to go around this. Perfect answer would provide an example of C++/CLI Wrapper that is working on x64 architecture.
Thanks in advance
EDIT,
oh, and I forget to add properties of my project so.
OS is Win10 (x64); .NET target framework 4.5.1; Core project(the lowest layer project, not presented here) is built as static .lib, and Wrapper is a dynamic .dll.
VisualStudio 2017 v15.9.14
Double check your project setting, especially linker. Check Command line tab for linker. Recently I encountered wild X86 flag there in Additional options that gave me similar errors.
In advanced, check Target machine.
Try to enable verbose output for linker and compiler, and check for any occurrence of x86.
If all of that is ruled out, make sure that your lib was really compiled and is valid, eg. via dependency walker.
I've compiled a dll from a C++/CLI project in Visual Studio.
The code looks like:
#include "stdafx.h"
#include "api209.h"
using namespace System;
using namespace api209;
namespace CDK_net {
public ref class CDK_wrapper
{
public:
CDK_wrapper::CDK_wrapper(){};
public:
void init(){
//some magic
}
};
}
So this dll references a few other native C++ dlls and libraries, and does some stuff in the init() function.
If I create a C# project, reference this dll, the CDK_wrapper.init() works perfectly fine.
Now I want to reference this dll from a python script. So I have Python 2.7.15 and pythonnet to allow me to do this.
If I create a simple script:
import sys
import clr
dlldir = "C:\\dir\\of\\dll\\"
dllname = "CDK_net"
sys.path.append(dlldir)
clr.AddReference(dllname)
from CDK_net import CDK_wrapper
cdk = CDK_wrapper()
#works fine until here
cdk.init()
I get the following error when running it in Python:
Traceback (most recent call last):
File "test_script.py", line 33, in <module>
cdk.init()
System.Runtime.InteropServices.SEHException: External component has thrown an exception.
at api209.model.open(model* , SByte* , Repository* )
at CDK_net.CDK_wrapper.init() in d:\(...)cdk_net.h:line 21
So the error traces back to function in a C++ library which is referenced by my C++/CLI managed dll.
My question is; whatever is happening in the init() function in my dll, if it works when being called by a C# application, is there any reason why it shouldn't work when being called by python using pythonnet?
I am trying to do something similar to this:
I am working on Windows but my intention is to make my code work on Linux too later on (therefore I work with cygwin and clion for C++ ). VS2017 to compile the C# for a .NET Core app with a normal C# compiler. My problem is getting this error in visual studio:
"The program '[19944] dotnet.exe' has exited with code -1073741819
(0xc0000005) 'Access violation'."
Here is my cmake file (generated with clion):
cmake_minimum_required(VERSION 3.10) project(callFromCsharp)
set(CMAKE_CXX_STANDARD 14)
add_library(callFromCsharp SHARED library.cpp)
Here is my C++ code in library.cpp:
#include <cstdint>
extern "C" __declspec(dllexport) int32_t Test(){
return 10;
}
This is my cmake call generated by clion
C:\Users\Daant.CLion2018.1\system\cygwin_cmake\bin\cmake.exe --build
/cygdrive/c/Users/Daant/CLionProjects/callFromCsharp/cmake-build-release
--target callFromCsharp -- -j 6
Here is my C# code:
class Program
{
[DllImport("cygcallFromCsharp.dll", EntryPoint = "Test", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Int32 Test();
[STAThread]
static void Main()
{
var res = Test();
Console.WriteLine($"Done! {res}");
Console.ReadLine();
}
}
How to solve this? I just want to call a C++ method without errors or exceptions.
Lets begin with what not to do
when loading Cygwin dll from C# (I guess from Visual studio it will be the same).
do not use AnyCPU as platform, prefer to use x64 or x86 platform, in respectively to the Cygwin dll.
for some reason, I didn't figured out yet why, calling sprintf, sscanf ,stringstream ... and prints to console methods from the dll cause the program to halt.
Now What you can do:
Make sure cygwin bin folder added to path, or copy your DLL's dependencies to the DLL's folder (dependencies are usually: Cygwin1.dll, cyggcc_s-seh-1.dll cygstdc++-6.dll. use Dependency Walker tool to check).
Just to make sure: add EXPORT_API macro, use it on each exported method. like:
#define EXPORT_API extern "C" __cdecl __declspec(dllexport)
Your DLL sample is very simple, compile your code using Cygwin console:
g++ -c library.cpp; g++ -o cygcallFromCsharp.dll library.o
I used from C# the following (debug running dir set to dll location):
DllImport(#"cygcallFromCsharp.dll", CallingConvention=CallingConvention.Cdecl)]
static extern int Test();
Hope it will help.
I implemented a dotnet loader which is compatible with cygwin.
You can find it here: https://github.com/smx-smx/EzDotnet
In order to be able to use Cygwin from .NET (without any crashes) the entry point MUST be a Cygwin application, compiled and linked under cygwin.
I added a cygwin sample that demonstrates the use of P/Invoke as well as read(2) and write(2) to redirect the C# stdin/stdout to cygwin (otherwise it wouldn't be visible)
./samples/cli/ezdotnet.exe ./CoreCLR/cygcoreclrhost.dll ./samples/Managed/Cygwin/bin/Debug/net5.0/Cygwin.dll ManagedSample.EntryPoint Entry
I have Business Intelligence -> Integration Services Project where I have SSIS Packages -> Script Task. I need to call from Script Task Unmanaged code using DllImport. Since I don't know where code for Script Task is stored during run-time I can't call my unmanaged dll.
Example code below for Script Task:
using System; // Console
using System.Runtime.InteropServices; // DllImport
class App
{
[DllImport("lib.dll", CallingConvention = CallingConvention.Cdecl)]
extern static int next(int n);
static void Main()
{
Console.WriteLine(next(0));
Dts.TaskResult = (int)ScriptResults.Success;
}
}
You can find more about Script Task here
Question: How to call Unmanaged Code from SSRS Package -> Script Task?
SSIS won't load dll's by location, even managed dll's. You have to GAC them, http://microsoft-ssis.blogspot.com/2011/05/referencing-custom-assembly-inside.html . I would therefore expect you to have to COM register your unmanaged dll, https://technet.microsoft.com/en-us/library/bb490985.aspx .
Make sure to copy c/c++ dll into "C:\Program Files\Microsoft SQL Server\120\DTS\Binn" which will be loaded when managed code calls DllImport
NOTE: 120 is version specific make sure to copy to the correct version that you have.
I getting bug: crash happened outside the Java Virtual Machine in native code. whenever i run with class file with native library and .net module file it works fine.
but when i try to run alone class file and native library it gets crash .please clarify my mistake i have done, please review my code.
for your reference with parameter
==========================================
public class Sum
{
public int add(int a, int b)
{
return a + b;
}
}
===========================================
save as Sum.cs and compile it to module
using cmd:
csc /t:module sum.cs
Create Java File to test
===========================================
public class test{
public native int add(int a,int b);
static {
System.loadLibrary("JSample");
}
public static void main (String[] args) {
System.out.println(new test().add(10,15));
}
}
==========================================
save it as test.java compile as
javac test.java
create native header file
javah -jni test
it will create test.h
create win32 project using visual studio (I used VS2010)
Choose project name as JSample
include header and C#.net module
write header for manged C++ conversion
==============================================
#using <mscorlib.dll>
#using "Sum.netmodule"
using namespace System;
public __gc class SumC
{
public:
Sum __gc *t;
SumC()
{
t = new Sum();
}
int callCSharpSum(int a,int b)
{
return t->add(a,b);
}
};
===========================================
save it as sum.h
create sum.cpp file
============================================
#include <jni.h>
#include "test.h"
#include "sum.h"
JNIEXPORT jint JNICALL Java_test_add
(JNIEnv *, jobject, jint a, jint b)
{
SumC* t = new SumC();
return t->callCSharpSum(a ,b );
}
=============================================
optimize compiler to build /clr:oldSyntax
Include Jdk/Include directory path
build the project.
we will Get JSample DLL
run the project
with C#.net module,Native DLL file and class file at the same folder.
java test
25
but whenever i run the code with dll file and class file alone.
it shows bug report The crash happened outside the Java Virtual Machine in native code.
please clarify how to port managed code C# into C++ (Win32 Un-Managed code). library file.
To use .NET assemblies from Java, I strongly suggest you look at IKVM, which is a Java VM that bridges to .NET Runtime.
I've used this back in (I think) 2004 for production software and it worked nicely. The project is actively maintained and recieves support for .NET 4 and Java 7 these days.
You have a choice of
running the Java code in IKVM so you can use .NET libraries
run a .NET program that loads java libraries (e.g. jars)
Both ways, there is a preprocessing step to translate the jars to DLLS or viceversa.
See http://ikvm.net