由于歷史原因陋守,很多時候我們的代碼并不完全是使用.NET寫成的檬寂。這時候和以往C++代碼的混合編程就顯得相當重要了踢匣。最近碰到了這樣的問題,將方法簡要記述如下盖淡。
調(diào)用簡單的C++函數(shù)
要在C#代碼中調(diào)用C++函數(shù),大體的思路是這樣的:首先將C++函數(shù)寫成DLL形式的庫凿歼,然后在C#中導(dǎo)入DLL中的函數(shù)進行調(diào)用褪迟。具體的代碼類似這樣:
C++代碼:
按 Ctrl+C 復(fù)制代碼
int StaticElementNumber = 10;
extern "C" AFX_API_EXPORT int GetArrayElementNumber()
{
? ? ? ? return StaticElementNumber;
}
按 Ctrl+C 復(fù)制代碼
C#代碼:
(導(dǎo)入函數(shù)部分冗恨,寫在調(diào)用函數(shù)所在類中)
1 [DllImport("MFCDll.dll")]
2? public static extern int GetArrayElementNumber();
3? int ElementNumber = GetArrayElementNumber();
s其中的細節(jié),比如int和char等數(shù)據(jù)類型在C++和C#中占用的空間不同等等CLR會自動處理味赃。(主要是通過Marshal類自動處理)
這樣的調(diào)用還支持調(diào)試掀抹。打開C#工程的Properties,在Debug選項卡中勾選Enable unmanaged code debugging即可啟用C++代碼調(diào)試心俗。這樣在調(diào)試模式下傲武,調(diào)用這個函數(shù)時可以繼續(xù)按F11跟進函數(shù)內(nèi)部進行調(diào)試。
傳遞GDI對象
一些復(fù)雜的Windows對象可以通過句柄來傳送城榛。比如下面的代碼就將一個GDI+ Bitmap對象轉(zhuǎn)換成GDI句柄進行傳送揪利。
C++代碼(GDI+的聲明,引用等等省略):
按 Ctrl+C 復(fù)制代碼
extern "C" AFX_API_EXPORT HBITMAP GetABitmap(WCHAR *strFileName)
{
? ? ? ? Gdiplus::GdiplusStartupInput gdiplusStartupInput;
? ? ? ? ULONG_PTR? ? ? ? ? gdiplusToken;
? ? ? ? GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
? ? ? ? Bitmap *bitmap = Bitmap::FromFile(strFileName);
? ? ? ? HBITMAP HBitmapToReturn;
? ? ? ? bitmap->GetHBITMAP(NULL, &HBitmapToReturn);
? ? ? ? GdiplusShutdown(gdiplusToken);
? ? ? ? return HBitmapToReturn;
}
按 Ctrl+C 復(fù)制代碼
C#代碼(用戶界面采用WPF狠持,略去相關(guān)聲明和引用):
按 Ctrl+C 復(fù)制代碼
[DllImport("MFCDll.dll")]
public static extern IntPtr GetABitmap([MarshalAs(UnmanagedType.LPWStr)] string strFileName);
private void MenuItemFileOpenOnClicked(object sender, RoutedEventArgs e)
{
? ? OpenFileDialog dialog = new OpenFileDialog();
? ? dialog.Title = "Load an image...";
? ? dialog.Multiselect = false;
? ? if (dialog.ShowDialog() == true)
? ? {
? ? ? ? mainGrid.Children.Clear();
? ? ? ? IntPtr hBitmap = GetABitmap(dialog.FileName);
? ? ? ? Bitmap bitmap = Bitmap.FromHbitmap(hBitmap);
? ? ? ? System.Windows.Controls.Image image = new Windows.Controls.Image();
? ? ? ? image.Source = Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(hBitmap, ro, Int32Rect.Empty,
? ? ? ? Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
? ? ? ? image.Stretch = System.Windows.Media.Stretch.Fill;
? ? ? ? DeleteObject(hBitmap);
? ? ? ? mainGrid.Children.Add(image);
? ? }
}
按 Ctrl+C 復(fù)制代碼
傳遞數(shù)組
傳遞定長數(shù)組很簡單疟位,此處不述。下面的代碼實現(xiàn)變長數(shù)組的傳遞:
C++代碼:
按 Ctrl+C 復(fù)制代碼
int StaticElementNumber = 10;
extern "C" AFX_API_EXPORT bool GetArray(int ElementNumber, double *BaseAddress)
{
? ? if (ElementNumber < StaticElementNumber)
? ? {
? ? ? ? return false;
? ? }
? ? for (int i = 0; i < StaticElementNumber; ++i)
? ? {
? ? ? ? BaseAddress[i] = 1 / ((double)i + 1);
? ? }
? ? return true;
}
extern "C" AFX_API_EXPORT int GetArrayElementNumber()
{
? ? return StaticElementNumber;
}
按 Ctrl+C 復(fù)制代碼
C#代碼:?
按 Ctrl+C 復(fù)制代碼
[DllImport("MFCDll.dll")]
public static extern bool GetArray(int ElementNumber, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] double[] BaseAddress);
private void MenuItemFileGetArrayOnClicked(object sender, RoutedEventArgs e)
{
? ? //Get array data.
? ? int ElementNumber = GetArrayElementNumber();
? ? double[] doubleArray = new double[ElementNumber];
? ? GetArray(ElementNumber, doubleArray);
? ? //Show the data.
? ? mainGrid.Children.Clear();
? ? ListBox listBox = new ListBox();
? ? foreach (double number in doubleArray)
? ? {
? ? ? ? listBox.Items.Add(number);
? ? }
? ? mainGrid.Children.Add(listBox);
}
按 Ctrl+C 復(fù)制代碼
有了這三個功能工坊,一般來說C++代碼復(fù)用到C#平臺上就是比較簡單的事情了献汗。