VirtualBox

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

Last change on this file since 107362 was 107362, checked in by vboxsync, 5 weeks ago

Main,Installer/win: Removed VBoxProxyStubLegacy.dll since we no longer support Vista and older 64-bit windows hosts.

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