C/C++ 預處理程序參考——#import 指令

未完待續

C/C++ 預處理程序參考
#import 指令

 
C++ Specific
#import 指令被用來把type library中的信息合併。Type library的內容被轉換成 C++ classes,大部分表示成 COM 接口。
 
#import  "filename" [attributes]
#import  <filename> [attributes]
attributes
一個或多個 #import attributes。使用空格或者逗號區分多個attributes。例如:
 
#import "../drawctl/drawctl.tlb" no_namespace, raw_interfaces_only
-or-
 
#import "../drawctl/drawctl.tlb" no_namespace raw_interfaces_only
 
filename
用來描述你想應用哪個type library 。filename 可以是下面的某一個:
 一個 type library 文件(.tlb 或 .odl),type library是可選的。
 在 type library 中的控制 progid 。 progid:progid 是可選的。例如:
 #import "progid:my.prog.id.1.5"
關於更多的progid ,可以參考“Specifying the Localization ID and Version Number”(本地ID和版本號的描述)。

 Type library 的 library ID 。libid:library ID是可選的。例如:
 #import "libid:12341234-1234-1234-1234-123412341234" version("4.0") lcid("9")
你可以不指定版本或lcid,該規則也可以應用在progid:和libid:上
 一個可執行文件(.exe)。
 一個包括tyep library(例如:.ocx)資源的庫文件(.dll)。
 一個包括一個 type library 的混合文檔。
 可以被 LoadTypeLib API 解釋的任何格式的文檔。
想了解更多關於 #import 的信息,請閱讀下面的 Knowledge Base 文檔:
 Q242527 PRB: #import Wrapper Methods May Cause Access Violation
 Q269194 PRB: Compiler Errors When You Use #import with XML
filename (文件名)的查找順序
filename 之前的目錄是可選的。文件名必須是一個存在的文件。兩種語法之間的區別是爲了,當文件路徑完全指明時,預處理程序可以搜索到 type library 文件。
語法形式 作用
引號形式 預處理程序指令去查找 type library 文件,首先在#import 語句中所包含的文件的目錄中查找,然後再包含(#include)那個文件的所有文件目錄中查找。預處理程序將按照所指出的路徑順序查找下去。
尖括號形式 預處理程序指令將按照以下的路徑查找 type library 文件。
1. PATH 環境變量路徑列表。
2. LIB 環境變量路徑列表。
3. 由 /I(額外的包含路徑)編譯器選項定義的路徑。(The path specified by the /I (additional include directories) compiler option)
本地ID(Localization ID)和版本編號(Version Number)的詳細說明
在你定義progid 的同時,你可以也定義這個progid 本地ID 和版本號。例如:
 
#import "progid:my.prog.id" lcid("0") version("4.0)
如果你們有定義一個本地ID,可以通過下面的方法去選擇一個 progid:
 如果只有一個本地ID,就使用這個。
 如果多於一個本地ID,那就會使用版本編號爲0、9或409的版本號。
 如果多於一個本地ID並且都它們不含有0、9或409,那就會使用最後一個。
 如果沒有指定任何版本號,那就會使用最新的版本。
由導入(import)建立的頭文件
#import 建立兩個重構使用C++ 源代碼編寫的類型庫頭文件。主頭文件與Microsoft Interface Definition Language (MIDL)編譯器建立的文件類似,但是添加了編譯器自動生成的代碼和數據。這個主頭文件具有和type library一樣的基本名字,在添加上“.TLH”擴展名。第二個頭文件包含的基本名字與type library一樣,擴展名爲“.TLI”。它包含了編譯器自動生成的的成員函數接口,並且包含(#include)在主頭文件中。
If importing a dispinterface property that uses by ref parameters, #import will not generate __declspec(property) statement for the function.
Both header files are placed in the output directory specified by the /Fo (name object file) option. They are then read and compiled by the compiler as if the primary header file was named by a #include directive.
The following compiler optimizations come with the #import directive:
 The header file, when created, is given the same timestamp as the type library.
 When #import is processed, the compiler first checks if the header exists and is up to date. If yes, then it does not need to be re-created.
The #import directive also participates in minimal rebuild and can be placed in a precompiled header file. See Creating Precompiled Header Files for more information.
The Primary Type Library Header File
The primary type library header file consists of seven sections:
1. Heading boilerplate:   Consists of comments, #include statement for COMDEF.H (which defines some standard macros used in the header), and other miscellaneous setup information.
2. Forward references and typedefs:   Consists of structure declarations such as struct IMyInterface and typedefs.
3. Smart pointer declarations:    The template class _com_ptr_t is a smart-pointer implementation that encapsulates interface pointers and eliminates the need to call AddRef, Release, QueryInterface functions. In addition, it hides the CoCreateInstance call in creating a new COM object. This section uses macro statement _COM_SMARTPTR_TYPEDEF to establish typedefs of COM interfaces to be template specializations of the _com_ptr_t template class. For example, for interface IMyInterface, the .TLH file will contain: 
4.   Copy Code
_COM_SMARTPTR_TYPEDEF(IMyInterface, __uuidof(IMyInterface));
which the compiler will expand to: 
5.   Copy Code
typedef _com_ptr_t<_com_IIID<IMyInterface, __uuidof(IMyInterface)> > IMyInterfacePtr;
Type IMyInterfacePtr can then be used in place of the raw interface pointer IMyInterface*. Consequently, there is no need to call the various IUnknown member functions.
6. Typeinfo declarations:   Primarily consists of class definitions and other items exposing the individual typeinfo items returned by ITypeLib:GetTypeInfo. In this section, each typeinfo from the type library is reflected in the header in a form dependent on the TYPEKIND information.
7. Optional old-style GUID definition:   Contains initializations of the named GUID constants. These are names of the form CLSID_CoClass and IID_Interface, similar to those generated by the MIDL compiler.
8. #include statement for the secondary type library header.
9. Footer boilerplate:   Currently includes #pragma pack(pop).
All sections, except the heading boilerplate and footer boilerplate section, are enclosed in a namespace with its name specified by the library statement in the original IDL file. You can use the names from the type library header either by an explicit qualification with the namespace name or by including the following statement: 
  Copy Code
using namespace MyLib;
immediately after the #import statement in the source code.
The namespace can be suppressed by using the no_namespace attribute of the #import directive. However, suppressing the namespace may lead to name collisions. The namespace can also be renamed by the rename_namespace attribute.
The compiler provides the full path to any type library dependency required by the type library it is currently processing. The path is written, in the form of comments, into the type library header (.TLH) that the compiler generates for each processed type library.
If a type library includes references to types defined in other type libraries, then the .TLH file will include comments of the following sort: 
  Copy Code
//
// Cross-referenced type libraries:
//
//  #import "c:/path/typelib0.tlb"
//
The actual filename in the #import comment is the full path of the cross-referenced type library, as stored in the registry. If you encounter errors that are due to missing type definitions, check the comments at the head of the .TLH to see which dependent type libraries may need to be imported first. Likely errors are syntax errors (for example, C2143, C2146, C2321), C2501 (missing decl-specifiers), or C2433 ('inline' not permitted on data declaration) while compiling the .TLI file.
You must determine which of the dependency comments are not otherwise provided for by system headers and then provide an #import directive at some point before the #import directive of the dependent type library to resolve the errors.
Accessing Multiple Type Libraries
#import Attributes
#import can optionally include one or more attributes. These attributes tell the compiler to modify the contents of the type-library headers. A backslash (/) symbol can be used to include additional lines in a single #import statement. For example: 
  Copy Code
#import "test.lib" no_namespace /
   rename("OldName", "NewName")
The #import attributes are listed below:
auto_rename
auto_search

embedded_idl
exclude

high_method_prefix
high_property_prefixes

implementation_only
include()

inject_statement
named_guids

no_auto_exclude
no_dual_interfaces

no_implementation
no_namespace

no_search_namespace
no_smart_pointers

raw_dispinterfaces
raw_interfaces_only

raw_method_prefix
raw_native_types

raw_property_prefixes
rename

rename_namespace
rename_search_namespace

tlbid
 
auto_rename attribute 
auto_rename
When importing a type library that uses one or more C++ reserved words (keywords or macros) as variable names, the auto_rename attribute renames these reserved words by appending two underscores (__) to the variable name to resolve potential name conflicts.
auto_search attribute
When a type library is referenced with #import and itself references another type library, the compiler can do an implicit #import for the other type library.
embedded_idl attribute
The type library is written to the .tlh file with the attribute-generated code preserved.
exclude attribute 
exclude("Name1"[, "Name2",...])
Name1
First item to be excluded.
Name2
Second item to be excluded (if necessary).
Type libraries may include definitions of items defined in system headers or other type libraries. This attribute can be used to exclude these items from the type library header files being generated. This attribute can take any number of arguments, each being a top-level type library item to be excluded.
high_method_prefix attribute 
high_method_prefix("Prefix")
Prefix
Prefix to be used.
By default, high-level error-handling properties and methods are exposed by member functions named without a prefix. The names are from the type library. The high_method_prefix attribute is used to specify a prefix to be used in naming these high-level properties and methods.
high_property_prefixes attribute 
high_property_prefixes("GetPrefix","PutPrefix","PutRefPrefix")
GetPrefix
Prefix to be used for the propget methods.
PutPrefix
Prefix to be used for the propput methods.
PutRefPrefix
Prefix to be used for the propputref methods.
By default, high-level error-handling propget, propput, and propputref methods are exposed by member functions named with prefixes Get, Put, and PutRef respectively. The high_property_prefixes attribute is used to specify alternate prefixes for all three property methods.
implementation_only attribute
The implementation_only attribute suppresses the generation of the .TLH header file (the primary header file). This file contains all the declarations used to expose the type-library contents. The .TLI header file, with the implementations of the wrapper member functions, will be generated and included in the compilation.
When this attribute is specified, the content of the .TLI header is in the same namespace as the one normally used in the .TLH header. In addition, the member functions are not declared as inline.
The implementation_only attribute is intended for use in conjunction with the no_implementation attribute as a way of keeping the implementations out of the precompiled header (PCH) file. An #import statement with the no_implementation attribute is placed in the source region used to create the PCH. The resulting PCH is used by a number of source files. An #import statement with the implementation_only attribute is then used outside the PCH region. You are required to use this statement only once in one of the source files. This will generate all the required wrapper member functions without additional recompilation for each source file.
Note   The implementation_only attribute in one #import statement must be use in conjunction with another #import statement, of the same type library, with the no_implementation attribute. Otherwise, compiler errors will be generated. This is because wrapper class definitions generated by the #import statement with the no_implementation attribute are required to compile the implementations generated by the implementation_only attribute.
include(...) attribute 
include("Name1"[,"Name2", ...])
Name1
First item to be forcibly included.
Name2
Second item to be forcibly included (if necessary).
Type libraries may include definitions of items defined in system headers or other type libraries. #import attempts to avoid multiple definition errors by automatically excluding such items. If items have been excluded, as indicated by warning C4192, and they should not have been, this attribute can be used to disable the automatic exclusion. This attribute can take any number of arguments, each being the name of the type-library item to be included.
inject_statement attribute 
inject_statement("source_text")
source_text
Source text to be inserted into the type library header file.
The inject_statement attribute inserts its argument as source text into the type-library header. The text is placed at the beginning of the namespace declaration that wraps the type-library contents in the header file.
named_guids attribute
The named_guids attribute tells the compiler to define and initialize GUID variables in old style, of the form LIBID_MyLib, CLSID_MyCoClass, IID_MyInterface, and DIID_MyDispInterface.
no_auto_exclude attribute
Type libraries may include definitions of items defined in system headers or other type libraries. #import attempts to avoid multiple definition errors by automatically excluding such items. When this is done, warning C4192 will be issued for each item to be excluded. You can disable this automatic exclusion by using this attribute.
no_dual_interfaces attribute
The no_dual_interfaces attribute changes the way the compiler generates wrapper functions for dual interface methods. Normally, the wrapper will call the method through the virtual function table for the interface. With no_dual_interfaces, the wrapper instead calls IDispatch::Invoke to invoke the method.
no_implementation attribute
The no_implementation attribute suppresses the generation of the .TLI header, which contains the implementations of the wrapper member functions. If this attribute is specified, the .TLH header, with the declarations to expose type-library items, will be generated without an #include statement to include the .TLI header file.
This attribute is used in conjunction with implementation_only.
no_namespace attribute
The type-library contents in the #import header file are normally defined in a namespace. The namespace name is specified in the library statement of the original IDL file. If the no_namespace attribute is specified, then this namespace is not generated by the compiler.
If you want to use a different namespace name, use the rename_namespace attribute instead.
no_search_namespace attribute
Same functionality as the no_namespace but used on type libraries that are implicitly #import'ed with the auto_search attribute.
no_smart_pointers attribute
By default, when you use #import, you get a smart pointer declaration for all interfaces in the type library. These smart pointers are of type _com_ptr_t. The no_smart_pointers attribute suppresses the creation of these smart pointers.
raw_dispinterfaces attribute
The raw_dispinterfaces attribute tells the compiler to generate low-level wrapper functions for dispinterface methods and properties that call IDispatch::Invoke and return the HRESULT error code.
If this attribute is not specified, only high-level wrappers are generated, which throw C++ exceptions in case of failure.
raw_interfaces_only attribute
The raw_interfaces_only attribute suppresses the generation of error-handling wrapper functions and __declspec(property) declarations that use those wrapper functions.
The raw_interfaces_only attribute also causes the default prefix used in naming the non-property functions to be removed. Normally, the prefix is raw_. If this attribute is specified, the function names are directly from the type library.
This attribute allows you to expose only the low-level contents of the type library.
raw_method_prefix attribute 
raw_method_prefix("Prefix")
Prefix
The prefix to be used.
Low-level properties and methods are exposed by member functions named with a default prefix of raw_ to avoid name collisions with the high-level error-handling member functions. The raw_method_prefix attribute is used to specify a different prefix.
Note   The effects of the raw_method_prefix attribute will not be changed by the presence of the raw_interfaces_only attribute. The raw_method_prefix always takes precedence over raw_interfaces_only in specifying a prefix. If both attributes are used in the same #import statement, then the prefix specified by the raw_method_prefix attribute is used.
raw_native_types attribute
By default, the high-level error-handling methods use the COM support classes _bstr_t and _variant_t in place of the BSTR and VARIANT data types and raw COM interface pointers. These classes encapsulate the details of allocating and deallocating memory storage for these data types, and greatly simplify type casting and conversion operations. The raw_native_types attribute is used to disable the use of these COM support classes in the high-level wrapper functions, and force the use of low-level data types instead.
raw_property_prefixes attribute 
raw_property_prefixes("GetPrefix","PutPrefix","PutRefPrefix")
GetPrefix
Prefix to be used for the propget methods.
PutPrefix
Prefix to be used for the propput methods.
PutRefPrefix
Prefix to be used for the propputref methods.
By default, low-level propget, propput, and propputref methods are exposed by member functions named with prefixes of get_, put_, and putref_ respectively. These prefixes are compatible with the names used in the header files generated by MIDL. The raw_property_prefixes attribute is used to specify alternate prefixes for all three property methods.
rename attribute 
rename("OldName","NewName")
OldName
Old name in the type library.
NewName
Name to be used instead of the old name.
The rename attribute is used to work around name collision problems. If this attribute is specified, the compiler replaces all occurrences of OldName in a type library with the user-supplied NewName in the resulting header files.
This attribute can be used when a name in the type library coincides with a macro definition in the system header files. If this situation is not resolved, then various syntax errors will be generated, such as C2059 and C2061.
Note   The replacement is for a name used in the type library, not for a name used in the resulting header file.
Here is an example: Suppose a property named MyParent exists in a type library, and a macro GetMyParent is defined in a header file and used before #import. Since GetMyParent is the default name of a wrapper function for the error-handling get property, a name collision will occur. To work around the problem, use the following attribute in the #import statement: 
  Copy Code
rename("MyParent","MyParentX")
which renames the name MyParent in the type library. An attempt to rename the GetMyParent wrapper name will fail: 
  Copy Code
rename("GetMyParent","GetMyParentX")
This is because the name GetMyParent only occurs in the resulting type library header file.
rename_namespace attribute 
rename_namespace("NewName")
NewName
The new name of the namespace.
The rename_namespace attribute is used to rename the namespace that contains the contents of the type library. It takes a single argument, NewName, which specifies the new name for the namespace.
To remove the namespace, use the no_namespace attribute instead.
rename_search_namespace attribute 
rename_search_namespace("NewName")
NewName
The new name of the namespace.
Same functionality as the rename_namespace but used on type libraries that are implicitly #import'ed with the auto_search attribute.
tlbid attribute 
tlbid(number)
number
The number of the type library in filename.
If multiple type libraries are built into a single DLL, it possible to load libraries other than the primary by using tlbid. For example: 
  Copy Code
#import <MyResource.dll> tlbid(2)
is equivalent to: 
  Copy Code
LoadTypeLib("MyResource.dll//2");
END C++ Specific
See Also
Preprocessor Directives

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章