This question already has an answer here:
Using C# dll in C++ code
(1 answer)
Closed 7 years ago.
I have a dll file which is created in the c# language.And I wanted to use the functions which are written in c# language in that dll file from a c++ project.
I know it's possible to use c# dll with c# project. But no idea of what is the best way of doing c# dll in c++ project. I'm using visual studio 2013. All your guidance are highly appreciate.
I'll summarize the basic steps to take to expose a C# class to C++ through COM. Let's say you have the following C# class:
public class Number
{
public Number()
{
}
public int Value
{
get;
set;
}
}
First you need to create an interface for the class to implement. Only the methods and properties exposed through that interface are visible to COM (and therefore C++). Typically this interface has the same name as the class, but with an "I" prefix:
public interface INumber
{
int Value
{
get;
set;
}
}
Next you need to add the ComVisible and Guid attributes to both the interface and the class. It's also recommended to add [ClassInterface(ClassInterfaceType.None)] to the class:
[ComVisible(true)]
[Guid("71CACDF6-B6CD-4A46-B951-02E5C542852C")]
public interface INumber
{
...
[ComVisible(true)]
[Guid("B5809A32-A066-42E3-96D7-09FE622BC994")]
[ClassInterface(ClassInterfaceType.None)]
public class Number : INumber
{
...
(I got the GUIDs by using the GUID utility that comes with Visual Studio. You can find it at C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools)
That's it for the C# side. After you build the C# DLL, you need to register it with COM by using the Regasm.exe command-line utility. Start the command prompt and type the following commands:
"C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools\vsvars32"
Regasm ExampleDLL.dll /codebase /tlb
(You may need to modify the first one if your VS installation path is different.)
Now you can use the DLL from C++ like this:
#include <iostream>
#import "ExampleDLL.tlb" // This is a file that should have been generated by Regasm.exe
using namespace std;
using namespace ExampleDLL;
int main()
{
CoInitialize(NULL);
INumberPtr pNumber;
pNumber.CreateInstace(__uuidof(Number));
pNumber->Value = 5;
cout << pNumber->Value;
return 0;
}
For more details, see Exposing .NET Framework Components to COM.
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 may be reposting but I cannot find solution of this.
I create a C# Comvisible Class. This is the following class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace COMTrial
{
[Guid("2B71BC1B-16F5-4A0D-A015-CAE658A10B07")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IMyExample
{
string GetData();
}
[ClassInterface(ClassInterfaceType.AutoDual), ComSourceInterfaces(typeof(IMyExample))]
[Guid("2B71BC1B-16F5-4A0D-A015-CAE658A01B07")]
[ComVisible(true)]
public class Class1
{
public Class1()
{
}
[ComVisible(true)]
public string GetData()
{
return "Vikas";
}
}
}
Then I checked Register for Interop option and even made the complete assembly visible and compile the project and solution.
Then I went to excel and wrote this code:
Dim a as Object
set a = CreateObject("COMTrial.Class1")
It says,
ActiveX cannot create an object.
The only reason I think of is that I am running Office 2010 64 bit with Windows 7 64 bit.
Then I checked Register for Interop option
That will only register your assembly for 32-bit processes. Since this is the 64-bit version of Office, you will need to run Regasm.exe by hand. Do so from the Visual Studio Command Prompt, started with "Run as administrator". Be sure to use the 64-bit version of Regasm.exe, for .NET 4 it is located by default in C:\Windows\Microsoft.NET\Framework64\v4.0.30319. Note the 64. Use the /tlb and /codebase options to match the IDE's behavior.
Another improvement is to use the [ProgId] attribute explicitly so you don't have to guess at the name and won't have a problem if the project name is not "COMTrial".
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
I have a TestClass.cs file that contains an interface, and a class, much like this:
namespace CPierce.CSharpBridge
{
[System.Runtime.InteropServices.Guid("3D08DF02-EFBA-4A65-AD84-B08ADEADBEEF")]
public interface ICSide
{
// interface definition omitted...
}
[System.Runtime.InteropServices.Guid("CBC04D81-398B-4B03-A3D1-C6D5DEADBEEF")]
public partial class CSide : ICSide
{
// class definition omitted...
}
}
When I compile this at the command line, and run regasm on it:
csc /debug /t:library TestClass.cs
regasm TestClass.dll /tlb:TestClass.tlb
I get a nice, big .tlb file suitable for including in a C++ project elsewhere....
10/27/2011 01:50 PM 3,616 TestClass.tlb
When I put TestClass.cs into a "Class Project" in Visual Studio, compile it, run regasm, the resulting .tlb is pathetic and nearly useless -- it has no interface, no method signatures, etc...
[Compiled TestClass.cs as part of Project "ClassProject" in Visual Studio]
regasm ClassProject.dll /tlb:ClassProject.dll
10/27/2011 01:58 PM 1,132 ClassProject.tlb
This is the same C# code in both cases, one being compiled with Visual Studio one at the command line, giving me completely different results.
What gives?
--
Update: Hans suggests that the [ComVisible(true)] attribute missing is causing the problem. Tried it, and it worked. But that still doesn't answer the question, why? Why do I get different results based on which compile method I use?
If you create a new Class Library in Visual Studio, the default AssemblyInfo.cs file includes the line:
[assembly: ComVisible(false)]
The command-line command you're using is only compiling your TestClass.cs file, so you get the default setting for ComVisible (which, judging from the available evidence, is probably true). When you compile from the IDE, you include AssemblyInfo.cs as well, so its explicit setting overrides the compiler's default.
Also check if your class has functions of accessor type public.
In our case, the project was working fine when it was being used from within the solution but when we extracted the logic to create a DLL, it stopped creating the TLB file with no indication on why...
So if you have a class like so,
public class tlbuser{
private void functionTLB(){
//function code
}
// rest of the class code
}
Ensure it is changed to:
public class tlbuser{
public void functionTLB(){
//function code
}
// rest of the class code
}
I am trying to build an object library which can be registered and used from VBA using 64 bit excel 2010. I am using Dev Studio 2008. I think this is a 64 bit issue as I am pretty sure this worked when I tried it with with my previous version of Excel (XP). I have clicked "Make COM visible" in the Assembly info Information dialog and "Register for COM interop" in the build tag. When I set the target type to x64 I can't see the library in the references dialog at all. I if I select Any CPU I can register it but I get a "Can't create Active X object" error when I try to instantiate it.
namespace Tester
{
[Guid("D6F88E95-8A27-4ae6-B6DE-0542A0FC7039")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface _Numbers
{
int GetDay();
int GetMonth();
int GetYear();
int DayOfYear();
}
[Guid("13FE32AD-4BF8-495f-AB4D-6C61BD463EA4")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("Tester.Numbers")]
public class Numbers : _Numbers
{
public Numbers(){}
public int GetDay()
{
return(DateTime.Today.Day);
}
public int GetMonth()
{
return(DateTime.Today.Month);
}
public int GetYear()
{
return(DateTime.Today.Year);
}
public int DayOfYear()
{
return(DateTime.Now.DayOfYear);
}
}
}
Since Visual Studio is a 32-bit process, it will erroneously run the 32-bit version of regasm.exe in order to register your 64-bit assembly. Of course, that version of regasm.exe will write to the 32-bit portion of the registry, so that won't work.
One way to solve the problem would be to run the 64-bit version of regasm.exe on the target assembly yourself (e.g. in a post-build step). You'll need to export its type library using the /tlb option, and you'll also need to pass the /codebase option since the assembly doesn't reside in the GAC:
"%SystemRoot%\Microsoft.NET\Framework64\v2.0.50727\regasm.exe"
/tlb /codebase "$(TargetPath)"