VirtualBox

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

Last change on this file since 71118 was 70240, checked in by vboxsync, 7 years ago

VBoxProxyStub.c: Official docs says DELETE is required for DeleteService. No reason for removal stated in r119820, so restoring it. Dropped incorrectly formatted comments about where to also rename VBoxSDS if we ever want to do that (we won't, and if we do, there's grep).

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