VirtualBox

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

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

Windows Guest Additions: Support for querying user idle times.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.9 KB
Line 
1/* $Id: VBoxGuestInstallHelper.cpp 47232 2013-07-18 12:00:49Z 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
128/**
129 * Connects to VBoxTray IPC under the behalf of the user running
130 * in the current thread context.
131 *
132 * @return IPRT status code.
133 * @param phSession Where to store the IPC session.
134 */
135static int vboxConnectToVBoxTray(RTLOCALIPCSESSION hSession)
136{
137 int rc = VINF_SUCCESS;
138
139 RTUTF16 wszUserName[255];
140 DWORD cchUserName = sizeof(wszUserName) / sizeof(RTUTF16);
141 BOOL fRc = GetUserNameW(wszUserName, &cchUserName);
142 if (!fRc)
143 rc = RTErrConvertFromWin32(GetLastError());
144
145 if (RT_SUCCESS(rc))
146 {
147 char *pszUserName;
148 rc = RTUtf16ToUtf8(wszUserName, &pszUserName);
149 if (RT_SUCCESS(rc))
150 {
151 char szPipeName[255];
152 if (RTStrPrintf(szPipeName, sizeof(szPipeName), "%s%s",
153 VBOXTRAY_IPC_PIPE_PREFIX, pszUserName))
154 {
155 rc = RTLocalIpcSessionConnect(&hSession, szPipeName, 0 /* Flags */);
156 }
157 else
158 rc = VERR_NO_MEMORY;
159
160 RTStrFree(pszUserName);
161 }
162 }
163
164 return rc;
165}
166
167static void vboxChar2WCharFree(PWCHAR pwString)
168{
169 if (pwString)
170 HeapFree(GetProcessHeap(), 0, pwString);
171}
172
173static HRESULT vboxChar2WCharAlloc(const char *pszString, PWCHAR *ppwString)
174{
175 HRESULT hr;
176 int iLen = strlen(pszString) + 2;
177 WCHAR *pwString = (WCHAR*)HeapAlloc(GetProcessHeap(), 0, iLen * sizeof(WCHAR));
178 if (!pwString)
179 hr = __HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
180 else
181 {
182 if (MultiByteToWideChar(CP_ACP, 0, pszString, -1, pwString, iLen) == 0)
183 {
184 hr = HRESULT_FROM_WIN32(GetLastError());
185 HeapFree(GetProcessHeap(), 0, pwString);
186 }
187 else
188 {
189 hr = S_OK;
190 *ppwString = pwString;
191 }
192 }
193 return hr;
194}
195
196/**
197 * Loads a system DLL.
198 *
199 * @returns Module handle or NULL
200 * @param pszName The DLL name.
201 */
202static HMODULE loadSystemDll(const char *pszName)
203{
204 char szPath[MAX_PATH];
205 UINT cchPath = GetSystemDirectoryA(szPath, sizeof(szPath));
206 size_t cbName = strlen(pszName) + 1;
207 if (cchPath + 1 + cbName > sizeof(szPath))
208 return NULL;
209 szPath[cchPath] = '\\';
210 memcpy(&szPath[cchPath + 1], pszName, cbName);
211 return LoadLibraryA(szPath);
212}
213
214/**
215 * Disables the Windows File Protection for a specified file
216 * using an undocumented SFC API call. Don't try this at home!
217 *
218 * @param hwndParent Window handle of parent.
219 * @param string_size Size of variable string.
220 * @param variables The actual variable string.
221 * @param stacktop Pointer to a pointer to the current stack.
222 */
223VBOXINSTALLHELPER_EXPORT DisableWFP(HWND hwndParent, int string_size,
224 TCHAR *variables, stack_t **stacktop)
225{
226 EXDLL_INIT();
227
228 TCHAR szFile[MAX_PATH + 1];
229 HRESULT hr = vboxPopString(szFile, sizeof(szFile) / sizeof(TCHAR));
230 if (SUCCEEDED(hr))
231 {
232 HMODULE hSFC = loadSystemDll("sfc_os.dll"); /** @todo Replace this by RTLdr APIs. */
233 if (NULL != hSFC)
234 {
235 g_pfnSfcFileException = (PFNSFCFILEEXCEPTION)GetProcAddress(hSFC, "SfcFileException");
236 if (g_pfnSfcFileException == NULL)
237 {
238 /* If we didn't get the proc address with the call above, try it harder with
239 * the (zero based) index of the function list. */
240 g_pfnSfcFileException = (PFNSFCFILEEXCEPTION)GetProcAddress(hSFC, (LPCSTR)5);
241 if (g_pfnSfcFileException == NULL)
242 hr = HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND);
243 }
244 }
245 else
246 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
247
248 if (SUCCEEDED(hr))
249 {
250 WCHAR *pwszFile;
251 hr = vboxChar2WCharAlloc(szFile, &pwszFile);
252 if (SUCCEEDED(hr))
253 {
254 if (g_pfnSfcFileException(0, pwszFile, -1) != 0)
255 hr = HRESULT_FROM_WIN32(GetLastError());
256 vboxChar2WCharFree(pwszFile);
257 }
258 }
259
260 if (hSFC)
261 FreeLibrary(hSFC);
262 }
263
264 vboxPushResultAsString(hr);
265}
266
267/**
268 * Retrieves a file's architecture (x86 or amd64).
269 * Outputs "x86", "amd64" or an error message (if not found/invalid) on stack.
270 *
271 * @param hwndParent Window handle of parent.
272 * @param string_size Size of variable string.
273 * @param variables The actual variable string.
274 * @param stacktop Pointer to a pointer to the current stack.
275 */
276VBOXINSTALLHELPER_EXPORT FileGetArchitecture(HWND hwndParent, int string_size,
277 TCHAR *variables, stack_t **stacktop)
278{
279 EXDLL_INIT();
280
281 TCHAR szFile[MAX_PATH + 1];
282 HRESULT hr = vboxPopString(szFile, sizeof(szFile) / sizeof(TCHAR));
283 if (SUCCEEDED(hr))
284 {
285 /* See: http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx */
286 FILE *pFh = fopen(szFile, "rb");
287 if (pFh)
288 {
289 /* Assume the file is invalid. */
290 hr = __HRESULT_FROM_WIN32(ERROR_FILE_INVALID);
291
292 BYTE byOffsetPE; /* Absolute offset of PE signature. */
293
294 /* Do some basic validation. */
295 /* Check for "MZ" header (DOS stub). */
296 BYTE byBuf[255];
297 if ( fread(&byBuf, sizeof(BYTE), 2, pFh) == 2
298 && !memcmp(&byBuf, "MZ", 2))
299 {
300 /* Seek to 0x3C to get the PE offset. */
301 if (!fseek(pFh, 60L /*0x3C*/, SEEK_SET))
302 {
303 /* Read actual offset of PE signature. */
304 if (fread(&byOffsetPE, sizeof(BYTE), 1, pFh) == 1)
305 {
306 /* ... and seek to it. */
307 if (!fseek(pFh, byOffsetPE, SEEK_SET))
308 {
309 /* Validate PE signature. */
310 if (fread(byBuf, sizeof(BYTE), 4, pFh) == 4)
311 {
312 if (!memcmp(byBuf, "PE\0\0", 4))
313 hr = S_OK;
314 }
315 }
316 }
317 }
318 }
319
320 /* Validation successful? */
321 if (SUCCEEDED(hr))
322 {
323 BYTE byOffsetCOFF = byOffsetPE + 0x4; /* Skip PE signature. */
324
325 /** @todo When we need to do more stuff here, we probably should
326 * mmap the file w/ a struct so that we easily could access
327 * all the fixed size stuff. Later. */
328
329 /* Jump to machine type (first entry, 2 bytes):
330 * Use absolute PE offset retrieved above. */
331 if (!fseek(pFh, byOffsetCOFF, SEEK_SET))
332 {
333 WORD wMachineType;
334 if (fread(&wMachineType, 1,
335 sizeof(wMachineType), pFh) == 2)
336 {
337 switch (wMachineType)
338 {
339 case 0x14C: /* Intel 86 */
340 pushstring("x86");
341 break;
342
343 case 0x8664: /* AMD64 / x64 */
344 pushstring("amd64");
345 break;
346
347 default:
348 hr = __HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
349 break;
350 }
351 }
352 else
353 hr = __HRESULT_FROM_WIN32(ERROR_FILE_INVALID);
354 }
355 else
356 hr = __HRESULT_FROM_WIN32(ERROR_FILE_INVALID);
357 }
358
359 fclose(pFh);
360 }
361 else
362 hr = __HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
363 }
364
365 if (FAILED(hr))
366 vboxPushResultAsString(hr);
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 */
378VBOXINSTALLHELPER_EXPORT FileGetVendor(HWND hwndParent, int string_size,
379 TCHAR *variables, stack_t **stacktop)
380{
381 EXDLL_INIT();
382
383 TCHAR szFile[MAX_PATH + 1];
384 HRESULT hr = vboxPopString(szFile, sizeof(szFile) / sizeof(TCHAR));
385 if (SUCCEEDED(hr))
386 {
387 DWORD dwInfoSize = GetFileVersionInfoSize(szFile, NULL /* lpdwHandle */);
388 if (dwInfoSize)
389 {
390 void *pFileInfo = GlobalAlloc(GMEM_FIXED, dwInfoSize);
391 if (pFileInfo)
392 {
393 if (GetFileVersionInfo(szFile, 0, dwInfoSize, pFileInfo))
394 {
395 LPVOID pvInfo;
396 UINT puInfoLen;
397 if (VerQueryValue(pFileInfo, _T("\\VarFileInfo\\Translation"),
398 &pvInfo, &puInfoLen))
399 {
400 WORD wCodePage = LOWORD(*(DWORD*)pvInfo);
401 WORD wLanguageID = HIWORD(*(DWORD*)pvInfo);
402
403 TCHAR szQuery[MAX_PATH];
404 _sntprintf(szQuery, sizeof(szQuery), _T("StringFileInfo\\%04X%04X\\CompanyName"),
405 wCodePage,wLanguageID);
406
407 LPCTSTR pcData;
408 if (VerQueryValue(pFileInfo, szQuery,(void**)&pcData, &puInfoLen))
409 {
410 pushstring(pcData);
411 }
412 else
413 hr = __HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
414 }
415 else
416 hr = __HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
417 }
418 GlobalFree(pFileInfo);
419 }
420 else
421 hr = __HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
422 }
423 else
424 hr = __HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
425 }
426
427 if (FAILED(hr))
428 vboxPushResultAsString(hr);
429}
430
431/**
432 * Shows a balloon message using VBoxTray's notification area in the
433 * Windows task bar.
434 *
435 * @param hwndParent Window handle of parent.
436 * @param string_size Size of variable string.
437 * @param variables The actual variable string.
438 * @param stacktop Pointer to a pointer to the current stack.
439 */
440VBOXINSTALLHELPER_EXPORT VBoxTrayShowBallonMsg(HWND hwndParent, int string_size,
441 TCHAR *variables, stack_t **stacktop)
442{
443 EXDLL_INIT();
444
445 char szMsg[256];
446 char szTitle[128];
447 HRESULT hr = vboxPopString(szMsg, sizeof(szMsg) / sizeof(char));
448 if (SUCCEEDED(hr))
449 hr = vboxPopString(szTitle, sizeof(szTitle) / sizeof(char));
450
451 /** @todo Do we need to restore the stack on failure? */
452
453 if (SUCCEEDED(hr))
454 {
455 RTR3InitDll(0);
456
457 uint32_t cbMsg = sizeof(VBOXTRAYIPCMSG_SHOWBALLOONMSG)
458 + strlen(szMsg) + 1 /* Include terminating zero */
459 + strlen(szTitle) + 1; /* Dito. */
460 Assert(cbMsg);
461 PVBOXTRAYIPCMSG_SHOWBALLOONMSG pIpcMsg =
462 (PVBOXTRAYIPCMSG_SHOWBALLOONMSG)RTMemAlloc(cbMsg);
463 if (pIpcMsg)
464 {
465 /* Stuff in the strings. */
466 memcpy(pIpcMsg->szMsgContent, szMsg, strlen(szMsg) + 1);
467 memcpy(pIpcMsg->szMsgTitle, szTitle, strlen(szTitle) + 1);
468
469 /* Pop off the values in reverse order from the stack. */
470 if (SUCCEEDED(hr))
471 hr = vboxPopULong((ULONG*)&pIpcMsg->uType);
472 if (SUCCEEDED(hr))
473 hr = vboxPopULong((ULONG*)&pIpcMsg->uShowMS);
474
475 if (SUCCEEDED(hr))
476 {
477 RTLOCALIPCSESSION hSession;
478 int rc = vboxConnectToVBoxTray(hSession);
479 if (RT_SUCCESS(rc))
480 {
481 VBOXTRAYIPCHEADER ipcHdr = { 0 /* Header version */,
482 VBOXTRAYIPCMSGTYPE_SHOWBALLOONMSG, cbMsg };
483
484 rc = RTLocalIpcSessionWrite(hSession, &ipcHdr, sizeof(ipcHdr));
485 if (RT_SUCCESS(rc))
486 rc = RTLocalIpcSessionWrite(hSession, pIpcMsg, cbMsg);
487
488 int rc2 = RTLocalIpcSessionClose(hSession);
489 if (RT_SUCCESS(rc))
490 rc = rc2;
491 }
492
493 if (RT_FAILURE(rc))
494 hr = __HRESULT_FROM_WIN32(ERROR_BROKEN_PIPE);
495 }
496
497 RTMemFree(pIpcMsg);
498 }
499 else
500 hr = __HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
501 }
502
503 /* Push simple return value on stack. */
504 SUCCEEDED(hr) ? pushstring("0") : pushstring("1");
505}
506
507BOOL WINAPI DllMain(HANDLE hInst, ULONG uReason, LPVOID lpReserved)
508{
509 g_hInstance = (HINSTANCE)hInst;
510 return TRUE;
511}
512
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