From: Francis De Brabandere <francisdb@gmail.com> When Timeout > 0 (either from //T:nn on the command line or set by the running script), start a timer thread that waits for the configured number of seconds. On expiry the script is terminated with exit code 1 after printing the standard message to the console. Setting Timeout to 0 or a different non-zero value during execution cancels and re-arms the timer. --- programs/wscript/host.c | 1 + programs/wscript/main.c | 33 +++++++++++++++++++++++++++++++++ programs/wscript/resource.h | 1 + programs/wscript/wscript.h | 2 ++ programs/wscript/wscript.rc | 3 +++ 5 files changed, 40 insertions(+) diff --git a/programs/wscript/host.c b/programs/wscript/host.c index 137bf046813..99aca1308ec 100644 --- a/programs/wscript/host.c +++ b/programs/wscript/host.c @@ -286,6 +286,7 @@ static HRESULT WINAPI Host_put_Timeout(IHost *iface, LONG v) if(v < 0) return E_INVALIDARG; wshTimeout = v; + schedule_timeout(v); return S_OK; } diff --git a/programs/wscript/main.c b/programs/wscript/main.c index 4d1bfd20eb6..a971ceeec8d 100644 --- a/programs/wscript/main.c +++ b/programs/wscript/main.c @@ -224,6 +224,37 @@ static void WINAPIV print_resource(unsigned int id, ...) free(fmt); } +static HANDLE timeout_cancel_event; +static HANDLE timeout_thread; + +static DWORD WINAPI timeout_thread_proc(void *arg) +{ + DWORD ms = (DWORD)(DWORD_PTR)arg; + if(WaitForSingleObject(timeout_cancel_event, ms) == WAIT_TIMEOUT) { + print_resource(IDS_TIMEOUT_EXCEEDED, scriptFullName); + ExitProcess(1); + } + return 0; +} + +void schedule_timeout(LONG seconds) +{ + if(timeout_thread) { + SetEvent(timeout_cancel_event); + WaitForSingleObject(timeout_thread, INFINITE); + CloseHandle(timeout_thread); + timeout_thread = NULL; + } + if(seconds <= 0) + return; + if(!timeout_cancel_event) + timeout_cancel_event = CreateEventW(NULL, TRUE, FALSE, NULL); + else + ResetEvent(timeout_cancel_event); + timeout_thread = CreateThread(NULL, 0, timeout_thread_proc, + (void *)(DWORD_PTR)(seconds * 1000), 0, NULL); +} + static void print_banner(void) { const char * (CDECL *wine_get_version)(void); @@ -678,8 +709,10 @@ int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR cmdline, int cm } if(init_engine(script, parser)) { + schedule_timeout(wshTimeout); if(!run_script(script_text, script, parser)) ret = 1; + schedule_timeout(0); IActiveScript_Close(script); ITypeInfo_Release(host_ti); }else { diff --git a/programs/wscript/resource.h b/programs/wscript/resource.h index 7295040a6d9..4e065589ed0 100644 --- a/programs/wscript/resource.h +++ b/programs/wscript/resource.h @@ -20,3 +20,4 @@ #define IDS_NO_SCRIPT_FILE 2 #define IDS_FILE_NOT_FOUND 3 #define IDS_SCRIPT_LOAD_ERROR 4 +#define IDS_TIMEOUT_EXCEEDED 5 diff --git a/programs/wscript/wscript.h b/programs/wscript/wscript.h index 56371d97b0c..c49dc33a579 100644 --- a/programs/wscript/wscript.h +++ b/programs/wscript/wscript.h @@ -35,3 +35,5 @@ extern int numOfArgs; extern VARIANT_BOOL wshInteractive; extern LONG wshTimeout; + +void schedule_timeout(LONG seconds); diff --git a/programs/wscript/wscript.rc b/programs/wscript/wscript.rc index 920361c5dc6..be13beb0812 100644 --- a/programs/wscript/wscript.rc +++ b/programs/wscript/wscript.rc @@ -46,4 +46,7 @@ Options:\n\ IDS_NO_SCRIPT_FILE, "Input Error: There is no script file specified.\n" IDS_FILE_NOT_FOUND, "Input Error: Can not find script file ""%1"".\n" IDS_SCRIPT_LOAD_ERROR, "CScript Error: Loading script ""%1"" failed (%2).\n" + IDS_TIMEOUT_EXCEEDED, +"Script execution time was exceeded on script ""%1"".\n\ +Script execution was terminated.\n" } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10702