VirtualBox

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

Last change on this file since 46593 was 46593, checked in by vboxsync, 11 years ago

updates

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