And the CoLib

MyCom2 and the CoLib

Component Object Library

For educational use only. All commercial use only by written license.   Re-written Dec 28 2000 for the MASM32 package

Include masm32coliboaidl.inc

Include masm32colibcolib.inc

Includelib masm32colibcolib.lib ; new library

 

It is easier to create an include file to define your interface, as this gives you a running start towards creating the client program to use your new objects:

 

Include IMyCom2.inc

 

Finally, we make PUBLIC the single ClassMap so the library modules can also use it:

PUBLIC ClassMap ; need to export ONLY the ClassMap

All the library code is included by the linker as it resolves all the symbols, that is all we need do to fully invoke the library functions.   Our class will be defined last (though it appears first) so we can define the class item member names.

MyCom2ObjData STRUCT ; MyCom object private data struct Value DWORD 0 ; Value (private data member) MyCom2ObjData ENDS

 

This structure is inserted into an object definition. Objects MUST be defined to this pattern, with ClassDatafollowed by the custom data, and finallyanObjectEntrylist. This Each interface needs it's own ObjectEntrystructure (this is needed to "cast" the "this_" value returned from QueryInterface)

 

MyCom2Object STRUCT ClassData0 ClassData { } ; base values MyCom2Data MyCom2ObjData { } ; custom object data ObjectEntry0 ObjectEntry { } ; delegated Unknown ObjectEntry1 ObjectEntry { } ; IMyCom2 MyCom2Object ENDS

 

The interface map defines how many interfaces are supported by an object, and links to other information the maps supply. Each interface gets it's own MapItem entry. The structure needs to be defined for each object since you may include any number of interfaces in a particular object.

 

MyCom2IMap InterfaceItem { pIID_IMyCom2, OFFSET vtableIMyCom2 } END_INTERFACE_MAP

  Each object needs type library support. It needs a pointer to the library ID,… MyCom2TypeLibInfo TypeLibInfo { pLIBID_MyCom2, 1, 0 }

END_CLASS_MAP

 

Similarly to the InterfaceMap, END_CLASS_MAPis a macro to define a NULL interface to mark the end of theClassMap

 

The parameters of a ClassItem are defined as follows:

ClassItem1.m_refiid DWORD ; CLSID for the object ClassItem1.m_Flags DWORD ; flags (see below) ClassItem1.m_pTypeLibInfo DWORD ; ptr to the TypeLibInfo struct ClassItem1.m_pIMap DWORD ; ptr to the MC2InterfaceMap ClassItem1.m_pConstructor DWORD ; ptr to the object's constructor function ClassItem1.m_pDestructor DWORD ; ptr to the object's destructor function ClassItem1.m_ObjectSize DWORD ; SIZEOF the object

 

m_Flags is the sum of the following:

AGGREGATABLEAllows aggregation by other objects
DISPINTERFACEImplements IDispatch through a dual interface
SUPPORT_ERROR_INFOSupports rich error information for vtable clients
SUPPLY_TYPE_INFOType information may be hid with this flag

 

We create the MyCom2 vtable. Note the use of pvtIDispatch, which is a lib macro to add the addresses of the IUnknown and IDispatch implementations.

 

vtableIMyCom2 IMyCom2 { pvtIDispatch, GetValue, SetValue, RaiseValue}

 

We instance the object's 3 required GUIDs here. We also make pointers to these to simplify referencing them (these equated are used above) by using the DeclareGuid macro

DeclareGuid IID_IMyCom2 DeclareGuid CLSID_MyCom2 DeclareGuid LIBID_MyCom2

 

Similarly to C++, our objects may need custom Constructor and Destructor functions for whatever resources they need. The MyCom constructor simply needs to set the data value to zero.

Code CreateMyCom2 PROC this_:DWORD pObjectData this_, edx ; cast this_ to object data xor eax, eax ; get variable mov (MyCom2ObjData ptr [edx]).m_Value, eax ; store new value

Xor eax, eax ; return S_OK ret CreateMyCom2 ENDP

;------------------------------------------------------------------------------

 

Only the GetValue method is shown for example, as each work in a similar manor. The pObjectData macro is provided from the lib to convert (cast) this_ into a pointer to the object data. The pointer is placed in the register specified to the macro (here it is placed in ecx)

GetValue PROC this_:DWORD, pval:DWORD ; GetValue for the IMyCom Interface pObjectData this_, edx ; cast this_ to object data mov eax, (MyCom2ObjData ptr [edx]).m_Value ; get object data value mov ecx, pval ; get ptr to var for return mov [ecx], eax ; mov value to variable xor eax, eax ; return S_OK ret GetValue ENDP

;------------------------------------------------------------------------------

 

That code looks so simple it may be magic. Not really... just the special COM parts of the DLL are stuffed into the lib.

 

Now's the time to look at the other files required to build our DLL. These are:

 

· IMyCom2.inc The IMyCom interface definition in asm form

 

· rsrc.rc standard MASM32 resource file

 

· MyCom2.IDL Interface Definition File. This is compiled into MyCom.tlb

 

· MyCom2.def defines the exported functions for the Dynamic Link Library

 

As before, statements defined by the CoLib library are highlighted in blue.


--------------------------------------------------------------------------------------------------------------------

IMyCom2.inc, the interface definition

 

IMyCom2 Interface

; sIID_IMyCom2 TEXTEQU <{0F8CE5E41H, 01135H, 011D4H, {0A3H, 024H, 000H, 040H, 0F6H, 0D4H, 087H, 0D9H}}>

VtIMyCom2 MACRO CastName:REQ

IDispatch methods

VtIDispatch CastName

IMyCom2 methods

Amp;CastName&_GetValue comethod2 ?

Amp;CastName&_SetValue comethod2 ?

Amp;CastName&_RaiseValue comethod2 ?

ENDM

IMyCom2 STRUCT

VtIMyCom2 IMyCom2

IMyCom2 ENDS

 

 

The interface is defined as per the previous discussions in Creating COM objects in ASM (the orgional MyCom project). It is kept separate from the DLL file so it may be included in other ASM projects.

--------------------------------------------------------------------------------------------------------------------

rsrc.rc, the resource file

Get standard resources

#include <c:masm32includecolibcoserver.rc>

// type libraries here,

IDD_TypeLib TypeLib MyCom2.tlb

// add subsequent type libraries as such:

IDD_TypeLib + 1 TypeLib MyCom3.tlb

IDD_TypeLib + 2 TypeLib MyCom4.tlb

The one and only registrar script

IDD_RGS_SCRIPT REGISTRY C:masm32MyCom2MyCom2.rgs

Add additional resources here starting at ID number 300

This should be simple to duplicate. All you are specifying is the type library file and the resistrar script file. Should you have multiple objects,… MyCom.IDL Interface Definition File  

Library MyCom2Lib

{

importlib("stdole32.tlb");

[

uuid(F8CE5E41-1135-11d4-A324-0040F6D487D9),

dual,

helpstring("IMyCom2 Dispatch Interface")

]

Interface IMyCom2 : IDispatch

[propget, id(0), helpstring("property Value")] HRESULT Value([out, retval] long *pVal); [propput, id(0), helpstring("property Value")] HRESULT Value([in]… [id(1), helpstring("method Raise")] HRESULT Raise([in] long AddVal);

Coclass MyCom2

[default] interface IMyCom2; } };

HKCR

{

MyCom.MyCom2.1 = s 'MyCom2 Class'

{

CLSID = s '{F8CE5E43-1135-11d4-A324-0040F6D487D9}'

}

MyCom.MyCom2 = s 'MyCom2 Class'

{

CLSID = s '{F8CE5E43-1135-11d4-A324-0040F6D487D9}'

CurVer = s 'MyCom.MyCom2.1'

}

NoRemove CLSID

ForceRemove {F8CE5E43-1135-11d4-A324-0040F6D487D9} = s 'MyCom2 Class' { ProgID = s 'MyCom.MyCom2.1'

MyCom2.def : Declares the module parameters.

LIBRARY "MyCom2.dll"

EXPORTS DllCanUnloadNow @1 PRIVATE DllGetClassObject @2 PRIVATE DllRegisterServer @3 PRIVATE DllUnregisterServer @4 PRIVATE

This file is mostly boilerplate. All you need define is the LIBRARY name, which is optional as you really do not need the .lib file for a COM dll.…