How to pass C++ Object to C# - c#

Looking for help from experience people who have dealt with C++ and C#
I am now writing a C# project which requires calling an existing C++ function in the internal library, and encountering some difficulties.
C++ Code Function Header (Cannot be changed)
typedef int (*PTR_func)
(const char* param1, // input
const char* param2, // input
VirtualInternalString& po_output); // Third param is actually the output
C++ Code Class for the internal string object (Cannot be changed)
namespace InternalLib
{
class VirtualInternalString
{
public :
virtual ~VirtualInternalString(){};
virtual void _cdecl SetString(const char *) =0;
virtual const char * _cdecl c_str() const =0;
};
class SafeInternalString :public VirtualInternalString
{
public :
SafeInternalString():TheString(""){};
virtual ~SafeInternalString(){};
virtual void _cdecl SetString(const char * chararray) { TheString = chararray;};
virtual const char * _cdecl c_str() const { return TheString.c_str() ;} ; // This is the std::string
protected:
std::string TheString;
};
class SafePtrString :public VirtualInternalString
{
public :
SafePtrString():PtrString(0){};
SafePtrString(std::string &str):PtrString(&str){};
virtual ~SafePtrString(){};
virtual void _cdecl SetString(const char * chararray) { (* PtrString) = chararray;};
virtual const char * _cdecl c_str() const { return PtrString->c_str() ;} ;
protected :
std::string * PtrString;
};
}
Now I have to utilize this "func" in my C# code. I can call and use the C++ function properly, but problem occurs during output return (the third param). It should be problem related return type.
C# (Can be changed)
[DllImport("xxxxlib", CallingConvention = CallingConvention.Cdecl)]
private extern static int func(string param1,
string param2,
[MarshalAs(UnmanagedType.LPStr)] StringBuilder res); // problem here
I know I have to create an appropriate wrapper to decopose the c++ object into C# string but I don't have previous experience about it. I have tried several solutions from the internet but not working.
Does any one know how I can implement this? Would you mind showing me some simple C# skeleton code?

vasek's possible duplicate won't work if you only change the C# side. But what you can do is create wrappers in C++ that create raw char * with associated length parameter.
You create an additional C++ header and source which contains:
int func
(const char* param1, // input
const char* param2, // input
char* po_output, // Third param is actually the output
int length); // Length of the buffer allocated by caller
And then you make your func call PTR_func.

This is a case in which I think using C++/CLI does make sense. You may want to build a tiny C++/CLI bridge between the native C++ DLL and your C# code.
The C++/CLI layer is responsible to take your custom C++ string class as output parameter from the DLL function, and convert from this custom string to a C#/.NET string object.
Your custom C++ string class seems to wrap std::string; on the other hand, C#/.NET strings use Unicode UTF-16 as their text encoding, so you may need to convert between Unicode UTF-8 (stored in std::string and in your custom string class) and UTF-16 (for C#/.NET strings).
Similarly, you also need to convert C# UTF-16 strings to UTF-8 in this C++/CLI bridging layer, and pass these UTF-8-encoded strings as your const char* input parameters to the native DLL function.

Use C++ COM and consume from C# code. Only if u are on windows platform.

In past experience, I did use SWIG tool for generation wrapper implementation
It has support for C++ to wrapper generation to several languages, where Java the most popular one
There is a great tutorial - http://www.swig.org/tutorial.html
C# is also supported - http://www.swig.org/Doc3.0/CSharp.html
/* InternalLib.i */
%module InternalLib
%{
/* include header with a VirtualInternalString class*/
#include "InternalLib.h"
%}
then call swig to generate wrapper files:
swig -csharp InternalLib.i

Related

How can I return a string from a C++/CLI method back to unmanaged C++ that calls it

I'm trying to figure out how to return a string value from a C++/CLI method back to unmanaged C++ that calls it. In my current implementation, I have a string stored in a local String ^ variable in a (managed) C++/CLI method that I w/like the method to return back to the unmanaged C++ program that calls it. If using a String ^ variable is not a good choice, what construct/type w/be better? Note, I'm leaving out a part where a C# method returns the string value back to the C++/CLI method as it is not a problem.
I'm using VS2017.
CODE Example - for simplicity, code has been reduced.
Unmanaged C++ -----------------------------
_declspec(dllexport) void GetMyString();
int main()
{
GetMyString();
}
(managed) C++/CLI -------------------------
__declspec(dllexport) String GetMyString()
{
String ^ sValue = "Return this string";
return (sValue);
}
Any help is greatly appreciated. Thanks ahead of time.
You cannot return a String ^ to c++, since it will not recognize it. There is some conversions using the InteropServices though. From microsoft
using namespace System;
void MarshalString ( String ^ s, std::string& os ) {
using namespace Runtime::InteropServices;
const char* chars =
(const char*)(Marshal::StringToHGlobalAnsi(s)).ToPointer();
os = chars;
Marshal::FreeHGlobal(IntPtr((void*)chars));
}
I ended up converting a System::String^ to a std::string in a managed C++ method, returning the later to the unmanaged C++ caller.
Managed C++ file excerpts:
#include <msclr\marshal_cppstd.h>
__declspec(dllexport) std::string MyManagedCppFn()
{
System::String^ managed = "test";
std::string unmanaged2 = msclr::interop::marshal_as<std::string>(managed);
return unmanaged2;
}
Unmanaged C++ file excerpts:
_declspec(dllexport) std::string MyMangedCppFn();
std::string jjj = MyMangedCppFn(); // call Managed C++ fn
Credit goes to an answer/edit from tragomaskhalos and Juozas Kontvainis to a stackoverflow question asking how to convert a System::String^ to std::string.

Passing Pointer between C++ Project and C# Project without using unsafe on C# project

Stuck in very naive issue. I have two project, One in C++ and other in C#. Idea is to use C++ project as wrapper around some C libs. and performing actual logic in C#.
Passing the Value type is very convenient. But with reference type i am having hard time WITHOUT USING unsafe or DllImport attribute.
C++
Cryptoki.Wrapper.h File
using namespace System;
#pragma comment(lib, "legacy_stdio_definitions.lib")
namespace CryptokiWrapper {
public ref class CryptokiInit
{
public:
char* TESTString(char* test);
double TESTDouble(double test);
};
}
Cryptoki.Wrapper.cpp File
#include "stdafx.h"
#include "Cryptoki.Wrapper.h"
using namespace std;
using namespace CryptokiWrapper;
char* CryptokiInit::TESTString(char* test)
{
char* r = test;
return r;
}
double CryptokiInit::TESTDouble(double test)
{
unsigned long int r = test;
return r;
}
C# Code
using System;
using System.Runtime.InteropServices;
using CryptokiWrapper;
namespace CallCryptoki
{
class Program
{
//[MarshalAs(UnmanagedType.LPTStr)]
//public String msg = "Hello World";
static void Main(string[] args)
{
CryptokiInit ob = new CryptokiInit();
//This Works
doubled d = ob.TESTDouble(99);
//But having hard time accepting the char* reference
//or sending string as refrence without using unsafe
// like
string text = "Hello World!";
string res = (*something*)ob.TESTString((*something*)text);
}
}
}
IS there any type of cast (i.e. something) .....
is there anyway where i am able to easily perform this action. (only reference transfer will be sufficient, then i can build string or object)
Like on another function works, using the double as parameter and return type.
Though above example speak of string only, but would like to understand as concept so that i could write interop for any reference type between two project(i.e. C# and C++)
Thanks in advance for help!
First, that's not plain C++, but C++/CLI - which is primarily designed for managed/unmanaged code interoperability.
Your C++/CLI function can use .NET's string type like this:
System::String^ TESTString(System::String^ test);
^ means managed reference, think of it as the managed equivalent of *.
Now, to use the string data in pure C++, you have two choices:
marshal it - see Overview of Marshaling in C++
For instance, if you need to convert it to a const char*, do the following:
#include <msclr/marshal.h>
msclr::interop::marshal_context ctx;
auto testCStr = ctx.marshal_as<const char*>(test);
// testCStr is freed when ctx goes out of scope
This will copy the string data, as the memory representation needs to change from 2 bytes par character to a single one.
access the memory directly as const wchar_t*. You need to pin the string beforehand so it's not moved by the GC.
#include <vcclr.h>
pin_ptr<const wchar_t> testCStr = PtrToStringChars(test);
// testCStr behaves just like a const wchar_t*
Do not modify the string data this way.
To send a string back to the managed side, you can either use marshal_as<System::String^>(yourCString), or call gcnew System::String(yourCString);

Is gcroot and /clr mixed mode and a C++ wrapper the shortest path from pure C to C#?

So I am writing a plug-in DLL which is pure C (and a heap of foreign includes), but most of the real code is in an existing C# class library. I'm looking for the shortest path from C (not C++) to C#. The foreign includes are not C++ safe.
There are heaps of samples around for C++, not much for pure C.
It seems I should be able to compile the whole DLL as /clr but compile the C as not; then include in the same DLL a C++ wrapper that presents a C API but contains managed code to call the C# class.
So instantiate the C# class and hang onto it in a gcroot in a C++ class, and pass the C++ class pointer as a void* back for the the C code to keep for future calls.
Quite a few details to get right, but not all that much code. Is there a better way?
Thought it was time to add a bit of code.
// Wrapper.h
#pragma once
// API for call by C
#ifdef __cplusplus
extern "C" {
#endif
void* wrap_create();
void wrap_doit(void* wrapper, char* input, char* output, int maxlen);
#ifdef __cplusplus
}
#endif
// Wrapper.cpp
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <vcclr.h>
#include "Wrapper.h"
using namespace System;
class Wrapper {
public:
gcroot<Wrappee::Evaluator^> eval;
Wrapper() {}
};
void* wrap_create() {
Wrapper* w = new Wrapper();
w->eval = gcnew Wrappee::Evaluator();
return w;
}
void wrap_doit(void* wrapper, char* input, char* output, int maxlen) {
Wrapper* w = (Wrapper*)wrapper;
String^ s = w->eval->Doit(gcnew String(input));
pin_ptr<const wchar_t> wch = PtrToStringChars(s);
wcstombs(output, wch, maxlen);
}
// Wrappee.cs
using System;
namespace Wrappee {
public class Evaluator {
string _s;
public static Evaluator Create() {
return new Evaluator {
_s = "wrapped evaluator"
};
}
public string Doit(string s) {
return _s + ":" + s;
}
}
}
Why wouldn't that work? The code is based on this link: https://msdn.microsoft.com/EN-US/library/481fa11f%28v=VS.140,d=hv.2%29.aspx.
The answer is no, that won't work. The managed class depends on the CLR runtime, which needs to be hosted by the application. For a managed app that happens automatically (mscoree.dll during startup), but for a native app there is no host so no CLR.
So we have to provide one. As #hanspassant helpfully pointed out, this is "Reverse P/Invoke" and it really is different. You have to get there by the COM hosting interfaces, specifically ICLRMetaHost.
And the good news is that there is a sample here to show how it's done: https://code.msdn.microsoft.com/windowsdesktop/CppHostCLR-e6581ee0.
There are other samples too: search for CppHostCLR.

Passing char* buffer to C# as a StringBuilder

I have a C++ function that is called with a char* buffer to be used for the output. Now i want to write to it using C# so i need to call a managed method from the C++ function. What i can't figure out is how to pass it as a StringBuilder.
I previously used Robert Giesecke's Unmanaged Exports which worked fine and did this automatically using a default string marshalling scheme, but i want to use the size parameter for the MaxCapacity of the StringBuilder.
Is there a nicer way to do this than creating a new StringBuilder instance, writing to it, getting a CLR string with ToString(), and then copying the contents to the buffer? The strings in question might be as long as 10,000 characters and i don't really like the idea of copying it twice each time.
C#
public static void MyMethod(StringBuilder buffer)
{
//...
}
C++/CLI
extern "C" __declspec(dllexport)
void __stdcall MyFunction(char* buffer, int length)
{
MyNamespace::MyClass::MyMethod( /* ? */ );
}
Use a byte [] then c++ 8 bit character array will align correctly.
I prefer to do something similar to this because I use it for unmanaged code:
String ^ ToManagedString(const char * pString) {
return Marshal::PtrToStringAnsi(IntPtr((char *)pString)); // Marshal pString into Managed Memory. return as a C# string reference (^).
}
const std::string ToStdString(String ^ strString) {
IntPtr ptrString = IntPtr::Zero;
std::string strStdString;
try {
ptrString = Marshal::StringToHGlobalAnsi(strString); // Marshal a C# String reference into unmanaged HEAP memory space.
strStdString = (char *)ptrString.ToPointer(); // Convert C# IntPtr to char* implicitly, call assignment operator of std::string to copy.
}
finally {
if (ptrString != IntPtr::Zero) {
Marshal::FreeHGlobal(ptrString);
}
}
return strStdString; // return std::string copied out of interop unmanaged heap space
}

How to get string from managed c++ dll (using wrapper class) in c#

i have done this using unmanaged dll but having some difficulty using managed dll.
I want to pass a string to my managed c++ wrapper class which process it and return modified string
the purpose of c++ dll is to return hex code of a file(and later modifies it to do some complicated tasks within dll) which i pass it as a string, for this approcach i have used managed c++ dll instead of unmanaged one.
my c++ class is as follows :
using namespace std;
//main function - entry point of program __declspec(dllexport)
const char* hexclass:: getfilename(char* filename)
{
//to open file
ifstream::pos_type size;
string virusScanStatus;
char* fileAccessError;
string errorDes ="Exception has Occured With Current File Operation";
//hexcode logic goes here
fileAccessError = new char[errorDes.size()];
errorDes.copy(fileAccessError,errorDes.size());
return fileAccessError;
}
my c++ wrapper class is as follows :
header file including c++ file here (not shown for code readabitily)
using namespace System;
namespace CWrapperHexValue {
public ref class cWrapperHexValue
{
public:
cWrapperHexValue();
const char* hexValue;
const char* getHexValue(char* fileName);
private:
hexclass* pHexClass;
};
}
and my wrapper class is as follows :
// This is the main DLL file.
#pragma once
#include "stdafx.h"
#include "CWrapperHexValue.h"
#include "D:\Projects\program10\program10\hexclass.cpp"
#include "D:\Projects\program10\program10\hexclass.h"
CWrapperHexValue::cWrapperHexValue::cWrapperHexValue()
{
pHexClass = new hexclass();
}
const char* CWrapperHexValue::cWrapperHexValue::getHexValue(char* fileName)
{
hexValue= pHexClass -> getfilename(fileName);
return hexValue;
}
and finally my c# code to send filename is as follows :
//my c++ dll name is CWrapperHexValue
CWrapperHexValue.cWrapperHexValue objHexClass = new CWrapperHexValue.cWrapperHexValue();
byte[] fileNameBytes = Encoding.ASCII.GetBytes(fileNameForHexScan);
unsafe
{
fixed (byte* p= fileNameBytes)
{
sbyte* sp = (sbyte*)p;
sbyte* returnSp = objHexClass.getHexValue(sp);
}
}
now how do i get back the returnSp value as a string or any other better way to pass and get string, please provide useful code because i have not much experience with c++/c# cli conversion
please advice how can i improve my code for better memory management becuase i have to pass a whole lot of system files one by one and get their hex code
Depending on what
// hexcode logic
is, it might be better/easier to implement it in C# and forget about the marshaling.
If you really need to marshal strings from C++ to C#, this topic will likely help you quite a bit: How to marshall c++ char* to C# string using P/INVOKE (code is here)
Basically just build a native DLL out of your native code and you can just pinvoke it from C# rather than have the intermediate managed C++ class if all you need is a string.
In terms of memory management, if you can move the hexcode logic into C#, that would eliminate the need to marshal strings and likely save you some processing, but more importantly, be less painful to debug. Namely, why can't you do this?
C#
public void SomeFunction()
{
string filepath = "foo.bar"
string hexVal = HexCodeLogicInManaged(filepath);
... other code ...
}
private string HexCodeLogicInManaged(string filepath)
{
// hexcode logic converted from native to managed
}

Categories