天天看點

.Net環境下COM互操作

原創文章,轉載請注明出處!

接上文:http://www.cnblogs.com/yhlx125/archive/2011/11/22/2258543.html

博文的最後産生了問題:GC.Collect()顯著的釋放了記憶體,難道強制GC清理的效果這麼明顯?産生的記憶體增長不是因為COM對象、Mxd檔案,而是托管的記憶體?

于是産生了這樣的想法:MapClass、MapDocumentClass對象都是.Net托管對象,而非COM對象。事實是否如此呢?

IMapDocument pMapDoc = new MapDocumentClass();

int n = Marshal.ReleaseComObject(pMapDoc);

确實是執行了,傳回值為0,說明正确釋放了COM對象。如果執行下一段代碼則第2句報錯,說明.Net對象不能用Marshal.ReleaseComObject()方法來操作。

1    A pa = new A();
2    int m = Marshal.ReleaseComObject(pa);
3    MessageBox.Show(m.ToString());      

View Code

class A
    {
int a;

public int A1
        {
get { return a; }
set { a = value; }
        }

    }      

于是查找相關資料:學習了如下主題:

1. COM互操作性

2. Primary Interop Assemblies (PIAs,主互操作程式集),http://msdn.microsoft.com/zh-cn/library/aax7sdch.aspx

主互操作程式集是一個由供應商提供的唯一的程式集。它包含用 COM 實作的類型的類型定義(作為中繼資料)。 隻能有一個主互操作程式集,而且該程式集必須由 COM 類型庫的發行者用強名稱簽名。 一個主互操作程式集可以包裝同一類型庫的多個版本。

如果導入為程式集的 COM 類型庫不是由原類型庫的發行者簽名的,該類型庫不能作為主互操作程式集。 隻有類型庫的發行者才能産生真正的主互操作程式集。該程式集将成為用于與基礎 COM 類型進行互操作的正式類型定義單元。

COM 元件的發行者生成主互操作程式集并将它們釋出給開發人員以便在 .NET Framework 應用程式中使用。 對于發行者,本節提供有關産生主互操作程式集的資訊。 對于開發人員,本節描述如何用主互操作程式集程式設計。

3. COM包裝:http://msdn.microsoft.com/zh-cn/library/5dxz80y2.aspx

.Net環境下COM互操作

COM 包裝(COM Wrapper)

運作時提供了包裝類,使托管和非托管用戶端認為它們是在其各自的環境中調用對象。 每當托管用戶端對某個 COM 對象調用方法時,運作時就會建立一個運作時可調用包裝 (RCW)。 RCW 的功能之一是抽取托管和非托管引用機制之間的差異。 運作時還會建立一個 COM 可調用包裝 (CCW) 來逆轉此過程,使 COM 用戶端能夠對 .NET 對象無縫地調用方法。 如下圖所示,調用代碼的性質将确定運作時所建立的包裝類。

使用RCW,.NET客戶程式就可以使用. Net對象而不是COM元件,是以不需要處理COM特性,這是由包裝器來處理的。RCW隐藏了IUnknown接口和IDispatch接口并處理COM對象的引用數。(C#進階程式設計第六版 686頁)

于是問題明了了,IMap pMap = new MapClass();這句代碼使用的MapClass是Esri公司提供的PIAs表現形式,PIAs包含用 COM 實作的類型的類型定義(作為中繼資料)。 MapClass對象本身是.Net對象,實作了對COM對象Map的包裝,即可認為傳遞了Map對象的引用。是以上文末尾産生的問題,調用GC.Collect()顯著的釋放了記憶體是因為釋放了MapClass這個包裝對象,而包裝RCW對象是COM到.Net的橋梁,(資料封送處理是否可以視為産生了資料的副本?)Marshal.ReleaseComObject(pMapDoc);釋放了COM對象但是沒有釋放托管的RCW,是以記憶體要等托管運作時釋放。

(運作時所生成的标準 RCW 或 CCW 将為跨越 COM 和 .NET Framework 之間邊界的調用提供充分的封送處理。)

ReleaseComObject 方法遞減運作庫可調用包裝的引用計數。當引用計數達到零時,運作庫将釋放非托管 COM 對象上的所有引用(COM本身是自計數的)。

4.封送處理http://msdn.microsoft.com/zh-cn/library/9f9f3yxf.aspx

c#