VC++で ActiveXコンポーネント(OCX)を作ってみよう

・ MFCによるActiveXコンポーネント(OCX)の作成

Visual Basicで使用したり、Internet Explorerで使用するための コンポーネントとして ActiveX コンポーネントがありますが 今まで使いなれたMFCで安易に作成するには、新規作成でCOleControl から派生された CxxxxCtrl クラスに直接コントロールを配置したり イベントハンドラを配置するのは大変なので、ダイアログリソース を作成して、CDialog派生クラスにすべて処理を任せれば簡単です。

このCDialog派生クラス(CyyyyDlgとします)を CxxxxCtrlに配置するには、 通常のモーダルダイアログとして表示するのではなく、CxxxxCtrlクラス上に モードレスダイアログとして表示すればいいことになります。

[CxxxxCtrl.h ヘッダファイル]
class CyyyyDlg;               // クラスのプロトタイプ宣言

class CxxxxCtrl : public COleControl
{
private:
    CyyyyDlg*  m_pMainDlg;    // ダイアログクラスのポインタを
    .....                     // メンバ変数に設定

}

[CxxxxCtrl.cpp インプリメンテーションファイル]
int CxxxxCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    ....
    m_pMainDlg = new CyyyyDlg();
    m_pMainDlg->Create(IDD_YYYYY_DIALOG, this);
    m_pMainDlg->ShowWindow(SW_SHOW);
    ....
}

int CxxxxCtrl::OnDestroy()
{
    ....
    m_pMainDlg->DestroyWindow();
    delete m_pMainDlg;
    ....
}

なお、ダイアログリソースは [チャイルド]、[枠無し] に設定しておきます。 この手法は タブコントロールの中にダイアログを貼り付ける場合にも有効で、 タブの高さの分だけ [Y座標] に値を指定しておきます。
(プロパティシートスタイルの場合は、MFCにお任せですOKです)


(ちょっと一工夫)
ActiveXコントロールのプロパティ、メソッド、イベントは、本来の オートメーションクラスである COleControlの派生クラスでしか扱うことが 出来ません。このため ダイアログクラスを作るときに、CxxxxCtrlクラス へのポインタを変数として保存しておくと便利です。
ダイアログクラス内で、CxxxxCtrl *m_pOleCtrl; として保存しておきます。


・ ActiveXに設定したデザイン時の値を有効にするには

コンポーネントのプロパティとして 変数を宣言しても、このままでは Visual Basicでデザイン時に設定したプロパティの値は反映されません。
これを有効にするには、CxxxxCtrlクラスの関数、DoPropExchange(...) を使用します。具体的には、

void CxxxxCtrl::DoPropExchange(CPropExchange* pPX)
{
    ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
    ColeControl::DoPropExchange(pPX);

// 以下の変数に対する処理を追加
    PX_String(pPX, _T("sUserName"), m_sUserName);
    PX_Long(pPX, _T("iCode"), m_iCode, 0);
    PX_Bool(pPX, _T("bFlag"), m_bFlag, TRUE);
}

となります。なお sUserName が外部プロパティ名称、m_sUserName が 内部での変数名となります。iCode, m_iCode と bFlag, m_bFlag も 同じく外部プロパティ名と内部変数名です。


ActiveXコンポーネントとして作成したコントロールを、 Internet Explorer に配置した場合、[BS]、[↑]、[↓]といった 通常のカーソルコントロールが、ActiveXコンポーネントでは使用 できませんでした。
どうやら ActiveXコンポーネントにキー操作が渡る以前に、 Internet Explorer 側で処理を行っているみたいです。リストボックスの 選択中であっても、[↑]、[↓] キーを押すと、Internet Exploere 内の コンテンツがスクロールしました。
回避方法はまだ見つけておりません。ご存知の方はお教えください m(_ _)m;


・ プロパティページが不要な場合の削除方法 (2001-12-17)

ActiveX control wizard でコンポーネントを作成すると、自動的にプロパティ ページが作成されますが、小さなコンポーネントを作成する場合や、Internet Explorer に配置する場合は、プロパティページが不要な場合があります。
プロパティページの削除方法を簡単に示します。


プロパティページ用のクラスは、CxxxxPropPage に記述されますので、 プロジェクトワークスペース上で関連するファイルを[DEL]キーで削除します。 実際のファイルはプロジェクトを終了した後に削除すればいいでしょう。

続いてプロパティーページのインプリメントが行われている部分を修正します。 具体的には、コントロールクラス CxxxxCtrl内の記述で、

[xxxxCtrl.h] ..... ヘッダファイル
    DECLARE_OLECREATE_EX(CxxxxCtrl)   // クラス ファクトリ と guid
    DECLARE_OLETYPELIB(CxxxxCtrl)     // GetTypeInfo
//  DECLARE_PROPPAGEIDS(CxxxxCtrl)    // プロパティ ページ ID
    DECLARE_OLECTLTYPE(CxxxxCtrl)     // タイプ名とその他のステータス


[xxxxCtrl.cpp] ... インプリメンテーションファイル
#include "xxxxPpg.h"  ---> この1行を削除します
   ...
////////////////////////////////////////////////////////////////////////
// プロパティ ページ ... 以下の3行をコメントアウトします
// 
//BEGIN_PROPPAGEIDS(CxxxxCtrl, 1)
//  PROPPAGEID(CxxxxPropPage::guid)
//END_PROPPAGEIDS(CxxxxCtrl)

上記処理を行うことで、プロパティページを持たないコントロールを 作成することが出来るようになります。


・ ActiveXコンポーネント(OCX)の持つ情報を変更する(2001-12-17)

ActiveX コンポーネントの コントロール名や、VB等で使用する際の コントロール説明用文字列は、xxxx.odl ファイルに記述されています。


[ uuid(..................), version(1.0),
  helpfile("xxxx.hlp"),
  helpstring("xxxx ActiveX コントロール モジュール"),
  control ]
  ....
    //  CxxxxCtrl の最初のディスパッチ インターフェイス
    [ uuid(..................),
      helpstring("xxxx Control 用ディスパッチ インターフェイス"), hidden ]
    dispinterface _DSelectPatient
    {
  ....
    //  CxxxxCtrl のイベント ディスパッチ インターフェイス
    [ uuid(..................),
      helpstring("Event interface for xxxx Control") ]
    dispinterface _DSelectPatientEvents
    {
  ....
    //  CxxxxCtrl のクラス情報
    [ uuid(..................),
      helpstring("xxxx Control"), control ]
    coclass SelectPatient
    {
  ....

上記 helpstring() 内を書き換えてやると、コンポーネントの内部 情報が書き換えられます。


・ VCからVARIANT型、VARIANT配列の使用方法

* VARIANT の扱い

  VARIANT型 BSTRなどは、各プログラムの共通領域に確保される
  このため、通常のスタック・ヒープ領域に確保される変数とは
  扱いが異なる。

  自動化したクラスとして、_variant_t タイプが存在する
  CString への代入は、(LPCWSTR)bstrString とキャストする

  逆に、BSTRの確保は、strString.AllocSysString();
              解放は、SysFreeString(BSTR *);

* 配列の場合

  // 配列型のVARIANT変数に代入
    COleSafeArray vr(AppData);
  // 配列の次元数は, GetDim()で得られる

  // 個々の要素もVARIANT型なので受け取る変数を宣言
    _variant_t v;
    CString sResult;

  // 配列のインデックスを指定するlong型配列を準備
    long lIndex[2] = { 0, 1 };          // vr[0][1]の指定
    vr.GetElement(lIndex, &v);          // 実際の要素の取得
    sResult = (LPCWSTR)v.bstrVal;       // 文字列の場合
    iResult = v.iVal;        // LONG型の場合は v.lVal;
  

・ COM, OLE DB, ActiveX に関して (Tips)

1. 通常の文字列との変換.
   OLE2T(), T2OLE() といった変換マクロの使用.
   関数の最初に,USES_CONVERSION; マクロ宣言が必要!

   COleVar の使用.
   _bstr_t 変数の使用  ・・・ 必要に応じて,BSTRを確保,解放する

   一般には,BSTRは共通領域に確保されるため,明示的な解放が必要

   CString sString;
   BSTR bstrString;
   bstrString = sString.AllocSysString();   // BSTRを確保
   ....
   FreeSysString(bstrString);               // BSTRを解放


2. HRESULTについて.
   COM関連の戻り値は,HRESULT型として返される

   S_OK : うまく実行できた場合
   FAILED(hr) : 失敗したかどうかはマクロでチェック

   戻り値 hrを使用して,
   _com_error  err(hr);
   AfxMessageBox(err.ErrorMessage()); とすることで,
   エラー内容を表示できる

   *MSDN Lib の [コンパイラ COM サポート クラス] を参照
  

TOMOsan Top Page に戻る
パソコン・プログラミングに戻る


Copyright(c) 2001 Tomohiko Saito. All rights reserved.
last update :