VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use