#import 指令
1. C++中使用 COM 簡單的方法是用 #import 導入 type library
2. # import 指令將 COM 產生對應的 C++類別,可以用接近於VBScript和Visual Basic的語句操作 COM
3. 使用 #import 命令就可以將該文件導入到我們的程式碼中。type library 的內容將被轉換為描述了 COM Interface 的 COM smart pointer
4. 語法
#import "filename" [attributes]
#import <filename> [attributes]
2. # import 指令將 COM 產生對應的 C++類別,可以用接近於VBScript和Visual Basic的語句操作 COM
3. 使用 #import 命令就可以將該文件導入到我們的程式碼中。type library 的內容將被轉換為描述了 COM Interface 的 COM smart pointer
4. 語法
#import "filename" [attributes]
#import <filename> [attributes]
attributes:
用來通知編譯器修改 type library header 的內文。可以使用空白或逗號分隔 attribute。該選項為選擇性。如果 attribute 太多,可以使用 \ 斷行分隔
a) auto_rename
b) auto_search
c) embedded_idl
d) exclude
e) high_method_prefix
f) high_property_prefixes
g) implementation_only
h) include()
i) inject_statement
j) named_guids
k) no_auto_exclude
l) no_dual_interfaces
m) no_implementation no_namespace
n) no_search_namespace
o) no_smart_pointers
p) raw_dispinterfaces
q) raw_interfaces_only
r) raw_method_prefix
s) raw_native_types
t) raw_property_prefixes
u) rename
v) rename_namespace
w) rename_search_namespace
x) tlbid
用來通知編譯器修改 type library header 的內文。可以使用空白或逗號分隔 attribute。該選項為選擇性。如果 attribute 太多,可以使用 \ 斷行分隔
a) auto_rename
b) auto_search
c) embedded_idl
d) exclude
e) high_method_prefix
f) high_property_prefixes
g) implementation_only
h) include()
i) inject_statement
j) named_guids
k) no_auto_exclude
l) no_dual_interfaces
m) no_implementation no_namespace
n) no_search_namespace
o) no_smart_pointers
p) raw_dispinterfaces
q) raw_interfaces_only
r) raw_method_prefix
s) raw_native_types
t) raw_property_prefixes
u) rename
v) rename_namespace
w) rename_search_namespace
x) tlbid
filename:
你想要匯入的 type library,可以指定的值如下
a) type library (.tlb, .odl): #import "drawctl.tlb"
b) ProgID: #import "progid:my.prog.id.1.5"
可以額外指定地區ID和版本號碼,如下:
#import "progid:my.prog.id" lcid("0") version("4.0)
你想要匯入的 type library,可以指定的值如下
a) type library (.tlb, .odl): #import "drawctl.tlb"
b) ProgID: #import "progid:my.prog.id.1.5"
可以額外指定地區ID和版本號碼,如下:
#import "progid:my.prog.id" lcid("0") version("4.0)
假如沒有指定地區 ID 會依循下列規則自動選擇
1) 假如只有一個地區 ID 就直接使用
2) 假如有多個地區 ID,選擇版本編號的第一碼為 0, 9 或 499 的使用
3) 假如有多個地區 ID,且版本編號的第一碼為 0, 9 或 499 有多個可以選擇,則選用最後一個
4) 假如沒有指定版本號碼,則使用最近的版本號碼
c) type library ID: #import "libid:12341234-1234-1234-1234-123412341234" version("4.0") lcid("9")
d) 一個可執行檔(.exe)
e) 包含 type library 資訊的 dll
f) 內含 type library 的文件
g) 任何可被 LoadTypeLib 接受的檔案
1) 假如只有一個地區 ID 就直接使用
2) 假如有多個地區 ID,選擇版本編號的第一碼為 0, 9 或 499 的使用
3) 假如有多個地區 ID,且版本編號的第一碼為 0, 9 或 499 有多個可以選擇,則選用最後一個
4) 假如沒有指定版本號碼,則使用最近的版本號碼
c) type library ID: #import "libid:12341234-1234-1234-1234-123412341234" version("4.0") lcid("9")
d) 一個可執行檔(.exe)
e) 包含 type library 資訊的 dll
f) 內含 type library 的文件
g) 任何可被 LoadTypeLib 接受的檔案
filename 如果為一個實體檔案,會依循下面的規則進行搜尋
1) #import 中指定的路徑
2) 引用該檔案的程式所在路徑
3) PATH 環境變數
4) LIB 環境變數
5) 編譯器選項 /I 指定的路徑
1) #import 中指定的路徑
2) 引用該檔案的程式所在路徑
3) PATH 環境變數
4) LIB 環境變數
5) 編譯器選項 /I 指定的路徑
5. #import 產生的 header 檔
包含類似 MIDL(Microsoft Interface Definition Language) 產生的主要 header 檔,但是包含額外的編譯器產生的程式碼和資料。該檔案和 type library 具有相同的名稱但附檔名為 .tlh。第二個 header 檔也具有和 type library 相同的檔名,但附檔名為 .tli。他內含編譯器產生的成員函式的實作,且該 header 被包含在主要 header 檔(.tlh)中。
假如併入(import)一個包含 byref 參數的 dispinterface property, #import 將不會產生 __declspec (property) 敘述
這兩個 header 放置在 /Fo 指定的目錄,
#import 在接到 type library 同時間會產生 header 檔。當 #import 處理完,編譯器會檢查檔案是否存在並且日期夠新。假如條件吻合則不重新建立。
#import 指令也可以放在預先編譯的 header 中,詳請參考
包含類似 MIDL(Microsoft Interface Definition Language) 產生的主要 header 檔,但是包含額外的編譯器產生的程式碼和資料。該檔案和 type library 具有相同的名稱但附檔名為 .tlh。第二個 header 檔也具有和 type library 相同的檔名,但附檔名為 .tli。他內含編譯器產生的成員函式的實作,且該 header 被包含在主要 header 檔(.tlh)中。
假如併入(import)一個包含 byref 參數的 dispinterface property, #import 將不會產生 __declspec (property) 敘述
這兩個 header 放置在 /Fo 指定的目錄,
#import 在接到 type library 同時間會產生 header 檔。當 #import 處理完,編譯器會檢查檔案是否存在並且日期夠新。假如條件吻合則不重新建立。
#import 指令也可以放在預先編譯的 header 中,詳請參考
http://msdn.microsoft.com/library/en-us/vccore/html/_core_Creating_Precompiled_Header_Files.asp
6. 主要的 header (.tlh)包含七個部分
a) 固定的標頭:包含註解、#include "COMDEF.h"和其他安裝資訊
b) 向前參照和 typdef
c) 智慧型指標宣告:樣板類別 _com_ptr_t 屬於一個智慧型指標,該類別封裝了介面指標並排除呼叫 AddRef, Release, QueryInterface 等繁瑣的步驟。另外也隱藏了 CoCreateInstance 建立一個新的 COM 物件的呼叫。這個部分使用 _COM_SMARTPTR_TYPEDEF 來產生特異化(Specialization)版本的 _com_ptr_t 類別。例如:
_COM_SMARTPTR_TYPEDEF(IMyInterface, __uuidof(IMyInterface));
編譯器會將上述的程式擴展成
typedef _com_ptr_t<_com_IIID<IMyInterface, __uuidof(IMyInterface)> > IMyInterfacePtr;
d) Typeinfo 宣告
e) 舊型 GUIDE 定義:選擇性部分,包含命名過的 GUID 常數 ,命名類似 CLSID_CoClass 和 IID_Interface,類似 MIDL 編譯器產生的資料
f) #include 第二個 header (*.tli)
g) 檔尾: #pragma pack(pop)
a) 固定的標頭:包含註解、#include "COMDEF.h"和其他安裝資訊
b) 向前參照和 typdef
c) 智慧型指標宣告:樣板類別 _com_ptr_t 屬於一個智慧型指標,該類別封裝了介面指標並排除呼叫 AddRef, Release, QueryInterface 等繁瑣的步驟。另外也隱藏了 CoCreateInstance 建立一個新的 COM 物件的呼叫。這個部分使用 _COM_SMARTPTR_TYPEDEF 來產生特異化(Specialization)版本的 _com_ptr_t 類別。例如:
_COM_SMARTPTR_TYPEDEF(IMyInterface, __uuidof(IMyInterface));
編譯器會將上述的程式擴展成
typedef _com_ptr_t<_com_IIID<IMyInterface, __uuidof(IMyInterface)> > IMyInterfacePtr;
d) Typeinfo 宣告
e) 舊型 GUIDE 定義:選擇性部分,包含命名過的 GUID 常數 ,命名類似 CLSID_CoClass 和 IID_Interface,類似 MIDL 編譯器產生的資料
f) #include 第二個 header (*.tli)
g) 檔尾: #pragma pack(pop)
7. 使用 type library 可以用全域的解析或是明確的使用 namespace,如下
using namespace MyLib;
該程式碼必須加在 #import 之後。
可以使用 no_namespace attribute 不需指定 namespace,不過可能發生名稱衝突。也可以使用 rename_namespace attribute 變更 namespace 名稱。
using namespace MyLib;
該程式碼必須加在 #import 之後。
可以使用 no_namespace attribute 不需指定 namespace,不過可能發生名稱衝突。也可以使用 rename_namespace attribute 變更 namespace 名稱。
參考資料:
[1] MSDN,
[1] MSDN,
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/_predir_The_.23.import_Directive.asp
[2] Q242527 PRB: #import Wrapper Methods May Cause Access Violation
[3] Q269194 PRB: Compiler Errors When You Use #import with XML