Dot net framework is profound for coding, features the integrated API with service. However, some people would not be satisfied at its performance for large scale numerical computing.
Essentially, dot net framework is a runtime interpreting virtual machine, it cost CPU resource to explain instructions.
To exploit the convenience of dot.Net combining with efficiency of native instruction, the burden for this goad is to increase the coding complexity. This post is to demonstrate how to reach the purpose.
零.
Create 2 projects
separately, One is for C#, named as CsharpCallC; Another is for C++.( I use VS2005 in here.), named as clibrary. Close the 2 project and place the two project in the same folder.
一.
Open CsharpCallC solution file, and add the clibrary project under this solution:
Set the clibrary project as dll project:
The post-build event should be added some command :
copy /Y "$(SolutionDir)\$(ConfigurationName)\$(ProjectName).dll" "$(SolutionDir)\bin\$(ConfigurationName)\$(ProjectName).dll"
It is, after the build has been done , the C/C++ dll binary would be copyed to the folder which the C# binary would be put after the C# build has been done
二.
For the C# project, setthe build target be x86 ( for VC++ of VS2005 support 32 bits only), and allow unsafe code:
And Set the C# project depends on clibary project.
三.
Change the default C# main class file Program.cs, as Csharp.cs, and the code on the file be :
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace LoadCPPExample
{
public class Demonstration
{
[DllImport("Clibrary")]
public static extern void CallByRefUnmanagedFun(double inVar, ref double outVar);
public static void CallByRefFun(double inVar, ref double refOutVar)
{
CallByRefUnmanagedFun(inVar, ref refOutVar);
}//CallByRefFun
[DllImport("Clibrary")]
public static extern void SetStringValueUnmanagedFun(StringBuilder pStr);
public static void SetStringValue(StringBuilder str)
{
SetStringValueUnmanagedFun(str);
}//CallByRefFun
[DllImport("Clibrary")]
public static extern void ArrayOperationUnmanagedFun(int m, int n,
double[,] matrix);
public static void ArrayFun(int m, int n, double[,] matrix)
{
ArrayOperationUnmanagedFun(m, n, matrix);
}//ArrayFun
public struct arrayStruct
{
public int length;
public IntPtr data;
};
[DllImport("Clibrary")]
public static extern int InitArrayStructUnmanagedFun(
ref arrayStruct refArrayStruct, int len);
public static int InitArrayStruct(ref arrayStruct refArrayStruct, int len)
{
return InitArrayStructUnmanagedFun(ref refArrayStruct, len);
}//InitArrayStruct
[DllImport("Clibrary")]
public static extern void
FreeArrayStructUnmanagedFun(ref arrayStruct refArrayStruct);
public static void FreeArrayStruct(ref arrayStruct refArrayStruct)
{
FreeArrayStructUnmanagedFun(ref refArrayStruct);
}//FreeArrayStruct
public delegate void CSharpCallBack(IntPtr args);
public static void OnCSharpCalled(IntPtr args)
{
unsafe
{
Console.Write(
"C# callback :{0} has been called, args as int = {1}\n",
System.Reflection.MethodBase.GetCurrentMethod().Name,
*((Int32*)args) );
}//unsafe
Console.Write("\n");
}//OnCSharpCalled
[DllImport("Clibrary")]
public static extern int CFunWouldCallCSharpCallBacktUnmanagedFun(
CSharpCallBack OnCSharpCalled);
public static void
CFunWouldCallCSharpCallBack(CSharpCallBack OnCSharpCalled)
{
CFunWouldCallCSharpCallBacktUnmanagedFun(OnCSharpCalled);
}//CFunWouldCallCSharpCallBack
public static void Main()
{
{
Console.Write("\n");
double inVar = 5.0;
double outVar = 0.0;
CallByRefFun(inVar, ref outVar);
Console.Write("invar = {0}, outvar = {1}\n", inVar, outVar);
}
{
Console.WriteLine("");
StringBuilder str;
str = new StringBuilder(256);
SetStringValue(str);
Console.Write("str = {0}\n", str);
}
{
Console.Write("\n");
int m = 2;
int n = 3;
double[,] matrix;
matrix = new double[m, n];
ArrayOperationUnmanagedFun(m, n, matrix);
Console.Write("matrix:\n");
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
Console.Write("{0}\t", matrix[i, j]);
}/*for j*/
Console.Write("\n");
}/*for i*/
}
{
Console.Write("\n");
int len = 5;
arrayStruct charArray = new arrayStruct();
InitArrayStruct(ref charArray, len);
Console.WriteLine("InitArray:");
unsafe
{
byte* data;
data = (byte*)charArray.data;
for (int i = 0; i < len; i++)
Console.Write("{0}\t", data[i]);
}
//byte[] data = new byte[len];
//Marshal.Copy(charArray.data, data, 0, len);
//for (int i = 0; i < len; i++)
// Console.Write("{0}\t", data[i]);
Console.Write("\n");
FreeArrayStruct(ref charArray);
Console.WriteLine("");
}
{
CFunWouldCallCSharpCallBack(OnCSharpCalled);
Console.WriteLine("");
}
Console.ReadKey();
}//Main
}//class Demonstration
}//namespace LoadCPPExample
四.
Add a file clibrary.cpp under the project clibrary, the code in it be :
#include <stdlib.h>
#include <string.h>
#define UNMANAGED_CALL __stdcall
#define UNMANAGED_EXPORT __declspec(dllexport)
#ifdef __cplusplus
extern "C"{
#endif
typedef void( UNMANAGED_CALL *CSharpCallbackFun)(void* pArgs);
UNMANAGED_EXPORT void UNMANAGED_CALL
CallByRefUnmanagedFun(double, double*);
UNMANAGED_EXPORT void UNMANAGED_CALL
SetStringValueUnmanagedFun(char *pStr);
UNMANAGED_EXPORT void UNMANAGED_CALL
ArrayOperationUnmanagedFun(int m, int n, double *pMatrix);
struct arrayStruct;
UNMANAGED_EXPORT int UNMANAGED_CALL
InitArrayStructUnmanagedFun( arrayStruct *pArrayStruct, int len);
UNMANAGED_EXPORT void UNMANAGED_CALL
FreeArrayStructUnmanagedFun(arrayStruct *pArrayStruct);
UNMANAGED_EXPORT void UNMANAGED_CALL
CFunWouldCallCSharpCallBacktUnmanagedFun(
void(UNMANAGED_CALL *pCallbackFun)(void* pArgs) );
#ifdef __cplusplus
}
#endif
UNMANAGED_EXPORT void UNMANAGED_CALL CallByRefUnmanagedFun(double in, double *out)
{
*out = in;
}/*CallByRefUnmanagedFun*/
UNMANAGED_EXPORT void UNMANAGED_CALL
SetStringValueUnmanagedFun(char *pStr)
{
strncpy(pStr, "it is a string", 256);
}/*SetStringValueUnmanagedFun*/
UNMANAGED_EXPORT void UNMANAGED_CALL
ArrayOperationUnmanagedFun(int m, int n, double *pMatrix)
{
int i, j;
double value;
value = 0.0;
for(i = 0;i < m; i++){
for(j = 0; j< n; j++){
*(pMatrix + n*i + j) = value;
value += 1.0;
}/*for j*/
}/*for i*/
}/*ArrayFunUnmanagedFun*/
struct arrayStruct
{
int length;
unsigned char *pData;
};
UNMANAGED_EXPORT int UNMANAGED_CALL
InitArrayStructUnmanagedFun( arrayStruct *pArrayStruct, int len)
{
int i;
pArrayStruct->length = len;
pArrayStruct->pData = (unsigned char*)malloc(len*sizeof(unsigned char));
if(NULL == pArrayStruct->pData)
{
pArrayStruct->length = 0;
return -1;
}
for(int i = 0; i< len ; i++)
pArrayStruct->pData[i] = (unsigned char)(i%256);
return 0;
}/*InitArrayStructUnmanagedFun*/
UNMANAGED_EXPORT void UNMANAGED_CALL
FreeArrayStructUnmanagedFun(arrayStruct *pArrayStruct)
{
if(NULL == pArrayStruct->pData)
return;
free(pArrayStruct->pData); pArrayStruct->pData = NULL;
pArrayStruct->length = 0;
}/*FreeArrayStructUnmanagedFun*/
UNMANAGED_EXPORT void UNMANAGED_CALL
CFunWouldCallCSharpCallBacktUnmanagedFun(
void(UNMANAGED_CALL *pCallbackFun)(void* pArgs) )
{
int number;
number = 12345;
pCallbackFun(&number);
}/*CFunWouldCallCSharpCallBacktUnmanagedFun*/
Though the file be C++ file (VS would use C++ compiler to build this file automatically), but the code is written in strict C89 standard. You could change the extension name frome .cpp to c, there is no different at all.
you could found the console has been printed some thing :
invar = 5, outvar = 5
str = it is a string
matrix:
0 1 2
3 4 5
InitArray:
0 1 2 3 4
C## callback :OnCSharpCalled has been called, args as int = 12345
五.
Summary in here :
The
knack for C# calling C/C++ be :
0. The target machine and
output foldershould be set as the same for C/C++ and C#.
1. As common dynamical linking library manufacturing, the functions which would be exported should be denoted as __declspec(dllexport), and extern "C".
2. The C/C++ function should be declared as stdcall function to satisfy dot net protocol. thus, it is forbidden to call a c function be
variadic(
variable number of arguments).
3. In C#, the C/C++ functions should be declaired as public static extern functions, and there should be denotions [DllImport("DLLFileName")] to indicate what dll file the function be.
This article has referred to this one, an Numerical Algorithms Group's pdf file.