Реферат Курсовая Конспект
ObjectData - раздел Образование, ABSTRACT The Projectdata Structure Is...
|
The ProjectData structure is custom to each class and must be defined by the project for each class. There are no limits on the size or makeup of this structure. Since both this data structure and the methods are created together in a project, it is simple to allocate any private data required.
The ProjectData structure is a runtime creation, thus you will never need to create a .data structure of type ProjectData. The structure definition is quite useful for defining and accessing the private data when writing the custom method code. The size of this structure (m_ObjectSize) is used in the ClassItem.
The ObjectEntry structure is used to either direct a method call to the implementation table, or to cast this_ to the base address of the object itself.
ObjectEntry STRUCT
m_pVtbl DWORD ; interface object
m_pBase DWORD ; pointer to base
ObjectEntry ENDS
When CoLib creates an object, it included(N+1) ObjectEntrystructures to support N interfaces. The extra ObjectEntry is needed to support the two IUnknown interfaces for aggregation (see the discussion following on aggregation).
Note that the ProjectObject structure itself is only instanced at runtime, no instance of the project object structure is made. Nor is there any ProjectObject structure defined anywhere. It is just a convenient fiction, used only to see how the of memory is organized at runtime.
OBJECT CONSTRUCTION AND DESTRUCTON
To allow for custom object creation and destruction, you may define functions to handle these events. This is a convent way to allocate and deallocate resources.
These functions should be written to the following prototypes:
ConstructorProto PROC this_:DWORD, pCustomData:DWORD
DestructorProto PROC this_:DWORD
The Constructor proto includes a pointer to a data structure you may customize for this class. This pointer is included in the AllocObject method. When called from DllGetClassObject, there is no way to customize this pointer, but it may be defined as needs be in a sub-object creation. (This prototype and definition was corrected for CoLib 1.1)
Thus. classes are provided two separate ways to be customized. The constructor accepts a reference to custom data, and there is also a undefined data pointer in the ClassItem itself. Alternate methods of customization are provided since a class may be instanced in two ways, and may be useful with a general prototype class, one that just requires a little extra bit of custom information. An enumeration interface is one example of this.
CASTING AN OBJECT FOR AN INTERFACE
To "cast" an object in assembler does need some explanation. The term "cast" is borrowed from C++, where it does make some concrete sense, but here in the assembly end, the concepts of class and object are a bit fuzzier.
The COM interface contract allows an object to support multiple interfaces. This interface has a well-defined binary structure that we can easily duplicate in assembly, but this opens the question of interface casting.
A much better explanation of this may be found on page 44 of "Inside COM," "Multiple Inheritance and Casting."
Let us look at the interface for an imaginary object. An interface is a table of pointers to functions. Say Object this imaginary object contains Interfaces IX and IY. As this is a COM object, both IX and IY inherit from IUnknown. Let us give both IX and IY a single method each, IX.Foo and IY.Bar. Also remember that this_ holds a reference to a pointer to the virtual table of functions. The binary layout of this interface would look like so:
CLIENT | OBJECT | OBJECT | |||
COM | INSTANCE | IMPLIMENTATION | |||
POINTER | |||||
IX::QueryInterface | IX | ||||
this_ | pvtable1 | IX::AddRef | |||
pvtable2 | IX::Release | ||||
IX::Foo | |||||
IY::QueryInterface | IY | ||||
IY::AddRef | |||||
IY::Release | |||||
IY::Bar |
Figure 2. Interface casting detail (or why this_ is sometimes that_).
The first thing to notice from this figure is that there are two possible values of this_, one for each interface, and remember, it's not possible to call them "this_" and “that_". One little known property of casting is that the actual numeric value returned from a cast may not be equal to what was cast. This is another way of saying a cast may do more then just adjusting for different data formats.
When QueryInterface is invoked to get another interface inside an object, the returned pointer changes. this_ actually changes value. It has to, it must. This is completely normal. The only requirement COM imposes on the returned pointer is that a QueryInterface on two separate interfaces for IUnknown return the same value, so object identity may be determined.
This is important to us in the following way: we need a method to pass back this_, a cast interface pointer, cast to any arbitrary interface we support, and at the same time, use this_ to unwind our entire object structure. We need to get to all the information of the object, since all our code initially knows about it's instance is literally this_, and if this_can change it means we cannot simply add an offset tothis_to get to other elements in the object structure.
Interface casting is performed like so: In our object, each vtable pointer is kept in a ObjectEntry structure, which has two elements, the vtable pointer immediately followed by the base address of our object. The base address is the starting address of the object, it's the address of the ObjectData structure.
Also, the ObjectData structure contains the address of the first ObjectEntry structure.
In this way, given this_ we can walk about our object and get to any structure from any this_ cast via code such as follows:
SomeInterface_SomeFunct PROC this_:DWORD, param1:DWORD, param2:DWORD
mov ecx, this_
mov eax, [ecx + 4] ; ObjectData pointer in eax
Simple and direct. In actual use, we cast ecx at an ObjectEntry pointer so we don't have to remember the binary layout. Thus the actual library code to cast this_ to the custom data area is like so:
pObjectBase MACRO pObject:REQ, reg:REQ, _offset:VARARG
.code
; cast object to the base ClassItem interface
mov reg, pObject ; get object
mov reg, (ObjectEntry PTR[reg]).m_pBase ; walk to base data
IFNB <_offset>
add reg, _offset
ENDIF
ENDM
Once we have these references to the object's internal structures, we can access any and all parts of it.
Casting for an interface is performed in only one place: the IUnknown::QueryInterface implementation. Back when the object was first created, the ClassMap was used to get reference to the InterfaceMap. The InterfaceItem held the interface ID iid, and a pointer to that vtable. These pointer values were then copied in order over into our object. When QueryInterface is given an interface to cast, it compares the given iid parameter with this InterfaceMap, looking for a match. If interface iid N matches the parameter, then the object is cast to it by returning the address of ObjectEntryN, thus making this_ point to the requested interface.
AGGREGATION
When an object is aggregated, it uses the IUnknown implementation of the containing object. If not aggregated, it uses it's own code for these functions. Aggregation is a runtime choice, so this change must be done on the fly.
CoLib uses the same method as found in "Inside COM," Chapter 8, "Component Reuse: Containment and Aggregation." Briefly, this entails having two separate IUnknown implementations, a delegation and non-delegating IUnknown. The non-delegating version does what we've come to expect from IUnknown, reference count and interface cast. The delegating IUnknown looks for another IUnknown implementation to pass it's work off to.
At object creation time, pUnkOuter is checked for NULL. If not NULL, it is stored in the object and used by the delegating IUnknown to do the work. If it is NULL, a reference to the very first ObjectEntry is saved instead. The first ObjectEntry is always automatically assigned to the non-delegating IUnknown.
If none of this made sense, you really need not worry, the library does this all for you. If you're still worrying, go check out "Inside COM."
IMPORTING THE LIBRARY
The coserver files need to be added to your masm32 area. For consistency sake, it is recommended that you place the library .inc files in masm32cominclude, and the library itself in masm32comcolib. To use the library, you will first need to include the library itself (and it's own dependencies):
include masm32includemasm32.inc
include masm32comincludeoaidl.inc
include masm32comincludeCoLib.inc
includelib masm32libmasm32.lib
includelib masm32comcolibCoLib.lib
The main project, if a dll server, should also export a ClassMapfor each coclass:
PUBLIC ClassMap
CoLib.Lib depends on the linker to add those components a project requires, making it simple to override CoLib methods if you choose to implement anything differently. The CoLib.inc just defines some of the basic structures, it does not make .code or .data.
USING OTHER FEATURES OF THE LIBRARY
The following macros of CoLib.inc expand to code (not procedures) (they act as inline functions) and may be used anywhere in your code:
pObjectBase pObject, reg, _offsetUsed to cast this_ to the base address of the
object so ObjectData may be accessed.
Rarely used, except inside to the library itself
pObject the this_ to cast
reg register to place result
_offset optional parameter, additional offset to
add to cast
pObjectData pObject, reg, _offset Used to cast this_ to the base address of the
custom data structure so the custom data
may be accessed.
pObject the this_ to cast
reg register to place result
_offset optional parameter, additional offset to
add to cast
DeclareGuid gName, sIID Used to instance a GUID textequate. Will
assign a GUID textequate to a guid name,
and also define a pointer to this guid.
gName Label name for this guid. Will also assign
"p" & "gName" to create a reference
to the guid.
sIID optional parameter, used to define the
textequate for the guid if this does not
exist elsewhere.
DeclareGuid is handy to reduce typing (and hopefully improve clarity). For example:
DeclareGuidIID_IUnknown, sIID_IUnknown
will generate the following symbols:
IID_Unknown GUID {000000000H, 00000H, 00000H, {0C0H, 000H,
000H, 000H, 000H, 000H, 000H, 046H}}
pIID_Unknown OFFSET IID_Unknown
The second parameter is optional. If sIID_IUnknown is defined elsewhere and is of the form "s" & "guid name" then the macro will supply the equate. sIID is included for the occasion one needs to define a new guid number.
A DeclareVARIANT macro is provided to correctly initialize a VARIANT structure. These can be messy on your own. For example:
DeclareVARIANT MyVariant, VT_I4, 10
will generate the following symbols:
MyVariant VARIANT {VT_I4, , , , {10}}
OTHER REQUIRED PROJECT FILES
A project will also require the following files to completely build and define a COM server dll. See example project for samples and further explanation.
Interface Definition file .idl Defines the object to produce a type library
Type Library .tlb Produced by the .idl file, a black
box of object information
registry script .rgs Standard script for dll registration or
unregistration. See "Creating Registrar Scripts" in MSDN for .rgs syntax and usage. The library follows the same format.
rcrs.rc .rc Standard masm32 resource file. A starter
template is provided, this should be edited to your own needs as to your particular
typelib and registrar script filenames.
Project.def .def DLL export definitions.
RELATED FILES
· CoLib.inc | structures, constants, and macro functions needed by the CoLib library, include with your server project. |
· component.inc | perhaps a continual work in progress, defining many constants, structures, and interfaces (54 and counting) for .ocx controls. |
· L.inc | macro to define Unicode string constants |
· language.inc | Equates and macros to support localization (help to interpret lcid parameters) |
· mini_win.inc | Striped to the bone windows.inc file to speed the CoLib.Lib building process |
· oaidl.inc | Basic definitions for any ASM COM project |
· olectl.inc | Basic definitions for an .ocx project |
· colibl.rc | Common resource definitions |
APPENDIX A
EXPORTED LIBRARY METHODS
Standard dll Exports
DllMain PROTO :DWORD, :DWORD, :DWORD
DllRegisterServer PROTO
DllUnregisterServer PROTO
DllCanUnloadNow PROTO
DllGetClassObject PROTO :DWORD, :DWORD, :DWORD
DllRegister/Unregister Internal Functions
Register PROTO :DWORD
SetSubKey PROTO :DWORD, :DWORD, :DWORD
GetNextToken PROTO
AddReplacements PROTO :DWORD
GuardedDeleteKey PROTO :DWORD, :DWORD
Standard Interface Implementations
IUnknown Interface Implementations
QueryInterface PROTO :DWORD, :DWORD, :DWORD
AddRef PROTO :DWORD
Release PROTO :DWORD
NDQueryInterface PROTO :DWORD, :DWORD, :DWORD
NDAddRef PROTO :DWORD
NDRelease PROTO :DWORD
IDispatch Interface Implementations
GetTypeInfoCount PROTO :DWORD, :DWORD
GetTypeInfo PROTO :DWORD, :DWORD, :DWORD, :DWORD
GetIDsOfNames PROTO :DWORD, :DWORD, :DWORD, :DWORD, :DWORD, :DWORD
Invoke_ PROTO :DWORD, :DWORD, :DWORD, :DWORD, :WORD, :DWORD,
:DWORD, :DWORD, :DWORD
IDispatch Interface Helper Function
GetCachedTypeInfo PROTO :DWORD, :DWORD, :DWORD
Class Factory Interface Implementations
CreateInstance PROTO :DWORD, :DWORD, :DWORD, :DWORD
LockServer PROTO :DWORD, :DWORD
Class Factory Internal Functions
AllocObject PROTO :DWORD, :DWORD, :DWORD, :DWORD
DeallocObject PROTO :DWORD
External Helper Functions
ComPtrAssign PROTO :DWORD, :DWORD
ComQIPtrAssign PROTO :DWORD, :DWORD, :DWORD
APPENDIX B
LIBRARY DATA STRUCTURES
ClassItem
ClassItem STRUCT
m_clsidDWORD 0 ; CLSID; GUID of this class
m_FlagsDWORD 0 ; various flags
m_pTypeLibInfo DWORD 0 ; type info map
m_pIMapDWORD 0 ; InterfaceMap for this object
m_pConstructor DWORD 0 ; custom object constructor function
m_pDestructorDWORD 0 ; custom object destructor function
m_pData DWORD 0 ; custom object data reference
m_ObjectSizeDWORD 0 ; byte count of the
; private data structure
ClassItem ENDS
Contains parameters for the ClassMap array elements to define a class supported by the project dll.
– Конец работы –
Эта тема принадлежит разделу:
Copyright by Ernest Murphy ernie surfree com... For educational use only All commercial use only by written license...
Если Вам нужно дополнительный материал на эту тему, или Вы не нашли то, что искали, рекомендуем воспользоваться поиском по нашей базе работ: ObjectData
Если этот материал оказался полезным ля Вас, Вы можете сохранить его на свою страничку в социальных сетях:
Твитнуть |
Новости и инфо для студентов