From b618b0c4f7b4316891ef1aca4be9d4bc33249d90 Mon Sep 17 00:00:00 2001 From: dlannan Date: Wed, 15 Oct 2025 22:41:41 +1030 Subject: [PATCH] More improvements to window creation --- editor/aspect-error.log | 2 +- editor/deps/winutils.lua | 138 ++++++++++++++++++++++++++++++++++----- editor/editor-win64.lua | 16 ++--- 3 files changed, 131 insertions(+), 25 deletions(-) diff --git a/editor/aspect-error.log b/editor/aspect-error.log index 05a69f5..5f553ba 100644 --- a/editor/aspect-error.log +++ b/editor/aspect-error.log @@ -1,4 +1,4 @@ -internal error: Template 'partials/statistics_js.html' not found in runtime:0 +internal error: Template 'partials/config_modules_js.html' not found in runtime:0 Lua stack traceback: editor\twig/aspect\error.lua:103: in function 'new' editor\twig/aspect\template.lua:395: in function 'render' diff --git a/editor/deps/winutils.lua b/editor/deps/winutils.lua index 066f2aa..15ca34c 100644 --- a/editor/deps/winutils.lua +++ b/editor/deps/winutils.lua @@ -1,6 +1,8 @@ ------------------------------------------------------------------------------------------------------------ local ffi = require( "ffi" ) +local tinsert = table.insert + local kernel32 = ffi.load( "kernel32.dll" ) local user32 = ffi.load( "user32.dll" ) local comdlg32 = ffi.load( "Comdlg32.dll" ) @@ -19,25 +21,124 @@ local Colors = { } ffi.cdef[[ - void Sleep(uint32_t ms); + + typedef unsigned long DWORD; + typedef int BOOL; + typedef const char* LPCSTR; + typedef unsigned int HANDLE; + typedef unsigned int HWND; + typedef unsigned long *ULONG_PTR; + typedef long LPARAM; + typedef int (*WNDENUMPROC)(HWND hwnd, LPARAM lParam); typedef struct enumData { uint64_t lparam[1]; const char * title; - } enumData; + } enumData; + + typedef struct tagPROCESSENTRY32 { + DWORD dwSize; + DWORD cntUsage; + DWORD th32ProcessID; + ULONG_PTR th32DefaultHeapID; + DWORD th32ModuleID; + DWORD cntThreads; + DWORD th32ParentProcessID; + long pcPriClassBase; + DWORD dwFlags; + char szExeFile[260]; + } PROCESSENTRY32; typedef struct { long left; long top; long right; long bottom; } RECT; + HANDLE CreateToolhelp32Snapshot(DWORD dwFlags, DWORD th32ProcessID); + BOOL Process32First(HANDLE hSnapshot, PROCESSENTRY32 *lppe); + BOOL Process32Next(HANDLE hSnapshot, PROCESSENTRY32 *lppe); + BOOL CloseHandle(HANDLE hObject); + + BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARAM lParam); + DWORD GetWindowThreadProcessId(HWND hWnd, DWORD *lpdwProcessId); + BOOL IsWindowVisible(HWND hWnd); + + DWORD WaitForInputIdle(HANDLE hProcess, DWORD dwMilliseconds); + HWND GetForegroundWindow(void); + int GetSystemMetrics(int nIndex); int AdjustWindowRect(RECT* lpRect, unsigned long dwStyle, int bMenu); long GetWindowLongA(unsigned int hWnd, int nIndex); - int SystemParametersInfoW(unsigned int uiAction, unsigned int uiParam, RECT* pvParam, unsigned int fWinIni); + BOOL SystemParametersInfoW(unsigned int uiAction, unsigned int uiParam, RECT* pvParam, unsigned int fWinIni); - int SetWindowPos(unsigned int hWnd, void* hWndInsertAfter, int X, int Y, int cx, int cy, unsigned int uFlags); + BOOL SetWindowPos(unsigned int hWnd, void* hWndInsertAfter, int X, int Y, int cx, int cy, unsigned int uFlags); + + void Sleep(uint32_t ms); ]] require("ffi.windows") +-- ----------------------------------------------------------------------------------- +local TH32CS_SNAPPROCESS = 0x00000002 +local process_parents = {} +local process_childs = {} + +local function GetAllProcesses( ) + -- Setup Toolhelp snapshot + local snapshot = kernel32.CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) + if snapshot == -1 then return end + + local entry = ffi.new("PROCESSENTRY32[1]") + entry[0].dwSize = ffi.sizeof("PROCESSENTRY32") + + local found = false + local first_entry = kernel32.Process32First(snapshot, entry) + if first_entry ~= 0 then + repeat + process_parents[entry[0].th32ParentProcessID] = process_parents[entry[0].th32ParentProcessID] or {} + tinsert(process_parents[entry[0].th32ParentProcessID], entry[0].th32ProcessID) + process_childs[entry[0].th32ProcessID] = entry[0].th32ParentProcessID + print(entry[0].th32ProcessID, entry[0].th32ParentProcessID) + until kernel32.Process32Next(snapshot, entry) == 0 + end + + kernel32.CloseHandle(snapshot) +end + +-- ----------------------------------------------------------------------------------- + +function CheckChildren( win_pid, target_pid ) + + if( process_parents[target_pid] ) then + for i, v in ipairs(process_parents[target_pid]) do + print(v, win_pid, target_pid) + if v == win_pid then return true end + end + end + return false +end + +-- ----------------------------------------------------------------------------------- + +local function FindWindowByProcId( proc_handle, proc_id, timeout_ms ) + + timeout_ms = timeout_ms or 5000 + + -- Wait until process is idle (i.e., its message queue is waiting) + local wait_result = ffi.C.Sleep(timeout_ms) + + -- Get the currently active (foreground) window + local hwnd = user32.GetForegroundWindow() + if hwnd == nil then + print("No foreground window found.") + return nil + end + + -- Check if it belongs to our target process + local pid_ptr = ffi.new("DWORD[1]") + user32.GetWindowThreadProcessId(hwnd, pid_ptr) + return hwnd +end + +-- ----------------------------------------------------------------------------------- + local function AssocQ( outstr, bsize ) local ftype = ffi.cast("char *", ffi.string("http")) local verb = ffi.cast("char *", ffi.string("open")) @@ -285,18 +386,23 @@ end ------------------------------------------------------------------------------------------------------------ return { - CreateWindow = CreateWindow, - SetWindowPos = SetWindowPos, - SetTransparentBlend = SetTransparentBlend, - GetHwndFromProcess = GetHwndFromProcess, - RemoveWindowBorders = RemoveWindowBorders, - WindowsFileSelect = WindowsFileSelect, - WindowsFolderSelect = WindowsFolderSelect, - execute = execute, - shellexecute = shellexecute, - Sleep = ffi.C.Sleep, - GetFile = GetFile, - getDefaultBrowser = getDefaultBrowser, + CreateWindow = CreateWindow, + SetWindowPos = SetWindowPos, + + SetTransparentBlend = SetTransparentBlend, + GetHwndFromProcess = GetHwndFromProcess, + RemoveWindowBorders = RemoveWindowBorders, + WindowsFileSelect = WindowsFileSelect, + WindowsFolderSelect = WindowsFolderSelect, + + execute = execute, + shellexecute = shellexecute, + Sleep = ffi.C.Sleep, + GetFile = GetFile, + + FindWindowByProcId = FindWindowByProcId, + GetAllProcesses = GetAllProcesses, + getDefaultBrowser = getDefaultBrowser, kernel = kernel32, user = user32, diff --git a/editor/editor-win64.lua b/editor/editor-win64.lua index a991a92..3fec512 100644 --- a/editor/editor-win64.lua +++ b/editor/editor-win64.lua @@ -38,12 +38,12 @@ print("BROWSER SETUP") local browser, bsize = winu.getDefaultBrowser() local browser_path = ffi.string(browser)..[[ -new-window "http://localhost:9190/index.html"]] - hproc_browser, hthread_browser, si_browser = execute(browser_path) - sleep(200) + hproc_browser, hthread_browser, pi_browser = execute(browser_path) -- Need to make this more generic (ie browser agnostic) - local browserhwnd = GetHwndFromProcess( hthread_browser, "Mozilla Firefox" ) + -- local browserhwnd = winu.GetHwndFromProcess( hthread_browser, "Mozilla Firefox" ) + local browserhwnd = winu.FindWindowByProcId(pi_browser[0].hProcess, hproc_browser, 400) -- local browserhwnd = user32.FindWindowA( nil, "http://localhost:9190/index.html") - print(hproc_browser, hthread_browser, si_browser) + -- print(hproc_browser, hthread_browser, si_browser) if(browserhwnd) then sleep(100) -- Let things setup (window pos etc) local style = user32.GetWindowLongA(browserhwnd, -16) @@ -63,10 +63,10 @@ print("SOKOL-LUAJIT SETUP") local width = rect[0].right - rect[0].left local height = rect[0].bottom - rect[0].top local sokolluajit_path = [["bin/win64/luajit.exe" "editor/editor.lua" ]]..string.format(" %d %d", width, height) - hproc_sokol, hthread_sokol, si_sokol = execute(sokolluajit_path) - sleep(200) + hproc_sokol, hthread_sokol, pi_sokol = execute(sokolluajit_path) print(hproc_sokol, hthread_sokol, si_sokol) - local sokolhwnd = GetHwndFromProcess( hthread_sokol, "editor - sokol" ) + -- local sokolhwnd = GetHwndFromProcess( hthread_sokol, "editor - sokol" ) + local sokolhwnd = winu.FindWindowByProcId(pi_sokol[0].hProcess, hproc_sokol, 200) -- local sokolhwnd = user32.FindWindowA( nil, "editor - sokol") if(sokolhwnd) then sleep(100) -- Let things setup (window pos etc) @@ -89,7 +89,7 @@ local function setupWindows() desktop_width = workArea.right - workArea.left desktop_height = workArea.bottom - workArea.top print("Screen size:", desktop_width, "x", desktop_height) - + local desktop = ffi.new("RECT[1]") -- Get a handle to the desktop window hDesktop = user32.GetDesktopWindow()