#import <ファイル名>
COMのタイプライブラリを含んだDLL(やEXE等?の)ファイルを指定すると、その中のタイプライブラリを取り込んでくれる。
VB等で「参照設定」と言われている仕組みに相当していると思われる。
#importが書かれているソースをコンパイルすると、拡張子がtlhとtliのファイルが作られる。
そして、tlhが(#includeしたかのように)読み込まれる。(tliも自動的にコンパイルされる)
拡張子 | 説明? | 内容 |
---|---|---|
tlh | タイプライブラリヘッダー? | C++の通常のヘッダーファイルと同様に、クラスや関数や定数が宣言されている。 |
tli | タイプライブラリの実装(implements)? | C++の通常のソースファイルと同様に、クラスや関数が定義されている。 |
例えば「#import <shdocvw.dll>」により、プロジェクトのワークディレクトリ内(デバッグビルドなら「Debugディレクトリ」の下)に「shdocvw.tlh」と「shdocvw.tli」というファイルが作られる。
shdocvw.dllやmshtml.tlbをインポートすると、コンパイル時に警告が出る。(VC++2005)
#import <shdocvw.dll> #import <mshtml.tlb>
'tagREADYSTATE' を自動的に除外し、タイプ ライブラリ 'shdocvw.dll' をインポートします
tagREADYSTATEが他の場所(ocidl.hの中)で既に定義されているので、shdocvw.tlhの中ではtagREADYSTATEを定義しない(除外する)。そのままインポートを続行する。
という意味。
この警告を消すには以下のような方法がある。
'FindText': タイプ ライブラリ 'shdocvw.dll' の識別子は既にマクロです。'rename' 修飾子を使用してください。
例によって変な日本語だが、要するに、shdocvw.dllの中で使っている「FindText」という識別子が 既に別の場所でマクロとして定義されている(commdlg.hで#defineしている)ので、rename属性を使って変更しろ、ということ。
この警告を消すには以下のような方法がある。
#importでは、後ろに各種の属性を付与することが出来る。
属性は、スペース区切りまたはカンマ区切りで複数指定することが出来る。
また、行末に「\」を置くことにより、複数行にまたがって指定することが出来る。(#define等の普通のプリプロセッサ命令と一緒)
属性 | 例 | 説明 | |
---|---|---|---|
ネームスペース関連 | no_namespace |
#import <shdocvw.dll> \ |
ネームスペースの扱いを指定する。 shdocvw.dllの場合、 何も指定しないとネームスペースは「SHDocVw」になる。 SHDocVw::IWebBrowser2 のように使う。ネームスペースが「IE」ならば、 IE::IWebBrowser2 のようになる。no_namespaceならそのまま IWebBrowser2 と書いて使う。 |
rename_namespace |
#import <shdocvw.dll> \ |
||
識別子関連 | exclude |
#import <shdocvw.dll> \ |
tlhの中では指定した項目の定義を行わない。 |
no_auto_exclude |
#import <shdocvw.dll> \ |
自動除外(exclude)を行わない。 すなわち、(他の場所で同名の定義があっても)tlhの中で定義を行う。 |
|
マクロ関連 | rename |
#import <shdocvw.dll> \ |
tlhの中の識別子を指定された名前に変更する。 左記の例だと、shdocvw.tlhの中で FindText となっていた箇所がFindTextIE になる。 |
auto_rename |
#import <shdocvw.dll> \ |
tlhの中で使っている識別子が他の場所でマクロとして定義されている場合、tlh内の識別子の名前を自動的に変更する。 左記の例だと、shdocvw.tlh内の FindText が__FindText になる。 |
|
生成内容関連 | named_guids |
GUID構造体を使ったCLSIDやIIDの定義が生成される。 | |
no_dual_interfaces |
デュアルインターフェース(って何じゃ?)に関して、Invokeの方法が変わるらしい?? | ||
no_implementation |
tliファイルを生成しない。 | ||
no_smart_pointers |
スマートポインターの定義を行わない。 例えば、(IWebBrowser2に対する)IWebBrowser2Ptrが定義されない。 |
||
raw_interfaces_only |
rawインターフェースのみ定義する。 例えばReadyStateというプロパティーに対し、get_ReadyState()という関数だけ定義される。(通常のCOMインターフェースなんだそうだ) この属性を指定しない場合は、GetReadyState()という関数も定義される。(特殊なラッパーなんだそうだ) |
||
バージョン関連 | version |
#import "libid:〜" \ |
バージョン番号 |
lcid |
localization ID |
属性は他にもあるようだ。VisualStudioのヘルプを参照。
VC++2005の場合、メニューバーの「ヘルプ(H)」→「カテゴリから検索(D)」でヘルプ画面を出し、URLに#import
Attributesのものを入力すると属性一覧が表示される。(VisualStudioがインストールされている場合、InternetExplorerでそのURLを入力することでも表示される!ただしローカル以外からのリンククリックでは何も動作しない。VS2005がインストールされていない環境では、遷移はするが“無効なURL”のエラーになる)
もしくは、MSDNで。
A.cppとB.cppがそれぞれ同じdllを#importしたとする。その際、#importの属性が違うと…
したがって、別々のソースで同じファイルを#importするなら属性は同じにしないといけない。
しかし全ての#importに同じ属性を書くのは面倒(特に属性を色々付けていると)なので、#importするファイルは1つだけにして、他のソースからはtlhファイルを#includeするようにするとよい。
ただし、DebugビルドとReleaseビルドでtlhとtliファイルの作られる場所が違うので、場合分けする必要がある。
import.cpp:
#import <shdocvw.dll> auto_rename \ exclude("OLECMDID","OLECMDF", "OLECMDEXECOPT","tagREADYSTATE") #import <mshtml.tlb> auto_rename \ exclude("_userHGLOBAL","wireHWND","wireHDC","_userHBITMAP","_userBITMAP", \ "_RemotableHandle","_FLAGGED_BYTE_BLOB","IEnumUnknown" \ "tagRECT","tagPOINT","tagSIZE", \ "__MIDL_IWinTypes_0003","__MIDL_IWinTypes_0007","__MIDL_IWinTypes_0009")
A.cpp: B.cpp:
#ifdef _DEBUG #include "Debug/shdocvw.tlh" #include "Debug/mshtml.tlh" #else #include "Release/shdocvw.tlh" #include "Release/mshtml.tlh" #endif
…なんちゃって。素直に#import専用のヘッダーファイルを用意すればいい(爆)
#pragma once #import <shdocvw.dll> auto_rename \ exclude("OLECMDID","OLECMDF", "OLECMDEXECOPT","tagREADYSTATE") #import <mshtml.tlb> auto_rename \ exclude("_userHGLOBAL","wireHWND","wireHDC","_userHBITMAP","_userBITMAP", \ "_RemotableHandle","_FLAGGED_BYTE_BLOB","IEnumUnknown", \ "tagRECT","tagPOINT","tagSIZE", \ "__MIDL_IWinTypes_0003","__MIDL_IWinTypes_0007","__MIDL_IWinTypes_0009")
A.cpp: B.cpp:
#include "import.h"
しかしexcludeに関して、なんでauto_excludeという属性は無いんだろう…?
C4192の警告が出てるだけで、デフォルト動作は自動除外だからか?
ということは、#pragma warningで警告を抑制するだけでもいいのか。
import.h:
#pragma once #pragma warning(disable:4192) #import <shdocvw.dll> auto_rename #import <mshtml.tlb> auto_rename #pragma warning(default:4192)
…実際、excludeで全項目を列挙するのと同じ内容が生成された。全項目を列挙する苦労の意味は…?(苦笑)