VirtualBox

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

Last change on this file since 66353 was 66353, checked in by vboxsync, 8 years ago

VBoxProxyStub.c: More style.

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