///////////////////////
//
//
// On MS Windows
// -------------
// cl /c /D_WINDOWS DllSave.cpp
// link /out:libMonoWindows.dll /DLL /DEF:libMonoWindows.def DllSave.obj
//
// On GNU/Linux
// ------------
//
// g++ -c fPIC DllSave.cpp
// g++ -shared -o libMonoLinux.so DllSave.o
//
// On MAC OS X
// ------------
// g++ -c -fPIC DllSave.cpp
// g++ -dynamiclib -o libMonoMac.so DllSave.o
//
//
// Written by Praseed Pai K.T.
// http://praseedp.blogspot.com
//
#include <stdio.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
////////////////////////////////
//
// .NET follows __stdcall calling convention
//
//
//
#ifdef _WINDOWS
#define EXPORT_FUNC __declspec(dllexport)
#define CALL_CONV __stdcall
#else
//---------------------- MAC OS X | LINUX
#define EXPORT_FUNC
#define CALL_CONV
#endif
//////////////////////////////////////////////////////
//
//
// A Simple Function to Add two numbers
//
//
//
extern "C" EXPORT_FUNC int CALL_CONV Add(int a, int b )
{
return a + b;
}
////////
//
//
//
//
//
//
// A Function to demonstrate CallBacks
//
// The function calls a C# method via delegate
//
// (remember cyclic definition of delgate ? )
//
// What is a delegate ?
// Delegates are function Pointers....!
//
// What are function pointers ?
// I told you,it is equivalent to a delegate
//
//
//
extern "C" EXPORT_FUNC void CALL_CONV ListOfSquares(
long (CALL_CONV *square_callback) (int rs)
)
{
for(int i=0; i<10; ++i )
{
double ret = (*square_callback)(i);
printf("Printing from C++ ... %g\n",ret);
}
}
////////////////////
//
//
//
//
//
//
// a clone of lstrcpy WIN API function...
//
//
extern "C" EXPORT_FUNC bool CALL_CONV StringCopy( char *t ,
const char *src )
{
if ( t == 0 || src == 0 )
return false;
if (*src == 0 )
return false;
strcpy(t,src);
return true;
}
///////////////////////////////////
//
// This structure will be passed between
// C# and C++
//
//
struct EventData
{
int I;
char * Message;
};
extern "C" EXPORT_FUNC bool CALL_CONV PutEventData(
EventData *ptr )
{
printf("%s\n",ptr->Message);
printf("%d\n",ptr->I);
return false;
}
On Microsoft Windows , you require a DEF (Module Definition ) file to avoid name mangling by the Visual C++ compiler.
;----------- A module definition file
;------------for Windows DLL
LIBRARY libMonoWindows
EXPORTS
Add
ListOfSquares
StringCopy
PutEventData
Here is a sample C# program which invokes the dll mentioned above... The code works on Windows , Linux and MAC OS X as well.
//////////////////////////////////////////////////////
//
//
// First.cs
//
// On Windows
// -----------
// csc First.cs
//
// on Linux/MAC OS X
// -----------------
// mcs First.cs (in ubuntu, it is gmcs First.cs )
//
//
// When executing , make sure that libMonoWindows.dll
// (under windows ) is in the current directory or
// in the path
//
// Written by Praseed Pai K.T.
// http://praseedp.blogspot.com
//
//
#define WINDOWS // MAC_OS_X | GNU_LINUX
using System;
using System.Text;
using System.Runtime.InteropServices;
////////////////////////////////
//
// C# mapping of C/C++ structure...
//
//
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct EventData
{
public int I;
public string Message;
}
public class Test
{
///////////////////////////////////
//
// Declare a delegate which is a mapping
// to function pointer expected by
// ListOfSquares method....
//
//
public delegate long CallBack( int i );
////////////////////////////////////////
//
// This method will be called from C++
//
//
public static long SpitConsole(int i ) {
Console.WriteLine( "Printing from C# {0}",i*i);
return i*i;
}
#if MAC_OS_X
//MONO
[DllImport ("./libMonoMac.so")]
private static extern int Add (int a, int b);
[DllImport ("./libMonoMac.so")]
private static extern long ListOfSquares ( CallBack a );
[DllImport ("./libMonoMac.so")]
private static extern bool StringCopy( StringBuilder dest , String src );
[DllImport ("./libMonoMac.so")]
private static extern bool PutEventData( ref EventData r );
#elif GNU_LINUX // MONO
[DllImport ("./libMonoLinux.so")]
private static extern int Add (int a, int b);
[DllImport ("./libMonoLinux.so")]
private static extern long ListOfSquares ( CallBack a );
[DllImport ("./libMonoLinux.so")]
private static extern bool StringCopy( StringBuilder dest , String src );
[DllImport ("./libMonoLinux.so")]
private static extern bool PutEventData( ref EventData r );
#else
// WINDOWS , MS C#
[DllImport ("libMonoWindows.dll")]
private static extern int Add (int a, int b);
[DllImport ("libMonoWindows.dll")]
private static extern long ListOfSquares ( CallBack a );
[DllImport ("libMonoWindows.dll")]
private static extern bool StringCopy( StringBuilder dest , String src );
[DllImport ("libMonoWindows.dll")]
private static extern bool PutEventData( ref EventData r );
#endif
public static void Main()
{
////////////////////////////////////////////////////
//
// Call the Add method from the DLL
//
Console.WriteLine("Hello DevCon 2010....{0}",Add(2,3));
///////////////////////////////////////////
//
// Call StringCopy
StringBuilder sb = new StringBuilder(256);
StringCopy(sb,"Hello World...");
Console.WriteLine(sb.ToString());
///////////////////////////////////////////////////
//
// This demonstrates how to pass structure to C++
//
EventData rt = new EventData();
rt.I = 13;
rt.Message = "I might be from MONO or Visual C# ........!";
PutEventData(ref rt);
/////////////////////////////
// CallBack Demo
//
ListOfSquares(SpitConsole);
}
}
Happy Coding

