VS2017編寫純C庫以及使用C#呼叫C庫方法
原博主部落格地址:https://blog.csdn.net/qq21497936
本文章部落格地址:https://blog.csdn.net/qq21497936/article/details/83825098
VS2017編寫純C庫以及使用C#呼叫C庫方法
Demo原始碼下載
https://download.csdn.net/download/qq21497936/10770528
建立C庫
使用VS2017建立Visual C++ Dll空專案
開啟VS2017建立Visual C++桌面嚮導,如下圖:
點選確認後,開始嚮導建立工程,如下圖:
點選“確認”,工程目錄,如下圖:
建立庫原始碼,並生成C庫
新增標頭檔案(cDllDemo.h)與原始檔(cDllDemo.cpp)
定義變數和函式巨集定義
實現函式原始碼
編譯生成動態庫
添加回調函式
C庫標頭檔案新增(回撥函式的全域性變數指標和設定回撥函式的函式)
C庫原始檔新增
解決被呼叫時可能無法檢視到printf列印資訊
winform以及wpf使用C庫
建立wpf工程(winform工程呼叫也是一樣)
設定依賴項,為了每次執行該測試應用之前,先編譯生成對應的dll,方式dll修改未更新,如下圖:
填入測試程式碼
執行時出現如下報錯,呼叫不帶輸入引數的不報錯,輸入引數的簽名對不上(就是函式定義);
此時我們修改c#呼叫方式,如下圖:
執行結果:
使用C庫中的全域性變數
在c中把全域性變數的讀寫封裝成函式,c#通過P/Invoke來呼叫函式(理解為set和get),修改c庫標頭檔案內容如下:
原始檔如下:
修改wpf程式如下:
執行結果如下:
使用C庫中的回撥函式
首先,在C庫標頭檔案和原始檔中定義回撥函式全域性變數和回撥函式,如下圖:
在c#中回撥步驟:1定義委託->2引入C庫函式->3定義靜態委託函式->4定義委託變數->5設定委託
在C#中若出現直接掛掉(當前專案中,若當機無異常或者無已停止執行,目前所知都是呼叫的C庫掛掉的,從C庫找原因),特別注意委託函式需要加上呼叫的方式,是Cdecl不是StdDecl,如下圖:
如果不寫該項,則表示委託定義預設為StdDecl,讀者可自行嘗試,會跑完會後會直接掛掉,示意如下圖:
理解[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- UnmanagedFunctionPointer:表示動態使用未託管的dll函式指標;
- CallingConvention.Cdecl:C呼叫約定(即用__cdecl關鍵字說明)按從右至左的順序壓引數入棧,由呼叫者把引數彈出棧。對於傳送引數的記憶體棧是由呼叫者來維護的(正因為如此,實現可變引數的函式只能使用該呼叫約定)。另外,在函式名修飾約定方面也有所不同。_cdecl是C和C++程式的預設呼叫方式。每一個呼叫它的函式都包含清空堆疊的程式碼,所以產生的可執行檔案大小會比呼叫_stdcall函式的大。函式採用從右到左的壓棧方式。VC將函式編譯後會在函式名前面加上下劃線字首,是MFC預設呼叫約定;
- CallingConvention.StdDecl:__stdcall呼叫約定相當於16位動態庫中經常使用的PASCAL呼叫約定。在32位的VC++5.0中PASCAL呼叫約定不再被支援(實際上它已被定義為__stdcall。除了__pascal外,__fortran和__syscall也不被支援),取而代之的是__stdcall呼叫約定。兩者實質上是一致的,即函式的引數自右向左通過棧傳遞,被呼叫的函式在返回前清理傳送引數的記憶體棧,但不同的是函式名的修飾部分(關於函式名的修飾部分在後面將詳細說明)。_stdcall是Pascal程式的預設呼叫方式,通常用於Win32Api中,函式採用從右到左的壓棧方式,自己在退出時清空堆疊。VC將函式編譯後會在函式名前面加上下劃線字首,在函式名後加上"@"和引數的位元組數;
c庫列印資訊問題
C庫新增列印語句
執行的程式碼
關閉應用後打印出來:
解決被呼叫時可能無法檢視到printf列印資訊
需要重定向輸出,使用setbuf函式,如下圖:
不能在執行時,每次呼叫,所以我們優化一下,定義一個初始化函式,修改庫的標頭檔案和原始檔如下:
原博主部落格地址:https://blog.csdn.net/qq21497936
本文章部落格地址:https://blog.csdn.net/qq21497936/article/details/83825098