VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/win/nocrt-startup-exe-win.cpp@ 95830

Last change on this file since 95830 was 95818, checked in by vboxsync, 3 years ago

IPRT: More IPRT_NO_CRT work on windows. bugref:10261

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.7 KB
Line 
1/* $Id: nocrt-startup-exe-win.cpp 95818 2022-07-25 14:48:00Z vboxsync $ */
2/** @file
3 * IPRT - No-CRT - Windows EXE startup code.
4 *
5 * @note Does not run static constructors and destructors!
6 */
7
8/*
9 * Copyright (C) 2006-2022 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 *
19 * The contents of this file may alternatively be used under the terms
20 * of the Common Development and Distribution License Version 1.0
21 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
22 * VirtualBox OSE distribution, in which case the provisions of the
23 * CDDL are applicable instead of those of the GPL.
24 *
25 * You may elect to license modified versions of this file under the
26 * terms and conditions of either the GPL or the CDDL or both.
27 */
28
29
30/*********************************************************************************************************************************
31* Header Files *
32*********************************************************************************************************************************/
33#include "internal/iprt.h"
34#include "internal/process.h"
35
36#include <iprt/nt/nt-and-windows.h>
37#include <iprt/getopt.h>
38#include <iprt/message.h>
39#include <iprt/path.h>
40#include <iprt/string.h>
41#include <iprt/utf16.h>
42
43#ifdef IPRT_NO_CRT
44# include <iprt/asm.h>
45# include <iprt/nocrt/stdlib.h>
46#endif
47
48
49/*********************************************************************************************************************************
50* Structures and Typedefs *
51*********************************************************************************************************************************/
52#ifdef IPRT_NO_CRT
53typedef struct RTNOCRTATEXITCHUNK
54{
55 PFNRTNOCRTATEXITCALLBACK apfnCallbacks[256];
56} RTNOCRTATEXITCHUNK;
57#endif
58
59
60/*********************************************************************************************************************************
61* Global Variables *
62*********************************************************************************************************************************/
63RT_C_DECLS_BEGIN
64DECL_HIDDEN_DATA(char) g_szrtProcExePath[RTPATH_MAX] = "Unknown.exe";
65DECL_HIDDEN_DATA(size_t) g_cchrtProcExePath = 11;
66DECL_HIDDEN_DATA(size_t) g_cchrtProcExeDir = 0;
67DECL_HIDDEN_DATA(size_t) g_offrtProcName = 0;
68RT_C_DECLS_END
69
70#ifdef IPRT_NO_CRT
71/** The first atexit() registration chunk. */
72static RTNOCRTATEXITCHUNK g_aAtExitPrealloc;
73/** Array of atexit() callback chunk pointers. */
74static RTNOCRTATEXITCHUNK *g_apAtExit[8192 / 256] = { &g_aAtExitPrealloc, };
75/** Chunk and callback index in one. */
76static volatile uint32_t g_idxNextAtExit = 0;
77#endif
78
79
80/*********************************************************************************************************************************
81* External Symbols *
82*********************************************************************************************************************************/
83extern DECLHIDDEN(void) InitStdHandles(PRTL_USER_PROCESS_PARAMETERS pParams); /* nocrt-streams-win.cpp */ /** @todo put in header */
84
85extern int main(int argc, char **argv, char **envp); /* in program */
86
87
88#ifdef IPRT_NO_CRT
89extern "C"
90int rtnocrt_atexit(PFNRTNOCRTATEXITCALLBACK pfnCallback) RT_NOEXCEPT
91{
92 AssertPtr(pfnCallback);
93
94 /*
95 * Allocate a table index.
96 */
97 uint32_t idx = ASMAtomicIncU32(&g_idxNextAtExit) - 1;
98 AssertReturnStmt(idx < RT_ELEMENTS(g_apAtExit) * RT_ELEMENTS(g_apAtExit[0]->apfnCallbacks),
99 ASMAtomicDecU32(&g_idxNextAtExit), -1);
100
101 /*
102 * Make sure the table chunk is there.
103 */
104 uint32_t idxChunk = idx / RT_ELEMENTS(g_apAtExit[0]->apfnCallbacks);
105 RTNOCRTATEXITCHUNK *pChunk = ASMAtomicReadPtrT(&g_apAtExit[idxChunk], RTNOCRTATEXITCHUNK *);
106 if (!pChunk)
107 {
108 pChunk = (RTNOCRTATEXITCHUNK *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pChunk));
109 AssertReturn(pChunk, -1); /* don't try decrement, someone could be racing us... */
110
111 if (!ASMAtomicCmpXchgPtr(&g_apAtExit[idxChunk], pChunk, NULL))
112 {
113 HeapFree(GetProcessHeap(), 0, pChunk);
114
115 pChunk = ASMAtomicReadPtrT(&g_apAtExit[idxChunk], RTNOCRTATEXITCHUNK *);
116 Assert(pChunk);
117 }
118 }
119
120 /*
121 * Add our callback.
122 */
123 pChunk->apfnCallbacks[idxChunk % RT_ELEMENTS(pChunk->apfnCallbacks)] = pfnCallback;
124 return 0;
125}
126#endif
127
128
129static int rtTerminateProcess(int32_t rcExit, bool fDoAtExit)
130{
131#ifdef IPRT_NO_CRT
132 /*
133 * Run atexit callback in reverse order.
134 */
135 if (fDoAtExit)
136 {
137 uint32_t idxAtExit = ASMAtomicReadU32(&g_idxNextAtExit);
138 if (idxAtExit-- > 0)
139 {
140 uint32_t idxChunk = idxAtExit / RT_ELEMENTS(g_apAtExit[0]->apfnCallbacks);
141 uint32_t idxCallback = idxAtExit % RT_ELEMENTS(g_apAtExit[0]->apfnCallbacks);
142 for (;;)
143 {
144 RTNOCRTATEXITCHUNK *pChunk = ASMAtomicReadPtrT(&g_apAtExit[idxChunk], RTNOCRTATEXITCHUNK *);
145 if (pChunk)
146 {
147 do
148 {
149 PFNRTNOCRTATEXITCALLBACK pfnCallback = pChunk->apfnCallbacks[idxCallback];
150 if (pfnCallback) /* Can be NULL see registration code */
151 pfnCallback();
152 } while (idxCallback-- > 0);
153 }
154 if (idxChunk == 0)
155 break;
156 idxChunk--;
157 idxCallback = RT_ELEMENTS(g_apAtExit[0]->apfnCallbacks) - 1;
158 }
159 }
160 }
161#else
162 RT_NOREF(fDoAtExit);
163#endif
164
165 /*
166 * Terminate.
167 */
168 for (;;)
169 NtTerminateProcess(NtCurrentProcess(), rcExit);
170}
171
172
173DECL_NO_INLINE(static, void) initProcExecPath(void)
174{
175 WCHAR wszPath[RTPATH_MAX];
176 UINT cwcPath = GetModuleFileNameW(NULL, wszPath, RT_ELEMENTS(wszPath));
177 if (cwcPath)
178 {
179 char *pszDst = g_szrtProcExePath;
180 int rc = RTUtf16ToUtf8Ex(wszPath, cwcPath, &pszDst, sizeof(g_szrtProcExePath), &g_cchrtProcExePath);
181 if (RT_SUCCESS(rc))
182 {
183 g_cchrtProcExeDir = g_offrtProcName = RTPathFilename(pszDst) - g_szrtProcExePath;
184 while ( g_cchrtProcExeDir >= 2
185 && RTPATH_IS_SLASH(g_szrtProcExePath[g_cchrtProcExeDir - 1])
186 && g_szrtProcExePath[g_cchrtProcExeDir - 2] != ':')
187 g_cchrtProcExeDir--;
188 }
189 else
190 RTMsgError("initProcExecPath: RTUtf16ToUtf8Ex failed: %Rrc\n", rc);
191 }
192 else
193 RTMsgError("initProcExecPath: GetModuleFileNameW failed: %Rhrc\n", GetLastError());
194}
195
196
197DECLASM(void) CustomMainEntrypoint(PPEB pPeb)
198{
199 /*
200 * Initialize stuff.
201 */
202 InitStdHandles(pPeb->ProcessParameters);
203 initProcExecPath();
204
205 /*
206 * Get and convert the command line to argc/argv format.
207 */
208 RTEXITCODE rcExit;
209 UNICODE_STRING const *pCmdLine = pPeb->ProcessParameters ? &pPeb->ProcessParameters->CommandLine : NULL;
210 if (pCmdLine)
211 {
212 char *pszCmdLine = NULL;
213 int rc = RTUtf16ToUtf8Ex(pCmdLine->Buffer, pCmdLine->Length / sizeof(WCHAR), &pszCmdLine, 0, NULL);
214 if (RT_SUCCESS(rc))
215 {
216 char **papszArgv;
217 int cArgs = 0;
218 rc = RTGetOptArgvFromString(&papszArgv, &cArgs, pszCmdLine,
219 RTGETOPTARGV_CNV_MODIFY_INPUT | RTGETOPTARGV_CNV_QUOTE_MS_CRT, NULL);
220 if (RT_SUCCESS(rc))
221 {
222 /*
223 * Call the main function.
224 */
225 AssertCompile(sizeof(rcExit) == sizeof(int));
226 rcExit = (RTEXITCODE)main(cArgs, papszArgv, NULL /*envp*/);
227 }
228 else
229 rcExit = RTMsgErrorExitFailure("Error parsing command line: %Rrc\n", rc);
230 }
231 else
232 rcExit = RTMsgErrorExitFailure("Failed to convert command line to UTF-8: %Rrc\n", rc);
233 }
234 else
235 rcExit = RTMsgErrorExitFailure("No command line\n");
236
237 rtTerminateProcess(rcExit, true /*fDoAtExit*/);
238}
239
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette