VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Installer/VBoxDrvInst.cpp@ 63566

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

scm: cleaning up todos

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 50.0 KB
Line 
1/* $Id: VBoxDrvInst.cpp 63566 2016-08-16 14:05:58Z vboxsync $ */
2/** @file
3 * VBoxDrvInst - Driver and service installation helper for Windows guests.
4 */
5
6/*
7 * Copyright (C) 2011-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#ifndef UNICODE
23# define UNICODE
24#endif
25
26#include <iprt/cdefs.h>
27#include <VBox/version.h>
28
29#include <iprt/win/windows.h>
30#include <iprt/win/setupapi.h>
31#include <stdio.h>
32#include <tchar.h>
33
34
35/*********************************************************************************************************************************
36* Defines *
37*********************************************************************************************************************************/
38
39/* Exit codes */
40#define EXIT_OK (0)
41#define EXIT_REBOOT (1)
42#define EXIT_FAIL (2)
43#define EXIT_USAGE (3)
44
45/* Prototypes */
46typedef struct {
47 PWSTR pApplicationId;
48 PWSTR pDisplayName;
49 PWSTR pProductName;
50 PWSTR pMfgName;
51} INSTALLERINFO, *PINSTALLERINFO;
52typedef const PINSTALLERINFO PCINSTALLERINFO;
53
54typedef enum {
55 DIFXAPI_SUCCESS,
56 DIFXAPI_INFO,
57 DIFXAPI_WARNING,
58 DIFXAPI_ERROR
59} DIFXAPI_LOG;
60
61typedef void (WINAPI * DIFXLOGCALLBACK_W)( DIFXAPI_LOG Event, DWORD Error, PCWSTR EventDescription, PVOID CallbackContext);
62typedef void ( __cdecl* DIFXAPILOGCALLBACK_W)( DIFXAPI_LOG Event, DWORD Error, PCWSTR EventDescription, PVOID CallbackContext);
63
64typedef DWORD (WINAPI *fnDriverPackageInstall) (PCTSTR DriverPackageInfPath, DWORD Flags, PCINSTALLERINFO pInstallerInfo, BOOL *pNeedReboot);
65fnDriverPackageInstall g_pfnDriverPackageInstall = NULL;
66
67typedef DWORD (WINAPI *fnDriverPackageUninstall) (PCTSTR DriverPackageInfPath, DWORD Flags, PCINSTALLERINFO pInstallerInfo, BOOL *pNeedReboot);
68fnDriverPackageUninstall g_pfnDriverPackageUninstall = NULL;
69
70typedef VOID (WINAPI *fnDIFXAPISetLogCallback) (DIFXAPILOGCALLBACK_W LogCallback, PVOID CallbackContext);
71fnDIFXAPISetLogCallback g_pfnDIFXAPISetLogCallback = NULL;
72
73/* Defines */
74#define DRIVER_PACKAGE_REPAIR 0x00000001
75#define DRIVER_PACKAGE_SILENT 0x00000002
76#define DRIVER_PACKAGE_FORCE 0x00000004
77#define DRIVER_PACKAGE_ONLY_IF_DEVICE_PRESENT 0x00000008
78#define DRIVER_PACKAGE_LEGACY_MODE 0x00000010
79#define DRIVER_PACKAGE_DELETE_FILES 0x00000020
80
81/* DIFx error codes */
82/** @todo any reason why we're not using difxapi.h instead of these redefinitions? */
83#ifndef ERROR_DRIVER_STORE_ADD_FAILED
84# define ERROR_DRIVER_STORE_ADD_FAILED \
85 (APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x0247L)
86#endif
87#define ERROR_DEPENDENT_APPLICATIONS_EXIST \
88 (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x300)
89#define ERROR_DRIVER_PACKAGE_NOT_IN_STORE \
90 (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x302)
91
92/* Registry string list flags */
93#define VBOX_REG_STRINGLIST_NONE 0x00000000 /* No flags set. */
94#define VBOX_REG_STRINGLIST_ALLOW_DUPLICATES 0x00000001 /* Allows duplicates in list when adding a value. */
95
96#ifdef DEBUG
97# define VBOX_DRVINST_LOGFILE "C:\\Temp\\VBoxDrvInstDIFx.log"
98#endif
99
100bool GetErrorMsg(DWORD dwLastError, _TCHAR *pszMsg, DWORD dwBufSize)
101{
102 if (::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwLastError, 0, pszMsg, dwBufSize / sizeof(TCHAR), NULL) == 0)
103 {
104 _sntprintf(pszMsg, dwBufSize / sizeof(TCHAR), _T("Unknown error!\n"), dwLastError);
105 return false;
106 }
107 _TCHAR *p = _tcschr(pszMsg, _T('\r'));
108 if (p != NULL)
109 *p = _T('\0');
110 return true;
111}
112
113/**
114 * Log callback for DIFxAPI calls.
115 *
116 * @param Event The event's structure to log.
117 * @param dwError The event's error level.
118 * @param pEventDescription The event's text description.
119 * @param pCallbackContext User-supplied callback context.
120 */
121void LogCallback(DIFXAPI_LOG Event, DWORD dwError, PCWSTR pEventDescription, PVOID pCallbackContext)
122{
123 if (dwError == 0)
124 _tprintf(_T("(%u) %ws\n"), Event, pEventDescription);
125 else
126 _tprintf(_T("(%u) ERROR: %u - %ws\n"), Event, dwError, pEventDescription);
127
128 if (pCallbackContext)
129 fwprintf((FILE*)pCallbackContext, _T("(%u) %u - %s\n"), Event, dwError, pEventDescription);
130}
131
132/**
133 * Loads a system DLL.
134 *
135 * @returns Module handle or NULL
136 * @param pwszName The DLL name.
137 */
138static HMODULE loadInstalledDll(const wchar_t *pwszName)
139{
140 /* Get the process image path. */
141 WCHAR wszPath[MAX_PATH];
142 UINT cwcPath = GetModuleFileNameW(NULL, wszPath, MAX_PATH);
143 if (!cwcPath || cwcPath >= MAX_PATH)
144 return NULL;
145
146 /* Drop the image filename. */
147 UINT off = cwcPath - 1;
148 for (;;)
149 {
150 if ( wszPath[off] == '\\'
151 || wszPath[off] == '/'
152 || wszPath[off] == ':')
153 {
154 wszPath[off] = '\0';
155 cwcPath = off;
156 break;
157 }
158 if (!off--)
159 return NULL; /* No path? Shouldn't ever happen! */
160 }
161
162 /* Check if there is room in the buffer to construct the desired name. */
163 size_t cwcName = 0;
164 while (pwszName[cwcName])
165 cwcName++;
166 if (cwcPath + 1 + cwcName + 1 > MAX_PATH)
167 return NULL;
168
169 wszPath[cwcPath] = '\\';
170 memcpy(&wszPath[cwcPath + 1], pwszName, (cwcName + 1) * sizeof(wszPath[0]));
171 return LoadLibraryW(wszPath);
172}
173
174/**
175 * (Un)Installs a driver from/to the system.
176 *
177 * @return Exit code (EXIT_OK, EXIT_FAIL)
178 * @param fInstall Flag indicating whether to install (TRUE) or uninstall (FALSE) a driver.
179 * @param pszDriverPath Pointer to full qualified path to the driver's .INF file (+ driver files).
180 * @param fSilent Flag indicating a silent installation (TRUE) or not (FALSE).
181 * @param pszLogFile Pointer to full qualified path to log file to be written during installation.
182 * Optional.
183 */
184int VBoxInstallDriver(const BOOL fInstall, const _TCHAR *pszDriverPath, BOOL fSilent,
185 const _TCHAR *pszLogFile)
186{
187 HRESULT hr = S_OK;
188 HMODULE hDIFxAPI = loadInstalledDll(L"DIFxAPI.dll");
189 if (NULL == hDIFxAPI)
190 {
191 _tprintf(_T("ERROR: Unable to locate DIFxAPI.dll!\n"));
192 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
193 }
194 else
195 {
196 if (fInstall)
197 {
198 g_pfnDriverPackageInstall = (fnDriverPackageInstall)GetProcAddress(hDIFxAPI, "DriverPackageInstallW");
199 if (g_pfnDriverPackageInstall == NULL)
200 {
201 _tprintf(_T("ERROR: Unable to retrieve entry point for DriverPackageInstallW!\n"));
202 hr = HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND);
203 }
204 }
205 else
206 {
207 g_pfnDriverPackageUninstall = (fnDriverPackageUninstall)GetProcAddress(hDIFxAPI, "DriverPackageUninstallW");
208 if (g_pfnDriverPackageUninstall == NULL)
209 {
210 _tprintf(_T("ERROR: Unable to retrieve entry point for DriverPackageUninstallW!\n"));
211 hr = HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND);
212 }
213 }
214
215 if (SUCCEEDED(hr))
216 {
217 g_pfnDIFXAPISetLogCallback = (fnDIFXAPISetLogCallback)GetProcAddress(hDIFxAPI, "DIFXAPISetLogCallbackW");
218 if (g_pfnDIFXAPISetLogCallback == NULL)
219 {
220 _tprintf(_T("ERROR: Unable to retrieve entry point for DIFXAPISetLogCallbackW!\n"));
221 hr = HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND);
222 }
223 }
224 }
225
226 if (SUCCEEDED(hr))
227 {
228 FILE *phFile = NULL;
229 if (pszLogFile)
230 {
231 phFile = _wfopen(pszLogFile, _T("a"));
232 if (!phFile)
233 _tprintf(_T("ERROR: Unable to create log file!\n"));
234 g_pfnDIFXAPISetLogCallback(LogCallback, phFile);
235 }
236
237 INSTALLERINFO instInfo =
238 {
239 TEXT("{7d2c708d-c202-40ab-b3e8-de21da1dc629}"), /* Our GUID for representing this installation tool. */
240 TEXT("VirtualBox Guest Additions Install Helper"),
241 TEXT("VirtualBox Guest Additions"), /** @todo Add version! */
242 TEXT("Oracle Corporation")
243 };
244
245 _TCHAR szDriverInf[MAX_PATH + 1];
246 if (0 == GetFullPathNameW(pszDriverPath, MAX_PATH, szDriverInf, NULL))
247 {
248 _tprintf(_T("ERROR: INF-Path too long / could not be retrieved!\n"));
249 hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
250 }
251 else
252 {
253 if (fInstall)
254 _tprintf(_T("Installing driver ...\n"));
255 else
256 _tprintf(_T("Uninstalling driver ...\n"));
257 _tprintf(_T("INF-File: %ws\n"), szDriverInf);
258
259 DWORD dwFlags = DRIVER_PACKAGE_FORCE;
260 if (!fInstall)
261 dwFlags |= DRIVER_PACKAGE_DELETE_FILES;
262
263 OSVERSIONINFO osi;
264 memset(&osi, 0, sizeof(OSVERSIONINFO));
265 osi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
266 if ( (GetVersionEx(&osi) != 0)
267 && (osi.dwPlatformId == VER_PLATFORM_WIN32_NT)
268 && (osi.dwMajorVersion < 6))
269 {
270 if (fInstall)
271 {
272 _tprintf(_T("Using legacy mode for install ...\n"));
273 dwFlags |= DRIVER_PACKAGE_LEGACY_MODE;
274 }
275 }
276
277 if (fSilent)
278 {
279 _tprintf(_T("Installation is silent ...\n"));
280 /*
281 * Don't add DRIVER_PACKAGE_SILENT to dwFlags here, otherwise
282 * installation will fail because we (still) don't have WHQL certified
283 * drivers. See CERT_E_WRONG_USAGE on MSDN for more information.
284 */
285 }
286
287 BOOL fReboot;
288 DWORD dwRet = fInstall ?
289 g_pfnDriverPackageInstall(szDriverInf, dwFlags, &instInfo, &fReboot)
290 : g_pfnDriverPackageUninstall(szDriverInf, dwFlags, &instInfo, &fReboot);
291 if (dwRet != ERROR_SUCCESS)
292 {
293 switch (dwRet)
294 {
295 case CRYPT_E_FILE_ERROR:
296 _tprintf(_T("ERROR: The catalog file for the specified driver package was not found!\n"));
297 break;
298
299 case ERROR_ACCESS_DENIED:
300 _tprintf(_T("ERROR: Caller is not in Administrators group to (un)install this driver package!\n"));
301 break;
302
303 case ERROR_BAD_ENVIRONMENT:
304 _tprintf(_T("ERROR: The current Microsoft Windows version does not support this operation!\n"));
305 break;
306
307 case ERROR_CANT_ACCESS_FILE:
308 _tprintf(_T("ERROR: The driver package files could not be accessed!\n"));
309 break;
310
311 case ERROR_DEPENDENT_APPLICATIONS_EXIST:
312 _tprintf(_T("ERROR: DriverPackageUninstall removed an association between the driver package and the specified application but the function did not uninstall the driver package because other applications are associated with the driver package!\n"));
313 break;
314
315 case ERROR_DRIVER_PACKAGE_NOT_IN_STORE:
316 _tprintf(_T("ERROR: There is no INF file in the DIFx driver store that corresponds to the INF file %ws!\n"), szDriverInf);
317 break;
318
319 case ERROR_FILE_NOT_FOUND:
320 _tprintf(_T("ERROR: File not found! File = %ws\n"), szDriverInf);
321 break;
322
323 case ERROR_IN_WOW64:
324 _tprintf(_T("ERROR: The calling application is a 32-bit application attempting to execute in a 64-bit environment, which is not allowed!\n"));
325 break;
326
327 case ERROR_INVALID_FLAGS:
328 _tprintf(_T("ERROR: The flags specified are invalid!\n"));
329 break;
330
331 case ERROR_INSTALL_FAILURE:
332 _tprintf(_T("ERROR: The (un)install operation failed! Consult the Setup API logs for more information.\n"));
333 break;
334
335 case ERROR_NO_MORE_ITEMS:
336 _tprintf(
337 _T(
338 "ERROR: The function found a match for the HardwareId value, but the specified driver was not a better match than the current driver and the caller did not specify the INSTALLFLAG_FORCE flag!\n"));
339 break;
340
341 case ERROR_NO_DRIVER_SELECTED:
342 _tprintf(_T("ERROR: No driver in .INF-file selected!\n"));
343 break;
344
345 case ERROR_SECTION_NOT_FOUND:
346 _tprintf(_T("ERROR: Section in .INF-file was not found!\n"));
347 break;
348
349 case ERROR_SHARING_VIOLATION:
350 _tprintf(_T("ERROR: A component of the driver package in the DIFx driver store is locked by a thread or process\n"));
351 break;
352
353 /*
354 * ! sig: Verifying file against specific Authenticode(tm) catalog failed! (0x800b0109)
355 * ! sig: Error 0x800b0109: A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider.
356 * !!! sto: No error message will be displayed as client is running in non-interactive mode.
357 * !!! ndv: Driver package failed signature validation. Error = 0xE0000247
358 */
359 case ERROR_DRIVER_STORE_ADD_FAILED:
360 _tprintf(_T("ERROR: Adding driver to the driver store failed!!\n"));
361 break;
362
363 case ERROR_UNSUPPORTED_TYPE:
364 _tprintf(_T("ERROR: The driver package type is not supported of INF %ws!\n"), szDriverInf);
365 break;
366
367 default:
368 {
369 /* Try error lookup with GetErrorMsg(). */
370 TCHAR szErrMsg[1024];
371 GetErrorMsg(dwRet, szErrMsg, sizeof(szErrMsg));
372 _tprintf(_T("ERROR (%08x): %ws\n"), dwRet, szErrMsg);
373 break;
374 }
375 }
376 hr = HRESULT_FROM_WIN32(dwRet);
377 }
378 g_pfnDIFXAPISetLogCallback(NULL, NULL);
379 if (phFile)
380 fclose(phFile);
381 if (SUCCEEDED(hr))
382 {
383 _tprintf(_T("Driver was installed successfully!\n"));
384 if (fReboot)
385 _tprintf(_T("A reboot is needed to complete the driver (un)installation!\n"));
386 }
387 }
388 }
389
390 if (NULL != hDIFxAPI)
391 FreeLibrary(hDIFxAPI);
392
393 return SUCCEEDED(hr) ? EXIT_OK : EXIT_FAIL;
394}
395
396static UINT WINAPI vboxDrvInstExecuteInfFileCallback(PVOID Context,
397 UINT Notification,
398 UINT_PTR Param1,
399 UINT_PTR Param2)
400{
401#ifdef DEBUG
402 _tprintf (_T( "Got installation notification %u\n"), Notification);
403#endif
404
405 switch (Notification)
406 {
407 case SPFILENOTIFY_NEEDMEDIA:
408 _tprintf (_T( "Requesting installation media ...\n"));
409 break;
410
411 case SPFILENOTIFY_STARTCOPY:
412 _tprintf (_T( "Copying driver files to destination ...\n"));
413 break;
414
415 case SPFILENOTIFY_TARGETNEWER:
416 case SPFILENOTIFY_TARGETEXISTS:
417 return TRUE;
418 }
419
420 return SetupDefaultQueueCallback(Context, Notification, Param1, Param2);
421}
422
423/**
424 * Executes a sepcified .INF section to install/uninstall drivers and/or services.
425 *
426 * @return Exit code (EXIT_OK, EXIT_FAIL)
427 * @param pszSection Section to execute; usually it's "DefaultInstall".
428 * @param iMode Execution mode to use (see MSDN).
429 * @param pszInf Full qualified path of the .INF file to use.
430 */
431int ExecuteInfFile(const _TCHAR *pszSection, int iMode, const _TCHAR *pszInf)
432{
433 RT_NOREF(iMode);
434 _tprintf(_T("Installing from INF-File: %ws (Section: %ws) ...\n"),
435 pszInf, pszSection);
436
437 UINT uErrorLine = 0;
438 HINF hINF = SetupOpenInfFile(pszInf, NULL, INF_STYLE_WIN4, &uErrorLine);
439 if (hINF != INVALID_HANDLE_VALUE)
440 {
441 PVOID pvQueue = SetupInitDefaultQueueCallback(NULL);
442
443 BOOL fSuccess = SetupInstallFromInfSection(NULL,
444 hINF,
445 pszSection,
446 SPINST_ALL,
447 HKEY_LOCAL_MACHINE,
448 NULL,
449 SP_COPY_NEWER_OR_SAME | SP_COPY_NOSKIP,
450 vboxDrvInstExecuteInfFileCallback,
451 pvQueue,
452 NULL,
453 NULL
454 );
455 if (fSuccess)
456 {
457 _tprintf (_T( "File installation stage successful\n"));
458
459 fSuccess = SetupInstallServicesFromInfSection(hINF,
460 L"DefaultInstall.Services",
461 0 /* Flags */);
462 if (fSuccess)
463 {
464 _tprintf (_T( "Service installation stage successful. Installation completed\n"));
465 }
466 else
467 {
468 DWORD dwErr = GetLastError();
469 switch (dwErr)
470 {
471 case ERROR_SUCCESS_REBOOT_REQUIRED:
472 _tprintf (_T( "A reboot is required to complete the installation\n"));
473 break;
474
475 case ERROR_SECTION_NOT_FOUND:
476 break;
477
478 default:
479 _tprintf (_T( "Error %ld while installing service\n"), dwErr);
480 break;
481 }
482 }
483 }
484 else
485 _tprintf (_T( "Error %ld while installing files\n"), GetLastError());
486
487 if (pvQueue)
488 SetupTermDefaultQueueCallback(pvQueue);
489
490 SetupCloseInfFile(hINF);
491 }
492 else
493 _tprintf (_T( "Unable to open %ws: %ld (error line %u)\n"),
494 pszInf, GetLastError(), uErrorLine);
495
496 return EXIT_OK;
497}
498
499/**
500 * Adds a string entry to a MULTI_SZ registry list.
501 *
502 * @return Exit code (EXIT_OK, EXIT_FAIL)
503 * @param pszSubKey Sub key containing the list.
504 * @param pszKeyValue The actual key name of the list.
505 * @param pszValueToRemove The value to add to the list.
506 * @param uiOrder Position (zero-based) of where to add the value to the list.
507 */
508int RegistryAddStringToMultiSZ(const TCHAR *pszSubKey, const TCHAR *pszKeyValue, const TCHAR *pszValueToAdd, unsigned int uiOrder)
509{
510#ifdef DEBUG
511 _tprintf(_T("AddStringToMultiSZ: Adding MULTI_SZ string %ws to %ws\\%ws (Order = %d)\n"), pszValueToAdd, pszSubKey, pszKeyValue, uiOrder);
512#endif
513
514 HKEY hKey = NULL;
515 DWORD disp, dwType;
516 LONG lRet = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey, &disp);
517 if (lRet != ERROR_SUCCESS)
518 _tprintf(_T("AddStringToMultiSZ: RegCreateKeyEx %ts failed with error %ld!\n"), pszSubKey, lRet);
519
520 if (lRet == ERROR_SUCCESS)
521 {
522 TCHAR szKeyValue[512] = { 0 };
523 TCHAR szNewKeyValue[512] = { 0 };
524 DWORD cbKeyValue = sizeof(szKeyValue);
525
526 lRet = RegQueryValueEx(hKey, pszKeyValue, NULL, &dwType, (LPBYTE)szKeyValue, &cbKeyValue);
527 if ( lRet != ERROR_SUCCESS
528 || dwType != REG_MULTI_SZ)
529 {
530 _tprintf(_T("AddStringToMultiSZ: RegQueryValueEx failed with error %ld, key type = 0x%x!\n"), lRet, dwType);
531 }
532 else
533 {
534
535 /* Look if the network provider is already in the list. */
536 unsigned int iPos = 0;
537 size_t cb = 0;
538
539 /* Replace delimiting "\0"'s with "," to make tokenizing work. */
540 for (unsigned i = 0; i < cbKeyValue / sizeof(TCHAR); i++)
541 if (szKeyValue[i] == '\0') szKeyValue[i] = ',';
542
543 TCHAR *pszToken = wcstok(szKeyValue, _T(","));
544 TCHAR *pszNewToken = NULL;
545 TCHAR *pNewKeyValuePos = szNewKeyValue;
546 while (pszToken != NULL)
547 {
548 pszNewToken = wcstok(NULL, _T(","));
549
550 /* Append new value (at beginning if iOrder=0). */
551 if (iPos == uiOrder)
552 {
553 memcpy(pNewKeyValuePos, pszValueToAdd, wcslen(pszValueToAdd)*sizeof(TCHAR));
554
555 cb += (wcslen(pszValueToAdd) + 1) * sizeof(TCHAR); /* Add trailing zero as well. */
556 pNewKeyValuePos += wcslen(pszValueToAdd) + 1;
557 iPos++;
558 }
559
560 if (0 != wcsicmp(pszToken, pszValueToAdd))
561 {
562 memcpy(pNewKeyValuePos, pszToken, wcslen(pszToken)*sizeof(TCHAR));
563 cb += (wcslen(pszToken) + 1) * sizeof(TCHAR); /* Add trailing zero as well. */
564 pNewKeyValuePos += wcslen(pszToken) + 1;
565 iPos++;
566 }
567
568 pszToken = pszNewToken;
569 }
570
571 /* Append as last item if needed. */
572 if (uiOrder >= iPos)
573 {
574 memcpy(pNewKeyValuePos, pszValueToAdd, wcslen(pszValueToAdd)*sizeof(TCHAR));
575 cb += wcslen(pszValueToAdd) * sizeof(TCHAR); /* Add trailing zero as well. */
576 }
577
578 lRet = RegSetValueExW(hKey, pszKeyValue, 0, REG_MULTI_SZ, (LPBYTE)szNewKeyValue, (DWORD)cb);
579 if (lRet != ERROR_SUCCESS)
580 _tprintf(_T("AddStringToMultiSZ: RegSetValueEx failed with error %ld!\n"), lRet);
581 }
582
583 RegCloseKey(hKey);
584 #ifdef DEBUG
585 if (lRet == ERROR_SUCCESS)
586 _tprintf(_T("AddStringToMultiSZ: Value %ws successfully written!\n"), pszValueToAdd);
587 #endif
588 }
589
590 return (lRet == ERROR_SUCCESS) ? EXIT_OK : EXIT_FAIL;
591}
592
593/**
594 * Removes a string entry from a MULTI_SZ registry list.
595 *
596 * @return Exit code (EXIT_OK, EXIT_FAIL)
597 * @param pszSubKey Sub key containing the list.
598 * @param pszKeyValue The actual key name of the list.
599 * @param pszValueToRemove The value to remove from the list.
600 */
601int RegistryRemoveStringFromMultiSZ(const TCHAR *pszSubKey, const TCHAR *pszKeyValue, const TCHAR *pszValueToRemove)
602{
603 /// @todo Make string sizes dynamically allocated!
604
605 const TCHAR *pszKey = pszSubKey;
606#ifdef DEBUG
607 _tprintf(_T("RemoveStringFromMultiSZ: Removing MULTI_SZ string: %ws from %ws\\%ws ...\n"), pszValueToRemove, pszSubKey, pszKeyValue);
608#endif
609
610 HKEY hkey;
611 DWORD disp, dwType;
612 LONG lRet = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pszKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hkey, &disp);
613 if (lRet != ERROR_SUCCESS)
614 _tprintf(_T("RemoveStringFromMultiSZ: RegCreateKeyEx %ts failed with error %ld!\n"), pszKey, lRet);
615
616 if (lRet == ERROR_SUCCESS)
617 {
618 TCHAR szKeyValue[1024];
619 DWORD cbKeyValue = sizeof(szKeyValue);
620
621 lRet = RegQueryValueEx(hkey, pszKeyValue, NULL, &dwType, (LPBYTE)szKeyValue, &cbKeyValue);
622 if ( lRet != ERROR_SUCCESS
623 || dwType != REG_MULTI_SZ)
624 {
625 _tprintf(_T("RemoveStringFromMultiSZ: RegQueryValueEx failed with %d, key type = 0x%x!\n"), lRet, dwType);
626 }
627 else
628 {
629 #ifdef DEBUG
630 _tprintf(_T("RemoveStringFromMultiSZ: Current key len: %ld\n"), cbKeyValue);
631 #endif
632
633 TCHAR szCurString[1024] = { 0 };
634 TCHAR szFinalString[1024] = { 0 };
635 int iIndex = 0;
636 int iNewIndex = 0;
637 for (unsigned i = 0; i < cbKeyValue / sizeof(TCHAR); i++)
638 {
639 if (szKeyValue[i] != _T('\0'))
640 szCurString[iIndex++] = szKeyValue[i];
641
642 if ( (!szKeyValue[i] == _T('\0'))
643 && (szKeyValue[i + 1] == _T('\0')))
644 {
645 if (NULL == wcsstr(szCurString, pszValueToRemove))
646 {
647 wcscat(&szFinalString[iNewIndex], szCurString);
648
649 if (iNewIndex == 0)
650 iNewIndex = iIndex;
651 else iNewIndex += iIndex;
652
653 szFinalString[++iNewIndex] = _T('\0');
654 }
655
656 iIndex = 0;
657 ZeroMemory(szCurString, sizeof(szCurString));
658 }
659 }
660 szFinalString[++iNewIndex] = _T('\0');
661 #ifdef DEBUG
662 _tprintf(_T("RemoveStringFromMultiSZ: New key value: %ws (%u bytes)\n"),
663 szFinalString, iNewIndex * sizeof(TCHAR));
664 #endif
665
666 lRet = RegSetValueExW(hkey, pszKeyValue, 0, REG_MULTI_SZ, (LPBYTE)szFinalString, iNewIndex * sizeof(TCHAR));
667 if (lRet != ERROR_SUCCESS)
668 _tprintf(_T("RemoveStringFromMultiSZ: RegSetValueEx failed with %d!\n"), lRet);
669 }
670
671 RegCloseKey(hkey);
672 #ifdef DEBUG
673 if (lRet == ERROR_SUCCESS)
674 _tprintf(_T("RemoveStringFromMultiSZ: Value %ws successfully removed!\n"), pszValueToRemove);
675 #endif
676 }
677
678 return (lRet == ERROR_SUCCESS) ? EXIT_OK : EXIT_FAIL;
679}
680
681/**
682 * Adds a string to a registry string list (STRING_SZ).
683 * Only operates in HKLM for now, needs to be extended later for
684 * using other hives. Only processes lists with a "," separator
685 * at the moment.
686 *
687 * @return Exit code (EXIT_OK, EXIT_FAIL)
688 * @param pszSubKey Sub key containing the list.
689 * @param pszKeyValue The actual key name of the list.
690 * @param pszValueToAdd The value to add to the list.
691 * @param uiOrder Position (zero-based) of where to add the value to the list.
692 * @param dwFlags Flags.
693 */
694int RegistryAddStringToList(const TCHAR *pszSubKey, const TCHAR *pszKeyValue, const TCHAR *pszValueToAdd,
695 unsigned int uiOrder, DWORD dwFlags)
696{
697 HKEY hKey = NULL;
698 DWORD disp, dwType;
699 LONG lRet = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey, &disp);
700 if (lRet != ERROR_SUCCESS)
701 _tprintf(_T("RegistryAddStringToList: RegCreateKeyEx %ts failed with error %ld!\n"), pszSubKey, lRet);
702
703 TCHAR szKeyValue[512] = { 0 };
704 TCHAR szNewKeyValue[512] = { 0 };
705 DWORD cbKeyValue = sizeof(szKeyValue);
706
707 lRet = RegQueryValueEx(hKey, pszKeyValue, NULL, &dwType, (LPBYTE)szKeyValue, &cbKeyValue);
708 if ( lRet != ERROR_SUCCESS
709 || dwType != REG_SZ)
710 {
711 _tprintf(_T("RegistryAddStringToList: RegQueryValueEx failed with %d, key type = 0x%x!\n"), lRet, dwType);
712 }
713
714 if (lRet == ERROR_SUCCESS)
715 {
716 #ifdef DEBUG
717 _tprintf(_T("RegistryAddStringToList: Key value: %ws\n"), szKeyValue);
718 #endif
719
720 /* Create entire new list. */
721 unsigned int iPos = 0;
722 TCHAR *pszToken = wcstok(szKeyValue, _T(","));
723 TCHAR *pszNewToken = NULL;
724 while (pszToken != NULL)
725 {
726 pszNewToken = wcstok(NULL, _T(","));
727
728 /* Append new provider name (at beginning if iOrder=0). */
729 if (iPos == uiOrder)
730 {
731 wcscat(szNewKeyValue, pszValueToAdd);
732 wcscat(szNewKeyValue, _T(","));
733 iPos++;
734 }
735
736 BOOL fAddToList = FALSE;
737 if ( !wcsicmp(pszToken, pszValueToAdd)
738 && (dwFlags & VBOX_REG_STRINGLIST_ALLOW_DUPLICATES))
739 fAddToList = TRUE;
740 else if (wcsicmp(pszToken, pszValueToAdd))
741 fAddToList = TRUE;
742
743 if (fAddToList)
744 {
745 wcscat(szNewKeyValue, pszToken);
746 wcscat(szNewKeyValue, _T(","));
747 iPos++;
748 }
749
750 #ifdef DEBUG
751 _tprintf (_T("RegistryAddStringToList: Temp new key value: %ws\n"), szNewKeyValue);
752 #endif
753 pszToken = pszNewToken;
754 }
755
756 /* Append as last item if needed. */
757 if (uiOrder >= iPos)
758 wcscat(szNewKeyValue, pszValueToAdd);
759
760 /* Last char a delimiter? Cut off ... */
761 if (szNewKeyValue[wcslen(szNewKeyValue) - 1] == ',')
762 szNewKeyValue[wcslen(szNewKeyValue) - 1] = '\0';
763
764 size_t iNewLen = (wcslen(szNewKeyValue) * sizeof(WCHAR)) + sizeof(WCHAR);
765
766 #ifdef DEBUG
767 _tprintf(_T("RegistryAddStringToList: New provider list: %ws (%u bytes)\n"), szNewKeyValue, iNewLen);
768 #endif
769
770 lRet = RegSetValueExW(hKey, pszKeyValue, 0, REG_SZ, (LPBYTE)szNewKeyValue, (DWORD)iNewLen);
771 if (lRet != ERROR_SUCCESS)
772 _tprintf(_T("RegistryAddStringToList: RegSetValueEx failed with %ld!\n"), lRet);
773 }
774
775 RegCloseKey(hKey);
776 return (lRet == ERROR_SUCCESS) ? EXIT_OK : EXIT_FAIL;
777}
778
779/**
780 * Removes a string from a registry string list (STRING_SZ).
781 * Only operates in HKLM for now, needs to be extended later for
782 * using other hives. Only processes lists with a "," separator
783 * at the moment.
784 *
785 * @return Exit code (EXIT_OK, EXIT_FAIL)
786 * @param pszSubKey Sub key containing the list.
787 * @param pszKeyValue The actual key name of the list.
788 * @param pszValueToRemove The value to remove from the list.
789 */
790int RegistryRemoveStringFromList(const TCHAR *pszSubKey, const TCHAR *pszKeyValue, const TCHAR *pszValueToRemove)
791{
792 HKEY hKey = NULL;
793 DWORD disp, dwType;
794 LONG lRet = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey, &disp);
795 if (lRet != ERROR_SUCCESS)
796 _tprintf(_T("RegistryRemoveStringFromList: RegCreateKeyEx %ts failed with error %ld!\n"), pszSubKey, lRet);
797
798 TCHAR szKeyValue[512] = { 0 };
799 TCHAR szNewKeyValue[512] = { 0 };
800 DWORD cbKeyValue = sizeof(szKeyValue);
801
802 lRet = RegQueryValueEx(hKey, pszKeyValue, NULL, &dwType, (LPBYTE)szKeyValue, &cbKeyValue);
803 if ( lRet != ERROR_SUCCESS
804 || dwType != REG_SZ)
805 {
806 _tprintf(_T("RegistryRemoveStringFromList: RegQueryValueEx failed with %d, key type = 0x%x!\n"), lRet, dwType);
807 }
808
809 if (lRet == ERROR_SUCCESS)
810 {
811 #ifdef DEBUG
812 _tprintf(_T("RegistryRemoveStringFromList: Key value: %ws\n"), szKeyValue);
813 #endif
814
815 /* Create entire new list. */
816 int iPos = 0;
817
818 TCHAR *pszToken = wcstok(szKeyValue, _T(","));
819 TCHAR *pszNewToken = NULL;
820 while (pszToken != NULL)
821 {
822 pszNewToken = wcstok(NULL, _T(","));
823
824 /* Append all list values as long as it's not the
825 * value we want to remove. */
826 if (wcsicmp(pszToken, pszValueToRemove))
827 {
828 wcscat(szNewKeyValue, pszToken);
829 wcscat(szNewKeyValue, _T(","));
830 iPos++;
831 }
832
833 #ifdef DEBUG
834 _tprintf (_T("RegistryRemoveStringFromList: Temp new key value: %ws\n"), szNewKeyValue);
835 #endif
836 pszToken = pszNewToken;
837 }
838
839 /* Last char a delimiter? Cut off ... */
840 if (szNewKeyValue[wcslen(szNewKeyValue) - 1] == ',')
841 szNewKeyValue[wcslen(szNewKeyValue) - 1] = '\0';
842
843 size_t iNewLen = (wcslen(szNewKeyValue) * sizeof(WCHAR)) + sizeof(WCHAR);
844
845 #ifdef DEBUG
846 _tprintf(_T("RegistryRemoveStringFromList: New provider list: %ws (%u bytes)\n"), szNewKeyValue, iNewLen);
847 #endif
848
849 lRet = RegSetValueExW(hKey, pszKeyValue, 0, REG_SZ, (LPBYTE)szNewKeyValue, (DWORD)iNewLen);
850 if (lRet != ERROR_SUCCESS)
851 _tprintf(_T("RegistryRemoveStringFromList: RegSetValueEx failed with %ld!\n"), lRet);
852 }
853
854 RegCloseKey(hKey);
855 return (lRet == ERROR_SUCCESS) ? EXIT_OK : EXIT_FAIL;
856}
857
858/**
859 * Adds a network provider with a specified order to the system.
860 *
861 * @return Exit code (EXIT_OK, EXIT_FAIL)
862 * @param pszProvider Name of network provider to add.
863 * @param uiOrder Position in list (zero-based) of where to add.
864 */
865int AddNetworkProvider(const TCHAR *pszProvider, unsigned int uiOrder)
866{
867 _tprintf(_T("Adding network provider \"%ws\" (Order = %u) ...\n"), pszProvider, uiOrder);
868 int rc = RegistryAddStringToList(_T("System\\CurrentControlSet\\Control\\NetworkProvider\\Order"),
869 _T("ProviderOrder"),
870 pszProvider, uiOrder, VBOX_REG_STRINGLIST_NONE /* No flags set */);
871 if (rc == EXIT_OK)
872 _tprintf(_T("Network provider successfully added!\n"));
873 return rc;
874}
875
876/**
877 * Removes a network provider from the system.
878 *
879 * @return Exit code (EXIT_OK, EXIT_FAIL)
880 * @param pszProvider Name of network provider to remove.
881 */
882int RemoveNetworkProvider(const TCHAR *pszProvider)
883{
884 _tprintf(_T("Removing network provider \"%ws\" ...\n"), pszProvider);
885 int rc = RegistryRemoveStringFromList(_T("System\\CurrentControlSet\\Control\\NetworkProvider\\Order"),
886 _T("ProviderOrder"),
887 pszProvider);
888 if (rc == EXIT_OK)
889 _tprintf(_T("Network provider successfully removed!\n"));
890 return rc;
891}
892
893int CreateService(const TCHAR *pszStartStopName,
894 const TCHAR *pszDisplayName,
895 int iServiceType,
896 int iStartType,
897 const TCHAR *pszBinPath,
898 const TCHAR *pszLoadOrderGroup,
899 const TCHAR *pszDependencies,
900 const TCHAR *pszLogonUser,
901 const TCHAR *pszLogonPassword)
902{
903 int rc = ERROR_SUCCESS;
904
905 _tprintf(_T("Installing service %ws (%ws) ...\n"), pszDisplayName, pszStartStopName);
906
907 SC_HANDLE hSCManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
908 if (hSCManager == NULL)
909 {
910 _tprintf(_T("Could not get handle to SCM! Error: %ld\n"), GetLastError());
911 return EXIT_FAIL;
912 }
913
914 /* Fixup end of multistring. */
915 TCHAR szDepend[ _MAX_PATH ] = { 0 }; /** @todo Use dynamically allocated string here! */
916 if (pszDependencies != NULL)
917 {
918 _tcsnccpy (szDepend, pszDependencies, wcslen(pszDependencies));
919 DWORD len = (DWORD)wcslen (szDepend);
920 szDepend [len + 1] = 0;
921
922 /* Replace comma separator on null separator. */
923 for (DWORD i = 0; i < len; i++)
924 {
925 if (',' == szDepend [i])
926 szDepend [i] = 0;
927 }
928 }
929
930 DWORD dwTag = 0xDEADBEAF;
931 SC_HANDLE hService = CreateService (hSCManager, /* SCManager database handle. */
932 pszStartStopName, /* Name of service. */
933 pszDisplayName, /* Name to display. */
934 SERVICE_ALL_ACCESS, /* Desired access. */
935 iServiceType, /* Service type. */
936 iStartType, /* Start type. */
937 SERVICE_ERROR_NORMAL, /* Error control type. */
938 pszBinPath, /* Service's binary. */
939 pszLoadOrderGroup, /* Ordering group. */
940 (pszLoadOrderGroup != NULL) ? &dwTag : NULL, /* Tag identifier. */
941 (pszDependencies != NULL) ? szDepend : NULL, /* Dependencies. */
942 (pszLogonUser != NULL) ? pszLogonUser: NULL, /* Account. */
943 (pszLogonPassword != NULL) ? pszLogonPassword : NULL); /* Password. */
944 if (NULL == hService)
945 {
946 DWORD dwErr = GetLastError();
947 switch (dwErr)
948 {
949
950 case ERROR_SERVICE_EXISTS:
951 {
952 _tprintf(_T("Service already exists. No installation required. Updating the service config.\n"));
953
954 hService = OpenService (hSCManager, /* SCManager database handle. */
955 pszStartStopName, /* Name of service. */
956 SERVICE_ALL_ACCESS); /* Desired access. */
957 if (NULL == hService)
958 {
959 dwErr = GetLastError();
960 _tprintf(_T("Could not open service! Error: %ld\n"), dwErr);
961 }
962 else
963 {
964 BOOL fResult = ChangeServiceConfig (hService, /* Service handle. */
965 iServiceType, /* Service type. */
966 iStartType, /* Start type. */
967 SERVICE_ERROR_NORMAL, /* Error control type. */
968 pszBinPath, /* Service's binary. */
969 pszLoadOrderGroup, /* Ordering group. */
970 (pszLoadOrderGroup != NULL) ? &dwTag : NULL, /* Tag identifier. */
971 (pszDependencies != NULL) ? szDepend : NULL, /* Dependencies. */
972 (pszLogonUser != NULL) ? pszLogonUser: NULL, /* Account. */
973 (pszLogonPassword != NULL) ? pszLogonPassword : NULL, /* Password. */
974 pszDisplayName); /* Name to display. */
975 if (fResult)
976 _tprintf(_T("The service config has been successfully updated.\n"));
977 else
978 {
979 dwErr = GetLastError();
980 _tprintf(_T("Could not change service config! Error: %ld\n"), dwErr);
981 }
982 CloseServiceHandle(hService);
983 }
984
985 /*
986 * This entire branch do not return an error to avoid installations failures,
987 * if updating service parameters. Better to have a running system with old
988 * parameters and the failure information in the installation log.
989 */
990 break;
991 }
992
993 case ERROR_INVALID_PARAMETER:
994
995 _tprintf(_T("Invalid parameter specified!\n"));
996 rc = EXIT_FAIL;
997 break;
998
999 default:
1000
1001 _tprintf(_T("Could not create service! Error: %ld\n"), dwErr);
1002 rc = EXIT_FAIL;
1003 break;
1004 }
1005
1006 if (rc == EXIT_FAIL)
1007 goto cleanup;
1008 }
1009 else
1010 {
1011 CloseServiceHandle (hService);
1012 _tprintf(_T("Installation of service successful!\n"));
1013 }
1014
1015cleanup:
1016
1017 if (hSCManager != NULL)
1018 CloseServiceHandle (hSCManager);
1019
1020 return rc;
1021}
1022
1023int DelService(const TCHAR *pszStartStopName)
1024{
1025 int rc = ERROR_SUCCESS;
1026
1027 _tprintf(_T("Deleting service '%ws' ...\n"), pszStartStopName);
1028
1029 SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
1030 SC_HANDLE hService = NULL;
1031 if (hSCManager == NULL)
1032 {
1033 _tprintf(_T("Could not get handle to SCM! Error: %ld\n"), GetLastError());
1034 rc = EXIT_FAIL;
1035 }
1036 else
1037 {
1038 hService = OpenService(hSCManager, pszStartStopName, SERVICE_ALL_ACCESS);
1039 if (NULL == hService)
1040 {
1041 _tprintf(_T("Could not open service '%ws'! Error: %ld\n"), pszStartStopName, GetLastError());
1042 rc = EXIT_FAIL;
1043 }
1044 }
1045
1046 if (hService != NULL)
1047 {
1048 SC_LOCK hSCLock = LockServiceDatabase(hSCManager);
1049 if (hSCLock != NULL)
1050 {
1051 if (FALSE == DeleteService(hService))
1052 {
1053 DWORD dwErr = GetLastError();
1054 switch (dwErr)
1055 {
1056
1057 case ERROR_SERVICE_MARKED_FOR_DELETE:
1058
1059 _tprintf(_T("Service '%ws' already marked for deletion.\n"), pszStartStopName);
1060 break;
1061
1062 default:
1063
1064 _tprintf(_T("Could not delete service '%ws'! Error: %ld\n"), pszStartStopName, GetLastError());
1065 rc = EXIT_FAIL;
1066 break;
1067 }
1068 }
1069 else
1070 {
1071 _tprintf(_T("Service '%ws' successfully removed!\n"), pszStartStopName);
1072 }
1073 UnlockServiceDatabase(hSCLock);
1074 }
1075 else
1076 {
1077 _tprintf(_T("Unable to lock service database! Error: %ld\n"), GetLastError());
1078 rc = EXIT_FAIL;
1079 }
1080 CloseServiceHandle(hService);
1081 }
1082
1083 if (hSCManager != NULL)
1084 CloseServiceHandle(hSCManager);
1085
1086 return rc;
1087}
1088
1089DWORD RegistryWrite(HKEY hRootKey,
1090 const _TCHAR *pszSubKey,
1091 const _TCHAR *pszValueName,
1092 DWORD dwType,
1093 const BYTE *pbData,
1094 DWORD cbData)
1095{
1096 DWORD lRet;
1097 HKEY hKey;
1098 lRet = RegCreateKeyEx (hRootKey,
1099 pszSubKey,
1100 0, /* Reserved */
1101 NULL, /* lpClass [in, optional] */
1102 0, /* dwOptions [in] */
1103 KEY_WRITE,
1104 NULL, /* lpSecurityAttributes [in, optional] */
1105 &hKey,
1106 NULL); /* lpdwDisposition [out, optional] */
1107 if (lRet != ERROR_SUCCESS)
1108 {
1109 _tprintf(_T("Could not open registry key! Error: %ld\n"), GetLastError());
1110 }
1111 else
1112 {
1113 lRet = RegSetValueEx(hKey, pszValueName, 0, dwType, (BYTE*)pbData, cbData);
1114 if (lRet != ERROR_SUCCESS)
1115 _tprintf(_T("Could not write to registry! Error: %ld\n"), GetLastError());
1116 RegCloseKey(hKey);
1117
1118 }
1119 return lRet;
1120}
1121
1122void PrintHelp(void)
1123{
1124 _tprintf(_T("VirtualBox Guest Additions Installation Helper for Windows\n"));
1125 _tprintf(_T("Version: %d.%d.%d.%d\n\n"), VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV);
1126 _tprintf(_T("Syntax:\n"));
1127 _tprintf(_T("\n"));
1128 _tprintf(_T("Drivers:\n"));
1129 _tprintf(_T("\tVBoxDrvInst driver install <inf-file> [log file]\n"));
1130 _tprintf(_T("\tVBoxDrvInst driver uninstall <inf-file> [log file]\n"));
1131 _tprintf(_T("\tVBoxDrvInst driver executeinf <inf-file>\n"));
1132 _tprintf(_T("\n"));
1133 _tprintf(_T("Network Provider:\n"));
1134 _tprintf(_T("\tVBoxDrvInst netprovider add <name> [order]\n"));
1135 _tprintf(_T("\tVBoxDrvInst netprovider remove <name>\n"));
1136 _tprintf(_T("\n"));
1137 _tprintf(_T("Registry:\n"));
1138 _tprintf(_T("\tVBoxDrvInst registry write <root> <sub key>\n")
1139 _T("\t <key name> <key type> <value>\n")
1140 _T("\t [type] [size]\n"));
1141 _tprintf(_T("\tVBoxDrvInst registry addmultisz <root> <sub key>\n")
1142 _T("\t <value> [order]\n"));
1143 _tprintf(_T("\tVBoxDrvInst registry delmultisz <root> <sub key>\n")
1144 _T("\t <key name> <value to remove>\n"));
1145 /** @todo Add "service" category! */
1146 _tprintf(_T("\n"));
1147}
1148
1149int __cdecl _tmain(int argc, _TCHAR *argv[])
1150{
1151 int rc = EXIT_USAGE;
1152
1153 OSVERSIONINFO OSinfo;
1154 OSinfo.dwOSVersionInfoSize = sizeof(OSinfo);
1155 GetVersionEx(&OSinfo);
1156
1157 if (argc >= 2)
1158 {
1159 if ( !_tcsicmp(argv[1], _T("driver"))
1160 && argc >= 3)
1161 {
1162 _TCHAR szINF[_MAX_PATH] = { 0 }; /* Complete path to INF file.*/
1163 if ( ( !_tcsicmp(argv[2], _T("install"))
1164 || !_tcsicmp(argv[2], _T("uninstall")))
1165 && argc >= 4)
1166 {
1167 if (OSinfo.dwMajorVersion < 5)
1168 {
1169 _tprintf(_T("ERROR: Platform not supported for driver (un)installation!\n"));
1170 rc = EXIT_FAIL;
1171 }
1172 else
1173 {
1174 _sntprintf(szINF, sizeof(szINF) / sizeof(TCHAR), _T("%ws"), argv[3]);
1175
1176 _TCHAR szLogFile[_MAX_PATH] = { 0 };
1177 if (argc > 4)
1178 _sntprintf(szLogFile, sizeof(szLogFile) / sizeof(TCHAR), _T("%ws"), argv[4]);
1179 rc = VBoxInstallDriver(!_tcsicmp(argv[2], _T("install")) ? TRUE : FALSE, szINF,
1180 FALSE /* Not silent */, szLogFile[0] != NULL ? szLogFile : NULL);
1181 }
1182 }
1183 else if ( !_tcsicmp(argv[2], _T("executeinf"))
1184 && argc == 4)
1185 {
1186 _sntprintf(szINF, sizeof(szINF) / sizeof(TCHAR), _T("%ws"), argv[3]);
1187 rc = ExecuteInfFile(_T("DefaultInstall"), 132, szINF);
1188 }
1189 }
1190 else if ( !_tcsicmp(argv[1], _T("netprovider"))
1191 && argc >= 3)
1192 {
1193 _TCHAR szProvider[_MAX_PATH] = { 0 }; /* The network provider name for the registry. */
1194 if ( !_tcsicmp(argv[2], _T("add"))
1195 && argc >= 4)
1196 {
1197 int iOrder = 0;
1198 if (argc > 4)
1199 iOrder = _ttoi(argv[4]);
1200 _sntprintf(szProvider, sizeof(szProvider) / sizeof(TCHAR), _T("%ws"), argv[3]);
1201 rc = AddNetworkProvider(szProvider, iOrder);
1202 }
1203 else if ( !_tcsicmp(argv[2], _T("remove"))
1204 && argc >= 4)
1205 {
1206 _sntprintf(szProvider, sizeof(szProvider) / sizeof(TCHAR), _T("%ws"), argv[3]);
1207 rc = RemoveNetworkProvider(szProvider);
1208 }
1209 }
1210 else if ( !_tcsicmp(argv[1], _T("service"))
1211 && argc >= 3)
1212 {
1213 if ( !_tcsicmp(argv[2], _T("create"))
1214 && argc >= 8)
1215 {
1216 rc = CreateService(argv[3],
1217 argv[4],
1218 _ttoi(argv[5]),
1219 _ttoi(argv[6]),
1220 argv[7],
1221 (argc > 8) ? argv[8] : NULL,
1222 (argc > 9) ? argv[9] : NULL,
1223 (argc > 10) ? argv[10] : NULL,
1224 (argc > 11) ? argv[11] : NULL);
1225 }
1226 else if ( !_tcsicmp(argv[2], _T("delete"))
1227 && argc == 4)
1228 {
1229 rc = DelService(argv[3]);
1230 }
1231 }
1232 else if ( !_tcsicmp(argv[1], _T("registry"))
1233 && argc >= 3)
1234 {
1235 /** @todo add a handleRegistry(argc, argv) method to keep things cleaner */
1236 if ( !_tcsicmp(argv[2], _T("addmultisz"))
1237 && argc == 7)
1238 {
1239 rc = RegistryAddStringToMultiSZ(argv[3], argv[4], argv[5], _ttoi(argv[6]));
1240 }
1241 else if ( !_tcsicmp(argv[2], _T("delmultisz"))
1242 && argc == 6)
1243 {
1244 rc = RegistryRemoveStringFromMultiSZ(argv[3], argv[4], argv[5]);
1245 }
1246 else if ( !_tcsicmp(argv[2], _T("write"))
1247 && argc >= 8)
1248 {
1249 HKEY hRootKey = HKEY_LOCAL_MACHINE; /** @todo needs to be expanded (argv[3]) */
1250 DWORD dwValSize = 0;
1251 BYTE *pbVal = NULL;
1252 DWORD dwVal;
1253
1254 if (argc > 8)
1255 {
1256 if (!_tcsicmp(argv[8], _T("dword")))
1257 {
1258 dwVal = _ttol(argv[7]);
1259 pbVal = (BYTE*)&dwVal;
1260 dwValSize = sizeof(DWORD);
1261 }
1262 }
1263 if (pbVal == NULL) /* By default interpret value as string */
1264 {
1265 pbVal = (BYTE *)argv[7];
1266 dwValSize = (DWORD)_tcslen(argv[7]);
1267 }
1268 if (argc > 9)
1269 dwValSize = _ttol(argv[9]); /* Get the size in bytes of the value we want to write */
1270 rc = RegistryWrite(hRootKey,
1271 argv[4], /* Sub key */
1272 argv[5], /* Value name */
1273 REG_BINARY, /** @todo needs to be expanded (argv[6]) */
1274 pbVal, /* The value itself */
1275 dwValSize); /* Size of the value */
1276 }
1277#if 0
1278 else if (!_tcsicmp(argv[2], _T("read")))
1279 {
1280 }
1281 else if (!_tcsicmp(argv[2], _T("del")))
1282 {
1283 }
1284#endif
1285 }
1286 else if (!_tcsicmp(argv[1], _T("--version")))
1287 {
1288 _tprintf(_T("%d.%d.%d.%d\n"), VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV);
1289 rc = EXIT_OK;
1290 }
1291 else if ( !_tcsicmp(argv[1], _T("--help"))
1292 || !_tcsicmp(argv[1], _T("/help"))
1293 || !_tcsicmp(argv[1], _T("/h"))
1294 || !_tcsicmp(argv[1], _T("/?")))
1295 {
1296 PrintHelp();
1297 rc = EXIT_OK;
1298 }
1299 }
1300
1301 if (rc == EXIT_USAGE)
1302 _tprintf(_T("No or wrong parameters given! Please consult the help (\"--help\" or \"/?\") for more information.\n"));
1303
1304 return rc;
1305}
1306
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