| ... | @@ -23,8 +23,16 @@ comptime { | ... | @@ -23,8 +23,16 @@ comptime { |
| 23 | } else if (builtin.os.tag == .windows) { | 23 | } else if (builtin.os.tag == .windows) { |
| 24 | if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and | 24 | if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and |
| 25 | !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup")) | 25 | !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup")) |
| | 26 | { |
| | 27 | @export(WinStartup, .{ .name = "WinMainCRTStartup" }); |
| | 28 | } else if (@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and |
| | 29 | !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup")) |
| 26 | { | 30 | { |
| 27 | @export(WinMainCRTStartup, .{ .name = "WinMainCRTStartup" }); | 31 | @export(WinMainCRTStartup, .{ .name = "WinMainCRTStartup" }); |
| | 32 | } else if (@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup") and |
| | 33 | !@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup")) |
| | 34 | { |
| | 35 | @export(wWinMainCRTStartup, .{ .name = "wWinMainCRTStartup" }); |
| 28 | } | 36 | } |
| 29 | } else if (builtin.os.tag == .uefi) { | 37 | } else if (builtin.os.tag == .uefi) { |
| 30 | if (!@hasDecl(root, "EfiMain")) @export(EfiMain, .{ .name = "EfiMain" }); | 38 | if (!@hasDecl(root, "EfiMain")) @export(EfiMain, .{ .name = "EfiMain" }); |
| ... | @@ -123,6 +131,17 @@ fn _start() callconv(.Naked) noreturn { | ... | @@ -123,6 +131,17 @@ fn _start() callconv(.Naked) noreturn { |
| 123 | @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{}); | 131 | @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{}); |
| 124 | } | 132 | } |
| 125 | | 133 | |
| | 134 | fn WinStartup() callconv(.Stdcall) noreturn { |
| | 135 | @setAlignStack(16); |
| | 136 | if (!builtin.single_threaded) { |
| | 137 | _ = @import("start_windows_tls.zig"); |
| | 138 | } |
| | 139 | |
| | 140 | std.debug.maybeEnableSegfaultHandler(); |
| | 141 | |
| | 142 | std.os.windows.kernel32.ExitProcess(initEventLoopAndCallMain(u8, callMain)); |
| | 143 | } |
| | 144 | |
| 126 | fn WinMainCRTStartup() callconv(.Stdcall) noreturn { | 145 | fn WinMainCRTStartup() callconv(.Stdcall) noreturn { |
| 127 | @setAlignStack(16); | 146 | @setAlignStack(16); |
| 128 | if (!builtin.single_threaded) { | 147 | if (!builtin.single_threaded) { |
| ... | @@ -131,7 +150,20 @@ fn WinMainCRTStartup() callconv(.Stdcall) noreturn { | ... | @@ -131,7 +150,20 @@ fn WinMainCRTStartup() callconv(.Stdcall) noreturn { |
| 131 | | 150 | |
| 132 | std.debug.maybeEnableSegfaultHandler(); | 151 | std.debug.maybeEnableSegfaultHandler(); |
| 133 | | 152 | |
| 134 | std.os.windows.kernel32.ExitProcess(initEventLoopAndCallMain()); | 153 | const result = initEventLoopAndCallMain(std.os.windows.INT, callWinMain); |
| | 154 | std.os.windows.kernel32.ExitProcess(@bitCast(std.os.windows.UINT, result)); |
| | 155 | } |
| | 156 | |
| | 157 | fn wWinMainCRTStartup() callconv(.Stdcall) noreturn { |
| | 158 | @setAlignStack(16); |
| | 159 | if (!builtin.single_threaded) { |
| | 160 | _ = @import("start_windows_tls.zig"); |
| | 161 | } |
| | 162 | |
| | 163 | std.debug.maybeEnableSegfaultHandler(); |
| | 164 | |
| | 165 | const result = initEventLoopAndCallMain(std.os.windows.INT, callWWinMain); |
| | 166 | std.os.windows.kernel32.ExitProcess(@bitCast(std.os.windows.UINT, result)); |
| 135 | } | 167 | } |
| 136 | | 168 | |
| 137 | // TODO https://github.com/ziglang/zig/issues/265 | 169 | // TODO https://github.com/ziglang/zig/issues/265 |
| ... | @@ -185,7 +217,7 @@ fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 { | ... | @@ -185,7 +217,7 @@ fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 { |
| 185 | | 217 | |
| 186 | std.debug.maybeEnableSegfaultHandler(); | 218 | std.debug.maybeEnableSegfaultHandler(); |
| 187 | | 219 | |
| 188 | return initEventLoopAndCallMain(); | 220 | return initEventLoopAndCallMain(u8, callMain); |
| 189 | } | 221 | } |
| 190 | | 222 | |
| 191 | fn main(c_argc: i32, c_argv: [*][*:0]u8, c_envp: [*:null]?[*:0]u8) callconv(.C) i32 { | 223 | fn main(c_argc: i32, c_argv: [*][*:0]u8, c_envp: [*:null]?[*:0]u8) callconv(.C) i32 { |
| ... | @@ -200,7 +232,7 @@ const bad_main_ret = "expected return type of main to be 'void', '!void', 'noret | ... | @@ -200,7 +232,7 @@ const bad_main_ret = "expected return type of main to be 'void', '!void', 'noret |
| 200 | | 232 | |
| 201 | // This is marked inline because for some reason LLVM in release mode fails to inline it, | 233 | // This is marked inline because for some reason LLVM in release mode fails to inline it, |
| 202 | // and we want fewer call frames in stack traces. | 234 | // and we want fewer call frames in stack traces. |
| 203 | inline fn initEventLoopAndCallMain() u8 { | 235 | inline fn initEventLoopAndCallMain(comptime Out: type, comptime mainFunc: fn () Out) Out { |
| 204 | if (std.event.Loop.instance) |loop| { | 236 | if (std.event.Loop.instance) |loop| { |
| 205 | if (!@hasDecl(root, "event_loop")) { | 237 | if (!@hasDecl(root, "event_loop")) { |
| 206 | loop.init() catch |err| { | 238 | loop.init() catch |err| { |
| ... | @@ -214,7 +246,7 @@ inline fn initEventLoopAndCallMain() u8 { | ... | @@ -214,7 +246,7 @@ inline fn initEventLoopAndCallMain() u8 { |
| 214 | | 246 | |
| 215 | var result: u8 = undefined; | 247 | var result: u8 = undefined; |
| 216 | var frame: @Frame(callMainAsync) = undefined; | 248 | var frame: @Frame(callMainAsync) = undefined; |
| 217 | _ = @asyncCall(&frame, &result, callMainAsync, loop); | 249 | _ = @asyncCall(&frame, &result, callMainAsync, u8, mainFunc, loop); |
| 218 | loop.run(); | 250 | loop.run(); |
| 219 | return result; | 251 | return result; |
| 220 | } | 252 | } |
| ... | @@ -222,13 +254,13 @@ inline fn initEventLoopAndCallMain() u8 { | ... | @@ -222,13 +254,13 @@ inline fn initEventLoopAndCallMain() u8 { |
| 222 | | 254 | |
| 223 | // This is marked inline because for some reason LLVM in release mode fails to inline it, | 255 | // This is marked inline because for some reason LLVM in release mode fails to inline it, |
| 224 | // and we want fewer call frames in stack traces. | 256 | // and we want fewer call frames in stack traces. |
| 225 | return @call(.{ .modifier = .always_inline }, callMain, .{}); | 257 | return @call(.{ .modifier = .always_inline }, mainFunc, .{}); |
| 226 | } | 258 | } |
| 227 | fn callMainAsync(loop: *std.event.Loop) callconv(.Async) u8 { | 259 | fn callMainAsync(comptime Out: type, comptime mainProc: fn () Out, loop: *std.event.Loop) callconv(.Async) Out { |
| 228 | // This prevents the event loop from terminating at least until main() has returned. | 260 | // This prevents the event loop from terminating at least until main() has returned. |
| 229 | loop.beginOneEvent(); | 261 | loop.beginOneEvent(); |
| 230 | defer loop.finishOneEvent(); | 262 | defer loop.finishOneEvent(); |
| 231 | return callMain(); | 263 | return mainProc(); |
| 232 | } | 264 | } |
| 233 | | 265 | |
| 234 | // This is not marked inline because it is called with @asyncCall when | 266 | // This is not marked inline because it is called with @asyncCall when |
| ... | @@ -270,3 +302,25 @@ pub fn callMain() u8 { | ... | @@ -270,3 +302,25 @@ pub fn callMain() u8 { |
| 270 | else => @compileError(bad_main_ret), | 302 | else => @compileError(bad_main_ret), |
| 271 | } | 303 | } |
| 272 | } | 304 | } |
| | 305 | |
| | 306 | pub fn callWinMain() std.os.windows.INT { |
| | 307 | const hInstance = std.os.windows.kernel32.GetModuleHandleA(null); |
| | 308 | const lpCmdLine = std.os.windows.kernel32.GetCommandLineA(); |
| | 309 | |
| | 310 | // There's no (documented) way to get the nCmdShow parameter, so we're |
| | 311 | // using this fairly standard default. |
| | 312 | const nCmdShow = std.os.windows.user32.SW_SHOW; |
| | 313 | |
| | 314 | return root.WinMain(hInstance, null, lpCmdLine, nCmdShow); |
| | 315 | } |
| | 316 | |
| | 317 | pub fn callWWinMain() std.os.windows.INT { |
| | 318 | const hInstance = std.os.windows.kernel32.GetModuleHandleA(null); |
| | 319 | const lpCmdLine = std.os.windows.kernel32.GetCommandLineW(); |
| | 320 | |
| | 321 | // There's no (documented) way to get the nCmdShow parameter, so we're |
| | 322 | // using this fairly standard default. |
| | 323 | const nCmdShow = std.os.windows.user32.SW_SHOW; |
| | 324 | |
| | 325 | return root.wWinMain(hInstance, null, lpCmdLine, nCmdShow); |
| | 326 | } |