4343import org .graalvm .nativeimage .Platforms ;
4444import org .graalvm .nativeimage .StackValue ;
4545import org .graalvm .nativeimage .VMRuntime ;
46+ import org .graalvm .nativeimage .c .CContext ;
4647import org .graalvm .nativeimage .c .function .CEntryPoint ;
48+ import org .graalvm .nativeimage .c .function .CFunction ;
4749import org .graalvm .nativeimage .c .function .CFunctionPointer ;
50+ import org .graalvm .nativeimage .c .struct .CPointerTo ;
4851import org .graalvm .nativeimage .c .struct .SizeOf ;
4952import org .graalvm .nativeimage .c .type .CCharPointer ;
5053import org .graalvm .nativeimage .c .type .CCharPointerPointer ;
54+ import org .graalvm .nativeimage .c .type .CIntPointer ;
5155import org .graalvm .nativeimage .c .type .CTypeConversion ;
5256import org .graalvm .nativeimage .c .type .CTypeConversion .CCharPointerHolder ;
5357import org .graalvm .nativeimage .c .type .WordPointer ;
@@ -229,7 +233,11 @@ private static int runCore0() {
229233 * exceptions in a InvocationTargetException.
230234 */
231235 JavaMainSupport mainSupport = ImageSingletons .lookup (JavaMainSupport .class );
232- invokeMain (mainSupport .mainArgs );
236+ String [] args = mainSupport .mainArgs ;
237+ if (Platform .includedIn (Platform .WINDOWS .class )) {
238+ args = WindowsArguments .alterArgs (args );
239+ }
240+ invokeMain (args );
233241
234242 return 0 ;
235243 } catch (Throwable ex ) {
@@ -244,6 +252,88 @@ private static int runCore0() {
244252 }
245253 }
246254
255+ @ CContext (WindowsArguments .Directives .class )
256+ final class WindowsArguments {
257+
258+ private WindowsArguments () {
259+ }
260+
261+ public static String [] alterArgs (String [] originalArgs ) {
262+ return readCommandLineArgs ();
263+ }
264+
265+ private static final int WCHAR_SIZE = 2 ;
266+
267+ private static String [] readCommandLineArgs () {
268+ var cmd = GetCommandLineW ();
269+
270+ CIntPointer numOfArgs = StackValue .get (Long .BYTES );
271+
272+ WCharPointerPointer args = CommandLineToArgvW (cmd , numOfArgs );
273+ try {
274+ var numArgs = numOfArgs .read ();
275+
276+ var results = new String [numArgs - 1 ];
277+ for (var i = 0 ; i < results .length ; i ++) {
278+ var arg = args .read (i + 1 );
279+ results [i ] = toJavaString (arg );
280+ }
281+
282+ return results ;
283+ } finally {
284+ LocalFree (args );
285+ }
286+ }
287+
288+ private static String toJavaString (WCharPointer arg ) {
289+ return CTypeConversion .asByteBuffer (arg , wcslen (arg ) * WCHAR_SIZE )
290+ .order (java .nio .ByteOrder .LITTLE_ENDIAN )
291+ .asCharBuffer ()
292+ .toString ();
293+ }
294+
295+ @ CPointerTo (nameOfCType = "wchar_t" )
296+ private interface WCharPointer extends PointerBase {
297+ }
298+
299+ @ CPointerTo (WCharPointer .class )
300+ private interface WCharPointerPointer extends PointerBase {
301+
302+ WCharPointer read (int index );
303+ }
304+
305+ @ CFunction
306+ private static native WCharPointer GetCommandLineW ();
307+
308+ @ CFunction
309+ private static native WCharPointerPointer CommandLineToArgvW (
310+ WCharPointer cmdLine , CIntPointer numArgsOut );
311+
312+ @ CFunction
313+ private static native int wcslen (WCharPointer str );
314+
315+ @ CFunction
316+ private static native void LocalFree (PointerBase p );
317+
318+ static final class Directives implements CContext .Directives {
319+
320+ @ Override
321+ public boolean isInConfiguration () {
322+ return Platform .includedIn (Platform .WINDOWS .class );
323+ }
324+
325+ @ Override
326+ public List <String > getHeaderFiles () {
327+ return List .of ("<windows.h>" , "<wchar.h>" );
328+ }
329+
330+ @ Override
331+ public List <String > getLibraries () {
332+ return List .of ("Kernel32" , "Shell32" );
333+ }
334+ }
335+ }
336+
247337 @ Uninterruptible (reason = "The caller initialized the thread state, so the callees do not need to be uninterruptible." , calleeMustBe = false )
248338 private static void runShutdown () {
249339 RecurringCallbackSupport .suspendCallbackTimer ("Recurring callbacks can't be executed during shutdown." );
0 commit comments