VirtualBox

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

Last change on this file since 41541 was 39548, checked in by vboxsync, 13 years ago

VBoxGuestInstallHelper: Added routines for looking up a file's vendor and target architecture (PE/COFF).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.7 KB
Line 
1/* $Id: VBoxGuestInstallHelper.cpp 39548 2011-12-07 15:34:34Z vboxsync $ */
2/** @file
3 * VBoxGuestInstallHelper - Various helper routines for Windows guest installer.
4 */
5
6/*
7 * Copyright (C) 2011 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 <Strsafe.h>
25#include <tchar.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 * Disables the Windows File Protection for a specified file
200 * using an undocumented SFC API call. Don't try this at home!
201 *
202 * @param hwndParent Window handle of parent.
203 * @param string_size Size of variable string.
204 * @param variables The actual variable string.
205 * @param stacktop Pointer to a pointer to the current stack.
206 */
207VBOXINSTALLHELPER_EXPORT DisableWFP(HWND hwndParent, int string_size,
208 TCHAR *variables, stack_t **stacktop)
209{
210 EXDLL_INIT();
211
212 TCHAR szFile[MAX_PATH + 1];
213 HRESULT hr = vboxPopString(szFile, sizeof(szFile) / sizeof(TCHAR));
214 if (SUCCEEDED(hr))
215 {
216 HMODULE hSFC = LoadLibrary("sfc_os.dll");
217 if (NULL != hSFC)
218 {
219 g_pfnSfcFileException = (PFNSFCFILEEXCEPTION)GetProcAddress(hSFC, "SfcFileException");
220 if (g_pfnSfcFileException == NULL)
221 {
222 /* If we didn't get the proc address with the call above, try it harder with
223 * the (zero based) index of the function list. */
224 g_pfnSfcFileException = (PFNSFCFILEEXCEPTION)GetProcAddress(hSFC, (LPCSTR)5);
225 if (g_pfnSfcFileException == NULL)
226 hr = HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND);
227 }
228 }
229 else
230 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
231
232 if (SUCCEEDED(hr))
233 {
234 WCHAR *pwszFile;
235 hr = vboxChar2WCharAlloc(szFile, &pwszFile);
236 if (SUCCEEDED(hr))
237 {
238 if (g_pfnSfcFileException(0, pwszFile, -1) != 0)
239 hr = HRESULT_FROM_WIN32(GetLastError());
240 vboxChar2WCharFree(pwszFile);
241 }
242 }
243
244 if (hSFC)
245 FreeLibrary(hSFC);
246 }
247
248 vboxPushResultAsString(hr);
249}
250
251/**
252 * Retrieves a file's architecture (x86 or amd64).
253 * Outputs "x86", "amd64" or an error message (if not found/invalid) on stack.
254 *
255 * @param hwndParent Window handle of parent.
256 * @param string_size Size of variable string.
257 * @param variables The actual variable string.
258 * @param stacktop Pointer to a pointer to the current stack.
259 */
260VBOXINSTALLHELPER_EXPORT FileGetArchitecture(HWND hwndParent, int string_size,
261 TCHAR *variables, stack_t **stacktop)
262{
263 EXDLL_INIT();
264
265 TCHAR szFile[MAX_PATH + 1];
266 HRESULT hr = vboxPopString(szFile, sizeof(szFile) / sizeof(TCHAR));
267 if (SUCCEEDED(hr))
268 {
269 /* See: http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx */
270 FILE *pFh = fopen(szFile, "rb");
271 if (pFh)
272 {
273 /* Assume the file is invalid. */
274 hr = __HRESULT_FROM_WIN32(ERROR_FILE_INVALID);
275
276 BYTE byOffsetPE; /* Absolute offset of PE signature. */
277
278 /* Do some basic validation. */
279 /* Check for "MZ" header (DOS stub). */
280 BYTE byBuf[255];
281 if ( fread(&byBuf, sizeof(BYTE), 2, pFh) == 2
282 && !memcmp(&byBuf, "MZ", 2))
283 {
284 /* Seek to 0x3C to get the PE offset. */
285 if (!fseek(pFh, 60L /*0x3C*/, SEEK_SET))
286 {
287 /* Read actual offset of PE signature. */
288 if (fread(&byOffsetPE, sizeof(BYTE), 1, pFh) == 1)
289 {
290 /* ... and seek to it. */
291 if (!fseek(pFh, byOffsetPE, SEEK_SET))
292 {
293 /* Validate PE signature. */
294 if (fread(byBuf, sizeof(BYTE), 4, pFh) == 4)
295 {
296 if (!memcmp(byBuf, "PE\0\0", 4))
297 hr = S_OK;
298 }
299 }
300 }
301 }
302 }
303
304 /* Validation successful? */
305 if (SUCCEEDED(hr))
306 {
307 BYTE byOffsetCOFF = byOffsetPE + 0x4; /* Skip PE signature. */
308
309 /** @todo When we need to do more stuff here, we probably should
310 * mmap the file w/ a struct so that we easily could access
311 * all the fixed size stuff. Later. */
312
313 /* Jump to machine type (first entry, 2 bytes):
314 * Use absolute PE offset retrieved above. */
315 if (!fseek(pFh, byOffsetCOFF, SEEK_SET))
316 {
317 WORD wMachineType;
318 if (fread(&wMachineType, 1,
319 sizeof(wMachineType), pFh) == 2)
320 {
321 switch (wMachineType)
322 {
323 case 0x14C: /* Intel 86 */
324 pushstring("x86");
325 break;
326
327 case 0x8664: /* AMD64 / x64 */
328 pushstring("amd64");
329 break;
330
331 default:
332 hr = __HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
333 break;
334 }
335 }
336 else
337 hr = __HRESULT_FROM_WIN32(ERROR_FILE_INVALID);
338 }
339 else
340 hr = __HRESULT_FROM_WIN32(ERROR_FILE_INVALID);
341 }
342
343 fclose(pFh);
344 }
345 else
346 hr = __HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
347 }
348
349 if (FAILED(hr))
350 vboxPushResultAsString(hr);
351}
352
353/**
354 * Retrieves a file's vendor.
355 * Outputs the vendor's name or an error message (if not found/invalid) on stack.
356 *
357 * @param hwndParent Window handle of parent.
358 * @param string_size Size of variable string.
359 * @param variables The actual variable string.
360 * @param stacktop Pointer to a pointer to the current stack.
361 */
362VBOXINSTALLHELPER_EXPORT FileGetVendor(HWND hwndParent, int string_size,
363 TCHAR *variables, stack_t **stacktop)
364{
365 EXDLL_INIT();
366
367 TCHAR szFile[MAX_PATH + 1];
368 HRESULT hr = vboxPopString(szFile, sizeof(szFile) / sizeof(TCHAR));
369 if (SUCCEEDED(hr))
370 {
371 DWORD dwInfoSize = GetFileVersionInfoSize(szFile, NULL /* lpdwHandle */);
372 if (dwInfoSize)
373 {
374 void *pFileInfo = GlobalAlloc(GMEM_FIXED, dwInfoSize);
375 if (pFileInfo)
376 {
377 if (GetFileVersionInfo(szFile, 0, dwInfoSize, pFileInfo))
378 {
379 LPVOID pvInfo;
380 UINT puInfoLen;
381 if (VerQueryValue(pFileInfo, _T("\\VarFileInfo\\Translation"),
382 &pvInfo, &puInfoLen))
383 {
384 WORD wCodePage = LOWORD(*(DWORD*)pvInfo);
385 WORD wLanguageID = HIWORD(*(DWORD*)pvInfo);
386
387 TCHAR szQuery[MAX_PATH];
388 _sntprintf(szQuery, sizeof(szQuery), _T("StringFileInfo\\%04X%04X\\CompanyName"),
389 wCodePage,wLanguageID);
390
391 LPCTSTR pcData;
392 if (VerQueryValue(pFileInfo, szQuery,(void**)&pcData, &puInfoLen))
393 {
394 pushstring(pcData);
395 }
396 else
397 hr = __HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
398 }
399 else
400 hr = __HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
401 }
402 GlobalFree(pFileInfo);
403 }
404 else
405 hr = __HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
406 }
407 else
408 hr = __HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
409 }
410
411 if (FAILED(hr))
412 vboxPushResultAsString(hr);
413}
414
415/**
416 * Shows a balloon message using VBoxTray's notification area in the
417 * Windows task bar.
418 *
419 * @param hwndParent Window handle of parent.
420 * @param string_size Size of variable string.
421 * @param variables The actual variable string.
422 * @param stacktop Pointer to a pointer to the current stack.
423 */
424VBOXINSTALLHELPER_EXPORT VBoxTrayShowBallonMsg(HWND hwndParent, int string_size,
425 TCHAR *variables, stack_t **stacktop)
426{
427 EXDLL_INIT();
428
429 VBOXTRAYIPCHEADER hdr;
430 hdr.ulMsg = VBOXTRAYIPCMSGTYPE_SHOWBALLOONMSG;
431 hdr.cbBody = sizeof(VBOXTRAYIPCMSG_SHOWBALLOONMSG);
432
433 VBOXTRAYIPCMSG_SHOWBALLOONMSG msg;
434 HRESULT hr = vboxPopString(msg.szContent, sizeof(msg.szContent) / sizeof(TCHAR));
435 if (SUCCEEDED(hr))
436 hr = vboxPopString(msg.szTitle, sizeof(msg.szTitle) / sizeof(TCHAR));
437 if (SUCCEEDED(hr))
438 hr = vboxPopULong(&msg.ulType);
439 if (SUCCEEDED(hr))
440 hr = vboxPopULong(&msg.ulShowMS);
441
442 if (SUCCEEDED(hr))
443 {
444 msg.ulFlags = 0;
445
446 HANDLE hPipe = vboxIPCConnect();
447 if (hPipe)
448 {
449 hr = vboxIPCWriteMessage(hPipe, (BYTE*)&hdr, sizeof(VBOXTRAYIPCHEADER));
450 if (SUCCEEDED(hr))
451 hr = vboxIPCWriteMessage(hPipe, (BYTE*)&msg, sizeof(VBOXTRAYIPCMSG_SHOWBALLOONMSG));
452 vboxIPCDisconnect(hPipe);
453 }
454 }
455
456 /* Push simple return value on stack. */
457 SUCCEEDED(hr) ? pushstring("0") : pushstring("1");
458}
459
460BOOL WINAPI DllMain(HANDLE hInst, ULONG uReason, LPVOID lpReserved)
461{
462 g_hInstance = (HINSTANCE)hInst;
463 return TRUE;
464}
465
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