VirtualBox

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

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

Config.kmk,Main: VBOX_MIDL_PROXY_CLSID and corresponding VBOX_MIDL_PROXY_CLSID_IS now in Config and not duplicated around the place.

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