I have a C# function that I made into a DLL:
public static string Test(string name)
{
return "Hello " + name;
}
In C++/CLI project I successfully import that DLL, now I want to have a way to call that function and make it available for normal unmanaged C++. So I want to export the C++/CLI function like this:
extern "C" __declspec(dllexport)
void __stdcall Example(char* name, char* greet) {
// name will be passed to C# Test(...) function
// and greet will contains the returned value
// call to the C# function here:
...
}
I dont care what the C++/CLI function looks like, as long as i can export it to normal unmanaged C++.
** Edit: as someone complain about my question, I only need to know how you can call the C# function, given a C string, and how to retrieve the returned result and store it in another C string. It's not like a "problem", it's like a newbie who don't know how to code, and come here to ask... Thank you **
** Edit2: now i noticed, someone has edited my post (i dont know, a moderator or someone...). Now when i re-read my post, even i don't know what the post trying to ask... Please, i think you shouldn't do that **
With C++/CLI you have everything you need at your disposal.
You could do it this way:
#include <string>
#include <msclr\marshal_cppstd.h>
extern "C" __declspec(dllexport)
void __stdcall Example(char* name, char* greet) {
// name will be passed to C# Test(...) function
// and greet will contains the returned value
// Create new System::String^ from char*
System::String^ clrString = msclr::interop::marshal_as<System::String^>(name);
// Call C# function
System::String^ result = Test(clrString);
// Create new std::string from System::String^
std::string cppString = msclr::interop::marshal_as<std::string>(result);
// Copy C++-string to the destination
strcpy(greet, cppString.c_str());
}
This solution uses std::string
. You can also use a marshal_context
to directly convert between System::String
and char[]
, but I prefer to use std::string
since it saves you some typing and there is less to go wrong.
Of course, one can shorten this down to:
strcpy(greet, marshal_as<string>(Test(marshal_as<String^>(name))).c_str());
Or even further, since System::String
has a constructor accepting char*
:
strcpy(greet, marshal_as<string>(Test(name)).c_str());
Have a look here for more info about marshalling: http://msdn.microsoft.com/en-us/library/bb384865.aspx
Important:
C# uses dynamic strings and C# code often happily generates very long strings, resulting in a crash or worse if the memory pointed to by greet
is not large enough to contain the string.
A common way to deal with this is to change the signature of Example
to something like this:
void __stdcall Example(char* name, char* greet, size_t destBufferSize)
And check if the destBufferSize is large enough to contain the resulting string or truncate the value using strncpy
or similar methods.