VirtualBox

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

最後變更 在這個檔案從83979是 83979,由 vboxsync 提交於 5 年 前

Add/Nt/Installer: Simple installer program for NT 3.x.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 36.1 KB
 
1/* $Id: VBoxAddInstallNt3x.cpp 83979 2020-04-26 01:28:56Z vboxsync $ */
2/** @file
3 * VBoxAddInstallNt3x = Install Guest Additions on NT3.51, 3.5 and 3.1.
4 */
5
6/*
7 * Copyright (c) 2020 knut st. osmundsen <[email protected]>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with This program. If not, see <http://www.gnu.org/licenses/>
21 *
22 */
23
24
25/*********************************************************************************************************************************
26* Header Files *
27*********************************************************************************************************************************/
28#include <iprt/nt/nt-and-windows.h>
29#include <iprt/ctype.h>
30#include <iprt/getopt.h>
31#include <iprt/mem.h>
32#include <iprt/message.h>
33#include <iprt/path.h>
34#include <iprt/stream.h>
35#include <iprt/string.h>
36#include <iprt/utf16.h>
37
38#include <VBox/version.h>
39#include <revision-generated.h> /* VBOX_SVN_REV. */
40
41
42/*********************************************************************************************************************************
43* Minimal stream implementation (for message.cpp). *
44*********************************************************************************************************************************/
45/** @todo might be an idea to make a more native version of this and use
46 * this as a base for it. */
47
48typedef struct PRINTFBUF
49{
50 HANDLE hHandle;
51 size_t offBuf;
52 char szBuf[128];
53} PRINTFBUF;
54
55struct RTSTREAM
56{
57 int iStream;
58 HANDLE hHandle;
59};
60
61
62RTSTREAM g_aStdStreams[3] =
63{
64 { 0, NULL },
65 { 1, NULL },
66 { 2, NULL },
67};
68
69RTSTREAM *g_pStdIn = &g_aStdStreams[0];
70RTSTREAM *g_pStdOut = &g_aStdStreams[1];
71RTSTREAM *g_pStdErr = &g_aStdStreams[2];
72
73
74static void InitStdHandles(PRTL_USER_PROCESS_PARAMETERS pParams)
75{
76 if (pParams)
77 {
78 g_pStdIn->hHandle = pParams->StandardInput;
79 g_pStdOut->hHandle = pParams->StandardOutput;
80 g_pStdErr->hHandle = pParams->StandardError;
81 }
82}
83
84
85static void FlushPrintfBuffer(PRINTFBUF *pBuf)
86{
87 if (pBuf->offBuf)
88 {
89 DWORD cbWritten = 0;
90 WriteFile(pBuf->hHandle, pBuf->szBuf, pBuf->offBuf, &cbWritten, NULL);
91 pBuf->offBuf = 0;
92 pBuf->szBuf[0] = '\0';
93 }
94}
95
96
97/** @callback_method_impl{FNRTSTROUTPUT} */
98static DECLCALLBACK(size_t) MyPrintfOutputter(void *pvArg, const char *pachChars, size_t cbChars)
99{
100 PRINTFBUF *pBuf = (PRINTFBUF *)pvArg;
101 if (cbChars != 0)
102 {
103 size_t offSrc = 0;
104 while (offSrc < cbChars)
105 {
106 size_t cbLeft = sizeof(pBuf->szBuf) - pBuf->offBuf - 1;
107 if (cbLeft > 0)
108 {
109 size_t cbToCopy = RT_MIN(cbChars - offSrc, cbLeft);
110 memcpy(&pBuf->szBuf[pBuf->offBuf], &pachChars[offSrc], cbToCopy);
111 pBuf->offBuf += cbToCopy;
112 pBuf->szBuf[pBuf->offBuf] = '\0';
113 if (cbLeft > cbToCopy)
114 break;
115 offSrc += cbToCopy;
116 }
117 FlushPrintfBuffer(pBuf);
118 }
119 }
120 else /* Special zero byte write at the end of the formatting. */
121 FlushPrintfBuffer(pBuf);
122 return cbChars;
123}
124
125
126RTR3DECL(int) RTStrmPrintfV(PRTSTREAM pStream, const char *pszFormat, va_list args)
127{
128 PRINTFBUF Buf;
129 Buf.hHandle = pStream->hHandle;
130 Buf.offBuf = 0;
131 Buf.szBuf[0] = '\0';
132
133 return RTStrFormatV(MyPrintfOutputter, &Buf, NULL, NULL, pszFormat, args);
134}
135
136
137RTR3DECL(int) RTStrmPrintf(PRTSTREAM pStream, const char *pszFormat, ...)
138{
139 va_list args;
140 va_start(args, pszFormat);
141 int rc = RTStrmPrintfV(pStream, pszFormat, args);
142 va_end(args);
143 return rc;
144}
145
146
147RTR3DECL(int) RTPrintfV(const char *pszFormat, va_list va)
148{
149 PRINTFBUF Buf;
150 Buf.hHandle = g_pStdOut->hHandle;
151 Buf.offBuf = 0;
152 Buf.szBuf[0] = '\0';
153
154 return RTStrFormatV(MyPrintfOutputter, &Buf, NULL, NULL, pszFormat, va);
155}
156
157
158RTR3DECL(int) RTPrintf(const char *pszFormat, ...)
159{
160 va_list va;
161 va_start(va, pszFormat);
162 int rc = RTPrintfV(pszFormat, va);
163 va_end(va);
164 return rc;
165}
166
167
168/*********************************************************************************************************************************
169* Allocation using process heap *
170*********************************************************************************************************************************/
171/** @todo put this into a file in r3/win/ and r3/nt/ */
172RTDECL(void) RTMemTmpFree(void *pv)
173{
174 HeapFree(GetProcessHeap(), 0, pv);
175}
176
177RTDECL(void) RTMemFree(void *pv)
178{
179 HeapFree(GetProcessHeap(), 0, pv);
180}
181
182
183RTDECL(void *) RTMemTmpAllocTag(size_t cb, const char *pszTag)
184{
185 RT_NOREF(pszTag);
186 return HeapAlloc(GetProcessHeap(), 0, cb);
187}
188
189
190RTDECL(void *) RTMemTmpAllocZTag(size_t cb, const char *pszTag)
191{
192 RT_NOREF(pszTag);
193 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cb);
194}
195
196
197RTDECL(void *) RTMemAllocTag(size_t cb, const char *pszTag)
198{
199 RT_NOREF(pszTag);
200 return HeapAlloc(GetProcessHeap(), 0, cb);
201}
202
203
204RTDECL(void *) RTMemAllocZTag(size_t cb, const char *pszTag)
205{
206 RT_NOREF(pszTag);
207 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cb);
208}
209
210
211RTDECL(void *) RTMemReallocTag(void *pvOld, size_t cbNew, const char *pszTag)
212{
213 RT_NOREF(pszTag);
214 if (pvOld)
215 return HeapReAlloc(GetProcessHeap(), 0, pvOld, cbNew);
216 return HeapAlloc(GetProcessHeap(), 0, cbNew);
217}
218
219
220RTDECL(void *) RTMemReallocZTag(void *pvOld, size_t cbOld, size_t cbNew, const char *pszTag)
221{
222 RT_NOREF(pszTag, cbOld);
223 if (pvOld)
224 return HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pvOld, cbNew);
225 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbNew);
226}
227
228
229/*********************************************************************************************************************************
230* UTF-16 *
231*********************************************************************************************************************************/
232
233RTDECL(PRTUTF16) RTUtf16ToLowerAscii(PRTUTF16 pwsz)
234{
235 for (PRTUTF16 pwc = pwsz; *pwc; pwc++)
236 if (*pwc < 0x7f)
237 *pwc = RT_C_TO_LOWER(*pwc);
238 return pwsz;
239}
240
241
242/*********************************************************************************************************************************
243* Actual installer code. *
244*********************************************************************************************************************************/
245
246/** Components (also indexes into g_aComponents). */
247typedef enum { kComp_VBoxGuest = 0, kComp_VBoxService = 1, kComp_VBoxMouse = 2} VBOXGACOMP;
248/** File status. */
249typedef enum { kFile_NotFound, kFile_LongName, kFile_8Dot3, kFile_Both, kFile_Mismatch } VBOXGAFILE;
250
251/** The components. */
252struct
253{
254 const char *pszName;
255 VBOXGACOMP enmComp;
256 bool fSelected;
257
258 bool fDriverFile;
259 const wchar_t *pwszFilename;
260 const wchar_t *pwsz8Dot3;
261 const wchar_t *pwszServiceName;
262 const wchar_t *pwszServiceDesc;
263 const wchar_t *pwszServiceLoadOrderGroup;
264
265 /** @name Status
266 * @{ */
267 VBOXGAFILE enmFileStatus;
268 bool fServiceInstalled;
269 bool fMisconfigured;
270 bool fActive;
271 VBOXGAFILE enmServiceFile;
272 wchar_t wszServiceImagePath[MAX_PATH];
273 /** @} */
274
275} g_aComponents[] =
276{
277 {
278 "VBoxGuest", kComp_VBoxGuest, true, true, L"VBoxGuest.sys", L"VBoxGst.sys",
279 L"VBoxGuest", L"VirtualBox Guest Additions Driver", L"System",
280 kFile_NotFound, false, false, false, kFile_NotFound, {0},
281 },
282 {
283 "VBoxService", kComp_VBoxService, true, false, L"VBoxService.exe", L"VBoxGaSv.exe",
284 L"VBoxService", L"VirtualBox Guest Additions Service", L"Base",
285 kFile_NotFound, false, false, false, kFile_NotFound, {0},
286 },
287 {
288 "VBoxMouse", kComp_VBoxMouse, true, true, L"VBoxMouseNT.sys", L"VBoxMou.sys",
289 L"i8042prt", L"i8042prt", L"Pointer Port",
290 kFile_NotFound, true, false, false, kFile_NotFound, {0},
291 },
292};
293
294/** The source path where the files are. */
295static WCHAR g_wszSrc[MAX_PATH];
296static size_t g_cwcSrc = 0;
297
298#define MAKE_SANE_VERSION(a_uMajor, a_uMinor) RT_MAKE_U32(a_uMinor, a_uMajor)
299static uint32_t g_uSaneVersion = MAKE_SANE_VERSION(3,51);
300static DWORD g_dwVersion = 3 | (51 << 8);
301
302
303/**
304 * Composes the service binary path for component.
305 */
306static WCHAR *ComposeServicePath(WCHAR *pwszPath, size_t cwcPath, size_t iComponent, bool f8Dot3)
307{
308 static wchar_t const s_wszPrefixDrv[] = L"\\SystemRoot\\System32\\drivers\\";
309 static wchar_t const s_wszPrefixExe[] = L"%SystemRoot%\\System32\\";
310 size_t cwcDst;
311 if (g_aComponents[iComponent].fDriverFile)
312 {
313 RTUtf16Copy(pwszPath, cwcPath, s_wszPrefixDrv);
314 cwcDst = RT_ELEMENTS(s_wszPrefixDrv) - 1;
315 }
316 else
317 {
318 RTUtf16Copy(pwszPath, cwcPath, s_wszPrefixExe);
319 cwcDst = RT_ELEMENTS(s_wszPrefixExe) - 1;
320 }
321
322 RTUtf16Copy(&pwszPath[cwcDst], cwcPath - cwcDst,
323 f8Dot3 ? g_aComponents[iComponent].pwsz8Dot3 : g_aComponents[iComponent].pwszFilename);
324 return pwszPath;
325}
326
327
328/**
329 * Composes the installed filename for a component.
330 */
331static int ComposeFilename(WCHAR *pwszPath, size_t cwcPath, size_t iComponent, bool f8Dot3)
332{
333 UINT cwcDst = GetSystemDirectoryW(pwszPath, cwcPath - 30);
334 if (cwcDst > 0)
335 {
336 pwszPath[cwcDst++] = '\\';
337 if (g_aComponents[iComponent].fDriverFile)
338 {
339 pwszPath[cwcDst++] = 'd';
340 pwszPath[cwcDst++] = 'r';
341 pwszPath[cwcDst++] = 'i';
342 pwszPath[cwcDst++] = 'v';
343 pwszPath[cwcDst++] = 'e';
344 pwszPath[cwcDst++] = 'r';
345 pwszPath[cwcDst++] = 's';
346 pwszPath[cwcDst++] = '\\';
347 }
348 const wchar_t *pwszSrc = f8Dot3 ? g_aComponents[iComponent].pwsz8Dot3 : g_aComponents[iComponent].pwszFilename;
349 do
350 pwszPath[cwcDst++] = *pwszSrc;
351 while (*pwszSrc++);
352 return VINF_SUCCESS;
353 }
354 RTMsgError("GetSystemDirectoryW failed: %u\n", GetLastError());
355 return VERR_GENERAL_FAILURE;
356}
357
358
359/**
360 * Composes the source filename for a component.
361 */
362static int ComposeSourceFilename(WCHAR *pwszPath, size_t cwcPath, size_t iComponent)
363{
364 int rc = RTUtf16Copy(pwszPath, cwcPath, g_wszSrc);
365 if (RT_SUCCESS(rc))
366 rc = RTUtf16Copy(&pwszPath[g_cwcSrc], cwcPath - g_cwcSrc, g_aComponents[iComponent].pwszFilename);
367 if (RT_FAILURE(rc))
368 RTMsgError("Failed to compose source filename path for '%ls': %Rrc\n", g_aComponents[iComponent].pwszFilename, rc);
369 return rc;
370}
371
372
373static DWORD DeterminServiceType(size_t iComponent)
374{
375 if (g_aComponents[iComponent].fDriverFile)
376 return SERVICE_KERNEL_DRIVER;
377 /* SERVICE_INTERACTIVE_PROCESS was added in 3.50: */
378 if (g_uSaneVersion >= MAKE_SANE_VERSION(3, 50))
379 return SERVICE_INTERACTIVE_PROCESS | SERVICE_WIN32_OWN_PROCESS;
380 return SERVICE_WIN32_OWN_PROCESS;
381}
382
383
384static DWORD DeterminServiceStartType(size_t iComponent)
385{
386 if (g_aComponents[iComponent].fDriverFile)
387 {
388 if (g_aComponents[iComponent].enmComp == kComp_VBoxMouse)
389 return SERVICE_SYSTEM_START;
390 return SERVICE_BOOT_START;
391 }
392 return SERVICE_AUTO_START;
393}
394
395
396static DWORD DeterminServiceErrorControl(size_t iComponent)
397{
398 if ( g_aComponents[iComponent].enmComp == kComp_VBoxMouse
399 && g_uSaneVersion != MAKE_SANE_VERSION(3, 10))
400 return SERVICE_ERROR_IGNORE;
401 return SERVICE_ERROR_NORMAL;
402}
403
404
405static WCHAR const *DeterminServiceLoadOrderGroup(size_t iComponent)
406{
407 if ( g_aComponents[iComponent].enmComp == kComp_VBoxMouse
408 && g_uSaneVersion == MAKE_SANE_VERSION(3, 10))
409 return L"Keyboard Port";
410 return g_aComponents[iComponent].pwszServiceLoadOrderGroup;
411}
412
413
414static DWORD *DeterminServiceTag(size_t iComponent, DWORD *pidTag)
415{
416 if (g_aComponents[iComponent].enmComp != kComp_VBoxMouse)
417 return NULL;
418 *pidTag = 1;
419 return pidTag;
420}
421
422
423/**
424 * Updates the status portion of g_aComponents.
425 */
426void UpdateStatus(void)
427{
428 /*
429 * File precense.
430 */
431 WCHAR wszPath[MAX_PATH];
432 for (size_t i = 0; i < RT_ELEMENTS(g_aComponents); i++)
433 {
434 ComposeFilename(wszPath, RT_ELEMENTS(wszPath), i, false /*f8Dot3*/);
435 DWORD fLongAttribs = GetFileAttributesW(wszPath);
436
437 ComposeFilename(wszPath, RT_ELEMENTS(wszPath), i, true /*f8Dot3*/);
438 DWORD f8Dot3Attribs = GetFileAttributesW(wszPath);
439
440 if (f8Dot3Attribs == INVALID_FILE_ATTRIBUTES && fLongAttribs == INVALID_FILE_ATTRIBUTES)
441 g_aComponents[i].enmFileStatus = kFile_NotFound;
442 else if (f8Dot3Attribs != INVALID_FILE_ATTRIBUTES && fLongAttribs == INVALID_FILE_ATTRIBUTES)
443 g_aComponents[i].enmFileStatus = kFile_8Dot3;
444 else if (f8Dot3Attribs == INVALID_FILE_ATTRIBUTES && fLongAttribs != INVALID_FILE_ATTRIBUTES)
445 g_aComponents[i].enmFileStatus = kFile_LongName;
446 else
447 g_aComponents[i].enmFileStatus = kFile_Both;
448 }
449
450 /*
451 * Service config.
452 */
453 SC_HANDLE hServiceMgr = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
454 if (!hServiceMgr)
455 {
456 RTMsgError("Failed to open service manager (for status queries): %u\n", GetLastError());
457 return;
458 }
459
460 for (size_t i = 0; i < RT_ELEMENTS(g_aComponents); i++)
461 {
462 g_aComponents[i].fActive = false;
463 g_aComponents[i].fMisconfigured = false;
464
465 SetLastError(NO_ERROR);
466 SC_HANDLE hService = OpenServiceW(hServiceMgr, g_aComponents[i].pwszServiceName,
467 SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG);
468 if (hService)
469 {
470 DWORD const dwExpectedType = DeterminServiceType(i);
471 DWORD const dwExpectedStartType = DeterminServiceStartType(i);
472
473 g_aComponents[i].fServiceInstalled = true;
474
475 union
476 {
477 QUERY_SERVICE_CONFIGW Config;
478 SERVICE_STATUS Status;
479 uint8_t abPadding[_8K];
480 } u;
481
482 /* Status: */
483 RT_ZERO(u);
484 if (QueryServiceStatus(hService, &u.Status))
485 {
486 g_aComponents[i].fMisconfigured = false;
487
488 if (u.Status.dwServiceType != dwExpectedType)
489 {
490 RTMsgWarning("Unexpected dwServiceType for '%ls': %#x, expected %#x\n",
491 g_aComponents[i].pwszServiceName, u.Status.dwServiceType, dwExpectedType);
492 g_aComponents[i].fMisconfigured = true;
493 }
494
495 g_aComponents[i].fActive = u.Status.dwCurrentState == SERVICE_RUNNING
496 || u.Status.dwCurrentState == SERVICE_START_PENDING;
497 }
498 else
499 RTMsgWarning("QueryServiceStatus failed on '%ls': %u\n", g_aComponents[i].pwszServiceName, GetLastError());
500
501 /* Configuration: */
502 RT_ZERO(u);
503 DWORD cbNeeded = 0;
504 if (QueryServiceConfigW(hService, &u.Config, sizeof(u), &cbNeeded))
505 {
506 if (u.Config.dwServiceType != dwExpectedType)
507 g_aComponents[i].fMisconfigured = true;
508
509 if (u.Config.dwStartType != dwExpectedStartType)
510 {
511 RTMsgWarning("Unexpected dwStartType for '%ls': %#x, expected %#x\n",
512 g_aComponents[i].pwszServiceName, u.Config.dwStartType, dwExpectedStartType);
513 g_aComponents[i].fMisconfigured = true;
514 }
515
516 if (u.Config.lpBinaryPathName)
517 {
518 RTUtf16Copy(g_aComponents[i].wszServiceImagePath, RT_ELEMENTS(g_aComponents[i].wszServiceImagePath),
519 u.Config.lpBinaryPathName);
520
521 PRTUTF16 const pwszCfg = RTUtf16ToLowerAscii(u.Config.lpBinaryPathName);
522 if (RTUtf16Cmp(RTUtf16ToLowerAscii(ComposeServicePath(wszPath, RT_ELEMENTS(wszPath), i, false /*f8Dot3*/)),
523 pwszCfg) == 0)
524 g_aComponents[i].enmServiceFile = kFile_LongName;
525 else if (RTUtf16Cmp(RTUtf16ToLowerAscii(ComposeServicePath(wszPath, RT_ELEMENTS(wszPath), i, true /*f8Dot3*/)),
526 pwszCfg) == 0)
527 g_aComponents[i].enmServiceFile = kFile_8Dot3;
528 else
529 {
530 g_aComponents[i].enmServiceFile = kFile_Mismatch;
531 g_aComponents[i].fMisconfigured = true;
532 }
533 }
534 else
535 g_aComponents[i].fMisconfigured = true;
536
537 if ( !u.Config.lpLoadOrderGroup
538 || RTUtf16Cmp(u.Config.lpLoadOrderGroup, DeterminServiceLoadOrderGroup(i)) != 0)
539 {
540 RTMsgWarning("Unexpected load group for '%ls': '%ls', expected '%ls'\n",
541 g_aComponents[i].pwszServiceName, u.Config.lpLoadOrderGroup, DeterminServiceLoadOrderGroup(i));
542 g_aComponents[i].fMisconfigured = true;
543 }
544 }
545 else
546 RTMsgWarning("QueryServiceConfigW failed on '%ls': %u\n", g_aComponents[i].pwszServiceName, GetLastError());
547
548 CloseServiceHandle(hService);
549 }
550 else
551 {
552 DWORD dwErr = GetLastError();
553 if (dwErr == ERROR_SERVICE_DOES_NOT_EXIST)
554 g_aComponents[i].fServiceInstalled = false;
555 else
556 RTMsgWarning("Failed to open '%ls' for status query: %u\n", g_aComponents[i].pwszServiceName, dwErr);
557 }
558 }
559
560 CloseServiceHandle(hServiceMgr);
561}
562
563
564/**
565 * Reports the device statuses.
566 */
567int DoStatus(void)
568{
569 RTPrintf("NT Version: %#x = %u.%u build %u\n", g_dwVersion,
570 g_dwVersion & 0xff, (g_dwVersion >> 8) & 0xff, g_dwVersion >> 16);
571
572 WCHAR wszPath[MAX_PATH];
573 for (size_t i = 0; i < RT_ELEMENTS(g_aComponents); i++)
574 if (g_aComponents[i].fSelected)
575 {
576 RTPrintf("%ls:\n", g_aComponents[i].pwszServiceName);
577 RTPrintf(" %s%s\n", g_aComponents[i].fServiceInstalled ? "service installed" : "service not installed",
578 g_aComponents[i].fMisconfigured ? " - misconfigured" : "");
579 if ( g_aComponents[i].enmFileStatus == kFile_LongName
580 || g_aComponents[i].enmFileStatus == kFile_Both)
581 {
582 ComposeFilename(wszPath, RT_ELEMENTS(wszPath), i, false /*f8Dot3*/);
583 RTPrintf(" File: %ls\n", wszPath);
584 }
585 if ( g_aComponents[i].enmFileStatus == kFile_8Dot3
586 || g_aComponents[i].enmFileStatus == kFile_Both)
587 {
588 ComposeFilename(wszPath, RT_ELEMENTS(wszPath), i, true /*f8Dot3*/);
589 RTPrintf(" File 8.3: %ls\n", wszPath);
590 }
591 if (g_aComponents[i].wszServiceImagePath[0])
592 RTPrintf(" ServiceImage: %ls (%s)\n", g_aComponents[i].wszServiceImagePath,
593 g_aComponents[i].enmServiceFile == kFile_Mismatch ? "mismatch"
594 : g_aComponents[i].enmServiceFile == kFile_LongName ? "long"
595 : g_aComponents[i].enmServiceFile == kFile_8Dot3 ? "8.3" : "whut!?!");
596 }
597 return RTEXITCODE_SUCCESS;
598}
599
600
601/**
602 * Does the installation.
603 */
604int DoInstall(bool f8Dot3)
605{
606 /*
607 * Validate the request. We cannot install either VBoxService
608 * or VBoxMouse w/o the VBoxGuest driver (being) installed.
609 */
610 if ( !g_aComponents[kComp_VBoxGuest].fSelected
611 && !( g_aComponents[kComp_VBoxGuest].fActive
612 || (g_aComponents[kComp_VBoxGuest].fServiceInstalled && !g_aComponents[kComp_VBoxGuest].fMisconfigured)))
613 {
614 RTMsgError("VBoxGuest is required by all other components!\n"
615 "It is not selected nor installed in any working state!\n");
616 return RTEXITCODE_FAILURE;
617 }
618
619 /*
620 * We may need the service manager for stopping VBoxService, so open it
621 * before doing the copying.
622 */
623 SC_HANDLE hServiceMgr = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
624 if (!hServiceMgr)
625 return RTMsgErrorExitFailure("Failed to open service manager (for all access): %u\n", GetLastError());
626
627 /*
628 * First step, copy over the files.
629 */
630 WCHAR wszSrc[MAX_PATH];
631 WCHAR wszDst[MAX_PATH];
632 for (size_t i = 0; i < RT_ELEMENTS(g_aComponents); i++)
633 {
634 if (!g_aComponents[i].fSelected)
635 continue;
636 int rc = ComposeSourceFilename(wszSrc, RT_ELEMENTS(wszSrc), i);
637 if (RT_SUCCESS(rc))
638 rc = ComposeFilename(wszDst, RT_ELEMENTS(wszDst), i, f8Dot3);
639 if (RT_FAILURE(rc))
640 return RTEXITCODE_FAILURE;
641
642 /* If service active and it isn't a driver, we must stop it or we
643 cannot copy the file. */
644 if (g_aComponents[i].fActive && !g_aComponents[i].fDriverFile)
645 {
646 SC_HANDLE hService = OpenServiceW(hServiceMgr, g_aComponents[i].pwszServiceName, SERVICE_STOP | SERVICE_QUERY_STATUS);
647 if (!hService)
648 return RTMsgErrorExitFailure("Failed to open service '%ls' for stopping: %u\n",
649 g_aComponents[i].pwszServiceName, GetLastError());
650 uint32_t const uStartTick = GetTickCount();
651 uint32_t cStopsSent = 0;
652 for (;;)
653 {
654 SERVICE_STATUS Status;
655 RT_ZERO(Status);
656 if (!QueryServiceStatus(hService, &Status))
657 return RTMsgErrorExitFailure("Failed to query status of service '%ls': %u\n",
658 g_aComponents[i].pwszServiceName, GetLastError());
659 if (Status.dwCurrentState == SERVICE_STOPPED)
660 break;
661
662 if (GetTickCount() - uStartTick > 30000)
663 return RTMsgErrorExitFailure("Giving up trying to stop service '%ls': %u\n",
664 g_aComponents[i].pwszServiceName, GetLastError());
665
666 if (Status.dwCurrentState != SERVICE_STOP_PENDING)
667 {
668 if (cStopsSent > 5)
669 return RTMsgErrorExitFailure("Giving up trying to stop service '%ls': %u\n",
670 g_aComponents[i].pwszServiceName, GetLastError());
671 if (cStopsSent)
672 Sleep(128);
673 if (!ControlService(hService, SERVICE_CONTROL_STOP, &Status))
674 return RTMsgErrorExitFailure("Failed to stop service '%ls': %u\n",
675 g_aComponents[i].pwszServiceName, GetLastError());
676 cStopsSent++;
677 if (Status.dwCurrentState == SERVICE_STOPPED)
678 break;
679 }
680 Sleep(256);
681 }
682 CloseServiceHandle(hService);
683 }
684
685 /* Before copying, make sure the destination doesn't have the
686 readonly bit set. */
687 DWORD fAttribs = GetFileAttributesW(wszDst);
688 if ( (fAttribs & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN))
689 && fAttribs != INVALID_FILE_ATTRIBUTES)
690 {
691 fAttribs &= ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
692 if (!fAttribs)
693 fAttribs |= FILE_ATTRIBUTE_NORMAL;
694 SetFileAttributesW(wszDst, fAttribs);
695 }
696
697 if (CopyFileW(wszSrc, wszDst, FALSE /*fFailIfExists*/))
698 RTMsgInfo("Copied '%ls' to '%ls'\n", wszSrc, wszDst);
699 else
700 return RTMsgErrorExitFailure("Failed to copy '%ls' to '%ls': %u\n", wszSrc, wszDst, GetLastError());
701 }
702
703 /*
704 * Second step, do the installing / reconfiguring of services.
705 */
706 for (size_t i = 0; i < RT_ELEMENTS(g_aComponents); i++)
707 {
708 if (!g_aComponents[i].fSelected)
709 continue;
710 DWORD const dwType = DeterminServiceType(i);
711 DWORD const dwStartType = DeterminServiceStartType(i);
712 DWORD const dwErrorCtrl = DeterminServiceErrorControl(i);
713 wchar_t const *pwszLoadOrderGroup = DeterminServiceLoadOrderGroup(i);
714 DWORD idTag = 0;
715 DWORD * const pidTag = DeterminServiceTag(i, &idTag);
716
717 ComposeServicePath(wszDst, RT_ELEMENTS(wszDst), i, f8Dot3);
718
719 SC_HANDLE hService;
720 if (!g_aComponents[i].fServiceInstalled)
721 {
722 hService = CreateServiceW(hServiceMgr,
723 g_aComponents[i].pwszServiceName,
724 g_aComponents[i].pwszServiceDesc,
725 SERVICE_ALL_ACCESS,
726 dwType,
727 dwStartType,
728 dwErrorCtrl,
729 wszDst,
730 pwszLoadOrderGroup,
731 pidTag,
732 NULL /*pwszDependencies*/,
733 NULL /*pwszServiceStartName*/,
734 NULL /*pwszPassword*/);
735 if (!hService)
736 return RTMsgErrorExitFailure("Failed to create service '%ls': %u\n",
737 g_aComponents[i].pwszServiceName, GetLastError());
738 RTMsgInfo("Created service '%ls'.\n", g_aComponents[i].pwszServiceName);
739 }
740 else if ( g_aComponents[i].fMisconfigured
741 || RTUtf16Cmp(g_aComponents[i].wszServiceImagePath, wszDst) != 0)
742 {
743 hService = OpenServiceW(hServiceMgr, g_aComponents[i].pwszServiceName, SERVICE_ALL_ACCESS);
744 if (!hService)
745 return RTMsgErrorExitFailure("Failed to open service '%ls': %u\n",
746 g_aComponents[i].pwszServiceName, GetLastError());
747 if (!ChangeServiceConfigW(hService,
748 dwType,
749 dwStartType,
750 dwErrorCtrl,
751 wszDst,
752 pwszLoadOrderGroup,
753 pidTag,
754 NULL /*pwszDependencies*/,
755 NULL /*pwszServiceStartName*/,
756 NULL /*pwszPassword*/,
757 g_aComponents[i].enmComp != kComp_VBoxMouse ? g_aComponents[i].pwszServiceDesc : NULL))
758 return RTMsgErrorExitFailure("Failed to change configuration of service '%ls': %u\n",
759 g_aComponents[i].pwszServiceName, GetLastError());
760 RTMsgInfo("Reconfigured service '%ls'.\n", g_aComponents[i].pwszServiceName);
761 }
762 else
763 {
764 RTMsgInfo("No changes to service '%ls'.\n", g_aComponents[i].pwszServiceName);
765 continue;
766 }
767 CloseServiceHandle(hService);
768 }
769
770 CloseServiceHandle(hServiceMgr);
771
772 RTMsgInfo("Done. Please reboot.\n");
773 return RTEXITCODE_SUCCESS;
774}
775
776
777int DoUninstall(void)
778{
779 return RTMsgError("Not implemented. Sorry.\n");
780}
781
782
783int usage(const char *argv0)
784{
785 RTPrintf("Usage: %Rbn [--status] [--select <component> [..]]\n"
786 " or %Rbn --install [--select <component> [..]] [--8-dot-3]\n"
787 " or %Rbn --uninstall [--select <component> [..]]\n"
788 " or %Rbn --help\n"
789 " or %Rbn --version\n"
790 "\n"
791 "VirtualBox Guest Additions installer for NT 3.x.\n"
792 "\n"
793 "Options:\n"
794 " --status\n"
795 " Checks the installation status of the components.\n"
796 " --install\n"
797 " Installs the selected components.\n"
798 " --uninstall\n"
799 " Uninstalls the selected components.\n"
800 " --selected <component>\n"
801 " Select a component. By default all components are selected. However,\n"
802 " when this option is first used all are unselected before processing it.\n"
803 " Components:",
804 argv0, argv0, argv0, argv0, argv0);
805 for (size_t i = 0; i < RT_ELEMENTS(g_aComponents); i++)
806 RTPrintf(" %s", g_aComponents[i].pszName);
807 RTPrintf("\n"
808 " --8-dot-3, -8\n"
809 " Install files in 8.3 compatible manner (for FAT system volume).\n"
810 " --long-names, -l\n"
811 " Install files with long filenames (NTFS system volume). The default.\n"
812 " --help, -h, -?\n"
813 " Display this help text.\n"
814 " --version, -V\n"
815 " Display the version number.\n"
816 );
817 return RTEXITCODE_SUCCESS;
818}
819
820
821int main(int argc, char **argv)
822{
823 /*
824 * Init version.
825 */
826 g_dwVersion = GetVersion();
827 g_uSaneVersion = MAKE_SANE_VERSION(g_dwVersion & 0xff, (g_dwVersion >> 8) & 0xff);
828
829 /*
830 * Parse arguments.
831 */
832 static RTGETOPTDEF const s_aOptions[] =
833 {
834 { "--status", 1000 + 's', RTGETOPT_REQ_NOTHING },
835 { "--install", 1000 + 'i', RTGETOPT_REQ_NOTHING },
836 { "--uninstall", 1000 + 'u', RTGETOPT_REQ_NOTHING },
837 { "--select", 's', RTGETOPT_REQ_STRING },
838 { "--8-dot-3", '8', RTGETOPT_REQ_NOTHING },
839 { "--long-names", 'l', RTGETOPT_REQ_NOTHING },
840 { "--src", 'S', RTGETOPT_REQ_STRING },
841 { "--source", 'S', RTGETOPT_REQ_STRING },
842 };
843
844 bool fFirstSelect = true;
845 bool f8Dot3 = false;
846 enum { kMode_Status, kMode_Install, kMode_Uninstall }
847 enmMode = kMode_Status;
848
849 g_cwcSrc = GetModuleFileNameW(NULL, g_wszSrc, RT_ELEMENTS(g_wszSrc));
850 if (g_cwcSrc == 0)
851 return RTMsgErrorExitFailure("GetModuleFileNameW failed: %u\n", GetLastError());
852 while (g_cwcSrc > 0 && !RTPATH_IS_SEP(g_wszSrc[g_cwcSrc - 1]))
853 g_cwcSrc--;
854 g_wszSrc[g_cwcSrc] = '\0';
855
856 RTGETOPTSTATE State;
857 int rc = RTGetOptInit(&State,argc,argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
858 if (RT_FAILURE(rc))
859 return RTMsgErrorExitFailure("RTGetOptInit failed: %Rrc\n", rc);
860
861 RTGETOPTUNION ValueUnion;
862 int chOpt;
863 while ((chOpt = RTGetOpt(&State, &ValueUnion)) != 0)
864 {
865 switch (chOpt)
866 {
867 case 1000 + 's':
868 enmMode = kMode_Status;
869 break;
870
871 case 1000 + 'i':
872 enmMode = kMode_Install;
873 break;
874
875 case 1000 + 'u':
876 enmMode = kMode_Uninstall;
877 break;
878
879 case '8':
880 f8Dot3 = true;
881 break;
882
883 case 'l':
884 f8Dot3 = false;
885 break;
886
887 case 's':
888 {
889 size_t i;
890 if (fFirstSelect)
891 {
892 for (i = 0; i < RT_ELEMENTS(g_aComponents); i++)
893 g_aComponents[i].fSelected = false;
894 fFirstSelect = false;
895 }
896 for (i = 0; i < RT_ELEMENTS(g_aComponents); i++)
897 if (RTStrICmpAscii(ValueUnion.psz, g_aComponents[i].pszName) == 0)
898 {
899 g_aComponents[i].fSelected = true;
900 break;
901 }
902 if (i >= RT_ELEMENTS(g_aComponents))
903 return RTMsgErrorExitFailure("Unknown component: %s\n", ValueUnion.psz);
904 break;
905 }
906
907 case 'S':
908 {
909 PRTUTF16 pwszDst = g_wszSrc;
910 rc = RTStrToUtf16Ex(ValueUnion.psz, RTSTR_MAX, &pwszDst, RT_ELEMENTS(g_wszSrc) - 16, &g_cwcSrc);
911 if (RT_FAILURE(rc))
912 return RTMsgErrorExitFailure("Error converting source to UTF-16: %Rrc\n", rc);
913 if (!g_cwcSrc)
914 return RTMsgErrorExitFailure("Empty source argument!\n");
915 if (!RTPATH_IS_SEP(g_wszSrc[g_cwcSrc - 1]))
916 {
917 g_wszSrc[g_cwcSrc++] = '\\';
918 g_wszSrc[g_cwcSrc] = '\0';
919 }
920 break;
921 }
922
923 case 'h':
924 return usage(argv[0]);
925
926 case 'V':
927 RTPrintf("%sr%u\n", VBOX_VERSION_STRING, VBOX_SVN_REV);
928 return RTEXITCODE_SUCCESS;
929
930 default:
931 return RTGetOptPrintError(chOpt, &ValueUnion);
932 }
933 }
934
935 /*
936 * Before we do anything gather status info on the components.
937 */
938 UpdateStatus();
939
940 /*
941 * Take action.
942 */
943 if (enmMode == kMode_Status)
944 return DoStatus();
945 if (enmMode == kMode_Install)
946 return DoInstall(f8Dot3);
947 return DoUninstall();
948}
949
950
951#include <internal/process.h>
952
953RT_C_DECLS_BEGIN
954DECLHIDDEN(char) g_szrtProcExePath[RTPATH_MAX] = "Unknown.exe";
955DECLHIDDEN(size_t) g_cchrtProcExePath = 11;
956DECLHIDDEN(size_t) g_cchrtProcExeDir = 0;
957DECLHIDDEN(size_t) g_offrtProcName = 0;
958RT_C_DECLS_END
959
960
961DECL_NO_INLINE(static, void) initProcExecPath(void)
962{
963 WCHAR wszPath[RTPATH_MAX];
964 UINT cwcPath = GetModuleFileNameW(NULL, wszPath, RT_ELEMENTS(wszPath));
965 if (cwcPath)
966 {
967 char *pszDst = g_szrtProcExePath;
968 int rc = RTUtf16ToUtf8Ex(wszPath, cwcPath, &pszDst, sizeof(g_szrtProcExePath), &g_cchrtProcExePath);
969 if (RT_SUCCESS(rc))
970 {
971 g_cchrtProcExeDir = g_offrtProcName = RTPathFilename(pszDst) - g_szrtProcExePath;
972 while ( g_cchrtProcExeDir >= 2
973 && RTPATH_IS_SLASH(g_szrtProcExePath[g_cchrtProcExeDir - 1])
974 && g_szrtProcExePath[g_cchrtProcExeDir - 2] != ':')
975 g_cchrtProcExeDir--;
976 }
977 }
978}
979
980
981void CustomMainEntrypoint(PPEB pPeb)
982{
983 /*
984 * Initialize stuff.
985 */
986 InitStdHandles(pPeb->ProcessParameters);
987 initProcExecPath();
988
989 /*
990 * Get and convert the command line to argc/argv format.
991 */
992 RTEXITCODE rcExit;
993 UNICODE_STRING const *pCmdLine = pPeb->ProcessParameters ? &pPeb->ProcessParameters->CommandLine : NULL;
994 if (pCmdLine)
995 {
996 char *pszCmdLine = NULL;
997 int rc = RTUtf16ToUtf8Ex(pCmdLine->Buffer, pCmdLine->Length / sizeof(WCHAR), &pszCmdLine, 0, NULL);
998 if (RT_SUCCESS(rc))
999 {
1000 char **papszArgv;
1001 int cArgs = 0;
1002 rc = RTGetOptArgvFromString(&papszArgv, &cArgs, pszCmdLine,
1003 RTGETOPTARGV_CNV_MODIFY_INPUT | RTGETOPTARGV_CNV_QUOTE_MS_CRT, NULL);
1004 if (RT_SUCCESS(rc))
1005 {
1006 /*
1007 * Call the main function.
1008 */
1009 rcExit = (RTEXITCODE)main(cArgs, papszArgv);
1010 }
1011 else
1012 rcExit = RTMsgErrorExitFailure("Error parsing command line: %Rrc\n", rc);
1013 }
1014 else
1015 rcExit = RTMsgErrorExitFailure("Failed to convert command line to UTF-8: %Rrc\n", rc);
1016 }
1017 else
1018 rcExit = RTMsgErrorExitFailure("No command line\n");
1019
1020 for (;;)
1021 NtTerminateProcess(NtCurrentProcess(), rcExit);
1022}
1023
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette