忍者ブログ
AMAZON
フリーエリア
最新コメント
広告
インテル製チップセットを搭載し、基本機能の充実、メンテナンス性も向上した高性能なクライアントPC Endeavor AT971 HP Directplus オンラインストア
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

投稿者 : かおん [編集]
久しぶりに、ActiveXを作って署名してアップしたら、丸一日はまってしまった。
実行しても安全として、MFC コントロールにマークするのをてっきりやり忘れてしまっていた事が原因。
忘れない為に、残しておこうということで、

普通に作成したMFC ActiveXは、スクリプトおよび初期化を実行しても安全としてマークされていません。
そのため、セキュリティ レベルが中または高に設定された Internet Explorer でコントロールの実行が出来ません。
そのため、開発者は、DllRegisterServerの関数を変更して スクリプトおよび初期化を実行しても安全として MFC ActiveX コントロールにマークする必要があります。

方法は、以下のとおり
  1. 以下の cathelp.h および cathelp.cpp ファイルをプロジェクトに追加して、ヘルパ関数 CreateComponentCategory および RegisterCLSIDInCategory を実装します。

    Cathelp.h

    #include "comcat.h"

    // Helper function to create a component category and associated
    // description
    HRESULT CreateComponentCategory(CATID catid, WCHAR* catDescription);

    // Helper function to register a CLSID as belonging to a component
    // category
    HRESULT RegisterCLSIDInCategory(REFCLSID clsid, CATID catid);

    Cathelp.cpp

    #include "comcat.h"

    // Helper function to create a component category and associated
    // description
    HRESULT CreateComponentCategory(CATID catid, WCHAR* catDescription)
    {
    ICatRegister* pcr = NULL ;
    HRESULT hr = S_OK ;

    hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr,
    NULL,
    CLSCTX_INPROC_SERVER,
    IID_ICatRegister,
    (void**)&pcr);
    if (FAILED(hr))
    return hr;

    // Make sure the HKCR\Component Categories\{..catid...}
    // key is registered
    CATEGORYINFO catinfo;
    catinfo.catid = catid;
    catinfo.lcid = 0x0409 ; // english

    // Make sure the provided description is not too long.
    // Only copy the first 127 characters if it is
    int len = wcslen(catDescription);
    if (len>127)
    len = 127;
    wcsncpy(catinfo.szDescription, catDescription, len);
    // Make sure the description is null terminated
    catinfo.szDescription[len] = '\0';

    hr = pcr->RegisterCategories(1, &catinfo);
    pcr->Release();

    return hr;
    }

    // Helper function to register a CLSID as belonging to a component
    // category
    HRESULT RegisterCLSIDInCategory(REFCLSID clsid, CATID catid)
    {
    // Register your component categories information.
    ICatRegister* pcr = NULL ;
    HRESULT hr = S_OK ;
    hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr,
    NULL,
    CLSCTX_INPROC_SERVER,
    IID_ICatRegister,
    (void**)&pcr);
    if (SUCCEEDED(hr))
    {
    // Register this category as being "implemented" by
    // the class.
    CATID rgcatid[1] ;
    rgcatid[0] = catid;
    hr = pcr->RegisterClassImplCategories(clsid, 1, rgcatid);
    }

    if (pcr != NULL)
    pcr->Release();

    return hr;
    }
  2.  DllRegisterServer を変更し、コントロールを安全としてマークします。プロジェクトの .cpp ファイルに DllRegisterServer の実装を配置します。この .cpp ファイルにはいくつかの要素を追加する必要があります。CreateComponentCategory および RegisterCLSIDInCategory を実装するファイルをインクルードします。
    #include "stdafx.h"
    #include "CatHelp.h"  // ← 上記で追加したファイルをincludeする。 

    ※ ~Ctl.cppではなく、プロジェクト名.cpp のファイル。

    安全なコンポーネント カテゴリに関連付けられた GUID を定義します。
    C~~App NEAR theApp; //これが書かれた後に以下のGUIDを追加

    const CATID CATID_SafeForScripting     =
    {0x7dd95801,0x9882,0x11cf,{0x9f,0xa9,0x00,0xaa,0x00,0x6c,0x42,0xc4}};
    const CATID CATID_SafeForInitializing  =     {0x7dd95802,0x9882,0x11cf,{0x9f,0xa9,0x00,0xaa,0x00,0x6c,0x42,0xc4}};
    ※ここで指定されている 0x7dd~というGUIDは、気にせず、ここまま追加しちゃってください。

    コントロールに関連付けられた GUID を定義します。コントロールのメインの .cpp ファイルにある IMPLEMENT_OLECREATE_EX マクロから GUID を参照すると、容易に定義できます。以下のような形式に修正します。
    const GUID CDECL BASED_CODE _ctlid =
    { 0x43bd9e45, 0x328f, 0x11d0,
    { 0xa6, 0xb9, 0x0, 0xaa, 0x0, 0xa7, 0xf, 0xc2 } };
    ※ここで指定するGUIDは、コントロールのメインの.cppにある guidを指定するとなっていますが、要するに、プロジェクトCtl.cppの最初にほうに書かれている以下のソースの部分を探してください。

    //////////////////////////////////
    // クラス ファクトリと guid を初期化します

    IMPLEMENT_OLECREATE_EX(CTestCtrl, "Test.TestCtrl.1",
        0x43bd9e45, 0x328f, 0x11d0, 0xa6, 0xb9, 0x0, 0xaa, 0x0, 0xa7, 0xf, 0xc2)

    CTestCtrl~は、作成したプロジェクトのコントロール名等


    次に追加した関数などを実装する為に、DllRegisterServer 関数を以下のように変更します。

    STDAPI DllRegisterServer(void)
    {
        AFX_MANAGE_STATE(_afxModuleAddrThis);

        if (!AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid))
            return ResultFromScode(SELFREG_E_TYPELIB);

        if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE))
            return ResultFromScode(SELFREG_E_CLASS);

        return NOERROR;
    }

                           

    STDAPI DllRegisterServer(void)
    {
    AFX_MANAGE_STATE(_afxModuleAddrThis);

    if (!AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid))
    return ResultFromScode(SELFREG_E_TYPELIB);

    if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE))
    return ResultFromScode(SELFREG_E_CLASS);

    if (FAILED( CreateComponentCategory(
    CATID_SafeForScripting,
    L"Controls that are safely scriptable") ))
    return ResultFromScode(SELFREG_E_CLASS);

    if (FAILED( CreateComponentCategory(
    CATID_SafeForInitializing,
    L"Controls safely initializable from persistent data") ))
    return ResultFromScode(SELFREG_E_CLASS);

    if (FAILED( RegisterCLSIDInCategory(
    _ctlid, CATID_SafeForScripting) ))
    return ResultFromScode(SELFREG_E_CLASS);

    if (FAILED( RegisterCLSIDInCategory(
    _ctlid, CATID_SafeForInitializing) ))
    return ResultFromScode(SELFREG_E_CLASS);

    return NOERROR;
    }
※参考までに、DllRegisterServer 関数を登録したのだから、削除する時にDllUnregisterServer 関数も変更がいるのでは?と思いきや、以下の理由により、変更しないそうです。
  • 他のコントロールがコンポーネント カテゴリを使用している可能性があるため、コンポーネント カテゴリは削除しない。
  • UnRegisterCLSIDInCategory 関数が定義されてるが、デフォルトでは DllUnregisterServer によってコントロールのエントリがレジストリからすべて削除されるため、コントロールの登録情報からカテゴリを削除しても、ほとんど意味がない。
※また、 コントロールのコンパイルと登録が完了すると、レジストリに以下のエントリが登録されていることがわかります。

HKEY_CLASSES_ROOT\Component
Categories\{7DD95801-9882-11CF-9FA9-00AA006C42C4}

HKEY_CLASSES_ROOT\Component
Categories\{7DD95802-9882-11CF-9FA9-00AA006C42C4}

HKEY_CLASSES_ROOT\CLSID\{"your controls GUID"}\Implemented
Categories\{7DD95801-9882-11CF-9FA9-00AA006C42C4}

HKEY_CLASSES_ROOT\CLSID\{"your controls GUID"}\Implemented
Categories\{7DD95802-9882-11CF-9FA9-00AA006C42C4}
PR
投稿者 : かおん [編集]