Chapter.30

はまり道(3)

2011/9/20
 ・「マーシャリング」を一般的ではないがより的確な表現に変更

1.StandardOleMarshalObject

前回のサンプルでは突然 System.Runtime.InteropServices.StandardOleMarshalObject を使用していますが、これには理由があります。.NET Framework 1.1 を対象にサンプルを作成していた時は System.Windows.Forms.Form クラスに直接 IOleClientSite を実装していましたが、.NET Framework 2.0 から (恐らく CLR のバージョンが同じ以降の .NET Framework のすべてのバージョンにおいて) はこの実装方法では正常に動作しません。前回のサンプルで StandardOleMarshalObject を使用しなければ、IOleClientSite.SaveObject の呼び出しはメインスレッドのアパートメント(STA)ではなくスタブが動作しているアパートメント(MTA)で実行されることになり、この時 OleSave を呼び出すとアパートメントの不一致のためにエラーとなります。

.NET Framework 2.0 で追加された StandardOleMarshalObject はこの動作を抑制しアパートメント外部からの呼び出しを、元のアパートメント (前回のサンプルでは OleCreateOleLoad を呼び出したアパートメント) に固定します。以下、この動作をアパートメント同期化と呼びます。


2.CLR-FTM のバージョン間での動作の差異について

ではなぜ、.NET Framework 1.1 では問題が起こらず、.NET Framework 2.0 では StandardOleMarshalObject の派生クラスで処理しなければならないかというと、それは共通言語ランタイム (CLR) のフリースレッド化マーシャラ (FTM) の仕様変更に原因があります。MSDN ライブラリには CCW は FTM を実装していると記述されていますが、それは CLR が独自に実装したもので COM 標準の FTM とは多少動作が異なります。以下、これを CLR-FTM と呼びます。

.NET Framework のバージョンにより CLR-FTM には次の差異があります。.NET Framework 1.1 の CLR-FTM はインプロセスの呼び出しをアパートメント同期化しますが、アウトプロセスの(マシン間呼び出しを含む)呼び出しはアパートメント同期化しません。.NET Framework 2.0 の CLR-FTM はすべての呼び出しをアパートメント同期化しません。このバージョンによる動作の差異によって、最初に記述した問題が発生します。.NET Framework 2.0 でアウトプロセスの呼び出しをアパートメント同期化するため StandardOleMarshalObject を使用する必要があるのです。

ただし、COM 標準の FTM は .NET Framework 2.0 の動作に近いため、この仕様変更は歓迎するべきところなのですが・・・、当サイトのサンプルは .NET Framework 1.1 の CLR-FTM の動作に拠るところが大きいため、.NET Framework 2.0 への対応をめんどくさく難しくしています。


3.まとめ

.NET Framework 2.0 に StandardOleMarshalObject が追加された理由を推測する助けになれば良いかと思います。が、一般的な開発者にはどうでもいい話ですね。なお、StandardOleMarshalObject を使わなくても IMarshal を直接実装することにより、CLR-FTM の動作を変えることができます。以下に IMarshal を実装し StandardOleMarshalObject を使わなくしたサンプルを提示しておきます。

VB.NETサンプルソース:chap30.vb.lzh (54KB 2009/4/11)
C#サンプルソース:chap30.cs.lzh (47KB 2009/4/11)

逆に .NET Framework 1.1 でも IMarshal を直接実装すれば、.NET Framework 2.0 の動作に近づけることができます。

ILockBytes の解説よりこっちを先に解説してしまいましたが、前章以前の解説もボチボチ書きたいと思います。


前へ
OLE on .NET Frameworkへ
総合トップへ

サンプルで使用しているキーワード
CoGetStandardMarshal ILockBytes IMarshal IOleClientSite IOleObject IPersistStorage IStorage OleCreate OleLoad OleSave StgCreateDocfileOnILockBytes StgIsStorageILockBytes StgOpenStorageOnILockBytes System.Runtime.InteropServices.ComTypes.STATSTG