Click here to Skip to main content
15,074,668 members
Articles / Programming Languages / VC++
Article
Posted 18 Nov 2014

Stats

33.6K views
565 downloads
24 bookmarked

Calling All Stations

Rate me:
Please Sign up or sign in to vote.
4.15/5 (10 votes)
5 Dec 2014CPOL2 min read
Interoperability: Calling C++ from C#

Introduction

Interoperability between the different languages in Visual Studio is cool feature, because it enhances posibilities and make code reuse easier. To demonstrate it I wrote some plain vanilla code which works.

Image 1

Background

Some days ago somebody asked "how can I call C++ from C#" and I felt write a short article is good idea to condense my knowledge.

Using the code

The code consists of two parts: the C# code which consumes the C++ code from a dll. The C++ dll is some annoying code like using a C++ class with its function and some standard lib calls.

C++
CPLUSPLUS_API int multiply(int v1, int v2)
{
	//do the heavy lifting with C++
	Worker worker;

	int res = worker.DoMultiply(v1,v2);
	//finally return the result, or error code !!!
	return res;
}

CPLUSPLUS_API int buildText(const char* s1, const char *s2, char* sResult, int len)
{
	int cnt = _snprintf( sResult, len, "%s %s.", s1, s2 );

	int rc  = (len > cnt) ? cnt : -1;

	return rc;
}

Interesting is that Strings and buffers are manipulated, but I stick to the rule that the memory comes from the client and no memory is allocated in the server code to be read in the server code. So the client needs to deliver the bytes, and the server works carefully with it.

C++
CPLUSPLUS_API int buildBuffer(const unsigned char* s1, int l1, unsigned char* sResult, int len)
{
	//some lite error handling
	bool enoughBytes = (len >l1);
	//only copy buffersize
	size_t lenCopy = enoughBytes ? l1 : len;

	memcpy(sResult, s1, lenCopy);

	return enoughBytes ? 0 : -1;
}

A final problem is working with callbacks which are functions and more precisly function pointers. In my sample only a function pointer is set and called. For more complex scenarios, the pointer should be only set and called back later in some threading scenarios.

C++
CPLUSPLUS_API int setCallback( void* callback)
{
	if( callback == NULL ) return -1;

	VOID_CALLBACK_FUNCTION cbFunction = (VOID_CALLBACK_FUNCTION) callback;
	//simple callback
	cbFunction();

	return 0;
}

 

More interesting is the C# side, in which I use the Interop services. In that I declare the the use of the dll function with its interface. If something crashes at most there is the cause. My real trick is to use Ansi characterset and the StringBuilder class which has a char[] operator or use a byte[]. And the callback is type defined in C# as a void delegate and has so the same "footprint" as the pointer is used in the dll.

C#
//for dll imports we need that
using System.Runtime.InteropServices;

// this class manages the calls to the dll
namespace CSharpInterOp
{
    class CDllWrapper
    {
        #region Dll interface
        public CDllWrapper() { }

        [DllImport("CPlusPlus",                //name of the dll
                    EntryPoint = "multiply",   //name of function in dll
                    ExactSpelling = true,
                    CharSet = CharSet.Ansi,
                    CallingConvention = CallingConvention.Cdecl)]
        public static extern unsafe int multiply(int i1, int i2);

        [DllImport("CPlusPlus",               //name of the dll
                    EntryPoint = "buildText", //name of function in dll
                    ExactSpelling = true,
                    CharSet = CharSet.Ansi,
                    CallingConvention = CallingConvention.Cdecl)]
        public static extern unsafe int buildText(StringBuilder s1, StringBuilder s2, StringBuilder sResult, int len);
               
         [DllImport("CPlusPlus",               //name of the dll
                    EntryPoint = "buildBuffer", //name of function in dll
                    ExactSpelling = true,
                    CharSet = CharSet.Ansi,
                    CallingConvention = CallingConvention.Cdecl)]
        public static extern unsafe int buildBuffer(byte[] b1, int l1, byte[] bResult, int len);
        
        [DllImport("CPlusPlus",                     //name of the dll
                    EntryPoint = "setCallback",  //name of function in dll
                    ExactSpelling = true,
                    CharSet = CharSet.Ansi,
                    CallingConvention = CallingConvention.Cdecl)]
         public static extern unsafe int setCallback(Form1.callbackDelegate cb);
        #endregion
    }
}

Points of Interest

In the end looks it all clean and easy, but in this little code are some hard lessons. So I hope many will help it and the question "How to do this" are ending. 

One of the learned lessons, is that "Sh*t happens" and some stable error handling is really need. If the dll is missing or cant be loaded because of other missing dlls you are right in the "DLL Hell". So be warned!!!

Finally I also want to point to my article Full power on the Phone which handles managed C++ with C# on Windows Phone 8, but could be some blueprint for the whole Windows platform.

History

Initial version.

Added simple callback functionality (5 dec 14)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

KarstenK
Software Developer
Germany Germany
I am living in germany and now living from programming for some Years. In my spare time I like sports as jogging, playing football (soccer) and basketball.

We must take care for our planet, because we and our family has no other. And everybody has to do something for it.

Comments and Discussions

 
QuestionVery short Pin
BillW3321-Oct-15 8:41
professionalBillW3321-Oct-15 8:41 
SuggestionCalling All Stations??? Pin
sreeyush sudhakaran10-Aug-15 0:48
professionalsreeyush sudhakaran10-Aug-15 0:48 
Questionhave you consider to post this as a tip? Pin
Nelek7-Dec-14 1:02
protectorNelek7-Dec-14 1:02 
GeneralWhat does this have to do with C++? Pin
Yves Goergen1-Dec-14 1:17
MemberYves Goergen1-Dec-14 1:17 
GeneralRe: What does this have to do with C++? Pin
KarstenK5-Dec-14 2:34
mveKarstenK5-Dec-14 2:34 
GeneralRe: What does this have to do with C++? Pin
Yves Goergen5-Dec-14 3:01
MemberYves Goergen5-Dec-14 3:01 
GeneralRe: What does this have to do with C++? Pin
KarstenK6-Dec-14 7:04
mveKarstenK6-Dec-14 7:04 
QuestionWhat is the definition of CPLUSPLUS_API? Pin
wim ton21-Nov-14 1:35
Memberwim ton21-Nov-14 1:35 
AnswerRe: What is the definition of CPLUSPLUS_API? Pin
KarstenK26-Nov-14 4:36
mveKarstenK26-Nov-14 4:36 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.