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?
Related
This question already has an answer here:
Returning a string from a C# DLL with Unmanaged Exports to Inno Setup script
(1 answer)
Closed 3 years ago.
I'm trying to load a DLL written in C# into Inno Setup.
Here is the code:
function Check(version, dir: String): Integer;
external 'Check#{src}\check.dll stdcall';
Then I call it like Check(x,y)
But the DLL couldn't be loaded.
I tried it with stdcall and cdecl.
The check.dll file is along to setup.exe.
Why isn't it working?
Use the Unmanaged Exports to export function from a C# assembly, so that it can be called in Inno Setup.
Implement a static method in C#
Add the Unmanaged Exports NuGet package to your project
Set Platform target of your project to x86
Add the DllExport attribute to your method
If needed, define marshaling for the function arguments (particularly marshaling of string arguments has to be defined).
Build
using RGiesecke.DllExport;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
namespace MyNetDll
{
public class MyFunctions
{
[DllExport(CallingConvention = CallingConvention.StdCall)]
public static bool RegexMatch(
[MarshalAs(UnmanagedType.LPWStr)]string pattern,
[MarshalAs(UnmanagedType.LPWStr)]string input)
{
return Regex.Match(input, pattern).Success;
}
}
}
On Inno Setup side (Unicode version):
[Files]
Source: "MyNetDll.dll"; Flags: dontcopy
[Code]
function RegexMatch(Pattern: string; Input: string): Boolean;
external 'RegexMatch#files:MyNetDll.dll stdcall';
And now you can use your function:
if RegexMatch('[0-9]+', '123456789') then
begin
Log('Matched');
end
else
begin
Log('Not matched');
end;
See also:
Returning a string from a C# DLL with Unmanaged Exports to Inno Setup script
Inno Setup Calling DLL with string as parameter
Inno Setup - External .NET DLL with dependencies
Take a look at Unmanaged Exports from Robert Giesecke.
I don't think this is possible. Managed DLLs do not export functions directly. Calling DLLs from InnoSetup requires the function to be directly exported.
The problem is the same when trying to use managed DLLs from C++ for example. This can not be done except when using COM, as described here.
You should use a native Win32 DLL.
with absolutely no knowledge of coding in C#, I wish to call a C# function within my python code. I know there's quite a lot of Q&As around the same problem, but for some strange reason, i'm unable to import a simple c# class library from a sample python module.
Here's below as to what i've done -
C# Class Library setup
I'm using the VS 2017 CE.
I create a new project TestClassLibrary under the type of ClassLibrary(.NET Standard)
The classes inside the project are as follows -
MyClass.cs
using System;
namespace TestClassLibrary
{
public class MyClass
{
public string function()
{
return "Hello World!";
}
}
}
This was built successfully, generating the .dll file under the \bin\Debug\netstandard2.0 dir as TestClassLibrary.dll
Now, I switch over to python3.6 (running on a virtualenv, backed with pythonnet 2.3.0)
main.py
import sys
sys.path.append(r"<Ablsloute Path to \bin>\Debug\netstandard2.0")
import clr
clr.AddReference(r"TestClassLibrary")
from TestClassLibrary import MyClass
When i Run python main.py, the code fails with the error -
Traceback (most recent call last):
File "main.py", line 6, in <module>
from TestClassLibrary import MyClass
ModuleNotFoundError: No module named 'TestClassLibrary'
Should the code be -
import sys
sys.path.append(r"C:\Users\DELL\source\repos\TestClassLibrary\TestClassLibrary\bin\Debug\netstandard2.0")
import clr
clr.AddReference("TestClassLibrary.dll")
from TestClassLibrary import MyClass
I get -
clr.AddReference("TestClassLibrary.dll")
System.IO.FileNotFoundException: Unable to find assembly 'TestClassLibrary.dll'.
at Python.Runtime.CLRModule.AddReference(String name)
But when i ran the code below, the code runs as expected -
import clr
clr.AddReference(r"System.Windows.Forms")
from System.Windows.Forms import MessageBox
MessageBox.Show("Hello World!")
I've no idea of what i might be missing :(
This is really janky but how I like to do things that are personal projects.
Python lets you send stuff to the command line really easily. C# can be run from command line. You probably see where I'm going with this.
Try adding C sharp to PATH. import os to python. then use this line of code when you want to run the C# script:
os.system("csc nameofscript.cs")
perhaps I've misunderstood, but this is how I would make it work on my machine
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 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.
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