Home Forum RSS PGP Alerts Links (D) |
|
Monikers and the ROT Comment on this articleThere's a situation where you want to run workstation singletons, like if you want an NT service on the machine to be used from a number of places in client code. That's exactly what I wanted, of course. Already knowing that I needed the Running Object Table (ROT) somehow, at least I had an idea of where to start looking. The ROT keeps references to running objects, and does that by means of "Monikers". For some funny reason, the most obvious type of Moniker isn't in the system and you have to write it yourself as a COM DLL. This moniker then gets run by the system, if its name appears in a "display name prefix". Well, you'll understand all this lingo after a while (a day, or two days, or so). To create your own Moniker (in this case a Moniker called "QcMk"), just write the following code. To make things slightly easier on yourself, begin by creating an ATL COM project as a DLL, without any MFC or merge proxy/stub or anything. Then add/modify according to what follows here. Note that I modified the original code in some ways. In particular, I replaced the dumb interface pointers with smart pointers. I even found one place where the original didn't release where it should; reason enough to switch to smarter stuff. You'll find the original files at: http://www.microsoft.com/MSJ/1199/MSJNov99.zip and Jeff Prosise's article at: http://www.microsoft.com/msj/backissues99.asp, and then look for November 1999, Wicked code column. Quickjump to files: ///////////////////////////////////////////////////////////////////////////// // QcMk.h // // Moniker factory and object // // JMW 2000 // // see Prosise, MSJ nov 1999, wicked code + samples ///////////////////////////////////////////////////////////////////////////// #pragma once #include "resource.h" ///////////////////////////////////////////////////////////////////////////// // Factory class ///////////////////////////////////////////////////////////////////////////// template ///////////////////////////////////////////////////////////////////////////// // QcMk.cpp // // JMW 2000 // // Jeff Prosise MSJ nov 1999 ///////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "QcMoniker.h" #include "QcMk.h" // you'll have to write this one by hand as well // JMW 2000 HKCR { QcMk.1 = s 'QcMk Moniker Class' { CLSID = s '{A7351CE2-C9CC-47c1-99D0-AA9E99AC9F86}' } QcMk = s 'QcMk Moniker Class' { CLSID = s '{A7351CE2-C9CC-47c1-99D0-AA9E99AC9F86}' CurVer = s 'QcMk.1' } NoRemove CLSID { ForceRemove {A7351CE2-C9CC-47c1-99D0-AA9E99AC9F86} = s 'QcMk Moniker Class' { ProgID = s 'QcMk.1' VersionIndependentProgID = s 'QcMk' InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Both' } 'TypeLib' = s '{F2D49734-ACCA-4457-8C68-0960D0D121DC}' } } } // QcMoniker.idl : IDL source for QcMoniker.dll // // This file will be processed by the MIDL tool to // produce the type library (QcMoniker.tlb) and marshalling code. import "oaidl.idl"; import "ocidl.idl"; [ uuid(F2D49734-ACCA-4457-8C68-0960D0D121DC), version(1.0), helpstring("QcMoniker 1.0 Type Library") ] library QCMONIKERLib { importlib("stdole32.tlb"); importlib("stdole2.tlb"); // ------------------------------------------------------------- [ uuid(A7351CE2-C9CC-47c1-99D0-AA9E99AC9F86), helpstring("QcMk instance moniker class") ] coclass QcMk { [default] interface IMoniker; interface IROTData; }; }; This file is largely standard. Just add in the red lines. // QcMoniker.cpp : Implementation of DLL Exports. // Note: Proxy/Stub Information // To build a separate proxy/stub DLL, // run nmake -f QcMonikerps.mk in the project directory. #include "stdafx.h" #include "resource.h" #include <initguid.h> #include "QcMoniker.h" #include "QcMoniker_i.c" #include "QcMk.h" CComModule _Module; BEGIN_OBJECT_MAP(ObjectMap) OBJECT_ENTRY(CLSID_QcMk, CQcMk) END_OBJECT_MAP() ///////////////////////////////////////////////////////////////////////////// // DLL Entry Point extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/) { if (dwReason == DLL_PROCESS_ATTACH) { _Module.Init(ObjectMap, hInstance, &LIBID_QCMONIKERLib); DisableThreadLibraryCalls(hInstance); } else if (dwReason == DLL_PROCESS_DETACH) _Module.Term(); return TRUE; // ok } ///////////////////////////////////////////////////////////////////////////// // Used to determine whether the DLL can be unloaded by OLE STDAPI DllCanUnloadNow(void) { return (_Module.GetLockCount()==0) ? S_OK : S_FALSE; } ///////////////////////////////////////////////////////////////////////////// // Returns a class factory to create an object of the requested type STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) { return _Module.GetClassObject(rclsid, riid, ppv); } ///////////////////////////////////////////////////////////////////////////// // DllRegisterServer - Adds entries to the system registry STDAPI DllRegisterServer(void) { // registers object, typelib and all interfaces in typelib return _Module.RegisterServer(TRUE); } ///////////////////////////////////////////////////////////////////////////// // DllUnregisterServer - Removes entries from the system registry STDAPI DllUnregisterServer(void) { return _Module.UnregisterServer(TRUE); } All this stuff in here is automagically produced by the ATL wizard. Just add the red stuff. //Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) #ifdef _WIN32 LANGUAGE 9, 1 #pragma code_page(1252) #endif //_WIN32 #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE DISCARDABLE BEGIN "resource.h\0" END 2 TEXTINCLUDE DISCARDABLE BEGIN "#include ""winres.h""\r\n" "\0" END 3 TEXTINCLUDE DISCARDABLE BEGIN "1 TYPELIB ""QcMoniker.tlb""\r\n" "\0" END #endif // APSTUDIO_INVOKED #ifndef _MAC ///////////////////////////////////////////////////////////////////////////// // // Version // VS_VERSION_INFO VERSIONINFO FILEVERSION 1,0,0,1 PRODUCTVERSION 1,0,0,1 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x4L FILETYPE 0x2L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904B0" BEGIN VALUE "CompanyName", "\0" VALUE "FileDescription", "QcMoniker Module\0" VALUE "FileVersion", "1, 0, 0, 1\0" VALUE "InternalName", "QcMoniker\0" VALUE "LegalCopyright", "Copyright 2000\0" VALUE "OriginalFilename", "QcMoniker.DLL\0" VALUE "ProductName", "QcMoniker Module\0" VALUE "ProductVersion", "1, 0, 0, 1\0" VALUE "OLESelfRegister", "\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x0409, 0x04B0 END END #endif // !_MAC ///////////////////////////////////////////////////////////////////////////// // // Registry // IDR_QCMK REGISTRY DISCARDABLE "QcMk.rgs" ///////////////////////////////////////////////////////////////////////////// // // String Table // STRINGTABLE DISCARDABLE BEGIN IDS_PROJNAME "QcMoniker" END ///////////////////////////////////////////////////////////////////////////// #endif #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // 1 TYPELIB "QcMoniker.tlb" ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKEDResource.h Just add one line (in red): //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by QcMoniker.rc // #define IDS_PROJNAME 100 #define IDR_QCMK 101 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 201 #define _APS_NEXT_COMMAND_VALUE 32768 #define _APS_NEXT_CONTROL_VALUE 201 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif |
TOP |