VirtualBox

Changeset 59367 in vbox for trunk/src/VBox/Main/src-all/win


Ignore:
Timestamp:
Jan 17, 2016 5:45:36 AM (9 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
105055
Message:

VBoxProxyStub: Implemented the automatic registration update code.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/src-all/win/VBoxProxyStub.c

    r59363 r59367  
    2424*********************************************************************************************************************************/
    2525#define PROXY_DELEGATION                                                                             /* see generated dlldata.c */
     26#include <iprt/nt/nt-and-windows.h>
    2627#include <rpcproxy.h>
    27 #include <Windows.h>
    2828#include <Shlwapi.h>
    2929#include <stdio.h>
    3030
    3131#include "VirtualBox.h"
     32#include <iprt/alloca.h>
    3233#include <iprt/assert.h>
    3334#include <iprt/path.h>
    3435#include <iprt/string.h>
     36#include <iprt/uuid.h>
    3537
    3638
     
    4244#if 1 /*defined(DEBUG) && !defined(VBOX_IN_32_ON_64_MAIN_API) - needed on testboxes (and obviously dev boxes)! */
    4345# define WITH_MANUAL_CLEANUP
     46#endif
     47
     48#ifdef DEBUG_bird
     49# define VBSP_LOG_ENABLED
     50#endif
     51
     52#ifdef VBSP_LOG_ENABLED
     53# define VBSP_LOG_VALUE_CHANGE(a)   RTAssertMsg2 a
     54#else
     55# define VBSP_LOG_VALUE_CHANGE(a)   do { } while (0)
     56#endif
     57
     58#ifdef VBSP_LOG_ENABLED
     59# define VBSP_LOG_SET_VALUE(a)      RTAssertMsg2 a
     60#else
     61# define VBSP_LOG_SET_VALUE(a)      do { } while (0)
     62#endif
     63
     64#ifdef VBSP_LOG_ENABLED
     65# define VBSP_LOG_NEW_KEY(a)        RTAssertMsg2 a
     66#else
     67# define VBSP_LOG_NEW_KEY(a)        do { } while (0)
    4468#endif
    4569
     
    117141    {
    118142        case DLL_PROCESS_ATTACH:
     143            /* Save the DLL handle so we can get the path to this DLL during
     144               registration and updating. */
    119145            g_hDllSelf = hInstance;
     146
     147            /* We don't need callbacks for thread creation and destruction. */
    120148            DisableThreadLibraryCalls(hInstance);
     149
    121150            /* We don't use IPRT, so no need to init it! */
    122151            break;
     
    138167    *ppapInfo = &g_apProxyFiles[0];
    139168    *ppClsid  = &g_ProxyClsId;
    140 };
     169}
    141170
    142171
     
    219248
    220249
     250#ifdef VBSP_LOG_ENABLED
     251# include <iprt/asm.h>
     252
     253/** For logging full key names.   */
     254static PCRTUTF16 vbpsDebugKeyToWSZ(HKEY hKey)
     255{
     256    static union
     257    {
     258        KEY_NAME_INFORMATION NameInfo;
     259        WCHAR awchPadding[260];
     260    }                           s_aBufs[4];
     261    static uint32_t volatile    iNext = 0;
     262    uint32_t                    i = ASMAtomicIncU32(&iNext) % RT_ELEMENTS(s_aBufs);
     263    ULONG                       cbRet = 0;
     264    NTSTATUS                    rcNt;
     265
     266    memset(&s_aBufs[i], 0, sizeof(s_aBufs[i]));
     267    rcNt = NtQueryKey(hKey, KeyNameInformation, &s_aBufs[i], sizeof(s_aBufs[i]) - sizeof(WCHAR), &cbRet);
     268    if (!NT_SUCCESS(rcNt))
     269        s_aBufs[i].NameInfo.NameLength = 0;
     270    s_aBufs[i].NameInfo.Name[s_aBufs[i].NameInfo.NameLength] = '\0';
     271    return s_aBufs[i].NameInfo.Name;
     272}
     273#endif
     274
    221275/**
    222276 * Registry modifier state.
     
    228282    /** The handle to the CLSID key under hkeyClassesRootDst. */
    229283    HKEY hkeyClsidRootDst;
    230     /** For logging purposes.   */
    231     const char *pszLogRoot;
    232 
    233     /** Alternative location where duplicates must always be unregistered from. */
    234     HKEY hkeyAltClassesRootsUnreg;
    235     /** The handle to the CLSID key under hkeyAltClassesRootsUnreg. */
    236     HKEY hkeyAltClsidRootsUnreg;
     284    /** The handle to the Interface key under hkeyClassesRootDst. */
     285    HKEY hkeyInterfaceRootDst;
     286
     287    /** Alternative locations where data needs to be deleted, but never updated.  */
     288    struct
     289    {
     290        /** The classes root key handle. */
     291        HKEY hkeyClasses;
     292        /** The classes/CLSID key handle. */
     293        HKEY hkeyClsid;
     294        /** The classes/Interface key handle. */
     295        HKEY hkeyInterface;
     296    } aAltDeletes[3];
     297    /** Alternative delete locations. */
     298    uint32_t cAltDeletes;
    237299
    238300    /** The current total result. */
     
    242304     * almost the work from one process (at least W7+ due to aliases). */
    243305    DWORD   fSamWow;
    244     /** Desired key Access when only unregistring. */
    245     DWORD   fSamUnreg;
    246     /** Desired key Access when both unregistring and registering. */
     306    /** Desired key access when only deleting. */
     307    DWORD   fSamDelete;
     308    /** Desired key access when only doing updates. */
     309    DWORD   fSamUpdate;
     310    /** Desired key access when both deleting and updating. */
    247311    DWORD   fSamBoth;
    248     /** Set if we're only unregistering. */
    249     bool    fUnregisterOnly;
     312    /** Whether to delete registrations first. */
     313    bool    fDelete;
     314    /** Whether to update registry value and keys. */
     315    bool    fUpdate;
     316
    250317} VBPSREGSTATE;
    251318
     
    261328 * @param   pszSubRoot      The path to the where the classes are registered,
    262329 *                          NULL if @a hkeyRoot.
    263  * @param   pszLogRoot      For error logging/debugging?
    264330 * @param   hkeyAltRoot     The registry root tree constant for the alternative
    265331 *                          registrations (remove only).
    266332 * @param   pszAltSubRoot   The path to where classes could also be registered,
    267333 *                          but shouldn't be in our setup.
    268  * @param   fUnregisterOnly If true, only unregister. If false, also register.
     334 * @param   fDelete         Whether to delete registrations first.
     335 * @param   fUpdate         Whether to update registrations.
    269336 * @param   fSamWow         KEY_WOW64_32KEY or 0.
    270337 */
    271 static LSTATUS vbpsRegInit(VBPSREGSTATE *pState, HKEY hkeyRoot, const char *pszSubRoot, const char *pszLogRoot,
    272                            HKEY hkeyAltRoot, const char *pszAltSubRoot, bool fUnregisterOnly, DWORD fSamWow)
     338static LSTATUS vbpsRegInit(VBPSREGSTATE *pState, HKEY hkeyRoot, const char *pszSubRoot, bool fDelete, bool fUpdate, DWORD fSamWow)
    273339{
    274340    LSTATUS rc;
    275     REGSAM  fAccess = !fUnregisterOnly
    276                     ? DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY
    277                     : DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE;
    278 
     341    unsigned i = 0;
     342
     343    /*
     344     * Initialize the whole structure first so we can safely call vbpsRegTerm on failure.
     345     */
    279346    pState->hkeyClassesRootDst          = NULL;
    280347    pState->hkeyClsidRootDst            = NULL;
    281     pState->pszLogRoot                  = pszLogRoot;
    282     pState->hkeyAltClassesRootsUnreg    = NULL;
    283     pState->hkeyAltClsidRootsUnreg      = NULL;
    284     pState->fUnregisterOnly             = fUnregisterOnly;
     348    pState->hkeyInterfaceRootDst        = NULL;
     349    for (i = 0; i < RT_ELEMENTS(pState->aAltDeletes); i++)
     350    {
     351        pState->aAltDeletes[i].hkeyClasses   = NULL;
     352        pState->aAltDeletes[i].hkeyClsid     = NULL;
     353        pState->aAltDeletes[i].hkeyInterface = NULL;
     354    }
     355    pState->cAltDeletes                 = 0;
     356    pState->rc                          = ERROR_SUCCESS;
     357    pState->fDelete                     = fDelete;
     358    pState->fUpdate                     = fUpdate;
    285359    pState->fSamWow                     = fSamWow;
    286     pState->fSamUnreg                   = pState->fSamWow | DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE;
    287     pState->fSamBoth                    = pState->fSamUnreg | (!fUnregisterOnly ? KEY_SET_VALUE | KEY_CREATE_SUB_KEY : 0);
    288     pState->rc                          = ERROR_SUCCESS;
    289 
     360    pState->fSamDelete                  = 0;
     361    if (fDelete)
     362        pState->fSamDelete = pState->fSamWow | DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE
     363                           | STANDARD_RIGHTS_READ | STANDARD_RIGHTS_WRITE;
     364    pState->fSamUpdate                  = 0;
     365    if (fUpdate)
     366        pState->fSamUpdate = pState->fSamWow | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY
     367                           | STANDARD_RIGHTS_READ | STANDARD_RIGHTS_WRITE;
     368    pState->fSamBoth                    = pState->fSamDelete | pState->fSamUpdate;
     369
     370    /*
     371     * Open the root keys.
     372     */
    290373    rc = RegOpenKeyExA(hkeyRoot, pszSubRoot, 0 /*fOptions*/, pState->fSamBoth, &pState->hkeyClassesRootDst);
    291374    AssertMsgReturn(rc == ERROR_SUCCESS, ("%u\n", rc), pState->rc = rc);
    292375    rc = RegOpenKeyExA(pState->hkeyClassesRootDst, "CLSID", 0 /*fOptions*/, pState->fSamBoth, &pState->hkeyClsidRootDst);
    293376    AssertMsgReturn(rc == ERROR_SUCCESS, ("%u\n", rc), pState->rc = rc);
    294     if (hkeyAltRoot)
    295     {
    296         rc = RegOpenKeyExA(hkeyAltRoot, pszAltSubRoot, 0 /*fOptions*/, pState->fSamUnreg, &pState->hkeyAltClassesRootsUnreg);
    297         AssertMsgReturn(rc == ERROR_SUCCESS || rc == ERROR_FILE_NOT_FOUND, ("%u\n", rc), pState->rc = rc);
    298         if (pState->hkeyAltClassesRootsUnreg)
    299         {
    300             rc = RegOpenKeyExA(pState->hkeyAltClassesRootsUnreg, "CLSID", 0 /*fOptions*/, pState->fSamUnreg,
    301                                &pState->hkeyAltClsidRootsUnreg);
    302             AssertMsgReturn(rc == ERROR_SUCCESS || rc == ERROR_FILE_NOT_FOUND, ("%u\n", rc), pState->rc = rc);
    303         }
    304     }
     377
    305378    return ERROR_SUCCESS;
    306379}
     
    327400        pState->hkeyClsidRootDst = NULL;
    328401    }
    329     if (pState->hkeyAltClassesRootsUnreg)
    330     {
    331         rc = RegCloseKey(pState->hkeyAltClassesRootsUnreg);
     402    if (pState->hkeyInterfaceRootDst)
     403    {
     404        rc = RegCloseKey(pState->hkeyInterfaceRootDst);
    332405        Assert(rc == ERROR_SUCCESS);
    333         pState->hkeyAltClassesRootsUnreg = NULL;
    334     }
    335     if (pState->hkeyAltClsidRootsUnreg)
    336     {
    337         rc = RegCloseKey(pState->hkeyAltClsidRootsUnreg);
    338         Assert(rc == ERROR_SUCCESS);
    339         pState->hkeyAltClsidRootsUnreg = NULL;
    340     }
     406        pState->hkeyInterfaceRootDst = NULL;
     407    }
     408
     409    while (pState->cAltDeletes > 0 && pState->cAltDeletes <= RT_ELEMENTS(pState->aAltDeletes))
     410    {
     411        unsigned i = --pState->cAltDeletes;
     412        if (pState->aAltDeletes[i].hkeyClasses)
     413        {
     414            rc = RegCloseKey(pState->aAltDeletes[i].hkeyClasses);
     415            Assert(rc == ERROR_SUCCESS);
     416            pState->aAltDeletes[i].hkeyClasses = NULL;
     417        }
     418        if (pState->aAltDeletes[i].hkeyClsid)
     419        {
     420            rc = RegCloseKey(pState->aAltDeletes[i].hkeyClsid);
     421            Assert(rc == ERROR_SUCCESS);
     422            pState->aAltDeletes[i].hkeyClsid = NULL;
     423        }
     424        if (pState->aAltDeletes[i].hkeyInterface)
     425        {
     426            rc = RegCloseKey(pState->aAltDeletes[i].hkeyInterface);
     427            Assert(rc == ERROR_SUCCESS);
     428            pState->aAltDeletes[i].hkeyInterface = NULL;
     429        }
     430    }
     431}
     432
     433
     434/**
     435 * Add an alternative registry classes tree from which to remove keys.
     436 *
     437 * @returns ERROR_SUCCESS if we successfully opened the destination root, other
     438 *          wise windows error code (remebered).
     439 * @param   pState              The registry modifier state.
     440 * @param   hkeyAltRoot         The root of the alternate registry classes
     441 *                              location.
     442 * @param   pszAltSubRoot       The path to the 'classes' sub-key, or NULL if
     443 *                              hkeyAltRoot is it.
     444 */
     445static LSTATUS vbpsRegAddAltDelete(VBPSREGSTATE *pState, HKEY hkeyAltRoot, const char *pszAltSubRoot)
     446{
     447    unsigned i;
     448    LSTATUS rc;
     449
     450    /* Ignore call if not in delete mode. */
     451    if (!pState->fDelete)
     452        return ERROR_SUCCESS;
     453
     454    /* Check that there is space in the state. */
     455    i = pState->cAltDeletes;
     456    AssertReturn(i < RT_ELEMENTS(pState->aAltDeletes), pState->rc = ERROR_TOO_MANY_NAMES);
     457
     458
     459    /* Open the root. */
     460    rc = RegOpenKeyExA(hkeyAltRoot, pszAltSubRoot, 0 /*fOptions*/, pState->fSamDelete,
     461                       &pState->aAltDeletes[i].hkeyClasses);
     462    if (rc == ERROR_SUCCESS)
     463    {
     464        /* Try open the CLSID subkey, it's fine if it doesn't exists. */
     465        rc = RegOpenKeyExA(pState->aAltDeletes[i].hkeyClasses, "CLSID", 0 /*fOptions*/, pState->fSamDelete,
     466                           &pState->aAltDeletes[i].hkeyClsid);
     467        if (rc == ERROR_SUCCESS || rc == ERROR_FILE_NOT_FOUND)
     468        {
     469            if (rc == ERROR_FILE_NOT_FOUND)
     470                pState->aAltDeletes[i].hkeyClsid = NULL;
     471            pState->cAltDeletes = i + 1;
     472            return ERROR_SUCCESS;
     473        }
     474        AssertMsgFailed(("%u\n", rc));
     475        RegCloseKey(pState->aAltDeletes[i].hkeyClasses);
     476    }
     477    /* No need to add non-existing alternative roots, nothing to delete in the void. */
     478    else if (rc == ERROR_FILE_NOT_FOUND)
     479        rc = ERROR_SUCCESS;
     480    else
     481    {
     482        AssertMsgFailed(("%u\n", rc));
     483        pState->rc = rc;
     484    }
     485
     486    pState->aAltDeletes[i].hkeyClasses = NULL;
     487    pState->aAltDeletes[i].hkeyClsid   = NULL;
     488    return rc;
     489}
     490
     491
     492/**
     493 * Open the 'Interface' keys under the current classes roots.
     494 *
     495 * We don't do this during vbpsRegInit as it's only needed for updating.
     496 *
     497 * @returns ERROR_SUCCESS if we successfully opened the destination root, other
     498 *          wise windows error code (remebered).
     499 * @param   pState              The registry modifier state.
     500 */
     501static LSTATUS vbpsRegOpenInterfaceKeys(VBPSREGSTATE *pState)
     502{
     503    unsigned i;
     504    LSTATUS rc;
     505
     506    /*
     507     * Under the root destination.
     508     */
     509    if (pState->hkeyInterfaceRootDst == NULL)
     510    {
     511        rc = RegOpenKeyExA(pState->hkeyClassesRootDst, "Interface", 0 /*fOptions*/, pState->fSamBoth, &pState->hkeyInterfaceRootDst);
     512        AssertMsgReturnStmt(rc == ERROR_SUCCESS, ("%u\n", rc), pState->hkeyInterfaceRootDst = NULL,  pState->rc = rc);
     513    }
     514
     515    /*
     516     * Under the alternative delete locations.
     517     */
     518    i = pState->cAltDeletes;
     519    while (i-- > 0)
     520        if (pState->aAltDeletes[i].hkeyInterface == NULL)
     521        {
     522            rc = RegOpenKeyExA(pState->aAltDeletes[i].hkeyClasses, "Interface", 0 /*fOptions*/, pState->fSamDelete,
     523                               &pState->aAltDeletes[i].hkeyInterface);
     524            if (rc != ERROR_SUCCESS)
     525            {
     526                AssertMsgStmt(rc == ERROR_FILE_NOT_FOUND, ("%u\n", rc), pState->rc = rc);
     527                pState->aAltDeletes[i].hkeyInterface = NULL;
     528            }
     529        }
     530
     531    return ERROR_SUCCESS;
    341532}
    342533
    343534
    344535/** The destination buffer size required by vbpsFormatUuidInCurly. */
    345 #define CURLY_UUID_STR_BUF_SIZE     48
     536#define CURLY_UUID_STR_BUF_SIZE     40
    346537
    347538/**
    348539 * Formats a UUID to a string, inside curly braces.
    349540 *
    350  * @returns ERROR_SUCCESS on success, otherwise windows error code.
    351  * @param   pszUuid             Output buffer of size CURLY_UUID_STR_BUF_SIZE.
    352  * @param   pUuid               The UUID to format.
    353  */
    354 static LSTATUS vbpsFormatUuidInCurly(char *pszUuid, const CLSID *pUuid)
    355 {
    356     unsigned char *pszTmpStr = NULL;
    357     size_t cchTmpStr;
    358     RPC_STATUS rc = UuidToStringA((UUID *)pUuid, &pszTmpStr);
    359     AssertReturnStmt(rc == RPC_S_OK, *pszUuid = '\0', ERROR_OUTOFMEMORY);
    360 
    361     cchTmpStr = strlen((const char *)pszTmpStr);
    362     AssertReturnStmt(cchTmpStr == 36 && cchTmpStr < CURLY_UUID_STR_BUF_SIZE - 3, RpcStringFreeA(&pszTmpStr), ERROR_INVALID_DATA);
    363 
    364     pszUuid[0] = '{';
    365     memcpy(pszUuid + 1, pszTmpStr, cchTmpStr);
    366     pszUuid[1 + cchTmpStr] = '}';
    367     pszUuid[1 + cchTmpStr + 1] = '\0';
    368 
    369     RpcStringFreeA(&pszTmpStr);
    370     return ERROR_SUCCESS;
    371 }
    372 
    373 
    374 /**
    375  * Sets a registry string value.
     541 * @returns @a pszString
     542 * @param   pszString           Output buffer of size CURLY_UUID_STR_BUF_SIZE.
     543 * @param   pUuidIn             The UUID to format.
     544 */
     545static const char *vbpsFormatUuidInCurly(char pszString[CURLY_UUID_STR_BUF_SIZE], const CLSID *pUuidIn)
     546{
     547    static const char s_achDigits[17] = "0123456789abcdef";
     548    PCRTUUID pUuid = (PCRTUUID)pUuidIn;
     549    uint32_t u32TimeLow;
     550    unsigned u;
     551
     552    pszString[ 0] = '{';
     553    u32TimeLow = RT_H2LE_U32(pUuid->Gen.u32TimeLow);
     554    pszString[ 1] = s_achDigits[(u32TimeLow >> 28)/*& 0xf*/];
     555    pszString[ 2] = s_achDigits[(u32TimeLow >> 24) & 0xf];
     556    pszString[ 3] = s_achDigits[(u32TimeLow >> 20) & 0xf];
     557    pszString[ 4] = s_achDigits[(u32TimeLow >> 16) & 0xf];
     558    pszString[ 5] = s_achDigits[(u32TimeLow >> 12) & 0xf];
     559    pszString[ 6] = s_achDigits[(u32TimeLow >>  8) & 0xf];
     560    pszString[ 7] = s_achDigits[(u32TimeLow >>  4) & 0xf];
     561    pszString[ 8] = s_achDigits[(u32TimeLow/*>>0*/)& 0xf];
     562    pszString[ 9] = '-';
     563    u = RT_H2LE_U16(pUuid->Gen.u16TimeMid);
     564    pszString[10] = s_achDigits[(u >> 12)/*& 0xf*/];
     565    pszString[11] = s_achDigits[(u >>  8) & 0xf];
     566    pszString[12] = s_achDigits[(u >>  4) & 0xf];
     567    pszString[13] = s_achDigits[(u/*>>0*/)& 0xf];
     568    pszString[14] = '-';
     569    u = RT_H2LE_U16(pUuid->Gen.u16TimeHiAndVersion);
     570    pszString[15] = s_achDigits[(u >> 12)/*& 0xf*/];
     571    pszString[16] = s_achDigits[(u >>  8) & 0xf];
     572    pszString[17] = s_achDigits[(u >>  4) & 0xf];
     573    pszString[18] = s_achDigits[(u/*>>0*/)& 0xf];
     574    pszString[19] = '-';
     575    pszString[20] = s_achDigits[pUuid->Gen.u8ClockSeqHiAndReserved >> 4];
     576    pszString[21] = s_achDigits[pUuid->Gen.u8ClockSeqHiAndReserved & 0xf];
     577    pszString[22] = s_achDigits[pUuid->Gen.u8ClockSeqLow >> 4];
     578    pszString[23] = s_achDigits[pUuid->Gen.u8ClockSeqLow & 0xf];
     579    pszString[24] = '-';
     580    pszString[25] = s_achDigits[pUuid->Gen.au8Node[0] >> 4];
     581    pszString[26] = s_achDigits[pUuid->Gen.au8Node[0] & 0xf];
     582    pszString[27] = s_achDigits[pUuid->Gen.au8Node[1] >> 4];
     583    pszString[28] = s_achDigits[pUuid->Gen.au8Node[1] & 0xf];
     584    pszString[29] = s_achDigits[pUuid->Gen.au8Node[2] >> 4];
     585    pszString[30] = s_achDigits[pUuid->Gen.au8Node[2] & 0xf];
     586    pszString[31] = s_achDigits[pUuid->Gen.au8Node[3] >> 4];
     587    pszString[32] = s_achDigits[pUuid->Gen.au8Node[3] & 0xf];
     588    pszString[33] = s_achDigits[pUuid->Gen.au8Node[4] >> 4];
     589    pszString[34] = s_achDigits[pUuid->Gen.au8Node[4] & 0xf];
     590    pszString[35] = s_achDigits[pUuid->Gen.au8Node[5] >> 4];
     591    pszString[36] = s_achDigits[pUuid->Gen.au8Node[5] & 0xf];
     592    pszString[37] = '}';
     593    pszString[38] = '\0';
     594
     595    return pszString;
     596
     597}
     598
     599
     600/**
     601 * Sets a registry string value, wide char variant.
    376602 *
    377603 * @returns See RegSetValueExA (errors are remembered in the state).
    378604 * @param   pState              The registry modifier state.
    379  * @param   hKey                The key to add the value to.
     605 * @param   hkey                The key to add the value to.
     606 * @param   pwszValueNm         The value name. NULL for setting the default.
     607 * @param   pwszValue           The value string.
     608 * @param   uLine               The line we're called from.
     609 */
     610static LSTATUS vbpsSetRegValueWW(VBPSREGSTATE *pState, HKEY hkey, PCRTUTF16 pwszValueNm, PCRTUTF16 pwszValue, unsigned uLine)
     611{
     612    DWORD const cbValue = (DWORD)((RTUtf16Len(pwszValue) + 1) * sizeof(RTUTF16));
     613    LSTATUS rc;
     614    Assert(pState->fUpdate);
     615
     616    /*
     617     * If we're not deleting the key prior to updating, we're in gentle update
     618     * mode where we will query if the existing value matches the incoming one.
     619     */
     620    if (!pState->fDelete)
     621    {
     622        DWORD       cbExistingData   = cbValue + 128;
     623        PRTUTF16    pwszExistingData = (PRTUTF16)alloca(cbExistingData);
     624        DWORD       dwExistingType;
     625        rc = RegQueryValueExW(hkey, pwszValueNm, 0 /*Reserved*/, &dwExistingType, (BYTE *)pwszExistingData, &cbExistingData);
     626        if (rc == ERROR_SUCCESS)
     627        {
     628            if (   dwExistingType == REG_SZ
     629                && cbExistingData == cbValue)
     630            {
     631                if (memcmp(pwszValue, pwszExistingData, cbValue) == 0)
     632                    return ERROR_SUCCESS;
     633            }
     634            VBSP_LOG_VALUE_CHANGE(("vbpsSetRegValueWW: Value difference: dwExistingType=%d cbExistingData=%#x cbValue=%#x\n"
     635                                   " hkey=%#x %ls; value name=%ls\n"
     636                                   "existing: %.*Rhxs (%.*ls)\n"
     637                                   "     new: %.*Rhxs (%ls)\n",
     638                                   dwExistingType, cbExistingData, cbValue,
     639                                   hkey, vbpsDebugKeyToWSZ(hkey), pwszValueNm ? pwszValueNm : L"(default)",
     640                                   cbExistingData, pwszExistingData, cbExistingData / sizeof(RTUTF16), pwszExistingData,
     641                                   cbValue, pwszValue, pwszValue));
     642        }
     643        else
     644            Assert(rc == ERROR_FILE_NOT_FOUND || rc == ERROR_MORE_DATA);
     645    }
     646
     647    /*
     648     * Set the value.
     649     */
     650    rc = RegSetValueExW(hkey, pwszValueNm, 0 /*Reserved*/, REG_SZ, (const BYTE *)pwszValue, cbValue);
     651    if (rc == ERROR_SUCCESS)
     652    {
     653        VBSP_LOG_SET_VALUE(("vbpsSetRegValueWW: %ls/%ls=%ls (at %d)\n",
     654                            vbpsDebugKeyToWSZ(hkey), pwszValueNm ? pwszValueNm : L"(Default)", pwszValue, uLine));
     655        return ERROR_SUCCESS;
     656    }
     657
     658    AssertMsgFailed(("%d: '%ls'='%ls' -> %u\n", uLine, pwszValueNm, pwszValue, rc));
     659    pState->rc = rc;
     660    return rc;
     661}
     662
     663
     664/**
     665 * Sets a registry string value.
     666 *
     667 * @returns See RegSetValueExA (errors are remembered in the state).
     668 * @param   pState              The registry modifier state.
     669 * @param   hkey                The key to add the value to.
    380670 * @param   pszValueNm          The value name. NULL for setting the default.
    381671 * @param   pszValue            The value string.
    382672 * @param   uLine               The line we're called from.
    383673 */
    384 static LSTATUS vbpsSetRegValueAA(VBPSREGSTATE *pState, HKEY hKey, const char *pszValueNm, const char *pszValue, unsigned uLine)
    385 {
    386     LSTATUS rc = RegSetValueExA(hKey, pszValueNm, 0 /*Reserved*/, REG_SZ, pszValue, (DWORD)strlen(pszValue) + 1);
     674static LSTATUS vbpsSetRegValueAA(VBPSREGSTATE *pState, HKEY hkey, const char *pszValueNm, const char *pszValue, unsigned uLine)
     675{
     676    DWORD const cbValue = (DWORD)strlen(pszValue) + 1;
     677    LSTATUS rc;
     678    Assert(pState->fUpdate);
     679
     680    /*
     681     * If we're not deleting the key prior to updating, we're in gentle update
     682     * mode where we will query if the existing value matches the incoming one.
     683     */
     684    if (!pState->fDelete)
     685    {
     686        DWORD cbExistingData = cbValue + 128;
     687        char *pszExistingData = alloca(cbExistingData);
     688        DWORD dwExistingType;
     689        rc = RegQueryValueExA(hkey, pszValueNm, 0 /*Reserved*/, &dwExistingType, pszExistingData, &cbExistingData);
     690        if (rc == ERROR_SUCCESS)
     691        {
     692            if (   dwExistingType == REG_SZ
     693                && cbExistingData == cbValue)
     694            {
     695                if (memcmp(pszValue, pszExistingData, cbValue) == 0)
     696                    return ERROR_SUCCESS;
     697                if (memicmp(pszValue, pszExistingData, cbValue) == 0)
     698                    return ERROR_SUCCESS;
     699            }
     700            VBSP_LOG_VALUE_CHANGE(("vbpsSetRegValueAA: Value difference: dwExistingType=%d cbExistingData=%#x cbValue=%#x\n"
     701                                   " hkey=%#x %ls; value name=%s\n"
     702                                   "existing: %.*Rhxs (%.*s)\n"
     703                                   "     new: %.*Rhxs (%s)\n",
     704                                   dwExistingType, cbExistingData, cbValue,
     705                                   hkey, vbpsDebugKeyToWSZ(hkey), pszValueNm ? pszValueNm : "(default)",
     706                                   cbExistingData, pszExistingData, cbExistingData, pszExistingData,
     707                                   cbValue, pszValue, pszValue));
     708        }
     709        else
     710            Assert(rc == ERROR_FILE_NOT_FOUND || rc == ERROR_MORE_DATA);
     711    }
     712
     713    /*
     714     * Set the value.
     715     */
     716    rc = RegSetValueExA(hkey, pszValueNm, 0 /*Reserved*/, REG_SZ, pszValue, cbValue);
     717    if (rc == ERROR_SUCCESS)
     718    {
     719        VBSP_LOG_SET_VALUE(("vbpsSetRegValueAA: %ls/%s=%s (at %d)\n",
     720                            vbpsDebugKeyToWSZ(hkey), pszValueNm ? pszValueNm : "(Default)", pszValue, uLine));
     721        return ERROR_SUCCESS;
     722    }
     723
     724    AssertMsgFailed(("%d: '%s'='%s' -> %u\n", uLine, pszValueNm, pszValue, rc));
     725    pState->rc = rc;
     726    return rc;
     727}
     728
     729
     730/**
     731 * Closes a registry key.
     732 *
     733 * @returns See RegCloseKey (errors are remembered in the state).
     734 * @param   pState              The registry modifier state.
     735 * @param   hkey                The key to close.
     736 * @param   uLine               The line we're called from.
     737 */
     738static LSTATUS vbpsCloseKey(VBPSREGSTATE *pState, HKEY hkey, unsigned uLine)
     739{
     740    LSTATUS rc = RegCloseKey(hkey);
    387741    if (rc == ERROR_SUCCESS)
    388742        return ERROR_SUCCESS;
    389     AssertMsgFailed(("%d: '%s'='%s' -> %u\n", uLine, pszValueNm, pszValue, rc));
    390     return pState->rc = rc;
    391 }
     743
     744    AssertMsgFailed(("%d: close key -> %u\n", uLine, rc));
     745    pState->rc = rc;
     746    return rc;
     747}
     748
    392749
    393750/**
     
    397754 *          state).
    398755 * @param   pState              The registry modifier state.
    399  * @param   hKeyParent          The parent key.
    400  * @param   pszKey              The new key under @a hKeyParent.
    401  * @param   phKey               Where to return the handle to the new key.
     756 * @param   hkeyParent          The parent key.
     757 * @param   pszKey              The new key under @a hkeyParent.
     758 * @param   phkey               Where to return the handle to the new key.
    402759 * @param   uLine               The line we're called from.
    403760 */
    404 static LSTATUS vbpsCreateRegKeyA(VBPSREGSTATE *pState, HKEY hKeyParent, const char *pszKey, PHKEY phKey, unsigned uLine)
    405 {
     761static LSTATUS vbpsCreateRegKeyA(VBPSREGSTATE *pState, HKEY hkeyParent, const char *pszKey, PHKEY phkey, unsigned uLine)
     762{
     763    /*
     764     * This will open if it exists and create if new, which is exactly what we want.
     765     */
    406766    HKEY hNewKey;
    407     LSTATUS rc = RegCreateKeyExA(hKeyParent, pszKey, 0 /*Reserved*/, NULL /*pszClass*/, 0 /*fOptions*/,
    408                                  pState->fSamBoth, NULL /*pSecAttr*/, &hNewKey, NULL /*pdwDisposition*/);
     767    DWORD dwDisposition = 0;
     768    LSTATUS rc = RegCreateKeyExA(hkeyParent, pszKey, 0 /*Reserved*/, NULL /*pszClass*/, 0 /*fOptions*/,
     769                                 pState->fSamBoth, NULL /*pSecAttr*/, &hNewKey, &dwDisposition);
    409770    if (rc == ERROR_SUCCESS)
    410         *phKey = hNewKey;
     771    {
     772        *phkey = hNewKey;
     773        if (dwDisposition == REG_CREATED_NEW_KEY)
     774            VBSP_LOG_NEW_KEY(("vbpsCreateRegKeyA: %ls/%s (at %d)\n", vbpsDebugKeyToWSZ(hkeyParent), pszKey, uLine));
     775    }
    411776    else
    412777    {
    413778        AssertMsgFailed(("%d: create key '%s' -> %u\n", uLine, pszKey,  rc));
    414779        pState->rc = rc;
    415         *phKey = NULL;
     780        *phkey = NULL;
    416781    }
    417782    return rc;
     
    425790 *          state).
    426791 * @param   pState              The registry modifier state.
    427  * @param   hKeyParent          The parent key.
    428  * @param   pszKey              The new key under @a hKeyParent.
     792 * @param   hkeyParent          The parent key.
     793 * @param   pszKey              The new key under @a hkeyParent.
    429794 * @param   pszValue            The value string.
    430795 * @param   uLine               The line we're called from.
    431796 */
    432 static LSTATUS vbpsCreateRegKeyWithDefaultValueAA(VBPSREGSTATE *pState, HKEY hKeyParent, const char *pszKey,
     797static LSTATUS vbpsCreateRegKeyWithDefaultValueAA(VBPSREGSTATE *pState, HKEY hkeyParent, const char *pszKey,
    433798                                                  const char *pszValue, unsigned uLine)
    434799{
    435800    HKEY hNewKey;
    436     LSTATUS rc = vbpsCreateRegKeyA(pState, hKeyParent, pszKey, &hNewKey, uLine);
     801    LSTATUS rc = vbpsCreateRegKeyA(pState, hkeyParent, pszKey, &hNewKey, uLine);
    437802    if (rc == ERROR_SUCCESS)
    438803    {
    439804        rc = vbpsSetRegValueAA(pState, hNewKey, NULL /*pszValueNm*/, pszValue, uLine);
    440         RegCloseKey(hNewKey);
     805        vbpsCloseKey(pState, hNewKey, uLine);
    441806    }
    442807    else
     
    450815
    451816/**
    452  * Creates a registry key with a default string value, return the key.
     817 * Creates a registry key with a default wide string value.
    453818 *
    454819 * @returns See RegCreateKeyA and RegSetValueExA (errors are remembered in the
    455820 *          state).
    456821 * @param   pState              The registry modifier state.
    457  * @param   hKeyParent          The parent key.
    458  * @param   pszKey              The new key under @a hKeyParent.
     822 * @param   hkeyParent          The parent key.
     823 * @param   pszKey              The new key under @a hkeyParent.
     824 * @param   pwszValue           The value string.
     825 * @param   uLine               The line we're called from.
     826 */
     827static LSTATUS vbpsCreateRegKeyWithDefaultValueAW(VBPSREGSTATE *pState, HKEY hkeyParent, const char *pszKey,
     828                                                  PCRTUTF16 pwszValue, unsigned uLine)
     829{
     830    HKEY hNewKey;
     831    LSTATUS rc = vbpsCreateRegKeyA(pState, hkeyParent, pszKey, &hNewKey, uLine);
     832    if (rc == ERROR_SUCCESS)
     833    {
     834        rc = vbpsSetRegValueWW(pState, hNewKey, NULL /*pwszValueNm*/, pwszValue, uLine);
     835        vbpsCloseKey(pState, hNewKey, uLine);
     836    }
     837    else
     838    {
     839        AssertMsgFailed(("%d: create key '%s'(/Default='%ls') -> %u\n", uLine, pszKey, pwszValue, rc));
     840        pState->rc = rc;
     841    }
     842    return rc;
     843}
     844
     845
     846/**
     847 * Creates a registry key with a default string value, return the key.
     848 *
     849 * @returns See RegCreateKeyA and RegSetValueExA (errors are remembered in the
     850 *          state).
     851 * @param   pState              The registry modifier state.
     852 * @param   hkeyParent          The parent key.
     853 * @param   pszKey              The new key under @a hkeyParent.
    459854 * @param   pszValue            The value string.
    460  * @param   phKey               Where to return the handle to the new key.
     855 * @param   phkey               Where to return the handle to the new key.
    461856 * @param   uLine               The line we're called from.
    462857 */
    463 static LSTATUS vbpsCreateRegKeyWithDefaultValueAAEx(VBPSREGSTATE *pState, HKEY hKeyParent, const char *pszKey,
    464                                                     const char *pszValue, PHKEY phKey, unsigned uLine)
     858static LSTATUS vbpsCreateRegKeyWithDefaultValueAAEx(VBPSREGSTATE *pState, HKEY hkeyParent, const char *pszKey,
     859                                                    const char *pszValue, PHKEY phkey, unsigned uLine)
    465860{
    466861    HKEY hNewKey;
    467     LSTATUS rc = vbpsCreateRegKeyA(pState, hKeyParent, pszKey, &hNewKey, uLine);
     862    LSTATUS rc = vbpsCreateRegKeyA(pState, hkeyParent, pszKey, &hNewKey, uLine);
    468863    if (rc == ERROR_SUCCESS)
    469864    {
    470865        rc = vbpsSetRegValueAA(pState, hNewKey, NULL /*pszValueNm*/, pszValue, uLine);
    471         *phKey = hNewKey;
     866        *phkey = hNewKey;
    472867    }
    473868    else
     
    475870        AssertMsgFailed(("%d: create key '%s'(/Default='%s') -> %u\n", uLine, pszKey, pszValue, rc));
    476871        pState->rc = rc;
    477         *phKey = NULL;
    478     }
     872        *phkey = NULL;
     873    }
     874    return rc;
     875}
     876
     877
     878/**
     879 * Recursively deletes a registry key.
     880 *
     881 * @returns See SHDeleteKeyA (errors are remembered in the state).
     882 * @param   pState              The registry modifier state.
     883 * @param   hkeyParent          The parent key.
     884 * @param   pszKey              The key under @a hkeyParent that should be
     885 *                              deleted.
     886 * @param   uLine               The line we're called from.
     887 */
     888static LSTATUS vbpsDeleteKeyRecursiveA(VBPSREGSTATE *pState, HKEY hkeyParent, const char *pszKey, unsigned uLine)
     889{
     890    LSTATUS rc;
     891
     892    Assert(pState->fDelete);
     893    Assert(pszKey);
     894    AssertReturn(*pszKey != '\0', pState->rc = ERROR_INVALID_PARAMETER);
     895
     896    rc = SHDeleteKeyA(hkeyParent, pszKey);
     897    if (rc == ERROR_SUCCESS || rc == ERROR_FILE_NOT_FOUND)
     898        return ERROR_SUCCESS;
     899
     900    AssertMsgFailed(("%d: delete key '%s' -> %u\n", uLine, pszKey, rc));
     901    pState->rc = rc;
    479902    return rc;
    480903}
     
    495918    Assert(*pszAppId == '{');
    496919
    497     /* Always unregister. */
    498     if (pState->hkeyAltClassesRootsUnreg)
    499     {
    500         rc = RegOpenKeyExW(pState->hkeyAltClassesRootsUnreg, L"AppID", 0 /*fOptions*/, pState->fSamUnreg, &hkeyAppIds);
    501         AssertMsgStmt(rc == ERROR_SUCCESS || rc == ERROR_FILE_NOT_FOUND, ("%u\n", rc), pState->rc = rc);
    502         if (rc == ERROR_SUCCESS)
     920    /*
     921     * Delete.
     922     */
     923    if (pState->fDelete)
     924    {
     925        unsigned i = pState->cAltDeletes;
     926        while (i-- > 0)
    503927        {
    504             rc = SHDeleteKeyA(hkeyAppIds, pszAppId);
     928            rc = RegOpenKeyExW(pState->aAltDeletes[i].hkeyClasses, L"AppID", 0 /*fOptions*/, pState->fSamDelete, &hkeyAppIds);
    505929            AssertMsgStmt(rc == ERROR_SUCCESS || rc == ERROR_FILE_NOT_FOUND, ("%u\n", rc), pState->rc = rc);
    506             RegCloseKey(hkeyAppIds);
     930            if (rc == ERROR_SUCCESS)
     931            {
     932                vbpsDeleteKeyRecursiveA(pState, hkeyAppIds, pszAppId, __LINE__);
     933                vbpsCloseKey(pState, hkeyAppIds, __LINE__);
     934            }
    507935        }
    508936    }
     
    510938    rc = RegOpenKeyExW(pState->hkeyClassesRootDst, L"AppID", 0 /*fOptions*/, pState->fSamBoth, &hkeyAppIds);
    511939    AssertMsgReturn(rc == ERROR_SUCCESS, ("%u\n", rc), pState->rc = rc);
    512     if (rc == ERROR_SUCCESS)
    513     {
    514         rc = SHDeleteKeyA(hkeyAppIds, pszAppId);
    515         AssertMsgStmt(rc == ERROR_SUCCESS || rc == ERROR_FILE_NOT_FOUND, ("%u\n", rc), pState->rc = rc);
    516     }
    517 
    518     /* Register */
    519     if (!pState->fUnregisterOnly)
     940
     941    if (pState->fDelete)
     942        vbpsDeleteKeyRecursiveA(pState, hkeyAppIds, pszAppId, __LINE__);
     943
     944    /*
     945     * Update.
     946    */
     947    if (pState->fUpdate)
    520948        vbpsCreateRegKeyWithDefaultValueAA(pState, hkeyAppIds, pszAppId, pszDescription, __LINE__);
    521949
    522     RegCloseKey(hkeyAppIds);
     950    vbpsCloseKey(pState, hkeyAppIds, __LINE__);
    523951
    524952    return pState->rc;
     
    544972
    545973    /*
    546      * Always unregister.
    547      */
    548     if (pState->hkeyAltClassesRootsUnreg)
    549     {
    550         rc = SHDeleteKeyA(pState->hkeyAltClassesRootsUnreg, pszClassName);
    551         AssertMsgStmt(rc == ERROR_SUCCESS || rc == ERROR_FILE_NOT_FOUND, ("%u\n", rc), pState->rc = rc);
    552     }
    553 
    554     rc = SHDeleteKeyA(pState->hkeyClassesRootDst, pszClassName);
    555     AssertMsgStmt(rc == ERROR_SUCCESS || rc == ERROR_FILE_NOT_FOUND, ("%u\n", rc), pState->rc = rc);
    556 
    557     if (!pState->fUnregisterOnly)
    558     {
    559         /*
    560          * Register
    561          */
     974     * Delete.
     975     */
     976    if (pState->fDelete)
     977    {
     978        unsigned i = pState->cAltDeletes;
     979        while (i-- > 0)
     980            vbpsDeleteKeyRecursiveA(pState, pState->aAltDeletes[i].hkeyClasses, pszClassName, __LINE__);
     981        vbpsDeleteKeyRecursiveA(pState, pState->hkeyClassesRootDst, pszClassName, __LINE__);
     982    }
     983
     984    /*
     985     * Update.
     986     */
     987    if (pState->fUpdate)
     988    {
    562989        /* pszClassName/Default = description. */
    563990        HKEY hkeyClass;
     
    569996
    570997            /* CLSID/Default = pClsId. */
    571             rc = vbpsFormatUuidInCurly(szClsId, pClsId);
    572             AssertMsgStmt(rc == ERROR_SUCCESS, ("%u\n", rc), pState->rc = rc);
    573             if (rc == ERROR_SUCCESS)
    574                 vbpsCreateRegKeyWithDefaultValueAA(pState, hkeyClass, "CLSID", szClsId, __LINE__);
     998            vbpsCreateRegKeyWithDefaultValueAA(pState, hkeyClass, "CLSID", vbpsFormatUuidInCurly(szClsId, pClsId), __LINE__);
    575999
    5761000            /* CurVer/Default = pszClassName+Suffix. */
     
    5861010            }
    5871011
    588             RegCloseKey(hkeyClass);
     1012            vbpsCloseKey(pState, hkeyClass, __LINE__);
    5891013        }
    5901014    }
     
    6231047    LSTATUS rc;
    6241048    char szClsId[CURLY_UUID_STR_BUF_SIZE];
    625     char szTypeLibId[CURLY_UUID_STR_BUF_SIZE];
    6261049
    6271050    Assert(!pszAppId || *pszAppId == '{');
    628     Assert((pwszVBoxDir == NULL && pState->fUnregisterOnly) || pwszVBoxDir[RTUtf16Len(pwszVBoxDir) - 1] == '\\');
    629 
    630     /*
    631      * Format the UUID first to get it over with.  We always need CLSID.
    632      */
    633     rc = vbpsFormatUuidInCurly(szClsId, pClsId);
    634     AssertMsgReturn(rc == ERROR_SUCCESS, ("%u\n", rc), pState->rc = rc);
    635     if (pTypeLibId)
    636     {
    637         rc = vbpsFormatUuidInCurly(szTypeLibId, pTypeLibId);
    638         AssertMsgReturn(rc == ERROR_SUCCESS, ("%u\n", rc), pState->rc = rc);
    639     }
    640     else
    641         szTypeLibId[0] = '\0';
    642 
    643     /*
    644      * Always unregister.
    645      */
    646     if (pState->hkeyAltClsidRootsUnreg)
    647     {
    648         rc = SHDeleteKeyA(pState->hkeyAltClsidRootsUnreg, szClsId);
    649         AssertMsgStmt(rc == ERROR_SUCCESS || rc == ERROR_FILE_NOT_FOUND, ("%u\n", rc), pState->rc = rc);
    650     }
    651 
    652     rc = SHDeleteKeyA(pState->hkeyClsidRootDst, szClsId);
    653     AssertMsgStmt(rc == ERROR_SUCCESS || rc == ERROR_FILE_NOT_FOUND, ("%u\n", rc), pState->rc = rc);
    654 
    655     if (!pState->fUnregisterOnly)
    656     {
    657         /*
    658          * Register
    659          */
     1051    Assert((pwszVBoxDir == NULL && !pState->fUpdate) || pwszVBoxDir[RTUtf16Len(pwszVBoxDir) - 1] == '\\');
     1052
     1053    /*
     1054     * We need this, whatever we end up having to do.
     1055     */
     1056    vbpsFormatUuidInCurly(szClsId, pClsId);
     1057
     1058    /*
     1059     * Delete.
     1060     */
     1061    if (pState->fDelete)
     1062    {
     1063        unsigned i = pState->cAltDeletes;
     1064        while (i-- > 0)
     1065            vbpsDeleteKeyRecursiveA(pState, pState->aAltDeletes[i].hkeyClsid, szClsId, __LINE__);
     1066        vbpsDeleteKeyRecursiveA(pState, pState->hkeyClsidRootDst, szClsId, __LINE__);
     1067    }
     1068
     1069    /*
     1070     * Update.
     1071     */
     1072    if (pState->fUpdate)
     1073    {
    6601074        HKEY hkeyClass;
    6611075        rc = vbpsCreateRegKeyWithDefaultValueAAEx(pState, pState->hkeyClsidRootDst, szClsId, pszDescription,
     
    6851099                *pwszCur++ = '\0';      /* included, so ++. */
    6861100
    687                 rc = RegSetValueExW(hkeyServerType, NULL /*pszValueNm*/, 0 /*Reserved*/,
    688                                     REG_SZ, (const BYTE *)&wszModule[0], (DWORD)((uintptr_t)pwszCur - (uintptr_t)&wszModule[0]));
    689                 AssertMsgStmt(rc == ERROR_SUCCESS, ("%u\n", rc), pState->rc = rc);
     1101                vbpsSetRegValueWW(pState, hkeyServerType, NULL /*pszValueNm*/, wszModule, __LINE__);
    6901102
    6911103                /* pszServerType/ThreadingModel = pszThreading Model. */
     
    6931105                    vbpsSetRegValueAA(pState, hkeyServerType, "ThreadingModel", pszThreadingModel, __LINE__);
    6941106
    695                 RegCloseKey(hkeyServerType);
     1107                vbpsCloseKey(pState, hkeyServerType, __LINE__);
    6961108            }
    6971109
     
    7121124            /* TypeLib/Default = pTypeLibId. */
    7131125            if (pTypeLibId)
    714                 vbpsCreateRegKeyWithDefaultValueAA(pState, hkeyClass, "TypeLib", szTypeLibId, __LINE__);
    715 
    716             RegCloseKey(hkeyClass);
     1126            {
     1127                char szTypeLibId[CURLY_UUID_STR_BUF_SIZE];
     1128                vbpsCreateRegKeyWithDefaultValueAA(pState, hkeyClass, "TypeLib",
     1129                                                   vbpsFormatUuidInCurly(szTypeLibId, pTypeLibId), __LINE__);
     1130            }
     1131
     1132            vbpsCloseKey(pState, hkeyClass, __LINE__);
    7171133        }
    7181134    }
     
    7541170                        "VirtualBox.VirtualBoxClient", ".1",
    7551171                        &LIBID_VirtualBox, "InprocServer32", pwszVBoxDir, pszInprocDll, "Free");
    756 
    757 }
    758 
    759 #ifndef VBOX_PROXY_STUB_32_ON_64
    760 void RegisterOtherProxyStubAndTypelibDll(VBPSREGSTATE *pState, PCRTUTF16 pwszVBoxDir, bool fIs32On64)
    761 {
    762     if (!pState->fUnregisterOnly)
    763     {
    764         const char *pszWinXx = !fIs32On64 ? "win64"             : "win32";
    765         const char *pszPsDll = !fIs32On64 ? "VBoxProxyStub.dll" : "VBoxProxyStub-x86.dll";
    766         char szTypeLibId[CURLY_UUID_STR_BUF_SIZE];
     1172}
     1173
     1174
     1175/**
     1176 * Updates the VBox type lib registration.
     1177 *
     1178 * This is only used when updating COM registrations during com::Initialize.
     1179 * For normal registration and unregistrations we use the RegisterTypeLib and
     1180 * UnRegisterTypeLib APIs.
     1181 *
     1182 * @param   pState              The registry modifier state.
     1183 * @param   pwszVBoxDir         The VirtualBox install directory (unicode),
     1184 *                              trailing slash.
     1185 * @param   fIs32On64           Set if we're registering the 32-bit proxy stub
     1186 *                              on a 64-bit system.
     1187 */
     1188static void vbpsUpdateTypeLibRegistration(VBPSREGSTATE *pState, PCRTUTF16 pwszVBoxDir, bool fIs32On64)
     1189{
     1190    const char * const pszTypeLibDll = !fIs32On64 ? "VBoxProxyStub.dll" : "x86\\VBoxProxyStub-x86.dll";
     1191    const char * const pszWinXx      = !fIs32On64 ? "win64"             : "win32";
     1192    const char * const pszDescription = "VirtualBox Type Library";
     1193
     1194    char szTypeLibId[CURLY_UUID_STR_BUF_SIZE];
     1195    HKEY hkeyTypeLibs;
     1196    HKEY hkeyTypeLibId;
     1197    LSTATUS rc;
     1198
     1199    Assert(pState->fUpdate && !pState->fDelete);
     1200
     1201    /*
     1202     * Type library registration (w/o interfaces).
     1203     */
     1204
     1205    /* Open Classes/TypeLib/. */
     1206    rc = vbpsCreateRegKeyA(pState, pState->hkeyClassesRootDst, "TypeLib", &hkeyTypeLibs, __LINE__);
     1207    AssertReturnVoid(rc == ERROR_SUCCESS);
     1208
     1209    /* Create TypeLib/{UUID}. */
     1210    rc = vbpsCreateRegKeyA(pState, hkeyTypeLibs, vbpsFormatUuidInCurly(szTypeLibId, &LIBID_VirtualBox), &hkeyTypeLibId, __LINE__);
     1211    if (rc == ERROR_SUCCESS)
     1212    {
     1213        /* {UUID}/Major.Minor/Default = pszDescription. */
     1214        HKEY hkeyMajMin;
    7671215        char szMajMin[64];
    768         HKEY hKeyTypeLibs;
    769         HKEY hKeyTypeLibId;
    770         HKEY hKeyMajMin;
    771         HKEY hKey0;
    772         HKEY hKeyWinXx;
    773         LSTATUS rc;
    774 
    775         /* Proxy stub factory class ID. */
    776         VbpsRegisterClassId(pState, &g_ProxyClsId, "PSFactoryBuffer", NULL /*pszAppId*/,
    777                             NULL /*pszClassName*/, NULL /*pszCurClassNameVerSuffix*/, NULL /*pTypeLibId*/,
    778                             "InprocServer32", pwszVBoxDir, pszPsDll, "Both");
    779 
    780         /*
    781          * Typelib DLL.
    782          */
    783         rc = vbpsFormatUuidInCurly(szTypeLibId, &LIBID_VirtualBox);
    784         AssertMsgReturnVoidStmt(rc == ERROR_SUCCESS, ("%u\n", rc), pState->rc = rc);
    785 
    786         rc = RegOpenKeyExA(pState->hkeyClassesRootDst, "TypeLib", 0 /*fOptions*/, pState->fSamBoth, &hKeyTypeLibs);
    787         AssertMsgReturnVoidStmt(rc == ERROR_SUCCESS, ("%u\n", rc), pState->rc = rc);
    788         rc = RegOpenKeyExA(hKeyTypeLibs, szTypeLibId, 0 /*fOptions*/, pState->fSamBoth, &hKeyTypeLibId);
    789         if (rc == ERROR_FILE_NOT_FOUND)
    790             rc = vbpsCreateRegKeyA(pState, hKeyTypeLibs, szTypeLibId, &hKeyTypeLibId, __LINE__);
    791         RegCloseKey(hKeyTypeLibs);
    792 
    793         AssertMsgReturnVoidStmt(rc == ERROR_SUCCESS, ("%u\n", rc), pState->rc = rc);
    794 
    795         /* Major.Minor/Default = Name. */
    7961216        sprintf(szMajMin, "%u.%u", kTypeLibraryMajorVersion, kTypeLibraryMinorVersion);
    797         rc = RegOpenKeyExA(hKeyTypeLibId, szMajMin, 0 /*fOptions*/, pState->fSamBoth, &hKeyMajMin);
    798         if (rc == ERROR_FILE_NOT_FOUND)
    799             rc = vbpsCreateRegKeyWithDefaultValueAAEx(pState, hKeyTypeLibId, szMajMin, "VirtualBox Type Library",
    800                                                       &hKeyMajMin, __LINE__);
    801         RegCloseKey(hKeyTypeLibId);
    802         AssertMsgReturnVoidStmt(rc == ERROR_SUCCESS, ("%u\n", rc), pState->rc = rc);
    803 
    804         /* 0/. */
    805         rc = RegOpenKeyExA(hKeyMajMin, "0", 0 /*fOptions*/, pState->fSamBoth, &hKey0);
    806         if (rc == ERROR_FILE_NOT_FOUND)
    807             rc = vbpsCreateRegKeyA(pState, hKeyMajMin, "0", &hKey0, __LINE__);
    808         RegCloseKey(hKeyMajMin);
    809         AssertMsgReturnVoidStmt(rc == ERROR_SUCCESS, ("%u\n", rc), pState->rc = rc);
    810 
    811         /* winXx/Default = VBoxProxyStub. */
    812         rc = RegOpenKeyExA(hKey0, pszWinXx, 0 /*fOptions*/, pState->fSamBoth, &hKeyWinXx);
    813         if (rc == ERROR_FILE_NOT_FOUND)
     1217        rc = vbpsCreateRegKeyWithDefaultValueAAEx(pState, hkeyTypeLibId, szMajMin, pszDescription, &hkeyMajMin, __LINE__);
     1218        if (rc == ERROR_SUCCESS)
    8141219        {
    815             RTUTF16 wszDllPath[MAX_PATH * 2];
    816 
    817             rc = RTUtf16Copy(wszDllPath, MAX_PATH, pwszVBoxDir); AssertRC(rc);
    818             rc = RTUtf16CatAscii(wszDllPath, MAX_PATH * 2, pszPsDll); AssertRC(rc);
    819 
    820             rc = vbpsCreateRegKeyA(pState, hKey0, pszWinXx, &hKeyWinXx, __LINE__);
     1220            RTUTF16 wszBuf[MAX_PATH * 2];
     1221            size_t  off;
     1222
     1223            /* {UUID}/Major.Minor/0. */
     1224            HKEY hkey0;
     1225            rc = vbpsCreateRegKeyA(pState, hkeyMajMin, "0", &hkey0, __LINE__);
    8211226            if (rc == ERROR_SUCCESS)
    8221227            {
    823                 rc = RegSetValueExW(hKeyWinXx, NULL /*pszValueNm*/, 0 /*Reserved*/,
    824                                     REG_SZ, (const BYTE *)&wszDllPath[0], (DWORD)((RTUtf16Len(wszDllPath) + 1 )* 2));
    825                 AssertMsgStmt(rc == ERROR_SUCCESS, ("%u\n", rc), pState->rc = rc);
     1228                /* {UUID}/Major.Minor/0/winXX/Default = VBoxProxyStub. */
     1229                rc = RTUtf16Copy(wszBuf, MAX_PATH, pwszVBoxDir); AssertRC(rc);
     1230                rc = RTUtf16CatAscii(wszBuf, MAX_PATH * 2, pszTypeLibDll); AssertRC(rc);
     1231
     1232                vbpsCreateRegKeyWithDefaultValueAW(pState, hkey0, pszWinXx, wszBuf, __LINE__);
     1233                vbpsCloseKey(pState, hkey0, __LINE__);
     1234            }
     1235
     1236            /* {UUID}/Major.Minor/FLAGS */
     1237            vbpsCreateRegKeyWithDefaultValueAA(pState, hkeyMajMin, "FLAGS", "0", __LINE__);
     1238
     1239            /* {UUID}/Major.Minor/HELPDIR */
     1240            rc = RTUtf16Copy(wszBuf, MAX_PATH, pwszVBoxDir); AssertRC(rc);
     1241            off = RTUtf16Len(wszBuf);
     1242            while (off > 2 && wszBuf[off - 2] != ':' && RTPATH_IS_SLASH(wszBuf[off - 1]))
     1243                off--;
     1244            wszBuf[off] = '\0';
     1245            vbpsCreateRegKeyWithDefaultValueAW(pState, hkeyMajMin, "HELPDIR", wszBuf, __LINE__);
     1246
     1247            vbpsCloseKey(pState, hkeyMajMin, __LINE__);
     1248        }
     1249        vbpsCloseKey(pState, hkeyTypeLibId, __LINE__);
     1250    }
     1251    vbpsCloseKey(pState, hkeyTypeLibs, __LINE__);
     1252}
     1253
     1254
     1255/**
     1256 * Update the VBox proxy stub registration.
     1257 *
     1258 * This is only used when updating COM registrations during com::Initialize.
     1259 * For normal registration and unregistrations we use the NdrDllRegisterProxy
     1260 * and NdrDllUnregisterProxy.
     1261 *
     1262 * @param   pState              The registry modifier state.
     1263 * @param   pwszVBoxDir         The VirtualBox install directory (unicode),
     1264 *                              trailing slash.
     1265 * @param   fIs32On64           Set if we're registering the 32-bit proxy stub
     1266 *                              on a 64-bit system.
     1267 */
     1268static void vbpsUpdateProxyStubRegistration(VBPSREGSTATE *pState, PCRTUTF16 pwszVBoxDir, bool fIs32On64)
     1269{
     1270    /*
     1271     * Register the proxy stub factory class ID.
     1272     * It's simple compared to the VBox classes, thus all the NULL parameters.
     1273     */
     1274    const char *pszPsDll = !fIs32On64 ? "VBoxProxyStub.dll" : "x86\\VBoxProxyStub-x86.dll";
     1275    Assert(pState->fUpdate && !pState->fDelete);
     1276    VbpsRegisterClassId(pState, &g_ProxyClsId, "PSFactoryBuffer", NULL /*pszAppId*/,
     1277                        NULL /*pszClassName*/, NULL /*pszCurClassNameVerSuffix*/, NULL /*pTypeLibId*/,
     1278                        "InprocServer32", pwszVBoxDir, pszPsDll, "Both");
     1279}
     1280
     1281
     1282/**
     1283 * Updates the VBox interface registrations.
     1284 *
     1285 * This is only used when updating COM registrations during com::Initialize.
     1286 * For normal registration and unregistrations we use the NdrDllRegisterProxy
     1287 * and NdrDllUnregisterProxy.
     1288 *
     1289 * @param   pState              The registry modifier state.
     1290 * @param   pwszVBoxDir         The VirtualBox install directory (unicode),
     1291 *                              trailing slash.
     1292 * @param   fIs32On64           Set if we're registering the 32-bit proxy stub
     1293 *                              on a 64-bit system.
     1294 */
     1295static void vbpsUpdateInterfaceRegistrations(VBPSREGSTATE *pState)
     1296{
     1297    const ProxyFileInfo **ppProxyFile = &g_apProxyFiles[0];
     1298    const ProxyFileInfo  *pProxyFile;
     1299    LSTATUS               rc;
     1300    char                  szProxyClsId[CURLY_UUID_STR_BUF_SIZE];
     1301
     1302    vbpsFormatUuidInCurly(szProxyClsId, &g_ProxyClsId);
     1303
     1304    Assert(pState->fUpdate && !pState->fDelete);
     1305    rc = vbpsRegOpenInterfaceKeys(pState);
     1306    AssertReturnVoid(rc == ERROR_SUCCESS);
     1307
     1308    /*
     1309     * We walk the proxy file list (even if we only have one).
     1310     */
     1311    while ((pProxyFile = *ppProxyFile++) != NULL)
     1312    {
     1313        const PCInterfaceStubVtblList * const   papStubVtbls  = pProxyFile->pStubVtblList;
     1314        const char * const                     *papszNames    = pProxyFile->pNamesArray;
     1315        unsigned                                iIf           = pProxyFile->TableSize;
     1316        AssertStmt(iIf < 1024, iIf = 0);
     1317        Assert(pProxyFile->TableVersion == 2);
     1318
     1319        /*
     1320         * Walk the interfaces in that file, picking data from the various tables.
     1321         */
     1322        while (iIf-- > 0)
     1323        {
     1324            char                szIfId[CURLY_UUID_STR_BUF_SIZE];
     1325            const char * const  pszIfNm  = papszNames[iIf];
     1326            size_t const        cchIfNm  = RT_VALID_PTR(pszIfNm) ? strlen(pszIfNm) : 0;
     1327            char                szMethods[32];
     1328            uint32_t const      cMethods = papStubVtbls[iIf]->header.DispatchTableCount;
     1329            HKEY                hkeyIfId;
     1330
     1331            AssertReturnVoidStmt(cchIfNm >= 3 && cchIfNm <= 72, pState->rc = ERROR_INVALID_DATA);
     1332
     1333            AssertReturnVoidStmt(cMethods >= 3 && cMethods < 1024, pState->rc = ERROR_INVALID_DATA);
     1334            sprintf(szMethods, "%u", cMethods);
     1335
     1336            AssertReturnVoid(rc == ERROR_SUCCESS);
     1337
     1338            rc = vbpsCreateRegKeyWithDefaultValueAAEx(pState, pState->hkeyInterfaceRootDst,
     1339                                                      vbpsFormatUuidInCurly(szIfId, papStubVtbls[iIf]->header.piid),
     1340                                                      pszIfNm, &hkeyIfId, __LINE__);
     1341            if (rc == ERROR_SUCCESS)
     1342            {
     1343                vbpsCreateRegKeyWithDefaultValueAA(pState, hkeyIfId, "ProxyStubClsid32", szProxyClsId, __LINE__);
     1344                vbpsCreateRegKeyWithDefaultValueAA(pState, hkeyIfId, "NumMethods", szMethods, __LINE__);
     1345                /** @todo Not having the typelib here means we'll have to fix the orphan cleanup
     1346                 *        code below. */
     1347
     1348                vbpsCloseKey(pState, hkeyIfId, __LINE__);
    8261349            }
    8271350        }
    828         RegCloseKey(hKey0);
    829         AssertMsgReturnVoidStmt(rc == ERROR_SUCCESS, ("%u\n", rc), pState->rc = rc);
    830         RegCloseKey(hKeyWinXx);
    831     }
    832 
    833 }
     1351    }
     1352}
     1353
     1354
     1355static bool vbpsIsUpToDate(VBPSREGSTATE *pState)
     1356{
     1357    /** @todo read some registry key and */
     1358    NOREF(pState);
     1359    return false;
     1360}
     1361
     1362static bool vbpsMarkUpToDate(VBPSREGSTATE *pState)
     1363{
     1364    /** @todo write the key vbpsIsUpToDate uses, if pState indicates success. */
     1365    NOREF(pState);
     1366    return false;
     1367}
     1368
     1369
     1370
     1371/**
     1372 * Strips the stub dll name and any x86 subdir off the full DLL path to get a
     1373 * path to the VirtualBox application directory.
     1374 *
     1375 * @param   pwszDllPath     The path to strip, returns will end with a slash.
     1376 */
     1377static void vbpsDllPathToVBoxDir(PRTUTF16 pwszDllPath)
     1378{
     1379    RTUTF16 wc;
     1380    size_t off = RTUtf16Len(pwszDllPath);
     1381    while (   off > 0
     1382           && (   (wc = pwszDllPath[off - 1]) >= 127U
     1383               || !RTPATH_IS_SEP((unsigned char)wc)))
     1384        off--;
     1385
     1386#ifdef VBOX_IN_32_ON_64_MAIN_API
     1387    /*
     1388     * The -x86 variant is in a x86 subdirectory, drop it.
     1389     */
     1390    while (   off > 0
     1391           && (   (wc = pwszDllPath[off - 1]) < 127U
     1392               && RTPATH_IS_SEP((unsigned char)wc)))
     1393        off--;
     1394    while (   off > 0
     1395           && (   (wc = pwszDllPath[off - 1]) >= 127U
     1396               || !RTPATH_IS_SEP((unsigned char)wc)))
     1397        off--;
    8341398#endif
    835 
    836 
    837 HRESULT RegisterXidlModulesAndClasses(PRTUTF16 pwszDllName, bool fUnregisterOnly)
    838 {
    839     VBPSREGSTATE State;
    840     LSTATUS rc;
    841 
    842     /*
    843      * Drop the filename and get the directory containing the DLL.
    844      */
    845     if (!fUnregisterOnly)
    846     {
    847         RTUTF16 wc;
    848         size_t off = RTUtf16Len(pwszDllName);
    849         while (   off > 0
    850                && (   (wc = pwszDllName[off - 1]) >= 127U
    851                    || !RTPATH_IS_SEP((unsigned char)wc)))
    852             off--;
    853 #ifdef VBOX_PROXY_STUB_32_ON_64
    854         /* The -x86 variant is in a x86 subdirectory, drop it. */
    855         while (   off > 0
    856                && (   (wc = pwszDllName[off - 1]) < 127U
    857                    && RTPATH_IS_SEP((unsigned char)wc)))
    858             off--;
    859         while (   off > 0
    860                && (   (wc = pwszDllName[off - 1]) >= 127U
    861                    || !RTPATH_IS_SEP((unsigned char)wc)))
    862             off--;
     1399    pwszDllPath[off] = '\0';
     1400}
     1401
     1402
     1403/**
     1404 * Wrapper around RegisterXidlModulesAndClassesGenerated for the convenience of
     1405 * the standard registration entry points.
     1406 *
     1407 * @returns COM status code.
     1408 * @param   pwszVBoxDir         The VirtualBox install directory (unicode),
     1409 *                              trailing slash.
     1410 * @param   fDelete             Whether to delete registration keys and values.
     1411 * @param   fUpdate             Whether to update registration keys and values.
     1412 */
     1413HRESULT RegisterXidlModulesAndClasses(PRTUTF16 pwszVBoxDir, bool fDelete, bool fUpdate)
     1414{
     1415#ifdef VBOX_IN_32_ON_64_MAIN_API
     1416    bool const      fIs32On64 = true;
     1417#else
     1418    bool const      fIs32On64 = false;
    8631419#endif
    864         pwszDllName[off] = '\0';
    865     }
     1420    VBPSREGSTATE    State;
     1421    LSTATUS         rc;
    8661422
    8671423    /*
    8681424     * Do registration for the current execution mode of the DLL.
    8691425     */
    870     rc = vbpsRegInit(&State,
    871                      HKEY_CLASSES_ROOT, NULL, "HKCR", /* HKEY_LOCAL_MACHINE, "Software\\Classes", "HKLM\\Software\\Classes", */
    872                      HKEY_CURRENT_USER,  "Software\\Classes",
    873                      fUnregisterOnly, 0);
     1426    rc = vbpsRegInit(&State, HKEY_CLASSES_ROOT, NULL /* Alt: HKEY_LOCAL_MACHINE, "Software\\Classes", */, fDelete, fUpdate, 0);
    8741427    if (rc == ERROR_SUCCESS)
    8751428    {
    876 #ifdef VBOX_PROXY_STUB_32_ON_64
    877         RegisterXidlModulesAndClassesGenerated(&State, pwszDllName, true);
    878 #else
    879         RegisterXidlModulesAndClassesGenerated(&State, pwszDllName, false);
    880 #endif
     1429        if (!fUpdate)
     1430        {
     1431            /* When only unregistering, really purge everything twice or trice. :-) */
     1432            vbpsRegAddAltDelete(&State, HKEY_LOCAL_MACHINE, "Software\\Classes");
     1433            vbpsRegAddAltDelete(&State, HKEY_CURRENT_USER,  "Software\\Classes");
     1434            vbpsRegAddAltDelete(&State, HKEY_CLASSES_ROOT,  NULL);
     1435        }
     1436
     1437        RegisterXidlModulesAndClassesGenerated(&State, pwszVBoxDir, fIs32On64);
    8811438        rc = State.rc;
    8821439    }
    883 
    8841440    vbpsRegTerm(&State);
    885 
    886 #ifndef VBOX_PROXY_STUB_32_ON_64
    887     /*
    888      * Do the WOW6432Node registrations too.
    889      */
    890     if (rc == ERROR_SUCCESS)
    891     {
    892         rc = vbpsRegInit(&State,
    893                          HKEY_CLASSES_ROOT, "Wow6432Node", "HKCR\\Wow6432Node",
    894                          HKEY_CURRENT_USER, "Software\\Classes",
    895                          fUnregisterOnly, KEY_WOW64_32KEY);
    896         if (rc == ERROR_SUCCESS)
    897         {
    898             RegisterXidlModulesAndClassesGenerated(&State, pwszDllName, true);
    899             RegisterOtherProxyStubAndTypelibDll(&State, pwszDllName, true);
    900             rc = State.rc;
    901         }
    902         vbpsRegTerm(&State);
    903     }
    904 #endif
    9051441
    9061442    /*
     
    9101446        return S_OK;
    9111447    return E_FAIL;
    912 }
    913 
    914 
    915 /**
    916  * Register the interfaces proxied by this DLL, and to avoid duplication and
    917  * minimize work the VBox type library, classes and servers are also registered.
    918  *
    919  * @returns COM status code.
    920  */
    921 HRESULT STDAPICALLTYPE DllRegisterServer(void)
    922 {
    923     HRESULT hrc;
    924 
    925     /*
    926      * Register the type library first.
    927      */
    928     ITypeLib *pITypeLib;
    929     WCHAR wszDllName[MAX_PATH];
    930     DWORD cwcRet = GetModuleFileNameW(g_hDllSelf, wszDllName, RT_ELEMENTS(wszDllName));
    931     AssertReturn(cwcRet > 0 && cwcRet < RT_ELEMENTS(wszDllName), CO_E_PATHTOOLONG);
    932 
    933     hrc = LoadTypeLib(wszDllName, &pITypeLib);
    934     AssertMsgReturn(SUCCEEDED(hrc), ("%Rhrc\n", hrc), hrc);
    935     hrc = RegisterTypeLib(pITypeLib, wszDllName, NULL /*pszHelpDir*/);
    936     pITypeLib->lpVtbl->Release(pITypeLib);
    937     AssertMsgReturn(SUCCEEDED(hrc), ("%Rhrc\n", hrc), hrc);
    938 
    939     /*
    940      * Register proxy stub.
    941      */
    942     hrc = NdrDllRegisterProxy(g_hDllSelf, &g_apProxyFiles[0], &g_ProxyClsId);         /* see DLLREGISTRY_ROUTINES in RpcProxy.h */
    943     AssertMsgReturn(SUCCEEDED(hrc), ("%Rhrc\n", hrc), hrc);
    944 
    945     /*
    946      * Register the VBox modules and classes.
    947      */
    948     hrc = RegisterXidlModulesAndClasses(wszDllName, false /*fUnregisterOnly*/);
    949     AssertMsgReturn(SUCCEEDED(hrc), ("%Rhrc\n", hrc), hrc);
    950 
    951     return S_OK;
    952 }
    953 
    954 
    955 /**
    956  * Reverse of DllRegisterServer.
    957  *
    958  * @returns COM status code.
    959  */
    960 HRESULT STDAPICALLTYPE DllUnregisterServer(void)
    961 {
    962     HRESULT hrc = S_OK;
    963     HRESULT hrc2;
    964 
    965     /*
    966      * Unregister the type library.
    967      *
    968      * We ignore TYPE_E_REGISTRYACCESS as that is what is returned if the
    969      * type lib hasn't been registered (W10).
    970      */
    971     hrc2 = UnRegisterTypeLib(&LIBID_VirtualBox, kTypeLibraryMajorVersion, kTypeLibraryMinorVersion,
    972                              0 /*LCid*/, RT_CONCAT(SYS_WIN, ARCH_BITS));
    973     AssertMsgStmt(SUCCEEDED(hrc2) || hrc2 == TYPE_E_REGISTRYACCESS, ("%Rhrc\n", hrc2), if (SUCCEEDED(hrc)) hrc = hrc2);
    974 
    975     /*
    976      * Unregister the proxy stub.
    977      *
    978      * We ignore ERROR_FILE_NOT_FOUND as that is returned if not registered (W10).
    979      */
    980     hrc2 = NdrDllUnregisterProxy(g_hDllSelf, &g_apProxyFiles[0], &g_ProxyClsId);      /* see DLLREGISTRY_ROUTINES in RpcProxy.h */
    981     AssertMsgStmt(   SUCCEEDED(hrc2)
    982                   || hrc2 == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND),
    983                   ("%Rhrc\n", hrc2), if (SUCCEEDED(hrc)) hrc = hrc2);
    984 
    985     /*
    986      * Register the VBox modules and classes.
    987      */
    988     hrc2 = RegisterXidlModulesAndClasses(NULL, true /*fUnregisterOnly*/);
    989     AssertMsgStmt(SUCCEEDED(hrc2), ("%Rhrc\n", hrc2), if (SUCCEEDED(hrc)) hrc = hrc2);
    990 
    991 #ifdef WITH_MANUAL_CLEANUP
    992     /*
    993      * Purge old mess.
    994      */
    995     removeOldMess();
    996 #endif
    997 
    998     return hrc;
    9991448}
    10001449
     
    12721721#endif /* WITH_MANUAL_CLEANUP */
    12731722
     1723
     1724/**
     1725 * Register the interfaces proxied by this DLL, and to avoid duplication and
     1726 * minimize work the VBox type library, classes and servers are also registered.
     1727 *
     1728 * This is normally only used by developers via comregister.cmd and the heat.exe
     1729 * tool during MSI creation.  The only situation where users may end up here is
     1730 * if they're playing around or we recommend it as a solution to COM problems.
     1731 * So, no problem if this approach is less gentle, though we leave the cleaning
     1732 * up of orphaned interfaces to DllUnregisterServer.
     1733 *
     1734 * @returns COM status code.
     1735 */
     1736HRESULT STDAPICALLTYPE DllRegisterServer(void)
     1737{
     1738    HRESULT hrc;
     1739
     1740    /*
     1741     * Register the type library first.
     1742     */
     1743    ITypeLib *pITypeLib;
     1744    WCHAR wszDllName[MAX_PATH];
     1745    DWORD cwcRet = GetModuleFileNameW(g_hDllSelf, wszDllName, RT_ELEMENTS(wszDllName));
     1746    AssertReturn(cwcRet > 0 && cwcRet < RT_ELEMENTS(wszDllName), CO_E_PATHTOOLONG);
     1747
     1748    hrc = LoadTypeLib(wszDllName, &pITypeLib);
     1749    AssertMsgReturn(SUCCEEDED(hrc), ("%Rhrc\n", hrc), hrc);
     1750    hrc = RegisterTypeLib(pITypeLib, wszDllName, NULL /*pszHelpDir*/);
     1751    pITypeLib->lpVtbl->Release(pITypeLib);
     1752    AssertMsgReturn(SUCCEEDED(hrc), ("%Rhrc\n", hrc), hrc);
     1753
     1754    /*
     1755     * Register proxy stub.
     1756     */
     1757    hrc = NdrDllRegisterProxy(g_hDllSelf, &g_apProxyFiles[0], &g_ProxyClsId);         /* see DLLREGISTRY_ROUTINES in RpcProxy.h */
     1758    AssertMsgReturn(SUCCEEDED(hrc), ("%Rhrc\n", hrc), hrc);
     1759
     1760    /*
     1761     * Register the VBox modules and classes.
     1762     */
     1763    vbpsDllPathToVBoxDir(wszDllName);
     1764    hrc = RegisterXidlModulesAndClasses(wszDllName, true /*fDelete*/, true /*fUpdate*/);
     1765    AssertMsgReturn(SUCCEEDED(hrc), ("%Rhrc\n", hrc), hrc);
     1766
     1767    return S_OK;
     1768}
     1769
     1770
     1771/**
     1772 * Reverse of DllRegisterServer.
     1773 *
     1774 * This is normally only used by developers via comregister.cmd.  Users may be
     1775 * asked to perform it in order to fix some COM issue.  So, it's OK if we spend
     1776 * some extra time and clean up orphaned interfaces, because developer boxes
     1777 * will end up with a bunch of those as interface UUIDs changes.
     1778 *
     1779 * @returns COM status code.
     1780 */
     1781HRESULT STDAPICALLTYPE DllUnregisterServer(void)
     1782{
     1783    HRESULT hrc = S_OK;
     1784    HRESULT hrc2;
     1785
     1786    /*
     1787     * Unregister the type library.
     1788     *
     1789     * We ignore TYPE_E_REGISTRYACCESS as that is what is returned if the
     1790     * type lib hasn't been registered (W10).
     1791     */
     1792    hrc2 = UnRegisterTypeLib(&LIBID_VirtualBox, kTypeLibraryMajorVersion, kTypeLibraryMinorVersion,
     1793                             0 /*LCid*/, RT_CONCAT(SYS_WIN, ARCH_BITS));
     1794    AssertMsgStmt(SUCCEEDED(hrc2) || hrc2 == TYPE_E_REGISTRYACCESS, ("%Rhrc\n", hrc2), if (SUCCEEDED(hrc)) hrc = hrc2);
     1795
     1796    /*
     1797     * Unregister the proxy stub.
     1798     *
     1799     * We ignore ERROR_FILE_NOT_FOUND as that is returned if not registered (W10).
     1800     */
     1801    hrc2 = NdrDllUnregisterProxy(g_hDllSelf, &g_apProxyFiles[0], &g_ProxyClsId);      /* see DLLREGISTRY_ROUTINES in RpcProxy.h */
     1802    AssertMsgStmt(   SUCCEEDED(hrc2)
     1803                  || hrc2 == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND),
     1804                  ("%Rhrc\n", hrc2), if (SUCCEEDED(hrc)) hrc = hrc2);
     1805
     1806    /*
     1807     * Register the VBox modules and classes.
     1808     */
     1809    hrc2 = RegisterXidlModulesAndClasses(NULL, true /*fDelete*/, false /*fUpdate*/);
     1810    AssertMsgStmt(SUCCEEDED(hrc2), ("%Rhrc\n", hrc2), if (SUCCEEDED(hrc)) hrc = hrc2);
     1811
     1812#ifdef WITH_MANUAL_CLEANUP
     1813    /*
     1814     * Purge old mess.
     1815     */
     1816    removeOldMess();
     1817#endif
     1818
     1819    return hrc;
     1820}
     1821
     1822
     1823/**
     1824 * Gently update the COM registrations for VirtualBox.
     1825 *
     1826 * API that com::Initialize (VBoxCOM/initterm.cpp) calls the first time COM is
     1827 * initialized in a process.  ASSUMES that the caller has initialized IPRT.
     1828 *
     1829 * @returns Windows error code.
     1830 */
     1831DECLEXPORT(uint32_t) VbpsUpdateRegistrations(void)
     1832{
     1833    LSTATUS         rc;
     1834    VBPSREGSTATE    State;
     1835#ifdef VBOX_IN_32_ON_64_MAIN_API
     1836    bool const      fIs32On64 = true;
     1837#else
     1838    bool const      fIs32On64 = false;
     1839#endif
     1840
     1841    /*
     1842     * Find the VirtualBox application directory first.
     1843     */
     1844    WCHAR wszVBoxDir[MAX_PATH];
     1845    DWORD cwcRet = GetModuleFileNameW(g_hDllSelf, wszVBoxDir, RT_ELEMENTS(wszVBoxDir));
     1846    AssertReturn(cwcRet > 0 && cwcRet < RT_ELEMENTS(wszVBoxDir), ERROR_BUFFER_OVERFLOW);
     1847    vbpsDllPathToVBoxDir(wszVBoxDir);
     1848
     1849    /*
     1850     * Update registry entries for the current CPU bitness.
     1851     */
     1852    rc = vbpsRegInit(&State, HKEY_CLASSES_ROOT, NULL, false /*fDelete*/, true /*fUpdate*/, 0);
     1853    if (rc == ERROR_SUCCESS && !vbpsIsUpToDate(&State))
     1854    {
     1855        vbpsUpdateTypeLibRegistration(&State, wszVBoxDir, fIs32On64);
     1856        vbpsUpdateProxyStubRegistration(&State, wszVBoxDir, fIs32On64);
     1857        vbpsUpdateInterfaceRegistrations(&State);
     1858        RegisterXidlModulesAndClassesGenerated(&State, wszVBoxDir, fIs32On64);
     1859        vbpsMarkUpToDate(&State);
     1860        rc = State.rc;
     1861    }
     1862    vbpsRegTerm(&State);
     1863
     1864
     1865//#if defined(VBOX_IN_32_ON_64_MAIN_API) || (ARCH_BITS == 64 && defined(VBOX_WITH_32_ON_64_MAIN_API))
     1866#ifndef VBOX_IN_32_ON_64_MAIN_API
     1867    /*
     1868     * Update registry entries for the other CPU bitness.
     1869     */
     1870    if (rc == ERROR_SUCCESS)
     1871    {
     1872        //rc = vbpsRegInit(&State, HKEY_CLASSES_ROOT, "Wow6432Node", fDelete, fUpdate, KEY_WOW64_32KEY);
     1873        rc = vbpsRegInit(&State, HKEY_CLASSES_ROOT, NULL, false /*fDelete*/, true /*fUpdate*/,
     1874                         !fIs32On64 ? KEY_WOW64_32KEY : KEY_WOW64_64KEY);
     1875        if (rc == ERROR_SUCCESS && !vbpsIsUpToDate(&State))
     1876        {
     1877            vbpsUpdateTypeLibRegistration(&State, wszVBoxDir, !fIs32On64);
     1878            vbpsUpdateProxyStubRegistration(&State, wszVBoxDir, !fIs32On64);
     1879            vbpsUpdateInterfaceRegistrations(&State);
     1880            RegisterXidlModulesAndClassesGenerated(&State, wszVBoxDir, !fIs32On64);
     1881            vbpsMarkUpToDate(&State);
     1882            rc = State.rc;
     1883        }
     1884        vbpsRegTerm(&State);
     1885    }
     1886#endif
     1887
     1888    return VINF_SUCCESS;
     1889}
     1890
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette