From a4610203d1cbbf2032d3fcec61d30c5c7e378846 Mon Sep 17 00:00:00 2001 From: Whindmar Saksit Date: Sat, 13 Jun 2026 22:20:44 +0200 Subject: [PATCH] [WSCRIPT] Sync to Wine 11.10 (#9100) Adds support for script time-out and proper script error reporting. --- base/applications/cmdutils/wscript/host.c | 69 ++- base/applications/cmdutils/wscript/main.c | 399 +++++++++++++++--- base/applications/cmdutils/wscript/resource.h | 23 + base/applications/cmdutils/wscript/wscript.h | 6 +- media/doc/WINESYNC.txt | 2 +- 5 files changed, 401 insertions(+), 98 deletions(-) create mode 100644 base/applications/cmdutils/wscript/resource.h diff --git a/base/applications/cmdutils/wscript/host.c b/base/applications/cmdutils/wscript/host.c index b44064028eb..794e749f0a2 100644 --- a/base/applications/cmdutils/wscript/host.c +++ b/base/applications/cmdutils/wscript/host.c @@ -28,14 +28,11 @@ #include "wscript.h" #include -#include WINE_DEFAULT_DEBUG_CHANNEL(wscript); #define BUILDVERSION 16535 - -static const WCHAR wshNameW[] = {'W','i','n','d','o','w','s',' ','S','c','r','i','p','t',' ','H','o','s','t',0}; -static const WCHAR wshVersionW[] = {'5','.','8'}; +static const WCHAR wshVersionW[] = L"5.8"; VARIANT_BOOL wshInteractive = #ifndef CSCRIPT_BUILD @@ -44,15 +41,15 @@ VARIANT_BOOL wshInteractive = VARIANT_FALSE; #endif +LONG wshTimeout = 0; + static HRESULT to_string(VARIANT *src, BSTR *dst) { VARIANT v; HRESULT hres; - static const WCHAR nullW[] = {'n','u','l','l',0}; - if(V_VT(src) == VT_NULL) { - *dst = SysAllocString(nullW); + *dst = SysAllocString(L"null"); return *dst ? S_OK : E_OUTOFMEMORY; } @@ -73,28 +70,25 @@ static void print_string(const WCHAR *string) char *buf; if(wshInteractive) { - static const WCHAR windows_script_hostW[] = - {'W','i','n','d','o','w','s',' ','S','c','r','i','p','t',' ','H','o','s','t',0}; - MessageBoxW(NULL, string, windows_script_hostW, MB_OK); + MessageBoxW(NULL, string, L"Windows Script Host", MB_OK); return; } len = lstrlenW(string); ret = WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), string, len, &count, NULL); if(ret) { - static const WCHAR crnlW[] = {'\r','\n'}; - WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), crnlW, ARRAY_SIZE(crnlW), &count, NULL); + WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), L"\r\n", lstrlenW(L"\r\n"), &count, NULL); return; } - lena = WideCharToMultiByte(GetConsoleOutputCP(), 0, string, len, NULL, 0, NULL, NULL); - buf = heap_alloc(len); + lena = WideCharToMultiByte(GetOEMCP(), 0, string, len, NULL, 0, NULL, NULL); + buf = malloc(len); if(!buf) return; - WideCharToMultiByte(GetConsoleOutputCP(), 0, string, len, buf, lena, NULL, NULL); + WideCharToMultiByte(GetOEMCP(), 0, string, len, buf, lena, NULL, NULL); WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buf, lena, &count, FALSE); - heap_free(buf); + free(buf); WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), "\r\n", 2, &count, FALSE); } @@ -133,7 +127,7 @@ static HRESULT WINAPI Host_GetTypeInfoCount(IHost *iface, UINT *pctinfo) static HRESULT WINAPI Host_GetTypeInfo(IHost *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) { - WINE_TRACE("(%x %x %p\n", iTInfo, lcid, ppTInfo); + WINE_TRACE("(%x %lx %p\n", iTInfo, lcid, ppTInfo); ITypeInfo_AddRef(host_ti); *ppTInfo = host_ti; @@ -143,7 +137,7 @@ static HRESULT WINAPI Host_GetTypeInfo(IHost *iface, UINT iTInfo, LCID lcid, static HRESULT WINAPI Host_GetIDsOfNames(IHost *iface, REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) { - WINE_TRACE("(%s %p %d %x %p)\n", wine_dbgstr_guid(riid), rgszNames, + WINE_TRACE("(%s %p %d %lx %p)\n", wine_dbgstr_guid(riid), rgszNames, cNames, lcid, rgDispId); return ITypeInfo_GetIDsOfNames(host_ti, rgszNames, cNames, rgDispId); @@ -153,7 +147,7 @@ static HRESULT WINAPI Host_Invoke(IHost *iface, DISPID dispIdMember, REFIID riid LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) { - WINE_TRACE("(%d %p %p)\n", dispIdMember, pDispParams, pVarResult); + WINE_TRACE("(%ld %p %p)\n", dispIdMember, pDispParams, pVarResult); return ITypeInfo_Invoke(host_ti, iface, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); @@ -163,7 +157,7 @@ static HRESULT WINAPI Host_get_Name(IHost *iface, BSTR *out_Name) { WINE_TRACE("(%p)\n", out_Name); - if(!(*out_Name = SysAllocString(wshNameW))) + if(!(*out_Name = SysAllocString(L"Windows Script Host"))) return E_OUTOFMEMORY; return S_OK; } @@ -279,14 +273,21 @@ 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("(%d)\n", v); - return E_NOTIMPL; + TRACE("(%ld)\n", v); + + if(v < 0) + return E_INVALIDARG; + wshTimeout = v; + schedule_timeout(v); + return S_OK; } static HRESULT WINAPI Host_CreateObject(IHost *iface, BSTR ProgID, BSTR Prefix, @@ -321,11 +322,7 @@ static HRESULT WINAPI Host_Echo(IHost *iface, SAFEARRAY *args) { WCHAR *output = NULL, *ptr; unsigned argc, i, len; -#ifdef __REACTOS__ LONG ubound, lbound; -#else - int ubound, lbound; -#endif VARIANT *argv; BSTR *strs; HRESULT hres; @@ -345,8 +342,8 @@ static HRESULT WINAPI Host_Echo(IHost *iface, SAFEARRAY *args) return hres; argc = ubound-lbound+1; - strs = heap_alloc_zero(argc*sizeof(*strs)); - if(!strs) { + if (!(strs = calloc(argc, sizeof(*strs)))) + { SafeArrayUnaccessData(args); return E_OUTOFMEMORY; } @@ -364,7 +361,7 @@ static HRESULT WINAPI Host_Echo(IHost *iface, SAFEARRAY *args) SafeArrayUnaccessData(args); if(SUCCEEDED(hres)) { - ptr = output = heap_alloc((len+1)*sizeof(WCHAR)); + ptr = output = malloc((len+1)*sizeof(WCHAR)); if(output) { for(i=0; i < argc; i++) { if(i) @@ -381,13 +378,13 @@ static HRESULT WINAPI Host_Echo(IHost *iface, SAFEARRAY *args) for(i=0; i < argc; i++) SysFreeString(strs[i]); - heap_free(strs); + free(strs); if(FAILED(hres)) return hres; print_string(output); - heap_free(output); + free(output); return S_OK; } @@ -409,14 +406,12 @@ static HRESULT WINAPI Host_Sleep(IHost *iface, LONG Time) { #ifdef __REACTOS__ UNREFERENCED_PARAMETER(iface); +#endif + TRACE("(%ld)\n", Time); if (Time < 0) return E_INVALIDARG; Sleep(Time); return S_OK; -#else - WINE_FIXME("(%d)\n", Time); - return E_NOTIMPL; -#endif } static HRESULT WINAPI Host_ConnectObject(IHost *iface, IDispatch *Object, BSTR Prefix) diff --git a/base/applications/cmdutils/wscript/main.c b/base/applications/cmdutils/wscript/main.c index 1051f6a2cab..bc36a348c0b 100644 --- a/base/applications/cmdutils/wscript/main.c +++ b/base/applications/cmdutils/wscript/main.c @@ -32,6 +32,7 @@ #include #include "wscript.h" +#include "resource.h" #include @@ -50,14 +51,13 @@ #endif WINE_DEFAULT_DEBUG_CHANNEL(wscript); - -static const WCHAR wscriptW[] = {'W','S','c','r','i','p','t',0}; -static const WCHAR wshW[] = {'W','S','H',0}; WCHAR scriptFullName[MAX_PATH]; ITypeInfo *host_ti; ITypeInfo *arguments_ti; +static BOOL nologo; + static HRESULT query_interface(REFIID,void**); #ifdef __REACTOS__ @@ -224,7 +224,7 @@ static HRESULT WINAPI ActiveScriptSite_GetLCID(IActiveScriptSite *iface, LCID *p static HRESULT WINAPI ActiveScriptSite_GetItemInfo(IActiveScriptSite *iface, LPCOLESTR pstrName, DWORD dwReturnMask, IUnknown **ppunkItem, ITypeInfo **ppti) { - WINE_TRACE("(%s %x %p %p)\n", wine_dbgstr_w(pstrName), dwReturnMask, ppunkItem, ppti); + WINE_TRACE("(%s %lx %p %p)\n", wine_dbgstr_w(pstrName), dwReturnMask, ppunkItem, ppti); #ifdef __REACTOS__ { @@ -235,7 +235,7 @@ static HRESULT WINAPI ActiveScriptSite_GetItemInfo(IActiveScriptSite *iface, } #endif - if(lstrcmpW(pstrName, wshW) && lstrcmpW(pstrName, wscriptW)) + if(lstrcmpW(pstrName, L"WSH") && lstrcmpW(pstrName, L"WScript")) return E_FAIL; if(dwReturnMask & SCRIPTINFO_ITYPEINFO) { @@ -272,11 +272,214 @@ static HRESULT WINAPI ActiveScriptSite_OnStateChange(IActiveScriptSite *iface, return S_OK; } +static void write_to_handle(HANDLE handle, const WCHAR *string) +{ + DWORD count, ret, len, lena; + char *buf; + + len = lstrlenW(string); + ret = WriteConsoleW(handle, string, len, &count, NULL); + if(ret) { + WriteConsoleW(handle, L"\r\n", 2, &count, NULL); + return; + } + + lena = WideCharToMultiByte(GetOEMCP(), 0, string, len, NULL, 0, NULL, NULL); + buf = malloc(lena); + if(!buf) + return; + + WideCharToMultiByte(GetOEMCP(), 0, string, len, buf, lena, NULL, NULL); + WriteFile(handle, buf, lena, &count, FALSE); + free(buf); + WriteFile(handle, "\r\n", 2, &count, FALSE); +} + +static void print_error(const WCHAR *string) +{ + if(wshInteractive) { + MessageBoxW(NULL, string, L"Windows Script Host", MB_OK); + return; + } + + write_to_handle(GetStdHandle(STD_ERROR_HANDLE), string); +} + +static void print_string(const WCHAR *string) +{ + write_to_handle(GetStdHandle(STD_OUTPUT_HANDLE), string); +} + +static void output_writeconsole(const WCHAR *str, DWORD wlen) +{ + DWORD count; + + if(!WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), str, wlen, &count, NULL)) { + DWORD len; + char *buf; + + /* On Windows WriteConsoleW() fails if the output is redirected. So fall + * back to WriteFile() with OEM code page. */ + len = WideCharToMultiByte(GetOEMCP(), 0, str, wlen, NULL, 0, NULL, NULL); + buf = malloc(len); + + WideCharToMultiByte(GetOEMCP(), 0, str, wlen, buf, len, NULL, NULL); + WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buf, len, &count, FALSE); + free(buf); + } +} + +static void output_formatstring(const WCHAR *fmt, va_list va_args) +{ + WCHAR *str; + DWORD len; + + len = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, + fmt, 0, 0, (WCHAR *)&str, 0, &va_args); + if(len == 0 && GetLastError() != ERROR_NO_WORK_DONE) { + WINE_FIXME("Could not format string: le=%lu, fmt=%s\n", GetLastError(), wine_dbgstr_w(fmt)); + return; + } + if(wshInteractive) { + MessageBoxW(NULL, str, L"Windows Script Host", MB_OK); + }else { + output_writeconsole(str, len); + } + LocalFree(str); +} + +static void WINAPIV print_resource(unsigned int id, ...) +{ + WCHAR *fmt = NULL; + int len; + va_list va_args; + +#ifdef __REACTOS__ + #ifndef CSCRIPT_BUILD + #define APPNAME L"WScript" + #else + #define APPNAME L"CScript" + #endif + const WCHAR *str = NULL; + switch (id) + { + case IDS_USAGE: str = L"Usage: " APPNAME L" scriptname.extension [option...] [arguments...]\n"; break; + case IDS_NO_SCRIPT_FILE: str = L"Input Error: There is no script file specified.\n"; break; + case IDS_FILE_NOT_FOUND: str = L"Input Error: Can not find script file ""%1"".\n"; break; + case IDS_SCRIPT_LOAD_ERROR: str = APPNAME L" Error: Loading script ""%1"" failed (%2).\n"; break; + case IDS_TIMEOUT_EXCEEDED: str = L"Script execution time was exceeded on script ""%1"".\n\nScript execution was terminated.\n"; break; + } + if(!str) + { + WINE_FIXME("Missing string %u\n", id); + return; + } + len = lstrlenW(str); + fmt = malloc(++len * sizeof(WCHAR)); + if(!fmt) + return; + lstrcpyW(fmt, str); +#else + if(!(len = LoadStringW(GetModuleHandleW(NULL), id, (WCHAR *)&fmt, 0))) { + WINE_FIXME("LoadString failed with %ld\n", GetLastError()); + return; + } + + len++; + fmt = malloc(len * sizeof(WCHAR)); + if(!fmt) + return; + + LoadStringW(GetModuleHandleW(NULL), id, fmt, len); +#endif + + va_start(va_args, id); + output_formatstring(fmt, va_args); + va_end(va_args); + + 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) +{ +#ifdef __REACTOS__ + const WCHAR *header = L"ReactOS Script Host"; +#else + const char * (CDECL *wine_get_version)(void); + WCHAR header[64]; + + wine_get_version = (void *)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "wine_get_version"); + if(wine_get_version) + swprintf(header, ARRAY_SIZE(header), L"Wine %S Script Host", wine_get_version()); + else + swprintf(header, ARRAY_SIZE(header), L"Wine Script Host"); +#endif + print_string(header); + print_string(L""); +} + static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface, IActiveScriptError *pscripterror) { - WINE_FIXME("()\n"); - return E_NOTIMPL; + EXCEPINFO excepinfo; + ULONG line; + LONG character; + HRESULT hres; + WCHAR buf[1024]; + + WINE_TRACE("()\n"); + + memset(&excepinfo, 0, sizeof(excepinfo)); + hres = IActiveScriptError_GetExceptionInfo(pscripterror, &excepinfo); + if(SUCCEEDED(hres)) { + line = 0; + character = 0; + IActiveScriptError_GetSourcePosition(pscripterror, NULL, &line, &character); + + swprintf(buf, ARRAY_SIZE(buf), L"%s(%lu, %ld) %s: %s", + scriptFullName, line + 1, character + 1, + excepinfo.bstrSource ? excepinfo.bstrSource : L"", + excepinfo.bstrDescription ? excepinfo.bstrDescription : L""); + + print_error(buf); + + SysFreeString(excepinfo.bstrSource); + SysFreeString(excepinfo.bstrDescription); + SysFreeString(excepinfo.bstrHelpFile); + } + + return S_OK; } static HRESULT WINAPI ActiveScriptSite_OnEnterScript(IActiveScriptSite *iface) @@ -372,9 +575,7 @@ static BOOL load_typelib(void) ITypeLib *typelib; HRESULT hres; - static const WCHAR wscript_exeW[] = {'w','s','c','r','i','p','t','.','e','x','e',0}; - - hres = LoadTypeLib(wscript_exeW, &typelib); + hres = LoadTypeLib(L"wscript.exe", &typelib); if(FAILED(hres)) return FALSE; @@ -394,9 +595,6 @@ static BOOL get_engine_clsid(const WCHAR *ext, CLSID *clsid) HKEY hkey; HRESULT hres; - static const WCHAR script_engineW[] = - {'\\','S','c','r','i','p','t','E','n','g','i','n','e',0}; - res = RegOpenKeyW(HKEY_CLASSES_ROOT, ext, &hkey); if(res != ERROR_SUCCESS) return FALSE; @@ -409,7 +607,7 @@ static BOOL get_engine_clsid(const WCHAR *ext, CLSID *clsid) WINE_TRACE("fileid is %s\n", wine_dbgstr_w(fileid)); - lstrcatW(fileid, script_engineW); + lstrcatW(fileid, L"\\ScriptEngine"); res = RegOpenKeyW(HKEY_CLASSES_ROOT, fileid, &hkey); if(res != ERROR_SUCCESS) return FALSE; @@ -468,11 +666,11 @@ static BOOL init_engine(IActiveScript *script, IActiveScriptParse *parser) if(FAILED(hres)) return FALSE; - hres = IActiveScript_AddNamedItem(script, wscriptW, SCRIPTITEM_ISVISIBLE); + hres = IActiveScript_AddNamedItem(script, L"WScript", SCRIPTITEM_ISVISIBLE); if(FAILED(hres)) return FALSE; - hres = IActiveScript_AddNamedItem(script, wshW, SCRIPTITEM_ISVISIBLE); + hres = IActiveScript_AddNamedItem(script, L"WSH", SCRIPTITEM_ISVISIBLE); if(FAILED(hres)) return FALSE; @@ -492,6 +690,11 @@ static BSTR get_script_str(const WCHAR *filename) return NULL; size = GetFileSize(file, NULL); + if(!size) { + CloseHandle(file); + return SysAllocStringLen(NULL, 0); + } + map = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL); CloseHandle(file); if(map == INVALID_HANDLE_VALUE) @@ -521,28 +724,25 @@ static BSTR get_script_str(const WCHAR *filename) return ret; } -static void run_script(const WCHAR *filename, IActiveScript *script, IActiveScriptParse *parser) +static BOOL run_script(BSTR text, IActiveScript *script, IActiveScriptParse *parser) { - BSTR text; HRESULT hres; - text = get_script_str(filename); - if(!text) { - WINE_FIXME("Could not get script text\n"); - return; - } - - hres = IActiveScriptParse_ParseScriptText(parser, text, NULL, NULL, NULL, 1, 1, + hres = IActiveScriptParse_ParseScriptText(parser, text, NULL, NULL, NULL, 1, 0, SCRIPTTEXT_HOSTMANAGESSOURCE|SCRIPTITEM_ISVISIBLE, NULL, NULL); - SysFreeString(text); if(FAILED(hres)) { - WINE_FIXME("ParseScriptText failed: %08x\n", hres); - return; + if(hres != SCRIPT_E_REPORTED) + WINE_WARN("ParseScriptText failed: %08lx\n", hres); + return FALSE; } hres = IActiveScript_SetScriptState(script, SCRIPTSTATE_STARTED); - if(FAILED(hres)) - WINE_FIXME("SetScriptState failed: %08x\n", hres); + if(FAILED(hres)) { + if(hres != SCRIPT_E_REPORTED) + WINE_WARN("SetScriptState failed: %08lx\n", hres); + } + + return TRUE; } #ifdef __REACTOS__ @@ -772,10 +972,6 @@ static HRESULT run_wsf(LPCWSTR xmlpath) static BOOL set_host_properties(const WCHAR *prop) { - static const WCHAR nologoW[] = {'n','o','l','o','g','o',0}; - static const WCHAR iactive[] = {'i',0}; - static const WCHAR batch[] = {'b',0}; - if(*prop == '/') { ++prop; if(*prop == '/') @@ -784,21 +980,41 @@ static BOOL set_host_properties(const WCHAR *prop) else ++prop; - if(wcsicmp(prop, iactive) == 0) + if(wcsicmp(prop, L"i") == 0) wshInteractive = VARIANT_TRUE; - else if(wcsicmp(prop, batch) == 0) + else if(wcsicmp(prop, L"b") == 0) wshInteractive = VARIANT_FALSE; - else if(wcsicmp(prop, nologoW) == 0) - WINE_FIXME("ignored %s switch\n", debugstr_w(nologoW)); + else if(wcsicmp(prop, L"nologo") == 0) + nologo = TRUE; + else if(wcsicmp(prop, L"logo") == 0) + nologo = FALSE; + else if(wcsicmp(prop, L"d") == 0) + WINE_FIXME("ignoring //d\n"); + else if(wcsicmp(prop, L"x") == 0) + WINE_FIXME("ignoring //x\n"); + else if(wcsicmp(prop, L"u") == 0) + WINE_FIXME("ignoring //u\n"); + else if(wcsicmp(prop, L"s") == 0) + WINE_FIXME("ignoring //s\n"); + else if(wcsnicmp(prop, L"e:", 2) == 0) #ifdef __REACTOS__ - else if((prop[0] | 32) == 'e' && prop[1] == ':') g_force_engine = &prop[2]; +#else + WINE_FIXME("ignoring //e:\n"); #endif - else - { - WINE_FIXME("unsupported switch %s\n", debugstr_w(prop)); - return FALSE; + else if(wcsnicmp(prop, L"h:", 2) == 0) + 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) { + 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; } @@ -807,9 +1023,11 @@ int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR cmdline, int cm WCHAR *ext, *filepart, *filename = NULL; IActiveScriptParse *parser; IActiveScript *script; + BSTR script_text; WCHAR **argv; CLSID clsid; int argc, i; + int ret = 0; DWORD res; WINE_TRACE("(%p %p %s %x)\n", hInst, hPrevInst, wine_dbgstr_w(cmdline), cmdshow); @@ -818,32 +1036,93 @@ int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR cmdline, int cm if(!argv) return 1; + /* Pass 1: consume // host options from all positions. */ for(i=1; i ARRAY_SIZE(scriptFullName)) return 1; - ext = wcsrchr(filepart, '.'); #ifdef __REACTOS__ - if (ext && !lstrcmpiW(ext, L".wsf")) { + ext = wcsrchr(filepart, '.'); + if(ext && !lstrcmpiW(ext, L".wsf")) { return run_wsf(scriptFullName); } - +#endif + + script_text = get_script_str(scriptFullName); + if(!script_text) { + DWORD err = GetLastError(); + if(err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) { + print_resource(IDS_FILE_NOT_FOUND, scriptFullName); + }else { + WCHAR *syserr = NULL; + FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (WCHAR *)&syserr, 0, NULL); + if(syserr) { + /* Trim trailing whitespace from system error message. */ + int len = lstrlenW(syserr); + while(len > 0 && (syserr[len - 1] == '\r' || syserr[len - 1] == '\n' || syserr[len - 1] == ' ')) + syserr[--len] = 0; + print_resource(IDS_SCRIPT_LOAD_ERROR, scriptFullName, syserr); + LocalFree(syserr); + }else { + print_resource(IDS_SCRIPT_LOAD_ERROR, scriptFullName, L""); + } + } + return 1; + } + + ext = wcsrchr(filepart, '.'); +#ifdef __REACTOS__ if(g_force_engine) { CLSIDFromProgID(g_force_engine, &clsid); } @@ -863,13 +1142,17 @@ int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR cmdline, int cm } if(init_engine(script, parser)) { - run_script(filename, 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 { WINE_FIXME("Script initialization failed\n"); } + SysFreeString(script_text); IActiveScript_Release(script); IActiveScriptParse_Release(parser); @@ -879,5 +1162,5 @@ int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR cmdline, int cm CoUninitialize(); - return 0; + return ret; } diff --git a/base/applications/cmdutils/wscript/resource.h b/base/applications/cmdutils/wscript/resource.h new file mode 100644 index 00000000000..4e065589ed0 --- /dev/null +++ b/base/applications/cmdutils/wscript/resource.h @@ -0,0 +1,23 @@ +/* + * Copyright 2025 Francis De Brabandere + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define IDS_USAGE 1 +#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/base/applications/cmdutils/wscript/wscript.h b/base/applications/cmdutils/wscript/wscript.h index ca18363233c..c49dc33a579 100644 --- a/base/applications/cmdutils/wscript/wscript.h +++ b/base/applications/cmdutils/wscript/wscript.h @@ -16,8 +16,6 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#pragma once - #include "ihost.h" extern IHost host_obj; @@ -35,3 +33,7 @@ extern WCHAR **argums; extern int numOfArgs; extern VARIANT_BOOL wshInteractive; + +extern LONG wshTimeout; + +void schedule_timeout(LONG seconds); diff --git a/media/doc/WINESYNC.txt b/media/doc/WINESYNC.txt index 886ae3709b5..0b7a63fad16 100644 --- a/media/doc/WINESYNC.txt +++ b/media/doc/WINESYNC.txt @@ -255,7 +255,7 @@ base/applications/cmdutils/reg # Synced to WineStaging-6.23 base/applications/cmdutils/schtasks # Synced to WineStaging-3.3 base/applications/cmdutils/taskkill # Synced to WineStaging-3.17 base/applications/cmdutils/wmic # Synced to WineStaging-4.0 -base/applications/cmdutils/wscript # Synced to WineStaging-4.18 +base/applications/cmdutils/wscript # Synced to Wine-11.10 base/applications/cmdutils/xcopy # Synced to WineStaging-3.17 base/applications/games/winmine # Synced to WineStaging-2.16 with our own resources. base/applications/extrac32 # Synced to WineStaging-4.0