Next post regarding COM and ATL

ATL

Handles COM infrastructure, implements all common stuff.

ATL is set of headers, is VS type of project.

Provides a class “CComModule” and global instance “_Module”, it initialized/uninitialized within DllMain (attach/detach).

It provides set of operations – register/unregister COM dll, creating class object.

BEGIN_OBJECT_MAP(ObjectMap)/END_OBJECT_MAP() – embraces all coclasses defined within module by OBJECT_ENTRY(<coclass name>) macro.

Registration for COM servers: for inrpoc – “regsvr32” utility, for local servers – “register/unregister” parameter for WinMain.

CoClass template

class ATL_NO_VTABLE CCoHexagon :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CCoHexagon, &CLSID_CoHexagon>,
public IDraw
{
public: CCoHexagon() { }
DECLARE_REGISTRY_RESOURCEID(IDR_COHEXAGON) DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CCoHexagon)
COM_INTERFACE_ENTRY(IDraw)
END_COM_MAP()
// IDraw
public:
STDMETHOD(<method name>)();
};

CComObjectRootEx<> provides IUnknown implementation

BEGIN_COM_MAP(<coclass name>)/END_COM_MAP() embraces interfaces declaration by COM_INTERFACE_ENTRY(<interface name>)

CComCoClass<CCoHexagon, &CLSID_CoHexagon> – defines coclass factory, handles aggregation

rgs-files – registry scripting

Properties – for VB, for C++ just a syntax sugar: methods get_<prop name>, set_<prop name>

IDL definition:[propget], function parameter specification: [out, retval]

COM string: CComBSTR – wrapper over raw BSTR

Text conversion macroses: converts between C (const C++ string), A (ANSI char*), BSTR, W, T, OLE strings.

ATLTRACE – trace macro for ATL debugging.

Advertisements

COM book extract

IUnknown (QueryInterface, AddRef, Release)

InProc
OutProc
Remote

Contained (nested wrapped by container), Aggregated (nested is exposed by container)

GUID – identificator (IID, CLSID, LIBID)

AddRef/Release rules
1. AddRef internally by CoClass if interface is passed to client
2. Release when client finish working with interface
3. AddRef if pointer on interface is copied
4. AddRef at begging at function which got interface as parameter, Release at function exit

Almost all COM methods returns HRESULT (error lookup can explain it)

IDL -interface definition lang (MIDL- compiler)

Macros: STDMETHOD, DECLARE_INTERFACE, …

Strings: OLECHAR (just char or wchar_t – only C/C++ lang) and BSTR (Sys* – family of functions), …

IClassFactory (CreateInstance, LockServer), IClassFactory2 = IClassFactory + Licensing

CoClassFactory is one to one with CoClass

Dll storage should provide mandatory export functions
DllGetClassObject
CanUnloadNow
RegisterServer
UnRegisterServer

DllGetClassObject – creates and returns factory for CoClass specified by CLSID. Factory doesn’t have CLSID

CanUnloadNow operates with two counters (common for all CoClasses contained within dll): manual (operated by LockServer), automatic (constructor/destructor of each COM object), returns TRUE if both are 0

Registry

ProgID – test represented CLSID, should be uniq (“servername.coclassname.version”). ProgID and CLSID can be pragmatically converted.

Min changes:
HKCR – contains all ProgIDs (subkeys: CLSID, CurVer)
HKCR\CLSID – contains all CLSIDs (subkeys: ProgID, VersionIdependentProgID, InprocServer32- path to dll, LocalServer32- path to exe)

ole32.dll – COM system dll, connects client and rpcss.exe – service manager

Client’s code:
1. each thread should call CoInitialize() before using COM and CoUnitialize() after it using.
2. CoGetClassObject() (or CoCreateInstance(), it is wrapper, it calls CoGetClassObject() internally)
3. Release interface pointer.

IDL data types: boolean, byte, char, small, wchar_t, short, long, void*, float, double, hyper.

Variant – compatible with non C++ lang (VB), if we have ONLY variants – stub/proxy can be automatically generated.

Variant compatible datatypes: VARIANT_BOOL, double, float, long, short, BSTR, DATE, IDispatsh*, *IUnknown, VARIANT, CY/CURRENCY, SAFEARRAY

IDL
typedef – like C++ typedef
import – like C++ #incluse, (wtypes.idl – winodw’s types, unknwn.idl – IUnknown + IClassFactory, objidl.idl – more COM stuff, oleidl.idl – OLE stuff, oaidl.idl – autoamation)
[object+uuid()] – define interface
interface method parameter’s attributes – in, out, in out
cpp_quote + helpstring attribute defines text hint
library – defines library (specified by LIBID) where coclass (specified by CLSID) is stores.
coclass – includes interface declaration inside.
default interface – for non C++ langs
out, retval – attributes that specify return value for C++ and non C++ langs

tlb – (binary idl) needs for non C++ langs, registry: HKCR\TypeLib\LIBID\version = helpstring + subkey (natural lang selector) and update HKCR\CLSID\<CLSID>\TypeLib = <LIBID>

OLE\COM object viewer – nice tool (COM browser)

COM smart pointers

Proxy Class is inherited from IRpcProxyBuffer (connect, disconnect)

IRpcChannelBuffer – instanse is provided for IRpcProxyBuffer::connect method as parameter.

Stub class is inherited from IRpcStubBuffer (connect, disconnect, invoke, isIIDsupported, CountRefs, DebugServerQueryInterface, DebugServerRelease)

IPSFactoryBuffer – factory for Proxies and Stubs

dllhost.exe – process that loads COM-dll and makes COM-exe local server process from it.

AppID – identifies local exe-server, can be equal to one of CLSID of coclasses that it stores.

Registry key HKCR\AppID\<AppID> contains names (AccessPermitions-  acl list, AuthentificationLevel, DLLSurrogate – default dllhost.exe, LaunchPermisions, RemoteServerName), it is some kind of security.

It is also required to update HKCR\CLSID\<CLSID> with AppID value that refers to it’s exe local server container’s AppID

OLE object viewer can upgrade inproc server to be spawned as local server

Marshaling
1. Custom – need to inherit your coclass from IMarshal (GetUnmarshalClass, GetMarshalSizeMax, MarshalInterface, UnMarshalInterface, ReleaseMarshalData, DisconnectObject) and implement it.
2. Standard – MIDL defines all proxy/stub code, we need to build and register proxy and stub dll. Preproc definitions should be defined REGISTER_PROXY_DLL and _WIN32_DCOM and link with libs: rpcndr.lib, rpcns4.lib, rpdrt4.lib

Registry: HKCR\Interface\<IID> (values: BaseInterface, NumMethods, ProxyStubClsid32 (this mandatory one), ProxyStubClsid, TypeLib)

3. Universal (or type library marshaling) – use system proxy/stub dll, but all interfeaces method parameters should be variant – compatible. IDL attribute [oleautomation] specifies that some interface will be marshaled by universal marshaling.

Registry: HKCR\Interface\<IID>\ProxyStubClsid32 should be set in oleaut32.dll library’s CLSID. TypeLib should be registered at HKCR\TypeLib. HKCR\Interface\<IID> should have TypeLib value pointed at valid TypeLib for mentioned interface

LoadTypeLibEx – loads and provides ITypeLib interface (it also can register typelib at registry REGKIND_REGISTER)

Registry settings:

HCKR\TypeLib\{your LIBID}\1.0
HCKR\TypeLib\{your LIBID}\1.0\win32 = <path to your *.tlb file>
HCKR\TypeLib\{your LIBID}\Flags
HCKR\TypeLib\{your LIBID}\1.0\Helpdir
HKCR\Interface\{your IID}
HKCR\Interface\ProxyStubClsid = <CLSID of oleaut32.dll>
HKCR\Interface\ProxyStubClsid32 = <CLSID of oleaut32.dll>
HKCR\Interface\TypeLib = <LIBID of *.tlb file describing the interfaces>

Local server architecture

CoRegisterClassObject() – registers some class object of local server in some SCM structure (class object table).
CoRevokeClassObject() – removes class object from class object table.

CoRegisterClassObject (on enter of WinMain) CoRevokeClassObject (on exit of WinMain)  is called if “embedding” string is contained in command line.

Standard schema:

WinMain()
{
CoRegisterClassObject
GetMessage
CoRevokeClassObject
}

Class objects within local server doesnt use reference counting, AddRef and Release just return constant values.

Constructors and destructors of coclasses calls global lock counter, which in case of zero value sends PostQuitMethod to unregister class objects and shutdown an app.

Registry settings:
HKCR\LocalShapes.CoHexagon\CLSID = {<guid>}
HKCR\CLSID\{<guid>} = LocalShapes.CoHexagon
HKCR\CLSID\{<guid>}\LocalServer32 = C:\LocalShapes\Debug\LocalShapes.exe

DCOM
dcomcnfg.exe – utlity redirects all local calls to remote machine
It is possible to make this programmatically, it overrides dcomcnfg.exe-made settings