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++
Related
I am using COM interop to call a method in a C# dll from a C++ application.
The C# code is:
namespace MyLibrary
{
[ComVisible(true)]
[Guid("f08942b1-db20-44aa-9713-7d28fff51e2b")]
public interface IMyLibraryInterface
{
string POSRequest(string request);
}
[ComVisible(true)]
[Guid("4d962dd5-05ed-431b-82e2-378aebe8d0dc")]
public class MyLibraryInterface : IMyLibraryInterface
{
public string myRequest(string request)
{
....
return response;
}
}
}
The calling C++ code is:
CoInitialize(NULL);
MyLibrary::IMyLibraryInterfacePtr MyLibraryInterface(__uuidof(MyLibrary::MyLibraryInterface));
myResult = (LPCTSTR) MyLibraryInterface->myRequest(myInput);
CoUninitialize();
where the relevant tlb file has been imported:
#import "MyLibrary.tlb"
This works both when debugging and running a release version from my development machine, but causes the application to crash when I run this from another machine. Specifically, the line creating the pointer appears to be the issue:
MyLibrary::IMyLibraryInterfacePtr MyLibraryInterface(__uuidof(MyLibrary::MyLibraryInterface));
It seems like something is perhaps missing on the other machine but I can't figure out what?
When using a dll that exposes a COM interface, that dll needs to be registered. The tool for registering a C# COM dll is regasm.exe. As part of your install process you need to call regasm on any dll that exposes a COM interface. As part of debugging and helping yourself, you can modify your code slightly to be able to check the HRESULT when you try to create the object, and log if needed.
Note: I don't have the setup to test this code, so their may be a typo, but it should point you in the right direction. If you don't have the "smart pointers" that VS creates, you can use the CoCreateInstance call to create your object and then check the HRESULT from that call.
IMyLibraryInterfacePtr myIntPtr = null;
HRESULT hRes = myIntPtr.CreateInstance(__uuidof(MyLibrary::MyLibr‌aryInterface));
if (!(SUCCEEDED(hRes))
{
// This means an error occurred, you can log it for debugging, etc.
}
Edit
Based on the comment from MickyD, and for sake of completion, there is a way to use COM without registering the dlls. It involves creating manifest files that live alongside the application.
I've been tasked with writing a new interface to a legacy C++ DLL I don't have the source code for, which - for reasons beyond me - accesses a global class in the legacy application directly.
From the application, it's something like:
extern Interface *App;
...
Interface App*; // A pointer to our interface class.
Then, from the legacy DLL:
if( App->GetStatus() ) return false;
The Interface class that App refers to is quite trivial to rewrite in C#, but how can I make it the equivalent of extern so that the legacy C++ DLL can access it?
Thanks!
You could try using Robert Giesecke's "UnmanagedExports" nuget package to achieve this functionality like so:
class Test
{
[DllExport("add", CallingConvention = CallingConvention.Cdecl)]
public static int TestExport(int left, int right)
{
return left + right;
}
}
However:
a) I believe this only works for methods, not classes and
b) the reason there isn't a native way to export a DLL in C# is because that the calling application must have the .NET framework loaded in order to access that entry point. This also applies to the UnmanagedExports nuget package that I linked to above.
You can hack your way around this by getting your C++ app to load mono before calling the C# app, but it doesn't sound like this is possible in your case.
(Also, UnmanagedExports will only work if you explicitly set a build target in your project's properties - eg. x86)
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
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
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