Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Kotlin Native Win32 GUI Sample
plugins {
id 'org.jetbrains.kotlin.multiplatform' version '1.3.41'
repositories {
kotlin {
// For ARM, should be changed to iosArm32 or iosArm64
// For Linux, should be changed to e.g. linuxX64
// For MacOS, should be changed to e.g. macosX64
// For Windows, should be changed to e.g. mingwX64
mingwX64("mingw") {
binaries {
executable {
// Change to specify fully qualified name of your application's entry point:
entryPoint = 'sample.main'
// Specify command-line arguments, if necessary:
sourceSets {
// Note: To enable common source sets please comment out 'kotlin.import.noCommonSourceSets' property
// in file and re-import your project in IDE.
mingwMain {
mingwTest {
// Use the following Gradle tasks to run your application:
// :runReleaseExecutableMingw - without debug symbols
// :runDebugExecutableMingw - with debug symbols
package sample
import kotlinx.cinterop.*
fun WndProc(hwnd: HWND?, msg: UINT, wParam: WPARAM, lParam: LPARAM) : LRESULT
// This switch block differentiates between the message type that could have been received. If you want to
// handle a specific type of message in your application, just define it in this block.
// This message type is used by the OS to close a window. Just closes the window using DestroyWindow(hwnd);
WM_CLOSE.toUInt() -> DestroyWindow(hwnd)
// This message type is part of the WM_CLOSE case. After the DestroyWindow(hwnd) function is called, a
// WM_DESTROY message is sent to the window, which actually closes it.
WM_DESTROY.toUInt() -> PostQuitMessage(0)
// This message type is an important one for GUI programming. It symbolizes an event for a button for example.
WM_COMMAND.toUInt() ->
// To differentiate between controls, compare the HWND of, for example, the button to the HWND that is passed
// into the LPARAM parameter. This way you can establish control-specific actions.
//if (lParam == button.objcPtr().toLong() && (wParam == BN_CLICKED.toULong()))
// // The button was clicked, this is your proof.
// MessageBoxA(hwnd, "Button is pressed!", "test", MB_ICONINFORMATION);
// When no message type is handled in your application, return the default window procedure. In this case the message
// will be handled elsewhere or not handled at all.
else -> return (DefWindowProc!!)(hwnd, msg, wParam, lParam)
return 0;
fun main() {
println("Hello, Kotlin/Native!")
memScoped {
val hInstance = (GetModuleHandle!!)(null)
val lpszClassName = "GijSoft"
// In order to be able to create a window you need to have a window class available. A window class can be created for your
// application by registering one. The following struct declaration and fill provides details for a new window class.
val wc = alloc<WNDCLASSEX>();
wc.cbSize = sizeOf<WNDCLASSEX>().toUInt(); = 0u;
wc.lpfnWndProc = staticCFunction(::WndProc)
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = null;
wc.hCursor = (LoadCursor!!)(hInstance, IDC_ARROW);
//wc.hbrBackground = HBRUSH(COLOR_WINDOW+1);
wc.lpszMenuName = null;
wc.lpszClassName = lpszClassName.wcstr.ptr
wc.hIconSm = null;
// This function actually registers the window class. If the information specified in the 'wc' struct is correct,
// the window class should be created and no error is returned.
if((RegisterClassEx!!)(wc.ptr) == 0u.toUShort())
println("Failed to register!")
// This function creates the first window. It uses the window class registered in the first part, and takes a title,
// style and position/size parameters. For more information about style-specific definitions, refer to the MSDN where
// extended documentation is available.
val hwnd = CreateWindowExA(WS_EX_CLIENTEDGE, lpszClassName, "Win32 C Window application by evolution536",
CW_USEDEFAULT, CW_USEDEFAULT, 320, 125, null, null, hInstance, NULL
// Everything went right, show the window including all controls.
ShowWindow(hwnd, 1);
// This part is the "message loop". This loop ensures the application keeps running and makes the window able to receive messages
// in the WndProc function. You must have this piece of code in your GUI application if you want it to run properly.
val Msg = alloc<MSG>();
while((GetMessage!!)(Msg.ptr, null, 0u, 0u) > 0)

This comment has been minimized.

Copy link
Owner Author

@Eng-Fouad Eng-Fouad commented Jul 9, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment