VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Installer/InstallHelper/VBoxGuestInstallHelper.cpp@ 82627

Last change on this file since 82627 was 82627, checked in by vboxsync, 5 years ago

Windows Additions/Installer: Got rid of own system library loading code and use RTLdrLoadSystem() and friends instead.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.0 KB
Line 
1/* $Id: VBoxGuestInstallHelper.cpp 82627 2019-12-20 09:22:17Z vboxsync $ */
2/** @file
3 * VBoxGuestInstallHelper - Various helper routines for Windows guest installer.
4 * Works with NSIS 3.x.
5 */
6
7/*
8 * Copyright (C) 2011-2019 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19
20/*********************************************************************************************************************************
21* Header Files *
22*********************************************************************************************************************************/
23#include <iprt/win/windows.h>
24#include <stdlib.h>
25#include <tchar.h>
26#include <strsafe.h>
27#pragma warning(push)
28#pragma warning(disable: 4995) /* warning C4995: 'lstrcpyA': name was marked as #pragma deprecated */
29#include "exdll.h"
30#pragma warning(pop)
31
32#include <iprt/err.h>
33#include <iprt/initterm.h>
34#include <iprt/ldr.h>
35#include <iprt/localipc.h>
36#include <iprt/mem.h>
37#include <iprt/process.h>
38#include <iprt/string.h>
39#ifdef UNICODE
40# include <iprt/utf16.h>
41#endif
42
43/* Required structures/defines of VBoxTray. */
44#include "../../VBoxTray/VBoxTrayMsg.h"
45
46
47/*********************************************************************************************************************************
48* Defined Constants And Macros *
49*********************************************************************************************************************************/
50#define VBOXINSTALLHELPER_EXPORT extern "C" void __declspec(dllexport)
51
52
53/*********************************************************************************************************************************
54* Structures and Typedefs *
55*********************************************************************************************************************************/
56typedef DWORD (WINAPI *PFNSFCFILEEXCEPTION)(DWORD param1, PWCHAR param2, DWORD param3);
57
58
59/*********************************************************************************************************************************
60* Global Variables *
61*********************************************************************************************************************************/
62HINSTANCE g_hInstance;
63HWND g_hwndParent;
64PFNSFCFILEEXCEPTION g_pfnSfcFileException = NULL;
65
66/**
67 * @todo Clean up this DLL, use more IPRT in here!
68 */
69
70/**
71 * Pops (gets) a value from the internal NSIS stack.
72 * Since the supplied popstring() method easily can cause buffer
73 * overflows, use vboxPopString() instead!
74 *
75 * @return VBox status code.
76 * @param pszDest Pointer to pre-allocated string to store result.
77 * @param cchDest Size (in characters) of pre-allocated string.
78 */
79static int vboxPopString(TCHAR *pszDest, size_t cchDest)
80{
81 int rc = VINF_SUCCESS;
82
83 if (!g_stacktop || !*g_stacktop)
84 {
85 rc = VERR_NO_DATA;
86 }
87 else
88 {
89 stack_t *pStack = (*g_stacktop);
90 AssertPtr(pStack);
91
92 HRESULT hr = StringCchCopy(pszDest, cchDest, pStack->text);
93 if (SUCCEEDED(hr))
94 {
95 *g_stacktop = pStack->next;
96 GlobalFree((HGLOBAL)pStack);
97 }
98 else
99 rc = VERR_INVALID_PARAMETER;
100 }
101 return rc;
102}
103
104static int vboxPopULong(PULONG pulValue)
105{
106 int rc = VINF_SUCCESS;
107
108 if (!g_stacktop || !*g_stacktop)
109 {
110 rc = VERR_NO_DATA;
111 }
112 else
113 {
114 stack_t *pStack = (*g_stacktop);
115 AssertPtr(pStack);
116
117 *pulValue = _tcstoul(pStack->text, NULL, 10 /* Base */);
118
119 *g_stacktop = pStack->next;
120 GlobalFree((HGLOBAL)pStack);
121 }
122
123 return rc;
124}
125
126static void vboxPushHResultAsString(HRESULT hr)
127{
128 TCHAR szErr[NSIS_MAX_STRLEN];
129 if (FAILED(hr))
130 {
131 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, 0, szErr, MAX_PATH, NULL))
132 szErr[MAX_PATH] = '\0';
133 else
134 StringCchPrintf(szErr, sizeof(szErr),
135 _T("FormatMessage failed! Error = %ld"), GetLastError());
136 }
137 else
138 StringCchPrintf(szErr, sizeof(szErr), _T("0"));
139 pushstring(szErr);
140}
141
142static void vboxPushRcAsString(int rc)
143{
144 TCHAR szErr[NSIS_MAX_STRLEN];
145 if (RT_FAILURE(rc))
146 {
147
148#ifdef UNICODE
149 TCHAR *pszErrAsString;
150 int rc2 = RTStrToUtf16(RTErrGetDefine(rc), &pszErrAsString);
151 if (RT_SUCCESS(rc2))
152 {
153#else
154 TCHAR *pszErrAsString = RTErrGetDefine(rc);
155#endif
156 StringCchPrintf(szErr, sizeof(szErr), _T("Error: %s"), pszErrAsString);
157
158#ifdef UNICODE
159 RTUtf16Free(pszErrAsString);
160 }
161#endif
162 }
163 else
164 StringCchPrintf(szErr, sizeof(szErr), _T("0"));
165
166 pushstring(szErr);
167}
168
169/**
170 * Connects to VBoxTray IPC under the behalf of the user running
171 * in the current thread context.
172 *
173 * @return IPRT status code.
174 * @param phSession Where to store the IPC session.
175 */
176static int vboxConnectToVBoxTray(RTLOCALIPCSESSION *phSession)
177{
178 char szPipeName[512 + sizeof(VBOXTRAY_IPC_PIPE_PREFIX)];
179 memcpy(szPipeName, VBOXTRAY_IPC_PIPE_PREFIX, sizeof(VBOXTRAY_IPC_PIPE_PREFIX));
180 int rc = RTProcQueryUsername(NIL_RTPROCESS,
181 &szPipeName[sizeof(VBOXTRAY_IPC_PIPE_PREFIX) - 1],
182 sizeof(szPipeName) - sizeof(VBOXTRAY_IPC_PIPE_PREFIX) + 1,
183 NULL /*pcbUser*/);
184 if (RT_SUCCESS(rc))
185 rc = RTLocalIpcSessionConnect(phSession, szPipeName, RTLOCALIPC_FLAGS_NATIVE_NAME);
186 return rc;
187}
188
189#ifndef UNICODE
190static void vboxChar2WCharFree(PWCHAR pwString)
191{
192 if (pwString)
193 HeapFree(GetProcessHeap(), 0, pwString);
194}
195
196static int vboxChar2WCharAlloc(const TCHAR *pszString, PWCHAR *ppwString)
197{
198 int rc = VINF_SUCCESS;
199
200 int iLen = (int)_tcslen(pszString) + 2;
201 WCHAR *pwString = (WCHAR*)HeapAlloc(GetProcessHeap(), 0, iLen * sizeof(WCHAR));
202 if (!pwString)
203 {
204 rc = VERR_NO_MEMORY;
205 }
206 else
207 {
208 if (MultiByteToWideChar(CP_ACP, 0, pszString, -1, pwString, iLen) == 0)
209 {
210 rc = VERR_INVALID_PARAMETER;
211 HeapFree(GetProcessHeap(), 0, pwString);
212 }
213 else
214 {
215 *ppwString = pwString;
216 }
217 }
218 return rc;
219}
220#endif /* !UNICODE */
221
222/**
223 * Disables the Windows File Protection for a specified file
224 * using an undocumented SFC API call. Don't try this at home!
225 *
226 * @param hwndParent Window handle of parent.
227 * @param string_size Size of variable string.
228 * @param variables The actual variable string.
229 * @param stacktop Pointer to a pointer to the current stack.
230 * @param extra Extra parameters. Currently unused.
231 */
232VBOXINSTALLHELPER_EXPORT DisableWFP(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop,
233 extra_parameters *extra)
234{
235 RT_NOREF(hwndParent, extra);
236
237 EXDLL_INIT();
238
239 TCHAR szFile[MAX_PATH + 1];
240 int rc = vboxPopString(szFile, sizeof(szFile) / sizeof(TCHAR));
241 if (RT_SUCCESS(rc))
242 {
243 HMODULE hSFCNative = NULL; /* Native fallback. */
244
245 RTLDRMOD hSFC;
246 rc = RTLdrLoadSystem("sfc_os.dll", true /* fNoUnload */, &hSFC);
247 if (RT_SUCCESS(rc))
248 {
249 rc = RTLdrGetSymbol(hSFC, "SfcFileException", (void **)&g_pfnSfcFileException);
250 if (RT_FAILURE(rc))
251 {
252 hSFCNative = (HMODULE)RTLdrGetNativeHandle(hSFC);
253
254 /* If we didn't get the proc address with the call above, try it harder with
255 * the (zero based) index of the function list (ordinal). */
256 g_pfnSfcFileException = (PFNSFCFILEEXCEPTION)GetProcAddress(hSFCNative, (LPCSTR)5);
257 if (g_pfnSfcFileException)
258 rc = VINF_SUCCESS;
259 }
260
261 RTLdrClose(hSFC);
262 }
263
264 if (RT_SUCCESS(rc))
265 {
266#ifndef UNICODE
267 WCHAR *pwszFile;
268 rc = vboxChar2WCharAlloc(szFile, &pwszFile);
269 if (RT_SUCCESS(rc))
270 {
271#else
272 TCHAR *pwszFile = szFile;
273#endif
274 if (g_pfnSfcFileException(0, pwszFile, UINT32_MAX) != 0)
275 rc = VERR_ACCESS_DENIED; /** @todo Find a better rc. */
276#ifndef UNICODE
277 vboxChar2WCharFree(pwszFile);
278 }
279#endif
280 }
281
282 if (hSFCNative)
283 FreeLibrary(hSFCNative);
284 }
285
286 vboxPushRcAsString(rc);
287}
288
289/**
290 * Retrieves a file's architecture (x86 or amd64).
291 * Outputs "x86", "amd64" or an error message (if not found/invalid) on stack.
292 *
293 * @param hwndParent Window handle of parent.
294 * @param string_size Size of variable string.
295 * @param variables The actual variable string.
296 * @param stacktop Pointer to a pointer to the current stack.
297 * @param extra Extra parameters. Currently unused.
298 */
299VBOXINSTALLHELPER_EXPORT FileGetArchitecture(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop,
300 extra_parameters *extra)
301{
302 RT_NOREF(hwndParent, extra);
303
304 EXDLL_INIT();
305
306 TCHAR szFile[MAX_PATH + 1];
307 int rc = vboxPopString(szFile, sizeof(szFile) / sizeof(TCHAR));
308 if (RT_SUCCESS(rc))
309 {
310#ifdef UNICODE
311 char *pszFileUtf8;
312 int rc = RTUtf16ToUtf8(szFile, &pszFileUtf8);
313 if (RT_SUCCESS(rc))
314 {
315#else
316 char *pszFileUtf8 = szFile;
317#endif
318 RTLDRMOD hLdrMod;
319 rc = RTLdrOpen(pszFileUtf8, RTLDR_O_FOR_VALIDATION, RTLDRARCH_WHATEVER, &hLdrMod);
320 if (RT_SUCCESS(rc))
321 {
322 if (RTLdrGetFormat(hLdrMod) == RTLDRFMT_PE)
323 {
324 RTLDRARCH enmLdrArch = RTLdrGetArch(hLdrMod);
325 switch (enmLdrArch)
326 {
327 case RTLDRARCH_X86_32:
328 pushstring(_T("x86"));
329 break;
330
331 case RTLDRARCH_AMD64:
332 pushstring(_T("amd64"));
333 break;
334
335 default:
336 pushstring(_T("Error: Unknown / invalid architecture"));
337 break;
338 }
339 }
340 else
341 pushstring(_T("Error: Unknown / invalid PE signature"));
342
343 RTLdrClose(hLdrMod);
344 }
345 else
346 pushstring(_T("Error: Could not open file"));
347#ifdef UNICODE
348 RTStrFree(pszFileUtf8);
349 }
350#endif
351 }
352 else
353 pushstring(_T("Error: Could not retrieve file name"));
354}
355
356/**
357 * Retrieves a file's vendor.
358 * Outputs the vendor's name or an error message (if not found/invalid) on stack.
359 *
360 * @param hwndParent Window handle of parent.
361 * @param string_size Size of variable string.
362 * @param variables The actual variable string.
363 * @param stacktop Pointer to a pointer to the current stack.
364 * @param extra Extra parameters. Currently unused.
365 */
366VBOXINSTALLHELPER_EXPORT FileGetVendor(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop,
367 extra_parameters *extra)
368{
369 RT_NOREF(hwndParent, extra);
370
371 EXDLL_INIT();
372
373 TCHAR szFile[MAX_PATH + 1];
374 int rc = vboxPopString(szFile, sizeof(szFile) / sizeof(TCHAR));
375 if (RT_SUCCESS(rc))
376 {
377 DWORD dwInfoSize = GetFileVersionInfoSize(szFile, NULL /* lpdwHandle */);
378 if (dwInfoSize)
379 {
380 void *pFileInfo = GlobalAlloc(GMEM_FIXED, dwInfoSize);
381 if (pFileInfo)
382 {
383 if (GetFileVersionInfo(szFile, 0, dwInfoSize, pFileInfo))
384 {
385 LPVOID pvInfo;
386 UINT puInfoLen;
387 if (VerQueryValue(pFileInfo, _T("\\VarFileInfo\\Translation"),
388 &pvInfo, &puInfoLen))
389 {
390 WORD wCodePage = LOWORD(*(DWORD*)pvInfo);
391 WORD wLanguageID = HIWORD(*(DWORD*)pvInfo);
392
393 TCHAR szQuery[MAX_PATH];
394 StringCchPrintf(szQuery, sizeof(szQuery), _T("StringFileInfo\\%04X%04X\\CompanyName"),
395 wCodePage, wLanguageID);
396
397 LPCTSTR pcData;
398 if (VerQueryValue(pFileInfo, szQuery, (void**)&pcData, &puInfoLen))
399 {
400 pushstring(pcData);
401 }
402 else
403 rc = VERR_NOT_FOUND;
404 }
405 else
406 rc = VERR_NOT_FOUND;
407 }
408 GlobalFree(pFileInfo);
409 }
410 else
411 rc = VERR_NO_MEMORY;
412 }
413 else
414 rc = VERR_NOT_FOUND;
415 }
416
417 if (RT_FAILURE(rc))
418 vboxPushRcAsString(rc);
419}
420
421/**
422 * Shows a balloon message using VBoxTray's notification area in the
423 * Windows task bar.
424 *
425 * @param hwndParent Window handle of parent.
426 * @param string_size Size of variable string.
427 * @param variables The actual variable string.
428 * @param stacktop Pointer to a pointer to the current stack.
429 * @param extra Extra parameters. Currently unused.
430 */
431VBOXINSTALLHELPER_EXPORT VBoxTrayShowBallonMsg(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop,
432 extra_parameters *extra)
433{
434 RT_NOREF(hwndParent, extra);
435
436 EXDLL_INIT();
437
438 TCHAR szMsg[256];
439 TCHAR szTitle[128];
440 int rc = vboxPopString(szMsg, sizeof(szMsg) / sizeof(TCHAR));
441 if (RT_SUCCESS(rc))
442 rc = vboxPopString(szTitle, sizeof(szTitle) / sizeof(TCHAR));
443
444 /** @todo Do we need to restore the stack on failure? */
445
446 if (RT_SUCCESS(rc))
447 {
448 RTR3InitDll(0);
449
450#ifdef UNICODE
451 char *pszMsgUtf8 = NULL;
452 char *pszTitleUtf8 = NULL;
453 rc = RTUtf16ToUtf8(szMsg, &pszMsgUtf8);
454 if (RT_SUCCESS(rc))
455 rc = RTUtf16ToUtf8(szTitle, &pszTitleUtf8);
456#else
457 char *pszMsgUtf8 = szMsg;
458 char *pszTitleUtf8 = szTitle;
459#endif
460 if (RT_SUCCESS(rc))
461 {
462 /* We use UTF-8 for the IPC data. */
463 uint32_t cbMsg = sizeof(VBOXTRAYIPCMSG_SHOWBALLOONMSG)
464 + (uint32_t)strlen(pszMsgUtf8) + 1 /* Include terminating zero */
465 + (uint32_t)strlen(pszTitleUtf8) + 1; /* Ditto. */
466 Assert(cbMsg);
467 PVBOXTRAYIPCMSG_SHOWBALLOONMSG pIpcMsg = (PVBOXTRAYIPCMSG_SHOWBALLOONMSG)RTMemAlloc(cbMsg);
468 if (pIpcMsg)
469 {
470 /* Stuff in the strings. */
471 memcpy(pIpcMsg->szMsgContent, pszMsgUtf8, strlen(pszMsgUtf8) + 1);
472 memcpy(pIpcMsg->szMsgTitle, pszTitleUtf8, strlen(pszTitleUtf8) + 1);
473
474 /* Pop off the values in reverse order from the stack. */
475 rc = vboxPopULong((ULONG *)&pIpcMsg->uType);
476 if (RT_SUCCESS(rc))
477 rc = vboxPopULong((ULONG *)&pIpcMsg->uShowMS);
478
479 if (RT_SUCCESS(rc))
480 {
481 RTLOCALIPCSESSION hSession = 0;
482 rc = vboxConnectToVBoxTray(&hSession);
483 if (RT_SUCCESS(rc))
484 {
485 VBOXTRAYIPCHEADER ipcHdr = { VBOXTRAY_IPC_HDR_MAGIC, 0 /* Header version */,
486 VBOXTRAYIPCMSGTYPE_SHOWBALLOONMSG, cbMsg };
487
488 rc = RTLocalIpcSessionWrite(hSession, &ipcHdr, sizeof(ipcHdr));
489 if (RT_SUCCESS(rc))
490 rc = RTLocalIpcSessionWrite(hSession, pIpcMsg, cbMsg);
491
492 int rc2 = RTLocalIpcSessionClose(hSession);
493 if (RT_SUCCESS(rc))
494 rc = rc2;
495 }
496 }
497
498 RTMemFree(pIpcMsg);
499 }
500 else
501 rc = VERR_NO_MEMORY;
502#ifdef UNICODE
503 RTStrFree(pszMsgUtf8);
504 RTStrFree(pszTitleUtf8);
505#endif
506 }
507 }
508
509 vboxPushRcAsString(rc);
510}
511
512BOOL WINAPI DllMain(HANDLE hInst, ULONG uReason, LPVOID pReserved)
513{
514 RT_NOREF(uReason, pReserved);
515 g_hInstance = (HINSTANCE)hInst;
516 return TRUE;
517}
518
Note: See TracBrowser for help on using the repository browser.

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