VirtualBox

source: vbox/trunk/src/VBox/Installer/win/StubBld/VBoxStubBld.cpp@ 106212

Last change on this file since 106212 was 106061, checked in by vboxsync, 4 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.0 KB
Line 
1/* $Id: VBoxStubBld.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * VBoxStubBld - VirtualBox's Windows installer stub builder.
4 */
5
6/*
7 * Copyright (C) 2009-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#include <iprt/win/windows.h>
33#include <shellapi.h>
34#include <strsafe.h>
35
36#include <VBox/version.h>
37#include <iprt/types.h>
38
39#include "VBoxStubBld.h"
40
41
42static HRESULT GetFile(const char *pszFilePath, HANDLE *phFile, DWORD *pcbFile)
43{
44 HANDLE hFile = CreateFileA(pszFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
45 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
46 if (hFile != INVALID_HANDLE_VALUE)
47 {
48 SetLastError(NO_ERROR);
49 LARGE_INTEGER cbFile;
50 if (GetFileSizeEx(hFile, &cbFile))
51 {
52 if (cbFile.HighPart == 0)
53 {
54 *pcbFile = cbFile.LowPart;
55 *phFile = hFile;
56 return S_OK;
57 }
58 fprintf(stderr, "error: File '%s' is too large: %llu bytes\n", pszFilePath, cbFile.QuadPart);
59 }
60 else
61 fprintf(stderr, "error: GetFileSizeEx failed on '%s': %lu\n", pszFilePath, GetLastError());
62 CloseHandle(hFile);
63 }
64 else
65 fprintf(stderr, "error: CreateFileA failed on '%s': %lu\n", pszFilePath, GetLastError());
66 *phFile = INVALID_HANDLE_VALUE;
67 return E_FAIL;
68}
69
70static HRESULT MyUpdateResource(HANDLE hFile, DWORD cbFile, HANDLE hResourceUpdate,
71 const char *pszResourceType, const char *pszResourceId)
72{
73 HRESULT hr = E_FAIL;
74 HANDLE hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
75 if (hMap != NULL)
76 {
77 PVOID pvFile = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, cbFile);
78 if (pvFile)
79 {
80 if (UpdateResourceA(hResourceUpdate, pszResourceType, pszResourceId,
81 MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), pvFile, cbFile))
82 hr = S_OK;
83 else
84 fprintf(stderr, "error: UpdateResourceA failed: %lu\n", GetLastError());
85
86 UnmapViewOfFile(pvFile);
87 }
88 else
89 fprintf(stderr, "error: MapViewOfFile failed: %lu\n", GetLastError());
90 CloseHandle(hMap);
91 }
92 else
93 fprintf(stderr, "error: CreateFileMappingW failed: %lu\n", GetLastError());
94 return hr;
95}
96
97static HRESULT IntegrateFile(HANDLE hResourceUpdate, const char *pszResourceType,
98 const char *pszResourceId, const char *pszFilePath)
99{
100 HANDLE hFile = INVALID_HANDLE_VALUE;
101 DWORD cbFile = 0;
102 HRESULT hr = GetFile(pszFilePath, &hFile, &cbFile);
103 if (SUCCEEDED(hr))
104 {
105 hr = MyUpdateResource(hFile, cbFile, hResourceUpdate, pszResourceType, pszResourceId);
106 if (FAILED(hr))
107 printf("ERROR: Error updating resource for file %s!", pszFilePath);
108 CloseHandle(hFile);
109 }
110 else
111 hr = HRESULT_FROM_WIN32(GetLastError());
112 return hr;
113}
114
115static char *MyPathFilename(const char *pszPath)
116{
117 const char *pszName = pszPath;
118 for (const char *psz = pszPath;; psz++)
119 {
120 switch (*psz)
121 {
122 /* handle separators. */
123 case ':':
124 pszName = psz + 1;
125 break;
126
127 case '\\':
128 case '/':
129 pszName = psz + 1;
130 break;
131
132 /* the end */
133 case '\0':
134 if (*pszName)
135 return (char *)(void *)pszName;
136 return NULL;
137 }
138 }
139
140 /* will never get here */
141}
142
143
144int main(int argc, char* argv[])
145{
146 /*
147 * Parse arguments.
148 */
149 const char *pszSetupStub = "VBoxStub.exe";
150 const char *pszOutput = "VirtualBox-MultiArch.exe";
151
152 printf(VBOX_PRODUCT " Stub Builder v%d.%d.%d.%d\n",
153 VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV);
154
155 struct VBOXSTUBBUILDPKG
156 {
157 const char *pszSrcPath;
158 VBOXSTUBPKGARCH enmArch;
159 } aBuildPkgs[VBOXSTUB_MAX_PACKAGES] = { { NULL } };
160 VBOXSTUBPKGHEADER StubHdr =
161 {
162 /*.szMagic = */ VBOXSTUBPKGHEADER_MAGIC_SZ,
163 /*.cPackages = */ 0
164 };
165
166 for (int i = 1; i < argc; i++)
167 {
168 const char *pszArg = argv[i];
169 if ( strcmp(pszArg, "--help") == 0
170 || strcmp(pszArg, "-help") == 0
171 || strcmp(pszArg, "-h") == 0
172 || strcmp(pszArg, "-?") == 0)
173 {
174 printf("usage: %s -out <installer.exe> -stub <stub.exe> [-target-all <file>] [-target-<arch> <file>]\n", argv[0]);
175 return RTEXITCODE_SUCCESS;
176 }
177
178 /* The remaining options all take a while. */
179 if ( strcmp(pszArg, "-out")
180 && strcmp(pszArg, "-stub")
181 && strcmp(pszArg, "-target-all")
182 && strcmp(pszArg, "-target-x86")
183 && strcmp(pszArg, "-target-amd64"))
184 {
185 fprintf(stderr, "syntax error: Invalid parameter: %s\n", argv[i]);
186 return RTEXITCODE_SYNTAX;
187 }
188
189 i++;
190 if (i >= argc)
191 {
192 fprintf(stderr, "syntax error: Option '%s' takes a value argument!\n", pszArg);
193 return RTEXITCODE_SYNTAX;
194 }
195 const char *pszValue = argv[i];
196
197 /* Process the individual options. */
198 if (strcmp(pszArg, "-out") == 0)
199 pszOutput = pszValue;
200 else if (strcmp(pszArg, "-stub") == 0)
201 pszSetupStub = pszValue;
202 else
203 {
204 if (StubHdr.cPackages >= RT_ELEMENTS(aBuildPkgs))
205 {
206 fprintf(stderr, "error: Too many packages specified!\n");
207 return RTEXITCODE_FAILURE;
208 }
209 aBuildPkgs[StubHdr.cPackages].pszSrcPath = pszValue;
210 if (strcmp(pszArg, "-target-all") == 0)
211 aBuildPkgs[StubHdr.cPackages].enmArch = VBOXSTUBPKGARCH_ALL;
212 else if (strcmp(pszArg, "-target-amd64") == 0)
213 aBuildPkgs[StubHdr.cPackages].enmArch = VBOXSTUBPKGARCH_AMD64;
214 else if (strcmp(pszArg, "-target-x86") == 0)
215 aBuildPkgs[StubHdr.cPackages].enmArch = VBOXSTUBPKGARCH_X86;
216 else
217 {
218 fprintf(stderr, "internal error: %u\n", __LINE__);
219 return RTEXITCODE_FAILURE;
220 }
221 StubHdr.cPackages++;
222 }
223 }
224
225 if (StubHdr.cPackages == 0)
226 {
227 fprintf(stderr, "syntax error: No packages specified! Exiting.\n");
228 return RTEXITCODE_SYNTAX;
229 }
230
231 printf("Stub: %s\n", pszSetupStub);
232 printf("Output: %s\n", pszOutput);
233 printf("# Packages: %u\n", StubHdr.cPackages);
234
235 /*
236 * Copy the stub over the output file.
237 */
238 if (!CopyFile(pszSetupStub, pszOutput, FALSE))
239 {
240 fprintf(stderr, "ERROR: Could not copy the stub loader: %lu\n", GetLastError());
241 return RTEXITCODE_SYNTAX;
242 }
243
244 /*
245 * Start updating the resources of the output file.
246 */
247 HANDLE hUpdate = BeginUpdateResourceA(pszOutput, FALSE);
248 if (hUpdate)
249 {
250 /*
251 * Add the file one by one to the output file.
252 */
253 HRESULT hrc = S_OK;
254 for (BYTE i = 0; i < StubHdr.cPackages; i++)
255 {
256 printf("Integrating (Platform %d): %s\n", aBuildPkgs[i].enmArch, aBuildPkgs[i].pszSrcPath);
257
258 /*
259 * Create the package header.
260 */
261 VBOXSTUBPKG Package = {0};
262 Package.enmArch = aBuildPkgs[i].enmArch;
263
264 /* The resource name */
265 hrc = StringCchPrintf(Package.szResourceName, sizeof(Package.szResourceName), "BIN_%02d", i);
266 if (FAILED(hrc))
267 {
268 fprintf(stderr, "Internal error: %u\n", __LINE__);
269 break;
270 }
271
272 /* Construct final name used when extracting. */
273 hrc = StringCchCopy(Package.szFilename, sizeof(Package.szFilename), MyPathFilename(aBuildPkgs[i].pszSrcPath));
274 if (FAILED(hrc))
275 {
276 fprintf(stderr, "ERROR: Filename is too long: %s\n", aBuildPkgs[i].pszSrcPath);
277 break;
278 }
279
280 /*
281 * Add the package header to the binary.
282 */
283 char szHeaderName[32];
284 hrc = StringCchPrintf(szHeaderName, sizeof(szHeaderName), "HDR_%02d", i);
285 if (FAILED(hrc))
286 {
287 fprintf(stderr, "Internal error: %u\n", __LINE__);
288 break;
289 }
290
291 if (!UpdateResourceA(hUpdate, RT_RCDATA, szHeaderName, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
292 &Package, sizeof(Package)))
293 {
294 fprintf(stderr, "ERROR: UpdateResourceA failed for the package header: %lu\n", GetLastError());
295 hrc = E_FAIL;
296 break;
297 }
298
299 /*
300 * Add the file content under the BIN_xx resource name.
301 */
302 hrc = IntegrateFile(hUpdate, RT_RCDATA, Package.szResourceName, aBuildPkgs[i].pszSrcPath);
303 if (FAILED(hrc))
304 break;
305 }
306 if (SUCCEEDED(hrc))
307 {
308 /*
309 * Now add the header/manifest and complete the operation.
310 */
311 if (UpdateResourceA(hUpdate, RT_RCDATA, "MANIFEST", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
312 &StubHdr, sizeof(StubHdr)))
313 {
314 if (EndUpdateResourceA(hUpdate, FALSE /*fDiscard*/))
315 {
316 printf("Successfully created the installer\n");
317 return RTEXITCODE_SUCCESS;
318 }
319 fprintf(stderr, "ERROR: EndUpdateResourceA failed: %lu\n", GetLastError());
320 }
321 else
322 fprintf(stderr, "ERROR: UpdateResourceA failed for the installer header/manifest: %lu\n", GetLastError());
323 }
324
325 EndUpdateResourceA(hUpdate, TRUE /*fDiscard*/);
326 hUpdate = NULL;
327 }
328 else
329 fprintf(stderr, "error: BeginUpdateResource failed: %lu\n", GetLastError());
330 return RTEXITCODE_FAILURE;
331}
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