VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Installer/VBoxAddInstallNt3x.cpp@ 93115

Last change on this file since 93115 was 93115, checked in by vboxsync, 2 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.8 KB
Line 
1/* $Id: VBoxAddInstallNt3x.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * VBoxAddInstallNt3x - Install Guest Additions on NT3.51, 3.5 and 3.1.
4 */
5
6/*
7 * Copyright (C) 2020-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#include <iprt/nt/nt-and-windows.h>
23#include <iprt/ctype.h>
24#include <iprt/getopt.h>
25#include <iprt/message.h>
26#include <iprt/path.h>
27#include <iprt/stream.h>
28#include <iprt/string.h>
29#include <iprt/utf16.h>
30
31#include <VBox/version.h>
32#include <revision-generated.h> /* VBOX_SVN_REV. */
33
34
35
36/*********************************************************************************************************************************
37* Structures and Typedefs *
38*********************************************************************************************************************************/
39/** Components (also indexes into g_aComponents). */
40typedef enum { kComp_VBoxGuest = 0, kComp_VBoxService = 1, kComp_VBoxMouse = 2} VBOXGACOMP;
41/** File status. */
42typedef enum { kFile_NotFound, kFile_LongName, kFile_8Dot3, kFile_Both, kFile_Mismatch } VBOXGAFILE;
43
44
45/*********************************************************************************************************************************
46* Defined Constants And Macros *
47*********************************************************************************************************************************/
48/** The components. */
49struct
50{
51 const char *pszName;
52 VBOXGACOMP enmComp;
53 bool fSelected;
54
55 bool fDriverFile;
56 const wchar_t *pwszFilename;
57 const wchar_t *pwsz8Dot3;
58 const wchar_t *pwszServiceName;
59 const wchar_t *pwszServiceDesc;
60 const wchar_t *pwszServiceLoadOrderGroup;
61
62 /** @name Status
63 * @{ */
64 VBOXGAFILE enmFileStatus;
65 bool fServiceInstalled;
66 bool fMisconfigured;
67 bool fActive;
68 VBOXGAFILE enmServiceFile;
69 wchar_t wszServiceImagePath[MAX_PATH];
70 /** @} */
71
72} g_aComponents[] =
73{
74 {
75 "VBoxGuest", kComp_VBoxGuest, true, true, L"VBoxGuest.sys", L"VBoxGst.sys",
76 L"VBoxGuest", L"VirtualBox Guest Additions Driver", L"System",
77 kFile_NotFound, false, false, false, kFile_NotFound, {0},
78 },
79 {
80 "VBoxService", kComp_VBoxService, true, false, L"VBoxService.exe", L"VBoxGaSv.exe",
81 L"VBoxService", L"VirtualBox Guest Additions Service", L"Base",
82 kFile_NotFound, false, false, false, kFile_NotFound, {0},
83 },
84 {
85 "VBoxMouse", kComp_VBoxMouse, true, true, L"VBoxMouseNT.sys", L"VBoxMou.sys",
86 L"i8042prt", L"i8042prt", L"Pointer Port",
87 kFile_NotFound, true, false, false, kFile_NotFound, {0},
88 },
89};
90
91/** The source path where the files are. */
92static WCHAR g_wszSrc[MAX_PATH];
93static size_t g_cwcSrc = 0;
94
95#define MAKE_SANE_VERSION(a_uMajor, a_uMinor) RT_MAKE_U32(a_uMinor, a_uMajor)
96static uint32_t g_uSaneVersion = MAKE_SANE_VERSION(3,51);
97static DWORD g_dwVersion = 3 | (51 << 8);
98
99
100RTDECL(PRTUTF16) RTUtf16ToLowerAscii(PRTUTF16 pwsz)
101{
102 for (PRTUTF16 pwc = pwsz; *pwc; pwc++)
103 if (*pwc < 0x7f)
104 *pwc = RT_C_TO_LOWER(*pwc);
105 return pwsz;
106}
107
108
109/**
110 * Composes the service binary path for component.
111 */
112static WCHAR *ComposeServicePath(WCHAR *pwszPath, size_t cwcPath, size_t iComponent, bool f8Dot3)
113{
114 static wchar_t const s_wszPrefixDrv[] = L"\\SystemRoot\\System32\\drivers\\";
115 static wchar_t const s_wszPrefixExe[] = L"%SystemRoot%\\System32\\";
116 size_t cwcDst;
117 if (g_aComponents[iComponent].fDriverFile)
118 {
119 RTUtf16Copy(pwszPath, cwcPath, s_wszPrefixDrv);
120 cwcDst = RT_ELEMENTS(s_wszPrefixDrv) - 1;
121 }
122 else
123 {
124 RTUtf16Copy(pwszPath, cwcPath, s_wszPrefixExe);
125 cwcDst = RT_ELEMENTS(s_wszPrefixExe) - 1;
126 }
127
128 RTUtf16Copy(&pwszPath[cwcDst], cwcPath - cwcDst,
129 f8Dot3 ? g_aComponents[iComponent].pwsz8Dot3 : g_aComponents[iComponent].pwszFilename);
130 return pwszPath;
131}
132
133
134/**
135 * Composes the installed filename for a component.
136 */
137static int ComposeFilename(WCHAR *pwszPath, size_t cwcPath, size_t iComponent, bool f8Dot3)
138{
139 UINT cwcDst = GetSystemDirectoryW(pwszPath, cwcPath - 30);
140 if (cwcDst > 0)
141 {
142 pwszPath[cwcDst++] = '\\';
143 if (g_aComponents[iComponent].fDriverFile)
144 {
145 pwszPath[cwcDst++] = 'd';
146 pwszPath[cwcDst++] = 'r';
147 pwszPath[cwcDst++] = 'i';
148 pwszPath[cwcDst++] = 'v';
149 pwszPath[cwcDst++] = 'e';
150 pwszPath[cwcDst++] = 'r';
151 pwszPath[cwcDst++] = 's';
152 pwszPath[cwcDst++] = '\\';
153 }
154 const wchar_t *pwszSrc = f8Dot3 ? g_aComponents[iComponent].pwsz8Dot3 : g_aComponents[iComponent].pwszFilename;
155 do
156 pwszPath[cwcDst++] = *pwszSrc;
157 while (*pwszSrc++);
158 return VINF_SUCCESS;
159 }
160 RTMsgError("GetSystemDirectoryW failed: %u\n", GetLastError());
161 return VERR_GENERAL_FAILURE;
162}
163
164
165/**
166 * Composes the source filename for a component.
167 */
168static int ComposeSourceFilename(WCHAR *pwszPath, size_t cwcPath, size_t iComponent)
169{
170 int rc = RTUtf16Copy(pwszPath, cwcPath, g_wszSrc);
171 if (RT_SUCCESS(rc))
172 rc = RTUtf16Copy(&pwszPath[g_cwcSrc], cwcPath - g_cwcSrc, g_aComponents[iComponent].pwszFilename);
173 if (RT_FAILURE(rc))
174 RTMsgError("Failed to compose source filename path for '%ls': %Rrc\n", g_aComponents[iComponent].pwszFilename, rc);
175 return rc;
176}
177
178
179static DWORD DeterminServiceType(size_t iComponent)
180{
181 if (g_aComponents[iComponent].fDriverFile)
182 return SERVICE_KERNEL_DRIVER;
183 /* SERVICE_INTERACTIVE_PROCESS was added in 3.50: */
184 if (g_uSaneVersion >= MAKE_SANE_VERSION(3, 50))
185 return SERVICE_INTERACTIVE_PROCESS | SERVICE_WIN32_OWN_PROCESS;
186 return SERVICE_WIN32_OWN_PROCESS;
187}
188
189
190static DWORD DeterminServiceStartType(size_t iComponent)
191{
192 if (g_aComponents[iComponent].fDriverFile)
193 {
194 if (g_aComponents[iComponent].enmComp == kComp_VBoxMouse)
195 return SERVICE_SYSTEM_START;
196 return SERVICE_BOOT_START;
197 }
198 return SERVICE_AUTO_START;
199}
200
201
202static DWORD DeterminServiceErrorControl(size_t iComponent)
203{
204 if ( g_aComponents[iComponent].enmComp == kComp_VBoxMouse
205 && g_uSaneVersion != MAKE_SANE_VERSION(3, 10))
206 return SERVICE_ERROR_IGNORE;
207 return SERVICE_ERROR_NORMAL;
208}
209
210
211static WCHAR const *DeterminServiceLoadOrderGroup(size_t iComponent)
212{
213 if ( g_aComponents[iComponent].enmComp == kComp_VBoxMouse
214 && g_uSaneVersion == MAKE_SANE_VERSION(3, 10))
215 return L"Keyboard Port";
216 return g_aComponents[iComponent].pwszServiceLoadOrderGroup;
217}
218
219
220static DWORD *DeterminServiceTag(size_t iComponent, DWORD *pidTag)
221{
222 if (g_aComponents[iComponent].enmComp != kComp_VBoxMouse)
223 return NULL;
224 *pidTag = 1;
225 return pidTag;
226}
227
228
229/**
230 * Updates the status portion of g_aComponents.
231 */
232void UpdateStatus(void)
233{
234 /*
235 * File precense.
236 */
237 WCHAR wszPath[MAX_PATH];
238 for (size_t i = 0; i < RT_ELEMENTS(g_aComponents); i++)
239 {
240 ComposeFilename(wszPath, RT_ELEMENTS(wszPath), i, false /*f8Dot3*/);
241 DWORD fLongAttribs = GetFileAttributesW(wszPath);
242
243 ComposeFilename(wszPath, RT_ELEMENTS(wszPath), i, true /*f8Dot3*/);
244 DWORD f8Dot3Attribs = GetFileAttributesW(wszPath);
245
246 if (f8Dot3Attribs == INVALID_FILE_ATTRIBUTES && fLongAttribs == INVALID_FILE_ATTRIBUTES)
247 g_aComponents[i].enmFileStatus = kFile_NotFound;
248 else if (f8Dot3Attribs != INVALID_FILE_ATTRIBUTES && fLongAttribs == INVALID_FILE_ATTRIBUTES)
249 g_aComponents[i].enmFileStatus = kFile_8Dot3;
250 else if (f8Dot3Attribs == INVALID_FILE_ATTRIBUTES && fLongAttribs != INVALID_FILE_ATTRIBUTES)
251 g_aComponents[i].enmFileStatus = kFile_LongName;
252 else
253 g_aComponents[i].enmFileStatus = kFile_Both;
254 }
255
256 /*
257 * Service config.
258 */
259 SC_HANDLE hServiceMgr = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
260 if (!hServiceMgr)
261 {
262 RTMsgError("Failed to open service manager (for status queries): %u\n", GetLastError());
263 return;
264 }
265
266 for (size_t i = 0; i < RT_ELEMENTS(g_aComponents); i++)
267 {
268 g_aComponents[i].fActive = false;
269 g_aComponents[i].fMisconfigured = false;
270
271 SetLastError(NO_ERROR);
272 SC_HANDLE hService = OpenServiceW(hServiceMgr, g_aComponents[i].pwszServiceName,
273 SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG);
274 if (hService)
275 {
276 DWORD const dwExpectedType = DeterminServiceType(i);
277 DWORD const dwExpectedStartType = DeterminServiceStartType(i);
278
279 g_aComponents[i].fServiceInstalled = true;
280
281 union
282 {
283 QUERY_SERVICE_CONFIGW Config;
284 SERVICE_STATUS Status;
285 uint8_t abPadding[_8K];
286 } u;
287
288 /* Status: */
289 RT_ZERO(u);
290 if (QueryServiceStatus(hService, &u.Status))
291 {
292 g_aComponents[i].fMisconfigured = false;
293
294 if (u.Status.dwServiceType != dwExpectedType)
295 {
296 RTMsgWarning("Unexpected dwServiceType for '%ls': %#x, expected %#x\n",
297 g_aComponents[i].pwszServiceName, u.Status.dwServiceType, dwExpectedType);
298 g_aComponents[i].fMisconfigured = true;
299 }
300
301 g_aComponents[i].fActive = u.Status.dwCurrentState == SERVICE_RUNNING
302 || u.Status.dwCurrentState == SERVICE_START_PENDING;
303 }
304 else
305 RTMsgWarning("QueryServiceStatus failed on '%ls': %u\n", g_aComponents[i].pwszServiceName, GetLastError());
306
307 /* Configuration: */
308 RT_ZERO(u);
309 DWORD cbNeeded = 0;
310 if (QueryServiceConfigW(hService, &u.Config, sizeof(u), &cbNeeded))
311 {
312 if (u.Config.dwServiceType != dwExpectedType)
313 g_aComponents[i].fMisconfigured = true;
314
315 if (u.Config.dwStartType != dwExpectedStartType)
316 {
317 RTMsgWarning("Unexpected dwStartType for '%ls': %#x, expected %#x\n",
318 g_aComponents[i].pwszServiceName, u.Config.dwStartType, dwExpectedStartType);
319 g_aComponents[i].fMisconfigured = true;
320 }
321
322 if (u.Config.lpBinaryPathName)
323 {
324 RTUtf16Copy(g_aComponents[i].wszServiceImagePath, RT_ELEMENTS(g_aComponents[i].wszServiceImagePath),
325 u.Config.lpBinaryPathName);
326
327 PRTUTF16 const pwszCfg = RTUtf16ToLowerAscii(u.Config.lpBinaryPathName);
328 if (RTUtf16Cmp(RTUtf16ToLowerAscii(ComposeServicePath(wszPath, RT_ELEMENTS(wszPath), i, false /*f8Dot3*/)),
329 pwszCfg) == 0)
330 g_aComponents[i].enmServiceFile = kFile_LongName;
331 else if (RTUtf16Cmp(RTUtf16ToLowerAscii(ComposeServicePath(wszPath, RT_ELEMENTS(wszPath), i, true /*f8Dot3*/)),
332 pwszCfg) == 0)
333 g_aComponents[i].enmServiceFile = kFile_8Dot3;
334 else
335 {
336 g_aComponents[i].enmServiceFile = kFile_Mismatch;
337 g_aComponents[i].fMisconfigured = true;
338 }
339 }
340 else
341 g_aComponents[i].fMisconfigured = true;
342
343 if ( !u.Config.lpLoadOrderGroup
344 || RTUtf16Cmp(u.Config.lpLoadOrderGroup, DeterminServiceLoadOrderGroup(i)) != 0)
345 {
346 RTMsgWarning("Unexpected load group for '%ls': '%ls', expected '%ls'\n",
347 g_aComponents[i].pwszServiceName, u.Config.lpLoadOrderGroup, DeterminServiceLoadOrderGroup(i));
348 g_aComponents[i].fMisconfigured = true;
349 }
350 }
351 else
352 RTMsgWarning("QueryServiceConfigW failed on '%ls': %u\n", g_aComponents[i].pwszServiceName, GetLastError());
353
354 CloseServiceHandle(hService);
355 }
356 else
357 {
358 DWORD dwErr = GetLastError();
359 if (dwErr == ERROR_SERVICE_DOES_NOT_EXIST)
360 g_aComponents[i].fServiceInstalled = false;
361 else
362 RTMsgWarning("Failed to open '%ls' for status query: %u\n", g_aComponents[i].pwszServiceName, dwErr);
363 }
364 }
365
366 CloseServiceHandle(hServiceMgr);
367}
368
369
370/**
371 * Reports the device statuses.
372 */
373int DoStatus(void)
374{
375 RTPrintf("NT Version: %#x = %u.%u build %u\n", g_dwVersion,
376 g_dwVersion & 0xff, (g_dwVersion >> 8) & 0xff, g_dwVersion >> 16);
377
378 WCHAR wszPath[MAX_PATH];
379 for (size_t i = 0; i < RT_ELEMENTS(g_aComponents); i++)
380 if (g_aComponents[i].fSelected)
381 {
382 RTPrintf("%ls:\n", g_aComponents[i].pwszServiceName);
383 RTPrintf(" %s%s\n", g_aComponents[i].fServiceInstalled ? "service installed" : "service not installed",
384 g_aComponents[i].fMisconfigured ? " - misconfigured" : "");
385 if ( g_aComponents[i].enmFileStatus == kFile_LongName
386 || g_aComponents[i].enmFileStatus == kFile_Both)
387 {
388 ComposeFilename(wszPath, RT_ELEMENTS(wszPath), i, false /*f8Dot3*/);
389 RTPrintf(" File: %ls\n", wszPath);
390 }
391 if ( g_aComponents[i].enmFileStatus == kFile_8Dot3
392 || g_aComponents[i].enmFileStatus == kFile_Both)
393 {
394 ComposeFilename(wszPath, RT_ELEMENTS(wszPath), i, true /*f8Dot3*/);
395 RTPrintf(" File 8.3: %ls\n", wszPath);
396 }
397 if (g_aComponents[i].wszServiceImagePath[0])
398 RTPrintf(" ServiceImage: %ls (%s)\n", g_aComponents[i].wszServiceImagePath,
399 g_aComponents[i].enmServiceFile == kFile_Mismatch ? "mismatch"
400 : g_aComponents[i].enmServiceFile == kFile_LongName ? "long"
401 : g_aComponents[i].enmServiceFile == kFile_8Dot3 ? "8.3" : "whut!?!");
402 }
403 return RTEXITCODE_SUCCESS;
404}
405
406
407/**
408 * Does the installation.
409 */
410int DoInstall(bool f8Dot3)
411{
412 /*
413 * Validate the request. We cannot install either VBoxService
414 * or VBoxMouse w/o the VBoxGuest driver (being) installed.
415 */
416 if ( !g_aComponents[kComp_VBoxGuest].fSelected
417 && !( g_aComponents[kComp_VBoxGuest].fActive
418 || (g_aComponents[kComp_VBoxGuest].fServiceInstalled && !g_aComponents[kComp_VBoxGuest].fMisconfigured)))
419 {
420 RTMsgError("VBoxGuest is required by all other components!\n"
421 "It is not selected nor installed in any working state!\n");
422 return RTEXITCODE_FAILURE;
423 }
424
425 /*
426 * We may need the service manager for stopping VBoxService, so open it
427 * before doing the copying.
428 */
429 SC_HANDLE hServiceMgr = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
430 if (!hServiceMgr)
431 return RTMsgErrorExitFailure("Failed to open service manager (for all access): %u\n", GetLastError());
432
433 /*
434 * First step, copy over the files.
435 */
436 WCHAR wszSrc[MAX_PATH];
437 WCHAR wszDst[MAX_PATH];
438 for (size_t i = 0; i < RT_ELEMENTS(g_aComponents); i++)
439 {
440 if (!g_aComponents[i].fSelected)
441 continue;
442 int rc = ComposeSourceFilename(wszSrc, RT_ELEMENTS(wszSrc), i);
443 if (RT_SUCCESS(rc))
444 rc = ComposeFilename(wszDst, RT_ELEMENTS(wszDst), i, f8Dot3);
445 if (RT_FAILURE(rc))
446 return RTEXITCODE_FAILURE;
447
448 /* If service active and it isn't a driver, we must stop it or we
449 cannot copy the file. */
450 if (g_aComponents[i].fActive && !g_aComponents[i].fDriverFile)
451 {
452 SC_HANDLE hService = OpenServiceW(hServiceMgr, g_aComponents[i].pwszServiceName, SERVICE_STOP | SERVICE_QUERY_STATUS);
453 if (!hService)
454 return RTMsgErrorExitFailure("Failed to open service '%ls' for stopping: %u\n",
455 g_aComponents[i].pwszServiceName, GetLastError());
456 uint32_t const uStartTick = GetTickCount();
457 uint32_t cStopsSent = 0;
458 for (;;)
459 {
460 SERVICE_STATUS Status;
461 RT_ZERO(Status);
462 if (!QueryServiceStatus(hService, &Status))
463 return RTMsgErrorExitFailure("Failed to query status of service '%ls': %u\n",
464 g_aComponents[i].pwszServiceName, GetLastError());
465 if (Status.dwCurrentState == SERVICE_STOPPED)
466 break;
467
468 if (GetTickCount() - uStartTick > 30000)
469 return RTMsgErrorExitFailure("Giving up trying to stop service '%ls': %u\n",
470 g_aComponents[i].pwszServiceName, GetLastError());
471
472 if (Status.dwCurrentState != SERVICE_STOP_PENDING)
473 {
474 if (cStopsSent > 5)
475 return RTMsgErrorExitFailure("Giving up trying to stop service '%ls': %u\n",
476 g_aComponents[i].pwszServiceName, GetLastError());
477 if (cStopsSent)
478 Sleep(128);
479 if (!ControlService(hService, SERVICE_CONTROL_STOP, &Status))
480 return RTMsgErrorExitFailure("Failed to stop service '%ls': %u\n",
481 g_aComponents[i].pwszServiceName, GetLastError());
482 cStopsSent++;
483 if (Status.dwCurrentState == SERVICE_STOPPED)
484 break;
485 }
486 Sleep(256);
487 }
488 CloseServiceHandle(hService);
489 }
490
491 /* Before copying, make sure the destination doesn't have the
492 readonly bit set. */
493 DWORD fAttribs = GetFileAttributesW(wszDst);
494 if ( (fAttribs & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN))
495 && fAttribs != INVALID_FILE_ATTRIBUTES)
496 {
497 fAttribs &= ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
498 if (!fAttribs)
499 fAttribs |= FILE_ATTRIBUTE_NORMAL;
500 SetFileAttributesW(wszDst, fAttribs);
501 }
502
503 if (CopyFileW(wszSrc, wszDst, FALSE /*fFailIfExists*/))
504 RTMsgInfo("Copied '%ls' to '%ls'\n", wszSrc, wszDst);
505 else
506 return RTMsgErrorExitFailure("Failed to copy '%ls' to '%ls': %u\n", wszSrc, wszDst, GetLastError());
507 }
508
509 /*
510 * Second step, do the installing / reconfiguring of services.
511 */
512 for (size_t i = 0; i < RT_ELEMENTS(g_aComponents); i++)
513 {
514 if (!g_aComponents[i].fSelected)
515 continue;
516 DWORD const dwType = DeterminServiceType(i);
517 DWORD const dwStartType = DeterminServiceStartType(i);
518 DWORD const dwErrorCtrl = DeterminServiceErrorControl(i);
519 wchar_t const *pwszLoadOrderGroup = DeterminServiceLoadOrderGroup(i);
520 DWORD idTag = 0;
521 DWORD * const pidTag = DeterminServiceTag(i, &idTag);
522
523 ComposeServicePath(wszDst, RT_ELEMENTS(wszDst), i, f8Dot3);
524
525 SC_HANDLE hService;
526 if (!g_aComponents[i].fServiceInstalled)
527 {
528 hService = CreateServiceW(hServiceMgr,
529 g_aComponents[i].pwszServiceName,
530 g_aComponents[i].pwszServiceDesc,
531 SERVICE_ALL_ACCESS,
532 dwType,
533 dwStartType,
534 dwErrorCtrl,
535 wszDst,
536 pwszLoadOrderGroup,
537 pidTag,
538 NULL /*pwszDependencies*/,
539 NULL /*pwszServiceStartName*/,
540 NULL /*pwszPassword*/);
541 if (!hService)
542 return RTMsgErrorExitFailure("Failed to create service '%ls': %u\n",
543 g_aComponents[i].pwszServiceName, GetLastError());
544 RTMsgInfo("Created service '%ls'.\n", g_aComponents[i].pwszServiceName);
545 }
546 else if ( g_aComponents[i].fMisconfigured
547 || RTUtf16Cmp(g_aComponents[i].wszServiceImagePath, wszDst) != 0)
548 {
549 hService = OpenServiceW(hServiceMgr, g_aComponents[i].pwszServiceName, SERVICE_ALL_ACCESS);
550 if (!hService)
551 return RTMsgErrorExitFailure("Failed to open service '%ls': %u\n",
552 g_aComponents[i].pwszServiceName, GetLastError());
553 if (!ChangeServiceConfigW(hService,
554 dwType,
555 dwStartType,
556 dwErrorCtrl,
557 wszDst,
558 pwszLoadOrderGroup,
559 pidTag,
560 NULL /*pwszDependencies*/,
561 NULL /*pwszServiceStartName*/,
562 NULL /*pwszPassword*/,
563 g_aComponents[i].enmComp != kComp_VBoxMouse ? g_aComponents[i].pwszServiceDesc : NULL))
564 return RTMsgErrorExitFailure("Failed to change configuration of service '%ls': %u\n",
565 g_aComponents[i].pwszServiceName, GetLastError());
566 RTMsgInfo("Reconfigured service '%ls'.\n", g_aComponents[i].pwszServiceName);
567 }
568 else
569 {
570 RTMsgInfo("No changes to service '%ls'.\n", g_aComponents[i].pwszServiceName);
571 continue;
572 }
573 CloseServiceHandle(hService);
574 }
575
576 CloseServiceHandle(hServiceMgr);
577
578 RTMsgInfo("Done. Please reboot.\n");
579 return RTEXITCODE_SUCCESS;
580}
581
582
583int DoUninstall(void)
584{
585 return RTMsgError("Not implemented. Sorry.\n");
586}
587
588
589int usage(const char *argv0)
590{
591 RTPrintf("Usage: %Rbn [--status] [--select <component> [..]]\n"
592 " or %Rbn --install [--select <component> [..]] [--8-dot-3]\n"
593 " or %Rbn --uninstall [--select <component> [..]]\n"
594 " or %Rbn --help\n"
595 " or %Rbn --version\n"
596 "\n"
597 "VirtualBox Guest Additions installer for NT 3.x.\n"
598 "\n"
599 "Options:\n"
600 " --status\n"
601 " Checks the installation status of the components.\n"
602 " --install\n"
603 " Installs the selected components.\n"
604 " --uninstall\n"
605 " Uninstalls the selected components.\n"
606 " --selected <component>\n"
607 " Select a component. By default all components are selected. However,\n"
608 " when this option is first used all are unselected before processing it.\n"
609 " Components:",
610 argv0, argv0, argv0, argv0, argv0);
611 for (size_t i = 0; i < RT_ELEMENTS(g_aComponents); i++)
612 RTPrintf(" %s", g_aComponents[i].pszName);
613 RTPrintf("\n"
614 " --8-dot-3, -8\n"
615 " Install files in 8.3 compatible manner (for FAT system volume).\n"
616 " --long-names, -l\n"
617 " Install files with long filenames (NTFS system volume). The default.\n"
618 " --help, -h, -?\n"
619 " Display this help text.\n"
620 " --version, -V\n"
621 " Display the version number.\n"
622 );
623 return RTEXITCODE_SUCCESS;
624}
625
626
627int main(int argc, char **argv)
628{
629 /*
630 * Init version.
631 */
632 g_dwVersion = GetVersion();
633 g_uSaneVersion = MAKE_SANE_VERSION(g_dwVersion & 0xff, (g_dwVersion >> 8) & 0xff);
634
635 /*
636 * Parse arguments.
637 */
638 static RTGETOPTDEF const s_aOptions[] =
639 {
640 { "--status", 1000 + 's', RTGETOPT_REQ_NOTHING },
641 { "--install", 1000 + 'i', RTGETOPT_REQ_NOTHING },
642 { "--uninstall", 1000 + 'u', RTGETOPT_REQ_NOTHING },
643 { "--select", 's', RTGETOPT_REQ_STRING },
644 { "--8-dot-3", '8', RTGETOPT_REQ_NOTHING },
645 { "--long-names", 'l', RTGETOPT_REQ_NOTHING },
646 { "--src", 'S', RTGETOPT_REQ_STRING },
647 { "--source", 'S', RTGETOPT_REQ_STRING },
648 };
649
650 bool fFirstSelect = true;
651 bool f8Dot3 = false;
652 enum { kMode_Status, kMode_Install, kMode_Uninstall }
653 enmMode = kMode_Status;
654
655 g_cwcSrc = GetModuleFileNameW(NULL, g_wszSrc, RT_ELEMENTS(g_wszSrc));
656 if (g_cwcSrc == 0)
657 return RTMsgErrorExitFailure("GetModuleFileNameW failed: %u\n", GetLastError());
658 while (g_cwcSrc > 0 && !RTPATH_IS_SEP(g_wszSrc[g_cwcSrc - 1]))
659 g_cwcSrc--;
660 g_wszSrc[g_cwcSrc] = '\0';
661
662 RTGETOPTSTATE State;
663 int rc = RTGetOptInit(&State,argc,argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
664 if (RT_FAILURE(rc))
665 return RTMsgErrorExitFailure("RTGetOptInit failed: %Rrc\n", rc);
666
667 RTGETOPTUNION ValueUnion;
668 int chOpt;
669 while ((chOpt = RTGetOpt(&State, &ValueUnion)) != 0)
670 {
671 switch (chOpt)
672 {
673 case 1000 + 's':
674 enmMode = kMode_Status;
675 break;
676
677 case 1000 + 'i':
678 enmMode = kMode_Install;
679 break;
680
681 case 1000 + 'u':
682 enmMode = kMode_Uninstall;
683 break;
684
685 case '8':
686 f8Dot3 = true;
687 break;
688
689 case 'l':
690 f8Dot3 = false;
691 break;
692
693 case 's':
694 {
695 size_t i;
696 if (fFirstSelect)
697 {
698 for (i = 0; i < RT_ELEMENTS(g_aComponents); i++)
699 g_aComponents[i].fSelected = false;
700 fFirstSelect = false;
701 }
702 for (i = 0; i < RT_ELEMENTS(g_aComponents); i++)
703 if (RTStrICmpAscii(ValueUnion.psz, g_aComponents[i].pszName) == 0)
704 {
705 g_aComponents[i].fSelected = true;
706 break;
707 }
708 if (i >= RT_ELEMENTS(g_aComponents))
709 return RTMsgErrorExitFailure("Unknown component: %s\n", ValueUnion.psz);
710 break;
711 }
712
713 case 'S':
714 {
715 PRTUTF16 pwszDst = g_wszSrc;
716 rc = RTStrToUtf16Ex(ValueUnion.psz, RTSTR_MAX, &pwszDst, RT_ELEMENTS(g_wszSrc) - 16, &g_cwcSrc);
717 if (RT_FAILURE(rc))
718 return RTMsgErrorExitFailure("Error converting source to UTF-16: %Rrc\n", rc);
719 if (!g_cwcSrc)
720 return RTMsgErrorExitFailure("Empty source argument!\n");
721 if (!RTPATH_IS_SEP(g_wszSrc[g_cwcSrc - 1]))
722 {
723 g_wszSrc[g_cwcSrc++] = '\\';
724 g_wszSrc[g_cwcSrc] = '\0';
725 }
726 break;
727 }
728
729 case 'h':
730 return usage(argv[0]);
731
732 case 'V':
733 RTPrintf("%sr%u\n", VBOX_VERSION_STRING, VBOX_SVN_REV);
734 return RTEXITCODE_SUCCESS;
735
736 default:
737 return RTGetOptPrintError(chOpt, &ValueUnion);
738 }
739 }
740
741 /*
742 * Before we do anything gather status info on the components.
743 */
744 UpdateStatus();
745
746 /*
747 * Take action.
748 */
749 if (enmMode == kMode_Status)
750 return DoStatus();
751 if (enmMode == kMode_Install)
752 return DoInstall(f8Dot3);
753 return DoUninstall();
754}
755
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use