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 .
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
.
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!
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.