| ... | ... | @@ -29,7 +29,15 @@ comptime { |
| 29 | 29 | if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and |
| 30 | 30 | !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup")) |
| 31 | 31 | { |
| 32 | | @export(WinMainCRTStartup, .{ .name = "WinMainCRTStartup" }); |
| 32 | @export(WinStartup, .{ .name = "wWinMainCRTStartup" }); |
| 33 | } else if (@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and |
| 34 | !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup")) |
| 35 | { |
| 36 | @compileError("WinMain not supported; declare wWinMain or main instead"); |
| 37 | } else if (@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup") and |
| 38 | !@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup")) |
| 39 | { |
| 40 | @export(wWinMainCRTStartup, .{ .name = "wWinMainCRTStartup" }); |
| 33 | 41 | } |
| 34 | 42 | } else if (builtin.os.tag == .uefi) { |
| 35 | 43 | if (!@hasDecl(root, "EfiMain")) @export(EfiMain, .{ .name = "EfiMain" }); |
| ... | ... | @@ -143,7 +151,18 @@ fn _start() callconv(.Naked) noreturn { |
| 143 | 151 | @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{}); |
| 144 | 152 | } |
| 145 | 153 | |
| 146 | | fn WinMainCRTStartup() callconv(.Stdcall) noreturn { |
| 154 | fn WinStartup() callconv(.Stdcall) noreturn { |
| 155 | @setAlignStack(16); |
| 156 | if (!builtin.single_threaded) { |
| 157 | _ = @import("start_windows_tls.zig"); |
| 158 | } |
| 159 | |
| 160 | std.debug.maybeEnableSegfaultHandler(); |
| 161 | |
| 162 | std.os.windows.kernel32.ExitProcess(initEventLoopAndCallMain(u8, callMain)); |
| 163 | } |
| 164 | |
| 165 | fn wWinMainCRTStartup() callconv(.Stdcall) noreturn { |
| 147 | 166 | @setAlignStack(16); |
| 148 | 167 | if (!builtin.single_threaded) { |
| 149 | 168 | _ = @import("start_windows_tls.zig"); |
| ... | ... | @@ -151,7 +170,8 @@ fn WinMainCRTStartup() callconv(.Stdcall) noreturn { |
| 151 | 170 | |
| 152 | 171 | std.debug.maybeEnableSegfaultHandler(); |
| 153 | 172 | |
| 154 | | std.os.windows.kernel32.ExitProcess(initEventLoopAndCallMain()); |
| 173 | const result = initEventLoopAndCallMain(std.os.windows.INT, call_wWinMain); |
| 174 | std.os.windows.kernel32.ExitProcess(@bitCast(std.os.windows.UINT, result)); |
| 155 | 175 | } |
| 156 | 176 | |
| 157 | 177 | // TODO https://github.com/ziglang/zig/issues/265 |
| ... | ... | @@ -205,7 +225,7 @@ fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 { |
| 205 | 225 | |
| 206 | 226 | std.debug.maybeEnableSegfaultHandler(); |
| 207 | 227 | |
| 208 | | return initEventLoopAndCallMain(); |
| 228 | return initEventLoopAndCallMain(u8, callMain); |
| 209 | 229 | } |
| 210 | 230 | |
| 211 | 231 | fn main(c_argc: i32, c_argv: [*][*:0]u8, c_envp: [*:null]?[*:0]u8) callconv(.C) i32 { |
| ... | ... | @@ -220,7 +240,7 @@ const bad_main_ret = "expected return type of main to be 'void', '!void', 'noret |
| 220 | 240 | |
| 221 | 241 | // This is marked inline because for some reason LLVM in release mode fails to inline it, |
| 222 | 242 | // and we want fewer call frames in stack traces. |
| 223 | | inline fn initEventLoopAndCallMain() u8 { |
| 243 | inline fn initEventLoopAndCallMain(comptime Out: type, comptime mainFunc: fn () Out) Out { |
| 224 | 244 | if (std.event.Loop.instance) |loop| { |
| 225 | 245 | if (!@hasDecl(root, "event_loop")) { |
| 226 | 246 | loop.init() catch |err| { |
| ... | ... | @@ -234,7 +254,7 @@ inline fn initEventLoopAndCallMain() u8 { |
| 234 | 254 | |
| 235 | 255 | var result: u8 = undefined; |
| 236 | 256 | var frame: @Frame(callMainAsync) = undefined; |
| 237 | | _ = @asyncCall(&frame, &result, callMainAsync, .{loop}); |
| 257 | _ = @asyncCall(&frame, &result, callMainAsync, .{ u8, mainFunc, loop }); |
| 238 | 258 | loop.run(); |
| 239 | 259 | return result; |
| 240 | 260 | } |
| ... | ... | @@ -242,13 +262,13 @@ inline fn initEventLoopAndCallMain() u8 { |
| 242 | 262 | |
| 243 | 263 | // This is marked inline because for some reason LLVM in release mode fails to inline it, |
| 244 | 264 | // and we want fewer call frames in stack traces. |
| 245 | | return @call(.{ .modifier = .always_inline }, callMain, .{}); |
| 265 | return @call(.{ .modifier = .always_inline }, mainFunc, .{}); |
| 246 | 266 | } |
| 247 | | fn callMainAsync(loop: *std.event.Loop) callconv(.Async) u8 { |
| 267 | fn callMainAsync(comptime Out: type, comptime mainProc: fn () Out, loop: *std.event.Loop) callconv(.Async) Out { |
| 248 | 268 | // This prevents the event loop from terminating at least until main() has returned. |
| 249 | 269 | loop.beginOneEvent(); |
| 250 | 270 | defer loop.finishOneEvent(); |
| 251 | | return callMain(); |
| 271 | return mainProc(); |
| 252 | 272 | } |
| 253 | 273 | |
| 254 | 274 | // This is not marked inline because it is called with @asyncCall when |
| ... | ... | @@ -290,3 +310,15 @@ pub fn callMain() u8 { |
| 290 | 310 | else => @compileError(bad_main_ret), |
| 291 | 311 | } |
| 292 | 312 | } |
| 313 | |
| 314 | pub fn call_wWinMain() std.os.windows.INT { |
| 315 | const hInstance = @ptrCast(std.os.windows.HINSTANCE, std.os.windows.kernel32.GetModuleHandleW(null).?); |
| 316 | const hPrevInstance: ?std.os.windows.HINSTANCE = null; // MSDN: "This parameter is always NULL" |
| 317 | const lpCmdLine = std.os.windows.kernel32.GetCommandLineW(); |
| 318 | |
| 319 | // There's no (documented) way to get the nCmdShow parameter, so we're |
| 320 | // using this fairly standard default. |
| 321 | const nCmdShow = std.os.windows.user32.SW_SHOW; |
| 322 | |
| 323 | return root.wWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow); |
| 324 | } |