[PATCH 0/2] MR10702: wscript: Implement WScript.Timeout and //T:nn
Wires up the WScript.Timeout property and its command-line counterpart //T:nn, both of which were no-op stubs. Commit 1: WScript.Timeout property + //T:nn parsing. Default 0, negative values rejected with VBScript error 5 (matches Windows). //T:nn sets the same value, readable from the script. Commit 2: Actual expiry. A timer thread is armed when Timeout > 0 (from either entry point). On expiry it prints the standard native message to the console and exits with code 1. Setting Timeout to 0 or re-assigning mid-script cancels/re-arms the timer. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10702
From: Francis De Brabandere <francisdb@gmail.com> Store an integer timeout value in the host. Reject negative values with E_INVALIDARG (VBScript error 5), matching Windows. Parse //T:nn on the command line into the same state, readable from the script as WScript.Timeout. Script-visible timeout expiry (terminating the script after the configured number of seconds) is not yet implemented. --- programs/wscript/host.c | 16 ++++++++++++---- programs/wscript/main.c | 9 +++++++-- programs/wscript/tests/run.js | 11 +++++++++++ programs/wscript/tests/run.vbs | 18 ++++++++++++++++++ programs/wscript/wscript.h | 2 ++ 5 files changed, 50 insertions(+), 6 deletions(-) diff --git a/programs/wscript/host.c b/programs/wscript/host.c index 2e6ed964f63..137bf046813 100644 --- a/programs/wscript/host.c +++ b/programs/wscript/host.c @@ -41,6 +41,8 @@ VARIANT_BOOL wshInteractive = VARIANT_FALSE; #endif +LONG wshTimeout = 0; + static HRESULT to_string(VARIANT *src, BSTR *dst) { VARIANT v; @@ -271,14 +273,20 @@ static HRESULT WINAPI Host_get_BuildVersion(IHost *iface, int *out_Build) static HRESULT WINAPI Host_get_Timeout(IHost *iface, LONG *out_Timeout) { - WINE_FIXME("(%p)\n", out_Timeout); - return E_NOTIMPL; + TRACE("(%p)\n", out_Timeout); + + *out_Timeout = wshTimeout; + return S_OK; } static HRESULT WINAPI Host_put_Timeout(IHost *iface, LONG v) { - WINE_FIXME("(%ld)\n", v); - return E_NOTIMPL; + TRACE("(%ld)\n", v); + + if(v < 0) + return E_INVALIDARG; + wshTimeout = v; + return S_OK; } static HRESULT WINAPI Host_CreateObject(IHost *iface, BSTR ProgID, BSTR Prefix, diff --git a/programs/wscript/main.c b/programs/wscript/main.c index 01b09030832..4d1bfd20eb6 100644 --- a/programs/wscript/main.c +++ b/programs/wscript/main.c @@ -555,8 +555,13 @@ static BOOL set_host_properties(const WCHAR *prop) WINE_FIXME("ignoring //h:\n"); else if(wcsnicmp(prop, L"job:", 4) == 0) WINE_FIXME("ignoring //job:\n"); - else if(wcsnicmp(prop, L"t:", 2) == 0) - WINE_FIXME("ignoring //t:\n"); + else if(wcsnicmp(prop, L"t:", 2) == 0) { + WCHAR *end; + LONG t = wcstol(prop + 2, &end, 10); + if(end == prop + 2 || *end || t < 0) + return FALSE; + wshTimeout = t; + } else return FALSE; return TRUE; diff --git a/programs/wscript/tests/run.js b/programs/wscript/tests/run.js index 7433f642f14..fee49c589ec 100644 --- a/programs/wscript/tests/run.js +++ b/programs/wscript/tests/run.js @@ -54,6 +54,17 @@ try { ok(false, "expected exception"); }catch(e) {} +ok(WScript.Timeout === 0, "default Timeout = " + WScript.Timeout); +WScript.Timeout = 30; +ok(WScript.Timeout === 30, "WScript.Timeout = " + WScript.Timeout); +WScript.Timeout = 0; +ok(WScript.Timeout === 0, "WScript.Timeout = " + WScript.Timeout); +try { + WScript.Timeout = -1; + ok(false, "expected exception for negative Timeout"); +}catch(e) {} +ok(WScript.Timeout === 0, "Timeout after negative = " + WScript.Timeout); + var obj = WScript.CreateObject("Wine.Test"); obj.ok(true, "Broken WScript.CreateObject object?"); diff --git a/programs/wscript/tests/run.vbs b/programs/wscript/tests/run.vbs index 785df78d4df..c29c80d9000 100644 --- a/programs/wscript/tests/run.vbs +++ b/programs/wscript/tests/run.vbs @@ -27,4 +27,22 @@ End Sub Call ok(WScript is WSH, "WScript is not WSH") +Call ok(WScript.Timeout = 0, "default Timeout = " & WScript.Timeout) +Call ok(TypeName(WScript.Timeout) = "Long", "Timeout TypeName = " & TypeName(WScript.Timeout)) + +WScript.Timeout = 30 +Call ok(WScript.Timeout = 30, "WScript.Timeout = " & WScript.Timeout) + +WScript.Timeout = 0 +Call ok(WScript.Timeout = 0, "WScript.Timeout = " & WScript.Timeout) + +Dim prev_timeout +prev_timeout = WScript.Timeout +On Error Resume Next +Err.Clear +WScript.Timeout = -1 +Call ok(Err.Number = 5, "negative Timeout err.Number = " & Err.Number) +Call ok(WScript.Timeout = prev_timeout, "negative Timeout changed value to " & WScript.Timeout) +On Error Goto 0 + Call winetest.reportSuccess() diff --git a/programs/wscript/wscript.h b/programs/wscript/wscript.h index d624a2d851e..56371d97b0c 100644 --- a/programs/wscript/wscript.h +++ b/programs/wscript/wscript.h @@ -33,3 +33,5 @@ extern WCHAR **argums; extern int numOfArgs; extern VARIANT_BOOL wshInteractive; + +extern LONG wshTimeout; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10702
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
This merge request was approved by Jacek Caban. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10702
participants (3)
-
Francis De Brabandere -
Francis De Brabandere (@francisdb) -
Jacek Caban (@jacek)