# HG changeset patch # User bsmith@81767d24-ef19-dc11-ae90-00e081727c95 # Date 1679868610 0 # Node ID 0058ab32e1bd663a0435e7635b6627412700904c # Parent 7e273fec75ae1a0ac6a5cb835bb25368319aeabc Win: Support for dw_html_javascript_add() and DW_SIGNAL_HTML_MESSAGE. This only works with Microsoft Edge WebView2 currently. diff -r 7e273fec75ae -r 0058ab32e1bd win/dw.c --- a/win/dw.c Sat Mar 25 20:10:05 2023 +0000 +++ b/win/dw.c Sun Mar 26 22:10:10 2023 +0000 @@ -392,9 +392,7 @@ static int in_checkbox_handler = 0; /* List of signals and their equivalent Win32 message */ -#define SIGNALMAX 19 - -DWSignalList DWSignalTranslate[SIGNALMAX] = { +DWSignalList DWSignalTranslate[] = { { WM_SIZE, DW_SIGNAL_CONFIGURE }, { WM_CHAR, DW_SIGNAL_KEY_PRESS }, { WM_LBUTTONDOWN, DW_SIGNAL_BUTTON_PRESS }, @@ -413,7 +411,9 @@ { LVN_COLUMNCLICK, DW_SIGNAL_COLUMN_CLICK }, { TVN_ITEMEXPANDED,DW_SIGNAL_TREE_EXPAND }, { WM_USER+100, DW_SIGNAL_HTML_RESULT }, - { WM_USER+101, DW_SIGNAL_HTML_CHANGED } + { WM_USER+101, DW_SIGNAL_HTML_CHANGED }, + { WM_USER+103, DW_SIGNAL_HTML_MESSAGE }, + { 0, "" } }; #ifdef BUILD_DLL @@ -1133,12 +1133,13 @@ /* Finds the message number for a given signal name */ ULONG _dw_findsigmessage(const char *signame) { - int z; - - for(z=0;zwindow) + { + int (DWSIGNAL *htmlmessagefunc)(HWND, char *, char *, void *) = tmp->signalfunction; + + return htmlmessagefunc(tmp->window, (char *)mp1, (char *)mp2, tmp->data); + } + } + break; } } if(tmp) @@ -6301,6 +6312,7 @@ int _dw_edge_raw(HWND hwnd, const char *string); int _dw_edge_url(HWND hwnd, const char *url); int _dw_edge_javascript_run(HWND hwnd, const char *script, void *scriptdata); +int _dw_edge_javascript_add(HWND hwnd, const char *name); #endif #endif @@ -6390,6 +6402,26 @@ } /* + * Install a javascript function with name that can call native code. + * Parameters: + * handle: Handle to the HTML window. + * name: Javascript function name. + * Notes: A DW_SIGNAL_HTML_MESSAGE event will be raised with scriptdata. + * Returns: + * DW_ERROR_NONE (0) on success. + */ +int API dw_html_javascript_add(HWND handle, const char *name) +{ +#ifdef BUILD_HTML +#ifdef BUILD_EDGE + if (_DW_EDGE_DETECTED) + return _dw_edge_javascript_add(handle, name); +#endif +#endif + return DW_ERROR_UNKNOWN; +} + +/* * Create a bitmap object to be packed. * Parameters: * id: An ID to be used with dw_window_from_id or 0L. @@ -13937,6 +13969,10 @@ case DW_FEATURE_TREE: case DW_FEATURE_WINDOW_PLACEMENT: return DW_FEATURE_ENABLED; +#if defined(BUILD_HTML) && defined(BUILD_EDGE) + case DW_FEATURE_HTML_MESSAGE: + return _DW_EDGE_DETECTED ? DW_FEATURE_ENABLED : DW_FEATURE_UNSUPPORTED; +#endif #ifdef BUILD_TOAST case DW_FEATURE_NOTIFICATION: { @@ -14023,6 +14059,10 @@ case DW_FEATURE_TREE: case DW_FEATURE_WINDOW_PLACEMENT: return DW_ERROR_GENERAL; +#if defined(BUILD_HTML) && defined(BUILD_EDGE) + case DW_FEATURE_HTML_MESSAGE: + return _DW_EDGE_DETECTED ? DW_ERROR_GENERAL : DW_FEATURE_UNSUPPORTED; +#endif #ifdef BUILD_TOAST case DW_FEATURE_NOTIFICATION: { diff -r 7e273fec75ae -r 0058ab32e1bd win/dw.def --- a/win/dw.def Sat Mar 25 20:10:05 2023 +0000 +++ b/win/dw.def Sun Mar 26 22:10:10 2023 +0000 @@ -311,6 +311,7 @@ dw_html_raw @472 dw_html_url @473 dw_html_javascript_run @474 + dw_html_javascript_add @475 dw_calendar_new @480 dw_calendar_set_date @481 diff -r 7e273fec75ae -r 0058ab32e1bd win/edge.cpp --- a/win/edge.cpp Sat Mar 25 20:10:05 2023 +0000 +++ b/win/edge.cpp Sun Mar 26 22:10:10 2023 +0000 @@ -9,12 +9,14 @@ #include "dw.h" #include "WebView2.h" #include +#include using namespace Microsoft::WRL; #define _DW_HTML_DATA_NAME "_dw_edge" #define _DW_HTML_DATA_LOCATION "_dw_edge_location" #define _DW_HTML_DATA_RAW "_dw_edge_raw" +#define _DW_HTML_DATA_ADD "_dw_edge_add" extern "C" { @@ -44,6 +46,7 @@ int Raw(const char* string); int URL(const char* url); int JavascriptRun(const char* script, void* scriptdata); + int JavascriptAdd(const char* name); VOID DoSize(VOID); VOID Setup(HWND hwnd, ICoreWebView2Controller* webview); VOID Close(VOID); @@ -166,6 +169,32 @@ return S_OK; }).Get(), &token); + + // Register a handler for the WebMessageReceived event. + webview->add_WebMessageReceived( + Callback( + [hWnd](ICoreWebView2* sender, + ICoreWebView2WebMessageReceivedEventArgs* args) -> HRESULT + { + LPWSTR message, name = NULL, body = NULL; + args->TryGetWebMessageAsString(&message); + + // Locate the DWindows|| signature and body + if(message && !wcsncmp(message, L"DWindows|", 9)) { + name = message + 9; + if(*name) { + body = wcschr(name, L'|'); + if(body) { + *body = 0; + body++; + } + } + } + if(name && body) + _dw_wndproc(hWnd, WM_USER + 103, (WPARAM)WideToUTF8(name), (LPARAM)WideToUTF8(body)); + + return S_OK; + }).Get(), &token); } // Resize WebView to fit the bounds of the parent window @@ -187,6 +216,21 @@ dw_window_set_data(hWnd, _DW_HTML_DATA_RAW, NULL); free((void*)raw); } + char *adds = (char *)dw_window_get_data(hWnd, _DW_HTML_DATA_ADD); + if(adds) + { + char *start = adds, *separator; + + while((separator = strchr(start, '|'))) + { + *separator = 0; + WebView->JavascriptAdd(start); + start = separator + 1; + } + WebView->JavascriptAdd(start); + dw_window_set_data(hWnd, _DW_HTML_DATA_ADD, NULL); + free((void *)adds); + } return S_OK; }).Get()); // Success @@ -366,6 +410,21 @@ return DW_ERROR_NONE; } +int EdgeWebView::JavascriptAdd(const char* name) +{ + if (WebView) { + std::wstring wname = std::wstring(UTF8toWide(name)); + std::wstring script = L"function " + wname + L"(body) {window.chrome.webview.postMessage('DWindows|" + wname + L"|' + body);}"; + WebView->AddScriptToExecuteOnDocumentCreated(script.c_str(), + Callback( + [this](HRESULT error, PCWSTR id) -> HRESULT { + return S_OK; + }).Get()); + return DW_ERROR_NONE; + } + return DW_ERROR_UNKNOWN; +} + VOID EdgeWebView::Setup(HWND hwnd, ICoreWebView2Controller* host) { hWnd = hwnd; @@ -506,8 +565,12 @@ EdgeWebView* webview = (EdgeWebView*)dw_window_get_data(hwnd, _DW_HTML_DATA_NAME); if (webview) return webview->Raw(string); - else + else { + char *oldstring = (char *)dw_window_get_data(hwnd, _DW_HTML_DATA_RAW); dw_window_set_data(hwnd, _DW_HTML_DATA_RAW, _strdup(string)); + if(oldstring) + free((void *)oldstring); + } return DW_ERROR_NONE; } @@ -525,8 +588,12 @@ EdgeWebView* webview = (EdgeWebView*)dw_window_get_data(hwnd, _DW_HTML_DATA_NAME); if (webview) return webview->URL(url); - else + else { + char *oldurl = (char *)dw_window_get_data(hwnd, _DW_HTML_DATA_LOCATION); dw_window_set_data(hwnd, _DW_HTML_DATA_LOCATION, _strdup(url)); + if(oldurl) + free((void *)oldurl); + } return DW_ERROR_NONE; } @@ -548,6 +615,38 @@ return DW_ERROR_UNKNOWN; } + /******************************* dw_edge_javascript_add() **************************** + * Adds a javascript function in the specified browser context. + * + * hwnd = Handle to the window hosting the browser object. + * name = Pointer to nul-terminated javascript function name string. + * + * RETURNS: 0 if success, or non-zero if an error. + */ + + int _dw_edge_javascript_add(HWND hwnd, const char* name) + { + if(name) { + EdgeWebView* webview = (EdgeWebView*)dw_window_get_data(hwnd, _DW_HTML_DATA_NAME); + if (webview) + return webview->JavascriptAdd(name); + else { + char *oldadd = (char *)dw_window_get_data(hwnd, _DW_HTML_DATA_ADD); + char *newadd = (char *)calloc(strlen(name) + (oldadd ? strlen(oldadd) : 0) + 2, 1); + if(oldadd) { + strcpy(newadd, oldadd); + strcat(newadd, "|"); + } + strcat(newadd, name); + dw_window_set_data(hwnd, _DW_HTML_DATA_ADD, newadd); + if(oldadd) + free((void *)oldadd); + return DW_ERROR_NONE; + } + } + return DW_ERROR_UNKNOWN; + } + /************************** edgeWindowProc() ************************* * Our message handler for our window to host the browser. */