Type Library to Assembly 转换摘要
Type Library to Assembly 转换摘要
COM_style type library ==> .NET Framework metadata.
The .NET Framework provides both tools and an API to perform type library to
assembly conversion. Although you have several mechanisms for generating an
assembly from a type library, each produces the same results. For simplicity, this
section describes only the Type Library Importer (Tlbimp.exe) tool in conjunction
with the conversion rules for importing type information.
$1、Imported Library Conversion
(Describes how the import process converts type library information. )
When the import process converts a type library, it automatically places the types
defined within the library in a namespace of the same name as the type library.
For example, if you run Tlbimp.exe on the following type library, the utility
imports all types defined within the AcmeLib type library into the AcmeLib
namespace.
library AcmeLib {
interface Widget {};
coclass Slingshot {};
};
==>
namespace AcmeLib {
interface Widget {};
class Slingshot {};
};
可以通过以下技术实现命名空间的重命名(和原来类型库名不一样)。
[
uuid(...),
version(1.0),
custom(0F21F359-AB84-41e8-9A78-36D110E6D2F9, "Acme.WidgetLib") //Here is it!
]
library AcmeLib {
interface Widget {};
coclass Slingshot {};
};
By using the user-defined attribute, you can force Tlbimp.exe to import the
AcmeLib type library into the Acme.WidgetLib namespace. The Slingshot class
becomes Acme.WidgetLib.Slingshot in managed code.
$2、Imported Module Conversion
(Describes how the import process converts modules containing the definitions of
constants and methods. )
A type library can have one or more modules containing the definitions of
constants and methods. Constants defined within modules are imported as public
constant static members of a class with the same name as the original module.
Constants defined outside of a module are not imported.
[
uuid(12345678-1234-1234-1234-123456789ABC),
]
library TestConstants
{
[
uuid(12345678-1234-1234-1234-123456789ABC),
dllname("test.dll")
]
module Constants
{
const short FRAME_COLOR = 0x10;
const short WINDOW_COLOR = 0x20;
const short BUTTON_COLOR = 0x40;
...
};
};
==> Converted types appear as follows:
public class Constants
{
public const short FRAME_COLOR = 0x10;
public const short WINDOW_COLOR = 0x20;
public const short BUTTON_COLOR = 0x40;
}
$3、Imported Type Conversion
(Describes how the import process converts interfaces, classes, structures,
enumerations, constants, and typedefs. )
This topic describes how the import process converts the following types:
Interfaces
Classes
Structures
Enumerations
Constants
Typedefs
In general, Tlbimp.exe imports types with the same name they had in the original
type library. Names within a type library must be unique, thereby eliminating
naming conflicts during the conversion process. All valid type-library names are
valid assembly names.
Imported types are scoped by the namespace to which they belong, which is the same
as the original type library. Types are individually identified by their complete
namespace and type names.
You can explicitly control the managed name of an imported type by using a type
library attribute in the type library. This user-defined attribute identifier is
0F21F359-AB84-41e8-9A78-36D110E6D2F9. The following type library shows the
addition of the user-defined attribute.
Type library representation:
[ uuid(...),
version(1.0)
]
library AcmeLib {
interface Widget {};
[custom(0F21F359-AB84-41e8-9A78-36D110E6D2F9,
"Acme.WidgetLib.Slingshot")]
coclass Slingshot {};
};
Even though Tlbimp.exe imports the type library into the AcmeLib namespace, the
Slingshot class becomes Acme.WidgetLib.Slingshot.
Interfaces
When the import process converts an interface, it strips out all IUnknown and
IDispatch methods. The conversion applies the GuidAttribute to the interface to
retain the interface identifier (IID) assigned in the type library and the
InterfaceTypeAttribute unless the interface is dual (an interface deriving from
IDispatch).
Type library representation:
[uuid(...), ]
interface IWidget : IUnknown {
HRESULT New()
HRESULT Start()
};
[uuid(...), ]
interface IGadget : IWidget {
HRESULT Baz()
};
==>
During conversion, the import process adds the methods of the base interface to
the derived interface. In the following example, New and Start are added to the
IGadget interface:
[Guid(...), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IWidget {
void New();
void Start();
};
[Guid(...), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IGadget : IWidget {
new void New();
new void Start();
void Baz();
};
Classes
The import process creates a managed class to represent each COM coclass, giving
the managed class the same name as the original coclass appended with Class. For
example, the NewNewer coclass becomes NewNewerClass. The conversion adds the
GuidAttribute to the class to capture the class identifier (CLSID) of the coclass.
In addition to the managed class, the import process adds an interface with the
same name as the coclass and applies the CoClassAttribute to identify the CLSID of
the original coclass. This interface has the same IID as the default interface for
the coclass. With this interface, clients can always register as event sinks.
Unlike a COM coclass, a managed class can contain class members. In keeping with
the .NET Framework approach, the conversion adds to each class the members
associated with each interface implemented by the coclass. Users of the managed
class can invoke methods and properties of the managed type without first casting
to a specific interface. The import process also adds a default constructor to
each converted coclass. A constructor makes it possible to create the class from
managed code. (Classes without a constructor cannot be created). The default
constructor has no arguments; its implementation calls the base class constructor.
If the noncreatable type library attribute is applied to the coclass, the import
process does not create a default constructor for the class.
Since interface member names are not always unique, name and DispId collisions
among members can occur. TlbImp.exe resolves name collisions by prefixing the
interface name and an underscore to the name of each colliding member of the
class. Where the names of members collide, the first interface listed in the
coclass statement remains unchanged.
When DispId collisions occur, the import process assigns DispIds to members of the
coclass's default interface and none to the conflicting class members. However,
the import process always assigns DispIds to members of the interface.
Type library representation:
[uuid(...)]
interface INew : IDispatch {
[id(0x100)] HRESULT DoFirst();
[id(0x101)] HRESULT DoSecond();
}
[uuid(...)]
interface INewer : IDispatch {
[id(0x100)] HRESULT DoNow();
[id(0x101)] HRESULT DoSecond();
}
[uuid(...)]
coclass NewNewer {
[default] interface INew;
interface INewer;
}
==>
The converted types appear as follows:
[Guid(...)]
public interface INew {...}
[Guid(...)]
public interface INewer {...}
[Guid(...)]
public interface NewNewer : INew {...}
[Guid(...)]
public class NewNewer : INew, INewer, NewNewer{
// Method implementation.
[DispId(100)]...
}
Structures
Structures defined within a type library are imported as metadata. If a field of a
struct is a reference type, Tlbimp.exe imports the type as an IntPtr and applies
the ComConversionLossAttribute. The attribute indicates that information was lost
during the import process.
Enumerations
Type Library Importer (Tlbimp.exe) imports unmanaged enumerations as managed Enum
types.
Constants
Constants will not be imported from type library in this release.
Typedefs
Type definitions (typedefs) within a type library are not imported. Instead,
parameters and fields are imported as the underlying types. For example, a
parameter of type BUTTON_COLOR is imported as type integer, since BUTTON_COLOR is
an alias for an integer.
Once imported, parameters and fields carry information that associates them with
their original type in the ComAliasNameAttribute. The conversion process applies
ComAliasNameAttribute to associate a field, parameter, or return value with the
name of the type library and the type within the library that was used as an
alias.
The following type library representation shows that the cl parameter is typed as
a BUTTON_COLOR, which is an alias for an integer.
Type library representation
library MyLib {
typedef [public] int BUTTON_COLOR;
interface ISee {
HResult SetColor([in] BUTTON_COLOR cl);
HResult GetColor([out, retval] BUTTON_COLOR *cl);
};
coclass See {
[default] interface ISee
};
};
==>
The converted types appear as follows:
public interface ISee {
void SetColor([ComAliasName("MyLib.BUTTON_COLOR")]] int cl);
[return: ComAliasName("MyLib.BUTTON_COLOR")] int GetColor();
};
public class See {
public void SetColor([ComAliasName("MyLib.BUTTON_COLOR")]] int cl);
[return: ComAliasName("MyLib.BUTTON_COLOR")] int GetColor();
};
Note that the actual type BUTTON_COLOR is not defined in the resulting metadata.
Instead, the parameters typed as BUTTON_COLOR in the type library are typed as the
underlying type, int, and are attributed with the ComAliasNameAttribute. This
conversion process also applies the attribute to arguments on class methods.
$4、Imported Member Conversion
(Describes how the import process converts methods, properties, and events.)
This topic describes how the import process converts the following members:
Methods
Properties
Events
Tlbimp.exe applies the DefaultMemberAttribute to any method or property with a
DispID of 0. Note that C# developers must treat these members as arrays. For
additional information, see your programming language documentation.
Methods
When COM interop imports a COM type, it produces a .NET Framework method signature
equivalent to the original COM method signature. During the conversion process, it
maps COM parameters, return values, and HRESULTs to those in a .NET Framework
method signature, as shown in the following illustration.
Method signature conversion
You can examine method syntax with an object viewer or by using reflection, just as with any other .NET class. By default, when the COM object returns a failure HRESULT, the runtime throws a corresponding exception.