Using Replaceable Parameters (The Registrar's Preprocessor)

Replaceable parameters allow a Registrar's client to specify run-time data. To do this, the Registrar maintains a replacement map into which it enters the values associated with the replaceable parameters in your script. The Registrar makes these entries at run time. The following section demonstrates these steps.

Using %MODULE%

The ATL Object Wizard automatically generates a script that uses %MODULE%. ATL uses this replaceable parameter for the actual location of your server's DLL or EXE.

Besides adding %MODULE% to the script, the ATL Object Wizard also adds the following line to the object's class declaration:

DECLARE_REGISTRY_RESOURCEID(IDR_MYCOMAPP)

This macro expands to:

static HRESULT WINAPI UpdateRegistry(BOOL bRegister)
{
   return _Module.UpdateRegistryFromResource(IDR_MYCOMAPP, 
                                   bRegister);
}

where _Module refers to the global CComModule, which has the following method and #define statement:

UpdateRegistryFromResource(UINT nResID, BOOL bRegister,
       struct _ATL_REGMAP_ENTRY* pMapEntries = NULL);

#define UpdateRegistryFromResource 
        UpdateRegistryFromResource

This method calls AtlModuleUpdateRegistryFromResource, which contains the following code:

ATLAPI AtlModuleUpdateRegistryFromResource(_ATL_MODULE*pM, 
          LPCOLESTR lpszRes, BOOL bRegister, 
          struct _ATL_REGMAP_ENTRY* pMapEntries, 
          IRegistrar* pReg)
{
   USES_CONVERSION;
   ...
   CComPtr<IRegistrar> p;
   ...

   TCHAR szModule[_MAX_PATH];
   GetModuleFileName(pM->m_hInst, szModule, _MAX_PATH);
   p->AddReplacement(OLESTR("Module"), T2OLE(szModule));

   ...
}

Note   You can find this code in atl\include\atlimpl.cpp.

CoCreateInstance acquires the pointer p, which points to the Registrar. Then, AddReplacement receives an LPCOLESTR containing the string "Module", as well as an LPCOLESTR containing the string acquired from the Win32 API function, GetModuleFileName. This code adds a replacement map entry for the Module variable that has a value associated with the result of GetModuleFileName. Now, when the preprocessor sees the %MODULE% in the script, it will replace it with the value from GetModuleFileName.

Concatenating run-time data with script data

Another use of the preprocessor is to concatenate run-time data with script data. For example, suppose we need an entry that contains a full path to a module with the string ", 1" appended at the end. First, define the following expansion:

'MyGoofyKey' = s '%MODULE%, 1'

Then, before calling one of the script processing methods, add a replacement to the map:

TCHAR szModule[_MAX_PATH]
GetModuleFileName(pM->m_hInst, szModule, _MAX_PATH);
p->AddReplacement(OLESTR("Module"), T2OLE(szModule));

During the parsing of the script, the Registrar expands '%MODULE%, 1' to c:\mycode\mydll.dll, 1.

Note   In a Registrar script, 4K is the maximum token size. (A token is any recognizable element in the syntax.) This includes tokens that were created or expanded by the preprocessor.

Note   To substitute replacement values at run time, remove the call to DECLARE_REGISTRY_RESOURCE or DECLARE_REGISTRY_RESOURCEID macro. Instead, replace it with your own UpdateRegistry member function that calls CComModule::UpdateRegistryFromResource, and pass your array of _ATL_REGMAP_ENTRY structures. Your array of _ATL_REGMAP_ENTRY must have at least one entry that is set to {NULL,NULL}, and this entry should always be the last entry. Otherwise, an access violation error will be generated when UpdateRegistryFromResrouce is called.