Alright, I've been digging at this for awhile and am looking for input.
I need a Java application that can load and unload native libraries, simple enough, C/C++/Java/Scripts/Executables/etc. is no real problem using JNI and other built in features.
However, I need the ability to also load .NET libraries, this has been crazy frustrating. My first attept was to use JNI and call a C++ wrapper as is below:
Java:
this.Lib = (LibHandler)Native.loadLibrary("MyLib", LibHandler.class);
The CPP:
#include <jni.h>
#using <MyLibCSharp.dll>
#include <vcclr.h>
#include <msclr\marshal.h>
using namespace msclr::interop;
using namespace System::Runtime::InteropServices;
using namespace System;
extern "C"
{
JNIEXPORT jstring JNICALL Java_Test(JNIEnv * env)
{
marshal_context ^ context = gcnew marshal_context();
const char* str4 = context->marshal_as<const char*>(CSharp::Class1::Test());
jstring js = env->NewStringUTF(str4);
return js;
}
JNIEXPORT jstring JNICALL Java_Test2(JNIEnv * env, jobject jobj)
{
marshal_context ^ context = gcnew marshal_context();
const char* str4 = context->marshal_as<const char*>(CSharp::Class1::Test());
jstring js = env->NewStringUTF(str4);
return js;
}
}
This would continously fail to even be loaded by the system, I can swap the files so that MyLib.dll is actually the C# one, and it successfully loads it (but fails to find any functions being as it's not a native C library and I don't think .NET can export like C++ can), so I'm not having file location issues.
Exception in thread "main" java.lang.UnsatisfiedLinkError: Unable to load library 'MyLib.dll': The specified module could not be found.
at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:163)
at com.sun.jna.NativeLibrary.getInstance(NativeLibrary.java:236)
at com.sun.jna.Library$Handler.<init>(Library.java:140)
at com.sun.jna.Native.loadLibrary(Native.java:379)
at com.sun.jna.Native.loadLibrary(Native.java:364)
at EntryPoint.main(EntryPoint.java:31)
I figured I'd try to compile the C# library as a COM object and call it that way, alas:
ActiveXComponent comp = new ActiveXComponent("MyLib.Class1");
Fails with:
Exception in thread "main" com.jacob.com.ComFailException: Can't co-create object
at com.jacob.com.Dispatch.createInstanceNative(Native Method)
at com.jacob.com.Dispatch.<init>(Dispatch.java:99)
at com.jacob.activeX.ActiveXComponent.<init>(ActiveXComponent.java:58)
at EntryPoint.main(EntryPoint.java:33)
C# code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace MyLib
{
[Guid("4F3A0A13-4D2B-4DE6-93EA-D6861C230290"),
ComVisible(true)]
public interface ITest
{
[DispId(1)]
string Test();
}
[Guid("A78C5820-3E4B-49B3-8C8E-63DD12346410"),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch),
ComVisible(true)]
public interface ITestEvents
{
}
[Guid("3ECD46AE-E8F4-4B62-B9DC-DD7F6CB435E2"),
ClassInterface(ClassInterfaceType.None),
ComSourceInterfaces(typeof(ITestEvents)),
ComVisible(true)]
public class Class1 : ITest
{
public string Test()
{
return "This is my C# DLL COM returning a string! heh!";
}
}
}
I can see the COM is registered, I can browse it with oleview.exe, but I can't call it from vbScript... I'm confused on that one, so I'm completely out of ideas, this has really been racking my brain all day.
I'd like to get away from COM, but I need to keep the implmentation fairly simple (the libraries wont be developed by us, so I don't want to drop a bunch of C/C++ code into the lap of VB6 developers).
I'd be fine with going back to the CLI C++ implementation method, being as it's so straightforward almost anyone can do it.
Any ideas would be extremely appreciated, thanks.
Edit:
I can't use System.LoadLibrary, wont let me unload libraries like Native.LoadLibrary with an assigned class does.
If you have single method to expose your approach is reasonable. Definetely going through JNI to C++/CLI and then .NET is much more reliable solution and easier to maintain than trying to handle such communication using COM objects.
Anyway for those who have more complex requirements like calling any method, passing ref/out arguments, calling generic methods, getting setting fields, subscribing .NET events handling exceptions, getting indexed properties etc..etc.. I think custom native wrapping will not work, at least not in rational time and cost.
If you have such requirements or just to be aware of the possbilities please have a look at third-party Java to .NET Bridges like:
Javonet
JNBridge
These two are more appropriate for this case as mentioned IKVM. Those Bridges let you use ANY .NET library directly in your JAVA code. They handle all the mentioned operations/scenarios and much more, including built-in data type translations and other mechanisms for known traps.
JNBridge is a lit bit more heavy and more expensive. However it has some dedicated plugins for enterprise systems like BizTalk. On the other hand Javonet is very light one jar-file solution half priced with very easy API. The other major difference is that Javonet works without proxy classes, so you do not have to generate any wrappers you just call .NET with reflection style whereas by JNBridge you can generate proxy classes that gives you strongly typed interface but it takes more time and effort. In my opinion it reduces flexibility a little bit as I like to have control over this what happens under the hood and with Javonet you can easily make your own strongly typed wrapped if you like.
I think this is not popular still but for single machine solution it is great approach that seamlessly covers the gap between .NET and JAVA with native performance. It is fraction of the percent of execution time taken by webservices and do not require any high level client-server infrastructures. In my tests it takes around 30% more time than executing particular code directly in .NET (it is very attractive).
It is good to hear you solve your case and I hope this post will help others with Java to .NET interop issues.
Below you can find sample code of Javonet using .NET Random class (it's important to notice that with third-party bridge you get access not only to your custom DLL but full .NET framework):
public void GenerateRandomNumber() throws JavonetException
{
NObject objRandom = Javonet.New("System.Random");
int value = objRandom.invoke("Next",10,20);
System.out.println(value);
}
Ended up getting JNI working correctly with C++ code, I was compiling the C++ as 32-bit, but I'm running a 64-bit JVM which was causing this extremely vague error.
I also ran into errors from .NET (Library wasn't in the GAC), so be sure to catch/report those correctly to Java, seems that uncaught exceptions cannot be wrapped in Java I believe.
I'll probably be posting this online as a resource soon, being as many JNI <-> .NET interop tutorials are way overcomplicated (usually adding what seems to be extremely unnecessary layers).
I do not know if this helps, but the open source project IKVM allows you to do the opposite, converting your Java application to .Net:
IKVM.NET is an implementation of Java
for Mono and the Microsoft .NET
Framework. It includes the following
components:
* A Java Virtual Machine implemented in .NET
* A .NET implementation of the Java class libraries
* Tools that enable Java and .NET interoperability
Your COM interop code looks almost right. However, you can't instantiate the coclass late-bound until you define the default interface on the class like this:
[Guid("3ECD46AE-E8F4-4B62-B9DC-DD7F6CB435E2"),
ClassInterface(ClassInterfaceType.None),
ComDefaultInterface(typeof(ITest)),
ComSourceInterfaces(typeof(ITestEvents)),
ComVisible(true)]
public class Class1 : ITest
Related
I have C# portable class library for Windows 8.1 and Windows Phone 8.1.
I want to write a native (unmanaged) C++ Windows application which uses this library.
As far as I seen, the best practise is to expose my library as COM interface.
This seems like a simple solution but when I create Portable Class Library project, checkboxes "Make assembly COM visible" and "Register for COM interop" are disabled. Is it impossible for Portable Class Library?
What I have tried:
I manually added entry <RegisterForComInterop>true</RegisterForComInterop> to my project and visual studio built me .tlb file without any errors.
I added it to my C++ project:
#include "stdafx.h"
#import "COM\MyLib.tlb"
#include<iostream>
using namespace MyLib;
using namespace std;
int main()
{
CoInitialize(NULL); //Initialize all COM Components
IPayMeLogicPtr core = IPayMeLogicPtr(_uuidof(ComPayMeLogic));
LoginStatus res = core->Login("myLogin", "myPassword", false, PayMeSDK::Language::Language_ru, true, "");
cout << res;
return 0;
}
Generated .tlh file seems pretty fine - here it is in a gist.
But when I try to run this code, it fails with an exceptions:
exception at memory location 0x74A5DAE8 (KernelBase.dll) in PayMeDemo.ComConsoleDemo.exe: 0xE0434352 (0x80131534, 0x00000000, 0x00000000, 0x00000000, 0x73A10000).
exception at memory location 0x74A5DAE8 in PayMeDemo.ComConsoleDemo.exe: Microsoft C++ exception: _com_error at location 0x00BBFADC.
Seems like it is happening on the fourth line of code in .tli (_hr fails):
inline enum LoginStatus IPayMeLogic::Login ( _bstr_t Login, _bstr_t password, VARIANT_BOOL testEnviroment, enum Language locale, VARIANT_BOOL savePassword, _bstr_t applicationToken ) {
enum LoginStatus _result;
HRESULT _hr = raw_Login(Login, password, testEnviroment, locale, savePassword, applicationToken, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}
_hr is equal to 0x80131534 error (TypeInitializationException)
However, I can't imagine what types can be wrong. Login function looks like this:
LoginStatus Login(string login, string password, bool testEnviroment, Language locale, bool savePassword, string applicationToken = null);
I already tried to
Add assembly to GAC
Manually register assembly with Regasm.exe
Everything seems fine but exception is still the same. Is it really impossible? Should I make a non-portable library? It would be a waste of time because my library uses classes from portable...
PCL libraries were designed to be just that - portable, so they implemented the the largest set of features that satisfy all target platforms. Unfortunately, this excludes COM (i.e. there is no COM on Mac OS, so having COM dependencies would take the Portable out of PCL).
RegisterForcomInterop only solves half the problem, you still need to deal with ComVisible, possibly the cause of your TypeInitializationException. More info here.
It is a bit of overhead but to save some pain, wrap your PCL in a standard class library implementing the same interface and just calling the PCL methods as a pass through is probably the best bet. Then use the standard ComVisible etc.
Here is some Pseudo code to explain, in the PCL assembly:
IMyPclInterface
{
void DoSomeWork();
}
public class MyPclImplementation : IMyPclInterface
{
public void DoSomeWork()
{
....
....
....
}
}
In a standard class library, reference your PCL Library and:
public class MyComImplementation : IMyPclInterface
{
MyPclInstance myPclInstance;
public MyComImplementation()
{
myPclInstance = new MyPclInstance();
}
public void DoSomeWork()
{
myPclInstance.DoSomeWork();
}
}
As Murray Foxcroft pointed, it is possible to make a copy of PCL library, compiled as standard class library. Furthermore, it is possible to add PCL dependencies for standard class library and it will work.
However, you don't have to do this. Despite Visual Studio not giving you checkbox for COM, you still can add atribute manually as pointed in the question or run Regasm.exe smth.dll /tlb manually and you will get a valid COM library. It's really difficult to debug but Hans Passant left some good tips:
The wrappers created by the #import directive turn COM error codes
into C++ exceptions. If you want to diagnose the error instead of just
having the program crash then you have to write try/catch (_com_error&
ex) {} to report it. Change the Debugger Type from Auto to Mixed so
you'll have a much easier time trouble-shooting the C# exception,
TypeInitializationException requires that kind of help. And write a C#
unit test so you get the basic problems out before you try to call it
from C++
Anyone can share a working example on how to call a simple C# library (actually its WPF) from python code? (I have tried using IronPython and had too much trouble with unsupported CPython library my python code is using so I thought of trying the other way around and calling my C# code from Python).
Here is the example I was playing with:
using System.Runtime.InteropServices;
using System.EnterpriseServices;
namespace DataViewerLibrary
{
public interface ISimpleProvider
{
[DispIdAttribute(0)]
void Start();
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class PlotData : ServicedComponent, ISimpleProvider
{
public void Start()
{
Plot plotter = new Plot();
plotter.ShowDialog();
}
}
}
Plotter is a WPF windows that plots an Ellipse
I don't know how to call this code from my python all. Any suggestions?
It is actually pretty easy. Just use NuGet to add the "UnmanagedExports" package to your .Net project. See https://sites.google.com/site/robertgiesecke/Home/uploads/unmanagedexports for details.
You can then export directly, without having to do a COM layer. Here is the sample C# code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using RGiesecke.DllExport;
class Test
{
[DllExport("add", CallingConvention = CallingConvention.Cdecl)]
public static int TestExport(int left, int right)
{
return left + right;
}
}
You can then load the dll and call the exposed methods in Python (works for 2.7)
import ctypes
a = ctypes.cdll.LoadLibrary(source)
a.add(3, 5)
Since your post is tagged IronPython, if you want to use the sample C# the following should work.
import clr
clr.AddReference('assembly name here')
from DataViewerLibrary import PlotData
p = PlotData()
p.Start()
Python for .Net (pythonnet) may be a reasonable alternative to IronPython in your situation.
https://github.com/pythonnet/pythonnet/blob/master/README.rst
From the site:
Note that this package does not implement Python as a first-class CLR
language - it does not produce managed code (IL) from Python code.
Rather, it is an integration of the CPython engine with the .NET
runtime. This approach allows you to use use CLR services and continue
to use existing Python code and C-based extensions while maintaining
native execution speeds for Python code.
Also
Python for .NET uses the PYTHONPATH (sys.path) to look for assemblies
to load, in addition to the usual application base and the GAC. To
ensure that you can implicitly import an assembly, put the directory
containing the assembly in sys.path.
This package still requires that you have a local CPython runtime on your machine.
See the full Readme for more info https://github.com/pythonnet/pythonnet
This project has been developed for that exact purpose - use C# classes in regular Python
https://bitbucket.org/pydotnet/pydotnet/wiki/Home
All you need to do is to install either MSI or EGG into your CPython. PyDotnet is Python module, so the executable stays regular python.exe from your installation of Python or Anaconda. Supported both 32bit and 64bit.
Unlimited access to all C# classes, methods with output and ref parameters, generic classes and generic methods, extension methods, private members.
Overloaded assembly loader with customized mechanics for searching assemblies.
.NET runtime type information convertible to class object, which can be instantiated as any other class.
Special import mode designed especially for Python interactive shell, which allows you to discover available assemblies, namespaces, classes, methods, etc.
I'm waiting for feedback:)
I am attempting to write a DLL using the C# .NET Framework 2.0. Everything compiles okay, but when I try to access the DLL from my application, it fails when attempting to get the procedure address. So, I oped the DLL in Dependency Walker, and all of my public functions are missing!
My DLL, so far, is fairly straightforward:
namespace MyDll_Namespace
{
public class MyDllClass
{
public static int Func1( /* params */ ) { /* ... */ }
public static int Func2( /* params */ ) { /* ... */ }
public static int Func3( /* params */ ) { /* ... */ }
public static int Func4( /* params */ ) { /* ... */ }
}
}
There's not much else, just a few constants and delegates defined inside the class, as well as outside the class in the namespace. Any thoughts or suggestions would be much appreciated. Thanks.
Dependency walker is for win32 DLLs (which is native code), not .NET assemblies (which is managed code). It won't find methods in an arbitrary class (even if they are static). If you need to call managed code from native code, there are ways of doing that, but it's not pretty.
If you want to use your dll from managed code, it's a lot easier. Check out System.Assembly and Activator.
An example of this:
var assembly = Assembly.LoadFile(#"\path\to\your.dll");
var mydllclass_type = assembly.GetType("MyDllClass");
var instance = Activator.CreateInstance(mydllclass_type);
The instance will be an object. To call the methods, you need to use reflection, because the interface is not known at compile-time.
If you are creating a plugin system, the best way is to have a common interface or abstract base for all plugins, and have that referenced by your program. Those third parties who implement a plugin, will also reference this contract. In this case, the last line changes a bit:
var instance = (IMyDllClass)Activator.CreateInstance(mydllclass_type);
Now you can use the methods like in a regularly constructed object.
Part of the problem here is that dependency walker is a tool for native applications. It doesn't understand managed code and hence won't display any of the managed types + methods that you've defined.
I'm confused by this line in your question
when I try to access the DLL from my application, it fails when attempting to get the procedure address
This sounds a bit like an error I would see in a native application, not a managed one. Are you trying to access the C# code from a native application? If so this can only be done via COM magic and not via direct calling. Can you explain in more detail what is going on here?
Try .net Reflector to see exactly what's inside your built DLL (in order to make sure everything is the way it is supposed to).
Also make sure you're in release mode while building your DLL before referencing it... I don't know if it's going to change anything, but it worths the try =)
You need to add a reference to your dll and the runtime will automatically allow you to call your function. Here is a little tutorial on writing a .net class library.
I decided to write my DLLs in C++. However, here is a bunch of useful information I found for using managed code from unmanaged code:
Is it possible to use a DLL created using C# in an unmanaged VC++ application?
How do I call C++/CLI (.NET) DLLs from standard, unmanaged non-.NET applications?
Using managed code in an unmanaged application
Using Managed Components from Unmanaged Code
An Overview of Managed/Unmanaged Code Interoperability
Unmanaged Exports
Calling Managed .NET C# COM Objects from Unmanaged C++ Code
All-In-One Code Framework
CLR Hosting APIs
How To: Migrate to /clr
How to call a managed DLL from native Visual C++ code in Visual Studio.NET or in Visual Studio 2005
i need to bind C++ dll to my C# WinCE program. (scanner dll)
how i can do it ?
thank's in advance
You need to use Interop to call into unmanaged code.
using System.Runtime.InteropServices; // DllImport
public class Win32 {
[DllImport("User32.Dll")]
public static extern void SetWindowText(int h, String s);
}
Here is an article that discusses the topic in detail (also where the code is sourced from).
http://msdn.microsoft.com/en-us/magazine/cc301501.aspx
An alternative to InterOp is to write a C++ DLL using CLR extensions which acts as a wrapper to the traditional C++ DLL. This gives you a chance to handle unusual types, e.g. custom structures or classes, if Marshaling isn't going to work. (According to MSDN you can extend the Marshaling support (http://msdn.microsoft.com/en-us/library/bb531313.aspx) but I haven't tried this personally, and depending on what you're doing it might be a lot of work).
For example if you want to access a DLL which exports a class, you can have a wrapper DLL which owns an instance of the C++ class and defines a .NET class which maps onto the C++ class. For example, here's a snippet from a C++/CLR DLL which we use to make one of our old C++ DLLs available in .NET:
// This is the constructor for the CLR (managed) object
FileInf::FileInf()
{
// Create the C++ (unmanaged) object
m_pFileInf = gcnew DILib::FileInf();
}
// This is a managed interface which replicates the old
// unmanaged functionality
bool FileInf::IsDirectory()
{
return m_pFileInf->IsDirectory();
}
I'd say if InterOp works then stick with it, but I'm not sure if it's the best way to solve every C++ / .NET interfacing problem, and this is an alternative.
Suppose I am writing an application in C++ and C#. I want to write the low level parts in C++ and write the high level logic in C#. How can I load a .NET assembly from my C++ program and start calling methods and accessing the properties of my C# classes?
You should really look into C++/CLI. It makes tasks like this nearly trivial.
Otherwise, you'll have to generate COM wrappers around the C# code and have your C++ app call the COM wrappers.
[Guid("123565C4-C5FA-4512-A560-1D47F9FDFA20")]
public interface IConfig
{
[DispId(1)]
string Destination{ get; }
[DispId(2)]
void Unserialize();
[DispId(3)]
void Serialize();
}
[ComVisible(true)]
[Guid("12AC8095-BD27-4de8-A30B-991940666927")]
[ClassInterface(ClassInterfaceType.None)]
public sealed class Config : IConfig
{
public Config()
{
}
public string Destination
{
get { return ""; }
}
public void Serialize()
{
}
public void Unserialize()
{
}
}
After that, you need to regasm your assembly. Regasm will add the necessary registry entries to allow your .NET component to be see as a COM Component. After, you can call your .NET Component in C++ in the same way as any other COM component.
I would definitely investigate C++/CLI for this and avoid COM and all the registration hassles that tends to produce.
What is the motivation for using C++? If it is simply style then you might find you can write everything in C++/CLI. If it is performance then calling back and forth between managed C++ and unmanaged code is relatively straight forward. But it is never going to be transparent. You can't pass a managed pointer to unmanaged code first without pinning it so that the garbage collector won't move it, and of course unmanaged code won't know about your managed types. But managed (C++) code can know about your unmanaged types.
One other thing to note is that C++/CLI assemblies that include unmanaged code will be architecture specific. You will need separates builds for x86 and x64 (and IA64).
If you can have both managed and unmanaged code in your process, you can create a C++ class with virtual functions. Implement the class with mixed mode C++/CLI. Inject the implementation to your C++ code, so that the (high-level) implementation can be called from your (low-level) C++ code.
You can wrap the .NET component in a COM component - which is quite easy with the .NET tools - and call it via COM.
If the low level parts in in C++ then typically you call that from the C# code passing in the values that are needed. This should work in the standard way that you're probably accustomed to. You'll need to read up on marshalling for example.
You could look at this blog to get some concrete details.
Create your .NET assembly as normal, but be sure to mark the class with the ClassInterface(ClassInterfaceType.AutoDual) and be sure an assembly info SetAssemblyAtribute to ComVisible( true ).
Then, create the COM wrapper with REGASM:
regasm mydll.dll /tlb:mydll.tbl /codebase f:_code\ClassLibraryForCom
be sure to use the /codebase directive -- it is necessary if you aren't going to give the assembly a strong name.
rp
Since C# can import C++ standard exports, it might be easier to load up your C++ dll inside of a C# application instead of using COM from C++.
See documentation for System.Runtime.InteropServices.DllImport.
Also, here is a complete list of the types of Interop that you can do between managed and unmanaged code:
http://blogs.msdn.com/deeptanshuv/archive/2005/06/26/432870.aspx
In a nutshell:
(a) Using COM-Interop
(b) Using imports/pinvoke (explicit method calls)
(c) IJW and MC++ apps : MC++ & IJW apps can freely call back and forth to each other.
(d) Hosting. This is rare, but the CLR can be hosted by an unmanaged app which means that the runtime invokes a bunch of hosting callbacks.
I found this link to embedding Mono:
http://www.mono-project.com/Embedding_Mono
It provides what seems to be a pretty straightforward interface for interacting with assemblies. This could be an attractive option, especially if you want to be cross-platform