ATLによるコンポーネントの登録サポート


ATLによるコンポーネントの登録サポート
[email protected]
Revision: 1.0 Date: 2005/12/10
前述したように、登録を必要としないCOMコンポーネントが必要な場合があります.ATLはこの状況を完全にサポートしています.この場合のCOMコンポーネントは、作成方法が特殊である以外は(ATL::CComObjectの提供する静的方法CreateInstanceで作成)、普通のC++クラスと変わりません.一方、このようなコンポーネントが登録を再要求される可能性もありますが、どのようにしてこのようなサポートに参加するのでしょうか.
まず、このコンポーネントにGUIDを割り当て、使用するスレッドモデル、progidなどの情報を指定する必要があります.VC++のいわゆる属性化プログラミングでは、次のようになります.

[coclass, progid("MyCoClass.coclass.1"), vi_progid("MyCoClass.coclass"), 
appobject, uuid("9E66A294-4365-11D2-A997-00C04FA37DDB")]
class CMyClass ... 

	

ステップ2では、このコンポーネントクラスにOBJECT_を追加します.ENTRY_AUTOマクロ.CoCreateInstance関数の基本的な流れは、CLSIDに従ってレジストリにコンポーネントが存在するCOMモジュールのパスを見つけ、それをロードし、エクスポートされたDllGetClassObjectを呼び出してコンポーネントのファクトリオブジェクトを取得し、ファクトリオブジェクトでコンポーネントインスタンスを作成することです(DLL形式のCOMモジュールでは、以下同様).ATLにおいてこの導出されたDllGetClassObjectは、CAtldellModuletクラスによって実現される.このクラスには、いわゆるObject Mapが格納されており、そのうちの各項目は1つのコンポーネントクラスに対応し、keyはコンポーネントクラスのguid、valueはコンポーネントクラスの関連情報であり、そのコンポーネントクラスの工場オブジェクトを取得する関数ポインタ、そのコンポーネントクラスの登録情報を更新する関数ポインタなどが含まれる.エクスポートされたDllGetClassObjectが呼び出されると、CAtlDllModuletは、そのObject Mapで要求されたコンポーネントクラスを検索し、対応するコンポーネントファクトリオブジェクトを取得する関数を呼び出す.OBJECT_ENTRY_AUTOマクロとは、指定されたコンポーネントクラスをそのObject Mapに追加することである.
最後に、Registrar Scriptリソースを作成し、コンポーネントクラスにDECLARE_を追加します.REGISTRY_RESOURCEIDマクロ.第2のステップで説明したように、CoCreateInstanceは、regsvr 32プログラムで一般的に書き込まれるレジストリにコンポーネントの登録情報が必要であることを要求する.regsvr 32をサポートするために、DLLモジュールは一般的に2つの関数をエクスポートします:DllRegisterServer/DellUnregisterServer、それぞれ登録と逆登録を実現します.CAtlDllModuletクラスには、この2つの関数が実装されていますが、コンポーネントクラスが提供する登録情報に依存します.エクスポートされたDllRegisterServer/DellUnregisterServerが呼び出されると、CAtlDllModuletはObject Mapの各項目について対応する更新レジストリの関数を呼び出し、その結果、コンポーネントの登録情報をレジストリに書き込みます.OBJECT_ENTRY_AUTOマクロは、コンポーネントクラスの静的関数UpdateRegistryを、そのコンポーネント登録情報を更新する関数として使用するため、コンポーネントクラスには、DECLARE_REGISTRY_RESOURCEIDマクロは、REGISTRYリソースを識別するresource IDである.このリソースは実際にはRegistrar Scriptであり、BNFの構文でレジストリを更新する操作を記述しています.以下はコンポーネントの例です.

HKCR
{
	ATLAsync.ATLAsync.1 = s 'ATLAsync Class'
	{
		CLSID = s '{012F24D4-35B0-11D0-BF2D-0000E8D0D146}'
		'Insertable'
	}
	ATLAsync.ATLAsync = s 'ATLAsync Class'
	{
		CLSID = s '{012F24D4-35B0-11D0-BF2D-0000E8D0D146}'
		CurVer = s 'ATLAsync.ATLAsync.1'
	}
	NoRemove CLSID
	{
		ForceRemove {012F24D4-35B0-11D0-BF2D-0000E8D0D146} = s 'ATLAsync Class'
		{
			ProgID = s 'ATLAsync.ATLAsync.1'
			VersionIndependentProgID = s 'ATLAsync.ATLAsync'
			InprocServer32 = s '%MODULE%'
			{
				val ThreadingModel = s 'Apartment'
			}
			ForceRemove 'Control'
			ForceRemove 'ToolboxBitmap32' = s '%MODULE%, 1'
			'MiscStatus' = s '0'
			{
			    '1' = s '131473'
			}
			'TypeLib' = s '{012F24C1-35B0-11D0-BF2D-0000E8D0D146}'
			'Version' = s '1.0'
		}
	}
}
	

具体的にレジストリを更新する操作はRegistry Scriptのエンジンが私たちに完成させ、私たちがしなければならないのは規定の文法に従ってレジストリを更新する論理を教えるだけです.