天天看點

混合語言程式設計:啟用CLR(公共語言運作時編譯)讓C#調用C++混合語言程式設計:啟用CLR(公共語言運作時編譯)讓C#調用C++

混合語言程式設計:啟用CLR(公共語言運作時編譯)讓C#調用C++

前言

關于混合C#和C++的程式設計方式,本人之前寫過一篇部落格(參見混合語言程式設計:C#使用原生的Directx和OpenGL),在之前的部落格中,介紹了在C#的Winform和WPF下使用原生的Direct和OpenGL進行繪圖,主要使用的方式是聲明一個函數為導出函數,然後就可以在C#中使用這個函數。

存在的問題

之前的方式使C#調用C/C++成為可能,但是存在很多缺點,主要表現在以下幾個方面:

  1. 使用

    extern "C" _declspec(dllexport)

    的聲明方式隻能定義C函數,無法直接使用C++的類,功能不夠強大。
  2. 參數傳遞很麻煩,尤其是傳入數組時,經常會出現參數類型錯誤或者數組長度不正确,很不靈活。
  3. 需要寫重複性的代碼,在C#代碼中需要重複聲明C/C++寫的DLL中的函數,如果在C/C++代碼中定義了結構體,還需要在C#中重複聲明,處理參數類型又是一個麻煩的事情。
  4. 需要手動拷貝DLL到C#程式的目錄下,如果忘記拷貝了,程式在運作時會報DLL未找到的錯誤。
  5. 非常不利于調試,無法在C/C++代碼中進行斷點跟蹤調試。同時對C/C++代碼修改編譯後,需要拷貝DLL到C#程式目錄,否則C#程式調用的還是修改之前的DLL。

前段時間開發的一個應用程式中需要控制兩個數采卡(SP Divece 的ADQ和SDR),官方提供了C和C++的驅動,可以使用C/C++對數采卡進行控制。我最開始還是使用了之前聲明導出函數的方式進行開發,用C語言實作,但是随着功能的複雜和代碼的增加,上面一系列問題越來越嚴重。

發現新大陸(公共語言運作時編譯)

在奮鬥解決各種Bug的時候突然在一次搜尋時找到了公共語言運作時編譯。所謂公共語言運作時編譯,就是允許應用程式群組件使用公共語言運作時 (CLR) 中的功能。找到MSDN上的相關文檔:

  1. /clr(公共語言運作時編譯)。
  2. 混合(本機和托管)程式集。
  3. 如何:使用 /clr 編譯 MFC 和 ATL 代碼。

有了公共語言運作時編譯,在C#程式集中就可以引用C++開發的DLL,并且使用C++的類就和使用使用C#類是一樣的,還可以直接斷點調試,以上問題全部解決。

很快,我就把之前用C寫的代碼改寫成了C++的代碼,啟用CLR,并删掉了C#中重複的代碼。

指針問題

使用C++開發就會經常使用到指針,但C#沒有指針(一般情況,其實C#是有指針的,隻不過預設被關閉了)。在C#中要傳遞一個指針至少有兩種方式:

  1. 使用

    stackalloc

    在棧上配置設定記憶體塊,這類似于C的

    malloc

    和C++的

    new

    (當然還是有差別的),詳細資訊可參考stackalloc(C# 參考)。
  2. 使用

    fixed語句

    固定變量的指針,C#中之是以不讓用指針,就是因為由于垃圾回收機制會導緻變量重定位,變量重定位後,之前的指針也就不再指向這個變量了,是以C#在這種情況下是要禁止使用指針。而

    fixed 語句

    禁止垃圾回收器重定位可移動的變量,并在執行該語句期間“固定”此變量。固定變量的位置後就可以使用指針了,詳細資訊可參考fixed 語句(C# 參考)。

需要提醒的是,這兩種方式都需要在不安全的上下文中使用,關于不安全上下文,可參考unsafe(C# 參考)。

結語

本文主要記錄我在做項目中發現的問題、解決問題所使用到相關的技術,有效地解決了C#調用C++的問題。當然,其中還有很多細節并沒有深入研究,可能會存在更好的方式。

繼續閱讀