VirtualBox

source: vbox/trunk/src/VBox/Main/src-all/win/VBoxProxyStub.c@ 59407

Last change on this file since 59407 was 59393, checked in by vboxsync, 9 years ago

VBoxProxyStub.c: Normal users aren't allowed to do COM registrations, at least not this way. So, quietly ignore ERROR_ACCESS_DENIED duing VbpsUpdateRegistrations.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 86.7 KB
Line 
1/* $Id: VBoxProxyStub.c 59393 2016-01-19 02:10:19Z vboxsync $ */
2/** @file
3 * VBoxProxyStub - Proxy Stub and Typelib, COM DLL exports and DLL init/term.
4 *
5 * @remarks This is a C file and not C++ because rpcproxy.h isn't C++ clean,
6 * at least not in SDK v7.1.
7 */
8
9/*
10 * Copyright (C) 2006-2016 Oracle Corporation
11 *
12 * This file is part of VirtualBox Open Source Edition (OSE), as
13 * available from http://www.virtualbox.org. This file is free software;
14 * you can redistribute it and/or modify it under the terms of the GNU
15 * General Public License (GPL) as published by the Free Software
16 * Foundation, in version 2 as it comes in the "COPYING" file of the
17 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19 */
20
21
22/*********************************************************************************************************************************
23* Header Files *
24*********************************************************************************************************************************/
25#define PROXY_DELEGATION /* see generated dlldata.c */
26#include <iprt/nt/nt-and-windows.h>
27#include <rpcproxy.h>
28#include <Shlwapi.h>
29#include <stdio.h>
30
31#include "VirtualBox.h"
32#include <iprt/alloca.h>
33#include <iprt/assert.h>
34#include <iprt/ctype.h>
35#include <iprt/initterm.h>
36#include <iprt/path.h>
37#include <iprt/string.h>
38#include <iprt/uuid.h>
39
40
41/*********************************************************************************************************************************
42* Defined Constants And Macros *
43*********************************************************************************************************************************/
44#ifdef DEBUG_bird
45# define VBSP_LOG_ENABLED
46#endif
47
48#ifdef VBSP_LOG_ENABLED
49# define VBSP_LOG_VALUE_CHANGE(a) RTAssertMsg2 a
50#else
51# define VBSP_LOG_VALUE_CHANGE(a) do { } while (0)
52#endif
53
54#ifdef VBSP_LOG_ENABLED
55# define VBSP_LOG_SET_VALUE(a) RTAssertMsg2 a
56#else
57# define VBSP_LOG_SET_VALUE(a) do { } while (0)
58#endif
59
60#ifdef VBSP_LOG_ENABLED
61# define VBSP_LOG_NEW_KEY(a) RTAssertMsg2 a
62#else
63# define VBSP_LOG_NEW_KEY(a) do { } while (0)
64#endif
65
66#ifdef VBSP_LOG_ENABLED
67# define VBSP_LOG_DEL_KEY(a) RTAssertMsg2 a
68#else
69# define VBSP_LOG_DEL_KEY(a) do { } while (0)
70#endif
71
72/**
73 * Selects the proxy stub DLL based on 32-on-64-bit and host OS version.
74 *
75 * The legacy DLL covers 64-bit pre Windows 7 versions of Windows. W2K3-amd64
76 * has trouble parsing the result when MIDL /target NT51 or higher. Vista and
77 * windows server 2008 seems to have trouble with newer IDL compilers.
78 */
79#define VBPS_PROXY_STUB_FILE(a_fIs32On64) \
80 ( (a_fIs32On64) ? "x86\\VBoxProxyStub-x86.dll" \
81 : RT_MAKE_U64(((PKUSER_SHARED_DATA)MM_SHARED_USER_DATA_VA)->NtMinorVersion, \
82 ((PKUSER_SHARED_DATA)MM_SHARED_USER_DATA_VA)->NtMajorVersion) >= RT_MAKE_U64(1/*Lo*/,6/*Hi*/) \
83 ? "VBoxProxyStub.dll" : "VBoxProxyStubLegacy.dll" )
84
85
86/*********************************************************************************************************************************
87* Global Variables *
88*********************************************************************************************************************************/
89/** For NdrXxx. */
90CStdPSFactoryBuffer g_ProxyStubFactory = /* see generated dlldata.c */
91{
92 NULL,
93 0,
94 NULL,
95 0
96};
97/** Reference to VirtualBox_p.c structure. */
98EXTERN_PROXY_FILE(VirtualBox) /* see generated dlldata.c */
99/** For NdrXxx and for returning. */
100static const ProxyFileInfo *g_apProxyFiles[] =
101{
102 REFERENCE_PROXY_FILE(VirtualBox),
103 NULL /* terminator */
104};
105/** The class ID for this proxy stub factory (see Makefile). */
106static const CLSID g_ProxyClsId = PROXY_CLSID_IS;
107/** The instance handle of this DLL. For use in registration routines. */
108static HINSTANCE g_hDllSelf;
109
110
111/** Type library GUIDs to clean up manually.
112 * Must be upper case! */
113static PCRTUTF16 const g_apwszTypeLibIds[] =
114{
115 L"{46137EEC-703B-4FE5-AFD4-7C9BBBBA0259}",
116 L"{D7569351-1750-46F0-936E-BD127D5BC264}",
117};
118
119/** Type library version to clean up manually. */
120static PCRTUTF16 const g_apwszTypelibVersions[] =
121{
122 L"1.0",
123 L"1.3",
124};
125
126/** Proxy stub class IDs we wish to clean up manually.
127 * Must be upper case! */
128static PCRTUTF16 const g_apwszProxyStubClsIds[] =
129{
130 L"{0BB3B78C-1807-4249-5BA5-EA42D66AF0BF}",
131 L"{327E3C00-EE61-462F-AED3-0DFF6CBF9904}",
132};
133
134
135/**
136 * DLL main function.
137 *
138 * @returns TRUE (/ FALSE).
139 * @param hInstance The DLL handle.
140 * @param dwReason The rason for the call (DLL_XXX).
141 * @param lpReserved Reserved.
142 */
143BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
144{
145 switch (dwReason)
146 {
147 case DLL_PROCESS_ATTACH:
148 /* Save the DLL handle so we can get the path to this DLL during
149 registration and updating. */
150 g_hDllSelf = hInstance;
151
152 /* We don't need callbacks for thread creation and destruction. */
153 DisableThreadLibraryCalls(hInstance);
154
155 /* Init IPRT. */
156 RTR3InitDll(RTR3INIT_FLAGS_UNOBTRUSIVE);
157
158#ifdef VBOX_STRICT
159 {
160 /*
161 * Check that no interface has more than 256 methods in the stub vtable.
162 */
163 const ProxyFileInfo **ppProxyFile = &g_apProxyFiles[0];
164 const ProxyFileInfo *pProxyFile;
165 while ((pProxyFile = *ppProxyFile++) != NULL)
166 {
167 const PCInterfaceStubVtblList * const papStubVtbls = pProxyFile->pStubVtblList;
168 const char * const *papszNames = pProxyFile->pNamesArray;
169 unsigned iIf = pProxyFile->TableSize;
170 AssertStmt(iIf < 1024, iIf = 0);
171 Assert(pProxyFile->TableVersion == 2);
172
173 while (iIf-- > 0)
174 AssertMsg(papStubVtbls[iIf]->header.DispatchTableCount <= 256,
175 ("%s: DispatchTableCount=%d\n", papszNames[iIf], papStubVtbls[iIf]->header.DispatchTableCount));
176 }
177 }
178#endif
179 break;
180
181 case DLL_PROCESS_DETACH:
182 break;
183 }
184
185 NOREF(lpReserved);
186 return TRUE;
187}
188
189
190/**
191 * RPC entry point returning info about the proxy.
192 */
193void RPC_ENTRY GetProxyDllInfo(const ProxyFileInfo ***ppapInfo, const CLSID **ppClsid)
194{
195 *ppapInfo = &g_apProxyFiles[0];
196 *ppClsid = &g_ProxyClsId;
197}
198
199
200/**
201 * Instantiate the proxy stub class object.
202 *
203 * @returns COM status code
204 * @param rclsid Reference to the ID of the call to instantiate (our
205 * g_ProxyClsId).
206 * @param riid The interface ID to return (IID_IPSFactoryBuffer).
207 * @param ppv Where to return the interface pointer on success.
208 */
209HRESULT STDAPICALLTYPE DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
210{
211 HRESULT hrc;
212 Assert(memcmp(rclsid, &g_ProxyClsId, sizeof(g_ProxyClsId)) == 0);
213
214 hrc = NdrDllGetClassObject(rclsid, riid, ppv, /* see DLLGETCLASSOBJECTROUTINE in RpcProxy.h */
215 g_apProxyFiles, &g_ProxyClsId, &g_ProxyStubFactory);
216
217 /*
218 * This may fail if the IDL compiler generates code that is incompatible
219 * with older windows releases. Like for instance 64-bit W2K8 SP1 not
220 * liking the output of MIDL 7.00.0555 (from the v7.1 SDK), despite
221 * /target being set to NT51.
222 */
223 AssertMsg(hrc == S_OK, ("%Rhrc\n", hrc));
224 return hrc;
225}
226
227
228/**
229 * Checks whether the DLL can be unloaded or not.
230 *
231 * @returns S_OK if it can be unloaded, S_FALSE if not.
232 */
233HRESULT STDAPICALLTYPE DllCanUnloadNow(void)
234{
235 return NdrDllCanUnloadNow(&g_ProxyStubFactory); /* see DLLCANUNLOADNOW in RpcProxy.h */
236}
237
238
239
240/**
241 * Release call that could be referenced by VirtualBox_p.c via
242 * CStdStubBuffer_METHODS.
243 *
244 * @returns New reference count.
245 * @param pThis Buffer to release.
246 */
247ULONG STDMETHODCALLTYPE CStdStubBuffer_Release(IRpcStubBuffer *pThis) /* see CSTDSTUBBUFFERRELEASE in RpcProxy.h */
248{
249 return NdrCStdStubBuffer_Release(pThis, (IPSFactoryBuffer *)&g_ProxyStubFactory);
250}
251
252
253/**
254 * Release call referenced by VirtualBox_p.c via
255 * CStdStubBuffer_DELEGATING_METHODS.
256 *
257 * @returns New reference count.
258 * @param pThis Buffer to release.
259 */
260ULONG WINAPI CStdStubBuffer2_Release(IRpcStubBuffer *pThis) /* see CSTDSTUBBUFFER2RELEASE in RpcProxy.h */
261{
262 return NdrCStdStubBuffer2_Release(pThis, (IPSFactoryBuffer *)&g_ProxyStubFactory);
263}
264
265
266/**
267 * Pure virtual method implementation referenced by VirtualBox_p.c
268 *
269 * @returns New reference count.
270 * @param pThis Buffer to release.
271 */
272void __cdecl _purecall(void) /* see DLLDUMMYPURECALL in RpcProxy.h */
273{
274 AssertFailed();
275}
276
277
278#ifdef VBSP_LOG_ENABLED
279# include <iprt/asm.h>
280
281/** For logging full key names. */
282static PCRTUTF16 vbpsDebugKeyToWSZ(HKEY hKey)
283{
284 static union
285 {
286 KEY_NAME_INFORMATION NameInfo;
287 WCHAR awchPadding[260];
288 } s_aBufs[4];
289 static uint32_t volatile iNext = 0;
290 uint32_t i = ASMAtomicIncU32(&iNext) % RT_ELEMENTS(s_aBufs);
291 ULONG cbRet = 0;
292 NTSTATUS rcNt;
293
294 memset(&s_aBufs[i], 0, sizeof(s_aBufs[i]));
295 rcNt = NtQueryKey(hKey, KeyNameInformation, &s_aBufs[i], sizeof(s_aBufs[i]) - sizeof(WCHAR), &cbRet);
296 if (!NT_SUCCESS(rcNt))
297 s_aBufs[i].NameInfo.NameLength = 0;
298 s_aBufs[i].NameInfo.Name[s_aBufs[i].NameInfo.NameLength] = '\0';
299 return s_aBufs[i].NameInfo.Name;
300}
301#endif
302
303/**
304 * Registry modifier state.
305 */
306typedef struct VBPSREGSTATE
307{
308 /** Where the classes and stuff are to be registered. */
309 HKEY hkeyClassesRootDst;
310 /** The handle to the CLSID key under hkeyClassesRootDst. */
311 HKEY hkeyClsidRootDst;
312 /** The handle to the Interface key under hkeyClassesRootDst. */
313 HKEY hkeyInterfaceRootDst;
314
315 /** Alternative locations where data needs to be deleted, but never updated. */
316 struct
317 {
318 /** The classes root key handle. */
319 HKEY hkeyClasses;
320 /** The classes/CLSID key handle. */
321 HKEY hkeyClsid;
322 /** The classes/Interface key handle. */
323 HKEY hkeyInterface;
324 } aAltDeletes[3];
325 /** Alternative delete locations. */
326 uint32_t cAltDeletes;
327
328 /** The current total result. */
329 LSTATUS rc;
330
331 /** KEY_WOW64_32KEY, KEY_WOW64_64KEY or 0 (for default). Allows doing all
332 * almost the work from one process (at least W7+ due to aliases). */
333 DWORD fSamWow;
334 /** Desired key access when only deleting. */
335 DWORD fSamDelete;
336 /** Desired key access when only doing updates. */
337 DWORD fSamUpdate;
338 /** Desired key access when both deleting and updating. */
339 DWORD fSamBoth;
340 /** Whether to delete registrations first. */
341 bool fDelete;
342 /** Whether to update registry value and keys. */
343 bool fUpdate;
344
345} VBPSREGSTATE;
346
347
348/**
349 * Initializes a registry modification job state.
350 *
351 * Always call vbpsRegTerm!
352 *
353 * @returns Windows error code (ERROR_SUCCESS on success).
354 * @param pState The state to init.
355 * @param hkeyRoot The registry root tree constant.
356 * @param pszSubRoot The path to the where the classes are registered,
357 * NULL if @a hkeyRoot.
358 * @param hkeyAltRoot The registry root tree constant for the alternative
359 * registrations (remove only).
360 * @param pszAltSubRoot The path to where classes could also be registered,
361 * but shouldn't be in our setup.
362 * @param fDelete Whether to delete registrations first.
363 * @param fUpdate Whether to update registrations.
364 * @param fSamWow KEY_WOW64_32KEY or 0.
365 */
366static LSTATUS vbpsRegInit(VBPSREGSTATE *pState, HKEY hkeyRoot, const char *pszSubRoot, bool fDelete, bool fUpdate, DWORD fSamWow)
367{
368 LSTATUS rc;
369 unsigned i = 0;
370
371 /*
372 * Initialize the whole structure first so we can safely call vbpsRegTerm on failure.
373 */
374 pState->hkeyClassesRootDst = NULL;
375 pState->hkeyClsidRootDst = NULL;
376 pState->hkeyInterfaceRootDst = NULL;
377 for (i = 0; i < RT_ELEMENTS(pState->aAltDeletes); i++)
378 {
379 pState->aAltDeletes[i].hkeyClasses = NULL;
380 pState->aAltDeletes[i].hkeyClsid = NULL;
381 pState->aAltDeletes[i].hkeyInterface = NULL;
382 }
383 pState->cAltDeletes = 0;
384 pState->rc = ERROR_SUCCESS;
385 pState->fDelete = fDelete;
386 pState->fUpdate = fUpdate;
387 pState->fSamWow = fSamWow;
388 pState->fSamDelete = 0;
389 if (fDelete)
390 pState->fSamDelete = pState->fSamWow | DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE
391 | STANDARD_RIGHTS_READ | STANDARD_RIGHTS_WRITE;
392 pState->fSamUpdate = 0;
393 if (fUpdate)
394 pState->fSamUpdate = pState->fSamWow | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY
395 | STANDARD_RIGHTS_READ | STANDARD_RIGHTS_WRITE;
396 pState->fSamBoth = pState->fSamDelete | pState->fSamUpdate;
397
398 /*
399 * Open the root keys.
400 */
401 rc = RegOpenKeyExA(hkeyRoot, pszSubRoot, 0 /*fOptions*/, pState->fSamBoth, &pState->hkeyClassesRootDst);
402 if (rc == ERROR_SUCCESS)
403 {
404 rc = RegCreateKeyExW(pState->hkeyClassesRootDst, L"CLSID", 0 /*Reserved*/, NULL /*pszClass*/, 0 /*fOptions*/,
405 pState->fSamBoth, NULL /*pSecAttr*/, &pState->hkeyClsidRootDst, NULL /*pdwDisposition*/);
406 if (rc == ERROR_SUCCESS)
407 return ERROR_SUCCESS;
408
409 /* Ignore access denied errors as these may easily happen for
410 non-admin users. Just give up when this happens */
411 AssertMsgReturn(rc == ERROR_ACCESS_DENIED, ("%u\n", rc), pState->rc = rc);
412 }
413 else
414 AssertMsgReturn(rc == ERROR_ACCESS_DENIED, ("%u\n", rc), pState->rc = rc);
415 return pState->rc = rc;
416}
417
418
419/**
420 * Terminates the state, closing all open keys.
421 *
422 * @param pState The state to clean up.
423 */
424static void vbpsRegTerm(VBPSREGSTATE *pState)
425{
426 LSTATUS rc;
427 if (pState->hkeyClassesRootDst)
428 {
429 rc = RegCloseKey(pState->hkeyClassesRootDst);
430 Assert(rc == ERROR_SUCCESS);
431 pState->hkeyClassesRootDst = NULL;
432 }
433 if (pState->hkeyClsidRootDst)
434 {
435 rc = RegCloseKey(pState->hkeyClsidRootDst);
436 Assert(rc == ERROR_SUCCESS);
437 pState->hkeyClsidRootDst = NULL;
438 }
439 if (pState->hkeyInterfaceRootDst)
440 {
441 rc = RegCloseKey(pState->hkeyInterfaceRootDst);
442 Assert(rc == ERROR_SUCCESS);
443 pState->hkeyInterfaceRootDst = NULL;
444 }
445
446 while (pState->cAltDeletes > 0 && pState->cAltDeletes <= RT_ELEMENTS(pState->aAltDeletes))
447 {
448 unsigned i = --pState->cAltDeletes;
449 if (pState->aAltDeletes[i].hkeyClasses)
450 {
451 rc = RegCloseKey(pState->aAltDeletes[i].hkeyClasses);
452 Assert(rc == ERROR_SUCCESS);
453 pState->aAltDeletes[i].hkeyClasses = NULL;
454 }
455 if (pState->aAltDeletes[i].hkeyClsid)
456 {
457 rc = RegCloseKey(pState->aAltDeletes[i].hkeyClsid);
458 Assert(rc == ERROR_SUCCESS);
459 pState->aAltDeletes[i].hkeyClsid = NULL;
460 }
461 if (pState->aAltDeletes[i].hkeyInterface)
462 {
463 rc = RegCloseKey(pState->aAltDeletes[i].hkeyInterface);
464 Assert(rc == ERROR_SUCCESS);
465 pState->aAltDeletes[i].hkeyInterface = NULL;
466 }
467 }
468}
469
470
471/**
472 * Add an alternative registry classes tree from which to remove keys.
473 *
474 * @returns ERROR_SUCCESS if we successfully opened the destination root, other
475 * wise windows error code (remebered).
476 * @param pState The registry modifier state.
477 * @param hkeyAltRoot The root of the alternate registry classes
478 * location.
479 * @param pszAltSubRoot The path to the 'classes' sub-key, or NULL if
480 * hkeyAltRoot is it.
481 */
482static LSTATUS vbpsRegAddAltDelete(VBPSREGSTATE *pState, HKEY hkeyAltRoot, const char *pszAltSubRoot)
483{
484 unsigned i;
485 LSTATUS rc;
486
487 /* Ignore call if not in delete mode. */
488 if (!pState->fDelete)
489 return ERROR_SUCCESS;
490
491 /* Check that there is space in the state. */
492 i = pState->cAltDeletes;
493 AssertReturn(i < RT_ELEMENTS(pState->aAltDeletes), pState->rc = ERROR_TOO_MANY_NAMES);
494
495
496 /* Open the root. */
497 rc = RegOpenKeyExA(hkeyAltRoot, pszAltSubRoot, 0 /*fOptions*/, pState->fSamDelete,
498 &pState->aAltDeletes[i].hkeyClasses);
499 if (rc == ERROR_SUCCESS)
500 {
501 /* Try open the CLSID subkey, it's fine if it doesn't exists. */
502 rc = RegOpenKeyExW(pState->aAltDeletes[i].hkeyClasses, L"CLSID", 0 /*fOptions*/, pState->fSamDelete,
503 &pState->aAltDeletes[i].hkeyClsid);
504 if (rc == ERROR_SUCCESS || rc == ERROR_FILE_NOT_FOUND)
505 {
506 if (rc == ERROR_FILE_NOT_FOUND)
507 pState->aAltDeletes[i].hkeyClsid = NULL;
508 pState->cAltDeletes = i + 1;
509 return ERROR_SUCCESS;
510 }
511 AssertMsgFailed(("%u\n", rc));
512 RegCloseKey(pState->aAltDeletes[i].hkeyClasses);
513 }
514 /* No need to add non-existing alternative roots, nothing to delete in the void. */
515 else if (rc == ERROR_FILE_NOT_FOUND)
516 rc = ERROR_SUCCESS;
517 else
518 {
519 AssertMsgFailed(("%u\n", rc));
520 pState->rc = rc;
521 }
522
523 pState->aAltDeletes[i].hkeyClasses = NULL;
524 pState->aAltDeletes[i].hkeyClsid = NULL;
525 return rc;
526}
527
528
529/**
530 * Open the 'Interface' keys under the current classes roots.
531 *
532 * We don't do this during vbpsRegInit as it's only needed for updating.
533 *
534 * @returns ERROR_SUCCESS if we successfully opened the destination root, other
535 * wise windows error code (remebered).
536 * @param pState The registry modifier state.
537 */
538static LSTATUS vbpsRegOpenInterfaceKeys(VBPSREGSTATE *pState)
539{
540 unsigned i;
541 LSTATUS rc;
542
543 /*
544 * Under the root destination.
545 */
546 if (pState->hkeyInterfaceRootDst == NULL)
547 {
548 if (pState->fSamUpdate)
549 rc = RegCreateKeyExW(pState->hkeyClassesRootDst, L"Interface", 0 /*Reserved*/, NULL /*pszClass*/, 0 /*fOptions*/,
550 pState->fSamBoth, NULL /*pSecAttr*/, &pState->hkeyInterfaceRootDst, NULL /*pdwDisposition*/);
551 else
552 rc = RegOpenKeyExW(pState->hkeyClassesRootDst, L"Interface", 0 /*fOptions*/, pState->fSamBoth,
553 &pState->hkeyClsidRootDst);
554 AssertMsgReturnStmt(rc == ERROR_SUCCESS, ("%u\n", rc), pState->hkeyInterfaceRootDst = NULL, pState->rc = rc);
555 }
556
557 /*
558 * Under the alternative delete locations.
559 */
560 i = pState->cAltDeletes;
561 while (i-- > 0)
562 if (pState->aAltDeletes[i].hkeyInterface == NULL)
563 {
564 rc = RegOpenKeyExW(pState->aAltDeletes[i].hkeyClasses, L"Interface", 0 /*fOptions*/, pState->fSamDelete,
565 &pState->aAltDeletes[i].hkeyInterface);
566 if (rc != ERROR_SUCCESS)
567 {
568 AssertMsgStmt(rc == ERROR_FILE_NOT_FOUND, ("%u\n", rc), pState->rc = rc);
569 pState->aAltDeletes[i].hkeyInterface = NULL;
570 }
571 }
572
573 return ERROR_SUCCESS;
574}
575
576
577/** The destination buffer size required by vbpsFormatUuidInCurly. */
578#define CURLY_UUID_STR_BUF_SIZE 40
579
580/**
581 * Formats a UUID to a string, inside curly braces.
582 *
583 * @returns @a pszString
584 * @param pszString Output buffer of size CURLY_UUID_STR_BUF_SIZE.
585 * @param pUuidIn The UUID to format.
586 */
587static const char *vbpsFormatUuidInCurly(char pszString[CURLY_UUID_STR_BUF_SIZE], const CLSID *pUuidIn)
588{
589 static const char s_achDigits[17] = "0123456789abcdef";
590 PCRTUUID pUuid = (PCRTUUID)pUuidIn;
591 uint32_t u32TimeLow;
592 unsigned u;
593
594 pszString[ 0] = '{';
595 u32TimeLow = RT_H2LE_U32(pUuid->Gen.u32TimeLow);
596 pszString[ 1] = s_achDigits[(u32TimeLow >> 28)/*& 0xf*/];
597 pszString[ 2] = s_achDigits[(u32TimeLow >> 24) & 0xf];
598 pszString[ 3] = s_achDigits[(u32TimeLow >> 20) & 0xf];
599 pszString[ 4] = s_achDigits[(u32TimeLow >> 16) & 0xf];
600 pszString[ 5] = s_achDigits[(u32TimeLow >> 12) & 0xf];
601 pszString[ 6] = s_achDigits[(u32TimeLow >> 8) & 0xf];
602 pszString[ 7] = s_achDigits[(u32TimeLow >> 4) & 0xf];
603 pszString[ 8] = s_achDigits[(u32TimeLow/*>>0*/)& 0xf];
604 pszString[ 9] = '-';
605 u = RT_H2LE_U16(pUuid->Gen.u16TimeMid);
606 pszString[10] = s_achDigits[(u >> 12)/*& 0xf*/];
607 pszString[11] = s_achDigits[(u >> 8) & 0xf];
608 pszString[12] = s_achDigits[(u >> 4) & 0xf];
609 pszString[13] = s_achDigits[(u/*>>0*/)& 0xf];
610 pszString[14] = '-';
611 u = RT_H2LE_U16(pUuid->Gen.u16TimeHiAndVersion);
612 pszString[15] = s_achDigits[(u >> 12)/*& 0xf*/];
613 pszString[16] = s_achDigits[(u >> 8) & 0xf];
614 pszString[17] = s_achDigits[(u >> 4) & 0xf];
615 pszString[18] = s_achDigits[(u/*>>0*/)& 0xf];
616 pszString[19] = '-';
617 pszString[20] = s_achDigits[pUuid->Gen.u8ClockSeqHiAndReserved >> 4];
618 pszString[21] = s_achDigits[pUuid->Gen.u8ClockSeqHiAndReserved & 0xf];
619 pszString[22] = s_achDigits[pUuid->Gen.u8ClockSeqLow >> 4];
620 pszString[23] = s_achDigits[pUuid->Gen.u8ClockSeqLow & 0xf];
621 pszString[24] = '-';
622 pszString[25] = s_achDigits[pUuid->Gen.au8Node[0] >> 4];
623 pszString[26] = s_achDigits[pUuid->Gen.au8Node[0] & 0xf];
624 pszString[27] = s_achDigits[pUuid->Gen.au8Node[1] >> 4];
625 pszString[28] = s_achDigits[pUuid->Gen.au8Node[1] & 0xf];
626 pszString[29] = s_achDigits[pUuid->Gen.au8Node[2] >> 4];
627 pszString[30] = s_achDigits[pUuid->Gen.au8Node[2] & 0xf];
628 pszString[31] = s_achDigits[pUuid->Gen.au8Node[3] >> 4];
629 pszString[32] = s_achDigits[pUuid->Gen.au8Node[3] & 0xf];
630 pszString[33] = s_achDigits[pUuid->Gen.au8Node[4] >> 4];
631 pszString[34] = s_achDigits[pUuid->Gen.au8Node[4] & 0xf];
632 pszString[35] = s_achDigits[pUuid->Gen.au8Node[5] >> 4];
633 pszString[36] = s_achDigits[pUuid->Gen.au8Node[5] & 0xf];
634 pszString[37] = '}';
635 pszString[38] = '\0';
636
637 return pszString;
638
639}
640
641
642/**
643 * Sets a registry string value, wide char variant.
644 *
645 * @returns See RegSetValueExA (errors are remembered in the state).
646 * @param pState The registry modifier state.
647 * @param hkey The key to add the value to.
648 * @param pwszValueNm The value name. NULL for setting the default.
649 * @param pwszValue The value string.
650 * @param uLine The line we're called from.
651 */
652static LSTATUS vbpsSetRegValueWW(VBPSREGSTATE *pState, HKEY hkey, PCRTUTF16 pwszValueNm, PCRTUTF16 pwszValue, unsigned uLine)
653{
654 DWORD const cbValue = (DWORD)((RTUtf16Len(pwszValue) + 1) * sizeof(RTUTF16));
655 LSTATUS rc;
656 Assert(pState->fUpdate);
657
658 /*
659 * If we're not deleting the key prior to updating, we're in gentle update
660 * mode where we will query if the existing value matches the incoming one.
661 */
662 if (!pState->fDelete)
663 {
664 DWORD cbExistingData = cbValue + 128;
665 PRTUTF16 pwszExistingData = (PRTUTF16)alloca(cbExistingData);
666 DWORD dwExistingType;
667 rc = RegQueryValueExW(hkey, pwszValueNm, 0 /*Reserved*/, &dwExistingType, (BYTE *)pwszExistingData, &cbExistingData);
668 if (rc == ERROR_SUCCESS)
669 {
670 if ( dwExistingType == REG_SZ
671 && cbExistingData == cbValue)
672 {
673 if (memcmp(pwszValue, pwszExistingData, cbValue) == 0)
674 return ERROR_SUCCESS;
675 }
676 VBSP_LOG_VALUE_CHANGE(("vbpsSetRegValueWW: Value difference: dwExistingType=%d cbExistingData=%#x cbValue=%#x\n"
677 " hkey=%#x %ls; value name=%ls\n"
678 "existing: %.*Rhxs (%.*ls)\n"
679 " new: %.*Rhxs (%ls)\n",
680 dwExistingType, cbExistingData, cbValue,
681 hkey, vbpsDebugKeyToWSZ(hkey), pwszValueNm ? pwszValueNm : L"(default)",
682 cbExistingData, pwszExistingData, cbExistingData / sizeof(RTUTF16), pwszExistingData,
683 cbValue, pwszValue, pwszValue));
684 }
685 else
686 Assert(rc == ERROR_FILE_NOT_FOUND || rc == ERROR_MORE_DATA);
687 }
688
689 /*
690 * Set the value.
691 */
692 rc = RegSetValueExW(hkey, pwszValueNm, 0 /*Reserved*/, REG_SZ, (const BYTE *)pwszValue, cbValue);
693 if (rc == ERROR_SUCCESS)
694 {
695 VBSP_LOG_SET_VALUE(("vbpsSetRegValueWW: %ls/%ls=%ls (at %d)\n",
696 vbpsDebugKeyToWSZ(hkey), pwszValueNm ? pwszValueNm : L"(Default)", pwszValue, uLine));
697 return ERROR_SUCCESS;
698 }
699
700 AssertMsgFailed(("%d: '%ls'='%ls' -> %u\n", uLine, pwszValueNm, pwszValue, rc));
701 pState->rc = rc;
702 return rc;
703}
704
705
706/**
707 * Sets a registry string value.
708 *
709 * @returns See RegSetValueExA (errors are remembered in the state).
710 * @param pState The registry modifier state.
711 * @param hkey The key to add the value to.
712 * @param pszValueNm The value name. NULL for setting the default.
713 * @param pszValue The value string.
714 * @param uLine The line we're called from.
715 */
716static LSTATUS vbpsSetRegValueAA(VBPSREGSTATE *pState, HKEY hkey, const char *pszValueNm, const char *pszValue, unsigned uLine)
717{
718 DWORD const cbValue = (DWORD)strlen(pszValue) + 1;
719 LSTATUS rc;
720 Assert(pState->fUpdate);
721
722 /*
723 * If we're not deleting the key prior to updating, we're in gentle update
724 * mode where we will query if the existing value matches the incoming one.
725 */
726 if (!pState->fDelete)
727 {
728 DWORD cbExistingData = cbValue + 128;
729 char *pszExistingData = alloca(cbExistingData);
730 DWORD dwExistingType;
731 rc = RegQueryValueExA(hkey, pszValueNm, 0 /*Reserved*/, &dwExistingType, pszExistingData, &cbExistingData);
732 if (rc == ERROR_SUCCESS)
733 {
734 if ( dwExistingType == REG_SZ
735 && cbExistingData == cbValue)
736 {
737 if (memcmp(pszValue, pszExistingData, cbValue) == 0)
738 return ERROR_SUCCESS;
739 if (memicmp(pszValue, pszExistingData, cbValue) == 0)
740 return ERROR_SUCCESS;
741 }
742 VBSP_LOG_VALUE_CHANGE(("vbpsSetRegValueAA: Value difference: dwExistingType=%d cbExistingData=%#x cbValue=%#x\n"
743 " hkey=%#x %ls; value name=%s\n"
744 "existing: %.*Rhxs (%.*s)\n"
745 " new: %.*Rhxs (%s)\n",
746 dwExistingType, cbExistingData, cbValue,
747 hkey, vbpsDebugKeyToWSZ(hkey), pszValueNm ? pszValueNm : "(default)",
748 cbExistingData, pszExistingData, cbExistingData, pszExistingData,
749 cbValue, pszValue, pszValue));
750 }
751 else
752 Assert(rc == ERROR_FILE_NOT_FOUND || rc == ERROR_MORE_DATA);
753 }
754
755 /*
756 * Set the value.
757 */
758 rc = RegSetValueExA(hkey, pszValueNm, 0 /*Reserved*/, REG_SZ, pszValue, cbValue);
759 if (rc == ERROR_SUCCESS)
760 {
761 VBSP_LOG_SET_VALUE(("vbpsSetRegValueAA: %ls/%s=%s (at %d)\n",
762 vbpsDebugKeyToWSZ(hkey), pszValueNm ? pszValueNm : "(Default)", pszValue, uLine));
763 return ERROR_SUCCESS;
764 }
765
766 AssertMsgFailed(("%d: '%s'='%s' -> %u\n", uLine, pszValueNm, pszValue, rc));
767 pState->rc = rc;
768 return rc;
769}
770
771
772/**
773 * Closes a registry key.
774 *
775 * @returns See RegCloseKey (errors are remembered in the state).
776 * @param pState The registry modifier state.
777 * @param hkey The key to close.
778 * @param uLine The line we're called from.
779 */
780static LSTATUS vbpsCloseKey(VBPSREGSTATE *pState, HKEY hkey, unsigned uLine)
781{
782 LSTATUS rc = RegCloseKey(hkey);
783 if (rc == ERROR_SUCCESS)
784 return ERROR_SUCCESS;
785
786 AssertMsgFailed(("%d: close key -> %u\n", uLine, rc));
787 pState->rc = rc;
788 return rc;
789}
790
791
792/**
793 * Creates a registry key.
794 *
795 * @returns See RegCreateKeyA and RegSetValueExA (errors are remembered in the
796 * state).
797 * @param pState The registry modifier state.
798 * @param hkeyParent The parent key.
799 * @param pszKey The new key under @a hkeyParent.
800 * @param phkey Where to return the handle to the new key.
801 * @param uLine The line we're called from.
802 */
803static LSTATUS vbpsCreateRegKeyA(VBPSREGSTATE *pState, HKEY hkeyParent, const char *pszKey, PHKEY phkey, unsigned uLine)
804{
805 /*
806 * This will open if it exists and create if new, which is exactly what we want.
807 */
808 HKEY hNewKey;
809 DWORD dwDisposition = 0;
810 LSTATUS rc = RegCreateKeyExA(hkeyParent, pszKey, 0 /*Reserved*/, NULL /*pszClass*/, 0 /*fOptions*/,
811 pState->fSamBoth, NULL /*pSecAttr*/, &hNewKey, &dwDisposition);
812 if (rc == ERROR_SUCCESS)
813 {
814 *phkey = hNewKey;
815 if (dwDisposition == REG_CREATED_NEW_KEY)
816 VBSP_LOG_NEW_KEY(("vbpsCreateRegKeyA: %ls/%s (at %d)\n", vbpsDebugKeyToWSZ(hkeyParent), pszKey, uLine));
817 }
818 else
819 {
820 AssertMsgFailed(("%d: create key '%s' -> %u\n", uLine, pszKey, rc));
821 pState->rc = rc;
822 *phkey = NULL;
823 }
824 return rc;
825}
826
827
828/**
829 * Creates a registry key with a default string value.
830 *
831 * @returns See RegCreateKeyA and RegSetValueExA (errors are remembered in the
832 * state).
833 * @param pState The registry modifier state.
834 * @param hkeyParent The parent key.
835 * @param pszKey The new key under @a hkeyParent.
836 * @param pszValue The value string.
837 * @param uLine The line we're called from.
838 */
839static LSTATUS vbpsCreateRegKeyWithDefaultValueAA(VBPSREGSTATE *pState, HKEY hkeyParent, const char *pszKey,
840 const char *pszValue, unsigned uLine)
841{
842 HKEY hNewKey;
843 LSTATUS rc = vbpsCreateRegKeyA(pState, hkeyParent, pszKey, &hNewKey, uLine);
844 if (rc == ERROR_SUCCESS)
845 {
846 rc = vbpsSetRegValueAA(pState, hNewKey, NULL /*pszValueNm*/, pszValue, uLine);
847 vbpsCloseKey(pState, hNewKey, uLine);
848 }
849 else
850 {
851 AssertMsgFailed(("%d: create key '%s'(/Default='%s') -> %u\n", uLine, pszKey, pszValue, rc));
852 pState->rc = rc;
853 }
854 return rc;
855}
856
857
858/**
859 * Creates a registry key with a default wide string value.
860 *
861 * @returns See RegCreateKeyA and RegSetValueExA (errors are remembered in the
862 * state).
863 * @param pState The registry modifier state.
864 * @param hkeyParent The parent key.
865 * @param pszKey The new key under @a hkeyParent.
866 * @param pwszValue The value string.
867 * @param uLine The line we're called from.
868 */
869static LSTATUS vbpsCreateRegKeyWithDefaultValueAW(VBPSREGSTATE *pState, HKEY hkeyParent, const char *pszKey,
870 PCRTUTF16 pwszValue, unsigned uLine)
871{
872 HKEY hNewKey;
873 LSTATUS rc = vbpsCreateRegKeyA(pState, hkeyParent, pszKey, &hNewKey, uLine);
874 if (rc == ERROR_SUCCESS)
875 {
876 rc = vbpsSetRegValueWW(pState, hNewKey, NULL /*pwszValueNm*/, pwszValue, uLine);
877 vbpsCloseKey(pState, hNewKey, uLine);
878 }
879 else
880 {
881 AssertMsgFailed(("%d: create key '%s'(/Default='%ls') -> %u\n", uLine, pszKey, pwszValue, rc));
882 pState->rc = rc;
883 }
884 return rc;
885}
886
887
888/**
889 * Creates a registry key with a default string value, return the key.
890 *
891 * @returns See RegCreateKeyA and RegSetValueExA (errors are remembered in the
892 * state).
893 * @param pState The registry modifier state.
894 * @param hkeyParent The parent key.
895 * @param pszKey The new key under @a hkeyParent.
896 * @param pszValue The value string.
897 * @param phkey Where to return the handle to the new key.
898 * @param uLine The line we're called from.
899 */
900static LSTATUS vbpsCreateRegKeyWithDefaultValueAAEx(VBPSREGSTATE *pState, HKEY hkeyParent, const char *pszKey,
901 const char *pszValue, PHKEY phkey, unsigned uLine)
902{
903 HKEY hNewKey;
904 LSTATUS rc = vbpsCreateRegKeyA(pState, hkeyParent, pszKey, &hNewKey, uLine);
905 if (rc == ERROR_SUCCESS)
906 {
907 rc = vbpsSetRegValueAA(pState, hNewKey, NULL /*pszValueNm*/, pszValue, uLine);
908 *phkey = hNewKey;
909 }
910 else
911 {
912 AssertMsgFailed(("%d: create key '%s'(/Default='%s') -> %u\n", uLine, pszKey, pszValue, rc));
913 pState->rc = rc;
914 *phkey = NULL;
915 }
916 return rc;
917}
918
919
920/**
921 * Recursively deletes a registry key.
922 *
923 * @returns See SHDeleteKeyA (errors are remembered in the state).
924 * @param pState The registry modifier state.
925 * @param hkeyParent The parent key.
926 * @param pszKey The key under @a hkeyParent that should be
927 * deleted.
928 * @param uLine The line we're called from.
929 */
930static LSTATUS vbpsDeleteKeyRecursiveA(VBPSREGSTATE *pState, HKEY hkeyParent, const char *pszKey, unsigned uLine)
931{
932 LSTATUS rc;
933
934 Assert(pState->fDelete);
935 Assert(pszKey);
936 AssertReturn(*pszKey != '\0', pState->rc = ERROR_INVALID_PARAMETER);
937
938#ifdef VBSP_LOG_ENABLED
939 {
940 HKEY hkeyLog;
941 rc = RegOpenKeyExA(hkeyParent, pszKey, 0 /*fOptions*/, pState->fSamDelete, &hkeyLog);
942 if (rc != ERROR_FILE_NOT_FOUND)
943 VBSP_LOG_DEL_KEY(("vbpsDeleteKeyRecursiveA: %ls/%s (at %d)\n", vbpsDebugKeyToWSZ(hkeyParent), pszKey, uLine));
944 if (rc == ERROR_SUCCESS)
945 RegCloseKey(hkeyLog);
946 }
947#endif
948
949 rc = SHDeleteKeyA(hkeyParent, pszKey);
950 if (rc == ERROR_SUCCESS || rc == ERROR_FILE_NOT_FOUND)
951 return ERROR_SUCCESS;
952
953 AssertMsgFailed(("%d: delete key '%s' -> %u\n", uLine, pszKey, rc));
954 pState->rc = rc;
955 return rc;
956}
957
958
959/**
960 * Recursively deletes a registry key, wide char version.
961 *
962 * @returns See SHDeleteKeyW (errors are remembered in the state).
963 * @param pState The registry modifier state.
964 * @param hkeyParent The parent key.
965 * @param pwszKey The key under @a hkeyParent that should be
966 * deleted.
967 * @param uLine The line we're called from.
968 */
969static LSTATUS vbpsDeleteKeyRecursiveW(VBPSREGSTATE *pState, HKEY hkeyParent, PCRTUTF16 pwszKey, unsigned uLine)
970{
971 LSTATUS rc;
972
973 Assert(pState->fDelete);
974 Assert(pwszKey);
975 AssertReturn(*pwszKey != '\0', pState->rc = ERROR_INVALID_PARAMETER);
976
977#ifdef VBSP_LOG_ENABLED
978 {
979 HKEY hkeyLog;
980 rc = RegOpenKeyExW(hkeyParent, pwszKey, 0 /*fOptions*/, pState->fSamDelete, &hkeyLog);
981 if (rc != ERROR_FILE_NOT_FOUND)
982 VBSP_LOG_DEL_KEY(("vbpsDeleteKeyRecursiveW: %ls/%ls (at %d)\n", vbpsDebugKeyToWSZ(hkeyParent), pwszKey, uLine));
983 if (rc == ERROR_SUCCESS)
984 RegCloseKey(hkeyLog);
985 }
986#endif
987
988 rc = SHDeleteKeyW(hkeyParent, pwszKey);
989 if (rc == ERROR_SUCCESS || rc == ERROR_FILE_NOT_FOUND)
990 return ERROR_SUCCESS;
991
992 AssertMsgFailed(("%d: delete key '%ls' -> %u\n", uLine, pwszKey, rc));
993 pState->rc = rc;
994 return rc;
995}
996
997
998/**
999 * Register an application id.
1000 *
1001 * @returns Windows error code (errors are rememberd in the state).
1002 * @param pState The registry modifier state.
1003 * @param pszAppId The application UUID string.
1004 * @param pszDescription The description string.
1005 */
1006LSTATUS VbpsRegisterAppId(VBPSREGSTATE *pState, const char *pszAppId, const char *pszDescription)
1007{
1008 LSTATUS rc;
1009 HKEY hkeyAppIds;
1010 Assert(*pszAppId == '{');
1011
1012 /*
1013 * Delete.
1014 */
1015 if (pState->fDelete)
1016 {
1017 unsigned i = pState->cAltDeletes;
1018 while (i-- > 0)
1019 {
1020 rc = RegOpenKeyExW(pState->aAltDeletes[i].hkeyClasses, L"AppID", 0 /*fOptions*/, pState->fSamDelete, &hkeyAppIds);
1021 AssertMsgStmt(rc == ERROR_SUCCESS || rc == ERROR_FILE_NOT_FOUND, ("%u\n", rc), pState->rc = rc);
1022 if (rc == ERROR_SUCCESS)
1023 {
1024 vbpsDeleteKeyRecursiveA(pState, hkeyAppIds, pszAppId, __LINE__);
1025 vbpsCloseKey(pState, hkeyAppIds, __LINE__);
1026 }
1027 }
1028 }
1029
1030 if (pState->fUpdate)
1031 rc = RegCreateKeyExW(pState->hkeyClassesRootDst, L"AppID", 0 /*Reserved*/, NULL /*pszClass*/, 0 /*fOptions*/,
1032 pState->fSamBoth, NULL /*pSecAttr*/, &hkeyAppIds, NULL /*pdwDisposition*/);
1033
1034 else
1035 {
1036 rc = RegOpenKeyExW(pState->hkeyClassesRootDst, L"AppID", 0 /*fOptions*/, pState->fSamBoth, &hkeyAppIds);
1037 if (rc == ERROR_FILE_NOT_FOUND)
1038 return ERROR_SUCCESS;
1039 }
1040 AssertMsgReturn(rc == ERROR_SUCCESS, ("%u\n", rc), pState->rc = rc);
1041
1042 if (pState->fDelete)
1043 vbpsDeleteKeyRecursiveA(pState, hkeyAppIds, pszAppId, __LINE__);
1044
1045 /*
1046 * Update.
1047 */
1048 if (pState->fUpdate)
1049 vbpsCreateRegKeyWithDefaultValueAA(pState, hkeyAppIds, pszAppId, pszDescription, __LINE__);
1050
1051 vbpsCloseKey(pState, hkeyAppIds, __LINE__);
1052
1053 return pState->rc;
1054}
1055
1056
1057/**
1058 * Register an class name.
1059 *
1060 * @returns Windows error code (errors are rememberd in the state).
1061 * @param pState The registry modifier state.
1062 * @param pszClassName The name of the class.
1063 * @param pszDescription The description string
1064 * @param pClsId The UUID for the class.
1065 * @param pszCurVerSuffIfRootName This is the current version suffix to
1066 * append to @a pszClassName when
1067 * registering the version idependent name.
1068 */
1069LSTATUS VbpsRegisterClassName(VBPSREGSTATE *pState, const char *pszClassName, const char *pszDescription,
1070 const CLSID *pClsId, const char *pszCurVerSuffIfRootName)
1071{
1072 LSTATUS rc;
1073
1074 /*
1075 * Delete.
1076 */
1077 if (pState->fDelete)
1078 {
1079 unsigned i = pState->cAltDeletes;
1080 while (i-- > 0)
1081 vbpsDeleteKeyRecursiveA(pState, pState->aAltDeletes[i].hkeyClasses, pszClassName, __LINE__);
1082 vbpsDeleteKeyRecursiveA(pState, pState->hkeyClassesRootDst, pszClassName, __LINE__);
1083 }
1084
1085 /*
1086 * Update.
1087 */
1088 if (pState->fUpdate)
1089 {
1090 /* pszClassName/Default = description. */
1091 HKEY hkeyClass;
1092 rc = vbpsCreateRegKeyWithDefaultValueAAEx(pState, pState->hkeyClassesRootDst, pszClassName, pszDescription,
1093 &hkeyClass, __LINE__);
1094 if (rc == ERROR_SUCCESS)
1095 {
1096 char szClsId[CURLY_UUID_STR_BUF_SIZE];
1097
1098 /* CLSID/Default = pClsId. */
1099 vbpsCreateRegKeyWithDefaultValueAA(pState, hkeyClass, "CLSID", vbpsFormatUuidInCurly(szClsId, pClsId), __LINE__);
1100
1101 /* CurVer/Default = pszClassName+Suffix. */
1102 if (pszCurVerSuffIfRootName != NULL)
1103 {
1104 char szCurClassNameVer[128];
1105 rc = RTStrCopy(szCurClassNameVer, sizeof(szCurClassNameVer), pszClassName);
1106 if (RT_SUCCESS(rc))
1107 rc = RTStrCat(szCurClassNameVer, sizeof(szCurClassNameVer), pszCurVerSuffIfRootName);
1108 AssertStmt(RT_SUCCESS(rc), pState->rc = rc = ERROR_INVALID_DATA);
1109 if (rc == ERROR_SUCCESS)
1110 vbpsCreateRegKeyWithDefaultValueAA(pState, hkeyClass, "CurVer", szCurClassNameVer, __LINE__);
1111 }
1112
1113 vbpsCloseKey(pState, hkeyClass, __LINE__);
1114 }
1115 }
1116
1117 return pState->rc;
1118}
1119
1120
1121/**
1122 * Registers a class ID.
1123 *
1124 * @returns Windows error code (errors are rememberd in the state).
1125 * @param pState The registry modifier state.
1126 * @param pClsId The UUID for the class.
1127 * @param pszDescription The description string.
1128 * @param pszAppId The application ID.
1129 * @param pszClassName The version idependent class name.
1130 * @param pszCurClassNameVerSuffix The suffix to add to @a pszClassName for
1131 * the current version.
1132 * @param pTypeLibId The UUID for the typelib this class
1133 * belongs to.
1134 * @param pszServerType The server type (InprocServer32 or
1135 * LocalServer32).
1136 * @param pwszVBoxDir The VirtualBox install directory
1137 * (unicode), trailing slash.
1138 * @param pszServerSubPath What to append to @a pwszVBoxDir to
1139 * construct the server module name.
1140 * @param pszThreadingModel The threading model for inproc servers,
1141 * NULL for local servers.
1142 */
1143LSTATUS VbpsRegisterClassId(VBPSREGSTATE *pState, const CLSID *pClsId, const char *pszDescription, const char *pszAppId,
1144 const char *pszClassName, const char *pszCurClassNameVerSuffix, const CLSID *pTypeLibId,
1145 const char *pszServerType, PCRTUTF16 pwszVBoxDir, const char *pszServerSubPath,
1146 const char *pszThreadingModel)
1147{
1148 LSTATUS rc;
1149 char szClsId[CURLY_UUID_STR_BUF_SIZE];
1150
1151 Assert(!pszAppId || *pszAppId == '{');
1152 Assert((pwszVBoxDir == NULL && !pState->fUpdate) || pwszVBoxDir[RTUtf16Len(pwszVBoxDir) - 1] == '\\');
1153
1154 /*
1155 * We need this, whatever we end up having to do.
1156 */
1157 vbpsFormatUuidInCurly(szClsId, pClsId);
1158
1159 /*
1160 * Delete.
1161 */
1162 if (pState->fDelete)
1163 {
1164 unsigned i = pState->cAltDeletes;
1165 while (i-- > 0)
1166 if (pState->aAltDeletes[i].hkeyClsid != NULL)
1167 vbpsDeleteKeyRecursiveA(pState, pState->aAltDeletes[i].hkeyClsid, szClsId, __LINE__);
1168 vbpsDeleteKeyRecursiveA(pState, pState->hkeyClsidRootDst, szClsId, __LINE__);
1169 }
1170
1171 /*
1172 * Update.
1173 */
1174 if (pState->fUpdate)
1175 {
1176 HKEY hkeyClass;
1177 rc = vbpsCreateRegKeyWithDefaultValueAAEx(pState, pState->hkeyClsidRootDst, szClsId, pszDescription,
1178 &hkeyClass, __LINE__);
1179 if (rc == ERROR_SUCCESS)
1180 {
1181 HKEY hkeyServerType;
1182 char szCurClassNameVer[128];
1183
1184 /* pszServerType/Default = module. */
1185 rc = vbpsCreateRegKeyA(pState, hkeyClass, pszServerType, &hkeyServerType, __LINE__);
1186 if (rc == ERROR_SUCCESS)
1187 {
1188 RTUTF16 wszModule[MAX_PATH * 2];
1189 PRTUTF16 pwszCur = wszModule;
1190 bool fQuoteIt = strcmp(pszServerType, "LocalServer32") == 0;
1191 if (fQuoteIt)
1192 *pwszCur++ = '"';
1193
1194 rc = RTUtf16Copy(pwszCur, MAX_PATH, pwszVBoxDir); AssertRC(rc);
1195 pwszCur += RTUtf16Len(pwszCur);
1196 rc = RTUtf16CopyAscii(pwszCur, MAX_PATH - 3, pszServerSubPath); AssertRC(rc);
1197 pwszCur += RTUtf16Len(pwszCur);
1198
1199 if (fQuoteIt)
1200 *pwszCur++ = '"';
1201 *pwszCur++ = '\0'; /* included, so ++. */
1202
1203 vbpsSetRegValueWW(pState, hkeyServerType, NULL /*pszValueNm*/, wszModule, __LINE__);
1204
1205 /* pszServerType/ThreadingModel = pszThreading Model. */
1206 if (pszThreadingModel)
1207 vbpsSetRegValueAA(pState, hkeyServerType, "ThreadingModel", pszThreadingModel, __LINE__);
1208
1209 vbpsCloseKey(pState, hkeyServerType, __LINE__);
1210 }
1211
1212 /* ProgId/Default = pszClassName + pszCurClassNameVerSuffix. */
1213 if (pszClassName)
1214 {
1215 rc = RTStrCopy(szCurClassNameVer, sizeof(szCurClassNameVer), pszClassName);
1216 if (RT_SUCCESS(rc))
1217 rc = RTStrCat(szCurClassNameVer, sizeof(szCurClassNameVer), pszCurClassNameVerSuffix);
1218 AssertStmt(RT_SUCCESS(rc), pState->rc = rc = ERROR_INVALID_DATA);
1219 if (rc == ERROR_SUCCESS)
1220 vbpsCreateRegKeyWithDefaultValueAA(pState, hkeyClass, "ProgId", szCurClassNameVer, __LINE__);
1221
1222 /* VersionIndependentProgID/Default = pszClassName. */
1223 vbpsCreateRegKeyWithDefaultValueAA(pState, hkeyClass, "VersionIndependentProgID", pszClassName, __LINE__);
1224 }
1225
1226 /* TypeLib/Default = pTypeLibId. */
1227 if (pTypeLibId)
1228 {
1229 char szTypeLibId[CURLY_UUID_STR_BUF_SIZE];
1230 vbpsCreateRegKeyWithDefaultValueAA(pState, hkeyClass, "TypeLib",
1231 vbpsFormatUuidInCurly(szTypeLibId, pTypeLibId), __LINE__);
1232 }
1233
1234 vbpsCloseKey(pState, hkeyClass, __LINE__);
1235 }
1236 }
1237
1238 return pState->rc;
1239}
1240
1241
1242/**
1243 * Register modules and classes from the VirtualBox.xidl file.
1244 *
1245 * @returns COM status code.
1246 * @param pwszVBoxDir The VirtualBox application directory.
1247 * @param fIs32On64 Set if this is the 32-bit on 64-bit component.
1248 *
1249 * @todo convert to XSLT.
1250 */
1251void RegisterXidlModulesAndClassesGenerated(VBPSREGSTATE *pState, PCRTUTF16 pwszVBoxDir, bool fIs32On64)
1252{
1253 const char *pszAppId = "{819B4D85-9CEE-493C-B6FC-64FFE759B3C9}";
1254 const char *pszInprocDll = !fIs32On64 ? "VBoxC.dll" : "x86\\VBoxClient-x86.dll";
1255
1256 VbpsRegisterAppId(pState, pszAppId, "VirtualBox Application");
1257
1258 /* VBoxSVC */
1259 VbpsRegisterClassName(pState, "VirtualBox.VirtualBox.1", "VirtualBox Class", &CLSID_VirtualBox, NULL);
1260 VbpsRegisterClassName(pState, "VirtualBox.VirtualBox", "VirtualBox Class", &CLSID_VirtualBox, ".1");
1261 VbpsRegisterClassId(pState, &CLSID_VirtualBox, "VirtualBox Class", pszAppId, "VirtualBox.VirtualBox", ".1",
1262 &LIBID_VirtualBox, "LocalServer32", pwszVBoxDir, "VBoxSVC.exe", NULL /*N/A*/);
1263 /* VBoxC */
1264 VbpsRegisterClassName(pState, "VirtualBox.Session.1", "Session Class", &CLSID_Session, NULL);
1265 VbpsRegisterClassName(pState, "VirtualBox.Session", "Session Class", &CLSID_Session, ".1");
1266 VbpsRegisterClassId(pState, &CLSID_Session, "Session Class", pszAppId, "VirtualBox.Session", ".1",
1267 &LIBID_VirtualBox, "InprocServer32", pwszVBoxDir, pszInprocDll, "Free");
1268
1269 VbpsRegisterClassName(pState, "VirtualBox.VirtualBoxClient.1", "VirtualBoxClient Class", &CLSID_VirtualBoxClient, NULL);
1270 VbpsRegisterClassName(pState, "VirtualBox.VirtualBoxClient", "VirtualBoxClient Class", &CLSID_VirtualBoxClient, ".1");
1271 VbpsRegisterClassId(pState, &CLSID_VirtualBoxClient, "VirtualBoxClient Class", pszAppId,
1272 "VirtualBox.VirtualBoxClient", ".1",
1273 &LIBID_VirtualBox, "InprocServer32", pwszVBoxDir, pszInprocDll, "Free");
1274}
1275
1276
1277/**
1278 * Updates the VBox type lib registration.
1279 *
1280 * This is only used when updating COM registrations during com::Initialize.
1281 * For normal registration and unregistrations we use the RegisterTypeLib and
1282 * UnRegisterTypeLib APIs.
1283 *
1284 * @param pState The registry modifier state.
1285 * @param pwszVBoxDir The VirtualBox install directory (unicode),
1286 * trailing slash.
1287 * @param fIs32On64 Set if we're registering the 32-bit proxy stub
1288 * on a 64-bit system.
1289 */
1290static void vbpsUpdateTypeLibRegistration(VBPSREGSTATE *pState, PCRTUTF16 pwszVBoxDir, bool fIs32On64)
1291{
1292 const char * const pszTypeLibDll = VBPS_PROXY_STUB_FILE(fIs32On64);
1293 const char * const pszWinXx = !fIs32On64 ? "win64" : "win32";
1294 const char * const pszDescription = "VirtualBox Type Library";
1295
1296 char szTypeLibId[CURLY_UUID_STR_BUF_SIZE];
1297 HKEY hkeyTypeLibs;
1298 HKEY hkeyTypeLibId;
1299 LSTATUS rc;
1300
1301 Assert(pState->fUpdate && !pState->fDelete);
1302
1303 /*
1304 * Type library registration (w/o interfaces).
1305 */
1306
1307 /* Open Classes/TypeLib/. */
1308 rc = vbpsCreateRegKeyA(pState, pState->hkeyClassesRootDst, "TypeLib", &hkeyTypeLibs, __LINE__);
1309 AssertReturnVoid(rc == ERROR_SUCCESS);
1310
1311 /* Create TypeLib/{UUID}. */
1312 rc = vbpsCreateRegKeyA(pState, hkeyTypeLibs, vbpsFormatUuidInCurly(szTypeLibId, &LIBID_VirtualBox), &hkeyTypeLibId, __LINE__);
1313 if (rc == ERROR_SUCCESS)
1314 {
1315 /* {UUID}/Major.Minor/Default = pszDescription. */
1316 HKEY hkeyMajMin;
1317 char szMajMin[64];
1318 sprintf(szMajMin, "%u.%u", kTypeLibraryMajorVersion, kTypeLibraryMinorVersion);
1319 rc = vbpsCreateRegKeyWithDefaultValueAAEx(pState, hkeyTypeLibId, szMajMin, pszDescription, &hkeyMajMin, __LINE__);
1320 if (rc == ERROR_SUCCESS)
1321 {
1322 RTUTF16 wszBuf[MAX_PATH * 2];
1323
1324 /* {UUID}/Major.Minor/0. */
1325 HKEY hkey0;
1326 rc = vbpsCreateRegKeyA(pState, hkeyMajMin, "0", &hkey0, __LINE__);
1327 if (rc == ERROR_SUCCESS)
1328 {
1329 /* {UUID}/Major.Minor/0/winXX/Default = VBoxProxyStub. */
1330 rc = RTUtf16Copy(wszBuf, MAX_PATH, pwszVBoxDir); AssertRC(rc);
1331 rc = RTUtf16CatAscii(wszBuf, MAX_PATH * 2, pszTypeLibDll); AssertRC(rc);
1332
1333 vbpsCreateRegKeyWithDefaultValueAW(pState, hkey0, pszWinXx, wszBuf, __LINE__);
1334 vbpsCloseKey(pState, hkey0, __LINE__);
1335 }
1336
1337 /* {UUID}/Major.Minor/FLAGS */
1338 vbpsCreateRegKeyWithDefaultValueAA(pState, hkeyMajMin, "FLAGS", "0", __LINE__);
1339
1340 /* {UUID}/Major.Minor/HELPDIR */
1341 rc = RTUtf16Copy(wszBuf, MAX_PATH, pwszVBoxDir); AssertRC(rc);
1342#if 0 /* MSI: trailing slash; regsvr32/comregister: strip unnecessary trailing slash. Go with MSI to avoid user issues. */
1343 {
1344 size_t off = RTUtf16Len(wszBuf);
1345 while (off > 2 && wszBuf[off - 2] != ':' && RTPATH_IS_SLASH(wszBuf[off - 1]))
1346 off--;
1347 wszBuf[off] = '\0';
1348 }
1349#endif
1350 vbpsCreateRegKeyWithDefaultValueAW(pState, hkeyMajMin, "HELPDIR", wszBuf, __LINE__);
1351
1352 vbpsCloseKey(pState, hkeyMajMin, __LINE__);
1353 }
1354 vbpsCloseKey(pState, hkeyTypeLibId, __LINE__);
1355 }
1356 vbpsCloseKey(pState, hkeyTypeLibs, __LINE__);
1357}
1358
1359
1360/**
1361 * Update the VBox proxy stub registration.
1362 *
1363 * This is only used when updating COM registrations during com::Initialize.
1364 * For normal registration and unregistrations we use the NdrDllRegisterProxy
1365 * and NdrDllUnregisterProxy.
1366 *
1367 * @param pState The registry modifier state.
1368 * @param pwszVBoxDir The VirtualBox install directory (unicode),
1369 * trailing slash.
1370 * @param fIs32On64 Set if we're registering the 32-bit proxy stub
1371 * on a 64-bit system.
1372 */
1373static void vbpsUpdateProxyStubRegistration(VBPSREGSTATE *pState, PCRTUTF16 pwszVBoxDir, bool fIs32On64)
1374{
1375 /*
1376 * Register the proxy stub factory class ID.
1377 * It's simple compared to the VBox classes, thus all the NULL parameters.
1378 */
1379 const char *pszPsDll = VBPS_PROXY_STUB_FILE(fIs32On64);
1380 Assert(pState->fUpdate && !pState->fDelete);
1381 VbpsRegisterClassId(pState, &g_ProxyClsId, "PSFactoryBuffer", NULL /*pszAppId*/,
1382 NULL /*pszClassName*/, NULL /*pszCurClassNameVerSuffix*/, NULL /*pTypeLibId*/,
1383 "InprocServer32", pwszVBoxDir, pszPsDll, "Both");
1384}
1385
1386
1387/**
1388 * Updates the VBox interface registrations.
1389 *
1390 * This is only used when updating COM registrations during com::Initialize.
1391 * For normal registration and unregistrations we use the NdrDllRegisterProxy
1392 * and NdrDllUnregisterProxy.
1393 *
1394 * @param pState The registry modifier state.
1395 * @param pwszVBoxDir The VirtualBox install directory (unicode),
1396 * trailing slash.
1397 * @param fIs32On64 Set if we're registering the 32-bit proxy stub
1398 * on a 64-bit system.
1399 */
1400static void vbpsUpdateInterfaceRegistrations(VBPSREGSTATE *pState)
1401{
1402 const ProxyFileInfo **ppProxyFile = &g_apProxyFiles[0];
1403 const ProxyFileInfo *pProxyFile;
1404 LSTATUS rc;
1405 char szProxyClsId[CURLY_UUID_STR_BUF_SIZE];
1406 char szTypeLibId[CURLY_UUID_STR_BUF_SIZE];
1407 char szTypeLibVersion[64];
1408
1409 vbpsFormatUuidInCurly(szProxyClsId, &g_ProxyClsId);
1410 vbpsFormatUuidInCurly(szTypeLibId, &LIBID_VirtualBox);
1411 sprintf(szTypeLibVersion, "%u.%u", kTypeLibraryMajorVersion, kTypeLibraryMinorVersion);
1412
1413 Assert(pState->fUpdate && !pState->fDelete);
1414 rc = vbpsRegOpenInterfaceKeys(pState);
1415 AssertReturnVoid(rc == ERROR_SUCCESS);
1416
1417 /*
1418 * We walk the proxy file list (even if we only have one).
1419 */
1420 while ((pProxyFile = *ppProxyFile++) != NULL)
1421 {
1422 const PCInterfaceStubVtblList * const papStubVtbls = pProxyFile->pStubVtblList;
1423 const char * const *papszNames = pProxyFile->pNamesArray;
1424 unsigned iIf = pProxyFile->TableSize;
1425 AssertStmt(iIf < 1024, iIf = 0);
1426 Assert(pProxyFile->TableVersion == 2);
1427
1428 /*
1429 * Walk the interfaces in that file, picking data from the various tables.
1430 */
1431 while (iIf-- > 0)
1432 {
1433 char szIfId[CURLY_UUID_STR_BUF_SIZE];
1434 const char * const pszIfNm = papszNames[iIf];
1435 size_t const cchIfNm = RT_VALID_PTR(pszIfNm) ? strlen(pszIfNm) : 0;
1436 char szMethods[32];
1437 uint32_t const cMethods = papStubVtbls[iIf]->header.DispatchTableCount;
1438 HKEY hkeyIfId;
1439
1440 AssertReturnVoidStmt(cchIfNm >= 3 && cchIfNm <= 72, pState->rc = ERROR_INVALID_DATA);
1441
1442 AssertReturnVoidStmt(cMethods >= 3 && cMethods < 1024, pState->rc = ERROR_INVALID_DATA);
1443 sprintf(szMethods, "%u", cMethods);
1444
1445 AssertReturnVoid(rc == ERROR_SUCCESS);
1446
1447 rc = vbpsCreateRegKeyWithDefaultValueAAEx(pState, pState->hkeyInterfaceRootDst,
1448 vbpsFormatUuidInCurly(szIfId, papStubVtbls[iIf]->header.piid),
1449 pszIfNm, &hkeyIfId, __LINE__);
1450 if (rc == ERROR_SUCCESS)
1451 {
1452 HKEY hkeyTypeLib;
1453 vbpsCreateRegKeyWithDefaultValueAA(pState, hkeyIfId, "ProxyStubClsid32", szProxyClsId, __LINE__);
1454 vbpsCreateRegKeyWithDefaultValueAA(pState, hkeyIfId, "NumMethods", szMethods, __LINE__);
1455
1456 /* The MSI seems to still be putting TypeLib keys here. So, let's do that too. */
1457 rc = vbpsCreateRegKeyWithDefaultValueAAEx(pState, hkeyIfId, "TypeLib", szTypeLibId, &hkeyTypeLib, __LINE__);
1458 if (rc == ERROR_SUCCESS)
1459 {
1460 vbpsSetRegValueAA(pState, hkeyTypeLib, "Version", szTypeLibVersion, __LINE__);
1461 vbpsCloseKey(pState, hkeyTypeLib, __LINE__);
1462 }
1463
1464 vbpsCloseKey(pState, hkeyIfId, __LINE__);
1465 }
1466 }
1467 }
1468}
1469
1470
1471static bool vbpsIsUpToDate(VBPSREGSTATE *pState)
1472{
1473 /** @todo read some registry key and */
1474 NOREF(pState);
1475 return false;
1476}
1477
1478static bool vbpsMarkUpToDate(VBPSREGSTATE *pState)
1479{
1480 /** @todo write the key vbpsIsUpToDate uses, if pState indicates success. */
1481 NOREF(pState);
1482 return false;
1483}
1484
1485
1486
1487/**
1488 * Strips the stub dll name and any x86 subdir off the full DLL path to get a
1489 * path to the VirtualBox application directory.
1490 *
1491 * @param pwszDllPath The path to strip, returns will end with a slash.
1492 */
1493static void vbpsDllPathToVBoxDir(PRTUTF16 pwszDllPath)
1494{
1495 RTUTF16 wc;
1496 size_t off = RTUtf16Len(pwszDllPath);
1497 while ( off > 0
1498 && ( (wc = pwszDllPath[off - 1]) >= 127U
1499 || !RTPATH_IS_SEP((unsigned char)wc)))
1500 off--;
1501
1502#ifdef VBOX_IN_32_ON_64_MAIN_API
1503 /*
1504 * The -x86 variant is in a x86 subdirectory, drop it.
1505 */
1506 while ( off > 0
1507 && ( (wc = pwszDllPath[off - 1]) < 127U
1508 && RTPATH_IS_SEP((unsigned char)wc)))
1509 off--;
1510 while ( off > 0
1511 && ( (wc = pwszDllPath[off - 1]) >= 127U
1512 || !RTPATH_IS_SEP((unsigned char)wc)))
1513 off--;
1514#endif
1515 pwszDllPath[off] = '\0';
1516}
1517
1518
1519/**
1520 * Wrapper around RegisterXidlModulesAndClassesGenerated for the convenience of
1521 * the standard registration entry points.
1522 *
1523 * @returns COM status code.
1524 * @param pwszVBoxDir The VirtualBox install directory (unicode),
1525 * trailing slash.
1526 * @param fDelete Whether to delete registration keys and values.
1527 * @param fUpdate Whether to update registration keys and values.
1528 */
1529HRESULT RegisterXidlModulesAndClasses(PRTUTF16 pwszVBoxDir, bool fDelete, bool fUpdate)
1530{
1531#ifdef VBOX_IN_32_ON_64_MAIN_API
1532 bool const fIs32On64 = true;
1533#else
1534 bool const fIs32On64 = false;
1535#endif
1536 VBPSREGSTATE State;
1537 LSTATUS rc;
1538
1539 /*
1540 * Do registration for the current execution mode of the DLL.
1541 */
1542 rc = vbpsRegInit(&State, HKEY_CLASSES_ROOT, NULL /* Alt: HKEY_LOCAL_MACHINE, "Software\\Classes", */, fDelete, fUpdate, 0);
1543 if (rc == ERROR_SUCCESS)
1544 {
1545 if (!fUpdate)
1546 {
1547 /* When only unregistering, really purge everything twice or trice. :-) */
1548 vbpsRegAddAltDelete(&State, HKEY_LOCAL_MACHINE, "Software\\Classes");
1549 vbpsRegAddAltDelete(&State, HKEY_CURRENT_USER, "Software\\Classes");
1550 vbpsRegAddAltDelete(&State, HKEY_CLASSES_ROOT, NULL);
1551 }
1552
1553 RegisterXidlModulesAndClassesGenerated(&State, pwszVBoxDir, fIs32On64);
1554 rc = State.rc;
1555 }
1556 vbpsRegTerm(&State);
1557
1558 /*
1559 * Translate error code? Return.
1560 */
1561 if (rc == ERROR_SUCCESS)
1562 return S_OK;
1563 return E_FAIL;
1564}
1565
1566
1567/**
1568 * Checks if the string matches any of our type library versions.
1569 *
1570 * @returns true on match, false on mismatch.
1571 * @param pwszTypeLibVersion The type library version string.
1572 */
1573static DECLINLINE(bool) vbpsIsTypeLibVersionToRemove(PCRTUTF16 pwszTypeLibVersion)
1574{
1575 AssertCompile(RT_ELEMENTS(g_apwszTypelibVersions) == 2);
1576
1577 /* ASSUMES: 1.x version strings and that the input buffer is at least 3 wchars long. */
1578 if ( g_apwszTypelibVersions[0][3] == pwszTypeLibVersion[3]
1579 && RTUtf16Cmp(g_apwszTypelibVersions[0], pwszTypeLibVersion) == 0)
1580 return true;
1581 if ( g_apwszTypelibVersions[1][3] == pwszTypeLibVersion[3]
1582 && RTUtf16Cmp(g_apwszTypelibVersions[1], pwszTypeLibVersion) == 0)
1583 return true;
1584
1585 return false;
1586}
1587
1588
1589/**
1590 * Quick check whether the given string looks like a UUID in braces.
1591 *
1592 * This does not check the whole string, just do a quick sweep.
1593 *
1594 * @returns true if possible UUID, false if definitely not.
1595 * @param pwszUuid Alleged UUID in braces.
1596 */
1597DECLINLINE(bool) vbpsIsUuidInBracesQuickW(PCRTUTF16 pwszUuid)
1598{
1599 return pwszUuid[ 0] == '{'
1600 && pwszUuid[ 9] == '-'
1601 && pwszUuid[14] == '-'
1602 && pwszUuid[19] == '-'
1603 && pwszUuid[24] == '-'
1604 && pwszUuid[37] == '}'
1605 && pwszUuid[38] == '\0'
1606 && RT_C_IS_XDIGIT(pwszUuid[1]);
1607}
1608
1609
1610/**
1611 * Compares two UUIDs (in braces).
1612 *
1613 * @returns true on match, false if no match.
1614 * @param pwszUuid1 The first UUID.
1615 * @param pwszUuid2 The second UUID.
1616 */
1617static bool vbpsCompareUuidW(PCRTUTF16 pwszUuid1, PCRTUTF16 pwszUuid2)
1618{
1619#define COMPARE_EXACT_RET(a_wch1, a_wch2) \
1620 if ((a_wch1) == (a_wch2)) { } else return false
1621
1622#define COMPARE_XDIGITS_RET(a_wch1, a_wch2) \
1623 if ((a_wch1) == (a_wch2)) { } \
1624 else if (RT_C_TO_UPPER(a_wch1) != RT_C_TO_UPPER(a_wch2) || (a_wch1) >= 127U || (a_wch2) >= 127U) \
1625 return false
1626 COMPARE_EXACT_RET( pwszUuid1[ 0], pwszUuid2[ 0]); /* { */
1627 COMPARE_XDIGITS_RET(pwszUuid1[ 1], pwszUuid2[ 1]); /* 5 */
1628 COMPARE_XDIGITS_RET(pwszUuid1[ 2], pwszUuid2[ 2]); /* e */
1629 COMPARE_XDIGITS_RET(pwszUuid1[ 3], pwszUuid2[ 3]); /* 5 */
1630 COMPARE_XDIGITS_RET(pwszUuid1[ 4], pwszUuid2[ 4]); /* e */
1631 COMPARE_XDIGITS_RET(pwszUuid1[ 5], pwszUuid2[ 5]); /* 3 */
1632 COMPARE_XDIGITS_RET(pwszUuid1[ 6], pwszUuid2[ 6]); /* 6 */
1633 COMPARE_XDIGITS_RET(pwszUuid1[ 7], pwszUuid2[ 7]); /* 4 */
1634 COMPARE_XDIGITS_RET(pwszUuid1[ 8], pwszUuid2[ 8]); /* 0 */
1635 COMPARE_EXACT_RET( pwszUuid1[ 9], pwszUuid2[ 9]); /* - */
1636 COMPARE_XDIGITS_RET(pwszUuid1[10], pwszUuid2[10]); /* 7 */
1637 COMPARE_XDIGITS_RET(pwszUuid1[11], pwszUuid2[11]); /* 4 */
1638 COMPARE_XDIGITS_RET(pwszUuid1[12], pwszUuid2[12]); /* f */
1639 COMPARE_XDIGITS_RET(pwszUuid1[13], pwszUuid2[13]); /* 3 */
1640 COMPARE_EXACT_RET( pwszUuid1[14], pwszUuid2[14]); /* - */
1641 COMPARE_XDIGITS_RET(pwszUuid1[15], pwszUuid2[15]); /* 4 */
1642 COMPARE_XDIGITS_RET(pwszUuid1[16], pwszUuid2[16]); /* 6 */
1643 COMPARE_XDIGITS_RET(pwszUuid1[17], pwszUuid2[17]); /* 8 */
1644 COMPARE_XDIGITS_RET(pwszUuid1[18], pwszUuid2[18]); /* 9 */
1645 COMPARE_EXACT_RET( pwszUuid1[19], pwszUuid2[19]); /* - */
1646 COMPARE_XDIGITS_RET(pwszUuid1[20], pwszUuid2[20]); /* 9 */
1647 COMPARE_XDIGITS_RET(pwszUuid1[21], pwszUuid2[21]); /* 7 */
1648 COMPARE_XDIGITS_RET(pwszUuid1[22], pwszUuid2[22]); /* 9 */
1649 COMPARE_XDIGITS_RET(pwszUuid1[23], pwszUuid2[23]); /* f */
1650 COMPARE_EXACT_RET( pwszUuid1[24], pwszUuid2[24]); /* - */
1651 COMPARE_XDIGITS_RET(pwszUuid1[25], pwszUuid2[25]); /* 6 */
1652 COMPARE_XDIGITS_RET(pwszUuid1[26], pwszUuid2[26]); /* b */
1653 COMPARE_XDIGITS_RET(pwszUuid1[27], pwszUuid2[27]); /* 1 */
1654 COMPARE_XDIGITS_RET(pwszUuid1[28], pwszUuid2[28]); /* b */
1655 COMPARE_XDIGITS_RET(pwszUuid1[29], pwszUuid2[29]); /* 8 */
1656 COMPARE_XDIGITS_RET(pwszUuid1[30], pwszUuid2[30]); /* d */
1657 COMPARE_XDIGITS_RET(pwszUuid1[31], pwszUuid2[31]); /* 7 */
1658 COMPARE_XDIGITS_RET(pwszUuid1[32], pwszUuid2[32]); /* 6 */
1659 COMPARE_XDIGITS_RET(pwszUuid1[33], pwszUuid2[33]); /* 0 */
1660 COMPARE_XDIGITS_RET(pwszUuid1[34], pwszUuid2[34]); /* 9 */
1661 COMPARE_XDIGITS_RET(pwszUuid1[35], pwszUuid2[35]); /* a */
1662 COMPARE_XDIGITS_RET(pwszUuid1[36], pwszUuid2[36]); /* 5 */
1663 COMPARE_EXACT_RET( pwszUuid1[37], pwszUuid2[37]); /* } */
1664 COMPARE_EXACT_RET( pwszUuid1[38], pwszUuid2[38]); /* \0 */
1665#undef COMPARE_EXACT_RET
1666#undef COMPARE_XDIGITS_RET
1667 return true;
1668}
1669
1670
1671/**
1672 * Checks if the type library ID is one of the ones we wish to clean up.
1673 *
1674 * @returns true if it should be cleaned up, false if not.
1675 * @param pwszTypeLibId The type library ID as a bracketed string.
1676 */
1677static DECLINLINE(bool) vbpsIsTypeLibIdToRemove(PRTUTF16 pwszTypeLibId)
1678{
1679#ifdef VBOX_STRICT
1680 static bool s_fDoneStrict = false;
1681 if (s_fDoneStrict) { }
1682 else
1683 {
1684 Assert(RT_ELEMENTS(g_apwszTypeLibIds) == 2);
1685 Assert(g_apwszTypeLibIds[0] == '{');
1686 Assert(g_apwszTypeLibIds[1] == '{');
1687 Assert(RT_C_IS_XDIGIT(g_apwszTypeLibIds[0][1]));
1688 Assert(RT_C_IS_XDIGIT(g_apwszTypeLibIds[1][1]));
1689 Assert(RT_C_IS_UPPER(g_apwszTypeLibIds[0][1]) || RT_C_IS_DIGIT(g_apwszTypeLibIds[0][1]));
1690 Assert(RT_C_IS_UPPER(g_apwszTypeLibIds[1][1]) || RT_C_IS_DIGIT(g_apwszTypeLibIds[1][1]));
1691 s_fDoneStrict = true;
1692 }
1693#endif
1694 AssertCompile(RT_ELEMENTS(g_apwszTypeLibIds) == 2);
1695
1696 /*
1697 * Rolled out matching with inlined check of the opening braces
1698 * and first two digits.
1699 *
1700 * ASSUMES input buffer is at least 3 wchars big and uppercased UUID in
1701 * our matching array.
1702 */
1703 if (pwszTypeLibId[0] == '{')
1704 {
1705 RTUTF16 const wcFirstDigit = RT_C_TO_UPPER(pwszTypeLibId[1]);
1706 RTUTF16 const wcSecondDigit = RT_C_TO_UPPER(pwszTypeLibId[2]);
1707 PCRTUTF16 pwsz2 = g_apwszTypeLibIds[0];
1708 if ( wcFirstDigit == pwsz2[1]
1709 && wcSecondDigit == pwsz2[2]
1710 && vbpsCompareUuidW(pwszTypeLibId, pwsz2))
1711 return true;
1712 pwsz2 = g_apwszTypeLibIds[1];
1713 if ( wcFirstDigit == pwsz2[1]
1714 && wcSecondDigit == pwsz2[2]
1715 && vbpsCompareUuidW(pwszTypeLibId, pwsz2))
1716 return true;
1717 }
1718 return false;
1719}
1720
1721
1722/**
1723 * Checks if the proxy stub class ID is one of the ones we wish to clean up.
1724 *
1725 * @returns true if it should be cleaned up, false if not.
1726 * @param pwszProxyStubId The proxy stub class ID.
1727 */
1728static DECLINLINE(bool) vbpsIsProxyStubClsIdToRemove(PRTUTF16 pwszProxyStubId)
1729{
1730#ifdef VBOX_STRICT
1731 static bool s_fDoneStrict = false;
1732 if (s_fDoneStrict) { }
1733 else
1734 {
1735 Assert(RT_ELEMENTS(g_apwszProxyStubClsIds) == 2);
1736 Assert(g_apwszProxyStubClsIds[0] == '{');
1737 Assert(g_apwszProxyStubClsIds[1] == '{');
1738 Assert(RT_C_IS_XDIGIT(g_apwszProxyStubClsIds[0][1]));
1739 Assert(RT_C_IS_XDIGIT(g_apwszProxyStubClsIds[1][1]));
1740 Assert(RT_C_IS_UPPER(g_apwszProxyStubClsIds[0][1]) || RT_C_IS_DIGIT(g_apwszProxyStubClsIds[0][1]));
1741 Assert(RT_C_IS_UPPER(g_apwszProxyStubClsIds[1][1]) || RT_C_IS_DIGIT(g_apwszProxyStubClsIds[1][1]));
1742 s_fDoneStrict = true;
1743 }
1744#endif
1745 AssertCompile(RT_ELEMENTS(g_apwszProxyStubClsIds) == 2);
1746
1747 /*
1748 * Rolled out matching with inlined check of the opening braces
1749 * and first two digits.
1750 *
1751 * ASSUMES input buffer is at least 3 wchars big and uppercased UUID in
1752 * our matching array.
1753 */
1754 if (pwszProxyStubId[0] == '{')
1755 {
1756 RTUTF16 const wcFirstDigit = RT_C_TO_UPPER(pwszProxyStubId[1]);
1757 RTUTF16 const wcSecondDigit = RT_C_TO_UPPER(pwszProxyStubId[2]);
1758 PCRTUTF16 pwsz2 = g_apwszProxyStubClsIds[0];
1759 if ( wcFirstDigit == pwsz2[1]
1760 && wcSecondDigit == pwsz2[2]
1761 && vbpsCompareUuidW(pwszProxyStubId, pwsz2))
1762 return true;
1763 pwsz2 = g_apwszProxyStubClsIds[1];
1764 if ( wcFirstDigit == pwsz2[1]
1765 && wcSecondDigit == pwsz2[2]
1766 && vbpsCompareUuidW(pwszProxyStubId, pwsz2))
1767 return true;
1768 }
1769 return false;
1770}
1771
1772
1773/**
1774 * Hack to clean out the interfaces belonging to obsolete typelibs on
1775 * development boxes and such likes.
1776 */
1777static void vbpsRemoveOldInterfaces(VBPSREGSTATE *pState)
1778{
1779 unsigned iAlt = pState->cAltDeletes;
1780 while (iAlt-- > 0)
1781 {
1782 /*
1783 * Open the interface root key. Not using the vbpsRegOpenInterfaceKeys feature
1784 * here in case it messes things up by keeping the special HKEY_CLASSES_ROOT key
1785 * open with possibly pending deletes in parent views or other weird stuff.
1786 */
1787 HKEY hkeyInterfaces;
1788 LRESULT rc = RegOpenKeyExW(pState->aAltDeletes[iAlt].hkeyClasses, L"Interface",
1789 0 /*fOptions*/, pState->fSamDelete, &hkeyInterfaces);
1790 if (rc == ERROR_SUCCESS)
1791 {
1792 /*
1793 * This is kind of expensive, but we have to check all registered interfaces.
1794 * Only use wide APIs to avoid wasting time on string conversion.
1795 */
1796 DWORD idxKey;
1797 for (idxKey = 0;; idxKey++)
1798 {
1799 RTUTF16 wszCurNm[128 + 48];
1800 DWORD cwcCurNm = 128;
1801 rc = RegEnumKeyExW(hkeyInterfaces, idxKey, wszCurNm, &cwcCurNm,
1802 NULL /*pdwReserved*/, NULL /*pwszClass*/, NULL /*pcwcClass*/, NULL /*pLastWriteTime*/);
1803 if (rc == ERROR_SUCCESS)
1804 {
1805 /*
1806 * We match the interface by type library ID or proxy stub class ID.
1807 *
1808 * We have to check the proxy ID last, as it is almost always there
1809 * and we can safely skip it if there is a mismatching type lib
1810 * associated with the interface.
1811 */
1812 static RTUTF16 const s_wszTypeLib[] = L"\\TypeLib";
1813 bool fDeleteMe = false;
1814 HKEY hkeySub;
1815 RTUTF16 wszValue[128];
1816 DWORD cbValue;
1817 DWORD dwType;
1818
1819 /* Skip this entry if it doesn't look like a braced UUID. */
1820 wszCurNm[cwcCurNm] = '\0'; /* paranoia */
1821 if (vbpsIsUuidInBracesQuickW(wszCurNm)) { }
1822 else continue;
1823
1824 /* Try the TypeLib sub-key. */
1825 memcpy(&wszCurNm[cwcCurNm], s_wszTypeLib, sizeof(s_wszTypeLib));
1826 rc = RegOpenKeyExW(hkeyInterfaces, wszCurNm, 0 /*fOptions*/, KEY_QUERY_VALUE, &hkeySub);
1827 if (rc == ERROR_SUCCESS)
1828 {
1829 cbValue = sizeof(wszValue) - sizeof(RTUTF16);
1830 rc = RegQueryValueExW(hkeySub, NULL /*pszValueNm*/, NULL /*pdwReserved*/,
1831 &dwType, (PBYTE)&wszValue[0], &cbValue);
1832 if (rc != ERROR_SUCCESS || dwType != REG_SZ)
1833 cbValue = 0;
1834 wszValue[cbValue / sizeof(RTUTF16)] = '\0';
1835
1836 if ( rc == ERROR_SUCCESS
1837 && vbpsIsTypeLibIdToRemove(wszValue))
1838 {
1839 /* Check the TypeLib/Version value to make sure. */
1840 cbValue = sizeof(wszValue) - sizeof(RTUTF16);
1841 rc = RegQueryValueExW(hkeySub, L"Version", 0 /*pdwReserved*/, &dwType, (PBYTE)&wszValue[0], &cbValue);
1842 if (rc != ERROR_SUCCESS)
1843 cbValue = 0;
1844 wszValue[cbValue] = '\0';
1845
1846 if ( rc == ERROR_SUCCESS
1847 && vbpsIsTypeLibVersionToRemove(wszValue))
1848 fDeleteMe = true;
1849 }
1850 vbpsCloseKey(pState, hkeySub, __LINE__);
1851 }
1852 else if (rc == ERROR_FILE_NOT_FOUND)
1853 {
1854 /* No TypeLib, try the ProxyStubClsid32 sub-key next. */
1855 static RTUTF16 const s_wszProxyStubClsid32[] = L"\\ProxyStubClsid32";
1856 memcpy(&wszCurNm[cwcCurNm], s_wszProxyStubClsid32, sizeof(s_wszProxyStubClsid32));
1857 rc = RegOpenKeyExW(hkeyInterfaces, wszCurNm, 0 /*fOptions*/, KEY_QUERY_VALUE, &hkeySub);
1858 if (rc == ERROR_SUCCESS)
1859 {
1860 cbValue = sizeof(wszValue) - sizeof(RTUTF16);
1861 rc = RegQueryValueExW(hkeySub, NULL /*pszValueNm*/, NULL /*pdwReserved*/,
1862 &dwType, (PBYTE)&wszValue[0], &cbValue);
1863 if (rc != ERROR_SUCCESS || dwType != REG_SZ)
1864 cbValue = 0;
1865 wszValue[cbValue / sizeof(RTUTF16)] = '\0';
1866
1867 if ( rc == ERROR_SUCCESS
1868 && vbpsIsProxyStubClsIdToRemove(wszValue))
1869 fDeleteMe = true;
1870
1871 vbpsCloseKey(pState, hkeySub, __LINE__);
1872 }
1873 }
1874
1875 if (fDeleteMe)
1876 {
1877 /*
1878 * Ok, it's an orphaned VirtualBox interface. Delete it.
1879 */
1880 wszCurNm[cwcCurNm] = '\0';
1881 vbpsDeleteKeyRecursiveW(pState, hkeyInterfaces, wszCurNm, __LINE__);
1882 }
1883 }
1884 else
1885 {
1886 Assert(rc == ERROR_NO_MORE_ITEMS);
1887 break;
1888 }
1889 }
1890
1891 vbpsCloseKey(pState, hkeyInterfaces, __LINE__);
1892 }
1893 }
1894}
1895
1896
1897/**
1898 * Hack to clean out the class IDs belonging to obsolete typelibs on development
1899 * boxes and such likes.
1900 */
1901static void vbpsRemoveOldClassIDs(VBPSREGSTATE *pState)
1902{
1903 unsigned iAlt = pState->cAltDeletes;
1904 while (iAlt-- > 0)
1905 {
1906 /*
1907 * Open the CLSID key if it exists.
1908 * We don't use the hKeyClsid member for the same paranoid reasons as
1909 * already stated in vbpsRemoveOldInterfaces.
1910 */
1911 HKEY hkeyClsIds;
1912 LRESULT rc;
1913 rc = RegOpenKeyExW(pState->aAltDeletes[iAlt].hkeyClasses, L"CLSID", 0 /*fOptions*/, pState->fSamDelete, &hkeyClsIds);
1914 if (rc == ERROR_SUCCESS)
1915 {
1916 /*
1917 * This is kind of expensive, but we have to check all registered interfaces.
1918 * Only use wide APIs to avoid wasting time on string conversion.
1919 */
1920 DWORD idxKey;
1921 for (idxKey = 0;; idxKey++)
1922 {
1923 RTUTF16 wszCurNm[128 + 48];
1924 DWORD cwcCurNm = 128;
1925 rc = RegEnumKeyExW(hkeyClsIds, idxKey, wszCurNm, &cwcCurNm,
1926 NULL /*pdwReserved*/, NULL /*pwszClass*/, NULL /*pcwcClass*/, NULL /*pLastWriteTime*/);
1927 if (rc == ERROR_SUCCESS)
1928 {
1929 /*
1930 * Match both the type library ID and the program ID.
1931 */
1932 static RTUTF16 const s_wszTypeLib[] = L"\\TypeLib";
1933 HKEY hkeySub;
1934 RTUTF16 wszValue[128];
1935 DWORD cbValue;
1936 DWORD dwType;
1937
1938
1939 /* Skip this entry if it doesn't look like a braced UUID. (Microsoft
1940 has one two malformed ones plus a hack.) */
1941 wszCurNm[cwcCurNm] = '\0'; /* paranoia */
1942 if (vbpsIsUuidInBracesQuickW(wszCurNm)) { }
1943 else continue;
1944
1945 /* The TypeLib sub-key. */
1946 memcpy(&wszCurNm[cwcCurNm], s_wszTypeLib, sizeof(s_wszTypeLib));
1947 rc = RegOpenKeyExW(hkeyClsIds, wszCurNm, 0 /*fOptions*/, KEY_QUERY_VALUE, &hkeySub);
1948 if (rc == ERROR_SUCCESS)
1949 {
1950 bool fDeleteMe = false;
1951
1952 cbValue = sizeof(wszValue) - sizeof(RTUTF16);
1953 rc = RegQueryValueExW(hkeySub, NULL /*pszValueNm*/, NULL /*pdwReserved*/,
1954 &dwType, (PBYTE)&wszValue[0], &cbValue);
1955 if (rc != ERROR_SUCCESS || dwType != REG_SZ)
1956 cbValue = 0;
1957 wszValue[cbValue / sizeof(RTUTF16)] = '\0';
1958
1959 if ( rc == ERROR_SUCCESS
1960 && vbpsIsTypeLibIdToRemove(wszValue))
1961 fDeleteMe = true;
1962
1963 vbpsCloseKey(pState, hkeySub, __LINE__);
1964
1965 if (fDeleteMe)
1966 {
1967 /* The ProgId sub-key. */
1968 static RTUTF16 const s_wszProgId[] = L"\\ProgId";
1969 memcpy(&wszCurNm[cwcCurNm], s_wszProgId, sizeof(s_wszProgId));
1970 rc = RegOpenKeyExW(hkeyClsIds, wszCurNm, 0 /*fOptions*/, KEY_QUERY_VALUE, &hkeySub);
1971 if (rc == ERROR_SUCCESS)
1972 {
1973 static RTUTF16 const s_wszProgIdPrefix[] = L"VirtualBox.";
1974
1975 cbValue = sizeof(wszValue) - sizeof(RTUTF16);
1976 rc = RegQueryValueExW(hkeySub, NULL /*pszValueNm*/, NULL /*pdwReserved*/,
1977 &dwType, (PBYTE)&wszValue[0], &cbValue);
1978 if (rc != ERROR_SUCCESS || dwType != REG_SZ)
1979 cbValue = 0;
1980 wszValue[cbValue / sizeof(RTUTF16)] = '\0';
1981
1982 if ( cbValue < sizeof(s_wszProgIdPrefix)
1983 || memcmp(wszValue, s_wszProgIdPrefix, sizeof(s_wszProgIdPrefix) - sizeof(RTUTF16)) != 0)
1984 fDeleteMe = false;
1985
1986 vbpsCloseKey(pState, hkeySub, __LINE__);
1987 }
1988 else
1989 AssertStmt(rc == ERROR_FILE_NOT_FOUND, fDeleteMe = false);
1990
1991 if (fDeleteMe)
1992 {
1993 /*
1994 * Ok, it's an orphaned VirtualBox interface. Delete it.
1995 */
1996 wszCurNm[cwcCurNm] = '\0';
1997 vbpsDeleteKeyRecursiveW(pState, hkeyClsIds, wszCurNm, __LINE__);
1998 }
1999 }
2000 }
2001 else
2002 Assert(rc == ERROR_FILE_NOT_FOUND);
2003 }
2004 else
2005 {
2006 Assert(rc == ERROR_NO_MORE_ITEMS);
2007 break;
2008 }
2009 }
2010
2011 vbpsCloseKey(pState, hkeyClsIds, __LINE__);
2012 }
2013 else
2014 Assert(rc == ERROR_FILE_NOT_FOUND);
2015 }
2016}
2017
2018
2019/**
2020 * Hack to clean obsolete typelibs on development boxes and such.
2021 */
2022static void vbpsRemoveOldTypeLibs(VBPSREGSTATE *pState)
2023{
2024 unsigned iAlt = pState->cAltDeletes;
2025 while (iAlt-- > 0)
2026 {
2027 /*
2028 * Open the TypeLib key, if it exists.
2029 */
2030 HKEY hkeyTypeLibs;
2031 LRESULT rc;
2032 rc = RegOpenKeyExW(pState->aAltDeletes[iAlt].hkeyClasses, L"TypeLib", 0 /*fOptions*/, pState->fSamDelete, &hkeyTypeLibs);
2033 if (rc == ERROR_SUCCESS)
2034 {
2035 /*
2036 * Look for our type library IDs.
2037 */
2038 unsigned iTlb = RT_ELEMENTS(g_apwszTypeLibIds);
2039 while (iTlb-- > 0)
2040 {
2041 HKEY hkeyTypeLibId;
2042 LONG rc = RegOpenKeyExW(hkeyTypeLibs, g_apwszTypeLibIds[iTlb], 0 /*fOptions*/, pState->fSamDelete, &hkeyTypeLibId);
2043 if (rc == ERROR_SUCCESS)
2044 {
2045 unsigned iVer = RT_ELEMENTS(g_apwszTypelibVersions);
2046 while (iVer-- > 0)
2047 {
2048 HKEY hkeyVer;
2049 rc = RegOpenKeyExW(hkeyTypeLibId, g_apwszTypelibVersions[iVer], 0, KEY_READ, &hkeyVer);
2050 if (rc == ERROR_SUCCESS)
2051 {
2052 char szValue[128];
2053 DWORD cbValue = sizeof(szValue) - 1;
2054 rc = RegQueryValueExA(hkeyVer, NULL, NULL, NULL, (PBYTE)&szValue[0], &cbValue);
2055 vbpsCloseKey(pState, hkeyVer, __LINE__);
2056 if (rc == ERROR_SUCCESS)
2057 {
2058 szValue[cbValue] = '\0';
2059 if (!strcmp(szValue, "VirtualBox Type Library"))
2060 {
2061 /*
2062 * Delete the type library version.
2063 * We do not delete the whole type library ID, just this version of it.
2064 */
2065 vbpsDeleteKeyRecursiveW(pState, hkeyTypeLibId, g_apwszTypelibVersions[iVer], __LINE__);
2066 }
2067 }
2068 }
2069 }
2070 vbpsCloseKey(pState, hkeyTypeLibId, __LINE__);
2071
2072 /*
2073 * The type library ID key should be empty now, so we can try remove it (non-recursively).
2074 */
2075 rc = RegDeleteKeyW(hkeyTypeLibs, g_apwszTypeLibIds[iTlb]);
2076 Assert(rc == ERROR_SUCCESS);
2077 }
2078 }
2079 }
2080 else
2081 Assert(rc == ERROR_FILE_NOT_FOUND);
2082 }
2083}
2084
2085
2086/**
2087 * Hack to clean out obsolete typelibs on development boxes and such.
2088 */
2089static void vbpsRemoveOldMessSub(REGSAM fSamWow)
2090{
2091 /*
2092 * Note! The worker procedures does not use the default destination,
2093 * because it's much much simpler to enumerate alternative locations.
2094 */
2095 VBPSREGSTATE State;
2096 LRESULT rc = vbpsRegInit(&State, HKEY_CLASSES_ROOT, NULL, true /*fDelete*/, false /*fUpdate*/, fSamWow);
2097 if (rc == ERROR_SUCCESS)
2098 {
2099 vbpsRegAddAltDelete(&State, HKEY_CURRENT_USER, "Software\\Classes");
2100 vbpsRegAddAltDelete(&State, HKEY_LOCAL_MACHINE, "Software\\Classes");
2101 vbpsRegAddAltDelete(&State, HKEY_CLASSES_ROOT, NULL);
2102
2103 vbpsRemoveOldInterfaces(&State);
2104 vbpsRemoveOldClassIDs(&State);
2105 vbpsRemoveOldTypeLibs(&State);
2106 }
2107 vbpsRegTerm(&State);
2108}
2109
2110
2111/**
2112 * Hack to clean out obsolete typelibs on development boxes and such.
2113 */
2114static void removeOldMess(void)
2115{
2116 vbpsRemoveOldMessSub(0 /*fSamWow*/);
2117#if ARCH_BITS == 64 || defined(VBOX_IN_32_ON_64_MAIN_API)
2118 vbpsRemoveOldMessSub(KEY_WOW64_32KEY);
2119#endif
2120}
2121
2122
2123
2124/**
2125 * Register the interfaces proxied by this DLL, and to avoid duplication and
2126 * minimize work the VBox type library, classes and servers are also registered.
2127 *
2128 * This is normally only used by developers via comregister.cmd and the heat.exe
2129 * tool during MSI creation. The only situation where users may end up here is
2130 * if they're playing around or we recommend it as a solution to COM problems.
2131 * So, no problem if this approach is less gentle, though we leave the cleaning
2132 * up of orphaned interfaces to DllUnregisterServer.
2133 *
2134 * @returns COM status code.
2135 */
2136HRESULT STDAPICALLTYPE DllRegisterServer(void)
2137{
2138 HRESULT hrc;
2139
2140 /*
2141 * Register the type library first.
2142 */
2143 ITypeLib *pITypeLib;
2144 WCHAR wszDllName[MAX_PATH];
2145 DWORD cwcRet = GetModuleFileNameW(g_hDllSelf, wszDllName, RT_ELEMENTS(wszDllName));
2146 AssertReturn(cwcRet > 0 && cwcRet < RT_ELEMENTS(wszDllName), CO_E_PATHTOOLONG);
2147
2148 hrc = LoadTypeLib(wszDllName, &pITypeLib);
2149 AssertMsgReturn(SUCCEEDED(hrc), ("%Rhrc\n", hrc), hrc);
2150 hrc = RegisterTypeLib(pITypeLib, wszDllName, NULL /*pszHelpDir*/);
2151 pITypeLib->lpVtbl->Release(pITypeLib);
2152 AssertMsgReturn(SUCCEEDED(hrc), ("%Rhrc\n", hrc), hrc);
2153
2154 /*
2155 * Register proxy stub.
2156 */
2157 hrc = NdrDllRegisterProxy(g_hDllSelf, &g_apProxyFiles[0], &g_ProxyClsId); /* see DLLREGISTRY_ROUTINES in RpcProxy.h */
2158 AssertMsgReturn(SUCCEEDED(hrc), ("%Rhrc\n", hrc), hrc);
2159
2160 /*
2161 * Register the VBox modules and classes.
2162 */
2163 vbpsDllPathToVBoxDir(wszDllName);
2164 hrc = RegisterXidlModulesAndClasses(wszDllName, true /*fDelete*/, true /*fUpdate*/);
2165 AssertMsgReturn(SUCCEEDED(hrc), ("%Rhrc\n", hrc), hrc);
2166
2167 return S_OK;
2168}
2169
2170
2171/**
2172 * Reverse of DllRegisterServer.
2173 *
2174 * This is normally only used by developers via comregister.cmd. Users may be
2175 * asked to perform it in order to fix some COM issue. So, it's OK if we spend
2176 * some extra time and clean up orphaned interfaces, because developer boxes
2177 * will end up with a bunch of those as interface UUIDs changes.
2178 *
2179 * @returns COM status code.
2180 */
2181HRESULT STDAPICALLTYPE DllUnregisterServer(void)
2182{
2183 HRESULT hrc = S_OK;
2184 HRESULT hrc2;
2185
2186 /*
2187 * Unregister the type library.
2188 *
2189 * We ignore TYPE_E_REGISTRYACCESS as that is what is returned if the
2190 * type lib hasn't been registered (W10).
2191 */
2192 hrc2 = UnRegisterTypeLib(&LIBID_VirtualBox, kTypeLibraryMajorVersion, kTypeLibraryMinorVersion,
2193 0 /*LCid*/, RT_CONCAT(SYS_WIN, ARCH_BITS));
2194 AssertMsgStmt(SUCCEEDED(hrc2) || hrc2 == TYPE_E_REGISTRYACCESS, ("%Rhrc\n", hrc2), if (SUCCEEDED(hrc)) hrc = hrc2);
2195
2196 /*
2197 * Unregister the proxy stub.
2198 *
2199 * We ignore ERROR_FILE_NOT_FOUND as that is returned if not registered (W10).
2200 */
2201 hrc2 = NdrDllUnregisterProxy(g_hDllSelf, &g_apProxyFiles[0], &g_ProxyClsId); /* see DLLREGISTRY_ROUTINES in RpcProxy.h */
2202 AssertMsgStmt( SUCCEEDED(hrc2)
2203 || hrc2 == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND)
2204 || hrc2 == REGDB_E_INVALIDVALUE,
2205 ("%Rhrc\n", hrc2), if (SUCCEEDED(hrc)) hrc = hrc2);
2206
2207 /*
2208 * Register the VBox modules and classes.
2209 */
2210 hrc2 = RegisterXidlModulesAndClasses(NULL, true /*fDelete*/, false /*fUpdate*/);
2211 AssertMsgStmt(SUCCEEDED(hrc2), ("%Rhrc\n", hrc2), if (SUCCEEDED(hrc)) hrc = hrc2);
2212
2213 /*
2214 * Purge old mess.
2215 */
2216 removeOldMess();
2217
2218 return hrc;
2219}
2220
2221
2222/**
2223 * Gently update the COM registrations for VirtualBox.
2224 *
2225 * API that com::Initialize (VBoxCOM/initterm.cpp) calls the first time COM is
2226 * initialized in a process. ASSUMES that the caller has initialized IPRT.
2227 *
2228 * @returns Windows error code.
2229 */
2230DECLEXPORT(uint32_t) VbpsUpdateRegistrations(void)
2231{
2232 LSTATUS rc;
2233 VBPSREGSTATE State;
2234#ifdef VBOX_IN_32_ON_64_MAIN_API
2235 bool const fIs32On64 = true;
2236#else
2237 bool const fIs32On64 = false;
2238#endif
2239
2240 /** @todo Should probably skip this when VBoxSVC is already running... Use
2241 * some mutex or something for checking. */
2242
2243 /*
2244 * Find the VirtualBox application directory first.
2245 */
2246 WCHAR wszVBoxDir[MAX_PATH];
2247 DWORD cwcRet = GetModuleFileNameW(g_hDllSelf, wszVBoxDir, RT_ELEMENTS(wszVBoxDir));
2248 AssertReturn(cwcRet > 0 && cwcRet < RT_ELEMENTS(wszVBoxDir), ERROR_BUFFER_OVERFLOW);
2249 vbpsDllPathToVBoxDir(wszVBoxDir);
2250
2251 /*
2252 * Update registry entries for the current CPU bitness.
2253 */
2254 rc = vbpsRegInit(&State, HKEY_CLASSES_ROOT, NULL, false /*fDelete*/, true /*fUpdate*/, 0);
2255 if (rc == ERROR_SUCCESS && !vbpsIsUpToDate(&State))
2256 {
2257 vbpsUpdateTypeLibRegistration(&State, wszVBoxDir, fIs32On64);
2258 vbpsUpdateProxyStubRegistration(&State, wszVBoxDir, fIs32On64);
2259 vbpsUpdateInterfaceRegistrations(&State);
2260 RegisterXidlModulesAndClassesGenerated(&State, wszVBoxDir, fIs32On64);
2261 vbpsMarkUpToDate(&State);
2262 rc = State.rc;
2263 }
2264 vbpsRegTerm(&State);
2265
2266
2267/*#if defined(VBOX_IN_32_ON_64_MAIN_API) || (ARCH_BITS == 64 && defined(VBOX_WITH_32_ON_64_MAIN_API)) ?? */
2268#ifndef VBOX_IN_32_ON_64_MAIN_API
2269 /*
2270 * Update registry entries for the other CPU bitness.
2271 */
2272 if (rc == ERROR_SUCCESS)
2273 {
2274 rc = vbpsRegInit(&State, HKEY_CLASSES_ROOT, NULL, false /*fDelete*/, true /*fUpdate*/,
2275 !fIs32On64 ? KEY_WOW64_32KEY : KEY_WOW64_64KEY);
2276 if (rc == ERROR_SUCCESS && !vbpsIsUpToDate(&State))
2277 {
2278 vbpsUpdateTypeLibRegistration(&State, wszVBoxDir, !fIs32On64);
2279 vbpsUpdateProxyStubRegistration(&State, wszVBoxDir, !fIs32On64);
2280 vbpsUpdateInterfaceRegistrations(&State);
2281 RegisterXidlModulesAndClassesGenerated(&State, wszVBoxDir, !fIs32On64);
2282 vbpsMarkUpToDate(&State);
2283 rc = State.rc;
2284 }
2285 vbpsRegTerm(&State);
2286 }
2287#endif
2288
2289 return VINF_SUCCESS;
2290}
2291
Note: See TracBrowser for help on using the repository browser.

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