このページでは

QtでのActiveXサーバーの構築

QAxServer モジュールは、ActiveQtフレームワークの一部です。このモジュールは3つのクラスで構成されています:

  • QAxFactory COM オブジェクトを作成するためのファクトリを定義します。
  • QAxBindable Qt WidgetsとCOMオブジェクト間のインターフェースを提供します。
  • QAxAggregated サブクラス化して、追加の COM インターフェースを実装できます。

ActiveX コントロールや COM オブジェクトの実装例がいくつか用意されています。

ライブラリの使用方法

QAxServer ライブラリを使用して標準の Qt アプリケーションを COM サーバーに変えるには、.pro ファイル内の QT 変数にaxserver を追加する必要があります。

次のような.pro ファイルから、アウトオブプロセス実行可能サーバーが生成されます。

TEMPLATE = app
QT  += axserver

RC_FILE  = qaxserver.rc
...

インプロセス・サーバーをビルドするには、次のような.pro ファイルを使用します:

TEMPLATE = lib
QT += axserver
CONFIG  += dll

DEF_FILE = qaxserver.def
RC_FILE  = qaxserver.rc
...

qaxserver.rc およびqaxserver.def ファイルはフレームワークの一部であり、通常の場所から使用することも(.pro ファイルでパスを指定)、プロジェクトディレクトリにコピーして使用することもできます。これらのファイルは、任意のファイルをタイプライブラリエントリとして含める限り、変更可能です。つまり、バージョン情報を追加したり、別のツールボックスアイコンを指定したりすることができます。

axserver モジュールを使用すると、qmake ツールがビルドシステムに必要なビルドステップを追加します:

  • バイナリを、以下の代わりにqaxserver.lib に対してリンクします。qtmain.lib
  • idcツールを呼び出して、COM サーバー用の IDL ファイルを生成する
  • MIDLツール(コンパイラのインストールに含まれる)を使用して、IDLをタイプライブラリにコンパイルする
  • 生成されたタイプライブラリを、サーバーバイナリにバイナリリソースとして添付する(これもidcツールを使用)
  • サーバーを登録します。この手順には管理者権限が必要な場合があり、qaxserver_no_register 設定を行うことでスキップできます。

後処理ステップをスキップするには、qaxserver_no_postlink 設定も設定してください。

さらに、VERSION 変数を使用してバージョン番号を指定することもできます。例:

TEMPLATE = lib
VERSION = 2.5
...

指定されたバージョン番号は、登録時にタイプライブラリおよびサーバーのバージョンとして使用されます。

プロセス外とプロセス内

COM サーバーをスタンドアロンの実行ファイルとして実行するか、クライアントプロセス内の共有ライブラリとして実行するかは、主にサーバーで提供したい COM オブジェクトの種類によって決まります。

実行可能サーバーには、スタンドアロンのアプリケーションとして実行できるという利点がありますが、COM クライアントと COM オブジェクト間の通信にかなりのオーバーヘッドが追加されます。コントロールにプログラミング上のエラーがある場合、そのコントロールを実行しているサーバープロセスだけがクラッシュし、クライアントアプリケーションは引き続き実行される可能性が高いです。すべての COM クライアントが実行可能サーバーをサポートしているわけではありません。

インプロセス・サーバーは通常、サイズが小さく、起動時間が短いという利点があります。 クライアントとサーバー間の通信は、仮想関数呼び出しを通じて直接行われるため、リモートプロシージャコールに必要なオーバーヘッドは発生しません。ただし、サーバーがクラッシュするとクライアントアプリケーションもクラッシュする可能性が高く、また、インプロセスサーバーではすべての機能が利用可能とは限りません(つまり、COMのランニングオブジェクトテーブルへの登録など)。

どちらのサーバータイプも、Qtを共有ライブラリとして、あるいはサーバーバイナリに静的にリンクして使用することができます。

ビルド後の処理で発生しやすいエラー

ActiveQt 固有の後処理ステップが正常に動作するためには、サーバーが以下の要件を満たしている必要があります:

  • 公開されるすべてのコントロールは、QApplication インスタンスのみが存在する状態で作成可能であること
  • サーバーの初期リンクには、一時的なタイプライブラリリソースが含まれていること
  • サーバーの実行に必要なすべての依存関係が、システムパス(または呼び出し元環境が使用するパス)にあること(Visual Studio には、「ツール|オプション|ディレクトリ」ダイアログに独自の環境変数セットがリストされていることに注意してください)。

これらの要件が満たされていない場合、以下のエラーのいずれかが発生する可能性があります:

サーバー実行ファイルがクラッシュする

IDLを生成するには、ActiveXコントロールとして公開されるウィジェットをインスタンス化する必要があります(コンストラクタが呼び出されます)。この時点では、QApplication オブジェクト以外に何も存在しません。ウィジェットのコンストラクタは、他のオブジェクトが作成されることを前提にしてはなりません。たとえば、NULLポインタのチェックを行う必要があります。

サーバーをデバッグするには、-dumpidl 出力ファイルオプションを指定して実行し、どこでクラッシュするかを確認してください。

なお、コントロールの関数は一切呼び出されません。

サーバー実行ファイルが有効な Win32 アプリケーションではありません

タイプライブラリの接続により、サーバーバイナリが破損しました。これは Windows のバグであり、リリースビルドでのみ発生します。

最初のリンクステップでは、後で idc によって置き換えられるダミーのタイプライブラリを実行ファイルにリンクする必要があります。サンプルで示されているように、タイプライブラリを含むリソースファイルをプロジェクトに追加してください。

「DLL が見つかりません」

ビルドシステムは、インターフェース定義を生成し、サーバーを登録するために、サーバー実行ファイルを実行する必要があります。サーバーがリンクしているダイナミックリンクライブラリがパスにない場合、この処理が失敗する可能性があります(例:Visual Studio は、「ディレクトリ」オプションで指定された環境設定を使用してサーバーを呼び出します)。 サーバーに必要なすべての DLL およびプラグインが、エラーメッセージボックスに表示されるパスに含まれるディレクトリにあることを確認してください(『Windows 展開ツール』も参照してください)。

「ファイルを開けません...」

最後のクライアントが使用を停止した際、ActiveX サーバーが正常にシャットダウンできませんでした。通常、アプリケーションの終了には約 2 秒かかりますが、タスク マネージャーを使用してプロセスを強制終了する必要がある場合があります(例: クライアントがコントロールを適切に解放していない場合など)。

コントロールをインスタンス化できません

この場合、管理者としてサーバーを登録すると解決する場合があります。

コントロールの実装

Qt XMLでCOMオブジェクトを実装するには、QObject または既存のQObject のサブクラスを作成します。クラスがQWidget のサブクラスである場合、そのCOMオブジェクトはActiveXコントロールとなります。

#include <QWidget>

class MyActiveX : public QWidget
{
    Q_OBJECT

Q_OBJECT マクロは、ウィジェットに関するメタオブジェクト情報をActiveQtフレームワークに提供するために必要です。

Q_CLASSINFO("ClassID", "{1D9928BD-4453-4bdd-903D-E525ED17FDE5}")
Q_CLASSINFO("InterfaceID", "{99F6860E-2C5A-42ec-87F2-43396F4BE389}")
Q_CLASSINFO("EventsID", "{0A3E9F27-E4F1-45bb-9E47-63099BCCD0E3}")

Q_CLASSINFO() マクロを使用して、COM オブジェクトの COM 識別子を指定します。ClassID およびInterfaceID は必須ですが、EventsID はオブジェクトにシグナルがある場合にのみ必要です。これらの識別子を生成するには、uuidgen やguidgen などのシステムツールを使用してください。

各クラスに対して追加の属性を指定することができます。詳細については、「クラス情報とチューニング」を参照してください。

Q_PROPERTY(int value READ value WRITE setValue)

Q_PROPERTY() マクロを使用して、ActiveX コントロールのプロパティを宣言します。

親オブジェクトを受け取る標準のコンストラクタ、およびQObject のサブクラスと同様に、関数、シグナル、スロットを宣言してください。

public:
    MyActiveX(QWidget *parent = 0)
    ...

    int value() const;

public slots:
    void setValue(int v);
    ...

signals:
    void valueChange(int v);
    ...

};

ActiveQt フレームワークは、プロパティとパブリックスロットを ActiveX プロパティおよびメソッドとして、シグナルを ActiveX イベントとして公開し、Qt データ型とそれに対応する COM データ型間の変換を行います。

データ型

プロパティでサポートされている Qt データ型は次のとおりです。

Qt データ型COM プロパティ
boolVARIANT_BOOL
QStringBSTR
intint
uintunsigned int
doubledouble
qlonglongCY
qulonglongCY
QColorOLE_COLOR
QDateDATE
QDateTimeDATE
QTimeDATE
QFontIFontDisp*
QPixmapIPictureDisp*
QVariantVARIANT
QVariantList (QList<QVariant> と同じ)SAFEARRAY(VARIANT)
QStringListSAFEARRAY(BSTR)
QByteArraySAFEARRAY(BYTE)
QRectユーザー定義型
QSizeユーザー定義型
QPointユーザー定義型

シグナルおよびスロットのパラメータとしてサポートされている Qt データ型は以下の通りです:

Qtデータ型COMパラメータ
bool[in] VARIANT_BOOL
bool&[in, out] VARIANT_BOOL*
QString, constQString&[in] BSTR
QString&[in, out] BSTR*
QString&[in, out] BSTR*
int[in] int
int&[in,out] int
uint[in] unsigned int
uint&[in, out] unsigned int*
double[in] double
double&[in, out] double*
QColor, constQColor&[in] OLE_COLOR
QColor&[in, out] OLE_COLOR*
QDate, constQDate&[in] DATE
QDate&[in, out] DATE*
QDateTime, constQDateTime&[in] DATE
QDateTime&[in, out] DATE*
QFont, constQFont&[in] IFontDisp*
QFont&[in, out] IFontDisp**
QPixmap, constQPixmap&[in] IPictureDisp*
QPixmap&[in, out] IPictureDisp**
QList<QVariant>, constQList<QVariant>&[in] SAFEARRAY(VARIANT)
QList<QVariant>&[in, out] SAFEARRAY(VARIANT)*
QStringList, constQStringList&[in] SAFEARRAY(BSTR)
QStringList&[in, out] SAFEARRAY(BSTR)*
QByteArray, constQByteArray&[in] SAFEARRAY(BYTE)
QByteArray&[in, out] SAFEARRAY(BYTE)*
QObject*[in] IDispatch*
QRect& [in, out] structQRect (ユーザー定義)
QSize&[in, out] structQSize (ユーザー定義)
QPoint&[in, out] structQPoint (ユーザー定義)

エクスポートされた列挙型やフラグもサポートされています(Q_ENUM() およびQ_FLAG() を参照)。入力パラメータの型は、戻り値としてもサポートされています。

その他のデータ型を使用するパラメータを持つプロパティやシグナル/スロットは、ActiveQt フレームワークによって無視されます。

サブオブジェクト

COM オブジェクトは、そのサブ要素を表す複数のサブオブジェクトを持つことができます。たとえば、マルチドキュメントのスプレッドシートアプリケーションを表す COM オブジェクトは、スプレッドシートごとに 1 つのサブオブジェクトを提供することができます。

QAxFactory で認識されている限り、QObject のサブクラスはすべて、ActiveXにおけるサブオブジェクトの型として使用できます。そうすれば、その型をプロパティ内や、スロットの戻り値型、あるいはパラメータとして使用できるようになります。

プロパティ通知

ActiveXクライアントがプロパティにバインドできるようにするには、QAxBindable クラスからの多重継承を使用します。

#include <QAxBindable>
#include <QWidget>

class MyActiveX : public QWidget, public QAxBindable
{
    Q_OBJECT

プロパティの書き込み関数を実装する際は、QAxBindable クラスのrequestPropertyChange()およびpropertyChanged()関数を使用して、ActiveXクライアントがコントロールのプロパティにバインドできるようにします。

コントロールの提供

COM システムで COM サーバーを利用可能にするには、5 つの一意の識別子を使用してシステムレジストリに登録する必要があります。これらの識別子は、guidgen やuuidgen などのツールによって提供されます。この登録情報により、COM は、要求された ActiveX コントロールを提供するバイナリを特定し、コントロールへのリモートプロシージャ呼び出しをマーシャリングし、コントロールによって公開されているメソッドやプロパティに関する型情報を読み取ることができます。

クライアントからの要求に応じて COM オブジェクトを作成するには、サーバーは `QAxFactory` の実装をエクスポートする必要があります。これを行う最も簡単な方法は、一連のマクロを使用することです:

QAXFACTORY_BEGIN("{ad90301a-849e-4e8b-9a91-0a6dc5f6461f}",
                 "{a8f21901-7ff7-4f6a-b939-789620c03d83}")
    QAXCLASS(MyWidget)
    QAXCLASS(MyWidget2)
    QAXTYPE(MySubType)
QAXFACTORY_END()

これにより、MyWidget およびMyWidget2 が、COM クライアントによって作成可能な COM オブジェクトとしてエクスポートされ、MySubType が、MyWidget およびMyWidget2 のプロパティやパラメータで使用可能な型として登録されます。

QAxFactory class documentation では、このマクロの使用方法、およびカスタムファクトリの実装と使用方法について説明しています。

プロセス外の実行可能サーバーの場合、main() 関数を実装してQApplication オブジェクトをインスタンス化し、通常の Qt アプリケーションと同様にイベントループに入るようにすることができます。 デフォルトでは、アプリケーションは標準的な Qt アプリケーションとして起動しますが、コマンドラインで `-activex ` を指定すると、ActiveX サーバーとして起動します。標準的なアプリケーションインターフェースを作成・実行したり、スタンドアロンでの実行を防止したりするには、`QAxFactory::isServer()` を使用します:

#include <QApplication>
#include <QAxFactory>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    if (!QAxFactory::isServer()) {
        // create and show main window
    }
    return app.exec();
}

ただし、ActiveQt には main 関数のデフォルト実装が用意されているため、これは必ずしも必要ではありません。デフォルトの実装では、QAxFactory::startServer() を呼び出し、QApplication インスタンスを作成して exec() を呼び出します。

ActiveXサーバーの実行ファイルをビルドするには、qmake を実行してmakefileを生成し、他のQtアプリケーションと同様にコンパイラのmakeツールを使用します。makeプロセスでは、生成された実行ファイルに-regserver コマンドラインオプションを指定して呼び出すことで、システムレジストリにコントロールを登録します。

ActiveX サーバーが実行ファイルである場合、以下のコマンドラインオプションがサポートされています:

オプション結果
-regserverサーバーをシステムレジストリに登録します
-regserverperuser現在のユーザーに対してサーバーをシステムレジストリに登録します(5.14以降)
-unregserverシステムレジストリからサーバーの登録を解除します
-unregserverperuser現在のユーザーのシステムレジストリからサーバーの登録を解除します(バージョン 5.14 以降)
-activexアプリケーションを ActiveX サーバーとして起動します
-dumpidl <file> -version x.yサーバーのIDLを指定されたファイルに書き込みます。タイプライブラリのバージョンは x.y になります

インプロセス・サーバーは、すべての Windows システムで利用可能な「regsvr32 」ツールを使用して登録できます。

一般的なコンパイル時の問題

以下に挙げるコンパイラ/リンカのエラーは、Microsoft Visual C++ 6.0 コンパイラで発生するものを基にしています。

「2 つのパラメータを取るオーバーロードされた関数はありません」

このエラーが、QAXCLASS() または QAXFACTORY_DEFAULT() マクロを使用するコードで発生する場合、ウィジェットクラスにデフォルトファクトリで使用できるコンストラクタが存在しないことを意味します。標準のウィジェットコンストラクタを追加するか、コンストラクタを必要としないカスタムファクトリを実装してください。

QAXFACTORY_EXPORT() マクロを使用するコードでこのエラーが発生した場合、QAxFactory のサブクラスに適切なコンストラクタが存在しません。ファクトリクラス用に次のようなパブリックなクラスコンストラクタを定義してください

MyFactory(const QUuid &, const QUuid &);

ようなパブリックなクラスコンストラクタを、ファクトリクラスに用意してください。

「構文エラー:数値の接尾辞が不正です」

一意の識別子が、QAXFACTORY_EXPORT()、QAXFACTORY_BEGIN()、またはQAXFACTORY_DEFAULT()マクロに文字列として渡されていません。

「未解決の外部シンボル _ucm_instantiate」

サーバーはQAxFactory の実装をエクスポートしていません。プロジェクトの実装ファイルのいずれかでQAXFACTORY_EXPORT()マクロを使用してファクトリをインスタンス化およびエクスポートするか、QAXCLASS()またはQAXFACTORY_DEFAULT()マクロを使用してデフォルトのファクトリを使用してください。

"_ucm_initialize はすでに ... で定義されています"

サーバーが、QAxFactory の複数の実装をエクスポートしているか、同じ実装を2回エクスポートしています。デフォルトのファクトリを使用する場合は、QAXFACTORY_BEGIN() または QAXFACTORY_DEFAULT() マクロをプロジェクト内で1回のみ使用する必要があります。サーバーが複数のActiveXコントロールを提供する場合は、カスタムQAxFactory 実装とQAXFACTORY_EXPORT() マクロを使用してください。

QAxServer バイナリの配布

Qt で記述された ActiveX サーバーは、Qt を共有ライブラリとして使用するか、Qt をバイナリに静的にリンクすることができます。どちらの方法でも、かなり大きなパッケージになります(サーバーバイナリ自体が大きくなるか、Qt DLL を同梱する必要があるため)。

スタンドアロン・サーバーのインストール

ActiveXサーバーがスタンドアロンアプリケーションとしても実行可能な場合は、ターゲットシステムにサーバーの実行ファイルをインストールした後、-regserver というコマンドライン引数を指定して実行ファイルを実行してください。その後、サーバーが提供するコントロールがActiveXクライアントから利用可能になります。

インプロセス・サーバーのインストール

ActiveXサーバーがインストールパッケージの一部である場合は、Microsoftが提供するregsvr32 ツールを使用して、ターゲットシステムにコントロールを登録します。このツールが存在しない場合は、インストーラプロセスにDLLを読み込み、DllRegisterServer シンボルを解決して、次の関数を呼び出します。

HMODULE dll = LoadLibrary("myserver.dll");
typedef HRESULT(__stdcall *DllRegisterServerProc)();
DllRegisterServerProc DllRegisterServer =
    (DllRegisterServerProc)GetProcAddress(dll, "DllRegisterServer");

HRESULT res = E_FAIL;
if (DllRegisterServer)
    res = DllRegisterServer();
if (res != S_OK)
    // error handling

インターネット上でのサーバーの配置

Webページ内でサーバー上のコントロールを使用するには、ページを表示するブラウザからそのサーバーにアクセスできるようにし、ページ内でサーバーパッケージの場所を指定する必要があります。

サーバーの場所を指定するには、Webサイトの OBJECT タグ内で CODEBASE 属性を使用します。この値は、サーバーファイル自体、サーバーが必要とする他のファイル(Qt DLL など)を列挙した INF ファイル、または圧縮された CAB アーカイブを指すことができます。

INFファイルおよびCABファイルについては、ActiveXやCOMプログラミングに関するほぼすべての書籍のほか、MSDNライブラリやその他のさまざまなオンラインリソースで解説されています。例には、CABアーカイブの作成に使用できるINFファイルが含まれています:

[version]
    signature="$CHICAGO$"
    AdvancedINF=2.0
 [Add.Code]
    simpleax.exe=simpleax.exe
 [simpleax.exe]
    file-win32-x86=thiscab
    clsid={DF16845C-92CD-4AAB-A982-EB9840E74669}
    RegisterServer=yes

Microsoft の CABARC ツールを使用すると、CAB アーカイブを簡単に生成できます:

cabarc N simpleax.cab simpleax.exe simple.inf

これらのINFファイルは、Qtの静的ビルドを前提としているため、INFファイル内には他のDLLへの依存関係は記載されていません。DLLに依存するActiveXサーバーを配布するには、依存関係を追加し、アーカイブにライブラリファイルを同梱する必要があります。

コントロールの使用方法

ActiveX コントロールを使用する場合(たとえば、Web ページに埋め込む場合など)は、<object> という HTML タグを使用します。

<object ID="MyActiveX1" CLASSID="CLSID:ad90301a-849e-4e8b-9a91-0a6dc5f6461f">
   ...
<\object>

コントロールのプロパティを初期化するには、次のようにします。

<object ID=...>
    <param name="name" value="value">
<\object>

Webブラウザがスクリプト機能をサポートしている場合は、JavaScript、VBScript、およびフォームを使用してコントロールを制御します。ActiveQtのサンプルには、各コントロールのデモ用HTMLページが含まれています。

サポートされている ActiveX クライアントとサポートされていない ActiveX クライアント

以下は、主に ActiveX コントロールおよびクライアントアプリケーションに関する当社独自の実験に基づいており、決して完全なものではありません。

サポートされているクライアント

これらの標準的なアプリケーションは、ActiveQt で開発された ActiveX コントロールと連携します。一部のクライアントは、インプロセス・コントロールのみをサポートしている点に注意してください。

  • Internet Explorer
  • Microsoft ActiveX コントロール テスト コンテナ
  • Microsoft Visual Studio 6.0
  • Microsoft Visual Studio.NET/2003
  • Microsoft Visual Basic 6.0
  • MFCおよびATLベースのコンテナ
  • Sybase PowerBuilder
  • ActiveQt ベースのコンテナ

Microsoft Office アプリケーションはサポートされていますが、コントロールを「挿入可能」オブジェクトとして登録する必要があります。QAxFactory::registerClass を再実装してこの属性を COM クラスに追加するか、Q_CLASSINFO マクロを使用して、クラスの「挿入可能」クラス情報を「yes」に設定してください。

サポートされていないクライアント

以下のクライアントアプリケーションでは、ActiveQt ベースの COM オブジェクトを動作させることに成功していません。

  • Borland C++ Builder(バージョン 5 および 6)
  • Borland Delphi

代表的なランタイムエラー

サーバーが応答しない

システムがサーバーを起動できない場合(タスクマネージャーでサーバーのプロセスが実行されているか確認してください)、サーバーが依存する DLL(Qt DLL など)がシステムパスに欠落していないことを確認してください。Dependency Walker を使用して、サーバーバイナリのすべての依存関係を確認してください。

サーバーが実行されている場合(たとえば、タスク マネージャーにプロセスが表示されている場合)、サーバーのデバッグに関する情報は次のセクションを参照してください。

オブジェクトを作成できません

ビルドプロセス中にサーバーが正しくビルドおよび登録されたにもかかわらず、OLE/COM オブジェクト ビューア アプリケーションなどによってオブジェクトを初期化できない場合は、サーバーが依存する DLL(例:Qt DLL)がシステムパスから欠落していないことを確認してください。 Dependency Walker を使用して、サーバーバイナリのすべての依存関係を確認してください。

サーバーが実行されている場合は、サーバーのデバッグに関する情報を次のセクションを参照してください。

COM サーバーのアンロードおよびリロード時にクラッシュする

Active Qt COM サーバーが Qt Base に含まれるもの以外の Qt モジュールを利用している場合は、その COM サーバーをアウトオブプロセス COM サーバーとしてアクティブ化する必要があります。Qt Quick などのモジュールを含むインプロセス COM サーバーをアクティブ化しようとすると、COM サーバーのアンロード後にクラッシュが発生する可能性があります。

COM 呼び出し中のクラッシュまたは予期しない動作

アウトオブプロセス COM サーバーは、クライアントへの発信呼び出しを実行している間も、自身のメッセージキューを処理し続けることに注意してください。クライアントが同時にサーバーを呼び出している場合、これにより予期しない動作やクラッシュが発生する可能性があります。この状況では、発信呼び出しが戻る前に、着信呼び出しがサーバー側で実行されてしまいます。 特に、ActiveX コントロールがクライアントへのコールバックを行っている最中に、クライアントがその ActiveX コントロールを閉じると、クラッシュにつながる可能性があります。このような再入性の問題は、メッセージ フィルター(IMessageFilter および CoRegisterMessageFilter)を使用することで軽減できます。

ランタイムエラーのデバッグ

Visual Studio でインプロセスサーバーをデバッグするには、サーバープロジェクトをアクティブなプロジェクトとして設定し、プロジェクト設定でクライアントの「デバッグ セッション用の実行可能ファイル」を指定します(例:ActiveX テスト コンテナを使用)。 コードにブレークポイントを設定できるほか、デバッグ版をインストールしていれば、ActiveQt や Qt のコードをステップ実行することも可能です。

実行可能サーバーをデバッグするには、デバッガーでアプリケーションを実行し、コマンドライン引数 `-activex` を指定して起動します。その後、クライアントを起動し、ActiveX コントロールのインスタンスを作成します。COM は、次に ActiveX コントロールの作成を試みるクライアントに対して、既存のプロセスを使用します。

クラス情報とチューニング

各 COM クラスに属性を指定するには、Qt のメタオブジェクトシステムの一部であるQ_CLASSINFO マクロを使用します。

キー値の意味
バージョンクラスのバージョン(デフォルトは 1.0)
説明クラスを説明する文字列。
ClassIDクラスID。指定されていない場合は、QAxFactory::classID を再実装する必要があります。
InterfaceIDインターフェースID。指定されていない場合は、QAxFactory::interfaceID を再実装する必要があります。
EventsIDイベントインターフェースID。指定されていない場合、シグナルはCOMイベントとして公開されません。
DefaultProperty指定されたプロパティは、このクラスのデフォルトのプロパティを表します。つまり、プッシュボタンのデフォルトのプロパティは「text」となります。
DefaultSignal指定されたシグナルは、このクラスのデフォルトのシグナルを表します。例えば、プッシュボタンのデフォルトのシグナルは「clicked」となります。
LicenseKeyオブジェクトの作成には、指定されたライセンスキーが必要です。ライセンス対象のマシンを必要とする場合は、キーを空にすることができます。デフォルトでは、クラスにはライセンスが適用されていません。次のセクションも参照してください。
StockEvents値が「yes」の場合、オブジェクトは標準イベントを公開します。QAxFactory::hasStockEvents() を参照してください。
ToSuperClassオブジェクトは、value に指定されたクラス名までのすべてのスーパークラスの機能を公開します。QAxFactory::exposeToSuperClass() を参照してください。
Insertable値が「yes」の場合、そのクラスは「Insertable」として登録され、OLE 2 コンテナ(例:Microsoft Office)に一覧表示されます。この属性はデフォルトでは設定されていません。
Aggregatable値が「no」の場合、そのクラスは集約をサポートしません。デフォルトでは集約がサポートされています。
Creatable値が「no」の場合、そのクラスはクライアントによって作成できず、別のクラスの API を通じてのみ利用可能です(つまり、そのクラスはサブタイプです)。
RegisterObject値が「yes」の場合、このクラスのオブジェクトは OLE に登録され、実行中オブジェクトテーブルからアクセス可能です(つまり、クライアントは、このクラスのすでに実行中のインスタンスに接続できます)。この属性は、プロセス外サーバーでのみサポートされています。
MIMEこのオブジェクトは、値で指定された形式のデータやファイルを処理できます。値の形式は mime:extension:description です。複数の形式はセミコロンで区切られます。
CoClassAlias生成される IDL およびレジストリで使用されるクラス名です。これは、名前空間内に存在する C++ クラスにとって特に有用です。デフォルトでは、ActiveQt は IDL がコンパイルされるように「::」を削除するだけです。
実装済みカテゴリカンマ区切りのカテゴリ ID (CATID) UUID のリスト。 「control」、「insertable」などに加えて、コンテナの追加機能を指定するための汎用メカニズムです。代表的なCATIDには、CATID_InternetAware (「{0DE86A58-2BAA-11CF-A229-00AA003D7352}」)、CATID_SafeForScripting (「{7DD95801-9882-11CF-9FA9-00AA006C42C4}」)や、ユーザー定義の CATID 値などが挙げられます。

キーと値はどちらも大文字と小文字が区別されることに注意してください。

以下は、独自の API のみを公開するクラスのバージョン 2.0 を宣言しており、Microsoft Office アプリケーションの [オブジェクトの挿入] ダイアログで使用できます。

class MyActiveX : public QWidget
{
    Q_OBJECT
    Q_CLASSINFO("Version", "2.0")
    Q_CLASSINFO("ClassID", "{7a4cffd8-cbcd-4ae9-ae7e-343e1e5710df}")
    Q_CLASSINFO("InterfaceID", "{6fb035bf-8019-48d8-be51-ef05427d8994}")
    Q_CLASSINFO("EventsID", "{c42fffdf-6557-47c9-817a-2da2228bc29c}")
    Q_CLASSINFO("Insertable", "yes")
    Q_CLASSINFO("ToSuperClass", "MyActiveX")
    Q_PROPERTY(...)

public:
    MyActiveX(QWidget *parent = 0);

    ...
};

ライセンス付きコンポーネントの開発

コンポーネントを開発する場合、そのコンポーネントをインスタンス化できるユーザーを制御したい場合があるでしょう。サーバーバイナリは任意のクライアントマシンに配布・登録できるため、誰でも自分のソフトウェアでそれらのコンポーネントを使用することが可能になります。

コンポーネントのライセンス管理には、さまざまな手法があります。たとえば、コントロールを作成するコードでライセンスキーを指定したり、コントロールを実行するマシンにライセンスを付与したりする方法があります。

Qt クラスにライセンスを付与するには、Q_CLASSINFO() マクロを使用して「LicenseKey」を指定します。

class MyLicensedControl : public QWidget
{
    Q_OBJECT
    Q_CLASSINFO("LicenseKey", "<key string>")
    ...
};

このキーは、それ自体がライセンスされていないマシン上でMyLicensedControl のインスタンスを作成するために必要です。これにより、ライセンスを取得した開発者は、自身のアプリケーションとともにサーバーバイナリを再配布できるようになります。このバイナリは「LicenseKey」の値を使用してコントロールを作成しますが、アプリケーションのユーザーはライセンスキーなしではコントロールを作成できません。

コントロール用の単一のライセンスキーでは不十分な場合(つまり、開発者ごとに異なるライセンスキーを割り当てたい場合など)、空のキーを指定してコントロールにライセンスが必要であることを示し、QAxFactory::validateLicenseKey() を再実装して、システム上にライセンスが存在することを(ライセンスファイルなどを通じて)検証することができます。

その他のインターフェース

ActiveQt サーバーが提供する ActiveX コントロールは、OLE 仕様を実装するために必要な最小限の COM インターフェースセットをサポートしています。ActiveX クラスがQAxBindable クラスを継承する場合、追加の COM インターフェースを実装することも可能です。

QAxAggregated の新しいサブクラスを作成し、多重継承を使用して追加のCOMインターフェースクラスをサブクラス化してください。

class AxImpl : public QAxAggregated, public ISomeCOMInterface
{
public:
    AxImpl() {}

    long queryInterface(const QUuid &iid, void **iface);

    // IUnknown
    QAXAGG_IUNKNOWN

    // ISomeCOMInterface
    ...
}

追加の COM インターフェースをサポートするには、QAxAggregated::queryInterface() 関数を再実装します。

long AxImpl::queryInterface(const QUuid &iid, void **iface)
{
    *iface = 0;
    if (iid == IID_ISomeCOMInterface)
        *iface = (ISomeCOMInterface *)this;
    else
        return E_NOINTERFACE;

    AddRef();
    return S_OK;
}

ISomeCOMInterface はIUnknown のサブクラスであるため、QueryInterface() 、AddRef() 、およびRelease() 関数を実装する必要があります。これを行うには、クラス定義でQAXAGG_IUNKNOWNマクロを使用してください。IUnknown 関数を手動で実装する場合は、QAxAggregated::controllingUnknown()関数が返すインターフェースポインタへの呼び出しを委譲してください。例:

HRESULT AxImpl::QueryInterface(REFIID iid, void **iface)
{
    return controllingUnknown()->QueryInterface(iid, iface);
}

queryInterface() の実装において、IUnknown インターフェース自体をサポートしないでください。

COM インターフェースのメソッドを実装し、コントロールを実装しているQObject サブクラスを呼び出す必要がある場合は、QAxAggregated::object() を使用してください。

QAxBindable サブクラスでは、QAxBindable::createAggregate() を実装して、QAxAggregated サブクラスの新しいオブジェクトを返すようにしてください。

class MyActiveX : public QWidget, public QAxBindable
{
    Q_OBJECT

public:
    MyActiveX(QWidget *parent);

    QAxAggregated *createAggregate()
    {
        return new AxImpl();
    }
};

ActiveQt フレームワークも参照してください 。

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.