VirtualBox

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

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

Windows Additions/Installer: More work required for the VBoxGuestInstallHelper plugin to respect ANSI/Unicode with NSIS 3.x (NSIS uses TCHAR), extended the testcase, bugref:9529.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.3 KB
Line 
1/* $Id: VBoxGuestInstallHelper.cpp 82626 2019-12-19 16:21:19Z 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 * Loads a system DLL.
224 *
225 * @returns Module handle or NULL
226 * @param pszName The DLL name.
227 */
228static HMODULE loadSystemDll(const char *pszName)
229{
230 char szPath[MAX_PATH];
231 UINT cchPath = GetSystemDirectoryA(szPath, sizeof(szPath));
232 size_t cbName = strlen(pszName) + 1;
233 if (cchPath + 1 + cbName > sizeof(szPath))
234 return NULL;
235 szPath[cchPath] = '\\';
236 memcpy(&szPath[cchPath + 1], pszName, cbName);
237 return LoadLibraryA(szPath);
238}
239
240/**
241 * Disables the Windows File Protection for a specified file
242 * using an undocumented SFC API call. Don't try this at home!
243 *
244 * @param hwndParent Window handle of parent.
245 * @param string_size Size of variable string.
246 * @param variables The actual variable string.
247 * @param stacktop Pointer to a pointer to the current stack.
248 * @param extra Extra parameters. Currently unused.
249 */
250VBOXINSTALLHELPER_EXPORT DisableWFP(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop,
251 extra_parameters *extra)
252{
253 RT_NOREF(hwndParent, extra);
254
255 EXDLL_INIT();
256
257 TCHAR szFile[MAX_PATH + 1];
258 int rc = vboxPopString(szFile, sizeof(szFile) / sizeof(TCHAR));
259 if (RT_SUCCESS(rc))
260 {
261 HMODULE hSFC = loadSystemDll("sfc_os.dll"); /** @todo Replace this by RTLdr APIs. */
262 if (NULL != hSFC)
263 {
264 g_pfnSfcFileException = (PFNSFCFILEEXCEPTION)GetProcAddress(hSFC, "SfcFileException");
265 if (g_pfnSfcFileException == NULL)
266 {
267 /* If we didn't get the proc address with the call above, try it harder with
268 * the (zero based) index of the function list. */
269 g_pfnSfcFileException = (PFNSFCFILEEXCEPTION)GetProcAddress(hSFC, (LPCSTR)5);
270 if (g_pfnSfcFileException == NULL)
271 rc = VERR_SYMBOL_NOT_FOUND;
272 }
273 }
274 else
275 rc = VERR_FILE_NOT_FOUND;
276
277 if (RT_SUCCESS(rc))
278 {
279#ifndef UNICODE
280 WCHAR *pwszFile;
281 rc = vboxChar2WCharAlloc(szFile, &pwszFile);
282 if (RT_SUCCESS(rc))
283 {
284#else
285 TCHAR *pwszFile = szFile;
286#endif
287 if (g_pfnSfcFileException(0, pwszFile, UINT32_MAX) != 0)
288 rc = VERR_ACCESS_DENIED; /** @todo Find a better rc. */
289#ifndef UNICODE
290 vboxChar2WCharFree(pwszFile);
291 }
292#endif
293 }
294
295 if (hSFC)
296 FreeLibrary(hSFC);
297 }
298
299 vboxPushRcAsString(rc);
300}
301
302/**
303 * Retrieves a file's architecture (x86 or amd64).
304 * Outputs "x86", "amd64" or an error message (if not found/invalid) on stack.
305 *
306 * @param hwndParent Window handle of parent.
307 * @param string_size Size of variable string.
308 * @param variables The actual variable string.
309 * @param stacktop Pointer to a pointer to the current stack.
310 * @param extra Extra parameters. Currently unused.
311 */
312VBOXINSTALLHELPER_EXPORT FileGetArchitecture(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop,
313 extra_parameters *extra)
314{
315 RT_NOREF(hwndParent, extra);
316
317 EXDLL_INIT();
318
319 TCHAR szFile[MAX_PATH + 1];
320 int rc = vboxPopString(szFile, sizeof(szFile) / sizeof(TCHAR));
321 if (RT_SUCCESS(rc))
322 {
323#ifdef UNICODE
324 char *pszFileUtf8;
325 int rc = RTUtf16ToUtf8(szFile, &pszFileUtf8);
326 if (RT_SUCCESS(rc))
327 {
328#else
329 char *pszFileUtf8 = szFile;
330#endif
331 RTLDRMOD hLdrMod;
332 rc = RTLdrOpen(pszFileUtf8, RTLDR_O_FOR_VALIDATION, RTLDRARCH_WHATEVER, &hLdrMod);
333 if (RT_SUCCESS(rc))
334 {
335 if (RTLdrGetFormat(hLdrMod) == RTLDRFMT_PE)
336 {
337 RTLDRARCH enmLdrArch = RTLdrGetArch(hLdrMod);
338 switch (enmLdrArch)
339 {
340 case RTLDRARCH_X86_32:
341 pushstring(_T("x86"));
342 break;
343
344 case RTLDRARCH_AMD64:
345 pushstring(_T("amd64"));
346 break;
347
348 default:
349 pushstring(_T("Error: Unknown / invalid architecture"));
350 break;
351 }
352 }
353 else
354 pushstring(_T("Error: Unknown / invalid PE signature"));
355
356 RTLdrClose(hLdrMod);
357 }
358 else
359 pushstring(_T("Error: Could not open file"));
360#ifdef UNICODE
361 RTStrFree(pszFileUtf8);
362 }
363#endif
364 }
365 else
366 pushstring(_T("Error: Could not retrieve file name"));
367}
368
369/**
370 * Retrieves a file's vendor.
371 * Outputs the vendor's name or an error message (if not found/invalid) on stack.
372 *
373 * @param hwndParent Window handle of parent.
374 * @param string_size Size of variable string.
375 * @param variables The actual variable string.
376 * @param stacktop Pointer to a pointer to the current stack.
377 * @param extra Extra parameters. Currently unused.
378 */
379VBOXINSTALLHELPER_EXPORT FileGetVendor(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop,
380 extra_parameters *extra)
381{
382 RT_NOREF(hwndParent, extra);
383
384 EXDLL_INIT();
385
386 TCHAR szFile[MAX_PATH + 1];
387 int rc = vboxPopString(szFile, sizeof(szFile) / sizeof(TCHAR));
388 if (RT_SUCCESS(rc))
389 {
390 DWORD dwInfoSize = GetFileVersionInfoSize(szFile, NULL /* lpdwHandle */);
391 if (dwInfoSize)
392 {
393 void *pFileInfo = GlobalAlloc(GMEM_FIXED, dwInfoSize);
394 if (pFileInfo)
395 {
396 if (GetFileVersionInfo(szFile, 0, dwInfoSize, pFileInfo))
397 {
398 LPVOID pvInfo;
399 UINT puInfoLen;
400 if (VerQueryValue(pFileInfo, _T("\\VarFileInfo\\Translation"),
401 &pvInfo, &puInfoLen))
402 {
403 WORD wCodePage = LOWORD(*(DWORD*)pvInfo);
404 WORD wLanguageID = HIWORD(*(DWORD*)pvInfo);
405
406 TCHAR szQuery[MAX_PATH];
407 StringCchPrintf(szQuery, sizeof(szQuery), _T("StringFileInfo\\%04X%04X\\CompanyName"),
408 wCodePage, wLanguageID);
409
410 LPCTSTR pcData;
411 if (VerQueryValue(pFileInfo, szQuery, (void**)&pcData, &puInfoLen))
412 {
413 pushstring(pcData);
414 }
415 else
416 rc = VERR_NOT_FOUND;
417 }
418 else
419 rc = VERR_NOT_FOUND;
420 }
421 GlobalFree(pFileInfo);
422 }
423 else
424 rc = VERR_NO_MEMORY;
425 }
426 else
427 rc = VERR_NOT_FOUND;
428 }
429
430 if (RT_FAILURE(rc))
431 vboxPushRcAsString(rc);
432}
433
434/**
435 * Shows a balloon message using VBoxTray's notification area in the
436 * Windows task bar.
437 *
438 * @param hwndParent Window handle of parent.
439 * @param string_size Size of variable string.
440 * @param variables The actual variable string.
441 * @param stacktop Pointer to a pointer to the current stack.
442 * @param extra Extra parameters. Currently unused.
443 */
444VBOXINSTALLHELPER_EXPORT VBoxTrayShowBallonMsg(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop,
445 extra_parameters *extra)
446{
447 RT_NOREF(hwndParent, extra);
448
449 EXDLL_INIT();
450
451 TCHAR szMsg[256];
452 TCHAR szTitle[128];
453 int rc = vboxPopString(szMsg, sizeof(szMsg) / sizeof(TCHAR));
454 if (RT_SUCCESS(rc))
455 rc = vboxPopString(szTitle, sizeof(szTitle) / sizeof(TCHAR));
456
457 /** @todo Do we need to restore the stack on failure? */
458
459 if (RT_SUCCESS(rc))
460 {
461 RTR3InitDll(0);
462
463#ifdef UNICODE
464 char *pszMsgUtf8 = NULL;
465 char *pszTitleUtf8 = NULL;
466 rc = RTUtf16ToUtf8(szMsg, &pszMsgUtf8);
467 if (RT_SUCCESS(rc))
468 rc = RTUtf16ToUtf8(szTitle, &pszTitleUtf8);
469#else
470 char *pszMsgUtf8 = szMsg;
471 char *pszTitleUtf8 = szTitle;
472#endif
473 if (RT_SUCCESS(rc))
474 {
475 /* We use UTF-8 for the IPC data. */
476 uint32_t cbMsg = sizeof(VBOXTRAYIPCMSG_SHOWBALLOONMSG)
477 + (uint32_t)strlen(pszMsgUtf8) + 1 /* Include terminating zero */
478 + (uint32_t)strlen(pszTitleUtf8) + 1; /* Ditto. */
479 Assert(cbMsg);
480 PVBOXTRAYIPCMSG_SHOWBALLOONMSG pIpcMsg = (PVBOXTRAYIPCMSG_SHOWBALLOONMSG)RTMemAlloc(cbMsg);
481 if (pIpcMsg)
482 {
483 /* Stuff in the strings. */
484 memcpy(pIpcMsg->szMsgContent, pszMsgUtf8, strlen(pszMsgUtf8) + 1);
485 memcpy(pIpcMsg->szMsgTitle, pszTitleUtf8, strlen(pszTitleUtf8) + 1);
486
487 /* Pop off the values in reverse order from the stack. */
488 rc = vboxPopULong((ULONG *)&pIpcMsg->uType);
489 if (RT_SUCCESS(rc))
490 rc = vboxPopULong((ULONG *)&pIpcMsg->uShowMS);
491
492 if (RT_SUCCESS(rc))
493 {
494 RTLOCALIPCSESSION hSession = 0;
495 rc = vboxConnectToVBoxTray(&hSession);
496 if (RT_SUCCESS(rc))
497 {
498 VBOXTRAYIPCHEADER ipcHdr = { VBOXTRAY_IPC_HDR_MAGIC, 0 /* Header version */,
499 VBOXTRAYIPCMSGTYPE_SHOWBALLOONMSG, cbMsg };
500
501 rc = RTLocalIpcSessionWrite(hSession, &ipcHdr, sizeof(ipcHdr));
502 if (RT_SUCCESS(rc))
503 rc = RTLocalIpcSessionWrite(hSession, pIpcMsg, cbMsg);
504
505 int rc2 = RTLocalIpcSessionClose(hSession);
506 if (RT_SUCCESS(rc))
507 rc = rc2;
508 }
509 }
510
511 RTMemFree(pIpcMsg);
512 }
513 else
514 rc = VERR_NO_MEMORY;
515#ifdef UNICODE
516 RTStrFree(pszMsgUtf8);
517 RTStrFree(pszTitleUtf8);
518#endif
519 }
520 }
521
522 vboxPushRcAsString(rc);
523}
524
525BOOL WINAPI DllMain(HANDLE hInst, ULONG uReason, LPVOID pReserved)
526{
527 RT_NOREF(uReason, pReserved);
528 g_hInstance = (HINSTANCE)hInst;
529 return TRUE;
530}
531
Note: See TracBrowser for help on using the repository browser.

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