VirtualBox

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

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

Main/VBoxSVC,VBoxSDS: fix for ​​​​​bugref:8161: added and updated copyright

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

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