The C++ code is as follows
#include "stdafx.h"
#include <Windows.h>
#import "C:\shreyas\Documents\ConsoleApplication1\ConsoleApplication1\bin\Debug\ConsoleApplication1.tlb" no_namespace
int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL);
IMyClassPtr obj;
//iProgramPtr obj;
obj.CreateInstance(__uuidof(MyClass));
printf("value: %d",obj->display());
CoUninitialize();
getchar();
return 0;
}
The C# code is as follows
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
namespace demo
{
[ComVisible(true)]
public interface IMyClass
{
int display();
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
class MyClass : IMyClass
{
public int display()
{
Console.WriteLine("Hello");
return 10;
}
}
}
I would like to call the C# display function from C++ code. I have done the required settings in C# project properties. In the code obj.CreateInstance(__uuid(MyClass)); the MyClass is giving an error as an undefined identifier.
Do pay attention to the build warning you get when you compile ConsoleApplication1:
warning MSB3214: "C:...\ConsoleApplication1\bin\Debug\ConsoleApplication1.dll" does not contain any types that can be registered for COM Interop.
That's not good of course. Also something you see with you look at the .tlb file with Oleview.exe's View + Typelib command. Or open the .tlh file that the #import directive generates with a text editor, find it back in the C++ project's Debug directory. You'll see that MyClass is completely missing, thus the compile error.
That is because of:
class MyClass : IMyClass
You forgot to declare it public. Required.
Related
I have a very basic unmanaged C++ project, C++/CLI wrapper and C# GUI. I've built all 3 projects as x64. I try and run the C# project and I get the following exception:
First-chance exception at 0x000007fefd84cacd in TestAppGUI.exe:
Microsoft C++ exception: EEFileLoadException * __ptr64 at memory
location 0x0057b498.
Does anyone know what could be causing the issue?
These are my classes:
Test.h (unmanaged code)
#define DllExport __declspec( dllexport )
#include <iostream>
namespace Test
{
class DllExport BasicTest
{
public:
BasicTest();
~BasicTest();
};
}
Test.cpp
#include "Test.h"
Test::BasicTest::BasicTest()
{
}
Test::BasicTest::~BasicTest()
{
}
TestCLR.h (wrapper)
// TestCLR.h
#pragma once
#include "../TestApp/Test.h"
using namespace System;
using namespace Test;
namespace TestCLR {
public ref class Class1
{
// TODO: Add your methods for this class here.
public:
Class1();
private:
BasicTest *bsTest;
};
}
TestCLR.cpp
// This is the main DLL file.
#include "stdafx.h"
#include "TestCLR.h"
TestCLR::Class1::Class1()
{
bsTest = new BasicTest();
}
TestAppGUI Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using TestCLR;
namespace TestAppGUI
{
public partial class Form1 : Form
{
Class1 obj = new Class1();
public Form1()
{
InitializeComponent();
}
}
}
I want to call a C# function from C++ , via CLI/C++.
C# code
private string _text = " ";
public void setText(string text)
{
// _text = text;
_text = "HI World";
}
Ideally setText shall have the commented line only. The _text = "HI World" is an example.
public string getText()
{
return _text;
}
C++/CLI code
Header :
gcroot<Bridge> _managedObject;
virtual void setText(std::string text);
virtual std::string getText();
CPP file
std::string CStringBridge::getText()
{
// _managedObject = gcnew Bridge();
return (marshal_as(_managedObject->getText()));
}
void CStringBridge::setText(std::string text)
{
// _managedObject = gcnew Bridge();
_managedObject->setText(gcnew System::String(text.c_str()));
}
IStringBridgeWrapper* IStringBridgeWrapper::CreateInstance(void)
{
return ((IStringBridgeWrapper *)new CStringBridge());
}
Note : When I use the following code
virtual void setText(System::String^ text);
virtual System::String^ getText();
I get the following error 3395
*__declspec(dllexport) cannot be applied to a function with the __clrcall calling convention*
, and so I stuck to std::string
When I use the library from the C++/CLI code, and call from my C++ program, "Hi World" should be printed ; instead nothing gets printed
C++ console application
IStringBridgeWrapper *pBridge = IStringBridgeWrapper::CreateInstance();
pBridge->setText(std::string("I am here"));
pBridge->getText();
I think the string is not being properly passed .
Any ideas to solve it shall be appreciated.
EDIT
I have updated the code after the comments , yet nothing shows up.
gcroot creates a handle, but does not allocate memory for it. But as Bridge has no memory allocated , the application does not work.My code is in the same lines at the article here - http://www.codeproject.com/Articles/10020/Using-managed-code-in-an-unmanaged-application .
COM is your friend:
Create a an interface in C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace CsharpLibrary
{
// Since the .NET Framework interface and coclass have to behave as
// COM objects, we have to give them guids.
[Guid("56A868B1-0AD4-11CE-B03A-0020AF0BA770"),
InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IStringHolder
{
String GetText();
void SetText(String s);
}
}
Implement the C# interface:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace CsharpLibrary
{
[Guid("C6659361-1625-4746-931C-36014B146679")]
public class MyStringHolder : IStringHolder
{
String _text;
public String GetText()
{
return this._text;
}
public void SetText(String value)
{
_text = value;
}
}
}
Create and call your C# object from C++
#include <windows.h>
#include <stdio.h>
#pragma warning (disable: 4278)
// To use managed-code servers like the C# server,
// we have to import the common language runtime:
#import <mscorlib.tlb> raw_interfaces_only
#pragma warning (disable: 4278)
// To use managed-code servers like the C# server,
// we have to import the common language runtime:
#import <mscorlib.tlb> raw_interfaces_only
#import "..\CsharpLibrary\bin\Debug\CsharpLibrary.tlb" no_namespace named_guids
int main(int argc, char* argv[])
{
HRESULT hr = S_OK;
IStringHolder *pStringHolder = NULL;
//
// Initialize COM and create an instance of the InterfaceImplementation class:
//
CoInitialize(NULL);
hr = CoCreateInstance( __uuidof(MyStringHolder),
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IStringHolder),
reinterpret_cast<void**>(&pStringHolder));
if(SUCCEEDED(hr))
{
_bstr_t sHelloWorld = SysAllocString( L"Hello, World" );
hr = pStringHolder->SetText(sHelloWorld);
SysFreeString(sHelloWorld);
}
//
// Be a good citizen and clean up COM
//
CoUninitialize();
return hr;
}
On the C# side you have to generate the type library and register the class by a post-build event:
generate the type library:
"$(FrameworkSDKDir)bin\NETFX 4.0 Tools\tlbexp.exe" "$(TargetPath)" /out:"$(TargetDir)$(TargetName).tlb"
register the class:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe "$(TargetPath)"
Enjoy!
I want to call a C# function from C++ , via CLI/C++.
Wait... you want to call a C++ function from C#, right? That's what C++/CLI is good for. Wrapping C++ code to be accessible in managed environments. If you really want to call C# code from C++, you should look into COM registering your C# code. If you use C++/CLI for this, your whole C++ program will be dragged into the .NET world and you could have used C# from the start.
In C++/CLI, your whole public class interface of ref (.NET) classes should consist of only managed types. That would be System::String^ instead of std::string.
I am currently trying to use a simple C++ DLL in a C# program for a school project but I have trouble making the DLL and Program link with each other. When I try to call the DLL's function in the main program, I get a SEHExcpetion thrown from the DLL.
Here is the DLL code
#include <stdio.h>
#include <string>
using namespace std;
extern "C"
{
__declspec(dllexport) string Crypter(string sIn)
{
return sIn+ " from DLL";
}
}
And here's the C# code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
[DllImport("CryptoDLL2.dll")]
public static extern string Crypter(string sIn);
public Form1()
{
InitializeComponent();
}
private void BTN_Crypter_Click(object sender, EventArgs e)
{
TB_OUT.Text = ("");
TB_OUT.Text = Crypter(TB_IN.Text); //exception thrown here
}
}
}
Strings in C# and C++ - Those are completely different types, layouts, etc. And you expect them to work.
Check out char* with marshalling.
you cannot use std::string from C#, it is a c++ class, .NET does not know how to handle it.
Try using wchar_t* or BSTR.
I did a test to make sure the linking was fine, here is a sample app showing it does work.
#include <stdio.h>
#include <string>
using namespace std;
extern "C"
{
__declspec(dllexport) string Crypter(string sIn)
{
printf("test");
return "from DLL";
}
}
And
public class Test
{
[DllImport("TestDll.dll")]
public static extern string Crypter(string sIn);
static void Main(string[] args)
{
Console.WriteLine(Crypter("a"));
}
}
This prints me out
test
followed by a newline.
You need to probably marshal the data from c++ to .net, or use a c++/clr managed dll which would make things easier on you.
C# methods cannot be called directly in Java using JNI due to different reasons. So first we have to write a wrapper for C# using C++ then create the dll and use it through JNI in Java.
I have problem in calling C# code in C++. I'm adding C# .netmodule file to a C++ project. Code is pasted below. Please guide me if i'm doing anything wrong.
This is my managed C++ class UsbSerialNum.h:
#using <mscorlib.dll>
#include <iostream>
#using "UsbSerialNumberCSharp.netmodule"
using namespace std;
using namespace System;
public __gc class UsbSerialNum
{
public:
UsbSerialNumberCSharp::UsbSerialNumberCSharp __gc *t;
UsbSerialNum() {
cout<<"Hello from C++";
t = new UsbSerialNumberCSharp::UsbSerialNumberCSharp();
}
void CallUsbSerialNumberCSharpHello() {
t->hello();
}
};
C# UsbSerialNumberCSharp.cs file from which i've created the .netmodule file:
using System.Collections.Generic;
using System.Text;
namespace UsbSerialNumberCSharp
{
public class UsbSerialNumberCSharp
{
public UsbSerialNumberCSharp(){
Console.WriteLine("hello");
}
public static void hello()
{
Console.WriteLine("hello");
}
public void helloCSharp ()
{
Console.WriteLine("helloCSharp");
}
}
}
Here is my main makeDLL.cpp file from which makeDLL.dll is created:
#include "jni.h"
#include <iostream>
// This is the java header created using the javah -jni command.
#include "testDLL.h"
// This is the Managed C++ header that contains the call to the C#
#include "UsbSerialNum.h"
using namespace std;
JNIEXPORT void JNICALL Java_testDLL_hello
(JNIEnv *, jobject) {
// Instantiate the MC++ class.
UsbSerialNum* serial = new UsbSerialNum();
serial->CallUsbSerialNumberCSharpHello();
}
Here is my java class:
public class testDLL {
static {
System.loadLibrary("makeDLL");
}
/**
* #param args
*/
public static void main (String[] args) {
// new testDLL().GetUSBDevices("SCR3", 100);
new testDLL().hello();
}
public native void hello();
}
EDIT:
If i simply ignore the call to UsbSerial.h in my main file i.e. use simple C++ then my code is working fine in Java. Basically C++ managed class is not working properly.
Please guide me. Thanks.
It would be useful to know what you need this interoperability for exactly. In any case, you should look into IKVM; alternatively you can (as has been suggested for a similar problem) use COM as a bridge: expose the C#/CLR as a COM interface and then use com4j in Java.
You can avoid C# and still can query WMI using C++ only. See Using WMI to call method on objects
I'm a bit rusty, actually really rusty with my C++. Haven't touched it since Freshman year of college so it's been a while.
Anyway, I'm doing the reverse of what most people do. Calling C# code from C++. I've done some research online and it seems like I need to create some managed C++ to form a bridge. Use __declspec(dllexport) and then create a dll from that and use the whole thing as a wrapper.
But my problem is - I'm really having a hard time finding examples. I found some basic stuff where someone wanted to use the C# version to String.ToUpper() but that was VERY basic and was only a small code snippet.
Anyone have any ideas of where I can look for something a bit more concrete? Note, I do NOT want to use COM. The goal is to not touch the C# code at all.
Create a new C++/CLI project in visual studio and add a reference to your C# dll. Assume we have a C# dll called DotNetLib.dll with this class in:
namespace DotNetLib
{
public class Calc
{
public int Add(int a, int b)
{
return a + b;
}
}
}
Now add a CLR C++ class to your C++/CLI project:
// TestCPlusPlus.h
#pragma once
using namespace System;
using namespace DotNetLib;
namespace TestCPlusPlus {
public ref class ManagedCPlusPlus
{
public:
int Add(int a, int b)
{
Calc^ c = gcnew Calc();
int result = c->Add(a, b);
return result;
}
};
}
This will call C# from C++.
Now if needed you can add a native C++ class to your C++/CLI project which can talk to the CLR C++ class:
// Native.h
#pragma once
class Native
{
public:
Native(void);
int Add(int a, int b);
~Native(void);
};
and:
// Native.cpp
#include "StdAfx.h"
#include "Native.h"
#include "TestCPlusPlus.h"
Native::Native(void)
{
}
Native::~Native(void)
{
}
int Native::Add(int a, int b)
{
TestCPlusPlus::ManagedCPlusPlus^ c = gcnew TestCPlusPlus::ManagedCPlusPlus();
return c->Add(a, b);
}
You should be able to call the Native class from any other native C++ dll's as normal.
Note also that Managed C++ is different to and was superceeded by C++/CLI. Wikipedia explains it best:
http://en.wikipedia.org/wiki/C%2B%2B/CLI
While lain beat me to writing an example, I'll post it anyhow just in case...
The process of writing a wrapper to access your own library is the same as accessing one of the standard .Net libraries.
Example C# class code in a project called CsharpProject:
using System;
namespace CsharpProject {
public class CsharpClass {
public string Name { get; set; }
public int Value { get; set; }
public string GetDisplayString() {
return string.Format("{0}: {1}", this.Name, this.Value);
}
}
}
You would create a managed C++ class library project (example is CsharpWrapper) and add your C# project as a reference to it. In order to use the same header file for internal use and in the referencing project, you need a way to use the right declspec. This can be done by defining a preprocessor directive (CSHARPWRAPPER_EXPORTS in this case) and using a #ifdef to set the export macro in your C/C++ interface in a header file. The unmanaged interface header file must contain unmanaged stuff (or have it filtered out by the preprocessor).
Unmanaged C++ Interface Header file (CppInterface.h):
#pragma once
#include <string>
// Sets the interface function's decoration as export or import
#ifdef CSHARPWRAPPER_EXPORTS
#define EXPORT_SPEC __declspec( dllexport )
#else
#define EXPORT_SPEC __declspec( dllimport )
#endif
// Unmanaged interface functions must use all unmanaged types
EXPORT_SPEC std::string GetDisplayString(const char * pName, int iValue);
Then you can create an internal header file to be able to include in your managed library files. This will add the using namespace statements and can include helper functions that you need.
Managed C++ Interface Header file (CsharpInterface.h):
#pragma once
#include <string>
// .Net System Namespaces
using namespace System;
using namespace System::Runtime::InteropServices;
// C# Projects
using namespace CsharpProject;
//////////////////////////////////////////////////
// String Conversion Functions
inline
String ^ ToManagedString(const char * pString) {
return Marshal::PtrToStringAnsi(IntPtr((char *) pString));
}
inline
const std::string ToStdString(String ^ strString) {
IntPtr ptrString = IntPtr::Zero;
std::string strStdString;
try {
ptrString = Marshal::StringToHGlobalAnsi(strString);
strStdString = (char *) ptrString.ToPointer();
}
finally {
if (ptrString != IntPtr::Zero) {
Marshal::FreeHGlobal(ptrString);
}
}
return strStdString;
}
Then you just write your interface code that does the wrapping.
Managed C++ Interface Source file (CppInterface.cpp):
#include "CppInterface.h"
#include "CsharpInterface.h"
std::string GetDisplayString(const char * pName, int iValue) {
CsharpClass ^ oCsharpObject = gcnew CsharpClass();
oCsharpObject->Name = ToManagedString(pName);
oCsharpObject->Value = iValue;
return ToStdString(oCsharpObject->GetDisplayString());
}
Then just include the unmanaged header in your unmanaged project, tell the linker to use the generated .lib file when linking, and make sure the .Net and wrapper DLLs are in the same folder as your unmanaged application.
#include <stdlib.h>
// Include the wrapper header
#include "CppInterface.h"
void main() {
// Call the unmanaged wrapper function
std::string strDisplayString = GetDisplayString("Test", 123);
// Do something with it
printf("%s\n", strDisplayString.c_str());
}