Implement real MsgBox() for VBScript table scripts (browser confirm/alert)
libwinevbs's __LIBWINEVBS__ build of Global_MsgBox() only logged the prompt text and never set a return value, since it has no host UI to show a dialog through. Any table script that branches on MsgBox(...) = vbYes (a common pattern - e.g. core.vbs's own trough ball-count dialog) always took the "no" branch, since the result stayed at its zero-initialized default. Adds a msgbox callback to libwinevbs_callbacks_t, wired on the vpinball-wasm side to a real window.confirm()/alert() call. Both are synchronous browser APIs that block JS execution and return a value immediately, matching what VBScript's MsgBox() needs (its result is used by the calling statement right away) - the only way to answer it asynchronously would require Asyncify or a busy-wait poll loop, which this project has deliberately avoided elsewhere. Confirmed fixed by hands-on testing: a table's ball-count confirm dialog now correctly returns Yes/No based on the user's click, instead of always silently taking the "no" branch. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
diff --git a/include/libwinevbs.h b/include/libwinevbs.h
|
||||
index 3ba4df9..6cac7df 100644
|
||||
--- a/include/libwinevbs.h
|
||||
+++ b/include/libwinevbs.h
|
||||
@@ -52,6 +52,14 @@ LIBWINEVBS_API const char* libwinevbs_hresult_name(HRESULT hr);
|
||||
typedef struct {
|
||||
void (*log)(libwinevbs_log_level_t level, const char* format, va_list args);
|
||||
HRESULT (*create_object)(const WCHAR* progid, IClassFactory* cf, IUnknown** obj);
|
||||
+ /* Answers a VBScript MsgBox() call. Must return synchronously (its result
|
||||
+ is used by the calling script statement immediately) - e.g. a real,
|
||||
+ blocking confirm()/alert() call under Emscripten. type is the raw
|
||||
+ VBScript "buttons" argument (MB_OK=0, MB_OKCANCEL=1, MB_YESNO=4, ...);
|
||||
+ title may be NULL. Return the matching button id (IDOK=1, IDCANCEL=2,
|
||||
+ IDABORT=3, IDRETRY=4, IDIGNORE=5, IDYES=6, IDNO=7), matching vbOK..vbNo.
|
||||
+ If unset, MsgBox always answers IDOK/vbOK without asking anything. */
|
||||
+ int (*msgbox)(const char* prompt, int type, const char* title);
|
||||
} libwinevbs_callbacks_t;
|
||||
|
||||
LIBWINEVBS_API void libwinevbs_init(const libwinevbs_callbacks_t* callbacks);
|
||||
diff --git a/src/libwinevbs.c b/src/libwinevbs.c
|
||||
index 7b3d6f0..91091e4 100644
|
||||
--- a/src/libwinevbs.c
|
||||
+++ b/src/libwinevbs.c
|
||||
@@ -32,6 +32,14 @@ HRESULT libwinevbs_create_object(const WCHAR* progid, IClassFactory* cf, IUnknow
|
||||
return CLASS_E_CLASSNOTAVAILABLE;
|
||||
}
|
||||
|
||||
+int libwinevbs_msgbox(const char* prompt, int type, const char* title)
|
||||
+{
|
||||
+ if (g_callbacks.msgbox)
|
||||
+ return g_callbacks.msgbox(prompt, type, title);
|
||||
+
|
||||
+ return 1; /* IDOK/vbOK - no host callback registered, so just proceed */
|
||||
+}
|
||||
+
|
||||
const char* libwinevbs_hresult_name(HRESULT hr)
|
||||
{
|
||||
switch (hr) {
|
||||
diff --git a/wine/dlls/vbscript/global.c b/wine/dlls/vbscript/global.c
|
||||
index 0e0e144..351f967 100644
|
||||
--- a/wine/dlls/vbscript/global.c
|
||||
+++ b/wine/dlls/vbscript/global.c
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <locale.h>
|
||||
#include "scrrun_private.h"
|
||||
HRESULT libwinevbs_create_object(const WCHAR *progid, IClassFactory* cf, IUnknown** obj);
|
||||
+int libwinevbs_msgbox(const char *prompt, int type, const char *title);
|
||||
extern HRESULT WINAPI WshShellFactory_CreateInstance(IClassFactory*,IUnknown*,REFIID,void**);
|
||||
#endif
|
||||
|
||||
@@ -2834,9 +2835,12 @@ static HRESULT Global_MsgBox(BuiltinDisp *This, VARIANT *args, unsigned args_cnt
|
||||
hres = show_msgbox(This->ctx, prompt, type, title, res);
|
||||
#else
|
||||
if(SUCCEEDED(hres)) {
|
||||
- char buf[2048];
|
||||
+ char buf[2048], title_buf[256] = {0};
|
||||
WideCharToMultiByte(CP_ACP, 0, prompt, -1, buf, sizeof(buf) - 1, NULL, NULL);
|
||||
+ if (title)
|
||||
+ WideCharToMultiByte(CP_ACP, 0, title, -1, title_buf, sizeof(title_buf) - 1, NULL, NULL);
|
||||
libwinevbs_log(LIBWINEVBS_LOG_INFO, "vbscript: MsgBox prompt=%s", buf);
|
||||
+ hres = return_short(res, libwinevbs_msgbox(buf, type, title ? title_buf : NULL));
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user