Changeset 96422 in vbox for trunk/src/VBox/Additions/WINNT/Installer
- Timestamp:
- Aug 23, 2022 2:36:00 AM (2 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/WINNT/Installer/VBoxDrvInst.cpp
r96407 r96422 34 34 #endif 35 35 36 #include <iprt/ cdefs.h>36 #include <iprt/alloca.h> 37 37 #include <VBox/version.h> 38 38 39 39 #include <iprt/win/windows.h> 40 40 #include <iprt/win/setupapi.h> 41 #include <stdio.h> 42 #include <tchar.h> 41 42 #include <iprt/asm.h> 43 #include <iprt/mem.h> 44 #include <iprt/path.h> /* RTPATH_IS_SEP */ 45 #include <iprt/string.h> 46 #include <iprt/utf16.h> 43 47 44 48 … … 46 50 * Defines * 47 51 *********************************************************************************************************************************/ 48 49 52 /* Exit codes */ 50 53 #define EXIT_OK (0) … … 53 56 #define EXIT_USAGE (3) 54 57 55 /* Prototypes */56 typedef struct {57 PWSTR pApplicationId;58 PWSTR pDisplayName;59 PWSTR pProductName;60 PWSTR pMfgName;61 } INSTALLERINFO, *PINSTALLERINFO;62 typedef const PINSTALLERINFO PCINSTALLERINFO;63 64 typedef enum {65 DIFXAPI_SUCCESS,66 DIFXAPI_INFO,67 DIFXAPI_WARNING,68 DIFXAPI_ERROR69 } DIFXAPI_LOG;70 71 typedef void (WINAPI * DIFXLOGCALLBACK_W)( DIFXAPI_LOG Event, DWORD Error, PCWSTR EventDescription, PVOID CallbackContext);72 typedef void ( __cdecl* DIFXAPILOGCALLBACK_W)( DIFXAPI_LOG Event, DWORD Error, PCWSTR EventDescription, PVOID CallbackContext);73 74 typedef DWORD (WINAPI *fnDriverPackageInstall) (PCTSTR DriverPackageInfPath, DWORD Flags, PCINSTALLERINFO pInstallerInfo, BOOL *pNeedReboot);75 fnDriverPackageInstall g_pfnDriverPackageInstall = NULL;76 77 typedef DWORD (WINAPI *fnDriverPackageUninstall) (PCTSTR DriverPackageInfPath, DWORD Flags, PCINSTALLERINFO pInstallerInfo, BOOL *pNeedReboot);78 fnDriverPackageUninstall g_pfnDriverPackageUninstall = NULL;79 80 typedef VOID (WINAPI *fnDIFXAPISetLogCallback) (DIFXAPILOGCALLBACK_W LogCallback, PVOID CallbackContext);81 fnDIFXAPISetLogCallback g_pfnDIFXAPISetLogCallback = NULL;82 83 58 /* Defines */ 84 #define DRIVER_PACKAGE_REPAIR 0x0000000185 #define DRIVER_PACKAGE_SILENT 0x0000000286 #define DRIVER_PACKAGE_FORCE 0x0000000487 #define DRIVER_PACKAGE_ONLY_IF_DEVICE_PRESENT 0x0000000888 #define DRIVER_PACKAGE_LEGACY_MODE 0x0000001089 #define DRIVER_PACKAGE_DELETE_FILES 0x0000002059 #define DRIVER_PACKAGE_REPAIR 0x00000001 60 #define DRIVER_PACKAGE_SILENT 0x00000002 61 #define DRIVER_PACKAGE_FORCE 0x00000004 62 #define DRIVER_PACKAGE_ONLY_IF_DEVICE_PRESENT 0x00000008 63 #define DRIVER_PACKAGE_LEGACY_MODE 0x00000010 64 #define DRIVER_PACKAGE_DELETE_FILES 0x00000020 90 65 91 66 /* DIFx error codes */ 92 67 /** @todo any reason why we're not using difxapi.h instead of these redefinitions? */ 93 68 #ifndef ERROR_DRIVER_STORE_ADD_FAILED 94 # define ERROR_DRIVER_STORE_ADD_FAILED \ 95 (APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x0247L) 69 # define ERROR_DRIVER_STORE_ADD_FAILED (APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x0247L) 96 70 #endif 97 #define ERROR_DEPENDENT_APPLICATIONS_EXIST \ 98 (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x300) 99 #define ERROR_DRIVER_PACKAGE_NOT_IN_STORE \ 100 (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x302) 71 #define ERROR_DEPENDENT_APPLICATIONS_EXIST (APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR|0x300) 72 #define ERROR_DRIVER_PACKAGE_NOT_IN_STORE (APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x302) 101 73 102 74 /* Registry string list flags */ 103 #define VBOX_REG_STRINGLIST_NONE 0x00000000 /*No flags set. */104 #define VBOX_REG_STRINGLIST_ALLOW_DUPLICATES 0x00000001 /*Allows duplicates in list when adding a value. */75 #define VBOX_REG_STRINGLIST_NONE 0x00000000 /**< No flags set. */ 76 #define VBOX_REG_STRINGLIST_ALLOW_DUPLICATES 0x00000001 /**< Allows duplicates in list when adding a value. */ 105 77 106 78 #ifdef DEBUG … … 108 80 #endif 109 81 110 /** @todo Get rid of all that TCHAR crap! Use WCHAR wherever possible. */ 111 112 bool GetErrorMsg(DWORD dwLastError, _TCHAR *pszMsg, DWORD dwBufSize) 113 { 114 if (::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwLastError, 0, pszMsg, dwBufSize / sizeof(TCHAR), NULL) == 0) 115 { 116 _sntprintf(pszMsg, dwBufSize / sizeof(TCHAR), _T("Unknown error!\n")); 82 83 /********************************************************************************************************************************* 84 * Structures and Typedefs * 85 *********************************************************************************************************************************/ 86 typedef struct 87 { 88 PWSTR pApplicationId; 89 PWSTR pDisplayName; 90 PWSTR pProductName; 91 PWSTR pMfgName; 92 } INSTALLERINFO, *PINSTALLERINFO; 93 typedef const PINSTALLERINFO PCINSTALLERINFO; 94 95 typedef enum 96 { 97 DIFXAPI_SUCCESS, 98 DIFXAPI_INFO, 99 DIFXAPI_WARNING, 100 DIFXAPI_ERROR 101 } DIFXAPI_LOG; 102 103 typedef void (__cdecl * DIFXAPILOGCALLBACK_W)(DIFXAPI_LOG Event, DWORD Error, PCWSTR EventDescription, PVOID CallbackContext); 104 105 typedef DWORD (WINAPI *fnDriverPackageInstall)(PCTSTR DriverPackageInfPath, DWORD Flags, PCINSTALLERINFO pInstallerInfo, BOOL *pNeedReboot); 106 fnDriverPackageInstall g_pfnDriverPackageInstall = NULL; 107 108 typedef DWORD (WINAPI *fnDriverPackageUninstall)(PCTSTR DriverPackageInfPath, DWORD Flags, PCINSTALLERINFO pInstallerInfo, BOOL *pNeedReboot); 109 fnDriverPackageUninstall g_pfnDriverPackageUninstall = NULL; 110 111 typedef VOID (WINAPI *fnDIFXAPISetLogCallback)(DIFXAPILOGCALLBACK_W LogCallback, PVOID CallbackContext); 112 fnDIFXAPISetLogCallback g_pfnDIFXAPISetLogCallback = NULL; 113 114 115 /** @name Output helpers 116 * 117 * The general ASSUMPTION here is that all strings are restricted to 7-bit 118 * ASCII, with the exception of wchar_t ones. 119 * 120 * @note We don't use printf, RTPrintf or similar not for masochistic reasons 121 * but to keep the binary small and make it easier to switch between CRT 122 * and IPRT w/ no-CRT. 123 * 124 * @{ 125 */ 126 127 static void OutputWStr(HANDLE hDst, const wchar_t *pwszStr) 128 { 129 DWORD cbIgn; 130 if (GetConsoleMode(hDst, &cbIgn)) 131 WriteConsoleW(hDst, pwszStr, (DWORD)RTUtf16Len(pwszStr), &cbIgn, NULL); 132 else 133 { 134 char *pszTmp; 135 int rc = RTUtf16ToUtf8(pwszStr, &pszTmp); 136 if (RT_SUCCESS(rc)) 137 { 138 char *pszInCodepage; 139 rc = RTStrUtf8ToCurrentCP(&pszInCodepage, pszTmp); 140 if (RT_SUCCESS(rc)) 141 { 142 WriteFile(hDst, pszInCodepage, (DWORD)strlen(pszInCodepage), &cbIgn, NULL); 143 RTStrFree(pszInCodepage); 144 } 145 else 146 WriteFile(hDst, RT_STR_TUPLE("<RTStrUtf8ToCurrentCP error>"), &cbIgn, NULL); 147 RTStrFree(pszTmp); 148 } 149 else 150 WriteFile(hDst, RT_STR_TUPLE("<RTUtf16ToUtf8 error>"), &cbIgn, NULL); 151 } 152 } 153 154 155 static void ErrorMsgBegin(const char *pszMsg) 156 { 157 HANDLE const hStdErr = GetStdHandle(STD_ERROR_HANDLE); 158 DWORD cbIgn; 159 WriteFile(hStdErr, RT_STR_TUPLE("error: "), &cbIgn, NULL); 160 WriteFile(hStdErr, pszMsg, (DWORD)strlen(pszMsg), &cbIgn, NULL); 161 } 162 163 164 static void ErrorMsgStr(const char *pszMsg) 165 { 166 HANDLE const hStdErr = GetStdHandle(STD_ERROR_HANDLE); 167 DWORD cbIgn; 168 WriteFile(hStdErr, pszMsg, (DWORD)strlen(pszMsg), &cbIgn, NULL); 169 } 170 171 172 static void ErrorMsgWStr(const wchar_t *pwszStr) 173 { 174 OutputWStr(GetStdHandle(STD_ERROR_HANDLE), pwszStr); 175 } 176 177 178 static int ErrorMsgEnd(const char *pszMsg) 179 { 180 HANDLE const hStdErr = GetStdHandle(STD_ERROR_HANDLE); 181 DWORD cbIgn; 182 if (pszMsg) 183 WriteFile(hStdErr, pszMsg, (DWORD)strlen(pszMsg), &cbIgn, NULL); 184 WriteFile(hStdErr, RT_STR_TUPLE("\r\n"), &cbIgn, NULL); 185 return EXIT_FAIL; 186 } 187 188 189 static void ErrorMsgU64(uint64_t uValue, bool fSigned = false) 190 { 191 char szVal[128]; 192 RTStrFormatU64(szVal, sizeof(szVal), uValue, 10, 0, 0, fSigned ? RTSTR_F_VALSIGNED : 0); 193 ErrorMsgStr(szVal); 194 } 195 196 197 static int ErrorMsg(const char *pszMsg) 198 { 199 ErrorMsgBegin(pszMsg); 200 return ErrorMsgEnd(NULL); 201 } 202 203 204 static int ErrorMsgSWS(const char *pszMsg1, const wchar_t *pwszMsg2, const char *pszMsg3) 205 { 206 ErrorMsgBegin(pszMsg1); 207 ErrorMsgWStr(pwszMsg2); 208 return ErrorMsgEnd(pszMsg3); 209 } 210 211 212 static int ErrorMsgSWSWS(const char *pszMsg1, const wchar_t *pwszMsg2, const char *pszMsg3, 213 const wchar_t *pwszMsg4, const char *pszMsg5) 214 { 215 ErrorMsgBegin(pszMsg1); 216 ErrorMsgWStr(pwszMsg2); 217 ErrorMsgStr(pszMsg3); 218 ErrorMsgWStr(pwszMsg4); 219 return ErrorMsgEnd(pszMsg5); 220 } 221 222 223 static void ErrorMsgErrVal(uint32_t uErrVal, bool fSigned) 224 { 225 char szVal[128]; 226 ssize_t cchVal = RTStrFormatU32(szVal, sizeof(szVal) - 1, uErrVal, 10, 0, 0, fSigned ? RTSTR_F_VALSIGNED : 0); 227 szVal[cchVal++] = '/'; 228 szVal[cchVal] = '\0'; 229 ErrorMsgStr(szVal); 230 231 RTStrFormatU32(szVal, sizeof(szVal) - 1, uErrVal, 16, 0, 0, RTSTR_F_SPECIAL); 232 ErrorMsgStr(szVal); 233 } 234 235 236 static int ErrorMsgErr(const char *pszMsg, uint32_t uErrVal, const char *pszErrIntro, bool fSigned) 237 { 238 ErrorMsgBegin(pszMsg); 239 ErrorMsgStr(pszErrIntro); 240 ErrorMsgErrVal(uErrVal, fSigned); 241 return ErrorMsgEnd(")"); 242 } 243 244 245 static int ErrorMsgVBoxErr(const char *pszMsg, int rc) 246 { 247 return ErrorMsgErr(pszMsg, rc, " (", true); 248 } 249 250 251 static int ErrorMsgLastErr(const char *pszMsg) 252 { 253 return ErrorMsgErr(pszMsg, GetLastError(), " (last error ", false); 254 } 255 256 257 static int ErrorMsgLastErrSWS(const char *pszMsg1, const wchar_t *pwszMsg2, const char *pszMsg3) 258 { 259 DWORD dwErr = GetLastError(); 260 ErrorMsgBegin(pszMsg1); 261 ErrorMsgWStr(pwszMsg2); 262 ErrorMsgStr(pszMsg3); 263 ErrorMsgStr(" (last error "); 264 ErrorMsgErrVal(dwErr, false); 265 return ErrorMsgEnd(")"); 266 } 267 268 static int ErrorMsgLastErrSWSWS(const char *pszMsg1, const wchar_t *pwszMsg2, const char *pszMsg3, 269 const wchar_t *pwszMsg4, const char *pszMsg5) 270 { 271 DWORD dwErr = GetLastError(); 272 ErrorMsgBegin(pszMsg1); 273 ErrorMsgWStr(pwszMsg2); 274 ErrorMsgStr(pszMsg3); 275 ErrorMsgWStr(pwszMsg4); 276 ErrorMsgStr(pszMsg5); 277 ErrorMsgStr(" (last error "); 278 ErrorMsgErrVal(dwErr, false); 279 return ErrorMsgEnd(")"); 280 } 281 282 283 static int ErrorMsgLastErrSWSRSUS(const char *pszMsg1, const wchar_t *pwszMsg2, const char *pszMsg3, const char *pszMsg4, 284 uint64_t uValue, const char *pszMsg5) 285 { 286 DWORD dwErr = GetLastError(); 287 ErrorMsgBegin(pszMsg1); 288 ErrorMsgWStr(pwszMsg2); 289 ErrorMsgStr(pszMsg3); 290 ErrorMsgStr(" (last error "); 291 ErrorMsgErrVal(dwErr, false); 292 ErrorMsgStr(")"); 293 ErrorMsgStr(pszMsg4); 294 ErrorMsgU64(uValue); 295 return ErrorMsgEnd(pszMsg5); 296 } 297 298 299 static int ErrorMsgLastErrSSS(const char *pszMsg1, const char *pszMsg2, const char *pszMsg3) 300 { 301 DWORD dwErr = GetLastError(); 302 ErrorMsgBegin(pszMsg1); 303 ErrorMsgStr(pszMsg2); 304 ErrorMsgStr(pszMsg3); 305 ErrorMsgStr(" (last error "); 306 ErrorMsgErrVal(dwErr, false); 307 return ErrorMsgEnd(")"); 308 } 309 310 311 static int ErrorMsgLStatus(const char *pszMsg, LSTATUS lrc) 312 { 313 return ErrorMsgErr(pszMsg, (DWORD)lrc, " (", true); 314 } 315 316 317 static int ErrorMsgLStatusSWSRS(const char *pszMsg1, const wchar_t *pwszMsg2, const char *pszMsg3, 318 LSTATUS lrc, const char *pszMsg4) 319 { 320 ErrorMsgBegin(pszMsg1); 321 ErrorMsgWStr(pwszMsg2); 322 ErrorMsgStr(pszMsg3); 323 ErrorMsgErrVal((DWORD)lrc, true); 324 return ErrorMsgEnd(pszMsg4); 325 } 326 327 328 static int ErrorMsgLStatusSWSWSRS(const char *pszMsg1, const wchar_t *pwszMsg2, const char *pszMsg3, const wchar_t *pwszMsg4, 329 const char *pszMsg5, LSTATUS lrc, const char *pszMsg6) 330 { 331 ErrorMsgBegin(pszMsg1); 332 ErrorMsgWStr(pwszMsg2); 333 ErrorMsgStr(pszMsg3); 334 ErrorMsgWStr(pwszMsg4); 335 ErrorMsgStr(pszMsg5); 336 ErrorMsgErrVal((DWORD)lrc, true); 337 return ErrorMsgEnd(pszMsg6); 338 } 339 340 341 static int ErrorMsgLStatusSWSWSWSRS(const char *pszMsg1, const wchar_t *pwszMsg2, const char *pszMsg3, const wchar_t *pwszMsg4, 342 const char *pszMsg5, const wchar_t *pwszMsg6, const char *pszMsg7, 343 LSTATUS lrc, const char *pszMsg8) 344 { 345 ErrorMsgBegin(pszMsg1); 346 ErrorMsgWStr(pwszMsg2); 347 ErrorMsgStr(pszMsg3); 348 ErrorMsgWStr(pwszMsg4); 349 ErrorMsgStr(pszMsg5); 350 ErrorMsgWStr(pwszMsg6); 351 ErrorMsgStr(pszMsg7); 352 ErrorMsgErrVal((DWORD)lrc, true); 353 return ErrorMsgEnd(pszMsg8); 354 } 355 356 357 static int ErrorBadArg(const char *pszName, wchar_t const *pwszArg, const char *pszValues = NULL) 358 { 359 ErrorMsgBegin("Bad argument '"); 360 ErrorMsgStr(pszName); 361 ErrorMsgStr("': "); 362 ErrorMsgWStr(pwszArg); 363 if (pszValues) 364 ErrorMsgStr(", expected: "); 365 return ErrorMsgEnd(pszValues); 366 } 367 368 369 /** Simple fputs(stdout) replacement. */ 370 static void PrintStr(const char *pszMsg) 371 { 372 HANDLE const hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); 373 DWORD cbIgn; 374 WriteFile(hStdOut, pszMsg, (DWORD)strlen(pszMsg), &cbIgn, NULL); 375 } 376 377 378 /** Simple fputs(stdout) replacement. */ 379 static void PrintWStr(const wchar_t *pwszStr) 380 { 381 OutputWStr(GetStdHandle(STD_OUTPUT_HANDLE), pwszStr); 382 } 383 384 385 static void PrintX64(uint64_t uValue) 386 { 387 char szVal[128]; 388 RTStrFormatU64(szVal, sizeof(szVal), uValue, 16, 0, 0, RTSTR_F_64BIT | RTSTR_F_SPECIAL); 389 PrintStr(szVal); 390 } 391 392 393 static void PrintSWS(const char *pszMsg1, const wchar_t *pwszMsg2, const char *pszMsg3) 394 { 395 PrintStr(pszMsg1); 396 PrintWStr(pwszMsg2); 397 PrintStr(pszMsg3); 398 } 399 400 401 static void PrintSWSWS(const char *pszMsg1, const wchar_t *pwszMsg2, const char *pszMsg3, 402 const wchar_t *pwszMsg4, const char *pszMsg5) 403 { 404 PrintStr(pszMsg1); 405 PrintWStr(pwszMsg2); 406 PrintStr(pszMsg3); 407 PrintWStr(pwszMsg4); 408 PrintStr(pszMsg5); 409 } 410 411 412 static void PrintSWSWSWS(const char *pszMsg1, const wchar_t *pwszMsg2, const char *pszMsg3, const wchar_t *pwszMsg4, 413 const char *pszMsg5, const wchar_t *pwszMsg6, const char *pszMsg7) 414 { 415 PrintStr(pszMsg1); 416 PrintWStr(pwszMsg2); 417 PrintStr(pszMsg3); 418 PrintWStr(pwszMsg4); 419 PrintStr(pszMsg5); 420 PrintWStr(pwszMsg6); 421 PrintStr(pszMsg7); 422 } 423 424 425 static void PrintSXS(const char *pszMsg1, uint64_t uValue, const char *pszMsg2) 426 { 427 PrintStr(pszMsg1); 428 PrintX64(uValue); 429 PrintStr(pszMsg2); 430 } 431 432 433 static void PrintSWSWSWSXS(const char *pszMsg1, const wchar_t *pwszMsg2, const char *pszMsg3, const wchar_t *pwszMsg4, 434 const char *pszMsg5, const wchar_t *pwszMsg6, const char *pszMsg7, uint64_t uValue, const char *pszMsg8) 435 { 436 PrintStr(pszMsg1); 437 PrintWStr(pwszMsg2); 438 PrintStr(pszMsg3); 439 PrintWStr(pwszMsg4); 440 PrintStr(pszMsg5); 441 PrintWStr(pwszMsg6); 442 PrintStr(pszMsg7); 443 PrintX64(uValue); 444 PrintStr(pszMsg8); 445 } 446 447 /** @} */ 448 449 static char *ArgToUtf8(wchar_t const *pwszString, const char *pszArgName) 450 { 451 char *pszUtf8 = NULL; 452 int rc = RTUtf16ToUtf8(pwszString, &pszUtf8); 453 if (RT_SUCCESS(rc)) 454 return pszUtf8; 455 ErrorMsgBegin("RTUtf16ToUtf8 failed on '"); 456 ErrorMsgStr(pszArgName); 457 ErrorMsgStr("': "); 458 ErrorMsgErrVal(rc, true); 459 ErrorMsgEnd(NULL); 460 return NULL; 461 } 462 463 /** 464 * @returns false. 465 * @note Frees pszValue 466 */ 467 static bool ErrorArtToNum(int rc, const char *pszArgName, char *pszValue) 468 { 469 ErrorMsgBegin("Failed to convert the '"); 470 ErrorMsgStr(pszArgName); 471 ErrorMsgStr("' value '"); 472 ErrorMsgStr(pszValue); 473 ErrorMsgStr("' to a number: "); 474 ErrorMsgErrVal(rc, true); 475 ErrorMsgEnd(NULL); 476 return false; 477 } 478 479 480 static bool ArgToUInt32Full(wchar_t const *pwszString, const char *pszArgName, uint32_t *puValue) 481 { 482 char *pszValue = ArgToUtf8(pwszString, pszArgName); 483 if (!pszValue) 117 484 return false; 118 }119 _TCHAR *p = _tcschr(pszMsg, _T('\r'));120 if (p != NULL)121 *p = _T('\0');485 int rc = RTStrToUInt32Full(pszValue, 0, puValue); 486 if (RT_FAILURE(rc)) 487 return ErrorArtToNum(rc, pszArgName, pszValue); 488 RTStrFree(pszValue); 122 489 return true; 123 490 } 491 492 493 static bool ArgToUInt64Full(wchar_t const *pwszString, const char *pszArgName, uint64_t *puValue) 494 { 495 char *pszValue = ArgToUtf8(pwszString, pszArgName); 496 if (!pszValue) 497 return false; 498 int rc = RTStrToUInt64Full(pszValue, 0, puValue); 499 if (rc != VINF_SUCCESS) 500 return ErrorArtToNum(rc, pszArgName, pszValue); 501 RTStrFree(pszValue); 502 return true; 503 } 504 505 506 507 static bool GetErrorMsg(DWORD dwLastError, wchar_t *pwszMsg, DWORD cwcMsg) 508 { 509 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwLastError, 0, pwszMsg, cwcMsg, NULL) == 0) 510 return false; 511 wchar_t *pwc = RTUtf16Chr(pwszMsg, '\r'); 512 if (pwc) 513 *pwc = '\0'; 514 return true; 515 } 516 124 517 125 518 /** 126 519 * Log callback for DIFxAPI calls. 127 520 * 128 * @param Event The event's structure to log.129 * @param dwError The event's error level.130 * @param p EventDescription The event's text description.131 * @param p CallbackContext User-supplied callback context.521 * @param enmEvent Event logging level. 522 * @param dwError Event error number. 523 * @param pwszEventDesc Event description text. 524 * @param pvCtx Log file handle, if we've got one. 132 525 */ 133 void LogCallback(DIFXAPI_LOG Event, DWORD dwError, PCWSTR pEventDescription, PVOID pCallbackContext) 134 { 526 static void __cdecl VBoxDIFxLogCallback(DIFXAPI_LOG enmEvent, DWORD dwError, PCWSTR pwszEventDesc, PVOID pvCtx) 527 { 528 const char *pszEvent; 529 switch (enmEvent) 530 { 531 case DIFXAPI_SUCCESS: pszEvent = "DIFXAPI_SUCCESS"; break; 532 case DIFXAPI_INFO: pszEvent = "DIFXAPI_INFO"; break; 533 case DIFXAPI_WARNING: pszEvent = "DIFXAPI_WARNING"; break; 534 case DIFXAPI_ERROR: pszEvent = "DIFXAPI_ERROR"; break; 535 default: pszEvent = "DIFXAPI_<unknown>"; break; 536 } 537 538 /* 539 * Log to standard output: 540 */ 541 PrintStr(pszEvent); 135 542 if (dwError == 0) 136 _tprintf(_T("(%u) %ws\n"), Event, pEventDescription);543 PrintStr(": "); 137 544 else 138 _tprintf(_T("(%u) ERROR: %lu - %ws\n"), Event, dwError, pEventDescription); 139 140 if (pCallbackContext) 141 fwprintf((FILE*)pCallbackContext, _T("(%u) %lu - %s\n"), Event, dwError, pEventDescription); 142 } 545 { 546 PrintStr(": ERROR: "); 547 PrintX64(dwError); 548 PrintStr(" - "); 549 } 550 PrintWStr(pwszEventDesc); 551 PrintStr("\r\n"); 552 553 /* 554 * Write to the log file if we have one (wide char format). 555 */ 556 HANDLE const hLogFile = (HANDLE)pvCtx; 557 if (hLogFile != INVALID_HANDLE_VALUE) 558 { 559 /* "event: err - desc\r\n" */ 560 wchar_t wszBuf[168]; 561 RTUtf16CopyAscii(wszBuf, RT_ELEMENTS(wszBuf), pszEvent); 562 RTUtf16CatAscii(wszBuf, RT_ELEMENTS(wszBuf), ": "); 563 char szVal[128]; 564 RTStrFormatU32(szVal, sizeof(szVal), dwError, 10, 0, 0, 0); 565 RTUtf16CatAscii(wszBuf, RT_ELEMENTS(wszBuf), szVal); 566 RTUtf16CatAscii(wszBuf, RT_ELEMENTS(wszBuf), " - "); 567 568 DWORD dwIgn; 569 WriteFile(hLogFile, wszBuf, (DWORD)(RTUtf16Len(wszBuf) * sizeof(wchar_t)), &dwIgn, NULL); 570 WriteFile(hLogFile, pwszEventDesc, (DWORD)(RTUtf16Len(pwszEventDesc) * sizeof(wchar_t)), &dwIgn, NULL); 571 WriteFile(hLogFile, L"\r\n", 2 * sizeof(wchar_t), &dwIgn, NULL); 572 } 573 } 574 143 575 144 576 /** 145 * Loads a system DLL.577 * Loads a DLL from the same directory as the installer. 146 578 * 147 * @returns Module handle or NULL579 * @returns Module handle, NULL on failure (fully messaged). 148 580 * @param pwszName The DLL name. 149 581 */ 150 static HMODULE loadInstalledDll(const wchar_t *pwszName)582 static HMODULE LoadAppDll(const wchar_t *pwszName) 151 583 { 152 584 /* Get the process image path. */ … … 154 586 UINT cwcPath = GetModuleFileNameW(NULL, wszPath, MAX_PATH); 155 587 if (!cwcPath || cwcPath >= MAX_PATH) 588 { 589 ErrorMsgLastErr("LoadAppDll: GetModuleFileNameW failed"); 156 590 return NULL; 591 } 157 592 158 593 /* Drop the image filename. */ 159 UINT off = cwcPath - 1; 160 for (;;) 161 { 162 if ( wszPath[off] == '\\' 163 || wszPath[off] == '/' 164 || wszPath[off] == ':') 594 do 595 { 596 cwcPath--; 597 if (RTPATH_IS_SEP(wszPath[cwcPath])) 165 598 { 166 wszPath[off] = '\0';167 cwcPath = off;599 cwcPath++; 600 wszPath[cwcPath] = '\0'; 168 601 break; 169 602 } 170 if (!off--) 171 return NULL; /* No path? Shouldn't ever happen! */ 172 } 173 174 /* Check if there is room in the buffer to construct the desired name. */ 175 size_t cwcName = 0; 176 while (pwszName[cwcName]) 177 cwcName++; 178 if (cwcPath + 1 + cwcName + 1 > MAX_PATH) 603 } while (cwcPath > 0); 604 605 if (!cwcPath) /* This should be impossible */ 606 { 607 ErrorMsg("LoadAppDll: GetModuleFileNameW returned no path!"); 179 608 return NULL; 180 181 wszPath[cwcPath] = '\\'; 182 memcpy(&wszPath[cwcPath + 1], pwszName, (cwcName + 1) * sizeof(wszPath[0])); 183 return LoadLibraryW(wszPath); 184 } 609 } 610 611 /* Append the dll name if we can. */ 612 size_t const cwcName = RTUtf16Len(pwszName); 613 if (cwcPath + cwcName >= RT_ELEMENTS(wszPath)) 614 { 615 ErrorMsgSWSWS("LoadAppDll: Path '", wszPath, "' too long when adding '", pwszName, "'"); 616 return NULL; 617 } 618 memcpy(&wszPath[cwcPath], pwszName, (cwcName + 1) * sizeof(wszPath[0])); 619 620 /* Try load the module. We will try restrict the library search to the 621 system32 directory if supported by the OS. Older OSes doesn't support 622 this, so we fall back on full search in that case. */ 623 HMODULE hMod = LoadLibraryExW(wszPath, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); 624 if (hMod == NULL && GetLastError() == ERROR_INVALID_PARAMETER) 625 hMod = LoadLibraryExW(wszPath, NULL, 0); 626 if (!hMod) 627 ErrorMsgLastErrSWS("LoadAppDll: LoadLibraryExW failed on '", wszPath, "'"); 628 return hMod; 629 } 630 185 631 186 632 /** 187 * (Un)Installs a driver from/to the system.633 * Installs or uninstalls a driver. 188 634 * 189 635 * @return Exit code (EXIT_OK, EXIT_FAIL) 190 * @param fInstall Flag indicating whether to install (TRUE) or uninstall (FALSE) a driver. 191 * @param pszDriverPath Pointer to full qualified path to the driver's .INF file (+ driver files). 192 * @param fSilent Flag indicating a silent installation (TRUE) or not (FALSE). 193 * @param pszLogFile Pointer to full qualified path to log file to be written during installation. 194 * Optional. 636 * @param fInstall Set to @c true for installation, and @c false 637 * for uninstallation. 638 * @param pwszDriverPath Path to the driver's .INF file. 639 * @param fSilent Set to @c true for silent installation. 640 * @param pwszLogFile Pointer to full qualified path to log file to be 641 * written during installation. Optional. 195 642 */ 196 int VBoxInstallDriver(const BOOL fInstall, const _TCHAR *pszDriverPath, BOOL fSilent, 197 const _TCHAR *pszLogFile) 198 { 199 HRESULT hr = S_OK; 200 HMODULE hDIFxAPI = loadInstalledDll(L"DIFxAPI.dll"); 201 if (NULL == hDIFxAPI) 202 { 203 _tprintf(_T("ERROR: Unable to locate DIFxAPI.dll!\n")); 204 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); 205 } 643 static int VBoxInstallDriver(const BOOL fInstall, const wchar_t *pwszDriverPath, bool fSilent, const wchar_t *pwszLogFile) 644 { 645 /* 646 * Windows 2000 and later. 647 */ 648 OSVERSIONINFO VerInfo = { sizeof(VerInfo) }; 649 GetVersionEx(&VerInfo); 650 if (VerInfo.dwPlatformId != VER_PLATFORM_WIN32_NT) 651 return ErrorMsg("Platform not supported for driver (un)installation!"); 652 if (VerInfo.dwMajorVersion < 5) 653 return ErrorMsg("Platform too old to be supported for driver (un)installation!"); 654 655 /* 656 * Get the full path to the INF file. 657 */ 658 wchar_t wszFullDriverInf[MAX_PATH]; 659 if (GetFullPathNameW(pwszDriverPath, MAX_PATH, wszFullDriverInf, NULL) ==0 ) 660 return ErrorMsgLastErrSWS("GetFullPathNameW failed on '", pwszDriverPath, "'"); 661 662 /* 663 * Load DIFxAPI.dll from our application directory and resolve the symbols we need 664 * from it. We always resolve all for reasons of simplicity and general paranoia. 665 */ 666 HMODULE hModDifXApi = LoadAppDll(L"DIFxAPI.dll"); 667 if (!hModDifXApi) 668 return EXIT_FAIL; 669 670 static struct { FARPROC *ppfn; const char *pszName; } const s_aFunctions[] = 671 { 672 { (FARPROC *)&g_pfnDriverPackageInstall, "DriverPackageInstallW" }, 673 { (FARPROC *)&g_pfnDriverPackageUninstall, "DriverPackageUninstallW" }, 674 { (FARPROC *)&g_pfnDIFXAPISetLogCallback, "DIFXAPISetLogCallbackW" }, 675 }; 676 for (size_t i = 0; i < RT_ELEMENTS(s_aFunctions); i++) 677 { 678 FARPROC pfn = *s_aFunctions[i].ppfn = GetProcAddress(hModDifXApi, s_aFunctions[i].pszName); 679 if (!pfn) 680 return ErrorMsgLastErrSSS("Failed to find symbol '", s_aFunctions[i].pszName, "' in DIFxAPI.dll"); 681 } 682 683 /* 684 * Try open the log file and register a logger callback with DIFx. 685 * Failures here are non-fatal. 686 */ 687 HANDLE hLogFile = INVALID_HANDLE_VALUE; 688 if (pwszLogFile) 689 { 690 hLogFile = CreateFileW(pwszLogFile, FILE_GENERIC_WRITE & ~FILE_WRITE_DATA /* append mode */, FILE_SHARE_READ, 691 NULL /*pSecAttr*/, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL /*hTemplateFile*/); 692 if (hLogFile == INVALID_HANDLE_VALUE) 693 ErrorMsgLastErrSWS("Failed to open/create log file '", pwszLogFile, "'"); 694 g_pfnDIFXAPISetLogCallback(VBoxDIFxLogCallback, (void *)hLogFile); 695 } 696 697 PrintStr(fInstall ? "Installing driver ...\r\n" : "Uninstalling driver ...\r\n"); 698 PrintSWS("INF-File: '", wszFullDriverInf, "'\r\n"); 699 700 INSTALLERINFO InstInfo = 701 { 702 L"{7d2c708d-c202-40ab-b3e8-de21da1dc629}", /* Our GUID for representing this installation tool. */ 703 L"VirtualBox Guest Additions Install Helper", 704 L"VirtualBox Guest Additions", /** @todo Add version! */ 705 L"Oracle Corporation" 706 }; 707 708 /* Flags */ 709 DWORD dwFlags = DRIVER_PACKAGE_FORCE; 710 if (!fInstall) 711 dwFlags |= DRIVER_PACKAGE_DELETE_FILES; 712 if (VerInfo.dwMajorVersion < 6 && fInstall) 713 { 714 PrintStr("Using legacy mode for install ...\r\n"); 715 dwFlags |= DRIVER_PACKAGE_LEGACY_MODE; 716 } 717 if (fSilent) 718 { 719 /* Don't add DRIVER_PACKAGE_SILENT to dwFlags here, otherwise the 720 installation will fail because we don't have WHQL certified drivers. 721 See CERT_E_WRONG_USAGE on MSDN for more information. */ 722 PrintStr("Installation is silent ...\r\n"); 723 } 724 725 /* Do the install/uninstall: */ 726 BOOL fReboot = FALSE; 727 DWORD dwErr; 728 if (fInstall) 729 dwErr = g_pfnDriverPackageInstall(wszFullDriverInf, dwFlags, &InstInfo, &fReboot); 206 730 else 207 { 208 if (fInstall) 731 dwErr = g_pfnDriverPackageUninstall(wszFullDriverInf, dwFlags, &InstInfo, &fReboot); 732 733 /* 734 * Report error 735 */ 736 int rcExit = EXIT_FAIL; 737 const char *psz = NULL; 738 switch (dwErr) 739 { 740 case ERROR_SUCCESS: 741 rcExit = EXIT_OK; 742 break; 743 744 case CRYPT_E_FILE_ERROR: 745 psz = "The catalog file for the specified driver package was not found!"; 746 break; 747 case ERROR_ACCESS_DENIED: 748 psz = fInstall ? "Caller is not in Administrators group to install this driver package!" 749 : "Caller is not in Administrators group to uninstall this driver package!"; 750 break; 751 case ERROR_BAD_ENVIRONMENT: 752 psz = "The current Microsoft Windows version does not support this operation!"; 753 break; 754 case ERROR_CANT_ACCESS_FILE: 755 psz = "The driver package files could not be accessed!"; 756 break; 757 case ERROR_DEPENDENT_APPLICATIONS_EXIST: 758 psz = "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!"; 759 break; 760 case ERROR_DRIVER_PACKAGE_NOT_IN_STORE: 761 psz = fInstall ? "There is no INF file in the DIFx driver store that corresponds to the INF file being installed!" 762 : "There is no INF file in the DIFx driver store that corresponds to the INF file being uninstalled!"; 763 break; 764 case ERROR_FILE_NOT_FOUND: 765 psz = "INF-file not found!"; 766 break; 767 case ERROR_IN_WOW64: 768 psz = "The calling application is a 32-bit application attempting to execute in a 64-bit environment, which is not allowed!"; 769 break; 770 case ERROR_INVALID_FLAGS: 771 psz = "The flags specified are invalid!"; 772 break; 773 case ERROR_INSTALL_FAILURE: 774 psz = fInstall ? "The install operation failed! Consult the Setup API logs for more information." 775 : "The uninstall operation failed! Consult the Setup API logs for more information."; 776 break; 777 case ERROR_NO_MORE_ITEMS: 778 psz = "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!"; 779 break; 780 case ERROR_NO_DRIVER_SELECTED: 781 psz = "No driver in .INF-file selected!"; 782 break; 783 case ERROR_SECTION_NOT_FOUND: 784 psz = "Section in .INF-file was not found!"; 785 break; 786 case ERROR_SHARING_VIOLATION: 787 psz = "A component of the driver package in the DIFx driver store is locked by a thread or process!"; 788 break; 789 790 /* 791 * ! sig: Verifying file against specific Authenticode(tm) catalog failed! (0x800b0109) 792 * ! sig: Error 0x800b0109: A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider. 793 * !!! sto: No error message will be displayed as client is running in non-interactive mode. 794 * !!! ndv: Driver package failed signature validation. Error = 0xE0000247 795 */ 796 case ERROR_DRIVER_STORE_ADD_FAILED: 797 psz = "Adding driver to the driver store failed!!"; 798 break; 799 case ERROR_UNSUPPORTED_TYPE: 800 psz = "The driver package type is not supported of INF-file!"; 801 break; 802 case ERROR_NO_SUCH_DEVINST: 803 psz = "The driver package was installed but no matching devices found in the device tree (ERROR_NO_SUCH_DEVINST)."; 804 /* GA installer should ignore this error code and continue */ 805 rcExit = EXIT_OK; 806 break; 807 808 default: 209 809 { 210 g_pfnDriverPackageInstall = (fnDriverPackageInstall)GetProcAddress(hDIFxAPI, "DriverPackageInstallW"); 211 if (g_pfnDriverPackageInstall == NULL) 810 /* Try error lookup with GetErrorMsg(). */ 811 ErrorMsgSWS(fInstall ? "Installation of '" : "Uninstallation of '", wszFullDriverInf, "' failed!"); 812 ErrorMsgBegin("dwErr="); 813 ErrorMsgErrVal(dwErr, false); 814 WCHAR wszErrMsg[1024]; 815 if (GetErrorMsg(dwErr, wszErrMsg, RT_ELEMENTS(wszErrMsg))) 212 816 { 213 _tprintf(_T("ERROR: Unable to retrieve entry point for DriverPackageInstallW!\n"));214 hr = HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND);817 ErrorMsgStr(": "); 818 ErrorMsgWStr(wszErrMsg); 215 819 } 820 ErrorMsgEnd(NULL); 821 break; 822 } 823 } 824 if (psz) 825 { 826 ErrorMsgSWS(fInstall ? "Installation of '" : "Uninstallation of '", wszFullDriverInf, "' failed!"); 827 ErrorMsgBegin("dwErr="); 828 ErrorMsgErrVal(dwErr, false); 829 ErrorMsgStr(": "); 830 ErrorMsgEnd(psz); 831 } 832 833 /* Close the log file. */ 834 if (pwszLogFile) 835 { 836 g_pfnDIFXAPISetLogCallback(NULL, NULL); 837 if (hLogFile != INVALID_HANDLE_VALUE) 838 CloseHandle(hLogFile); 839 } 840 if (rcExit == EXIT_OK) 841 { 842 PrintStr(fInstall ? "Driver was installed successfully!\r\n" 843 : "Driver was uninstalled successfully!\r\n"); 844 if (fReboot) 845 { 846 PrintStr(fInstall ? "A reboot is needed to complete the driver installation!\r\n" 847 : "A reboot is needed to complete the driver uninstallation!\r\n"); 848 /** @todo r=bird: We don't set EXIT_REBOOT here for some reason... The 849 * ExecuteInf didn't use EXIT_REBOOT either untill the no-CRT rewrite, 850 * so perhaps the EXIT_REBOOT stuff can be removed? */ 851 } 852 } 853 854 return rcExit; 855 } 856 857 858 /** Handles 'driver install'. */ 859 static int handleDriverInstall(unsigned cArgs, wchar_t **papwszArgs) 860 { 861 return VBoxInstallDriver(true /*fInstall*/, papwszArgs[1], false /*fSilent*/, 862 cArgs > 1 && papwszArgs[1][0] ? papwszArgs[1] : NULL /* pwszLogFile*/); 863 } 864 865 866 /** Handles 'driver uninstall'. */ 867 static int handleDriverUninstall(unsigned cArgs, wchar_t **papwszArgs) 868 { 869 return VBoxInstallDriver(false /*fInstall*/, papwszArgs[1], false /*fSilent*/, 870 cArgs > 1 && papwszArgs[1][0] ? papwszArgs[1] : NULL /* pwszLogFile*/); 871 } 872 873 874 /** 875 * Implementes PSP_FILE_CALLBACK_W, used by ExecuteInfFile. 876 */ 877 static UINT CALLBACK 878 vboxDrvInstExecuteInfFileCallback(PVOID pvContext, UINT uNotification, UINT_PTR uParam1, UINT_PTR uParam2) RT_NOTHROW_DEF 879 { 880 #ifdef DEBUG 881 PrintSXS("Got installation notification ", uNotification, "\r\n"); 882 #endif 883 884 switch (uNotification) 885 { 886 case SPFILENOTIFY_NEEDMEDIA: 887 PrintStr("Requesting installation media ...\r\n"); 888 break; 889 890 case SPFILENOTIFY_STARTCOPY: 891 PrintStr("Copying driver files to destination ...\r\n"); 892 break; 893 894 case SPFILENOTIFY_TARGETNEWER: 895 case SPFILENOTIFY_TARGETEXISTS: 896 return TRUE; 897 } 898 899 return SetupDefaultQueueCallbackW(pvContext, uNotification, uParam1, uParam2); 900 } 901 902 903 /** 904 * Executes a specific .INF section to install/uninstall drivers and/or 905 * services. 906 * 907 * @return Exit code (EXIT_OK, EXIT_FAIL, EXIT_REBOOT) 908 * @param pwszSection Section to execute; usually it's L"DefaultInstall". 909 * @param pwszInf Path of the .INF file to use. 910 */ 911 static int ExecuteInfFile(const wchar_t *pwszSection, const wchar_t *pwszInf) 912 { 913 PrintSWSWS("Installing from INF-File: '", pwszInf, "', Section: '", pwszSection, "' ...\r\n"); 914 915 UINT uErrorLine = 0; 916 HINF hInf = SetupOpenInfFileW(pwszInf, NULL, INF_STYLE_WIN4, &uErrorLine); 917 if (hInf == INVALID_HANDLE_VALUE) 918 return ErrorMsgLastErrSWSRSUS("SetupOpenInfFileW failed to open '", pwszInf, "' ", ", error line ", uErrorLine, NULL); 919 920 int rcExit = EXIT_FAIL; 921 PVOID pvQueue = SetupInitDefaultQueueCallback(NULL); 922 if (pvQueue) 923 { 924 if (SetupInstallFromInfSectionW(NULL /*hWndOwner*/, hInf, pwszSection, SPINST_ALL, HKEY_LOCAL_MACHINE, 925 NULL /*pwszSrcRootPath*/, SP_COPY_NEWER_OR_SAME | SP_COPY_NOSKIP, 926 vboxDrvInstExecuteInfFileCallback, pvQueue, NULL /*hDevInfoSet*/, NULL /*pDevInfoData*/)) 927 { 928 PrintStr("File installation stage successful\r\n"); 929 930 if (SetupInstallServicesFromInfSectionW(hInf, L"DefaultInstall.Services", 0 /* Flags */)) 931 { 932 PrintStr("Service installation stage successful. Installation completed.\r\n"); 933 rcExit = EXIT_OK; 934 } 935 else if (GetLastError() == ERROR_SUCCESS_REBOOT_REQUIRED) 936 { 937 PrintStr("A reboot is required to complete the installation\r\n"); 938 rcExit = EXIT_REBOOT; 939 } 940 else 941 ErrorMsgLastErrSWSWS("SetupInstallServicesFromInfSectionW failed on '", pwszSection, "' in '", pwszInf, "'"); 942 } 943 SetupTermDefaultQueueCallback(pvQueue); 944 } 945 else 946 ErrorMsgLastErr("SetupInitDefaultQueueCallback failed"); 947 SetupCloseInfFile(hInf); 948 return rcExit; 949 } 950 951 952 /** Handles 'driver executeinf'. */ 953 static int handleDriverExecuteInf(unsigned cArgs, wchar_t **papwszArgs) 954 { 955 RT_NOREF(cArgs); 956 return ExecuteInfFile(L"DefaultInstall", papwszArgs[0]); 957 } 958 959 960 /** 961 * Checks if a string is a substring of another one. 962 * 963 * Used by the RegistryAddStringToMultiSZ & RegistryRemoveStringToMultiSZ 964 * routines. 965 */ 966 static bool IsSubStringOf(wchar_t volatile const *pwszStr, size_t cwcStr, wchar_t const *pwszSubStr, size_t cwcSubStr) 967 { 968 if (cwcStr >= cwcSubStr && cwcSubStr > 0) 969 { 970 wchar_t const wcFirst = *pwszSubStr; 971 cwcStr -= cwcSubStr; 972 do 973 { 974 /* Could've used wmemchr here, but it isn't implemented in noCRT yet. */ 975 if ( *pwszStr == wcFirst 976 && memcmp((void const *)pwszStr, pwszSubStr, cwcSubStr * sizeof(wchar_t)) == 0) 977 return true; 978 pwszStr++; 979 } while (cwcStr-- > 0); 980 } 981 return false; 982 } 983 984 985 /** 986 * Adds a string entry to a MULTI_SZ registry list. 987 * 988 * @return Exit code (EXIT_OK, EXIT_FAIL) 989 * @param pwszSubKey Sub key containing the list. 990 * @param pwszValueName The actual key name of the list. 991 * @param pwszItemToAdd The item to add to the list. 992 * @param uPosition Position (zero-based) of where to add the 993 * value to the list. 994 */ 995 static int RegistryAddStringToMultiSZ(const wchar_t *pwszSubKey, const wchar_t *pwszValueName, 996 const wchar_t *pwszItemToAdd, uint32_t uPosition) 997 { 998 size_t const cwcItemToAdd = RTUtf16Len(pwszItemToAdd); 999 size_t const cbItemToAdd = (cwcItemToAdd + 1) * sizeof(wchar_t); 1000 #ifdef DEBUG 1001 PrintSWSWSWSXS("AddStringToMultiSZ: Adding MULTI_SZ item '", pwszItemToAdd, 1002 "' to HKLM/'", pwszSubKey, "'/'", pwszValueName, "' at position ", uPosition, "\r\n"); 1003 #endif 1004 1005 /* 1006 * Open/create the key. 1007 */ 1008 HKEY hKey = NULL; 1009 DWORD dwDisp = 0; 1010 LSTATUS lrc = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pwszSubKey, 0 /*Reserved*/, NULL /*pClass*/, REG_OPTION_NON_VOLATILE, 1011 KEY_READ | KEY_WRITE, NULL /*pSecAttr*/, &hKey, &dwDisp); 1012 if (lrc != ERROR_SUCCESS) 1013 return ErrorMsgLStatusSWSRS("RegistryAddStringToList: RegCreateKeyEx HKLM/'", pwszSubKey, "' failed: ", lrc, NULL); 1014 1015 /* 1016 * Query the current value, first query just gets the buffer size the 2nd does the actual query. 1017 * We make sure the buffer is large enough to contain the new item we're supposed to add. 1018 */ 1019 int rcExit = EXIT_FAIL; 1020 PBYTE pbBuf = NULL; 1021 DWORD cbValue = 0; 1022 DWORD dwType = 0; 1023 lrc = RegQueryValueEx(hKey, pwszValueName, NULL, &dwType, NULL, &cbValue); 1024 if (lrc == ERROR_SUCCESS || lrc == ERROR_MORE_DATA) 1025 { 1026 cbValue = cbValue + _1K - sizeof(wchar_t)*2; /* 1KB of paranoia fudge, even if we ASSUME no races. */ 1027 pbBuf = (PBYTE)RTMemAllocZ(cbValue + sizeof(wchar_t)*2 /* Two extra wchar_t's for proper zero termination. */ 1028 + cbItemToAdd); 1029 if (!pbBuf) 1030 lrc = ERROR_OUTOFMEMORY; 1031 lrc = RegQueryValueEx(hKey, pwszValueName, NULL, &dwType, pbBuf, &cbValue); 1032 } 1033 if (lrc == ERROR_FILE_NOT_FOUND) 1034 { 1035 PrintStr("RegistryAddStringToList: Value not found, creating a new one...\r\n"); 1036 pbBuf = (PBYTE)RTMemAllocZ(cbItemToAdd + sizeof(wchar_t)*8); 1037 if (pbBuf) 1038 { 1039 cbValue = sizeof(wchar_t); 1040 dwType = REG_MULTI_SZ; 1041 lrc = ERROR_SUCCESS; 1042 } 1043 else 1044 lrc = ERROR_OUTOFMEMORY; 1045 } 1046 if ( lrc == ERROR_SUCCESS 1047 && dwType == REG_MULTI_SZ) 1048 { 1049 #ifdef DEBUG 1050 PrintSXS("RegistryAddStringToList: Current value length: ", cbValue, "\r\n"); 1051 #endif 1052 1053 /* 1054 * Scan the strings in the buffer, inserting the new item and removing any 1055 * existing duplicates. We do this in place. 1056 * 1057 * We have made sure above that the buffer is both properly zero terminated 1058 * and large enough to contain the new item, so we need do no buffer size 1059 * checking here. 1060 */ 1061 wchar_t volatile *pwszSrc = (wchar_t volatile *)pbBuf; 1062 wchar_t volatile *pwszDst = (wchar_t volatile *)pbBuf; 1063 size_t cbLeft = cbValue; 1064 for (uint32_t uCurPos = 0; ; uCurPos++) 1065 { 1066 size_t const cwcSrc = RTUtf16Len((wchar_t const *)pwszSrc); 1067 size_t const cbSrc = (cwcSrc + 1) * sizeof(wchar_t); 1068 bool const fTheEnd = !cwcSrc && cbSrc >= cbLeft; 1069 1070 /* Insert the item if we're in the right position now, or if we're 1071 at the last string and still haven't reached it. */ 1072 if (uCurPos == uPosition || (fTheEnd && uCurPos < uPosition)) 1073 { 1074 pwszSrc = (wchar_t volatile *)memmove((PBYTE)pwszSrc + cbItemToAdd, (wchar_t const *)pwszSrc, cbLeft); 1075 memcpy((void *)pwszDst, pwszItemToAdd, cbItemToAdd); 1076 pwszDst += cwcItemToAdd + 1; 1077 uCurPos++; 1078 } 1079 if (fTheEnd) 1080 break; 1081 1082 /* We do not add empty strings nor strings matching the one we're adding. */ 1083 if (!cwcSrc || IsSubStringOf(pwszSrc, cwcSrc, pwszItemToAdd, cwcItemToAdd)) 1084 uCurPos--; 1085 else 1086 { 1087 if (pwszDst != pwszSrc) 1088 memmove((void *)pwszDst, (void const *)pwszSrc, cbSrc); 1089 pwszDst += cwcSrc + 1; 1090 } 1091 pwszSrc += cwcSrc + 1; 1092 cbLeft -= cbSrc; 1093 } 1094 *pwszDst = '\0'; 1095 DWORD const cbNewValue = (DWORD)((PBYTE)(pwszDst + 1) - pbBuf); 1096 #ifdef DEBUG 1097 PrintSXS("RegistryAddStringToList: New value length: ", cbNewValue, "\r\n"); 1098 #endif 1099 1100 /* 1101 * Always write the value since we cannot tell whether it changed or 1102 * not without adding a bunch extra code above. 1103 */ 1104 lrc = RegSetValueExW(hKey, pwszValueName, 0, REG_MULTI_SZ, pbBuf, cbNewValue); 1105 if (lrc == ERROR_SUCCESS) 1106 { 1107 #ifdef DEBUG 1108 PrintSWSWS("RegistryAddStringToList: The item '", pwszItemToAdd, "' was added successfully to '", 1109 pwszValueName, "'.\r\n"); 1110 #endif 1111 rcExit = EXIT_OK; 1112 } 1113 else 1114 ErrorMsgLStatusSWSWSRS("RegistryAddStringToList: RegSetValueExW HKLM/'", 1115 pwszSubKey, "'/'", pwszValueName, "' failed: ", lrc, NULL); 1116 } 1117 else if (lrc != ERROR_SUCCESS) 1118 ErrorMsgLStatusSWSWSRS("RemoveStringFromMultiSZ: RegQueryValueEx HKLM/'", 1119 pwszSubKey, "'/'", pwszValueName, "' failed: ", lrc, NULL); 1120 else 1121 ErrorMsgLStatusSWSWSRS("RemoveStringFromMultiSZ: Unexpected value type for HKLM/'", 1122 pwszSubKey, "'/'", pwszValueName, "': ", (LSTATUS)dwType, ", expected REG_SZ (1)"); 1123 return rcExit; 1124 } 1125 1126 1127 /** Handles 'registry addmultisz'. */ 1128 static int handleRegistryAddMultiSz(unsigned cArgs, wchar_t **papwszArgs) 1129 { 1130 RT_NOREF(cArgs); 1131 1132 uint32_t uPosition; 1133 if (!ArgToUInt32Full(papwszArgs[3], "position", &uPosition)) 1134 return EXIT_USAGE; 1135 1136 return RegistryAddStringToMultiSZ(papwszArgs[0], papwszArgs[1], papwszArgs[2], uPosition); 1137 } 1138 1139 1140 /** 1141 * Removes a item from a MULTI_SZ registry list. 1142 * 1143 * @return Exit code (EXIT_OK, EXIT_FAIL) 1144 * @param pwszSubKey Sub key containing the list. 1145 * @param pwszValueName The actual key name of the list. 1146 * @param pwszItemToRemove The item to remove from the list. Actually, we 1147 * only do a substring match on this, so any item 1148 * containing this string will be removed. 1149 */ 1150 static int RegistryRemoveStringFromMultiSZ(const wchar_t *pwszSubKey, const wchar_t *pwszValueName, 1151 const wchar_t *pwszItemToRemove) 1152 { 1153 #ifdef DEBUG 1154 PrintSWSWSWS("RemoveStringFromMultiSZ: Removing MULTI_SZ string '", pwszItemToRemove, 1155 "' from HKLM/'", pwszSubKey, "'/'", pwszValueName, "'\r\n"); 1156 #endif 1157 1158 /* 1159 * Open the specified key. 1160 */ 1161 HKEY hKey = NULL; 1162 LSTATUS lrc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, pwszSubKey, 0 /*dwOptions*/, KEY_READ | KEY_WRITE, &hKey); 1163 if (lrc != ERROR_SUCCESS) 1164 return ErrorMsgLStatusSWSRS("RemoveStringFromMultiSZ: RegOpenKeyExW HKLM/'", pwszSubKey, "' failed: ", lrc, NULL); 1165 1166 /* 1167 * Query the current value, first query just gets the buffer size the 2nd does the actual query. 1168 */ 1169 int rcExit = EXIT_FAIL; 1170 PBYTE pbBuf = NULL; 1171 DWORD cbValue = 0; 1172 DWORD dwType = 0; 1173 lrc = RegQueryValueEx(hKey, pwszValueName, NULL, &dwType, NULL, &cbValue); 1174 if (lrc == ERROR_SUCCESS || lrc == ERROR_MORE_DATA) 1175 { 1176 cbValue = cbValue + _1K - sizeof(wchar_t)*2; /* 1KB of paranoia fudge, even if we ASSUME no races. */ 1177 pbBuf = (PBYTE)RTMemAllocZ(cbValue + sizeof(wchar_t)*2); /* Two extra wchar_t's for proper zero termination, see docs. */ 1178 if (!pbBuf) 1179 lrc = ERROR_OUTOFMEMORY; 1180 lrc = RegQueryValueEx(hKey, pwszValueName, NULL, &dwType, pbBuf, &cbValue); 1181 } 1182 if ( lrc == ERROR_SUCCESS 1183 && dwType == REG_MULTI_SZ) 1184 { 1185 #ifdef DEBUG 1186 PrintSXS("RemoveStringFromMultiSZ: Current value length: ", cbValue, "\r\n"); 1187 #endif 1188 /* 1189 * Scan the buffer and remove all strings containing the pwszItemToRemove 1190 * as a substring. 1191 */ 1192 size_t const cwcValueToRemove = RTUtf16Len(pwszItemToRemove); 1193 wchar_t volatile *pwszSrc = (wchar_t volatile *)pbBuf; 1194 wchar_t volatile *pwszDst = (wchar_t volatile *)pbBuf; 1195 size_t cbLeft = cbValue; 1196 for (;;) 1197 { 1198 /* Find the length for the current string. We can safely use RTUtf16Len 1199 here because of a zero terminated buffer with two extra terminator chars. */ 1200 size_t const cwcSrc = RTUtf16Len((wchar_t const *)pwszSrc); 1201 size_t const cbSrc = (cwcSrc + 1) * sizeof(wchar_t); 1202 if (!IsSubStringOf(pwszSrc, cwcSrc, pwszItemToRemove, cwcValueToRemove)) 1203 { 1204 if (pwszDst != pwszSrc) 1205 memmove((void *)pwszDst, (void const *)pwszSrc, cbSrc); 1206 pwszDst += cwcSrc + 1; 1207 } 1208 1209 /* Advance. */ 1210 if (cbLeft < cbSrc) 1211 break; 1212 cbLeft -= cbSrc; 1213 pwszSrc += cwcSrc + 1; 1214 } 1215 *pwszDst = '\0'; 1216 DWORD const cbNewValue = (DWORD)((PBYTE)(pwszDst + 1) - pbBuf); 1217 #ifdef DEBUG 1218 PrintSXS("RemoveStringFromMultiSZ: New value length: ", cbNewValue, "\r\n"); 1219 #endif 1220 1221 /* 1222 * Update the value if we made any change. 1223 */ 1224 if (cbNewValue == cbValue) 1225 { 1226 #ifdef DEBUG 1227 PrintSWSWS("RemoveStringFromMultiSZ: The item '", pwszItemToRemove, "' was not part of '", 1228 pwszValueName, "', so nothing needed doing.\r\n"); 1229 #endif 1230 rcExit = EXIT_OK; 216 1231 } 217 1232 else 218 1233 { 219 g_pfnDriverPackageUninstall = (fnDriverPackageUninstall)GetProcAddress(hDIFxAPI, "DriverPackageUninstallW");220 if ( g_pfnDriverPackageUninstall == NULL)1234 lrc = RegSetValueExW(hKey, pwszValueName, 0, REG_MULTI_SZ, pbBuf, cbNewValue); 1235 if (lrc == ERROR_SUCCESS) 221 1236 { 222 _tprintf(_T("ERROR: Unable to retrieve entry point for DriverPackageUninstallW!\n")); 223 hr = HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND); 1237 #ifdef DEBUG 1238 PrintSWSWS("RemoveStringFromMultiSZ: The item '", pwszItemToRemove, "' was removed successfully from '", 1239 pwszValueName, "'.\r\n"); 1240 #endif 1241 rcExit = EXIT_OK; 224 1242 } 1243 else 1244 ErrorMsgLStatusSWSWSRS("RegistryAddStringToList: RegSetValueExW HKLM/'", 1245 pwszSubKey, "'/'", pwszValueName, "' failed: ", lrc, NULL); 225 1246 } 226 227 if (SUCCEEDED(hr)) 1247 } 1248 else if (lrc == ERROR_FILE_NOT_FOUND) 1249 { 1250 #ifdef DEBUG 1251 PrintStr("RemoveStringFromMultiSZ: value not present in registry\r\n"); 1252 #endif 1253 rcExit = EXIT_OK; 1254 } 1255 else if (lrc != ERROR_SUCCESS) 1256 ErrorMsgLStatusSWSWSRS("RemoveStringFromMultiSZ: RegQueryValueEx HKLM/'", 1257 pwszSubKey, "'/'", pwszValueName, "' failed: ", lrc, NULL); 1258 else 1259 ErrorMsgLStatusSWSWSRS("RemoveStringFromMultiSZ: Unexpected value type for HKLM/'", 1260 pwszSubKey, "'/'", pwszValueName, "': ", (LSTATUS)dwType, ", expected REG_SZ (1)"); 1261 RegCloseKey(hKey); 1262 RTMemFree(pbBuf); 1263 return rcExit; 1264 } 1265 1266 1267 /** Handles 'registry delmultisz'. */ 1268 static int handleRegistryDelMultiSz(unsigned cArgs, wchar_t **papwszArgs) 1269 { 1270 RT_NOREF(cArgs); 1271 return RegistryRemoveStringFromMultiSZ(papwszArgs[0], papwszArgs[1], papwszArgs[2]); 1272 } 1273 1274 1275 /** 1276 * Compare the current list item with the one to add/remove. 1277 * 1278 * Used by RegistryAddStringToList and RegistryRemoveStringFromList. 1279 */ 1280 static bool IsStringListItemMatch(wchar_t volatile *pwszItem1, size_t cwcItem1, 1281 wchar_t const *pwszItem2, size_t cwcItem2) 1282 { 1283 if (cwcItem1 == cwcItem2) 1284 { 1285 #if 0 /* 94720 bytes */ 1286 if (RTUtf16NICmp((wchar_t const *)pwszItem1, pwszItem2, cwcItem1) == 0) 1287 return true; 1288 #else /* vs 62464 bytes */ 1289 /* Temporarily zero termination of item 1 as it's easier, and therefore 1290 safer, to use lstrcmpiW than CompareStringW or CompareStringExW. The 1291 latter is Vista and later, the former has a big fat warning on it. */ 1292 wchar_t const wcEnd = pwszItem1[cwcItem1]; 1293 int const iDiff = lstrcmpiW((wchar_t const *)pwszItem1, pwszItem2); 1294 pwszItem1[cwcItem1] = wcEnd; 1295 return iDiff == 0; 1296 #endif 1297 } 1298 return false; 1299 } 1300 1301 1302 /** 1303 * Adds an item to a comma separated registry string list (REG_SZ). 1304 * 1305 * Only operates in HKLM for now, if needed it can be extended later for use 1306 * with other hives. 1307 * 1308 * @return Exit code (EXIT_OK, EXIT_FAIL) 1309 * @param pwszSubKey Sub key containing the list value. 1310 * @param pwszValueName The name of the value holding the list. 1311 * @param pwszItemToAdd The value to add to the list. 1312 * @param uPosition Position (zero-based) of where to insert the 1313 * value into the list. 1314 * @param fFlags VBOX_REG_STRINGLIST_ALLOW_DUPLICATES or 0. 1315 */ 1316 static int RegistryAddStringToList(const wchar_t *pwszSubKey, const wchar_t *pwszValueName, const wchar_t *pwszItemToAdd, 1317 uint32_t uPosition, uint32_t fFlags) 1318 { 1319 /* Overflow precaution - see comment below. */ 1320 size_t const cwcItemToAdd = RTUtf16Len(pwszItemToAdd); 1321 if (cwcItemToAdd >= 256 /* see wszNewValue size below */) 1322 return ErrorMsg("RegistryAddStringToList: The value to add is too long! Max 256 chars."); 1323 1324 /* 1325 * Open/create the key. 1326 */ 1327 HKEY hKey = NULL; 1328 DWORD dwDisp = 0; 1329 LSTATUS lrc = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pwszSubKey, 0 /*Reserved*/, NULL /*pClass*/, REG_OPTION_NON_VOLATILE, 1330 KEY_READ | KEY_WRITE, NULL /*pSecAttr*/, &hKey, &dwDisp); 1331 if (lrc != ERROR_SUCCESS) 1332 return ErrorMsgLStatusSWSRS("RegistryAddStringToList: RegCreateKeyEx HKLM/'", pwszSubKey, "' failed: ", lrc, NULL); 1333 1334 /* 1335 * Query the current value. 1336 */ 1337 int rcExit = EXIT_FAIL; 1338 wchar_t wszValue[1024] = { 0 }; 1339 DWORD cbValue = sizeof(wszValue) - sizeof(wchar_t); 1340 DWORD dwType = 0; 1341 lrc = RegQueryValueEx(hKey, pwszValueName, NULL /*pReserved*/, &dwType, (LPBYTE)wszValue, &cbValue); 1342 if (lrc == ERROR_FILE_NOT_FOUND) 1343 { 1344 PrintStr("RegistryAddStringToList: Value not found, creating a new one...\r\n"); 1345 wszValue[0] = '\0'; 1346 cbValue = sizeof(wchar_t); 1347 dwType = REG_SZ; 1348 lrc = ERROR_SUCCESS; 1349 } 1350 if (lrc == ERROR_SUCCESS && dwType == REG_SZ) 1351 { 1352 #ifdef DEBUG 1353 PrintSWS("RegistryAddStringToList: Value string: '", wszValue, "'\r\n"); 1354 #endif 1355 1356 /* 1357 * Scan the list and make a new copy of it with the new item added 1358 * in the specified place. 1359 * 1360 * Having checked that what we're adding isn't more than 256 + 1 chars long 1361 * above, we can avoid tedious overflow checking here the simple expedient of 1362 * using an output buffer that's at least 256 + 1 chars bigger than the source. 1363 */ 1364 wchar_t wszNewValue[RT_ELEMENTS(wszValue) + 256 + 4] = { 0 }; 1365 wchar_t *pwszDst = wszNewValue; 1366 wchar_t *pwszSrc = wszValue; 1367 unsigned uCurPos = 0; 1368 for (;;) 228 1369 { 229 g_pfnDIFXAPISetLogCallback = (fnDIFXAPISetLogCallback)GetProcAddress(hDIFxAPI, "DIFXAPISetLogCallbackW"); 230 if (g_pfnDIFXAPISetLogCallback == NULL) 1370 /* Skip leading commas: */ 1371 wchar_t wc = *pwszSrc; 1372 bool fLeadingComma = wc == ','; 1373 if (fLeadingComma) 1374 do 1375 wc = *++pwszSrc; 1376 while (wc == ','); 1377 1378 /* Insert the new item if we're at the right position or have reached 1379 the end of the list and have yet done so. */ 1380 if (uCurPos == uPosition || (!wc && uCurPos < uPosition)) 231 1381 { 232 _tprintf(_T("ERROR: Unable to retrieve entry point for DIFXAPISetLogCallbackW!\n")); 233 hr = HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND); 1382 if (fLeadingComma) 1383 *pwszDst++ = ','; 1384 memcpy(pwszDst, pwszItemToAdd, cwcItemToAdd * sizeof(wchar_t)); 1385 pwszDst += cwcItemToAdd; 1386 fLeadingComma = true; 234 1387 } 1388 1389 /* Get out of the loop if we're at the end of the input. */ 1390 if (!wc) 1391 break; /* don't preserve trailing commas? Old code didn't (see strtok_r code). */ 1392 1393 /* Start of a new 'value', so, find the end of it. */ 1394 wchar_t *pwszSrcEnd = pwszSrc + 1; 1395 do 1396 wc = *++pwszSrcEnd; 1397 while (wc != '\0' && wc != ','); 1398 size_t const cwcItem = (size_t)(pwszSrcEnd - pwszSrc); 1399 1400 /* If it matches pwszItemToRemove and the VBOX_REG_STRINGLIST_ALLOW_DUPLICATES 1401 wasn't specified, we'll skip this value. */ 1402 ASMCompilerBarrier(); /* Paranoia ^ 2*/ 1403 if ( !(fFlags & VBOX_REG_STRINGLIST_ALLOW_DUPLICATES) 1404 && IsStringListItemMatch(pwszSrc, cwcItem, pwszItemToAdd, cwcItemToAdd)) 1405 pwszSrc = pwszSrcEnd; 1406 else 1407 { 1408 if (fLeadingComma) 1409 *pwszDst++ = ','; 1410 memmove(pwszDst, pwszSrc, cwcItem * sizeof(*pwszDst)); 1411 pwszDst += cwcItem; 1412 pwszSrc = pwszSrcEnd; 1413 ASMCompilerBarrier(); /* Paranoia ^ 3 */ 1414 } 1415 1416 /* pwszSrc should not point at a comma or a zero terminator. */ 235 1417 } 236 } 237 238 if (SUCCEEDED(hr)) 239 { 240 FILE *phFile = NULL; 241 if (pszLogFile) 1418 *pwszDst = '\0'; 1419 DWORD const cbNewValue = (DWORD)((pwszDst + 1 - &wszNewValue[0]) * sizeof(wchar_t)); 1420 1421 #ifdef DEBUG 1422 PrintSWS("RegistryAddStringToList: New value: '", wszNewValue, "'\r\n"); 1423 #endif 1424 1425 /* 1426 * Add the value if changed. 1427 */ 1428 if ( cbNewValue == cbValue 1429 && memcmp(wszNewValue, wszValue, cbNewValue) == 0) 1430 rcExit = EXIT_OK; 1431 else 242 1432 { 243 phFile = _wfopen(pszLogFile, _T("a")); 244 if (!phFile) 245 _tprintf(_T("ERROR: Unable to create log file!\n")); 246 g_pfnDIFXAPISetLogCallback(LogCallback, phFile); 1433 lrc = RegSetValueExW(hKey, pwszValueName, 0, REG_SZ, (LPBYTE)wszNewValue, cbNewValue); 1434 if (lrc == ERROR_SUCCESS) 1435 rcExit = EXIT_OK; 1436 else 1437 ErrorMsgLStatusSWSWSWSRS("RegistryAddStringToList: RegSetValueExW HKLM/'", 1438 pwszSubKey, "'/'", pwszValueName, "' = '", wszNewValue, "' failed: ", lrc, NULL); 247 1439 } 248 249 INSTALLERINFO instInfo = 1440 } 1441 else if (lrc != ERROR_SUCCESS) 1442 ErrorMsgLStatusSWSWSRS("RegistryAddStringToList: RegQueryValueEx HKLM/'", 1443 pwszSubKey, "'/'", pwszValueName, "' failed: ", lrc, NULL); 1444 else 1445 ErrorMsgLStatusSWSWSRS("RegistryAddStringToList: Unexpected value type for HKLM/'", 1446 pwszSubKey, "'/'", pwszValueName, "': ", (LSTATUS)dwType, ", expected REG_SZ (1)"); 1447 1448 RegCloseKey(hKey); 1449 return rcExit; 1450 } 1451 1452 1453 /** 1454 * Handles 'netprovider add'. 1455 */ 1456 static int handleNetProviderAdd(unsigned cArgs, wchar_t **papwszArgs) 1457 { 1458 const wchar_t * const pwszProvider = papwszArgs[0]; 1459 wchar_t const * const pwszPosition = cArgs > 1 ? papwszArgs[1] : L"0"; 1460 uint32_t uPosition = 0; 1461 if (cArgs > 1 && !ArgToUInt32Full(pwszPosition, "position", &uPosition)) 1462 return EXIT_USAGE; 1463 1464 PrintSWSWS("Adding network provider '", pwszProvider, "' (Position = ", pwszPosition, ") ...\r\n"); 1465 int rcExit = RegistryAddStringToList(L"System\\CurrentControlSet\\Control\\NetworkProvider\\Order", 1466 L"ProviderOrder", 1467 pwszProvider, uPosition, VBOX_REG_STRINGLIST_NONE); 1468 if (rcExit == EXIT_OK) 1469 PrintStr("Network provider successfully added!\r\n"); 1470 1471 return rcExit; 1472 } 1473 1474 1475 /** 1476 * Removes an item from a comma separated registry string (REG_SZ). 1477 * 1478 * Only operates in HKLM for now, if needed it can be extended later for use 1479 * with other hives. 1480 * 1481 * @return Exit code (EXIT_OK, EXIT_FAIL) 1482 * @param pwszSubKey Subkey containing the list value. 1483 * @param pwszValueName The value name. 1484 * @param pwszItemToRemove The item to remove from the list. 1485 */ 1486 static int RegistryRemoveStringFromList(const wchar_t *pwszSubKey, const wchar_t *pwszValueName, const wchar_t *pwszItemToRemove) 1487 { 1488 /* 1489 * Open the specified key. 1490 */ 1491 HKEY hKey = NULL; 1492 LSTATUS lrc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, pwszSubKey, 0 /*dwOptions*/, KEY_READ | KEY_WRITE, &hKey); 1493 if (lrc != ERROR_SUCCESS) 1494 return ErrorMsgLStatusSWSRS("RegistryRemoveStringFromList: RegOpenKeyExW HKLM/'", pwszSubKey, "' failed: ", lrc, NULL); 1495 1496 /* 1497 * Query the specified value. 1498 */ 1499 int rcExit = EXIT_FAIL; 1500 wchar_t wszValue[1296] = { 0 }; 1501 DWORD cbValue = sizeof(wszValue) - sizeof(wchar_t); 1502 DWORD dwType = 0; 1503 lrc = RegQueryValueEx(hKey, pwszValueName, NULL /*pReserved*/, &dwType, (LPBYTE)wszValue, &cbValue); 1504 if (lrc == ERROR_SUCCESS && dwType == REG_SZ) 1505 { 1506 #ifdef DEBUG 1507 PrintSWS("RegistryRemoveStringFromList: Value string: '", wszValue, "'\r\n"); 1508 #endif 1509 1510 /* 1511 * Scan for item, shifting the query result as we scan. 1512 */ 1513 size_t const cwcItemToRemove = RTUtf16Len(pwszItemToRemove); 1514 wchar_t volatile *pwszSrc = wszValue; 1515 wchar_t volatile *pwszDst = wszValue; 1516 for (;;) 250 1517 { 251 TEXT("{7d2c708d-c202-40ab-b3e8-de21da1dc629}"), /* Our GUID for representing this installation tool. */ 252 TEXT("VirtualBox Guest Additions Install Helper"), 253 TEXT("VirtualBox Guest Additions"), /** @todo Add version! */ 254 TEXT("Oracle Corporation") 255 }; 256 257 _TCHAR szDriverInf[MAX_PATH + 1]; 258 if (0 == GetFullPathNameW(pszDriverPath, MAX_PATH, szDriverInf, NULL)) 1518 /* Skip leading commas: */ 1519 wchar_t wc = *pwszSrc; 1520 bool const fLeadingComma = wc == ','; 1521 if (fLeadingComma) 1522 do 1523 wc = *++pwszSrc; 1524 while (wc == ','); 1525 if (!wc) 1526 break; /* don't preserve trailing commas? Old code didn't (see strtok_r code). */ 1527 1528 /* Start of a new 'value', so, find the end of it. */ 1529 wchar_t volatile *pwszSrcEnd = pwszSrc + 1; 1530 do 1531 wc = *++pwszSrcEnd; 1532 while (wc != '\0' && wc != ','); 1533 size_t const cwcItem = (size_t)(pwszSrcEnd - pwszSrc); 1534 1535 /* If it matches pwszItemToRemove, do not copy it. */ 1536 ASMCompilerBarrier(); /* Paranoia ^ 2 */ 1537 if (IsStringListItemMatch(pwszSrc, cwcItem, pwszItemToRemove, cwcItemToRemove)) 1538 pwszSrc = pwszSrcEnd; 1539 else 1540 { 1541 if (fLeadingComma) 1542 *pwszDst++ = ','; 1543 memmove((void *)pwszDst, (void const *)pwszSrc, cwcItem * sizeof(*pwszDst)); 1544 pwszDst += cwcItem; 1545 pwszSrc = pwszSrcEnd; 1546 ASMCompilerBarrier(); /* paranoia ^ 3 */ 1547 } 1548 1549 /* pwszSrc should not point at a comma or a zero terminator. */ 1550 } 1551 *pwszDst = '\0'; 1552 #ifdef DEBUG 1553 PrintSWS("RegistryRemoveStringFromList: New value: '", wszValue, "'\r\n"); 1554 #endif 1555 1556 /* 1557 * Save the new value if we've made any changes. 1558 */ 1559 if (pwszDst == pwszSrc) 1560 rcExit = EXIT_OK; 1561 else 259 1562 { 260 _tprintf(_T("ERROR: INF-Path too long / could not be retrieved!\n")); 261 hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); 1563 cbValue = (DWORD)((pwszDst + 1 - &wszValue[0]) * sizeof(wchar_t)); 1564 lrc = RegSetValueExW(hKey, pwszValueName, 0, REG_SZ, (LPBYTE)wszValue, cbValue); 1565 if (lrc == ERROR_SUCCESS) 1566 rcExit = EXIT_OK; 1567 else 1568 ErrorMsgLStatusSWSWSWSRS("RegistryRemoveStringFromList: RegSetValueExW HKLM/'", 1569 pwszSubKey, "'/'", pwszValueName, "' = '", wszValue, "' failed: ", lrc, NULL); 1570 } 1571 } 1572 else if (lrc == ERROR_FILE_NOT_FOUND) 1573 { 1574 #ifdef DEBUG 1575 PrintStr("RegistryRemoveStringFromList: Value not present in registry\r\n"); 1576 #endif 1577 rcExit = EXIT_OK; 1578 } 1579 else if (lrc != ERROR_SUCCESS) 1580 ErrorMsgLStatusSWSWSRS("RegistryRemoveStringFromList: RegQueryValueEx HKLM/'", 1581 pwszSubKey, "'/'", pwszValueName, "' failed: ", lrc, NULL); 1582 else 1583 ErrorMsgLStatusSWSWSRS("RegistryRemoveStringFromList: Unexpected value type for HKLM/'", 1584 pwszSubKey, "'/'", pwszValueName, "': ", (LSTATUS)dwType, ", expected REG_SZ (1)"); 1585 RegCloseKey(hKey); 1586 return rcExit; 1587 } 1588 1589 1590 /** 1591 * Handles 'netprovider remove'. 1592 */ 1593 static int handleNetProviderRemove(unsigned cArgs, wchar_t **papwszArgs) 1594 { 1595 const wchar_t * const pwszProvider = papwszArgs[0]; 1596 PrintSWS("Removing network provider '", pwszProvider, "' ...\r\n"); 1597 1598 int rcExit = RegistryRemoveStringFromList(L"System\\CurrentControlSet\\Control\\NetworkProvider\\Order", 1599 L"ProviderOrder", 1600 pwszProvider); 1601 if (rcExit == EXIT_OK) 1602 PrintStr("Network provider successfully removed!\r\n"); 1603 1604 RT_NOREF(cArgs); 1605 return rcExit; 1606 } 1607 1608 1609 /** 1610 * Worker for the 'service create' handler. 1611 */ 1612 static int CreateService(const wchar_t *pwszService, 1613 const wchar_t *pwszDisplayName, 1614 uint32_t uServiceType, 1615 uint32_t uStartType, 1616 const wchar_t *pwszBinPath, 1617 const wchar_t *pwszLoadOrderGroup, 1618 const wchar_t *pwszDependencies, 1619 const wchar_t *pwszLogonUser, 1620 const wchar_t *pwszLogonPassword) 1621 { 1622 PrintSWSWS("Installing service '", pwszService, "' ('", pwszDisplayName, ") ...\r\n"); 1623 1624 /* 1625 * Transform the dependency list to a REG_MULTI_SZ. 1626 */ 1627 if (pwszDependencies != NULL) 1628 { 1629 /* Copy it into alloca() buffer so we can modify it. */ 1630 size_t cwc = RTUtf16Len(pwszDependencies); 1631 wchar_t *pwszDup = (wchar_t *)alloca((cwc + 2) * sizeof(wchar_t)); 1632 memcpy(pwszDup, pwszDependencies, cwc * sizeof(wchar_t)); 1633 pwszDup[cwc] = L'\0'; 1634 pwszDup[cwc + 1] = L'\0'; /* double termination */ 1635 1636 /* Perform: s/,/\0/g */ 1637 while (cwc-- > 0 ) 1638 if (pwszDup[cwc] == L',') 1639 pwszDup[cwc] = L'\0'; 1640 1641 pwszDependencies = pwszDup; 1642 } 1643 1644 SC_HANDLE hSCManager = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS); 1645 if (hSCManager == NULL) 1646 return ErrorMsgLastErr("OpenSCManagerW failed"); 1647 1648 int rcExit = EXIT_FAIL; 1649 DWORD dwTag = 0xDEADBEAF; 1650 SC_HANDLE hService = CreateServiceW(hSCManager, pwszService, pwszDisplayName, SERVICE_ALL_ACCESS, uServiceType, uStartType, 1651 SERVICE_ERROR_NORMAL, pwszBinPath, pwszLoadOrderGroup, pwszLoadOrderGroup ? &dwTag : NULL, 1652 pwszDependencies, pwszLogonUser, pwszLogonPassword); 1653 if (hService != NULL) 1654 { 1655 CloseServiceHandle(hService); 1656 PrintStr("Installation of service successful!\r\n"); 1657 rcExit = EXIT_OK; 1658 } 1659 else 1660 { 1661 DWORD dwErr = GetLastError(); 1662 if (dwErr == ERROR_SERVICE_EXISTS) 1663 { 1664 PrintStr("Service already exists. Updating the service config ...\r\n"); 1665 hService = OpenServiceW(hSCManager, pwszService, SERVICE_ALL_ACCESS); 1666 if (hService != NULL) 1667 { 1668 if (ChangeServiceConfigW(hService, uServiceType, uStartType, SERVICE_ERROR_NORMAL, pwszBinPath, 1669 pwszLoadOrderGroup, pwszLoadOrderGroup ? &dwTag : NULL, pwszDependencies, 1670 pwszLogonUser, pwszLogonPassword, pwszDisplayName)) 1671 { 1672 PrintStr("The service config has been successfully updated.\r\n"); 1673 rcExit = EXIT_OK; 1674 } 1675 else 1676 rcExit = ErrorMsgLastErrSWS("ChangeServiceConfigW failed on '", pwszService, "'!"); 1677 CloseServiceHandle(hService); 1678 } 1679 else 1680 rcExit = ErrorMsgLastErrSWS("OpenSCManagerW failed on '", pwszService, "'!"); 1681 1682 /* 1683 * This branch does not return an error to avoid installations failures, 1684 * if updating service parameters. Better to have a running system with old 1685 * parameters and the failure information in the installation log. 1686 */ 1687 rcExit = EXIT_OK; 262 1688 } 263 1689 else 1690 rcExit = ErrorMsgLastErrSWS("CreateServiceW for '", pwszService, "'!"); 1691 } 1692 1693 CloseServiceHandle(hSCManager); 1694 return rcExit; 1695 } 1696 1697 1698 /** Handles 'service create'. */ 1699 static int handleServiceCreate(unsigned cArgs, wchar_t **papwszArgs) 1700 { 1701 uint32_t uServiceType; 1702 if (!ArgToUInt32Full(papwszArgs[2], "service-type", &uServiceType)) 1703 return EXIT_USAGE; 1704 1705 uint32_t uStartType; 1706 if (!ArgToUInt32Full(papwszArgs[3], "start-type", &uStartType)) 1707 return EXIT_USAGE; 1708 1709 return CreateService(papwszArgs[0], papwszArgs[1], uServiceType, uStartType, papwszArgs[4], 1710 cArgs > 5 ? papwszArgs[5] : NULL, 1711 cArgs > 6 ? papwszArgs[6] : NULL, 1712 cArgs > 7 ? papwszArgs[7] : NULL, 1713 cArgs > 8 ? papwszArgs[8] : NULL); 1714 } 1715 1716 1717 /** 1718 * Worker for the 'service delete' handler. 1719 */ 1720 static int DelService(const wchar_t *pwszService) 1721 { 1722 PrintSWS("Removing service '", pwszService, "' ...\r\n"); 1723 1724 SC_HANDLE hSCManager = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS); 1725 if (hSCManager == NULL) 1726 return ErrorMsgLastErr("OpenSCManagerW failed"); 1727 1728 int rcExit = EXIT_FAIL; 1729 SC_HANDLE hService = NULL; 1730 hService = OpenServiceW(hSCManager, pwszService, SERVICE_ALL_ACCESS); 1731 if (hService) 1732 { 1733 SC_LOCK hSCLock = LockServiceDatabase(hSCManager); 1734 if (hSCLock != NULL) 264 1735 { 265 if (fInstall) 266 _tprintf(_T("Installing driver ...\n")); 267 else 268 _tprintf(_T("Uninstalling driver ...\n")); 269 _tprintf(_T("INF-File: %ws\n"), szDriverInf); 270 271 DWORD dwFlags = DRIVER_PACKAGE_FORCE; 272 if (!fInstall) 273 dwFlags |= DRIVER_PACKAGE_DELETE_FILES; 274 275 OSVERSIONINFO osi; 276 memset(&osi, 0, sizeof(OSVERSIONINFO)); 277 osi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); 278 if ( (GetVersionEx(&osi) != 0) 279 && (osi.dwPlatformId == VER_PLATFORM_WIN32_NT) 280 && (osi.dwMajorVersion < 6)) 1736 if (DeleteService(hService)) 281 1737 { 282 if (fInstall) 283 { 284 _tprintf(_T("Using legacy mode for install ...\n")); 285 dwFlags |= DRIVER_PACKAGE_LEGACY_MODE; 286 } 287 } 288 289 if (fSilent) 290 { 291 _tprintf(_T("Installation is silent ...\n")); 292 /* 293 * Don't add DRIVER_PACKAGE_SILENT to dwFlags here, otherwise 294 * installation will fail because we (still) don't have WHQL certified 295 * drivers. See CERT_E_WRONG_USAGE on MSDN for more information. 296 */ 297 } 298 299 BOOL fReboot; 300 DWORD dwRet = fInstall ? 301 g_pfnDriverPackageInstall(szDriverInf, dwFlags, &instInfo, &fReboot) 302 : g_pfnDriverPackageUninstall(szDriverInf, dwFlags, &instInfo, &fReboot); 303 if (dwRet != ERROR_SUCCESS) 304 { 305 switch (dwRet) 306 { 307 case CRYPT_E_FILE_ERROR: 308 _tprintf(_T("ERROR: The catalog file for the specified driver package was not found!\n")); 309 break; 310 311 case ERROR_ACCESS_DENIED: 312 _tprintf(_T("ERROR: Caller is not in Administrators group to (un)install this driver package!\n")); 313 break; 314 315 case ERROR_BAD_ENVIRONMENT: 316 _tprintf(_T("ERROR: The current Microsoft Windows version does not support this operation!\n")); 317 break; 318 319 case ERROR_CANT_ACCESS_FILE: 320 _tprintf(_T("ERROR: The driver package files could not be accessed!\n")); 321 break; 322 323 case ERROR_DEPENDENT_APPLICATIONS_EXIST: 324 _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")); 325 break; 326 327 case ERROR_DRIVER_PACKAGE_NOT_IN_STORE: 328 _tprintf(_T("ERROR: There is no INF file in the DIFx driver store that corresponds to the INF file %ws!\n"), szDriverInf); 329 break; 330 331 case ERROR_FILE_NOT_FOUND: 332 _tprintf(_T("ERROR: File not found! File = %ws\n"), szDriverInf); 333 break; 334 335 case ERROR_IN_WOW64: 336 _tprintf(_T("ERROR: The calling application is a 32-bit application attempting to execute in a 64-bit environment, which is not allowed!\n")); 337 break; 338 339 case ERROR_INVALID_FLAGS: 340 _tprintf(_T("ERROR: The flags specified are invalid!\n")); 341 break; 342 343 case ERROR_INSTALL_FAILURE: 344 _tprintf(_T("ERROR: The (un)install operation failed! Consult the Setup API logs for more information.\n")); 345 break; 346 347 case ERROR_NO_MORE_ITEMS: 348 _tprintf( 349 _T( 350 "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")); 351 break; 352 353 case ERROR_NO_DRIVER_SELECTED: 354 _tprintf(_T("ERROR: No driver in .INF-file selected!\n")); 355 break; 356 357 case ERROR_SECTION_NOT_FOUND: 358 _tprintf(_T("ERROR: Section in .INF-file was not found!\n")); 359 break; 360 361 case ERROR_SHARING_VIOLATION: 362 _tprintf(_T("ERROR: A component of the driver package in the DIFx driver store is locked by a thread or process\n")); 363 break; 364 365 /* 366 * ! sig: Verifying file against specific Authenticode(tm) catalog failed! (0x800b0109) 367 * ! sig: Error 0x800b0109: A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider. 368 * !!! sto: No error message will be displayed as client is running in non-interactive mode. 369 * !!! ndv: Driver package failed signature validation. Error = 0xE0000247 370 */ 371 case ERROR_DRIVER_STORE_ADD_FAILED: 372 _tprintf(_T("ERROR: Adding driver to the driver store failed!!\n")); 373 break; 374 375 case ERROR_UNSUPPORTED_TYPE: 376 _tprintf(_T("ERROR: The driver package type is not supported of INF %ws!\n"), szDriverInf); 377 break; 378 379 case ERROR_NO_SUCH_DEVINST: 380 _tprintf(_T("INFO: The driver package was installed but no matching devices found in the device tree (ERROR_NO_SUCH_DEVINST).\n")); 381 break; 382 383 default: 384 { 385 /* Try error lookup with GetErrorMsg(). */ 386 TCHAR szErrMsg[1024]; 387 GetErrorMsg(dwRet, szErrMsg, sizeof(szErrMsg)); 388 _tprintf(_T("ERROR (%08lx): %ws\n"), dwRet, szErrMsg); 389 break; 390 } 391 } 392 393 if (dwRet == ERROR_NO_SUCH_DEVINST) 394 { 395 /* GA installer should ignore this error code and continue */ 396 hr = S_OK; 397 } 398 else 399 hr = HRESULT_FROM_WIN32(dwRet); 400 } 401 g_pfnDIFXAPISetLogCallback(NULL, NULL); 402 if (phFile) 403 fclose(phFile); 404 if (SUCCEEDED(hr)) 405 { 406 _tprintf(_T("Driver was %sinstalled successfully!\n"), fInstall ? _T("") : _T("un")); 407 if (fReboot) 408 _tprintf(_T("A reboot is needed to complete the driver %sinstallation!\n"), fInstall ? _T("") : _T("un")); 409 } 410 } 411 } 412 413 if (NULL != hDIFxAPI) 414 FreeLibrary(hDIFxAPI); 415 416 return SUCCEEDED(hr) ? EXIT_OK : EXIT_FAIL; 417 } 418 419 static UINT WINAPI vboxDrvInstExecuteInfFileCallback(PVOID Context, 420 UINT Notification, 421 UINT_PTR Param1, 422 UINT_PTR Param2) RT_NOTHROW_DEF 423 { 424 #ifdef DEBUG 425 _tprintf (_T( "Got installation notification %u\n"), Notification); 426 #endif 427 428 switch (Notification) 429 { 430 case SPFILENOTIFY_NEEDMEDIA: 431 _tprintf (_T( "Requesting installation media ...\n")); 432 break; 433 434 case SPFILENOTIFY_STARTCOPY: 435 _tprintf (_T( "Copying driver files to destination ...\n")); 436 break; 437 438 case SPFILENOTIFY_TARGETNEWER: 439 case SPFILENOTIFY_TARGETEXISTS: 440 return TRUE; 441 } 442 443 return SetupDefaultQueueCallback(Context, Notification, Param1, Param2); 444 } 445 446 /** 447 * Executes a sepcified .INF section to install/uninstall drivers and/or services. 448 * 449 * @return Exit code (EXIT_OK, EXIT_FAIL) 450 * @param pszSection Section to execute; usually it's "DefaultInstall". 451 * @param iMode Execution mode to use (see MSDN). 452 * @param pszInf Full qualified path of the .INF file to use. 453 */ 454 int ExecuteInfFile(const _TCHAR *pszSection, int iMode, const _TCHAR *pszInf) 455 { 456 RT_NOREF(iMode); 457 _tprintf(_T("Installing from INF-File: %ws (Section: %ws) ...\n"), 458 pszInf, pszSection); 459 460 UINT uErrorLine = 0; 461 HINF hINF = SetupOpenInfFile(pszInf, NULL, INF_STYLE_WIN4, &uErrorLine); 462 if (hINF != INVALID_HANDLE_VALUE) 463 { 464 PVOID pvQueue = SetupInitDefaultQueueCallback(NULL); 465 466 BOOL fSuccess = SetupInstallFromInfSection(NULL, 467 hINF, 468 pszSection, 469 SPINST_ALL, 470 HKEY_LOCAL_MACHINE, 471 NULL, 472 SP_COPY_NEWER_OR_SAME | SP_COPY_NOSKIP, 473 vboxDrvInstExecuteInfFileCallback, 474 pvQueue, 475 NULL, 476 NULL 477 ); 478 if (fSuccess) 479 { 480 _tprintf (_T( "File installation stage successful\n")); 481 482 fSuccess = SetupInstallServicesFromInfSection(hINF, 483 L"DefaultInstall.Services", 484 0 /* Flags */); 485 if (fSuccess) 486 { 487 _tprintf (_T( "Service installation stage successful. Installation completed\n")); 1738 PrintSWS("Service '", pwszService, "' successfully deleted.\r\n"); 1739 rcExit = EXIT_OK; 488 1740 } 489 1741 else 490 1742 { 491 1743 DWORD dwErr = GetLastError(); 492 switch (dwErr)1744 if (dwErr == ERROR_SERVICE_MARKED_FOR_DELETE) 493 1745 { 494 case ERROR_SUCCESS_REBOOT_REQUIRED: 495 _tprintf (_T( "A reboot is required to complete the installation\n")); 496 break; 497 498 case ERROR_SECTION_NOT_FOUND: 499 break; 500 501 default: 502 _tprintf (_T( "Error %ld while installing service\n"), dwErr); 503 break; 1746 PrintSWS("Service '", pwszService, "' already marked for deletion.\r\n"); 1747 rcExit = EXIT_OK; 504 1748 } 505 }506 }507 else508 _tprintf (_T( "Error %ld while installing files\n"), GetLastError());509 510 if (pvQueue)511 SetupTermDefaultQueueCallback(pvQueue);512 513 SetupCloseInfFile(hINF);514 }515 else516 _tprintf (_T( "Unable to open %ws: %ld (error line %u)\n"),517 pszInf, GetLastError(), uErrorLine);518 519 return EXIT_OK;520 }521 522 /**523 * Adds a string entry to a MULTI_SZ registry list.524 *525 * @return Exit code (EXIT_OK, EXIT_FAIL)526 * @param pszSubKey Sub key containing the list.527 * @param pszKeyValue The actual key name of the list.528 * @param pszValueToAdd The value to add to the list.529 * @param uiOrder Position (zero-based) of where to add the value to the list.530 */531 int RegistryAddStringToMultiSZ(const TCHAR *pszSubKey, const TCHAR *pszKeyValue, const TCHAR *pszValueToAdd, unsigned int uiOrder)532 {533 #ifdef DEBUG534 _tprintf(_T("AddStringToMultiSZ: Adding MULTI_SZ string %ws to %ws\\%ws (Order = %d)\n"), pszValueToAdd, pszSubKey, pszKeyValue, uiOrder);535 #endif536 537 HKEY hKey = NULL;538 DWORD disp, dwType;539 LONG lRet = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey, &disp);540 if (lRet != ERROR_SUCCESS)541 _tprintf(_T("AddStringToMultiSZ: RegCreateKeyEx %s failed with error %ld!\n"), pszSubKey, lRet);542 543 if (lRet == ERROR_SUCCESS)544 {545 TCHAR szKeyValue[512] = { 0 };546 TCHAR szNewKeyValue[512] = { 0 };547 DWORD cbKeyValue = sizeof(szKeyValue);548 549 lRet = RegQueryValueEx(hKey, pszKeyValue, NULL, &dwType, (LPBYTE)szKeyValue, &cbKeyValue);550 if ( lRet != ERROR_SUCCESS551 || dwType != REG_MULTI_SZ)552 {553 _tprintf(_T("AddStringToMultiSZ: RegQueryValueEx failed with error %ld, key type = %#lx!\n"), lRet, dwType);554 }555 else556 {557 558 /* Look if the network provider is already in the list. */559 unsigned int iPos = 0;560 size_t cb = 0;561 562 /* Replace delimiting "\0"'s with "," to make tokenizing work. */563 for (unsigned i = 0; i < cbKeyValue / sizeof(TCHAR); i++)564 if (szKeyValue[i] == '\0') szKeyValue[i] = ',';565 566 TCHAR *pszToken = wcstok(szKeyValue, _T(","));567 TCHAR *pszNewToken = NULL;568 TCHAR *pNewKeyValuePos = szNewKeyValue;569 while (pszToken != NULL)570 {571 pszNewToken = wcstok(NULL, _T(","));572 573 /* Append new value (at beginning if iOrder=0). */574 if (iPos == uiOrder)575 {576 memcpy(pNewKeyValuePos, pszValueToAdd, wcslen(pszValueToAdd)*sizeof(TCHAR));577 578 cb += (wcslen(pszValueToAdd) + 1) * sizeof(TCHAR); /* Add trailing zero as well. */579 pNewKeyValuePos += wcslen(pszValueToAdd) + 1;580 iPos++;581 }582 583 if (0 != wcsicmp(pszToken, pszValueToAdd))584 {585 memcpy(pNewKeyValuePos, pszToken, wcslen(pszToken)*sizeof(TCHAR));586 cb += (wcslen(pszToken) + 1) * sizeof(TCHAR); /* Add trailing zero as well. */587 pNewKeyValuePos += wcslen(pszToken) + 1;588 iPos++;589 }590 591 pszToken = pszNewToken;592 }593 594 /* Append as last item if needed. */595 if (uiOrder >= iPos)596 {597 memcpy(pNewKeyValuePos, pszValueToAdd, wcslen(pszValueToAdd)*sizeof(TCHAR));598 cb += wcslen(pszValueToAdd) * sizeof(TCHAR); /* Add trailing zero as well. */599 }600 601 lRet = RegSetValueExW(hKey, pszKeyValue, 0, REG_MULTI_SZ, (LPBYTE)szNewKeyValue, (DWORD)cb);602 if (lRet != ERROR_SUCCESS)603 _tprintf(_T("AddStringToMultiSZ: RegSetValueEx failed with error %ld!\n"), lRet);604 }605 606 RegCloseKey(hKey);607 #ifdef DEBUG608 if (lRet == ERROR_SUCCESS)609 _tprintf(_T("AddStringToMultiSZ: Value %ws successfully written!\n"), pszValueToAdd);610 #endif611 }612 613 return (lRet == ERROR_SUCCESS) ? EXIT_OK : EXIT_FAIL;614 }615 616 /**617 * Removes a string entry from a MULTI_SZ registry list.618 *619 * @return Exit code (EXIT_OK, EXIT_FAIL)620 * @param pszSubKey Sub key containing the list.621 * @param pszKeyValue The actual key name of the list.622 * @param pszValueToRemove The value to remove from the list.623 */624 int RegistryRemoveStringFromMultiSZ(const TCHAR *pszSubKey, const TCHAR *pszKeyValue, const TCHAR *pszValueToRemove)625 {626 /// @todo Make string sizes dynamically allocated!627 628 const TCHAR *pszKey = pszSubKey;629 #ifdef DEBUG630 _tprintf(_T("RemoveStringFromMultiSZ: Removing MULTI_SZ string: %ws from %ws\\%ws ...\n"), pszValueToRemove, pszSubKey, pszKeyValue);631 #endif632 633 HKEY hkey;634 DWORD disp, dwType;635 LONG lRet = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pszKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hkey, &disp);636 if (lRet != ERROR_SUCCESS)637 _tprintf(_T("RemoveStringFromMultiSZ: RegCreateKeyEx %s failed with error %ld!\n"), pszKey, lRet);638 639 if (lRet == ERROR_SUCCESS)640 {641 TCHAR szKeyValue[1024];642 DWORD cbKeyValue = sizeof(szKeyValue);643 644 lRet = RegQueryValueEx(hkey, pszKeyValue, NULL, &dwType, (LPBYTE)szKeyValue, &cbKeyValue);645 if ( lRet != ERROR_SUCCESS646 || dwType != REG_MULTI_SZ)647 {648 _tprintf(_T("RemoveStringFromMultiSZ: RegQueryValueEx failed with %ld, key type = %#lx!\n"), lRet, dwType);649 }650 else651 {652 #ifdef DEBUG653 _tprintf(_T("RemoveStringFromMultiSZ: Current key len: %ld\n"), cbKeyValue);654 #endif655 656 TCHAR szCurString[1024] = { 0 };657 TCHAR szFinalString[1024] = { 0 };658 int iIndex = 0;659 int iNewIndex = 0;660 for (unsigned i = 0; i < cbKeyValue / sizeof(TCHAR); i++)661 {662 if (szKeyValue[i] != _T('\0'))663 szCurString[iIndex++] = szKeyValue[i];664 665 if ( (!szKeyValue[i] == _T('\0'))666 && (szKeyValue[i + 1] == _T('\0')))667 {668 if (NULL == wcsstr(szCurString, pszValueToRemove))669 {670 wcscat(&szFinalString[iNewIndex], szCurString);671 672 if (iNewIndex == 0)673 iNewIndex = iIndex;674 else iNewIndex += iIndex;675 676 szFinalString[++iNewIndex] = _T('\0');677 }678 679 iIndex = 0;680 ZeroMemory(szCurString, sizeof(szCurString));681 }682 }683 szFinalString[++iNewIndex] = _T('\0');684 #ifdef DEBUG685 _tprintf(_T("RemoveStringFromMultiSZ: New key value: %ws (%u bytes)\n"),686 szFinalString, (unsigned)(iNewIndex * sizeof(TCHAR)));687 #endif688 689 lRet = RegSetValueExW(hkey, pszKeyValue, 0, REG_MULTI_SZ, (LPBYTE)szFinalString, iNewIndex * sizeof(TCHAR));690 if (lRet != ERROR_SUCCESS)691 _tprintf(_T("RemoveStringFromMultiSZ: RegSetValueEx failed with %ld!\n"), lRet);692 }693 694 RegCloseKey(hkey);695 #ifdef DEBUG696 if (lRet == ERROR_SUCCESS)697 _tprintf(_T("RemoveStringFromMultiSZ: Value %ws successfully removed!\n"), pszValueToRemove);698 #endif699 }700 701 return (lRet == ERROR_SUCCESS) ? EXIT_OK : EXIT_FAIL;702 }703 704 /**705 * Adds a string to a registry string list (STRING_SZ).706 * Only operates in HKLM for now, needs to be extended later for707 * using other hives. Only processes lists with a "," separator708 * at the moment.709 *710 * @return Exit code (EXIT_OK, EXIT_FAIL)711 * @param pszSubKey Sub key containing the list.712 * @param pszKeyValue The actual key name of the list.713 * @param pszValueToAdd The value to add to the list.714 * @param uiOrder Position (zero-based) of where to add the value to the list.715 * @param dwFlags Flags.716 */717 int RegistryAddStringToList(const TCHAR *pszSubKey, const TCHAR *pszKeyValue, const TCHAR *pszValueToAdd,718 unsigned int uiOrder, DWORD dwFlags)719 {720 HKEY hKey = NULL;721 DWORD disp, dwType;722 LONG lRet = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey, &disp);723 if (lRet != ERROR_SUCCESS)724 _tprintf(_T("RegistryAddStringToList: RegCreateKeyEx %s failed with error %ld!\n"), pszSubKey, lRet);725 726 TCHAR szKeyValue[512] = { 0 };727 TCHAR szNewKeyValue[512] = { 0 };728 DWORD cbKeyValue = sizeof(szKeyValue);729 730 lRet = RegQueryValueEx(hKey, pszKeyValue, NULL, &dwType, (LPBYTE)szKeyValue, &cbKeyValue);731 if ( lRet != ERROR_SUCCESS732 || dwType != REG_SZ)733 {734 _tprintf(_T("RegistryAddStringToList: RegQueryValueEx failed with %ld, key type = %#lx!\n"), lRet, dwType);735 }736 737 if (lRet == ERROR_SUCCESS)738 {739 #ifdef DEBUG740 _tprintf(_T("RegistryAddStringToList: Key value: %ws\n"), szKeyValue);741 #endif742 743 /* Create entire new list. */744 unsigned int iPos = 0;745 TCHAR *pszToken = wcstok(szKeyValue, _T(","));746 TCHAR *pszNewToken = NULL;747 while (pszToken != NULL)748 {749 pszNewToken = wcstok(NULL, _T(","));750 751 /* Append new provider name (at beginning if iOrder=0). */752 if (iPos == uiOrder)753 {754 wcscat(szNewKeyValue, pszValueToAdd);755 wcscat(szNewKeyValue, _T(","));756 iPos++;757 }758 759 BOOL fAddToList = FALSE;760 if ( !wcsicmp(pszToken, pszValueToAdd)761 && (dwFlags & VBOX_REG_STRINGLIST_ALLOW_DUPLICATES))762 fAddToList = TRUE;763 else if (wcsicmp(pszToken, pszValueToAdd))764 fAddToList = TRUE;765 766 if (fAddToList)767 {768 wcscat(szNewKeyValue, pszToken);769 wcscat(szNewKeyValue, _T(","));770 iPos++;771 }772 773 #ifdef DEBUG774 _tprintf (_T("RegistryAddStringToList: Temp new key value: %ws\n"), szNewKeyValue);775 #endif776 pszToken = pszNewToken;777 }778 779 /* Append as last item if needed. */780 if (uiOrder >= iPos)781 wcscat(szNewKeyValue, pszValueToAdd);782 783 /* Last char a delimiter? Cut off ... */784 if (szNewKeyValue[wcslen(szNewKeyValue) - 1] == ',')785 szNewKeyValue[wcslen(szNewKeyValue) - 1] = '\0';786 787 size_t iNewLen = (wcslen(szNewKeyValue) * sizeof(WCHAR)) + sizeof(WCHAR);788 789 #ifdef DEBUG790 _tprintf(_T("RegistryAddStringToList: New provider list: %ws (%u bytes)\n"), szNewKeyValue, (unsigned)iNewLen);791 #endif792 793 lRet = RegSetValueExW(hKey, pszKeyValue, 0, REG_SZ, (LPBYTE)szNewKeyValue, (DWORD)iNewLen);794 if (lRet != ERROR_SUCCESS)795 _tprintf(_T("RegistryAddStringToList: RegSetValueEx failed with %ld!\n"), lRet);796 }797 798 RegCloseKey(hKey);799 return (lRet == ERROR_SUCCESS) ? EXIT_OK : EXIT_FAIL;800 }801 802 /**803 * Removes a string from a registry string list (STRING_SZ).804 * Only operates in HKLM for now, needs to be extended later for805 * using other hives. Only processes lists with a "," separator806 * at the moment.807 *808 * @return Exit code (EXIT_OK, EXIT_FAIL)809 * @param pszSubKey Sub key containing the list.810 * @param pszKeyValue The actual key name of the list.811 * @param pszValueToRemove The value to remove from the list.812 */813 int RegistryRemoveStringFromList(const TCHAR *pszSubKey, const TCHAR *pszKeyValue, const TCHAR *pszValueToRemove)814 {815 HKEY hKey = NULL;816 DWORD disp, dwType;817 LONG lRet = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey, &disp);818 if (lRet != ERROR_SUCCESS)819 _tprintf(_T("RegistryRemoveStringFromList: RegCreateKeyEx %s failed with error %ld!\n"), pszSubKey, lRet);820 821 TCHAR szKeyValue[512] = { 0 };822 TCHAR szNewKeyValue[512] = { 0 };823 DWORD cbKeyValue = sizeof(szKeyValue);824 825 lRet = RegQueryValueEx(hKey, pszKeyValue, NULL, &dwType, (LPBYTE)szKeyValue, &cbKeyValue);826 if ( lRet != ERROR_SUCCESS827 || dwType != REG_SZ)828 {829 _tprintf(_T("RegistryRemoveStringFromList: RegQueryValueEx failed with %ld, key type = %#lx!\n"), lRet, dwType);830 }831 832 if (lRet == ERROR_SUCCESS)833 {834 #ifdef DEBUG835 _tprintf(_T("RegistryRemoveStringFromList: Key value: %ws\n"), szKeyValue);836 #endif837 838 /* Create entire new list. */839 int iPos = 0;840 841 TCHAR *pszToken = wcstok(szKeyValue, _T(","));842 TCHAR *pszNewToken = NULL;843 while (pszToken != NULL)844 {845 pszNewToken = wcstok(NULL, _T(","));846 847 /* Append all list values as long as it's not the848 * value we want to remove. */849 if (wcsicmp(pszToken, pszValueToRemove))850 {851 wcscat(szNewKeyValue, pszToken);852 wcscat(szNewKeyValue, _T(","));853 iPos++;854 }855 856 #ifdef DEBUG857 _tprintf (_T("RegistryRemoveStringFromList: Temp new key value: %ws\n"), szNewKeyValue);858 #endif859 pszToken = pszNewToken;860 }861 862 /* Last char a delimiter? Cut off ... */863 if (szNewKeyValue[wcslen(szNewKeyValue) - 1] == ',')864 szNewKeyValue[wcslen(szNewKeyValue) - 1] = '\0';865 866 size_t iNewLen = (wcslen(szNewKeyValue) * sizeof(WCHAR)) + sizeof(WCHAR);867 868 #ifdef DEBUG869 _tprintf(_T("RegistryRemoveStringFromList: New provider list: %ws (%u bytes)\n"), szNewKeyValue, (unsigned)iNewLen);870 #endif871 872 lRet = RegSetValueExW(hKey, pszKeyValue, 0, REG_SZ, (LPBYTE)szNewKeyValue, (DWORD)iNewLen);873 if (lRet != ERROR_SUCCESS)874 _tprintf(_T("RegistryRemoveStringFromList: RegSetValueEx failed with %ld!\n"), lRet);875 }876 877 RegCloseKey(hKey);878 return (lRet == ERROR_SUCCESS) ? EXIT_OK : EXIT_FAIL;879 }880 881 /**882 * Adds a network provider with a specified order to the system.883 *884 * @return Exit code (EXIT_OK, EXIT_FAIL)885 * @param pszProvider Name of network provider to add.886 * @param uiOrder Position in list (zero-based) of where to add.887 */888 int AddNetworkProvider(const TCHAR *pszProvider, unsigned int uiOrder)889 {890 _tprintf(_T("Adding network provider \"%ws\" (Order = %u) ...\n"), pszProvider, uiOrder);891 int rc = RegistryAddStringToList(_T("System\\CurrentControlSet\\Control\\NetworkProvider\\Order"),892 _T("ProviderOrder"),893 pszProvider, uiOrder, VBOX_REG_STRINGLIST_NONE /* No flags set */);894 if (rc == EXIT_OK)895 _tprintf(_T("Network provider successfully added!\n"));896 return rc;897 }898 899 /**900 * Removes a network provider from the system.901 *902 * @return Exit code (EXIT_OK, EXIT_FAIL)903 * @param pszProvider Name of network provider to remove.904 */905 int RemoveNetworkProvider(const TCHAR *pszProvider)906 {907 _tprintf(_T("Removing network provider \"%ws\" ...\n"), pszProvider);908 int rc = RegistryRemoveStringFromList(_T("System\\CurrentControlSet\\Control\\NetworkProvider\\Order"),909 _T("ProviderOrder"),910 pszProvider);911 if (rc == EXIT_OK)912 _tprintf(_T("Network provider successfully removed!\n"));913 return rc;914 }915 916 int CreateService(const TCHAR *pszStartStopName,917 const TCHAR *pszDisplayName,918 int iServiceType,919 int iStartType,920 const TCHAR *pszBinPath,921 const TCHAR *pszLoadOrderGroup,922 const TCHAR *pszDependencies,923 const TCHAR *pszLogonUser,924 const TCHAR *pszLogonPassword)925 {926 int rc = ERROR_SUCCESS;927 928 _tprintf(_T("Installing service %ws (%ws) ...\n"), pszDisplayName, pszStartStopName);929 930 SC_HANDLE hSCManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);931 if (hSCManager == NULL)932 {933 _tprintf(_T("Could not get handle to SCM! Error: %ld\n"), GetLastError());934 return EXIT_FAIL;935 }936 937 /* Fixup end of multistring. */938 TCHAR szDepend[ _MAX_PATH ] = { 0 }; /** @todo Use dynamically allocated string here! */939 if (pszDependencies != NULL)940 {941 _tcsnccpy (szDepend, pszDependencies, wcslen(pszDependencies));942 DWORD len = (DWORD)wcslen (szDepend);943 szDepend [len + 1] = 0;944 945 /* Replace comma separator on null separator. */946 for (DWORD i = 0; i < len; i++)947 {948 if (',' == szDepend [i])949 szDepend [i] = 0;950 }951 }952 953 DWORD dwTag = 0xDEADBEAF;954 SC_HANDLE hService = CreateService (hSCManager, /* SCManager database handle. */955 pszStartStopName, /* Name of service. */956 pszDisplayName, /* Name to display. */957 SERVICE_ALL_ACCESS, /* Desired access. */958 iServiceType, /* Service type. */959 iStartType, /* Start type. */960 SERVICE_ERROR_NORMAL, /* Error control type. */961 pszBinPath, /* Service's binary. */962 pszLoadOrderGroup, /* Ordering group. */963 (pszLoadOrderGroup != NULL) ? &dwTag : NULL, /* Tag identifier. */964 (pszDependencies != NULL) ? szDepend : NULL, /* Dependencies. */965 (pszLogonUser != NULL) ? pszLogonUser: NULL, /* Account. */966 (pszLogonPassword != NULL) ? pszLogonPassword : NULL); /* Password. */967 if (NULL == hService)968 {969 DWORD dwErr = GetLastError();970 switch (dwErr)971 {972 973 case ERROR_SERVICE_EXISTS:974 {975 _tprintf(_T("Service already exists. No installation required. Updating the service config.\n"));976 977 hService = OpenService (hSCManager, /* SCManager database handle. */978 pszStartStopName, /* Name of service. */979 SERVICE_ALL_ACCESS); /* Desired access. */980 if (NULL == hService)981 {982 dwErr = GetLastError();983 _tprintf(_T("Could not open service! Error: %ld\n"), dwErr);984 }985 else986 {987 BOOL fResult = ChangeServiceConfig (hService, /* Service handle. */988 iServiceType, /* Service type. */989 iStartType, /* Start type. */990 SERVICE_ERROR_NORMAL, /* Error control type. */991 pszBinPath, /* Service's binary. */992 pszLoadOrderGroup, /* Ordering group. */993 (pszLoadOrderGroup != NULL) ? &dwTag : NULL, /* Tag identifier. */994 (pszDependencies != NULL) ? szDepend : NULL, /* Dependencies. */995 (pszLogonUser != NULL) ? pszLogonUser: NULL, /* Account. */996 (pszLogonPassword != NULL) ? pszLogonPassword : NULL, /* Password. */997 pszDisplayName); /* Name to display. */998 if (fResult)999 _tprintf(_T("The service config has been successfully updated.\n"));1000 1749 else 1001 { 1002 dwErr = GetLastError(); 1003 _tprintf(_T("Could not change service config! Error: %ld\n"), dwErr); 1004 } 1005 CloseServiceHandle(hService); 1006 } 1007 1008 /* 1009 * This entire branch do not return an error to avoid installations failures, 1010 * if updating service parameters. Better to have a running system with old 1011 * parameters and the failure information in the installation log. 1012 */ 1013 break; 1014 } 1015 1016 case ERROR_INVALID_PARAMETER: 1017 1018 _tprintf(_T("Invalid parameter specified!\n")); 1019 rc = EXIT_FAIL; 1020 break; 1021 1022 default: 1023 1024 _tprintf(_T("Could not create service! Error: %ld\n"), dwErr); 1025 rc = EXIT_FAIL; 1026 break; 1027 } 1028 1029 if (rc == EXIT_FAIL) 1030 goto cleanup; 1031 } 1032 else 1033 { 1034 CloseServiceHandle (hService); 1035 _tprintf(_T("Installation of service successful!\n")); 1036 } 1037 1038 cleanup: 1039 1040 if (hSCManager != NULL) 1041 CloseServiceHandle (hSCManager); 1042 1043 return rc; 1044 } 1045 1046 int DelService(const TCHAR *pszStartStopName) 1047 { 1048 int rc = ERROR_SUCCESS; 1049 1050 _tprintf(_T("Deleting service '%ws' ...\n"), pszStartStopName); 1051 1052 SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); 1053 SC_HANDLE hService = NULL; 1054 if (hSCManager == NULL) 1055 { 1056 _tprintf(_T("Could not get handle to SCM! Error: %ld\n"), GetLastError()); 1057 rc = EXIT_FAIL; 1058 } 1059 else 1060 { 1061 hService = OpenService(hSCManager, pszStartStopName, SERVICE_ALL_ACCESS); 1062 if (NULL == hService) 1063 { 1064 _tprintf(_T("Could not open service '%ws'! Error: %ld\n"), pszStartStopName, GetLastError()); 1065 rc = EXIT_FAIL; 1066 } 1067 } 1068 1069 if (hService != NULL) 1070 { 1071 SC_LOCK hSCLock = LockServiceDatabase(hSCManager); 1072 if (hSCLock != NULL) 1073 { 1074 if (FALSE == DeleteService(hService)) 1075 { 1076 DWORD dwErr = GetLastError(); 1077 switch (dwErr) 1078 { 1079 1080 case ERROR_SERVICE_MARKED_FOR_DELETE: 1081 1082 _tprintf(_T("Service '%ws' already marked for deletion.\n"), pszStartStopName); 1083 break; 1084 1085 default: 1086 1087 _tprintf(_T("Could not delete service '%ws'! Error: %ld\n"), pszStartStopName, GetLastError()); 1088 rc = EXIT_FAIL; 1089 break; 1090 } 1091 } 1092 else 1093 { 1094 _tprintf(_T("Service '%ws' successfully removed!\n"), pszStartStopName); 1750 rcExit = ErrorMsgLastErrSWS("Failed to delete service'", pwszService, "'!"); 1095 1751 } 1096 1752 UnlockServiceDatabase(hSCLock); 1097 1753 } 1098 1754 else 1755 ErrorMsgLastErr("LockServiceDatabase failed"); 1756 CloseServiceHandle(hService); 1757 } 1758 else 1759 rcExit = ErrorMsgLastErrSWS("Failed to open service'", pwszService, "'!"); 1760 CloseServiceHandle(hSCManager); 1761 return rcExit; 1762 } 1763 1764 1765 /** Handles 'service delete' */ 1766 static int handleServiceDelete(unsigned cArgs, wchar_t **papwszArgs) 1767 { 1768 RT_NOREF(cArgs); 1769 return DelService(papwszArgs[0]); 1770 } 1771 1772 1773 static HKEY ArgToRegistryRoot(const wchar_t *pwszRoot) 1774 { 1775 HKEY hRootKey = NULL; 1776 if (RTUtf16ICmpAscii(pwszRoot, "hklm") == 0) 1777 hRootKey = HKEY_LOCAL_MACHINE; 1778 else if (RTUtf16ICmpAscii(pwszRoot, "hkcu") == 0) 1779 hRootKey = HKEY_CURRENT_USER; 1780 else if (RTUtf16ICmpAscii(pwszRoot, "hkcr") == 0) 1781 hRootKey = HKEY_CLASSES_ROOT; 1782 else if (RTUtf16ICmpAscii(pwszRoot, "hku") == 0) 1783 hRootKey = HKEY_USERS; 1784 else if (RTUtf16ICmpAscii(pwszRoot, "hkcc") == 0) 1785 hRootKey = HKEY_CURRENT_CONFIG; 1786 else 1787 ErrorBadArg("root", pwszRoot, "hklm, hkcu, hkcr, hku or hkcc"); 1788 return hRootKey; 1789 } 1790 1791 1792 /** 1793 * Handles 'registry write'. 1794 */ 1795 static int handleRegistryWrite(unsigned cArgs, wchar_t **papwszArgs) 1796 { 1797 /* 1798 * Mandatory parameters. 1799 */ 1800 wchar_t const * const pwszRoot = papwszArgs[0]; 1801 wchar_t const * const pwszSubKey = papwszArgs[1]; 1802 wchar_t const * const pwszValueName = papwszArgs[2]; 1803 wchar_t const * const pwszType = papwszArgs[3]; 1804 wchar_t const * const pwszValue = papwszArgs[4]; 1805 1806 /* 1807 * Root key: 1808 */ 1809 HKEY hRootKey = ArgToRegistryRoot(papwszArgs[0]); 1810 if (hRootKey == NULL) 1811 return EXIT_USAGE; 1812 1813 /* 1814 * Type and value with default length. 1815 */ 1816 union 1817 { 1818 uint32_t dw; 1819 uint64_t qw; 1820 } uValue; 1821 DWORD dwType; 1822 DWORD cbValue; 1823 BYTE const *pbValue; 1824 if ( RTUtf16ICmpAscii(pwszType, "REG_BINARY") == 0 1825 || RTUtf16ICmpAscii(pwszType, "REG_BIN") == 0 1826 || RTUtf16ICmpAscii(pwszType, "BINARY") == 0) 1827 { 1828 dwType = REG_BINARY; 1829 cbValue = (DWORD)(RTUtf16Len(pwszValue) + 1) * sizeof(wchar_t); 1830 pbValue = (BYTE const *)pwszValue; 1831 } 1832 else if ( RTUtf16ICmpAscii(pwszType, "REG_DWORD") == 0 1833 || RTUtf16ICmpAscii(pwszType, "DWORD") == 0) 1834 { 1835 if (!ArgToUInt32Full(pwszValue, "dword value", &uValue.dw)) 1836 return EXIT_USAGE; 1837 dwType = REG_DWORD; 1838 pbValue = (BYTE const *)&uValue.dw; 1839 cbValue = sizeof(uValue.dw); 1840 } 1841 else if ( RTUtf16ICmpAscii(pwszType, "REG_QWORD") == 0 1842 || RTUtf16ICmpAscii(pwszType, "QWORD") == 0) 1843 { 1844 if (!ArgToUInt64Full(pwszValue, "qword value", &uValue.qw)) 1845 return EXIT_USAGE; 1846 dwType = REG_QWORD; 1847 pbValue = (BYTE const *)&uValue.qw; 1848 cbValue = sizeof(uValue.qw); 1849 } 1850 else if ( RTUtf16ICmpAscii(pwszType, "REG_SZ") == 0 1851 || RTUtf16ICmpAscii(pwszType, "SZ") == 0) 1852 { 1853 dwType = REG_SZ; 1854 cbValue = (DWORD)((RTUtf16Len(pwszValue) + 1) * sizeof(wchar_t)); 1855 pbValue = (BYTE const *)pwszValue; 1856 } 1857 else 1858 return ErrorBadArg("type", pwszType, ""); 1859 1860 /* 1861 * Binary only: Reinterpret the input as - optional. 1862 */ 1863 if (cArgs > 5) 1864 { 1865 if (dwType != REG_BINARY) 1866 return ErrorMsg("The 'binary-conversion' argument is currently only supported for REG_BINARY type values!"); 1867 if (RTUtf16ICmpAscii(papwszArgs[5], "dword") == 0) 1099 1868 { 1100 _tprintf(_T("Unable to lock service database! Error: %ld\n"), GetLastError()); 1101 rc = EXIT_FAIL; 1869 if (!ArgToUInt32Full(pwszValue, "dword(/binary) value", &uValue.dw)) 1870 return EXIT_USAGE; 1871 pbValue = (BYTE const *)&uValue.dw; 1872 cbValue = sizeof(uValue.dw); 1102 1873 } 1103 CloseServiceHandle(hService); 1104 } 1105 1106 if (hSCManager != NULL) 1107 CloseServiceHandle(hSCManager); 1108 1109 return rc; 1110 } 1111 1112 DWORD RegistryWrite(HKEY hRootKey, 1113 const _TCHAR *pszSubKey, 1114 const _TCHAR *pszValueName, 1115 DWORD dwType, 1116 const BYTE *pbData, 1117 DWORD cbData) 1118 { 1119 DWORD lRet; 1120 HKEY hKey; 1121 lRet = RegCreateKeyEx (hRootKey, 1122 pszSubKey, 1123 0, /* Reserved */ 1124 NULL, /* lpClass [in, optional] */ 1125 0, /* dwOptions [in] */ 1126 KEY_WRITE, 1127 NULL, /* lpSecurityAttributes [in, optional] */ 1128 &hKey, 1129 NULL); /* lpdwDisposition [out, optional] */ 1130 if (lRet != ERROR_SUCCESS) 1131 { 1132 _tprintf(_T("Could not open registry key! Error: %ld\n"), GetLastError()); 1133 } 1134 else 1135 { 1136 lRet = RegSetValueEx(hKey, pszValueName, 0, dwType, (BYTE*)pbData, cbData); 1137 if (lRet != ERROR_SUCCESS) 1138 _tprintf(_T("Could not write to registry! Error: %ld\n"), GetLastError()); 1874 else if (RTUtf16ICmpAscii(papwszArgs[5], "qword") == 0) 1875 { 1876 if (!ArgToUInt64Full(pwszValue, "qword(/binary) value", &uValue.qw)) 1877 return EXIT_USAGE; 1878 pbValue = (BYTE const *)&uValue.qw; 1879 cbValue = sizeof(uValue.qw); 1880 } 1881 else 1882 return ErrorBadArg("binary-conversion", papwszArgs[0], "dword"); 1883 } 1884 1885 /* 1886 * Binary only: Max length to write - optional. 1887 */ 1888 if (cArgs> 6) 1889 { 1890 if (dwType != REG_BINARY) 1891 return ErrorMsg("The 'max-size' argument is currently only supported for REG_BINARY type values!"); 1892 uint32_t cbMaxValue; 1893 if (!ArgToUInt32Full(papwszArgs[6], "max-size", &cbMaxValue)) 1894 return EXIT_USAGE; 1895 if (cbValue > cbMaxValue) 1896 cbValue = cbMaxValue; 1897 } 1898 1899 /* 1900 * Do the writing. 1901 */ 1902 HKEY hKey = NULL; 1903 LSTATUS lrc = RegCreateKeyExW(hRootKey, pwszSubKey, 0 /*Reserved*/, NULL /*pwszClass*/, 0 /*dwOptions*/, 1904 KEY_WRITE, NULL /*pSecAttr*/, &hKey, NULL /*pdwDisposition*/); 1905 if (lrc != ERROR_SUCCESS) 1906 return ErrorMsgLStatusSWSWSRS("RegCreateKeyExW ", pwszRoot, "/'", pwszSubKey, "' failed: ", lrc, NULL); 1907 1908 lrc = RegSetValueExW(hKey, pwszValueName, 0, dwType, pbValue, cbValue); 1909 RegCloseKey(hKey); 1910 if (lrc != ERROR_SUCCESS) 1911 return ErrorMsgLStatusSWSWSWSRS("RegSetValueExW ", pwszRoot, "/'", pwszSubKey, "'/'", 1912 pwszValueName, "' failed: ", lrc, NULL); 1913 return EXIT_OK; 1914 } 1915 1916 1917 /** 1918 * Handles 'registry delete'. 1919 */ 1920 static int handleRegistryDelete(unsigned cArgs, wchar_t **papwszArgs) 1921 { 1922 /* 1923 * Parameters. 1924 */ 1925 RT_NOREF(cArgs); 1926 wchar_t const * const pwszRoot = papwszArgs[0]; 1927 wchar_t const * const pwszSubKey = papwszArgs[1]; 1928 wchar_t const * const pwszValueName = papwszArgs[2]; 1929 1930 HKEY const hRootKey = ArgToRegistryRoot(pwszRoot); 1931 if (hRootKey == NULL) 1932 return EXIT_USAGE; 1933 1934 /* 1935 * Do the deleting. 1936 */ 1937 HKEY hKey = NULL; 1938 LSTATUS lrc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, papwszArgs[1] /*pwszSubKey*/, 0 /*dwOptions*/, KEY_READ | KEY_WRITE, &hKey); 1939 if (lrc != ERROR_FILE_NOT_FOUND) 1940 { 1941 if (lrc != ERROR_SUCCESS) 1942 return ErrorMsgLStatusSWSWSRS("RegOpenKeyExW ", pwszRoot, "/'", pwszSubKey, "' failed: ", lrc, NULL); 1943 1944 lrc = RegDeleteValueW(hKey, pwszValueName); 1139 1945 RegCloseKey(hKey); 1140 1141 } 1142 return lRet; 1143 } 1144 1145 void PrintHelp(void) 1146 { 1147 _tprintf(_T("VirtualBox Guest Additions Installation Helper for Windows\n")); 1148 _tprintf(_T("Version: %d.%d.%d.%d\n\n"), VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV); 1149 _tprintf(_T("Syntax:\n")); 1150 _tprintf(_T("\n")); 1151 _tprintf(_T("Drivers:\n")); 1152 _tprintf(_T("\tVBoxDrvInst driver install <inf-file> [log file]\n")); 1153 _tprintf(_T("\tVBoxDrvInst driver uninstall <inf-file> [log file]\n")); 1154 _tprintf(_T("\tVBoxDrvInst driver executeinf <inf-file>\n")); 1155 _tprintf(_T("\n")); 1156 _tprintf(_T("Network Provider:\n")); 1157 _tprintf(_T("\tVBoxDrvInst netprovider add <name> [order]\n")); 1158 _tprintf(_T("\tVBoxDrvInst netprovider remove <name>\n")); 1159 _tprintf(_T("\n")); 1160 _tprintf(_T("Registry:\n")); 1161 _tprintf(_T("\tVBoxDrvInst registry write <root> <sub key>\n") 1162 _T("\t <key name> <key type> <value>\n") 1163 _T("\t [type] [size]\n")); 1164 _tprintf(_T("\tVBoxDrvInst registry addmultisz <root> <sub key>\n") 1165 _T("\t <value> [order]\n")); 1166 _tprintf(_T("\tVBoxDrvInst registry delmultisz <root> <sub key>\n") 1167 _T("\t <key name> <value to remove>\n")); 1168 /** @todo Add "service" category! */ 1169 _tprintf(_T("\n")); 1170 } 1171 1172 int __cdecl _tmain(int argc, _TCHAR *argv[]) 1173 { 1174 int rc = EXIT_USAGE; 1175 1176 OSVERSIONINFO OSinfo; 1177 OSinfo.dwOSVersionInfoSize = sizeof(OSinfo); 1178 GetVersionEx(&OSinfo); 1179 1946 if (lrc != ERROR_SUCCESS && lrc != ERROR_FILE_NOT_FOUND) 1947 return ErrorMsgLStatusSWSWSWSRS("RegDeleteValueW ", pwszRoot, "/'", pwszSubKey, "'/'", 1948 pwszValueName, "' failed: ", lrc, NULL); 1949 } 1950 return EXIT_OK; 1951 } 1952 1953 1954 /** Handles 'version' and its aliases. */ 1955 static int handleVersion(unsigned cArgs, wchar_t **papwszArgs) 1956 { 1957 PrintStr(RT_XSTR(VBOX_VERSION_MAJOR) "." RT_XSTR(VBOX_VERSION_MINOR) "." RT_XSTR(VBOX_VERSION_BUILD) "r" RT_XSTR(VBOX_SVN_REV) "\r\n"); 1958 RT_NOREF(cArgs, papwszArgs); 1959 return EXIT_OK; 1960 } 1961 1962 1963 /** Handles 'help' and all its aliases. */ 1964 static int handleHelp(unsigned cArgs, wchar_t **papwszArgs) 1965 { 1966 /* "0 1 2 3 4 5 6 7 8 */ 1967 /* "012345678901234567890123456789012345678901234567890123456789012345678901234567890 */ 1968 PrintStr("VirtualBox Guest Additions Installation Helper for Windows\r\n" 1969 "Version: " RT_XSTR(VBOX_VERSION_MAJOR) "." RT_XSTR(VBOX_VERSION_MINOR) "." RT_XSTR(VBOX_VERSION_BUILD) "r" RT_XSTR(VBOX_SVN_REV) "\r\n" 1970 "\r\n" 1971 "Syntax: VBoxDrvInst <command> <subcommand>\r\n" 1972 "\r\n" 1973 "Drivers:\r\n" 1974 " VBoxDrvInst driver install <inf-file> [log-file]\r\n" 1975 " VBoxDrvInst driver uninstall <inf-file> [log-file]\r\n" 1976 " VBoxDrvInst driver executeinf <inf-file>\r\n" 1977 "\r\n" 1978 "Service:\r\n" 1979 " VBoxDrvInst service create <name> <display-name> <service-type>\r\n" 1980 " <start-type> <binary-path> [load-order] [deps] [user] [password]\r\n" 1981 " VBoxDrvInst service delete <name>\r\n" 1982 "\r\n" 1983 "Network Provider:\r\n" 1984 " VBoxDrvInst netprovider add <name> <position>\r\n" 1985 " VBoxDrvInst netprovider remove <name>\r\n" 1986 "\r\n" 1987 "Registry:\r\n" 1988 " VBoxDrvInst registry write <root> <sub-key> <value-name> <type> <value>\r\n" 1989 " [binary-conversion] [max-size]\r\n" 1990 " VBoxDrvInst registry delete <root> <sub-key> <value-name>\r\n" 1991 /** @todo Add roots for these two. */ 1992 " VBoxDrvInst registry addmultisz <sub-key> <value-name> <to-add> <position>\r\n" 1993 " VBoxDrvInst registry delmultisz <sub-key> <value-name> <to-remove>\r\n" 1994 "\r\n" 1995 "Standard options:\r\n" 1996 " VBoxDrvInst [help|--help|/help|-h|/h|-?|/h] [...]\r\n" 1997 " VBoxDrvInst [version|--version|-V]\r\n" 1998 ); 1999 RT_NOREF(cArgs, papwszArgs); 2000 return EXIT_OK; 2001 } 2002 2003 2004 int wmain(int argc, wchar_t **argv) 2005 { 2006 /* Not initializing IPRT here, ASSUMING the little bit we use of it does 2007 not need any initialization. Reduces the binary size a little. */ 2008 2009 static struct 2010 { 2011 const char *pszCmd; 2012 const char *pszSubCmd; 2013 unsigned cMin, cMax; 2014 int (*pfnHandler)(unsigned cArgs, wchar_t **papwszArgs); 2015 } s_aActions[] = 2016 { 2017 { "driver", "install", 1, 2, handleDriverInstall }, 2018 { "driver", "uninstall", 1, 2, handleDriverUninstall }, 2019 { "driver", "executeinf", 1, 1, handleDriverExecuteInf }, 2020 { "netprovider", "add", 1, 2, handleNetProviderAdd }, 2021 { "netprovider", "remove", 1, 2, handleNetProviderRemove }, 2022 { "service", "create", 5, 9, handleServiceCreate }, 2023 { "service", "delete", 1, 1, handleServiceDelete }, 2024 { "registry", "addmultisz", 4, 4, handleRegistryAddMultiSz }, 2025 { "registry", "delmultisz", 3, 3, handleRegistryDelMultiSz }, 2026 { "registry", "write", 5, 7, handleRegistryWrite }, 2027 { "registry", "delete", 3, 3, handleRegistryDelete }, 2028 2029 { "help", NULL, 0, ~0U, handleHelp }, 2030 { "--help", NULL, 0, ~0U, handleHelp }, 2031 { "/help", NULL, 0, ~0U, handleHelp }, 2032 { "-h", NULL, 0, ~0U, handleHelp }, 2033 { "/h", NULL, 0, ~0U, handleHelp }, 2034 { "-?", NULL, 0, ~0U, handleHelp }, 2035 { "/?", NULL, 0, ~0U, handleHelp }, 2036 { "version", NULL, 0, ~0U, handleVersion }, 2037 { "--version", NULL, 0, ~0U, handleVersion }, 2038 { "-V", NULL, 0, ~0U, handleVersion }, 2039 }; 2040 2041 /* 2042 * Lookup the action handler. 2043 */ 2044 int rcExit = EXIT_USAGE; 1180 2045 if (argc >= 2) 1181 2046 { 1182 if ( !_tcsicmp(argv[1], _T("driver"))1183 && argc >= 3)1184 {1185 _TCHAR szINF[_MAX_PATH] = { 0 }; /* Complete path to INF file.*/1186 if ( ( !_tcsicmp(argv[2], _T("install"))1187 || !_tcsicmp(argv[2], _T("uninstall")))1188 && argc >= 4)2047 const wchar_t * const pwszCmd = argv[1]; 2048 const wchar_t * const pwszSubCmd = argc > 2 ? argv[2] : NULL; 2049 unsigned i = 0; 2050 for (i = 0; i < RT_ELEMENTS(s_aActions); i++) 2051 if ( RTUtf16ICmpAscii(pwszCmd, s_aActions[i].pszCmd) == 0 2052 && ( !s_aActions[i].pszSubCmd 2053 || RTUtf16ICmpAscii(pwszSubCmd, s_aActions[i].pszSubCmd) == 0)) 1189 2054 { 1190 if (OSinfo.dwMajorVersion < 5) 1191 { 1192 _tprintf(_T("ERROR: Platform not supported for driver (un)installation!\n")); 1193 rc = EXIT_FAIL; 1194 } 2055 unsigned const cArgs = (unsigned)argc - (s_aActions[i].pszSubCmd ? 3 : 2); 2056 wchar_t ** const papwszArgs = &argv[s_aActions[i].pszSubCmd ? 3 : 2]; 2057 if (cArgs >= s_aActions[i].cMin && cArgs <= s_aActions[i].cMax) 2058 rcExit = s_aActions[i].pfnHandler(cArgs, papwszArgs); 1195 2059 else 1196 2060 { 1197 _sntprintf(szINF, sizeof(szINF) / sizeof(TCHAR), _T("%ws"), argv[3]); 1198 1199 _TCHAR szLogFile[_MAX_PATH] = { 0 }; 1200 if (argc > 4) 1201 _sntprintf(szLogFile, sizeof(szLogFile) / sizeof(TCHAR), _T("%ws"), argv[4]); 1202 rc = VBoxInstallDriver(!_tcsicmp(argv[2], _T("install")) ? TRUE : FALSE, szINF, 1203 FALSE /* Not silent */, szLogFile[0] != NULL ? szLogFile : NULL); 2061 bool const fTooFew = cArgs < s_aActions[i].cMin; 2062 ErrorMsgBegin(fTooFew ? "Too few parameters for '" : "Too many parameters for '"); 2063 ErrorMsgStr(s_aActions[i].pszCmd); 2064 if (s_aActions[i].pszSubCmd) 2065 { 2066 ErrorMsgStr(" "); 2067 ErrorMsgStr(s_aActions[i].pszSubCmd); 2068 } 2069 ErrorMsgStr("'! Got "); 2070 ErrorMsgU64(cArgs); 2071 ErrorMsgStr(fTooFew ? ", expected at least " : ", expected at most ");; 2072 ErrorMsgU64(fTooFew ? s_aActions[i].cMin : s_aActions[i].cMax); 2073 ErrorMsgEnd("."); 1204 2074 } 2075 break; 1205 2076 } 1206 else if ( !_tcsicmp(argv[2], _T("executeinf")) 1207 && argc == 4) 2077 if (i >= RT_ELEMENTS(s_aActions)) 2078 { 2079 ErrorMsgBegin("Unknown action '"); 2080 ErrorMsgWStr(pwszCmd); 2081 if (pwszSubCmd) 1208 2082 { 1209 _sntprintf(szINF, sizeof(szINF) / sizeof(TCHAR), _T("%ws"), argv[3]);1210 rc = ExecuteInfFile(_T("DefaultInstall"), 132, szINF);2083 ErrorMsgBegin(" "); 2084 ErrorMsgWStr(pwszSubCmd); 1211 2085 } 2086 ErrorMsgEnd("'! Please consult \"--help\" for more information.\r\n"); 1212 2087 } 1213 else if ( !_tcsicmp(argv[1], _T("netprovider")) 1214 && argc >= 3) 1215 { 1216 _TCHAR szProvider[_MAX_PATH] = { 0 }; /* The network provider name for the registry. */ 1217 if ( !_tcsicmp(argv[2], _T("add")) 1218 && argc >= 4) 1219 { 1220 int iOrder = 0; 1221 if (argc > 4) 1222 iOrder = _ttoi(argv[4]); 1223 _sntprintf(szProvider, sizeof(szProvider) / sizeof(TCHAR), _T("%ws"), argv[3]); 1224 rc = AddNetworkProvider(szProvider, iOrder); 1225 } 1226 else if ( !_tcsicmp(argv[2], _T("remove")) 1227 && argc >= 4) 1228 { 1229 _sntprintf(szProvider, sizeof(szProvider) / sizeof(TCHAR), _T("%ws"), argv[3]); 1230 rc = RemoveNetworkProvider(szProvider); 1231 } 1232 } 1233 else if ( !_tcsicmp(argv[1], _T("service")) 1234 && argc >= 3) 1235 { 1236 if ( !_tcsicmp(argv[2], _T("create")) 1237 && argc >= 8) 1238 { 1239 rc = CreateService(argv[3], 1240 argv[4], 1241 _ttoi(argv[5]), 1242 _ttoi(argv[6]), 1243 argv[7], 1244 (argc > 8) ? argv[8] : NULL, 1245 (argc > 9) ? argv[9] : NULL, 1246 (argc > 10) ? argv[10] : NULL, 1247 (argc > 11) ? argv[11] : NULL); 1248 } 1249 else if ( !_tcsicmp(argv[2], _T("delete")) 1250 && argc == 4) 1251 { 1252 rc = DelService(argv[3]); 1253 } 1254 } 1255 else if ( !_tcsicmp(argv[1], _T("registry")) 1256 && argc >= 3) 1257 { 1258 /** @todo add a handleRegistry(argc, argv) method to keep things cleaner */ 1259 if ( !_tcsicmp(argv[2], _T("addmultisz")) 1260 && argc == 7) 1261 { 1262 rc = RegistryAddStringToMultiSZ(argv[3], argv[4], argv[5], _ttoi(argv[6])); 1263 } 1264 else if ( !_tcsicmp(argv[2], _T("delmultisz")) 1265 && argc == 6) 1266 { 1267 rc = RegistryRemoveStringFromMultiSZ(argv[3], argv[4], argv[5]); 1268 } 1269 else if ( !_tcsicmp(argv[2], _T("write")) 1270 && argc >= 8) 1271 { 1272 HKEY hRootKey = HKEY_LOCAL_MACHINE; /** @todo needs to be expanded (argv[3]) */ 1273 DWORD dwValSize = 0; 1274 BYTE *pbVal = NULL; 1275 DWORD dwVal; 1276 1277 if (argc > 8) 1278 { 1279 if (!_tcsicmp(argv[8], _T("dword"))) 1280 { 1281 dwVal = _ttol(argv[7]); 1282 pbVal = (BYTE*)&dwVal; 1283 dwValSize = sizeof(DWORD); 1284 } 1285 } 1286 if (pbVal == NULL) /* By default interpret value as string */ 1287 { 1288 pbVal = (BYTE *)argv[7]; 1289 dwValSize = (DWORD)_tcslen(argv[7]); 1290 } 1291 if (argc > 9) 1292 dwValSize = _ttol(argv[9]); /* Get the size in bytes of the value we want to write */ 1293 rc = RegistryWrite(hRootKey, 1294 argv[4], /* Sub key */ 1295 argv[5], /* Value name */ 1296 REG_BINARY, /** @todo needs to be expanded (argv[6]) */ 1297 pbVal, /* The value itself */ 1298 dwValSize); /* Size of the value */ 1299 } 1300 #if 0 1301 else if (!_tcsicmp(argv[2], _T("read"))) 1302 { 1303 } 1304 else if (!_tcsicmp(argv[2], _T("del"))) 1305 { 1306 } 2088 } 2089 else 2090 ErrorMsg("No parameters given. Please consult \"--help\" for more information.\r\n"); 2091 return rcExit; 2092 } 2093 2094 2095 #ifdef IPRT_NO_CRT 2096 int main(int argc, char **argv) 2097 { 2098 /* 2099 * Convert the arguments to UTF16 and call wmain. We don't bother freeing 2100 * any of these strings as the process is exiting and it's a waste of time. 2101 */ 2102 wchar_t **papwszArgs = (wchar_t **)alloca((argc + 1) * sizeof(wchar_t *)); 2103 int i = 0; 2104 while (i < argc) 2105 { 2106 papwszArgs[i] = NULL; 2107 int rc = RTStrToUtf16(argv[i], &papwszArgs[i]); 2108 if (RT_SUCCESS(rc)) 2109 i++; 2110 else 2111 return ErrorMsg("Failed to convert command line arguments to UTF16!!"); 2112 } 2113 papwszArgs[i] = NULL; 2114 return wmain(argc, papwszArgs); 2115 } 1307 2116 #endif 1308 } 1309 else if (!_tcsicmp(argv[1], _T("--version"))) 1310 { 1311 _tprintf(_T("%d.%d.%d.%d\n"), VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV); 1312 rc = EXIT_OK; 1313 } 1314 else if ( !_tcsicmp(argv[1], _T("--help")) 1315 || !_tcsicmp(argv[1], _T("/help")) 1316 || !_tcsicmp(argv[1], _T("/h")) 1317 || !_tcsicmp(argv[1], _T("/?"))) 1318 { 1319 PrintHelp(); 1320 rc = EXIT_OK; 1321 } 1322 } 1323 1324 if (rc == EXIT_USAGE) 1325 _tprintf(_T("No or wrong parameters given! Please consult the help (\"--help\" or \"/?\") for more information.\n")); 1326 1327 return rc; 1328 } 1329 2117
Note:
See TracChangeset
for help on using the changeset viewer.