VirtualBox

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

Last change on this file since 58832 was 57358, checked in by vboxsync, 9 years ago

*: scm cleanup run.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.5 KB
Line 
1/* $Id: VBoxGuestInstallHelper.cpp 57358 2015-08-14 15:16:38Z vboxsync $ */
2/** @file
3 * VBoxGuestInstallHelper - Various helper routines for Windows guest installer.
4 */
5
6/*
7 * Copyright (C) 2011-2013 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 <windows.h>
23#include <atlconv.h>
24#include <stdlib.h>
25#include <tchar.h>
26#include <strsafe.h>
27#include "exdll.h"
28
29#include <iprt/err.h>
30#include <iprt/initterm.h>
31#include <iprt/localipc.h>
32#include <iprt/mem.h>
33#include <iprt/string.h>
34
35/* Required structures/defines of VBoxTray. */
36#include "../../VBoxTray/VBoxTrayMsg.h"
37
38
39/*********************************************************************************************************************************
40* Defined Constants And Macros *
41*********************************************************************************************************************************/
42#define VBOXINSTALLHELPER_EXPORT extern "C" void __declspec(dllexport)
43
44
45/*********************************************************************************************************************************
46* Structures and Typedefs *
47*********************************************************************************************************************************/
48typedef DWORD (WINAPI *PFNSFCFILEEXCEPTION)(DWORD param1, PWCHAR param2, DWORD param3);
49
50
51/*********************************************************************************************************************************
52* Global Variables *
53*********************************************************************************************************************************/
54HINSTANCE g_hInstance;
55HWND g_hwndParent;
56PFNSFCFILEEXCEPTION g_pfnSfcFileException = NULL;
57
58/**
59 * @todo Clean up this DLL, use more IPRT in here!
60 */
61
62/**
63 * Pops (gets) a value from the internal NSIS stack.
64 * Since the supplied popstring() method easily can cause buffer
65 * overflows, use vboxPopString() instead!
66 *
67 * @return HRESULT
68 * @param pszDest Pointer to pre-allocated string to store result.
69 * @param cchDest Size (in characters) of pre-allocated string.
70 */
71static HRESULT vboxPopString(TCHAR *pszDest, size_t cchDest)
72{
73 HRESULT hr = S_OK;
74 if (!g_stacktop || !*g_stacktop)
75 hr = __HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE);
76 else
77 {
78 stack_t *pStack = (*g_stacktop);
79 if (pStack)
80 {
81 hr = StringCchCopy(pszDest, cchDest, pStack->text);
82 if (SUCCEEDED(hr))
83 {
84 *g_stacktop = pStack->next;
85 GlobalFree((HGLOBAL)pStack);
86 }
87 }
88 else
89 hr = __HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE);
90 }
91 return hr;
92}
93
94static HRESULT vboxPopULong(PULONG pulValue)
95{
96 HRESULT hr = S_OK;
97 if (!g_stacktop || !*g_stacktop)
98 hr = __HRESULT_FROM_WIN32(ERROR_EMPTY);
99 else
100 {
101 stack_t *pStack = (*g_stacktop);
102 if (pStack)
103 {
104 *pulValue = strtoul(pStack->text, NULL, 10 /* Base */);
105
106 *g_stacktop = pStack->next;
107 GlobalFree((HGLOBAL)pStack);
108 }
109 }
110 return hr;
111}
112
113static void vboxPushResultAsString(HRESULT hr)
114{
115 TCHAR szErr[MAX_PATH + 1];
116 if (FAILED(hr))
117 {
118 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, 0, szErr, MAX_PATH, NULL))
119 szErr[MAX_PATH] = '\0';
120 else
121 StringCchPrintf(szErr, sizeof(szErr),
122 "FormatMessage failed! Error = %ld", GetLastError());
123 }
124 else
125 StringCchPrintf(szErr, sizeof(szErr), "0");
126 pushstring(szErr);
127}
128
129/**
130 * Connects to VBoxTray IPC under the behalf of the user running
131 * in the current thread context.
132 *
133 * @return IPRT status code.
134 * @param phSession Where to store the IPC session.
135 */
136static int vboxConnectToVBoxTray(RTLOCALIPCSESSION *phSession)
137{
138 int rc = VINF_SUCCESS;
139
140 RTUTF16 wszUserName[255];
141 DWORD cchUserName = sizeof(wszUserName) / sizeof(RTUTF16);
142 BOOL fRc = GetUserNameW(wszUserName, &cchUserName);
143 if (!fRc)
144 rc = RTErrConvertFromWin32(GetLastError());
145
146 if (RT_SUCCESS(rc))
147 {
148 char *pszUserName;
149 rc = RTUtf16ToUtf8(wszUserName, &pszUserName);
150 if (RT_SUCCESS(rc))
151 {
152 char szPipeName[255];
153 if (RTStrPrintf(szPipeName, sizeof(szPipeName), "%s%s",
154 VBOXTRAY_IPC_PIPE_PREFIX, pszUserName))
155 {
156 rc = RTLocalIpcSessionConnect(phSession, szPipeName, 0 /* Flags */);
157 }
158 else
159 rc = VERR_NO_MEMORY;
160
161 RTStrFree(pszUserName);
162 }
163 }
164
165 return rc;
166}
167
168static void vboxChar2WCharFree(PWCHAR pwString)
169{
170 if (pwString)
171 HeapFree(GetProcessHeap(), 0, pwString);
172}
173
174static HRESULT vboxChar2WCharAlloc(const char *pszString, PWCHAR *ppwString)
175{
176 HRESULT hr;
177 int iLen = strlen(pszString) + 2;
178 WCHAR *pwString = (WCHAR*)HeapAlloc(GetProcessHeap(), 0, iLen * sizeof(WCHAR));
179 if (!pwString)
180 hr = __HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
181 else
182 {
183 if (MultiByteToWideChar(CP_ACP, 0, pszString, -1, pwString, iLen) == 0)
184 {
185 hr = HRESULT_FROM_WIN32(GetLastError());
186 HeapFree(GetProcessHeap(), 0, pwString);
187 }
188 else
189 {
190 hr = S_OK;
191 *ppwString = pwString;
192 }
193 }
194 return hr;
195}
196
197/**
198 * Loads a system DLL.
199 *
200 * @returns Module handle or NULL
201 * @param pszName The DLL name.
202 */
203static HMODULE loadSystemDll(const char *pszName)
204{
205 char szPath[MAX_PATH];
206 UINT cchPath = GetSystemDirectoryA(szPath, sizeof(szPath));
207 size_t cbName = strlen(pszName) + 1;
208 if (cchPath + 1 + cbName > sizeof(szPath))
209 return NULL;
210 szPath[cchPath] = '\\';
211 memcpy(&szPath[cchPath + 1], pszName, cbName);
212 return LoadLibraryA(szPath);
213}
214
215/**
216 * Disables the Windows File Protection for a specified file
217 * using an undocumented SFC API call. Don't try this at home!
218 *
219 * @param hwndParent Window handle of parent.
220 * @param string_size Size of variable string.
221 * @param variables The actual variable string.
222 * @param stacktop Pointer to a pointer to the current stack.
223 */
224VBOXINSTALLHELPER_EXPORT DisableWFP(HWND hwndParent, int string_size,
225 TCHAR *variables, stack_t **stacktop)
226{
227 EXDLL_INIT();
228
229 TCHAR szFile[MAX_PATH + 1];
230 HRESULT hr = vboxPopString(szFile, sizeof(szFile) / sizeof(TCHAR));
231 if (SUCCEEDED(hr))
232 {
233 HMODULE hSFC = loadSystemDll("sfc_os.dll"); /** @todo Replace this by RTLdr APIs. */
234 if (NULL != hSFC)
235 {
236 g_pfnSfcFileException = (PFNSFCFILEEXCEPTION)GetProcAddress(hSFC, "SfcFileException");
237 if (g_pfnSfcFileException == NULL)
238 {
239 /* If we didn't get the proc address with the call above, try it harder with
240 * the (zero based) index of the function list. */
241 g_pfnSfcFileException = (PFNSFCFILEEXCEPTION)GetProcAddress(hSFC, (LPCSTR)5);
242 if (g_pfnSfcFileException == NULL)
243 hr = HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND);
244 }
245 }
246 else
247 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
248
249 if (SUCCEEDED(hr))
250 {
251 WCHAR *pwszFile;
252 hr = vboxChar2WCharAlloc(szFile, &pwszFile);
253 if (SUCCEEDED(hr))
254 {
255 if (g_pfnSfcFileException(0, pwszFile, -1) != 0)
256 hr = HRESULT_FROM_WIN32(GetLastError());
257 vboxChar2WCharFree(pwszFile);
258 }
259 }
260
261 if (hSFC)
262 FreeLibrary(hSFC);
263 }
264
265 vboxPushResultAsString(hr);
266}
267
268/**
269 * Retrieves a file's architecture (x86 or amd64).
270 * Outputs "x86", "amd64" or an error message (if not found/invalid) on stack.
271 *
272 * @param hwndParent Window handle of parent.
273 * @param string_size Size of variable string.
274 * @param variables The actual variable string.
275 * @param stacktop Pointer to a pointer to the current stack.
276 */
277VBOXINSTALLHELPER_EXPORT FileGetArchitecture(HWND hwndParent, int string_size,
278 TCHAR *variables, stack_t **stacktop)
279{
280 EXDLL_INIT();
281
282 TCHAR szFile[MAX_PATH + 1];
283 HRESULT hr = vboxPopString(szFile, sizeof(szFile) / sizeof(TCHAR));
284 if (SUCCEEDED(hr))
285 {
286 /* See: http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx */
287 FILE *pFh = fopen(szFile, "rb");
288 if (pFh)
289 {
290 /* Assume the file is invalid. */
291 hr = __HRESULT_FROM_WIN32(ERROR_FILE_INVALID);
292
293 BYTE byOffsetPE; /* Absolute offset of PE signature. */
294
295 /* Do some basic validation. */
296 /* Check for "MZ" header (DOS stub). */
297 BYTE byBuf[255];
298 if ( fread(&byBuf, sizeof(BYTE), 2, pFh) == 2
299 && !memcmp(&byBuf, "MZ", 2))
300 {
301 /* Seek to 0x3C to get the PE offset. */
302 if (!fseek(pFh, 60L /*0x3C*/, SEEK_SET))
303 {
304 /* Read actual offset of PE signature. */
305 if (fread(&byOffsetPE, sizeof(BYTE), 1, pFh) == 1)
306 {
307 /* ... and seek to it. */
308 if (!fseek(pFh, byOffsetPE, SEEK_SET))
309 {
310 /* Validate PE signature. */
311 if (fread(byBuf, sizeof(BYTE), 4, pFh) == 4)
312 {
313 if (!memcmp(byBuf, "PE\0\0", 4))
314 hr = S_OK;
315 }
316 }
317 }
318 }
319 }
320
321 /* Validation successful? */
322 if (SUCCEEDED(hr))
323 {
324 BYTE byOffsetCOFF = byOffsetPE + 0x4; /* Skip PE signature. */
325
326 /** @todo When we need to do more stuff here, we probably should
327 * mmap the file w/ a struct so that we easily could access
328 * all the fixed size stuff. Later. */
329
330 /* Jump to machine type (first entry, 2 bytes):
331 * Use absolute PE offset retrieved above. */
332 if (!fseek(pFh, byOffsetCOFF, SEEK_SET))
333 {
334 WORD wMachineType;
335 if (fread(&wMachineType, 1,
336 sizeof(wMachineType), pFh) == 2)
337 {
338 switch (wMachineType)
339 {
340 case 0x14C: /* Intel 86 */
341 pushstring("x86");
342 break;
343
344 case 0x8664: /* AMD64 / x64 */
345 pushstring("amd64");
346 break;
347
348 default:
349 hr = __HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
350 break;
351 }
352 }
353 else
354 hr = __HRESULT_FROM_WIN32(ERROR_FILE_INVALID);
355 }
356 else
357 hr = __HRESULT_FROM_WIN32(ERROR_FILE_INVALID);
358 }
359
360 fclose(pFh);
361 }
362 else
363 hr = __HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
364 }
365
366 if (FAILED(hr))
367 vboxPushResultAsString(hr);
368}
369
370/**
371 * Retrieves a file's vendor.
372 * Outputs the vendor's name or an error message (if not found/invalid) on stack.
373 *
374 * @param hwndParent Window handle of parent.
375 * @param string_size Size of variable string.
376 * @param variables The actual variable string.
377 * @param stacktop Pointer to a pointer to the current stack.
378 */
379VBOXINSTALLHELPER_EXPORT FileGetVendor(HWND hwndParent, int string_size,
380 TCHAR *variables, stack_t **stacktop)
381{
382 EXDLL_INIT();
383
384 TCHAR szFile[MAX_PATH + 1];
385 HRESULT hr = vboxPopString(szFile, sizeof(szFile) / sizeof(TCHAR));
386 if (SUCCEEDED(hr))
387 {
388 DWORD dwInfoSize = GetFileVersionInfoSize(szFile, NULL /* lpdwHandle */);
389 if (dwInfoSize)
390 {
391 void *pFileInfo = GlobalAlloc(GMEM_FIXED, dwInfoSize);
392 if (pFileInfo)
393 {
394 if (GetFileVersionInfo(szFile, 0, dwInfoSize, pFileInfo))
395 {
396 LPVOID pvInfo;
397 UINT puInfoLen;
398 if (VerQueryValue(pFileInfo, _T("\\VarFileInfo\\Translation"),
399 &pvInfo, &puInfoLen))
400 {
401 WORD wCodePage = LOWORD(*(DWORD*)pvInfo);
402 WORD wLanguageID = HIWORD(*(DWORD*)pvInfo);
403
404 TCHAR szQuery[MAX_PATH];
405 _sntprintf(szQuery, sizeof(szQuery), _T("StringFileInfo\\%04X%04X\\CompanyName"),
406 wCodePage,wLanguageID);
407
408 LPCTSTR pcData;
409 if (VerQueryValue(pFileInfo, szQuery,(void**)&pcData, &puInfoLen))
410 {
411 pushstring(pcData);
412 }
413 else
414 hr = __HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
415 }
416 else
417 hr = __HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
418 }
419 GlobalFree(pFileInfo);
420 }
421 else
422 hr = __HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
423 }
424 else
425 hr = __HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
426 }
427
428 if (FAILED(hr))
429 vboxPushResultAsString(hr);
430}
431
432/**
433 * Shows a balloon message using VBoxTray's notification area in the
434 * Windows task bar.
435 *
436 * @param hwndParent Window handle of parent.
437 * @param string_size Size of variable string.
438 * @param variables The actual variable string.
439 * @param stacktop Pointer to a pointer to the current stack.
440 */
441VBOXINSTALLHELPER_EXPORT VBoxTrayShowBallonMsg(HWND hwndParent, int string_size,
442 TCHAR *variables, stack_t **stacktop)
443{
444 EXDLL_INIT();
445
446 char szMsg[256];
447 char szTitle[128];
448 HRESULT hr = vboxPopString(szMsg, sizeof(szMsg) / sizeof(char));
449 if (SUCCEEDED(hr))
450 hr = vboxPopString(szTitle, sizeof(szTitle) / sizeof(char));
451
452 /** @todo Do we need to restore the stack on failure? */
453
454 if (SUCCEEDED(hr))
455 {
456 RTR3InitDll(0);
457
458 uint32_t cbMsg = sizeof(VBOXTRAYIPCMSG_SHOWBALLOONMSG)
459 + strlen(szMsg) + 1 /* Include terminating zero */
460 + strlen(szTitle) + 1; /* Dito. */
461 Assert(cbMsg);
462 PVBOXTRAYIPCMSG_SHOWBALLOONMSG pIpcMsg =
463 (PVBOXTRAYIPCMSG_SHOWBALLOONMSG)RTMemAlloc(cbMsg);
464 if (pIpcMsg)
465 {
466 /* Stuff in the strings. */
467 memcpy(pIpcMsg->szMsgContent, szMsg, strlen(szMsg) + 1);
468 memcpy(pIpcMsg->szMsgTitle, szTitle, strlen(szTitle) + 1);
469
470 /* Pop off the values in reverse order from the stack. */
471 if (SUCCEEDED(hr))
472 hr = vboxPopULong((ULONG*)&pIpcMsg->uType);
473 if (SUCCEEDED(hr))
474 hr = vboxPopULong((ULONG*)&pIpcMsg->uShowMS);
475
476 if (SUCCEEDED(hr))
477 {
478 RTLOCALIPCSESSION hSession = 0;
479 int rc = vboxConnectToVBoxTray(&hSession);
480 if (RT_SUCCESS(rc))
481 {
482 VBOXTRAYIPCHEADER ipcHdr = { VBOXTRAY_IPC_HDR_MAGIC, 0 /* Header version */,
483 VBOXTRAYIPCMSGTYPE_SHOWBALLOONMSG, cbMsg };
484
485 rc = RTLocalIpcSessionWrite(hSession, &ipcHdr, sizeof(ipcHdr));
486 if (RT_SUCCESS(rc))
487 rc = RTLocalIpcSessionWrite(hSession, pIpcMsg, cbMsg);
488
489 int rc2 = RTLocalIpcSessionClose(hSession);
490 if (RT_SUCCESS(rc))
491 rc = rc2;
492 }
493
494 if (RT_FAILURE(rc))
495 hr = __HRESULT_FROM_WIN32(ERROR_BROKEN_PIPE);
496 }
497
498 RTMemFree(pIpcMsg);
499 }
500 else
501 hr = __HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
502 }
503
504 /* Push simple return value on stack. */
505 SUCCEEDED(hr) ? pushstring("0") : pushstring("1");
506}
507
508BOOL WINAPI DllMain(HANDLE hInst, ULONG uReason, LPVOID lpReserved)
509{
510 g_hInstance = (HINSTANCE)hInst;
511 return TRUE;
512}
513
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