We are deriving our application class from CAtlExeModuleT, which takes
responsibility for the command line parsing and the class
registration.
When doing this as a permissoned user we have no issue doing machine
wide registration, into HKEY_LOCAL_MACHINE. However, when we run this
as either a permissoned user or a user that has no write access to
HKEY_LOCAL_MACHINE the registration fails silently.
I've tracked this down to a method on a class in atlbase.h,
ATL::CAtlServiceModuleT<T,nServiceNameID>::RegisterAppId, which always
attempts to write the registry key to HKCR. When per user
registration is set, via AtlSetPerUserRegistration, this fails.
MSDN states:
“To change the settings for the interactive user, store the changes
under KEY_CURRENT_USER\Software\Classes rather than
HKEY_CLASSES_ROOT.”
So, it seems as if the registration code in the ATL library is not
correctly handling this flag, and the fix is simply to redirect to the
current user registry space based upon the result of
AtlGetPerUserRegistration(). I fancy this shouldn’t be necessary but
experimentation has demonstrated that this change is sufficient and
necessary.
Has anyone encountered this problem and is there and 'official' fix or
a workaround available that doesn't involving hacking atlbase.h?
<snip>
CRegKey keyAppID;
LONG lRes = keyAppID.Open(HKEY_CLASSES_ROOT, _T("AppID"),
KEY_WRITE);
if (lRes != ERROR_SUCCESS)
return AtlHresultFromWin32(lRes);
</snip>
becomes:
<snip>
CRegKey keyAppID;
bool isPerUser;
AtlGetPerUserRegistration(&isPerUser);
if (lRes != ERROR_SUCCESS)
return AtlHresultFromWin32(lRes);
LONG lRes;
if (isPerUser == true)
{
//Bug in atlbase.h!!!!!
lRes = keyAppID.Open(HKEY_CURRENT_USER, _T("Software\\Classes\
\AppID"), KEY_WRITE);
}
else
{
lRes = keyAppID.Open(HKEY_CLASSES_ROOT, _T("AppID"), KEY_WRITE);
}
if (lRes != ERROR_SUCCESS)
return AtlHresultFromWin32(lRes);
</snip>
Use RegOverridePreDefKey to redirect HKCR to HKCU\Software\Classes
--
With best wishes,
Igor Tandetnik
With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925
> Use RegOverridePreDefKey to redirect HKCR to HKCU\Software\Classes
It is very powerful, esp. for the mentioned purpose but should be used
with care because it prevents from reading from actual HKCR. For
instance, as a part of registration it is necessary to read from
registry (e.g. to read a value which then used to build path to
another key) and HKCR is redefined so the existing value is
inaccessible.
Roman
I don't know when or why it would be necessary to read from HKCR when
registering your server. In any case, HKCR (when not redirected) is just
a blended view of HKCU\Software\Classes and HKLM\Software\Classes. When
you read from HKCR, the system tries HKCU first, then if the value is
not there falls back to HKLM. Writes always go to HKLM.
Redirecting HKCR prevents reads from falling back to
HKLM\Software\Classes. But of course you can always read from
HKLM\Software\Classes explicitly.
> I don't know when or why it would be necessary to read from HKCR when
> registering your server.
Suppose you need to add a shell property page handler to .dll files as
a part of DLL registration process. First step is to read default
value from HKCR\.dll (which is typically "dllfile") in order to build
registry key HKCR\dllfile. It is going to fail if the key was
redefined...
Of course you are correct about blending, and this is my point that
registration would generally work on redefined key but still there
might be issues in special cases.
Roman
Glad I don't have to start version controlling atl files, *phew*.