Click here to Skip to main content
15,881,812 members
Articles / Desktop Programming / ATL
Article

Registry Map for RGS files

Rate me:
Please Sign up or sign in to vote.
4.55/5 (16 votes)
3 Mar 20042 min read 117.6K   1K   44   22
Allows custom tags in RGS files to keep GUIDs in sink.

Introduction

RGS files are a good concept for being able to do some nifty custom registrations in ATL without having to muck round with the registry API.

It appears however, that the writers of ATL never got round to finishing the registry resources. They even passed up on an opportunity to add yet another #define macro map. The full power of the substitutions was just never realized for want of a couple of macros.

A very annoying consequence of this is that whenever you change the CLSID, LIBID, or other attribute of the IDL file, you need to reflect the change in the RGS file. Hands up, how many people have forgotten to do this more than once! (I certainly have).

This utility adds the missing macros, allowing the user to add an RGS substitution map which can include UUIDs as well as strings.

Usage

The extra functionality is enabled by using DECLARE_REGISTRY_RESOURCEID_EX(ResourceId) in place of DECLARE_REGISTRY_RESOURCEID(ResourceId). The resource entry used can be of a more generic format, rather than the specific RGS file currently required. This goes, as usual, in the class declaration in the header.

Then, along the same lines as all of the Microsoft macro maps, a map section is required, beginning with BEGIN_REGISTRY_MAP(Class) and ending with END_REGISTRY_MAP(). Inside the registry map is a list containing entries in one of 3 forms:

  • REGMAP_ENTRY(var,subst) Substitute the variable with the given string.
  • REGMAP_RESOURCE(var,resid) Substitute the variable with the string given by the specified resource
  • REGMAP_UUID(var,clsid) Substitute the variable with the string representation of the UUID.

The RGS file for a standard COM library will look like this:

HKCR
{
    %PROGID%.%VERSION% = s '%DESCRIPTION%'
    {
        CLSID = s '%CLSID%'
    }
    %PROGID% = s '%DESCRIPTION%'
    {
        CLSID = s '%CLSID%'
        CurVer = s '%PROGID%.%VERSION%'
    }
    NoRemove CLSID
    {
        ForceRemove %CLSID% = s '%DESCRIPTION%'
        {
            ProgID = s '%PROGID%.%VERSION%'
            VersionIndependentProgID = s '%PROGID%'
            ForceRemove 'Programmable'
            InprocServer32 = s '%MODULE%'
            {
                val ThreadingModel = s '%THREADING%'
            }
            'TypeLib' = s '%LIBID%'
        }
    }
}

The next step is to declare a substitution map. This uses the same format that most of the Microsoft declaration maps follow. If you use the 'RGS' file above, then the map will look something like this:

BEGIN_REGISTRY_MAP(CClassName)
    REGMAP_ENTRY("PROGID",      "MyLibrary.ClassName")
    REGMAP_ENTRY("VERSION",     "1")
    REGMAP_ENTRY("DESCRIPTION", "ClassName Class")
    REGMAP_UUID ("CLSID",       CLSID_ClassName)
    REGMAP_UUID ("LIBID",       LIBID_MyLibraryLib)
    REGMAP_ENTRY("THREADING",   "Apartment")
END_REGISTRY_MAP()

This needs to go in the class declaration as well, so I normally place it just below the DECLARE_REGISTRY_RESOURCEID_EX declaration.

Behind the scenes of the extra macros is a simple wrapper for struct _ATL_REGMAP_ENTRY that does some resource management, which is particularly useful for managing the lifetime of the GUID description string.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Australia Australia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionLicense Pin
Member 896106528-May-12 23:21
Member 896106528-May-12 23:21 
QuestionAnyone can modify this source to make it work in VC2010? Pin
ehaerim5-Mar-12 16:58
ehaerim5-Mar-12 16:58 
GeneralHKEY_CURRRENT_USER Pin
HakunaMatada14-Apr-10 21:25
HakunaMatada14-Apr-10 21:25 
QuestionHow precisely is this used? Pin
Qwertie27-Jan-09 6:16
Qwertie27-Jan-09 6:16 
AnswerRe: How precisely is this used? [modified] Pin
Qwertie8-Dec-09 7:07
Qwertie8-Dec-09 7:07 
The author isn't very talkative.... the good news is, you don't have to replace all your existing RGS files at once. You might want to replace just one to start with, to prove that the new system works for you. I will explain how to do this.

So let's say you have a class Foo in library BarLib, with an ATL class called CFoo and a threading model of Both.

To use the registry map, add RegistryMap.hpp and objects.rgs to your project, then add #include "RegistryMap.hpp" to the top of the header file that contains CFoo. Or better yet, put #include "RegistryMap.hpp" in StdAfx.h so that you don't have to do this step for every class.

Originally your header file for CFoo contains something like...

class ATL_NO_VTABLE CFoo :
	public CComObjectRoot,
	public CComCoClass<CFoo, &CLSID_Foo>,
	public ISupportErrorInfo,
	public IDispatchImpl<IFoo, &IID_IFoo, &LIBID_FooLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
{
public:
	DECLARE_REGISTRY_RESOURCEID(IDR_FOO)

Change this too
class ATL_NO_VTABLE CFoo :
	public CComObjectRoot,
	public CComCoClass<CFoo, &CLSID_Foo>,
	public ISupportErrorInfo,
	public IDispatchImpl<IFoo, &IID_IFoo, &LIBID_FooLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
{
public:
	DECLARE_REGISTRY_RESOURCEID_EX(IDR_OBJECT)

	BEGIN_REGISTRY_MAP(CFoo)
		REGMAP_ENTRY("PROGID", "Bar.Foo")
		REGMAP_ENTRY("VERSION", "1")
		REGMAP_ENTRY("DESCRIPTION", "Foo Class")
		REGMAP_UUID("CLSID", CLSID_Foo)
		REGMAP_UUID("LIBID", LIBID_BarLib)
		REGMAP_ENTRY("THREADING", "Both")
	END_REGISTRY_MAP()

Note: if you forget one of the variables in your registry map, an error will occur when registering your COM DLL with regsvr32. ATL will produce error 0x80020009 (the result of CRegParser::PreProcessBuffer() in statreg.h calling GenerateError(E_ATL_NOT_IN_MAP)).

You also need to change your resource file to point to objects.rgs instead of Foo.rgs, and to use just one IDR constant for all classes that use objects.rgs.

For example, change the line in Foo.rc from
IDR_FOO                 REGISTRY                "Foo.rgs"

to
IDR_OBJECT              REGISTRY                "objects.rgs"


Finally, you can delete Foo.rgs.

When I used this code, I got an error in DECLARE_REGISTRY_RESOURCEID_EX, which is defined as
#define DECLARE_REGISTRY_RESOURCEID_EX(x)\
	static HRESULT WINAPI UpdateRegistry(BOOL bRegister)\
	{\
		return _Module.UpdateRegistryFromResource((UINT)x, bRegister, _GetRegistryMap() );\
	}

To fix this error, I changed it to
#define DECLARE_REGISTRY_RESOURCEID_EX(x)\
	static HRESULT WINAPI UpdateRegistry(BOOL bRegister)\
	{\
		return ATL::_pAtlModule->UpdateRegistryFromResource
			((UINT)x, bRegister, _GetRegistryMap() );\
	}<div class="signature"><div class="modified">modified on Friday, February 19, 2010 1:52 PM</div></div>

GeneralRe: How precisely is this used? Pin
Michael Geddes23-Feb-11 12:12
Michael Geddes23-Feb-11 12:12 
GeneralRe: How precisely is this used? [modified] Pin
ehaerim18-Feb-12 17:25
ehaerim18-Feb-12 17:25 
GeneralRe: How precisely is this used? [modified] Pin
Qwertie18-Feb-12 20:14
Qwertie18-Feb-12 20:14 
GeneralRe: How precisely is this used? [modified] Pin
ehaerim14-Mar-12 7:33
ehaerim14-Mar-12 7:33 
GeneralRe: How precisely is this used? [modified] Pin
Qwertie15-Mar-12 10:48
Qwertie15-Mar-12 10:48 
QuestionHow is CLSID_ClassName Defined? Pin
Paul Voelker21-Oct-08 7:22
professionalPaul Voelker21-Oct-08 7:22 
AnswerRe: How is CLSID_ClassName Defined? Pin
Jean-Marc Arzoumanian13-Nov-08 12:19
Jean-Marc Arzoumanian13-Nov-08 12:19 
QuestionCan you extend this to ATL COM exe server? Pin
ehaerim29-Aug-08 15:38
ehaerim29-Aug-08 15:38 
AnswerRe: Can you extend this to ATL COM exe server? Pin
Michael Geddes23-Feb-11 12:15
Michael Geddes23-Feb-11 12:15 
GeneralDemo Pin
Lekrot27-May-07 15:34
Lekrot27-May-07 15:34 
GeneralA bit confused.. Pin
rahulN29-Apr-04 4:08
rahulN29-Apr-04 4:08 
General.net issue Pin
umgauth014-Apr-04 6:33
umgauth014-Apr-04 6:33 
GeneralRe: .net issue Pin
Michael Geddes14-Apr-04 12:58
Michael Geddes14-Apr-04 12:58 
GeneralWizard for changing UUIDs Pin
snakeware5-Mar-04 1:44
snakeware5-Mar-04 1:44 
GeneralRe: Wizard for changing UUIDs Pin
Michael Geddes5-Mar-04 11:00
Michael Geddes5-Mar-04 11:00 
QuestionWhere? Pin
snakeware5-Mar-04 1:40
snakeware5-Mar-04 1:40 
AnswerRe: Where? Pin
Michael Geddes7-Mar-04 11:08
Michael Geddes7-Mar-04 11:08 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.