VirtualBox

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

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

VBoxGuestInstallHelper: Added support for RTLocalIpc (untested).

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