Pastey Phix Windows Bare window demo

--
-- demo\window.exw 
-- =============== 
-- 
-- A Standard Windows Window coded at the primitive API level 
-- Most Phix programmers should simply use Arwen or similar (was:Win32Lib, wxWidgets, EuGTK or EuIUP!) 
-- See winwire.exw for a simpler way: use cffi for 32<->64 bit compatibility 
-- 
 
--?"hello" 
--{} = wait_key() 
 
--/* 
include std/os.e 
include std/machine.e 
include std/dll.e 
--*/ 
 
--DEV use cffi: 
constant cbSize = 0, 
         style  = 4, 
         lpfnWndProc = 8, 
         cbClsExtra = 12, 
         cbWndExtra = 16, 
         hInstance  = 20, 
         hIcon      = 24, 
         hCursor    = 28, 
         hbrBackground = 32, 
         lpszMenuName  = 36, 
         lpszClassName = 40, 
         hIconSm = 44, 
         SIZE_OF_WNDCLASS = 48 
 
constant cbSize64           = 0, 
         style64            = 4, 
         lpfnWndProc64      = 8, 
         cbClsExtra64       = 16, 
         cbWndExtra64       = 20, 
         hInstance64        = 24, 
         hIcon64            = 32, 
         hCursor64          = 40, 
         hbrBackground64    = 48, 
         lpszMenuName64     = 56, 
         lpszClassName64    = 64, 
         hIconSm64          = 72, 
         SIZE_OF_WNDCLASS64 = 80 
--/* 
 
typedef struct tagWNDCLASSEX { 
  UINT      cbSize; 
  UINT      style; 
  WNDPROC   lpfnWndProc; 
  int       cbClsExtra; 
  int       cbWndExtra; 
  HINSTANCE hInstance; 
  HICON     hIcon; 
  HCURSOR   hCursor; 
  HBRUSH    hbrBackground; 
  LPCTSTR   lpszMenuName; 
  LPCTSTR   lpszClassName; 
  HICON     hIconSm; 
} WNDCLASSEX, *PWNDCLASSEX; 
 
struct  WNDCLASSEX64 
        cbSize                  rd      1 
        style                   rd      1 
>       lpfnWndProc             rq      1 
        cbClsExtra              rd      1 
        cbWndExtra              rd      1 
>       hInstance               rq      1 
        hIcon                   rq      1 
        hCursor                 rq      1 
        hbrBackground           rq      1 
        lpszMenuName            rq      1 
        lpszClassName           rq      1 
        hIconSm                 rq      1 
ends 
  style         dd 0 
  lpfnWndProc   dd WindowProc 
  cbClsExtra    dd 0 
  cbWndExtra    dd 0 
  hInstance     dd NULL 
  hIcon         dd NULL 
  hCursor       dd NULL 
  hbrBackground dd COLOR_BTNFACE+1 
  lpszMenuName  dd NULL 
  lpszClassName dd _class 
;ends 
 
--*/ 
 
constant SIZE_OF_MESSAGE = 28 
constant SIZE_OF_MESSAGE64 = 48 
 
--/* 
 
struct  POINT64 
        x                       rd      1 
        y                       rd      1 
ends 
 
typedef struct tagMSG { 
  HWND   hwnd; 
  UINT   message; 
  WPARAM wParam; 
  LPARAM lParam; 
  DWORD  time; 
  POINT  pt; 
} MSG, *PMSG, *LPMSG; 
;  msg MSG  
 
struct  MSG64 
        hwnd                    rq      1 
        message                 rq      1       <<?? (align??) 
        wParam                  rq      1 
        lParam                  rq      1 
        time                    rd      1 
                                rd      1       ; padding 
        pt                      POINT64 
ends 
 
label msg 
  msg.hwnd dd ? 
  msg.message dd ? 
  msg.wParam dd ? 
  msg.lParam dd ? 
  msg.time dd ? 
  msg.ptx dd ? 
  msg.pty dd ? 
 
 
--*/ 
 
constant CS_HREDRAW = 2, 
         CS_VREDRAW = 1 
 
constant SW_SHOWNORMAL = 1 
 
constant WM_CREATE = #01, 
         WM_PAINT  = #0F, 
         WM_DESTROY = #02, 
         WM_CHAR = 258, 
         VK_ESCAPE = 27 
 
constant SND_FILENAME = #00020000, 
         SND_ASYNC    = #00000001 
 
constant DT_SINGLELINE = #0020, 
         DT_CENTER     = #0001, 
         DT_VCENTER    = #0004 
 
function or_all(sequence s) 
-- or together all elements of a sequence 
atom result 
 
    result = 0 
    for i=1 to length(s) do 
        result = or_bits(result, s[i]) 
    end for 
    return result 
end function 
 
constant WS_OVERLAPPED  = #00000000, 
         WS_CAPTION     = #00C00000, 
         WS_SYSMENU     = #00080000, 
         WS_THICKFRAME  = #00040000, 
         WS_MINIMIZEBOX = #00020000, 
         WS_MAXIMIZEBOX = #00010000 
 
constant IDC_ARROW = 32512, 
         WHITE_BRUSH = 0, 
         CW_USEDEFAULT = #80000000, 
         WS_OVERLAPPEDWINDOW = or_all({WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU, 
                                       WS_THICKFRAME, WS_MINIMIZEBOX, 
                                       WS_MAXIMIZEBOX}), 
         DT_SINGLECENTER = or_all({DT_SINGLELINE, DT_CENTER, DT_VCENTER}), 
         SND_FILEASYNC = or_bits(SND_FILENAME,SND_ASYNC) 
 
integer xLoadIcon, xLoadCursor, xGetStockObject, xRegisterClassEx, 
        xCreateWindowEx, xShowWindow, xUpdateWindow, xGetMessage, 
        xTranslateMessage, xDispatchMessage, xPlaySound, xBeginPaint, 
        xGetClientRect, xDrawText, xEndPaint, xPostQuitMessage, xDefWindowProc, 
        xGetLastError 
 
procedure not_found(sequence name) 
    puts(1, "Couldn't find " & name & '\n') 
    abort(1) 
end procedure 
 
function link_dll(sequence name) 
-- dynamically link a dll 
atom lib = open_dll(name) 
    if lib=NULL then not_found(name) end if 
    return lib 
end function 
 
function link_c_func(atom dll, sequence name, sequence args, atom result) 
-- dynamically link a C routine as a Euphoria function 
integer handle = define_c_func(dll, name, args, result) 
    if handle=-1 then not_found(name) end if 
    return handle 
end function 
 
function link_c_proc(atom dll, sequence name, sequence args) 
-- dynamically link a C routine as a Euphoria function 
integer handle = define_c_proc(dll, name, args) 
    if handle=-1 then not_found(name) end if 
    return handle 
end function 
 
procedure link_dll_routines() 
-- get handles to all dll routines that we need 
atom user32, gdi32, winmm, kernel32 
 
    user32 = link_dll("user32.dll") 
    gdi32 = link_dll("gdi32.dll") 
    winmm = link_dll("winmm.dll") 
    kernel32 = link_dll("kernel32.dll") 
 
    xLoadIcon = link_c_func(user32, "LoadIconA", {C_POINTER, C_INT}, C_INT) 
    xLoadCursor = link_c_func(user32, "LoadCursorA", {C_POINTER, C_INT}, C_INT) 
    xGetStockObject = link_c_func(gdi32, "GetStockObject", {C_INT}, C_INT) 
    xRegisterClassEx = link_c_func(user32, "RegisterClassExA", {C_POINTER}, C_INT) 
    xCreateWindowEx = link_c_func(user32, "CreateWindowExA", 
                                  {C_INT, C_INT,C_INT,C_INT,C_INT,C_INT,C_INT,C_INT,C_INT,C_INT,C_INT,C_INT}, 
                                  C_INT) 
    xShowWindow = link_c_proc(user32, "ShowWindow", {C_INT, C_INT}) 
    xUpdateWindow = link_c_proc(user32, "UpdateWindow", {C_INT}) 
    xGetMessage = link_c_func(user32, "GetMessageA", 
                             {C_INT, C_INT, C_INT, C_INT}, C_INT) 
    xTranslateMessage = link_c_proc(user32, "TranslateMessage", {C_INT}) 
    xDispatchMessage = link_c_proc(user32, "DispatchMessageA", {C_INT}) 
    xPlaySound = link_c_proc(winmm, "PlaySound", {C_INT, C_INT, C_INT}) 
    xBeginPaint = link_c_func(user32, "BeginPaint", {C_INT, C_POINTER}, C_INT) 
    xGetClientRect = link_c_proc(user32, "GetClientRect", {C_INT, C_POINTER}) 
    xDrawText = link_c_proc(user32, "DrawTextA", 
                           {C_INT, C_INT, C_INT, C_INT, C_INT}) 
    xEndPaint = link_c_proc(user32, "EndPaint", {C_INT, C_INT}) 
    xPostQuitMessage = link_c_proc(user32, "PostQuitMessage", {C_INT}) 
    xDefWindowProc = link_c_func(user32, "DefWindowProcA", 
                                {C_INT, C_INT, C_INT, C_INT}, C_INT) 
    xGetLastError = link_c_func(kernel32,"GetLastError",{},C_INT) 
end procedure 
 
puts(1, "link Dll routines\n") 
 
link_dll_routines() 
 
global function WndProc(atom hwnd, atom iMsg, atom wParam, atom lParam) 
-- callback routine to handle Window class 
atom hdc, wav_file, Euphoria, ps, rect 
 
    if iMsg=WM_CREATE then 
        wav_file = allocate_string(`\Windows\Media\tada.wav`) 
        c_proc(xPlaySound, {wav_file,NULL,SND_FILEASYNC}) 
        free(wav_file) 
        return 0 
 
    elsif iMsg=WM_PAINT then 
--DEV use cffi: 
if machine_bits()=32 then 
        ps = allocate(64) 
else 
        ps = allocate(72) 
end if 
--/* 
struct PAINTSTRUCT 
  hdc         dd ? 
  fErase      dd ? 
  rcPaint     RECT 
  fRestore    dd ? 
  fIncUpdate  dd ? 
  rgbReserved db 32 dup (?) 
ends 
 
struct PAINTSTRUCT64 
  hdc         dq ? 
  fErase      dd ? 
  rcPaint     RECT 
  fRestore    dd ? 
  fIncUpdate  dd ? 
  rgbReserved db 36 dup (?) 
ends 
 
struct RECT 
  left   dd ? 
  top    dd ? 
  right  dd ? 
  bottom dd ? 
ends 
 
struct RECT64 
  left   dd ? 
  top    dd ? 
  right  dd ? 
  bottom dd ? 
ends 
--*/ 
--DEV use cffi: 
        rect = allocate(16) 
        hdc = c_func(xBeginPaint, {hwnd, ps}) 
        c_proc(xGetClientRect, {hwnd, rect}) 
        Euphoria = allocate_string("A Plain Vanilla Window using Euphoria!") 
        c_proc(xDrawText, {hdc, Euphoria, -1, rect,DT_SINGLECENTER}) 
        free(Euphoria) 
        c_proc(xEndPaint, {hwnd, ps}) 
        free(ps) 
        free(rect) 
        return 0 
 
    elsif iMsg=WM_DESTROY or (iMsg=WM_CHAR and wParam=VK_ESCAPE) then 
        c_proc(xPostQuitMessage, {0}) 
        return 0 
 
    end if 
 
    return c_func(xDefWindowProc, {hwnd, iMsg, wParam, lParam}) 
end function 
 
procedure WinMain() 
atom wndclass 
atom szAppName 
integer id 
atom WndProcAddress 
atom hwnd 
atom msg 
atom class 
atom icon_handle 
atom my_title 
 
if machine_bits()=32 then 
    wndclass = allocate(SIZE_OF_WNDCLASS) 
else 
    wndclass = allocate(SIZE_OF_WNDCLASS64) 
end if 
    szAppName = allocate_string("HelloWin") 
 
    id = routine_id("WndProc") 
    if id<=0 then crash("routine_id failed!\n") end if 
    WndProcAddress = call_back(id) -- get 32-bit address for callback 
 
if machine_bits()=32 then 
    poke4(wndclass+cbSize, SIZE_OF_WNDCLASS) 
    poke4(wndclass+style, or_bits(CS_HREDRAW, CS_VREDRAW)) 
    poke4(wndclass+lpfnWndProc, WndProcAddress) 
    poke4(wndclass+cbClsExtra, 0) 
    poke4(wndclass+cbWndExtra, 0) 
    poke4(wndclass+hInstance, 0) --hInstance 
else --machine_bits()=64 
    poke4(wndclass+cbSize64, SIZE_OF_WNDCLASS64) 
    poke4(wndclass+style64, or_bits(CS_HREDRAW, CS_VREDRAW)) 
    poke8(wndclass+lpfnWndProc64, WndProcAddress) 
    poke4(wndclass+cbClsExtra64, 0) 
    poke4(wndclass+cbWndExtra64, 0) 
    poke8(wndclass+hInstance64, 0) --hInstance 
end if 
 
    -- set icon in top-left of window 
    icon_handle = c_func(xLoadIcon, {instance(), 10}) 
if machine_bits()=32 then 
    poke4(wndclass+hIcon, icon_handle) 
    poke4(wndclass+hIconSm, icon_handle) 
else 
    poke8(wndclass+hIcon64, icon_handle) 
    poke8(wndclass+hIconSm64, icon_handle) 
end if 
 
    -- Wolfgang Fritz observes that you can set an icon dynamically using: 
    -- junk = sendMessage(hwnd, WM_SETICON, 1, icon_handle)  
    -- where WM_SETICON is 128, 1=big icon, 0 for small icon 
 
if machine_bits()=32 then 
    poke4(wndclass+hCursor, c_func(xLoadCursor, {NULL, IDC_ARROW})) 
    poke4(wndclass+hbrBackground, c_func(xGetStockObject, {WHITE_BRUSH})) 
    poke4(wndclass+lpszMenuName, NULL) 
    poke4(wndclass+lpszClassName, szAppName) 
else 
    poke8(wndclass+hCursor64, c_func(xLoadCursor, {NULL, IDC_ARROW})) 
    poke8(wndclass+hbrBackground64, c_func(xGetStockObject, {WHITE_BRUSH})) 
    poke8(wndclass+lpszMenuName64, NULL) 
    poke8(wndclass+lpszClassName64, szAppName) 
end if 
 
    class = c_func(xRegisterClassEx, {wndclass}) 
    free(szAppName) 
    free(wndclass) 
    if class=0 then 
        puts(1, "Couldn't register class\n") 
--5 (ERROR_ACCESS_DENIED) [occurred when SIZE_OF_WNDCLASS64 was wrong/padded] 
        ?c_func(xGetLastError,{}) 
        abort(1) 
    end if 
    my_title = allocate_string("Euphoria for WIN32") 
    hwnd = c_func(xCreateWindowEx, { 
                                    0,                   -- extended style 
                                    class,               -- window class name 
                                    my_title,            -- window caption 
                                    WS_OVERLAPPEDWINDOW, -- window style 
                                    CW_USEDEFAULT,       -- initial x position 
                                    CW_USEDEFAULT,       -- initial y position 
                                    CW_USEDEFAULT,       -- initial x size 
                                    CW_USEDEFAULT,       -- initial y size 
                                    NULL,                -- parent window handle 
                                    NULL,                -- window menu handle 
                                    0 ,                  -- hInstance // program instance handle 
                                    NULL})               -- creation parameters 
    free(my_title) 
    if hwnd=0 then 
        puts(1, "Couldn't CreateWindow\n") 
--5 (ERROR_ACCESS_DENIED) 
        ?c_func(xGetLastError,{}) 
        abort(1) 
    end if 
    c_proc(xShowWindow, {hwnd, SW_SHOWNORMAL}) 
    c_proc(xUpdateWindow, {hwnd}) 
 
if machine_bits()=32 then 
    msg = allocate(SIZE_OF_MESSAGE) 
else 
    msg = allocate(SIZE_OF_MESSAGE64) 
end if 
    while c_func(xGetMessage, {msg, NULL, 0, 0}) do 
        c_proc(xTranslateMessage, {msg}) 
        c_proc(xDispatchMessage, {msg}) 
    end while 
    free(msg) 
end procedure 
 
WinMain() 
 
--added to prevent false positives... [DEV, reported] 
--include ..\test\t01type.exw 
--include ..\test\t02parms.exw