-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make it possible to create GUI mode applications in Windows #13058
Comments
At the minimum you will need the following monkey-patch, because otherwise the Crystal runtime will attempt to configure a non-existent console: module Crystal::System::FileDescriptor
def self.from_stdio(fd)
console_handle = false
handle = LibC._get_osfhandle(fd)
if handle != -1 && handle != -2
handle = LibC::HANDLE.new(handle)
# TODO: use `out old_mode` after implementing interpreter out closured var
old_mode = uninitialized LibC::DWORD
if LibC.GetConsoleMode(handle, pointerof(old_mode)) != 0
console_handle = true
if fd == 1 || fd == 2 # STDOUT or STDERR
if LibC.SetConsoleMode(handle, old_mode | LibC::ENABLE_VIRTUAL_TERMINAL_PROCESSING) != 0
at_exit { LibC.SetConsoleMode(handle, old_mode) }
end
end
end
end
io = IO::FileDescriptor.new(fd, blocking: true)
# Set sync or flush_on_newline as described in STDOUT and STDERR docs.
# See https://crystal-lang.org/api/toplevel.html#STDERR
if console_handle
io.sync = true
else
io.flush_on_newline = true
end
io
end
end Strictly speaking, you don't need a different entry point to be able to display any GUI, but one can be provided nonetheless: (if there are multiple @[Link(ldflags: "/ENTRY:wWinMainCRTStartup")]
@[Link(ldflags: "/SUBSYSTEM:WINDOWS")]
lib LibCrystalMain
end
lib LibC
alias HLOCAL = HANDLE
alias HINSTANCE = HANDLE
# shellapi.h
fun CommandLineToArgvW(lpCmdLine : LPWSTR, pNumArgs : Int*) : LPWSTR*
# winbase.h
fun LocalFree(hMem : HLOCAL) : HLOCAL
end
fun wWinMain(
hInstance : LibC::HINSTANCE,
hPrevInstance : LibC::HINSTANCE,
pCmdLine : LibC::LPWSTR,
nCmdShow : LibC::Int,
) : LibC::Int
argv = LibC.CommandLineToArgvW(pCmdLine, out argc)
wmain(argc, argv)
ensure
LibC.LocalFree(argv) if argv
end This is still not enough for production use because a lot of the places in Crystal's runtime still assume the presence of the standard streams (e.g. unhandled exceptions always go to |
The parameters in the alternative entrypoint can be retrieved as follows: lib LibC
# libloaderapi.h
fun GetModuleHandleW(lpModuleName : LPWSTR) : HMODULE
# processenv.h
fun GetCommandLineW : LPWSTR
# processthreadsapi.h
fun GetStartupInfoW(lpStartupInfo : STARTUPINFOW*)
end
# if `wWinMain` is invoked, then we are not building a DLL,
# so the following always works
hInstance = LibC.GetModuleHandleW(nil)
# this parameter exists for compatibility only
hPrevInstance = LibC::HINSTANCE.null
# the raw command line string, rarely needed when `ARGV` exists
pCmdLine = LibC.GetCommandLineW
# usually this is `SW_SHOW = 1`
# one way to customize this value is by creating a Windows shortcut to the program,
# then changing Shortcut -> Run in the shortcut properties dialog, which could produce
# `SW_MAXIMIZE = 3` or `SW_SHOWMINNOACTIVE = 7`
# the other way is by calling `LibC.CreateProcessW` directly
LibC.GetStartupInfoW(out startup_info)
nCmdShow = startup_info.wShowWindow So while If #13330 is implemented, it becomes the responsibility of user code to redefine |
This issue has been mentioned on Crystal Forum. There might be relevant details there: https://forum.crystal-lang.org/t/how-to-create-a-gui-app-using-libui-ng-on-windows/6361/24 |
Feature Request
Is your feature request related to a problem? Please describe clearly and concisely what is it.
Right now, every crystal program on Windows creates console window. It is fine for experimenting, but for polished programs (GUI, games, headless servers, etc) there should be a way to build without showing console window.
Describe the feature you would like, optionally illustrated by examples, and how it will solve the above problem.
I've tried adding
@[Link(ldflags: "/subsystem:windows")]
- application just silently closes after start.I think the problem is in https://github.com/crystal-lang/crystal/blob/master/src/crystal/system/win32/wmain.cr so tried to change it in different ways (change entry point to
fun wWinMain(ptr1 : Void*, ptr2 : Void*, argc : Int32, argv : UInt16**) : Int32
, change flags) but no luck - application still closes at start.Minimal example:
The text was updated successfully, but these errors were encountered: