東坡下載:內(nèi)容最豐富最安全的下載站!

首頁編程開發(fā)VC(VC++) → C++和C#之間互相調(diào)用經(jīng)驗(yàn)詳談

C++和C#之間互相調(diào)用經(jīng)驗(yàn)詳談

相關(guān)文章發(fā)表評論 來源:本站時(shí)間:2011/4/23 6:27:38字體大。A-A+

更多

作者:專題點(diǎn)擊:2007次評論:0次標(biāo)簽: c語言

先說說程序大概組織邏輯。主程序有一套公用接口(其實(shí)就是純虛類),在加載DLL時(shí)候?qū)⒋私涌趥鞯紻LL中,這樣子模塊在需要的時(shí)候就可以調(diào)用父的邏輯了,至于父調(diào)子,那就更簡單了,主程序有一個(gè)純虛類,子模塊都繼承此接口,并進(jìn)行重寫,主程序按照一定的順序分別調(diào)用,這樣父與子的邏輯交互就完成了,這些對都是C++程序來說,這當(dāng)然沒問題,F(xiàn)在問題是,要嵌入.NET的類庫,由此引發(fā)一系列問題。。。。。
軟件是以C++為父,DLL作為子的項(xiàng)目。
開發(fā)環(huán)境:WIN7 64BIT+VS2010+MFC+ATL+COM。
.NET環(huán)境下先以C#為例,其他的大部分一樣下,不排除做一些簡單或者復(fù)雜的修改。
下面正式開始把。
1. 動態(tài)加載 即父調(diào)子。
COM確實(shí)是好東西(他的褒與貶我們無作評論),她的語言無關(guān)性,不僅是我們實(shí)現(xiàn)動態(tài)加載的關(guān)鍵,更是實(shí)現(xiàn)加載其他.NET類庫的核心。如VB.NET。有了她,才是這一切皆有可能。
由于.NET下的類庫(DLL),和傳統(tǒng)的WIN DLL 不太一樣,畢竟托管的東西。她一些函數(shù)對外是不可見的,但對COM可見。因?yàn)槲覀兙鸵訡OM方式定義一套接口,并把此接口當(dāng)成普通C++的純虛接口,來完成父到子的調(diào)用。
這一點(diǎn)不論在理論上、代碼上都比較簡單,而且網(wǎng)上大多也是這樣子,所以我們直接上代碼。
如下為COM接口定義。
[ComVisible(true),
Guid("B86D71F4-FE07-4B60-8246-F5AE283ED2A3"),
InterfaceType(ComInterfaceType.InterfaceIsDual)
]
public interface IHMI
{
[PreserveSig, DispId(1)]
void OnCreate(int a);
[PreserveSig, DispId(2)]
void SetRect(int left, int top, int width, int height);
//其他接類似
}
[ ComVisible(true),
ClassInterface(ClassInterfaceType.AutoDual),
ProgId("xxxxxxx.xxxxxxx") //ProgId 主程序根據(jù)此,運(yùn)行時(shí)動態(tài)創(chuàng)建。
]
C#在使用時(shí)要繼承并實(shí)現(xiàn)接口邏輯,如下類似。
public class CustomCOMClient : IHMI
{
public CustomCOMClient()
{
}
[DispId(1)]
public void OnCreate(int a)
{
//邏輯
}
[DispId(2)]
public void SetRect(int left, int top, int width, int height)
{
//邏輯
}
}
當(dāng)然了,在建項(xiàng)目時(shí),項(xiàng)目類型要為類庫。至此類庫部分已經(jīng)完畢。接下來再看看主程序如何加載,以及如何調(diào)用把。
其中在動態(tài)創(chuàng)建時(shí),ProgId是關(guān)鍵。這一部分對搞過COM,在加上ATL的人來說,可能太簡單了,‘可能’這個(gè)詞也許用的不太恰當(dāng),因?yàn)樗皇?amp;lsquo;可能’,她確實(shí)簡單。不信看代碼。
::CoInitialize(NULL);
const OLECHAR lpszProgID[]=OLESTR("xxxxxxx.xxxxxxx"); //ProgID
CComPtr m_NetCustomer;
HRESULT hr = m_NetCustomer.CoCreateInstance(lpszProgID);
if(SUCCEEDED(hr))
{
const LPCOLESTR szMember=OLESTR("OnCreate");
VARIANT v;
v.vt = VT_I4; v.lVal = 1024;
hr = m_NetCustomer.Invoke1(szMember,&v);
if(SUCCEEDED(hr))
{
}
}
::CoUninitialize();
怎么樣?沒有撒謊把,幾行代碼就把創(chuàng)建、調(diào)用搞定了。
郁悶,從C++拷出來代碼沒有格式,還的手工加。。。。
2. 回調(diào) 即子調(diào)父。
主程序肯定按照自己的邏輯順序依次調(diào)用子模塊的接口,如先創(chuàng)建、子的相關(guān)邏輯、最后銷毀。如果說在實(shí)際運(yùn)用中,子模塊完全不會在調(diào)用父的相關(guān)功能,那么此時(shí)框架已經(jīng)完全實(shí)現(xiàn)了,我們之前做的工作就是。難道不是嗎?,但應(yīng)用程序往往也有父與子相互調(diào)用,下面就來看看,子如何回調(diào)父的功能把
前面也說過,子調(diào)父往往是這樣,從父身上分離出部分代碼,重新封裝一個(gè)dll,由子靜態(tài)綁定,這步最簡單、最方便。不過這顯然不是正道,讓人覺得別扭。
同時(shí)維護(hù)兩份相同功能代碼? 也許你會說,主程序從此也可以調(diào)用DLL啊,那不就一致了,你要真這樣說,我的回答是,“我只是在說明問題,不涉及到架構(gòu)問題”
還有每個(gè)子模塊都靜態(tài)綁定這個(gè)DLL?
還有你在分離這個(gè)DLL時(shí),如果依賴主程序太多,你怎么辦?
還有你能保證分離后的穩(wěn)定性嗎?回帶來其他的問題嗎?
還有你僅僅是為了滿足功能,才這樣做的?
你覺得這樣看著順眼嗎?
等等。反正我覺得是古怪之急。
接下來就要需找其他替代方案了。
先考慮下在C++中這一部分是如何實(shí)現(xiàn)的把。 父傳給子一個(gè)虛接口(虛類),子在適當(dāng)?shù)臅r(shí)候調(diào)用。僅此而已。讓我們把調(diào)用函數(shù)想的深入一點(diǎn)。直接看匯編代碼把。
看代碼之前,還要先簡單說一下函數(shù)調(diào)用相關(guān)信息。在匯編層調(diào)用一個(gè)函數(shù)無非也就是JMP、CALL 之類的指令,若函數(shù)還有參數(shù)就是一些PUSH指令。好了知道這些就足夠了,下面看看在VC中的偽代碼。
__asm
{//類虛函數(shù)的匯編模擬調(diào)用,函數(shù)無參數(shù)、無返回值。
mov eax,xxxxx //存放函數(shù)地址
mov ecx,xxxxx //this指針
call eax //調(diào)用
}
這樣調(diào)用就完成了,其實(shí)真正的調(diào)用也如此,只不過指令多幾條而已。因?yàn)樗玫侥承┬畔ⅰ?br/>好了,如果說.NET支持內(nèi)斂匯編,那我們完全可以自己模擬虛函數(shù)調(diào)用,不用在封裝什么DLL,這所有的一切都可以搞定,但可惜的時(shí),常規(guī)下內(nèi)斂匯編是不支持的。不錯(cuò),我說的是常規(guī),那非常規(guī)呢?答案是肯定的。
關(guān)于內(nèi)斂匯編網(wǎng)上也是一大片,底層思想是,在內(nèi)存開辟一段空間,并放入相應(yīng)指令,到時(shí)侯執(zhí)行這一部分邏輯即可,這樣就可以完成內(nèi)斂匯編了。
其中網(wǎng)上有一個(gè)封裝好的DLL(AsmClassLibrary.dll),提供接口編寫匯編代碼,用Reflector 查看了發(fā)現(xiàn)其最后執(zhí)行采用遠(yuǎn)程線程注入方式,對于嵌入一兩個(gè)模塊的,可以這樣做,但如果模塊很多的話,畢竟注入涉及到安全的問題,這一點(diǎn)不太好,當(dāng)然這也太另類了,我可不想應(yīng)用程序到處以這種方式來執(zhí)行。
所以我們采用Marshal.GetDelegateForFunctionPointer方式。
因?yàn)閺牡讓由现v,是不分什么語言編寫,只認(rèn)機(jī)器指令的,因此只要我們模擬的合理、正確,這一點(diǎn)是沒有問題的。
好了,現(xiàn)在我們目標(biāo)很明確,用內(nèi)斂方式在C#模擬虛函數(shù)的調(diào)用。
在給出代碼之前,也先說下思路。
根據(jù)之前所講以及常規(guī)知識,以下幾點(diǎn)是必須的。
A 類對象指針,因?yàn)槲覀円獙⒋酥到oECX。
B 成員函數(shù)地址,當(dāng)然了,我們要CALL嘛。
C 參數(shù),這值是在C#中使用的。
這就是主要內(nèi)容,實(shí)現(xiàn)他們方式有很多種,以下是我的方案。
因?yàn)榻涌跁芏,因此我將this指針、函數(shù)地址都放到數(shù)組中,然后在傳遞給C#中,其實(shí)按道理說,只傳遞一個(gè)this指針就夠了,其他部分應(yīng)該在C#中實(shí)現(xiàn),但操作指針C++中比較簡便,所以這部分代碼就在C++中做了。
得到this指針 太簡單啦,根據(jù)虛表布局得到其地址也很簡單。如下。
接口定義如下。
class CInterface
{
public:
virtual void test1( LPSTR p)
virtual void test2();
virtual void test3( int a);
};
得到this指針及成員函數(shù)地址。
CInterface *pInterface = new CInterface;
DWORD base_proc = (*((DWORD *)(pInterface))); //虛表指針
DWORD f1 = *(( DWORD *)base_proc); //第1個(gè)
DWORD f2 = *(( DWORD *)(base_proc + 4)); //第2個(gè)
DWORD f3 = *(( DWORD *)(base_proc + 8)); //第三個(gè)
到時(shí)將值賦值到SAFEARRAY 安全數(shù)組中,在傳遞到C#中。
看看在C#中時(shí)如何使用的把。當(dāng)然這一部分的內(nèi)斂、委托、開辟內(nèi)存、托管到非托管轉(zhuǎn)換時(shí)少不了的,老規(guī)矩,看代碼把。
先定義委托和內(nèi)斂。
//委托 參數(shù)分別為 this指針 成員函數(shù)地址 參數(shù)
delegate void testcall(int pthis, int pfun, int param);
byte[] codetest = {
// 0xCC,
0x8B, 0x5C, 0x24, 0x0C, //mov ebx,[esp+0Ch] 第三個(gè)參數(shù) @@
0x8B, 0x44, 0x24, 0x08, //mov eax,[esp+08h] 函數(shù)地址
0x8B, 0x4C, 0x24, 0x04, //mov ecx,[esp+04h] this 指針
0x53, //push ebx 參數(shù)入棧 @@
0xFF, 0xD0, //call eax
0xC3 // ret
};
書寫內(nèi)斂匯編當(dāng)然可以考研我們的功底啦,看看你知道不知道底層是如何實(shí)現(xiàn)的、如何入棧、出棧、傳值、傳指針、傳引用、堆棧平衡等。還有一點(diǎn),書寫匯編雖容易,但是機(jī)器指令我們并不都知道,山人自有妙計(jì),匯編代碼貼到VC中,ALT+8看反匯編,在拷貝回來即可。
以上代碼中,完成接口第三個(gè)函數(shù)調(diào)用,帶有一個(gè)整形參數(shù),并且傳值。
注釋掉@@部分完成接口第二個(gè)函數(shù)調(diào)用,無參數(shù)。
為了簡便都寫在一個(gè)里面,實(shí)際運(yùn)用中,你可以按照不同格式分開。
接下來看看如何調(diào)用,,主要代碼如下。
VirtualAlloc。。。。。。之前肯定得先開辟內(nèi)存啊
Marshal.Copy(codetest, 0, handle, codetest.Length);
testcall Customer = Marshal.GetDelegateForFunctionPointer(handle, typeof(testcall)) as testcall;
int bb = 22;
Customer (fun[0], fun[4], bb);
不錯(cuò),這就是子模塊調(diào)用父相關(guān)邏輯的主要實(shí)現(xiàn)。
3. 后話
這就是相互調(diào)用的所有部分嗎?這次答案是否定,實(shí)際上遠(yuǎn)遠(yuǎn)不至于此,我們此次實(shí)現(xiàn)的,只是最最基本的部分,尤其在參數(shù)上,我們用的最簡單的類型 int,實(shí)際使用中,對于兩者之間都存在的基本類型,還好說一點(diǎn),當(dāng)涉及到字符串、數(shù)組、結(jié)構(gòu)體等這些類型時(shí),真的會讓你很麻煩的,尤其是字符串,兩邊還不一樣。。。。。
其中對參數(shù)類型來說,我們用的是傳值方式,直接將值push,對于引用或者指針要把其地址push,就可以實(shí)現(xiàn)了,當(dāng)然還是針對最基本的類型來說的。
對于字符串參數(shù)的,我用全局函數(shù)實(shí)現(xiàn)了一個(gè)接口(具體的可以看代碼),這樣其中大部分轉(zhuǎn)換操作,對我們就透明了,為何不自己搞?我有時(shí)間在補(bǔ)充進(jìn)去把,這些就留給你們了,同樣你們搞出來之后要告訴我啊,這里給大家一個(gè)建議,處理字符串時(shí),在C#中最好使用char數(shù)組,但在書寫內(nèi)斂匯編時(shí)要注意,數(shù)組前面可有數(shù)組的大小,要偏移過去。
。。。。
。。。。
等把這一切都搞定之后,動態(tài)創(chuàng)建、嵌入VB的、C#的、WPF的以及她3D部分、硬件加速部分。。。。。。。。。
不錯(cuò),如此看來,現(xiàn)在才剛剛開始。。。。。。。。。。。。。
希望能給大家起到一個(gè)拋磚引玉作用。
最后附一個(gè)類型轉(zhuǎn)換的帖,供使用參考,類型轉(zhuǎn)換我就不啰嗦了。
http://topic.csdn.net/u/20090225/15/a6bc50ad-9721-4749-b189-dc4a4bc045a1.html
再附效果圖一張,圖中部分為嵌入C#的類型。

為了嵌入到父窗口上,使用了API SetParent 并且我有建了一個(gè)項(xiàng)目,就是封裝一些常用功能,具體看代碼把。

  • c語言學(xué)習(xí)app大全
  • c語言入門教程大全
  • C語言編程軟件下載
c語言學(xué)習(xí)app大全
(15)c語言學(xué)習(xí)app大全

C語言是一款編程的語言,很多軟件都是使用c語言編輯的,學(xué)好了c語言,以后找高新工作非常好找,在手機(jī)中安裝c語音學(xué)習(xí)軟件可以隨時(shí)利用空閑時(shí)間進(jìn)行學(xué)習(xí),cc語言學(xué)習(xí)app大全包含了豐富的學(xué)習(xí)軟件,從入門到精通的知識,基礎(chǔ)語法,視頻教程,二級考試題目都有涵蓋。

...更多>>
  • 菜鳥學(xué)C語言手機(jī)版1.0.0 安卓版

    04-21 / 5.0M

    推薦理由:菜鳥學(xué)C語言app是一款專業(yè)的C語言學(xué)習(xí)應(yīng)用,該平臺為用戶提供大量的C語言相關(guān)的知識和習(xí)題、答案,軟件包含
  • C語言英才寶典1.6.3 安卓手機(jī)版

    04-12 / 4.3M

    推薦理由:學(xué)習(xí)C語言需要系統(tǒng)的提供一些精華,C語言英才寶典集合多位名家經(jīng)典內(nèi)容,經(jīng)過整合發(fā)布的軟件,軟件完全免費(fèi)
  • C語言學(xué)習(xí)寶典4.7.5 安卓版

    05-04 / 12.1M

    推薦理由:C語言學(xué)習(xí)寶典是一款含C語言學(xué)習(xí)各階段知識學(xué)習(xí)軟件,為你包含了C語言課程的全部內(nèi)容,幫助你快速學(xué)習(xí)C語言
  • 計(jì)算機(jī)二級c語言app2.2安卓版

    09-09 / 15.2M

    推薦理由:馬上就是全國計(jì)算機(jī)等級考試的秋季考試時(shí)間了,大家準(zhǔn)備好了沒有,小編為您帶來的最新的計(jì)算機(jī)二級c語言app
  • 計(jì)算機(jī)二級C語言掌上通2.5.7 安卓最

    09-08 / 14.7M

    推薦理由:計(jì)算機(jī)二級C語言是很多大學(xué)計(jì)算機(jī)系的朋友都是需要考過的,那么現(xiàn)在小編就來教教你怎么才可以更好的一次性就
  • C語言入門神器2.9 安卓最新版

    08-18 / 9.2M

    推薦理由:作為計(jì)算機(jī)語言中非常重要的一門語言,各種IT行業(yè)的人員都需要學(xué)習(xí)這門語言,C語言入門神器為大家提供了詳細(xì)
c語言入門教程大全
(14)c語言入門教程大全

c語言在編程中是很多的程序員都是需要學(xué)習(xí)的,那么現(xiàn)在就可以試試本站為你收集到最新的c語言入門教程大全,這里面包含了各種最新的c語言入門視頻教程,還有很多的c語言學(xué)習(xí)軟件,有在學(xué)習(xí)c語言的用戶都是可以來免費(fèi)的下載的!

...更多>>
C語言編程軟件下載
(6)C語言編程軟件下載

C語言是計(jì)算機(jī)語言的基礎(chǔ)語言,學(xué)會了C語言,再去學(xué)習(xí)其它的語言就要簡單的多了!那么隨著想學(xué)習(xí)C語言的人越來越多了,如何學(xué)習(xí)C語言,學(xué)習(xí)C語言要用到那些軟件都是新手比較關(guān)心的問題了!今天本站給大家準(zhǔn)備了一些C語言編程相關(guān)的軟件供大家來參考,覺得自己有需要,或者是想找些C語言編程軟件的朋友都可以來本站看看有沒有你需要的軟件!

...更多>>

相關(guān)評論

閱讀本文后您有什么感想? 已有 人給出評價(jià)!

  • 2791 喜歡喜歡
  • 2101 頂
  • 800 難過難過
  • 1219 囧
  • 4049 圍觀圍觀
  • 5602 無聊無聊
熱門評論
最新評論
發(fā)表評論 查看所有評論(0)
昵稱:
表情: 高興 可 汗 我不要 害羞 好 下下下 送花 屎 親親
字?jǐn)?shù): 0/500 (您的評論需要經(jīng)過審核才能顯示)