VirtualBox

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

Last change on this file since 107248 was 107098, checked in by vboxsync, 3 months ago

Main/VBoxProxyStub: Print warning when registering VBoxSDS.exe on a network drive (it won't work). If you wan to run a development version of VBox on a network share, disabling VBoxSDS is currently the best option (LocalConfig.kmk: override VBOX_WITH_SDS := ). jiraref:VBP-1466

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