ATL and Visual Studio C++.NET 2008 Goodies

This seems to be undocumented (Google does not know anything on this): ATL server executables may be run with /RegServerPerUser and /UnregServerPerUser switches to hopefully (this what would expect this to do without checking) register contained COM classes under HKEY_CURRENT_USER rather than HKEY_LOCAL_MACHINE and thus allow COM server run under credentials of non-administrative user. See Also: Merged View of HKEY_CLASSES_ROOT.

Good bye _ATL_MIN_CRT: this mode is retired with Visual Studio .NET 2008.

PROP_ENTRY and PROP_ENTRY_EX are deprecated and replaced with PROP_ENTRY_TYPE and PROP_ENTRY_TYPE_EX. Note that property pages have to be mentioned in property map explicitly using PROP_PAGE as opposed to old behavior when they were referenced as a part of property declaration.

ATL Server is taken out of the product and moved to open source project at CodePlex.

Many small fixes, including for example for CenterWindow.

7 Replies to “ATL and Visual Studio C++.NET 2008 Goodies”

  1. I have an application which uses this, and assumed it would do that, but it fails silently.

    The error is because it doesn’t pay heed to AtlSetPerUserRegistration in the registry update and unconditionally tries to write the AppId to HKEY_CLASSES_ROOT, which fails in all cases independently of the user permissions when you try and register on a per user basis.

    The fix is easy in the method ATL::CAtlServiceModuleT::RegisterAppId but I don’t really want to be hacking around with atlbase.h. Is this a known issue and is there an ‘official’ fix?

    Who knows?

    I’m using VS 2008.

  2. I never heard of an official fix for this, and probably first of all because default installation sequence and COM class registration assumes that user has sufficient permissions to write to HKCR.

    In your application in any event I think you don’t actually need to hack ATL source. The firist option you have is try to register per-user from your installation script. This is a call to DllInstall “user” instead of DllRegisterServer, or what seems to be quite the same “regsvr32 /i yourdll.dll user” (/i switch).

    If this does not work for you, you can override this in your source code by trying to open HKLM\Shotware key before default registration takes place and if failed, switch to per-user registration automatically be calling AtlSetPerUserRegistration(TRUE);

  3. In a coporate environment it’s not common for users to be able to write to HKCR.

    With regards to my application, it’s an exe which can be loaded as a COM component. The installation involves calling this exe with the /RegServer flag. This has long since been a headache as it requires admin access to do, so we wanted to switch to the per user equivalent. This doesn’t work.

    Looking through the atl code it seems that the AtlSetPerUserRegistration(TRUE) is being called, if the pre user command line argument is used, but this doesn’t work. The code which actually writes the key assumes it has write access to HKCR, however msdn states:

    “To change the settings for the interactive user, store the changes under KEY_CURRENT_USER\Software\Classes rather than HKEY_CLASSES_ROOT.”

    Trying to write to HKCR as either a permissioned user or a non-permissioned user has no effect when AtlSetPerUserRegistration(TRUE) has been called, but works correctly only for the permissioned user when AtlSetPerUserRegistration(FALSE) has been called (or rather when AtlSetPerUserRegistration(TRUE) has not been called).

    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.

    Regsvr32 will not work in this case, as we are using an Exe and not a dll. I fancy the same problem would occur with DllInstall.

  4. I never tried per user registration myself so I cannot tell for sure if it works or not. What you wrote definitely makes sense and if so there is probably some problem in ATL base which makes it still unable to register per-user classes, even with registration switched to per-user through AtlSetPerUserRegistration.

    BTW you can also ask in ATL newsgroup here – microsoft.public.vc.atl, perhaps someone already investigated the problem.

  5. It might be an easy fix, but I am not aware of it yet :)

    P.S. Follow-up thread on Google Groups and it’s worth quoting Igor‘s post:

    Use RegOverridePreDefKey to redirect HKCR to HKCU\Software\Classes

    Apart from probable ATL base bug this might be an easy way to implement per-user registration without the whole internal ATL registration mechanism.

  6. I realized that the powerful RegOverridePredefKey API may bring a problem of making existing HKCR values inaccessible for the registration sequence. For instance,

    VOID PrintExeFileTypeTitle()
    {
        CRegKey Key;
        ATLENSURE_SUCCEEDED(HRESULT_FROM_WIN32(Key.Open(HKEY_CLASSES_ROOT, _T(".exe"), KEY_READ)));
        TCHAR pszValue[256] = { 0 };
        ULONG nValueLength = _countof(pszValue);
        ATLENSURE_SUCCEEDED(HRESULT_FROM_WIN32(Key.QueryStringValue(NULL, pszValue, &nValueLength)));
        _tprintf(_T("HKCR\\.exe is %s\n"), pszValue);
    }
    
    PrintExeFileTypeTitle();
    CRegKey Key;
    ATLENSURE_SUCCEEDED(HRESULT_FROM_WIN32(Key.Create(HKEY_CURRENT_USER, _T("Software\\Classes"))));
    ATLENSURE_SUCCEEDED(HRESULT_FROM_WIN32(RegOverridePredefKey(HKEY_CLASSES_ROOT, Key)));
    PrintExeFileTypeTitle();
    

    prints out:

    HKCR\.exe is exefile
    Error 0x800700a1

    because API substituted another key and the values are not merged for reading. It is going to be much safer to fix the ATL base bug rather than use registry key redefinition API.

Leave a Reply