このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。
早速アイコンを提供するクラスを実装…と行きたい所だが、
先にプロジェクトに下準備をしておく必要がある。
ちょっと前に、DLL のプロジェクトを作っときながら、
いままで放ったらかしにしてたので、
今日はヘッダやソースをプロジェクトに追加していこう。
今後やたらと COM クラスが出てくるのであるが、
クラスを追加する都度、少し前に作った、
IUnknown の実装である Object のコードをコピーして、
クラスを量産していくことはできる。
しかし、それではあまりにも芸がない上に、
同じようなコードが何箇所にも増えてしまうことになる。
多重継承の問題点にも触れて行きたいと思っているので、
今後設計する COM クラスは Object を継承することにする。
ということで、まずはコアとなる Object クラスを、
プロジェクト内に用意してやる必要がある。
C++ プロジェクトに最初に作成するのは、
ビルド環境の設定やグローバル変数や関数を記述した、
ヘッダファイルであることが多い。
と言うことで、まずは、global.hpp を作る。
このファイルは、全ソースファイルが参照することになる。
拡張子が hpp なのは、C++ 専用として使う予定だからだ。
========== global.hpp ==========
#ifndef global_hpp_included
#define global_hpp_included
#define STRICT
#define UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <ole2.h>
#endif // !global_hpp_included
========== end of global.hpp ==========
このファイルでは、基本となるシステムヘッダの取り込みと、
グローバル変数やグローバル関数などを宣言する。
もしこれが洗練されたプロジェクトなら、
環境設定とグローバル定義も分割するのだろうが、
今回は、あまりガチガチの設計にはしたくないので。
まあ、それでもここでの宣言は最小限にしておくこと。
今のところグローバル変数や関数はないので、
コンパイル環境に関する定義のみである。
STRICT は、型に厳密なコードを書くための宣言である。
WIN32_LEAN_AND_MEAN はコンパイル時間短縮のおまじないだ。
UNICODE は、Windows NT, 2000, XP, 2003 など、
Windows NT 系列用の環境を使うことを宣言している。
つまり、この時点で 9x 系 (95, 98, Me) は対象外になる。
NT 系 OS は、完全に Unicode が標準となっているが、
9x 系ではサポートは限られているため、
原則 Unicode しか使わない COM との相性が悪い。
現在の OS 普及率と、そもそも NTFS を扱うってことで、
今回は Windows 2000 以降専用ということにしておく。
あらゆるソースに共通で取り込むヘッダは、
Windows の基本となる windows.h と、
COM 開発の基本となる ole2.h としておこう。
では、次に、Object クラスを作る。
C++ でクラスを定義する場合、クラスの名前を持つ
ヘッダファイルとソースファイルを用意する。
まずは Object.hpp を作ろう。
========== Object.hpp ==========
#ifndef object_hpp_included
#define object_hpp_included
#include <unknwn.h>
class Object : public IUnknown {
// 中身は 3 日前の日記を参照
};
#endif // !object_hpp_included
========== end of Object.hpp ==========
Object は IUnknown を継承しているので、
IUnknown を定義している <unknwn.h> のみ取り込んでいる。
ヘッダファイルは、プリプロセッサの #include 命令で
他のファイルに取り込んで利用される。
取り込むというのは、参照するということではなく、
ヘッダファイルの内容が丸ごと一部となることを意味する。
なので、取り込んだソースに悪影響を与えないように、
ヘッダファイルには、変数や関数ならその宣言を、
クラスの場合は実体を含まない定義のみを含むのが一般的だ。
Object.hpp は、Object というクラスの実体が
「どこかに存在する」から利用可能だということを定義する。
これにより、Object.hpp を取り込んだソースファイルは、
実際にどこに存在するかに関係なく、
「どこかに存在する」Object クラスを利用する事ができる。
Object のクラスの実体は 1 つしか存在できないので、
もし、Object.hpp に実体を含めてしまうと、
複数のソースファイルに取り込まれた場合、
クラスの実体が複数存在すると言うエラーになってしまう。
続いて、実装ファイルである、Object.cpp を作る。
========== Object.cpp ==========
// ビルド環境用のヘッダ
#include "global.hpp"
// クラスを定義したヘッダ
#include "Object.hpp"
// Object の実体
// IUnknown メソッド
HRESULT Object::QueryInterface(
/* [in] */ REFIID riid,
/* [out] */ void** ppvObject) {
// 中身は 2 日前の日記を参照
}
ULONG Object::AddRef() {
// 参照カウンタを 1 加算
return ++referenceCount;
}
ULONG Object::Release() {
// 参照カウンタを 1 減算
if (--referenceCount == 0) {
// カウンタが 0 なら自身を破棄
delete this;
return 0;
}
return referenceCount;
}
Object::Object(void) {
// 初期状態ではカウンタは 0
referenceCount = 0;
}
Object::~Object(void) {
// 処理不要
}
========== end of Object.cpp ==========
Object.cpp は、Object というクラスの実体を定義している。
各ソースファイルでは、共通のヘッダファイルである
global.hpp を最初に取り込む必要がある。
では、この時点でビルドしてみよう。
コンパイルされるのは、ソースファイルだけなので、
現在は global.cpp だけである。
文法に問題がなければ、正常に終了するはずである。