Greetings,
I am sorry for bothering, I'll show the question:
I am trying to export some functions written in c++ in a DLL in order to import them in a C# Application running on Visual Studio.
I make the export as reported in the following code,
tobeexported.h:
namespace SOMENAMESPACE
{
class __declspec(dllexport) SOMECLASS
{
public:
SOMETYPE func(param A,char b[tot]);
};
}
tobeexported.cpp:
#include "stdafx.h"
#include "tobeexported.h"
...
using namespace SOMENAMESPACE;
SOMETYPE SOMECLASS:: func(param A,char b[tot])
{
...some stuff inside...
}
The dll is righly created and the code is already CLR-managed(looked with a disassembling software(reflector)) and contains the exported functions
then I "Add the Reference" in my c# application and the dll is found, but when
I open it with the object browser it is completely empty, neither class, nor object has been exported and ready to be used
can you help me please?
thanks
best regards
What about using managed C++ to compile your DLL? Then you just have to add a ref to the class like this:
namespace SOMENAMESPACE
{
public ref class SOMECLASS
{
public:
SOMETYPE func(param A,char b[tot]);
};
}
After successful compilation and referencing in the other project, the class should be visible. Exporting native C++ is not really portable, each compiler produces different results and is tedious to bind from within C#...
EDIT: added public access modifier to ref class...
Related
As the title implies, I am having difficulty calling C# code from C++. A bit of context: there is an API call in C# (that does not exist in the C++ version of the API) and I need to integrate it into a much larger C++ project.
I have been reading over this SO post, and made the most headway with the COM method.
My C# dll compiles*. After copying the resulting dll and tlb files into the appropriate C++ project directory, I open an admin cmd prompt in the same C++ project directory and run:
regasm MyFirstDll.dll /codebase /tlb
(*I compile it as a Class Library, Assembly name: MyFirstDll, Default namespace: MyMethods, Assembly Information... -> Make assembly Com-Visible is checked, Build->Register for COM interop is also checked.)
Using the Object Browser, I am able to see the class I defined, as well as a method with the appropriate args and signature.
Screenshot of it showing up in Object Browser
The issue I am experiencing is with the method call (and not the class). Even though the method is visible in the Object Browser, in my code it is not recognized as a method of the object.
class "ATL::_NoAddRefReleaseOnCComPtr" has no member "Add"
Here is my code:
MyFirstDll C# Project:
using System;
using System.Runtime.InteropServices;
//
namespace MyMethods
{
// Interface declaration.
[Guid("8a0f4457-b08f-4124-bc49-18fe11cb108e")]
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface Easy_Math
{
[DispId(1)]
long Add(long i, long j);
};
}
namespace MyMethods
{
[Guid("0cb5e240-0df8-4a13-87dc-50823a395ec1")]
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("MyMethods.AddClass")]
public class AddClass: Easy_Math
{
public AddClass() { }
[ComVisible(true)]
public long Add(long i, long j)
{
return (i + j);
}
}
}
NateMath.h:
#include <atlcomcli.h>
#import "MyFirstDll.tlb"
class NateMath
{
public:
NateMath(void);
~NateMath(void);
long Add(long a, long b);
private:
CComPtr<MyFirstDll::AddClass> adder;
};
NateMath.cpp:
#include "stdafx.h"
#include <atlcomcli.h>
#import "MyFirstDll.tlb"
#include "NateMath.h"
NateMath::NateMath(void)
{
CoInitialize(NULL);
adder.CoCreateInstance(__uuidof(MyFirstDll::AddClass));
}
NateMath::~NateMath(void)
{
CoUninitialize();
}
long NateMath::Add(long a, long b) {
return adder->Add(a,b);
}
The issue being that in "return adder->Add(a,b)" (NateMath.cpp) Add(a,b) shows up red with class "ATL::_NoAddRefReleaseOnCComPtr" has no member "Add"
This is because you are trying to use your class name in CComPtr instead of the interface. With COM, all methods are defined on an interface, not on the class that implements an interfaces.
You can CoCreateInstance(__uuidof(YourClass)) because the intent is to create an instance of YourClass (which is identified by the GUID expressed by __uuidof(YourClass)). However, YourClass in the C++ is a dummy struct that's only present so that you can read the uuid -- the definition of YourClass in the C++ generated from the #import is empty and will always be empty.
To fix this, use CComPtr<YourInterface>. This tells the C++ that you want to communicate with the referenced object via that interface. Here's a rule to remember: The type argument to CComPtr and CComQIPtr must always be a COM interface. That COM interface can either be an explicitly-defined interface, or it can be the "class interface" which was automatically produced by .NET.
Speaking of class interfaces: If you had used ClassInterfaceType.AutoDual instead of None, you could have used a CComPtr<_YourClass> (note the leading underscore -- _YourClass is the class interface, whereas YourClass would be the class. I would recommend doing it the way you already have, however.
I have a C++ Windows application developped with RAD Studio (C++Builder) XE4. It has some plugins, which are DLLs (always written with RAD Studio) that are dynamically loaded with this technique.
Now in one of this plugins I need reflection capabilities. While it seems I cannot achieve them with C++ (reflection is needed on a third-party COM DLL that I cannot modify) I decided to rewrite this plugin in C# (which has powerful reflection capabilities), thus creating a .NET assembly.
I know I should expose the assembly via COM, but I can't (we don't want to change the way the main application loads all DLLs).
My aim is to dynamically load the .NET assembly and invoke its functions (for instance here we call SetParam function) with something like the following, like I do with the other plugins.
//load DLL
HINSTANCE handleDll = LoadLibraryW("C:/Path/to/the/assembly.dll");
//get reference to the function
void* ptr = GetProcAddress(handleDll, "_SetParam");
ptr_SetParam ptrFunc = reinterpret_cast<ptr_SetParam>(ptr);
//invoke function
int result = (*ptrFunc)(String("mykey").c_str(), String("myvalue").c_str());
where ptr_SetParam is defined as
typedef int(*ptr_SetParam)(const wchar_t*, const wchar_t*);
Is there a way?
Thanks to #HansPassant's comment I found a way.
I created following Visual Studio projects.
MyDllCore .NET assembly project, written in C# or any other .NET language. Here I have my managed class like the following, where the real logic of the assembly is implemented.
using System;
using System.Collections.Generic;
//more usings...
namespace MyNamespace
{
public class HostDllB1
{
private Dictionary<string, string> Parameters = new Dictionary<string, string>();
public HostDllB1()
{
}
public int SetParam(string name, string value)
{
Parameters[name] = value;
return 1;
}
}
}
MyDllBridge DLL project, written in C++/CLI, with /clr compiler option. It is just a "bridge" project, it has a dependancy on MyDllCore project and has just one .cpp o .h file like the following, where I map the methods from the program that loads the DLL to the methods in the .NET assembly.
using namespace std;
using namespace System;
using namespace MyNamespace;
//more namespaces...
#pragma once
#define __dll__
#include <string.h>
#include <wchar.h>
#include "vcclr.h"
//more includes...
//References to the managed objects (mainly written in C#)
ref class ManagedGlobals
{
public:
static MyManagedClass^ m = gcnew MyManagedClass;
};
int SetParam(const wchar_t* name, const wchar_t* value)
{
return ManagedGlobals::m->SetParam(gcnew String(name), gcnew String(value));
}
Finally I have a C++Builder program that loads MyDllBridge.dll and uses its methods calling them like in the following.
//load DLL
HINSTANCE handleDll = LoadLibraryW("C:/Path/to/the/MyDllBridge.dll");
//get reference to the function
void* ptr = GetProcAddress(handleDll, "SetParam");
ptr_SetParam ptrFunc = reinterpret_cast<ptr_SetParam>(ptr);
//invoke function
int result = (*ptrFunc)(String("mykey").c_str(), String("myvalue").c_str());
I am very new to the .NET platform (coming from the JVM and having some limited C/C++ experience) and trying my first managed C++ class library. This is to serve as a bridge to a third-party DLL I got and I have to interface. I tried it with BridJ and Java but had no success so far, so I am now trying to write the program which uses the third-party DLL in C#.
The third-party DLL is unmanaged C++.
My ManagedBridge.h so far looks similar to this:
#pragma once
#include "thirdparty.h"
using namespace System;
namespace ManagedBridge {
class __declspec(dllexport) BridgedThirdPartyThing {
private:
THIRDPARTYNS::ThirdPartyThing* _delegate;
public:
BridgedThirdPartyThing();
~BridgedThirdPartyThing();
void foo();
// more methods
};
}
My ManagedBridge.cpp so far looks like this:
#include "stdafx.h"
#include "ManagedBridge.h"
namespace ManagedBridge {
BridgedThirdPartyThing::BridgedThirdPartyThing() {
_delegate = new THIRDPARTYNS::ThirdPartyThing();
}
BridgedThirdPartyThing::~BridgedThirdPartyThing() {
delete _delegate;
}
void BridgedThirdPartyThing::foo() {
_delegate -> foo();
}
// similar for the other methods
}
}
Now, when I build this, I get no errors, and a ManagedBridge.dll is created.
I then created a C# Console application to test my DLL, added it as a reference, but I cannot access the class I exported with __declspec(dllexport). Only the namespace is shown in the object browser.
What am I missing?
It's
public ref class BridgedThirdPartyThing
for C++/CLI. You don't use __declspec(dllexport). Note that the class needs to be public to be visible to comsuming assemblies.
So I have a WPF solution. I added a new project and added a CPP Dll project to it.
I used this example. Pretty straight forward.
http://www.codeproject.com/Articles/9826/How-to-create-a-DLL-library-in-C-and-then-use-it-w
Here is my code
CppTestDll.cpp
#include <stdio.h>
extern "C"
{
__declspec(dllexport) void DisplayHelloFromDLL()
{
printf("Hello from DLL !\n");
}
}
When I build this I do in fact get a DLL
Now when I go into my WPF app and attempt to add a reference to this DLL I get this error.
"A reference to 'C:\DIR\testcppdll.dll' could not be added. Please
make sure that the file is accessible, and that it is a valid assembly
or COM component."
If you look in the example you cite:
Creating a simple C# application:
Start Visual Studio .NET. Go to File->New->Project.
Select Visual C#
Project. ... (you can select WPF Project)
Give the name to your application. Press OK. Into the specified
class, insert the following two lines:
[DllImport("TestLib.dll")]
public static extern void DisplayHelloFromDLL ();
In C#, keyword extern indicates that the method is implemented externally.
Your code should look something like this:
using System;
using System.Runtime.InteropServices; // DLL support
class HelloWorld
{
[DllImport("TestLib.dll")]
public static extern void DisplayHelloFromDLL ();
public void SomeFunction()
{
Console.WriteLine ("This is C# program");
DisplayHelloFromDLL ();
}
}
You don't add a reference to the to the DLL - you P/Invoke the Function using DLLImport
I am new to .net .
I have a managed C++ library. It looks like this.
// header file
namespace cppnetdll
{
public __gc class Class1
{
public:
static int foo_int(void);
};
}
// source file
namespace cppnetdll
{
int Class1::foo_int(void)
{
return 123;
}
}
I can call this from a managed c++ program. When I try to call it from
a C# program, I get the compiler error: "The type or namespace name
'Class1' could not be found (are you missing a using directive or an
assembly reference?)" The error refers to the DllImport line below.
Here is the C# code
[code:1:a72c1df571]
namespace csuser
{
public class xxx
{
[DllImport("cppnetdll.dll")] extern
int Class1.foo_int();
private void yyy() { int i =
foo_int(); }
}
}[/code:1:a72c1df571]
I have tried various approaches but no success. What is the magic
syntax ?
It's funny that I can call unmanaged C++ functions from C# fairly
easily by declaring the functions as "C" and exporting from the DLL.
I expected calling managed code to be easier. Maybe it's so easy
that no one thought of documenting it !
You do not use a [DllImport] directive to call code that's written in managed C++. That is only intended for native DLLs that export their functions. Neither of which applies to yours, it isn't native and you don't export the function.
You built a managed assembly, you can treat it just like one you'd have written in C#. Project + Add Reference, Browse tab, navigate to the DLL. Or better yet, put both projects in one solution, use the Projects tab to select the reference.
Instead of using the [DllImport ...]
Try just adding a reference, here is a how to from MSDN:
http://msdn.microsoft.com/en-us/library/7314433t%28v=VS.90%29.aspx