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 folder should 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.
沒有留言:
張貼留言