VirtualBox

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

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

Main/VBoxSVC: add kmk flag to switch off client process watching functionality VBOX_SDS_CLIENTS_WATCHER. Functionality switched off temporary.

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

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