VirtualBox

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

Last change on this file since 104507 was 104154, checked in by vboxsync, 8 months ago

Main/VBoxProxyStub: Fixed using service start name when (re-)creating a (new) service via vbpsUpdateWindowsService() -- the service start name was used only to validate an existing service configuration, but not when actually (re-)creating the service if needed.

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

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