# How to receive different kinds of parameters in main function(eg \`winMain\`)

**URL:** <https://forum.crystal-lang.org/t/how-to-receive-different-kinds-of-parameters-in-main-function-eg-winmain/5039>\
**Category:** Help & Support\
**Created:** [October 28, 2022, 6:52am UTC](https://forum.crystal-lang.org/t/how-to-receive-different-kinds-of-parameters-in-main-function-eg-winmain/5039 "2022-10-28T06:52:26Z")\
**Posts on this page:** 1\
**Showing post:** 4

<div class="post-metadata">

**Author:** ![HertzDevil](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/hertzdevil/32/1023_2.png) [@HertzDevil](https://forum.crystal-lang.org/u/HertzDevil)\
**Post date:** [October 28, 2022, 10:04am UTC](https://forum.crystal-lang.org/t/how-to-receive-different-kinds-of-parameters-in-main-function-eg-winmain/5039/4 "2022-10-28T10:04:14Z")

</div>

Assuming you want to build a Windows application without a console, this is one way to do it:

```crystal
@[Link(ldflags: "/ENTRY:wWinMainCRTStartup")] # overrides previous `/ENTRY` setting
@[Link(ldflags: "/SUBSYSTEM:WINDOWS")]
lib LibCrystalMain
end

lib LibC
  fun CommandLineToArgvW(lpCmdLine : LPWSTR, pNumArgs : Int*) : LPWSTR*
  fun LocalFree(hMem : Void*) : Void*
end

@[CallConvention("X86_StdCall")]
fun wWinMain(hInstance : Void*, hPrevInstance : Void*, pCmdLine : UInt16*, nCmdShow : Int32) : Int32
  argv = LibC.CommandLineToArgvW(pCmdLine, out argc)
  status = wmain(argc, argv)
  LibC.LocalFree(argv)
  status
end

module Crystal::System::FileDescriptor
  def self.from_stdio(fd)
    console_handle = false
    handle = LibC._get_osfhandle(fd)
    if handle != -1 && handle != -2 # standard streams are unavailable
      handle = LibC::HANDLE.new(handle)
      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

    # don't use `#system_info` to determine whether the descriptor should block,
    # as that raises because `fd` is invalid (non-blocking IO isn't supported yet anyway)
    io = IO::FileDescriptor.new(fd, blocking: true)
    if console_handle
      io.sync = true
    else
      io.flush_on_newline = true
    end
    io
  end
end

```

Note that the entry point for the linker is _not_ `wmain` nor `wWinMain`, but rather `wWinMainCRTStartup`, which calls `wWinMain` eventually. There is no need to remove the existing `main` or `wmain`, they are simply not called directly by the real entry point. This real entry point never accepts arguments, so there is no general mechanism to pass the parameters from a user entry point like `wWinMain` to `Crystal.main`. In this case all the parameters can be retrieved anywhere as below:

```crystal
lib LibC
  GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT = 2

  fun GetCommandLineW : LPWSTR
  fun GetStartupInfoW(lpStartupInfo : STARTUPINFOW*)
end

hInstance = begin
  result = LibC.GetModuleHandleExW(LibC::GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, nil, out hmodule)
  result != 0 ? hmodule : Pointer(Void).null
end

hPrevInstance = Pointer(Void).null

pCmdLine = LibC.GetCommandLineW

nCmdShow = begin
  LibC.GetStartupInfoW(out info)
  info.wShowWindow
end

```

* * *

For GCC / Clang on Linux the entry point is specified similarly:

```crystal
@[Link(ldflags: "--entry=foo")]
lib LibCrystalMain
end

fun foo
  LibC.printf("abc\n")
  LibC._exit(0)
end

```

For macOS apparently [you need an extra link flag](https://stackoverflow.com/questions/24841283/how-can-i-set-a-custom-c-entry-point-with-clang-on-os-x-mavericks).

---

_[View the full topic](https://forum.crystal-lang.org/t/how-to-receive-different-kinds-of-parameters-in-main-function-eg-winmain/5039)._
