多年來在程序設計領域微軟技術一直引領著每個時代在每一代的技術背後都有相關的動機而這些動機及其實現細節往往是大部分的程序設計課程沒有涉及的但是對於我們理解相關的技術又十分重要本文將對幾種相關技術和隱藏在動機背後的細節做簡要的闡述算是拋磚引玉
COM技術於年首次發布稱得上是微軟技術的一個裡程碑其意義在於使組件編程化得以實現COM技術最初的思想起源於將類做成可重用的二進制組件把類的實現和接口分離以便把類的實現封裝到二進制防火牆的背後而這道防火牆以VPTR和VTBL的形式保證了這個防火牆的不變性……NET技術則在語言層面上支持了基於組件的程序設計相對於COM技術NET技術就是為基於組件的程序設計而生的所以其編碼效率和語言可讀性要高出COM一個等級但是由於年以後的十多年時間裡人們利用基於COM的組件程序設計技術開發了大量的高復雜度高可用性的代碼並且他們運行良好效率極高如果用NET技術重寫這些代碼簡直就是得不償失加之在NET的實現過程中並不是所有的Windows API都被重寫有些功能是NET所不能完成的面對這樣的問題 NET互操作技術應運而生可見需求才是技術的原動力
NET互操作技術主要分為種P/InvokeC++ InteropCOM Interop其中P/Invoke 主要用於調用C庫函數和Windows APIC++ Interop則主要用於Managed C++調用 C++類庫和核心算法庫它甚至允許托管代碼和非托管代碼在同一個文件中 COM Interop主要包括正向的RCW和反向的CCW下面以一個簡單的例子對互操作中比較重要的數據封送進行簡單的介紹
如何封送字符串(P/Invoke方式)
假設非托管代碼定義如下
void _cdecl stringMarshal( const wchar_t* inString wchar_t* outString int buffersize)
{ If(NULL != inString)
{ wcscpy_s(outString buffersize inString)}這段代碼編譯生成的文件名為stringMarshaldll
在托管代碼中其托管定義如下
[DllImport(stringMarshaldllCharSetCharSet = CharSetUnicodeCallingConventionCallingConvention =CallingConventionCdecl)
] public extern static void stringMarshal (string inString StringBuilder outString int bufferSize)這裡有幾點需要注意
在聲明函數時必須要用extern修飾符目的是為了告訴編譯器此函數是外部實現的沒有方法體因此不需要在托管代碼中搜索這個函數
在聲明函數時必須要用static修飾符原因是非托管的DLL導出的非托管方法都是可以直接調用的無需對相關的類進行實例化大部分情況下根本就不存在類
因為非托管代碼中的字符串為wchar_t*類型所以CharSet需要設置為CharSetUnicode
因為非托管代碼的調用方式為_cdecl 所以托管部分的CallingConvention需要設置為CallingConventionCdecl另外這種類型的調用方式是調用方負責處理堆棧所以支持可變類型參數函數例如printf()的互操作
輸入字符串需要封裝為string是因為這個字符串屬於固定字符串互操作過程中不需要變化而輸出字符串則需要封裝為StringBuilder因為這種字符串默認為具有IN/OUT屬性其內容可變而且當字符串經常需要變化時效率高
托管代碼中調用非托管代碼方式如下
private static void TestStringMarshal ()
{ string inString = Wally input test stringint bufferSize = inStringLengthStringBuilder strbd = new StringBuilder(bufferSize)stringMarshal (inString strbd bufferSize + )ConsoleWriteLine(Wally Input string {} inString)ConsoleWriteLine(Wally output string {} strbdToString())}總結
本文簡要的介紹了NET托管代碼和本地非托管代碼的互操作技術並對數據封送的實現細節做了簡單的說明希望對大家的技術提高有所幫助算是拋磚引玉期待大家在這方面寫出更多更好的文章
From:http://tw.wingwit.com/Article/program/net/201311/13285.html