IFileDialogがすでに実装されているか確認する方法
CLSID_FileOpenDialog または CLSID_FileSaveDialog で実際に CoCreateInstance してみて REGDB_E_CLASSNOTREG が返されれば未実装と判断してしまえば良いかと思います。
IFileDialogが実装されていなければ、システムに実装を追加する方法
一般的に以下に挙げる 3 種類方法があります。
1.レジストリに登録する。
インストールされていない前提であれば上記の CLSID を持った DLL を通常の COM と同様にレジストリ登録するのが最も単純で良いかと思います。
2.クラスファクトリを登録する。
CoRegisterClassObject で独自に作成したコンポーネントのクラスファクトリをスレッド毎に登録することでも実現可能です。レジストリに登録されている設定よりも優先されるので、実は一番お勧めしたいのですが、アパートメント毎ではなくスレッド毎に CoRegisterClassObject を呼び出す必要があるので、意外と手間がかかります。DllMain 内では KERNEL32 の処理しか呼んではいけないことになっているので、DLL_THREAD_ATTACH で登録するというのは避けた方が良いかなとは思います。
ドキュメントには記載がありませんが、DLL_THREAD_ATTACH で CoRegisterInitializeSpy で IInitializeSpy をインストールして、IInitializeSpy::PostInitialize メソッドで CoRegisterClassObject するとうまくいくと思います。CoInitialize はウィンドウ作成したりするので、DLL_THREAD_ATTACH 内で使うとハングすることがままありますが、CoRegisterInitializeSpy で遅延させれば回避可能かと思います。
ちょうどスタックオーバーフローで同じ回答を見つけました。
https://stackoverflow.com/questions/24993611/define-a-com-class-that-is-only-createable-from-the-same-exe-where-it-is-registe
スタックオーバーフローの文面ではアパートメント毎にという記載がありますが、CoRegisterClassObject はスレッド毎に必要であったと記憶しています。ただし、今回は GUI を持ったコンポーネントを登録するので、MTA ではないので違いは出ません。
3.API をフックする。
CoGetClassObject、CoCreateInstance、CoCreateInstanceEx をフックして該当の CLSID が指定されている場合に自分で作成したコンポーネント(or クラスファクトリ)を返すようにしてみてください。これはレジストリ登録が不要なので次にお勧めです。 2番の実現性が高くなったのでお勧めとしては3番目にします。
なお、XP を前提としない場合、CoCreateInstanceFromApp もフック対象となります。また、ProgID からの変換が必要である場合、CLSIDFromProgID および CLSIDFromProgIDEx もフック対象となります。今回のファイルダイアログに関しては上記は不要です。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/05/07 11:10
2019/05/07 17:47