| ... | @@ -29,7 +29,15 @@ comptime { | ... | @@ -29,7 +29,15 @@ comptime { |
| 29 | if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and | 29 | if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and |
| 30 | !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup")) | 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 | } else if (builtin.os.tag == .uefi) { | 42 | } else if (builtin.os.tag == .uefi) { |
| 35 | if (!@hasDecl(root, "EfiMain")) @export(EfiMain, .{ .name = "EfiMain" }); | 43 | if (!@hasDecl(root, "EfiMain")) @export(EfiMain, .{ .name = "EfiMain" }); |
| ... | @@ -143,7 +151,18 @@ fn _start() callconv(.Naked) noreturn { | ... | @@ -143,7 +151,18 @@ fn _start() callconv(.Naked) noreturn { |
| 143 | @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{}); | 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 | @setAlignStack(16); | 166 | @setAlignStack(16); |
| 148 | if (!builtin.single_threaded) { | 167 | if (!builtin.single_threaded) { |
| 149 | _ = @import("start_windows_tls.zig"); | 168 | _ = @import("start_windows_tls.zig"); |
| ... | @@ -151,7 +170,8 @@ fn WinMainCRTStartup() callconv(.Stdcall) noreturn { | ... | @@ -151,7 +170,8 @@ fn WinMainCRTStartup() callconv(.Stdcall) noreturn { |
| 151 | | 170 | |
| 152 | std.debug.maybeEnableSegfaultHandler(); | 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 | // TODO https://github.com/ziglang/zig/issues/265 | 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,7 +225,7 @@ fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 { |
| 205 | | 225 | |
| 206 | std.debug.maybeEnableSegfaultHandler(); | 226 | std.debug.maybeEnableSegfaultHandler(); |
| 207 | | 227 | |
| 208 | return initEventLoopAndCallMain(); | 228 | return initEventLoopAndCallMain(u8, callMain); |
| 209 | } | 229 | } |
| 210 | | 230 | |
| 211 | fn main(c_argc: i32, c_argv: [*][*:0]u8, c_envp: [*:null]?[*:0]u8) callconv(.C) i32 { | 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,7 +240,7 @@ const bad_main_ret = "expected return type of main to be 'void', '!void', 'noret |
| 220 | | 240 | |
| 221 | // This is marked inline because for some reason LLVM in release mode fails to inline it, | 241 | // This is marked inline because for some reason LLVM in release mode fails to inline it, |
| 222 | // and we want fewer call frames in stack traces. | 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 | if (std.event.Loop.instance) |loop| { | 244 | if (std.event.Loop.instance) |loop| { |
| 225 | if (!@hasDecl(root, "event_loop")) { | 245 | if (!@hasDecl(root, "event_loop")) { |
| 226 | loop.init() catch |err| { | 246 | loop.init() catch |err| { |
| ... | @@ -234,7 +254,7 @@ inline fn initEventLoopAndCallMain() u8 { | ... | @@ -234,7 +254,7 @@ inline fn initEventLoopAndCallMain() u8 { |
| 234 | | 254 | |
| 235 | var result: u8 = undefined; | 255 | var result: u8 = undefined; |
| 236 | var frame: @Frame(callMainAsync) = undefined; | 256 | var frame: @Frame(callMainAsync) = undefined; |
| 237 | _ = @asyncCall(&frame, &result, callMainAsync, .{loop}); | 257 | _ = @asyncCall(&frame, &result, callMainAsync, .{ u8, mainFunc, loop }); |
| 238 | loop.run(); | 258 | loop.run(); |
| 239 | return result; | 259 | return result; |
| 240 | } | 260 | } |
| ... | @@ -242,13 +262,13 @@ inline fn initEventLoopAndCallMain() u8 { | ... | @@ -242,13 +262,13 @@ inline fn initEventLoopAndCallMain() u8 { |
| 242 | | 262 | |
| 243 | // This is marked inline because for some reason LLVM in release mode fails to inline it, | 263 | // This is marked inline because for some reason LLVM in release mode fails to inline it, |
| 244 | // and we want fewer call frames in stack traces. | 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 | // This prevents the event loop from terminating at least until main() has returned. | 268 | // This prevents the event loop from terminating at least until main() has returned. |
| 249 | loop.beginOneEvent(); | 269 | loop.beginOneEvent(); |
| 250 | defer loop.finishOneEvent(); | 270 | defer loop.finishOneEvent(); |
| 251 | return callMain(); | 271 | return mainProc(); |
| 252 | } | 272 | } |
| 253 | | 273 | |
| 254 | // This is not marked inline because it is called with @asyncCall when | 274 | // This is not marked inline because it is called with @asyncCall when |
| ... | @@ -290,3 +310,15 @@ pub fn callMain() u8 { | ... | @@ -290,3 +310,15 @@ pub fn callMain() u8 { |
| 290 | else => @compileError(bad_main_ret), | 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 | } |