VirtualBox

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

Last change on this file since 96686 was 96452, checked in by vboxsync, 3 years ago

Add/NT/Inst,Add/NT/VBoxTray,Add/VBoxService: Cleaned up VBoxGuestInstallHelper.cpp (tested) and the VBoxTray IPC interface (not tested). The motivation for the former was to make it compile in no-CRT mode, the latter was buggy code. The IPC interface is not backwards compatible, this is intentional to avoid buggy code. [scm fix] bugref:10261

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.7 KB
Line 
1/* $Id: VBoxGuestInstallHelper.cpp 96452 2022-08-24 09:57:31Z vboxsync $ */
2/** @file
3 * VBoxGuestInstallHelper - Various helper routines for Windows guest installer.
4 * Works with NSIS 3.x.
5 */
6
7/*
8 * Copyright (C) 2011-2022 Oracle and/or its affiliates.
9 *
10 * This file is part of VirtualBox base platform packages, as
11 * available from https://www.virtualbox.org.
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation, in version 3 of the
16 * License.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, see <https://www.gnu.org/licenses>.
25 *
26 * SPDX-License-Identifier: GPL-3.0-only
27 */
28
29
30/*********************************************************************************************************************************
31* Header Files *
32*********************************************************************************************************************************/
33#ifndef UNICODE
34# define UNICODE
35#endif
36#include <iprt/win/windows.h>
37#include "exdll.h"
38
39#include <iprt/errcore.h>
40#include <iprt/initterm.h>
41#include <iprt/ldr.h>
42#include <iprt/localipc.h>
43#include <iprt/mem.h>
44#include <iprt/process.h>
45#include <iprt/string.h>
46#include <iprt/utf16.h>
47
48/* Required structures/defines of VBoxTray. */
49#include "../../VBoxTray/VBoxTrayMsg.h"
50
51
52/*********************************************************************************************************************************
53* Defined Constants And Macros *
54*********************************************************************************************************************************/
55#define VBOXINSTALLHELPER_EXPORT extern "C" DECLEXPORT(void)
56
57
58/*********************************************************************************************************************************
59* Structures and Typedefs *
60*********************************************************************************************************************************/
61typedef DWORD (WINAPI *PFNSFCFILEEXCEPTION)(DWORD param1, PWCHAR param2, DWORD param3);
62
63
64/*********************************************************************************************************************************
65* Global Variables *
66*********************************************************************************************************************************/
67static HINSTANCE g_hInstance;
68static HWND g_hwndParent;
69
70
71/**
72 * Frees a popped stack entry after use.
73 */
74DECLINLINE(void) vboxFreeStackEntry(stack_t *pEntry)
75{
76 if (pEntry)
77 GlobalFree((HGLOBAL)pEntry);
78}
79
80
81/**
82 * Allocates a new stack entry for containing a string of the given length
83 * (excluding terminator)
84 */
85DECLINLINE(stack_t *) vboxAllocStackEntry(size_t cwcString)
86{
87 return (stack_t *)GlobalAlloc(GPTR, RT_UOFFSETOF_DYN(stack_t, text[cwcString + 1]));
88}
89
90
91/**
92 * Pops an entry off the stack, return NULL if empty.
93 *
94 * Call vboxFreeStackEntry when done.
95 *
96 */
97DECLINLINE(stack_t *) vboxPopStack(stack_t **ppTopOfStack)
98{
99 stack_t *pEntry = ppTopOfStack ? *ppTopOfStack : NULL;
100 if (pEntry)
101 *ppTopOfStack = pEntry->next;
102 return pEntry;
103}
104
105
106/**
107 * Pushes an entry onto the stack.
108 */
109DECLINLINE(void) vboxPushStack(stack_t **ppTopOfStack, stack_t *pEntry)
110{
111 pEntry->next = *ppTopOfStack;
112 *ppTopOfStack = pEntry;
113}
114
115
116static void vboxPushUtf16N(stack_t **ppTopOfStack, wchar_t const *pwszString, size_t cwcString)
117{
118 stack_t *pEntry = vboxAllocStackEntry(cwcString);
119
120 memcpy(pEntry->text, pwszString, cwcString * sizeof(pEntry->text[0]));
121 pEntry->text[cwcString] = '\0';
122
123 vboxPushStack(ppTopOfStack, pEntry);
124}
125
126
127static void vboxPushUtf16(stack_t **ppTopOfStack, wchar_t const *pwszString)
128{
129 return vboxPushUtf16N(ppTopOfStack, pwszString, RTUtf16Len(pwszString));
130}
131
132
133#define VBOX_PUSH_STRING_LITERAL(a_ppTopOfStack, a_szLiteral) \
134 vboxPushUtf16N(a_ppTopOfStack, RT_CONCAT(L, a_szLiteral), sizeof(RT_CONCAT(L, a_szLiteral)) / sizeof(wchar_t) - 1)
135
136
137static void vboxPushUtf8(stack_t **ppTopOfStack, char const *pszString)
138{
139 size_t cwcUtf16 = RTStrCalcUtf16Len(pszString);
140 stack_t *pEntry = vboxAllocStackEntry(cwcUtf16);
141
142 PRTUTF16 pwszUtf16 = pEntry->text;
143 int rc = RTStrToUtf16Ex(pszString, RTSTR_MAX, &pwszUtf16, cwcUtf16 + 1, NULL);
144 AssertRC(rc);
145
146 vboxPushStack(ppTopOfStack, pEntry);
147}
148
149/**
150 * Pushes a string containing an error message and a VBox status code.
151 */
152static void vboxPushVBoxError(stack_t **ppTopOfStack, char const *pszString, int vrc)
153{
154 RTUTF16 wszTmp[128];
155 RTUtf16Printf(wszTmp, RT_ELEMENTS(wszTmp), "Error: %s! %Rrc", pszString, vrc);
156 vboxPushUtf16(ppTopOfStack, wszTmp);
157}
158
159
160static void vboxPushLastError(stack_t **ppTopOfStack, char const *pszString)
161{
162 DWORD const dwErr = GetLastError();
163 RTUTF16 wszTmp[128];
164 RTUtf16Printf(wszTmp, RT_ELEMENTS(wszTmp), "Error: %s! lasterr=%u (%#x)", pszString, dwErr, dwErr);
165 vboxPushUtf16(ppTopOfStack, wszTmp);
166}
167
168
169static void vboxPushLastErrorF(stack_t **ppTopOfStack, const char *pszFormat, ...)
170{
171 DWORD const dwErr = GetLastError();
172 RTUTF16 wszTmp[128];
173 va_list va;
174 va_start(va, pszFormat);
175 RTUtf16Printf(wszTmp, RT_ELEMENTS(wszTmp), "Error: %N! lasterr=%u (%#x)", pszFormat, &va, dwErr, dwErr);
176 va_end(va);
177 vboxPushUtf16(ppTopOfStack, wszTmp);
178}
179
180
181/**
182 * Convers a parameter to uint32_t.
183 *
184 * @returns IPRT status code.
185 * @param pwsz Will be trimmed.
186 * @param puValue Where to return the value.
187 */
188static int vboxUtf16ToUInt32(PRTUTF16 pwsz, uint32_t *puValue)
189{
190 *puValue = 0;
191
192 /* Trim the input: */
193 RTUTF16 wc;
194 while ((wc = *pwsz) == ' ' || wc == '\t')
195 pwsz++;
196 size_t cwc = RTUtf16Len(pwsz);
197 while (cwc > 0 && ((wc = pwsz[cwc - 1]) == ' ' || wc == '\t'))
198 pwsz[--cwc] = '\0';
199
200 /* Convert the remains into an UTF-8 string. */
201 char szValue[128];
202 char *pszValue = &szValue[0];
203 int rc = RTUtf16ToUtf8Ex(pwsz, cwc, &pszValue, sizeof(szValue), NULL);
204 if (RT_SUCCESS(rc))
205 rc = RTStrToUInt32Full(pszValue, 0, puValue);
206 return rc;
207}
208
209
210/**
211 * Connects to VBoxTray IPC under the behalf of the user running in the current
212 * thread context.
213 *
214 * @return IPRT status code.
215 * @param phSession Where to store the IPC session.
216 */
217static int vboxConnectToVBoxTray(RTLOCALIPCSESSION *phSession)
218{
219 char szPipeName[512 + sizeof(VBOXTRAY_IPC_PIPE_PREFIX)];
220 memcpy(szPipeName, VBOXTRAY_IPC_PIPE_PREFIX, sizeof(VBOXTRAY_IPC_PIPE_PREFIX));
221 int rc = RTProcQueryUsername(NIL_RTPROCESS,
222 &szPipeName[sizeof(VBOXTRAY_IPC_PIPE_PREFIX) - 1],
223 sizeof(szPipeName) - sizeof(VBOXTRAY_IPC_PIPE_PREFIX) + 1,
224 NULL /*pcbUser*/);
225 if (RT_SUCCESS(rc))
226 rc = RTLocalIpcSessionConnect(phSession, szPipeName, RTLOCALIPC_FLAGS_NATIVE_NAME);
227 return rc;
228}
229
230
231/**
232 * Retrieves a file's architecture (x86 or amd64).
233 *
234 * Outputs "x86", "amd64" or an error message (if not found/invalid) on stack.
235 *
236 * @param hwndParent Window handle of parent.
237 * @param string_size Size of variable string.
238 * @param variables The actual variable string.
239 * @param stacktop Pointer to a pointer to the current stack.
240 * @param extra Extra parameters.
241 */
242VBOXINSTALLHELPER_EXPORT FileGetArchitecture(HWND hwndParent, int string_size, WCHAR *variables, stack_t **stacktop,
243 extra_parameters *extra)
244{
245 RT_NOREF(hwndParent, string_size, variables, extra);
246
247 stack_t *pEntry = vboxPopStack(stacktop);
248 if (pEntry)
249 {
250 char *pszFileUtf8;
251 int rc = RTUtf16ToUtf8(pEntry->text, &pszFileUtf8);
252 if (RT_SUCCESS(rc))
253 {
254 RTLDRMOD hLdrMod;
255 rc = RTLdrOpen(pszFileUtf8, RTLDR_O_FOR_VALIDATION, RTLDRARCH_WHATEVER, &hLdrMod);
256 if (RT_SUCCESS(rc))
257 {
258 if (RTLdrGetFormat(hLdrMod) == RTLDRFMT_PE)
259 {
260 RTLDRARCH enmLdrArch = RTLdrGetArch(hLdrMod);
261 switch (enmLdrArch)
262 {
263 case RTLDRARCH_X86_32:
264 VBOX_PUSH_STRING_LITERAL(stacktop, "x86");
265 break;
266
267 case RTLDRARCH_AMD64:
268 VBOX_PUSH_STRING_LITERAL(stacktop, "amd64");
269 break;
270
271 default:
272 VBOX_PUSH_STRING_LITERAL(stacktop, "Error: Unknown / invalid architecture");
273 break;
274 }
275 }
276 else
277 VBOX_PUSH_STRING_LITERAL(stacktop, "Error: Unknown / invalid PE signature");
278
279 RTLdrClose(hLdrMod);
280 }
281 else
282 vboxPushVBoxError(stacktop, "RTLdrOpen failed", rc);
283 RTStrFree(pszFileUtf8);
284 }
285 else
286 vboxPushVBoxError(stacktop, "RTUtf16ToUtf8 failed", rc);
287 }
288 else
289 VBOX_PUSH_STRING_LITERAL(stacktop, "Error: Could not retrieve file name");
290 vboxFreeStackEntry(pEntry);
291}
292
293/**
294 * Retrieves a file's vendor.
295 *
296 * Outputs the vendor's name or an error message (if not found/invalid) on stack.
297 *
298 * @param hwndParent Window handle of parent.
299 * @param string_size Size of variable string.
300 * @param variables The actual variable string.
301 * @param stacktop Pointer to a pointer to the current stack.
302 * @param extra Extra parameters.
303 */
304VBOXINSTALLHELPER_EXPORT FileGetVendor(HWND hwndParent, int string_size, WCHAR *variables, stack_t **stacktop,
305 extra_parameters *extra)
306{
307 RT_NOREF(hwndParent, string_size, variables, extra);
308
309 stack_t *pEntry = vboxPopStack(stacktop);
310 if (pEntry)
311 {
312 DWORD dwInfoSize = GetFileVersionInfoSizeW(pEntry->text, NULL /* lpdwHandle */);
313 if (dwInfoSize)
314 {
315 void *pvFileInfo = GlobalAlloc(GMEM_FIXED, dwInfoSize);
316 if (pvFileInfo)
317 {
318 if (GetFileVersionInfoW(pEntry->text, 0, dwInfoSize, pvFileInfo))
319 {
320 LPVOID pvInfo;
321 UINT cbInfo;
322 if (VerQueryValueW(pvFileInfo, L"\\VarFileInfo\\Translation", &pvInfo, &cbInfo))
323 {
324 WORD wCodePage = LOWORD(*(DWORD const *)pvInfo);
325 WORD wLanguageID = HIWORD(*(DWORD const *)pvInfo);
326
327 WCHAR wszQuery[80];
328 RTUtf16Printf(wszQuery, RT_ELEMENTS(wszQuery), "StringFileInfo\\%04X%04X\\CompanyName",
329 wCodePage, wLanguageID);
330
331 LPCWSTR pwszData;
332 if (VerQueryValueW(pvFileInfo, wszQuery, (void **)&pwszData, &cbInfo))
333 vboxPushUtf16(stacktop, pwszData);
334 else
335 vboxPushLastErrorF(stacktop, "VerQueryValueW '%ls' failed", wszQuery);
336 }
337 else
338 vboxPushLastError(stacktop, "VerQueryValueW '\\VarFileInfo\\Translation' failed");
339 }
340 else
341 vboxPushLastError(stacktop, "GetFileVersionInfo failed");
342 GlobalFree(pvFileInfo);
343 }
344 else
345 VBOX_PUSH_STRING_LITERAL(stacktop, "Error: GlobalAlloc failed");
346 }
347 else
348 vboxPushLastError(stacktop, "GetFileVersionInfoSizeW failed");
349 }
350 else
351 VBOX_PUSH_STRING_LITERAL(stacktop, "Error: Could not retrieve file name");
352 vboxFreeStackEntry(pEntry);
353}
354
355/**
356 * Shows a balloon message using VBoxTray's notification area in the
357 * Windows task bar.
358 *
359 * @param hwndParent Window handle of parent.
360 * @param string_size Size of variable string.
361 * @param variables The actual variable string.
362 * @param stacktop Pointer to a pointer to the current stack.
363 * @param extra Extra parameters.
364 */
365VBOXINSTALLHELPER_EXPORT VBoxTrayShowBallonMsg(HWND hwndParent, int string_size, WCHAR *variables, stack_t **stacktop,
366 extra_parameters *extra)
367{
368 RT_NOREF(hwndParent, string_size, variables, extra);
369
370 /*
371 * Get parameters from the stack.
372 */
373 stack_t * const pMsgEntry = vboxPopStack(stacktop);
374 stack_t * const pTitleEntry = vboxPopStack(stacktop);
375 stack_t * const pTypeEntry = vboxPopStack(stacktop);
376 stack_t * const pTimeoutEntry = vboxPopStack(stacktop);
377 if (pTimeoutEntry)
378 {
379 /*
380 * Allocate an IPC message payload structure of the right size.
381 */
382 size_t const cchMsg = RTUtf16CalcUtf8Len(pMsgEntry->text);
383 size_t const cchTitle = RTUtf16CalcUtf8Len(pTitleEntry->text);
384 size_t const cbPayload = RT_UOFFSETOF_DYN(VBOXTRAYIPCMSG_SHOW_BALLOON_MSG_T, szzStrings[cchMsg + 1 + cchTitle + 1]);
385 PVBOXTRAYIPCMSG_SHOW_BALLOON_MSG_T pPayload = (PVBOXTRAYIPCMSG_SHOW_BALLOON_MSG_T)RTMemAllocZVar(cbPayload);
386 if (pPayload)
387 {
388 VBOXTRAYIPCHEADER const MsgHdr =
389 {
390 VBOXTRAY_IPC_HDR_MAGIC,
391 VBOXTRAY_IPC_HDR_VERSION,
392 VBOXTRAYIPCMSGTYPE_SHOW_BALLOON_MSG,
393 cbPayload
394 };
395
396 /*
397 * Convert the parametes and put them into the payload structure.
398 */
399 pPayload->cchMsg = cchMsg;
400 pPayload->cchTitle = cchTitle;
401 char *psz = &pPayload->szzStrings[0];
402 int rc = RTUtf16ToUtf8Ex(pMsgEntry->text, RTSTR_MAX, &psz, cchMsg + 1, NULL);
403 if (RT_SUCCESS(rc))
404 {
405 psz = &pPayload->szzStrings[cchMsg + 1];
406 rc = RTUtf16ToUtf8Ex(pTitleEntry->text, RTSTR_MAX, &psz, cchTitle + 1, NULL);
407 if (RT_SUCCESS(rc))
408 {
409 rc = vboxUtf16ToUInt32(pTypeEntry->text, &pPayload->uType);
410 if (RT_SUCCESS(rc))
411 {
412 rc = vboxUtf16ToUInt32(pTypeEntry->text, &pPayload->cMsTimeout);
413 if (RT_SUCCESS(rc))
414 {
415 /*
416 * Connect to VBoxTray and send the message.
417 */
418 RTLOCALIPCSESSION hSession = 0;
419 rc = vboxConnectToVBoxTray(&hSession);
420 if (RT_SUCCESS(rc))
421 {
422 rc = RTLocalIpcSessionWrite(hSession, &MsgHdr, sizeof(MsgHdr));
423 if (RT_SUCCESS(rc))
424 {
425 rc = RTLocalIpcSessionWrite(hSession, pPayload, cbPayload);
426 if (RT_FAILURE(rc))
427 vboxPushVBoxError(stacktop, "Failed to write message payload", rc);
428 }
429 else
430 vboxPushVBoxError(stacktop, "Failed to write message header", rc);
431
432 int rc2 = RTLocalIpcSessionClose(hSession);
433 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
434 {
435 vboxPushVBoxError(stacktop, "RTLocalIpcSessionClose failed", rc);
436 rc = rc2;
437 }
438 }
439 else
440 vboxPushVBoxError(stacktop, "vboxConnectToVBoxTray failed", rc);
441 }
442 else
443 vboxPushVBoxError(stacktop, "MyUtf16ToUInt32 failed on the timeout value", rc);
444 }
445 else
446 vboxPushVBoxError(stacktop, "MyUtf16ToUInt32 failed on the type value", rc);
447 }
448 else
449 vboxPushVBoxError(stacktop, "RTUtf16ToUtf8Ex failed on the title text", rc);
450 }
451 else
452 vboxPushVBoxError(stacktop, "RTUtf16ToUtf8Ex failed on the message text", rc);
453 }
454 else
455 VBOX_PUSH_STRING_LITERAL(stacktop, "Error: Out of memory!");
456 }
457 else
458 VBOX_PUSH_STRING_LITERAL(stacktop, "Error: Too few parameters on the stack!");
459 vboxFreeStackEntry(pTimeoutEntry);
460 vboxFreeStackEntry(pTypeEntry);
461 vboxFreeStackEntry(pTitleEntry);
462 vboxFreeStackEntry(pMsgEntry);
463}
464
465BOOL WINAPI DllMain(HANDLE hInst, ULONG uReason, LPVOID pReserved)
466{
467 RT_NOREF(pReserved);
468
469 g_hInstance = (HINSTANCE)hInst;
470
471 switch (uReason)
472 {
473 case DLL_PROCESS_ATTACH:
474 RTR3InitDll(RTR3INIT_FLAGS_UNOBTRUSIVE);
475 break;
476
477 case DLL_PROCESS_DETACH:
478 break;
479
480 case DLL_THREAD_ATTACH:
481 break;
482
483 case DLL_THREAD_DETACH:
484 break;
485
486 default:
487 break;
488 }
489
490 return TRUE;
491}
492
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