From f4f337474cbc90fefb233df5a2710b340a0acd7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=81=8D=E5=85=AE=E6=83=9A=E5=85=AE?= <1173718158@qq.com> Date: Sun, 22 Dec 2024 01:02:46 +0800 Subject: [PATCH] . --- cpp/version.cmake | 2 +- cpp/winsharedutils/MWebBrowser.cpp | 230 +++++++++++++++++++++++--- cpp/winsharedutils/MWebBrowser.hpp | 73 +++++--- cpp/winsharedutils/SimpleBrowser.cpp | 8 + py/LunaTranslator/cishu/mdict.py | 19 ++- py/LunaTranslator/gui/usefulwidget.py | 14 ++ py/LunaTranslator/windows.py | 4 +- py/LunaTranslator/winsharedutils.py | 3 + 8 files changed, 298 insertions(+), 55 deletions(-) diff --git a/cpp/version.cmake b/cpp/version.cmake index 43fb4fbb..ea2a1a4f 100644 --- a/cpp/version.cmake +++ b/cpp/version.cmake @@ -1,7 +1,7 @@ set(VERSION_MAJOR 6) set(VERSION_MINOR 14) -set(VERSION_PATCH 7) +set(VERSION_PATCH 8) set(VERSION_REVISION 0) set(LUNA_VERSION "{${VERSION_MAJOR},${VERSION_MINOR},${VERSION_PATCH},${VERSION_REVISION}}") add_library(VERSION_DEF ${CMAKE_CURRENT_LIST_DIR}/version_def.cpp) diff --git a/cpp/winsharedutils/MWebBrowser.cpp b/cpp/winsharedutils/MWebBrowser.cpp index 21a60329..3f214fcb 100644 --- a/cpp/winsharedutils/MWebBrowser.cpp +++ b/cpp/winsharedutils/MWebBrowser.cpp @@ -16,6 +16,105 @@ MWebBrowser::Create(HWND hwndParent) } return pBrowser; } +void JSObject::bindfunction(const std::wstring &funcname, functiontype function) +{ + auto curr = DISPID_VALUE + 1 + funcnames.size(); + funcnames[funcname] = curr; + funcmap[curr] = function; +} +HRESULT STDMETHODCALLTYPE JSObject::QueryInterface(REFIID riid, void **ppv) +{ + *ppv = NULL; + + if (riid == IID_IUnknown || riid == IID_IDispatch) + { + *ppv = static_cast(this); + } + + if (*ppv != NULL) + { + AddRef(); + return S_OK; + } + + return E_NOINTERFACE; +} + +ULONG STDMETHODCALLTYPE JSObject::AddRef() +{ + return InterlockedIncrement(&ref); +} + +ULONG STDMETHODCALLTYPE JSObject::Release() +{ + int tmp = InterlockedDecrement(&ref); + + if (tmp == 0) + { + // OutputDebugString("JSObject::Release(): delete this"); + delete this; + } + + return tmp; +} + +HRESULT STDMETHODCALLTYPE JSObject::GetTypeInfoCount(UINT *pctinfo) +{ + *pctinfo = 0; + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE JSObject::GetTypeInfo(UINT iTInfo, LCID lcid, + ITypeInfo **ppTInfo) +{ + return E_FAIL; +} + +HRESULT STDMETHODCALLTYPE JSObject::GetIDsOfNames(REFIID riid, + LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) +{ + HRESULT hr = S_OK; + + for (UINT i = 0; i < cNames; i++) + { + auto iter = funcnames.find(rgszNames[i]); + if (iter != funcnames.end()) + { + rgDispId[i] = iter->second; + } + else + { + rgDispId[i] = DISPID_UNKNOWN; + hr = DISP_E_UNKNOWNNAME; + } + } + + return hr; +} + +// https://github.com/Tobbe/CppIEEmbed +HRESULT STDMETHODCALLTYPE JSObject::Invoke(DISPID dispIdMember, REFIID riid, + LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + if (wFlags & DISPATCH_METHOD) + { + HRESULT hr = S_OK; + std::vector args; + for (size_t i = 0; i < pDispParams->cArgs; ++i) + { + BSTR bstrArg = pDispParams->rgvarg[i].bstrVal; + args.push_back(bstrArg); + } + if (funcmap.find(dispIdMember) == funcmap.end()) + return DISP_E_MEMBERNOTFOUND; + funcmap[dispIdMember](args.data(), args.size()); + return S_OK; + } + + return E_FAIL; +} MWebBrowser::MWebBrowser(HWND hwndParent) : m_nRefCount(0), m_hwndParent(NULL), @@ -34,14 +133,16 @@ MWebBrowser::MWebBrowser(HWND hwndParent) : m_nRefCount(0), m_hr = CreateBrowser(hwndParent); htmlSource = L""; - IConnectionPointContainer* container = nullptr; - m_web_browser2->QueryInterface(IID_IConnectionPointContainer, (void**)&container); + IConnectionPointContainer *container = nullptr; + m_web_browser2->QueryInterface(IID_IConnectionPointContainer, (void **)&container); container->FindConnectionPoint(__uuidof(DWebBrowserEvents2), &callback); - IUnknown* punk = nullptr; - QueryInterface(IID_IUnknown, (void**)&punk); + IUnknown *punk = nullptr; + QueryInterface(IID_IUnknown, (void **)&punk); callback->Advise(punk, &eventCookie); punk->Release(); container->Release(); + jsobj = new JSObject(); + jsobj->AddRef(); } BOOL MWebBrowser::IsCreated() const @@ -71,6 +172,12 @@ MWebBrowser::~MWebBrowser() m_web_browser2->Release(); m_web_browser2 = NULL; } + if (jsobj) + { + jsobj->Release(); + delete jsobj; + jsobj = NULL; + } } IWebBrowser2 *MWebBrowser::GetIWebBrowser2() @@ -998,55 +1105,124 @@ HRESULT MWebBrowser::GetTypeInfoCount(UINT *pctinfo) { return E_FAIL; } HRESULT MWebBrowser::GetTypeInfo(UINT, LCID, ITypeInfo **) { return E_FAIL; } HRESULT MWebBrowser::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) { return E_FAIL; } +void AddCustomObject(IHTMLDocument2 *doc, IDispatch *custObj, std::string name) +{ + + if (doc == NULL) + { + return; + } + + IHTMLWindow2 *win = NULL; + doc->get_parentWindow(&win); + doc->Release(); + + if (win == NULL) + { + return; + } + + IDispatchEx *winEx; + win->QueryInterface(&winEx); + win->Release(); + + if (winEx == NULL) + { + return; + } + + int lenW = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name.c_str(), -1, NULL, 0); + BSTR objName = SysAllocStringLen(0, lenW); + MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name.c_str(), -1, objName, lenW); + + DISPID dispid; + HRESULT hr = winEx->GetDispID(objName, fdexNameEnsure, &dispid); + + SysFreeString(objName); + + if (FAILED(hr)) + { + return; + } + + DISPID namedArgs[] = {DISPID_PROPERTYPUT}; + DISPPARAMS params; + params.rgvarg = new VARIANT[1]; + params.rgvarg[0].pdispVal = custObj; + params.rgvarg[0].vt = VT_DISPATCH; + params.rgdispidNamedArgs = namedArgs; + params.cArgs = 1; + params.cNamedArgs = 1; + + hr = winEx->InvokeEx(dispid, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, ¶ms, NULL, NULL, NULL); + winEx->Release(); + + if (FAILED(hr)) + { + return; + } +} HRESULT MWebBrowser::Invoke(DISPID dispIdMember, REFIID, LCID, WORD, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *, UINT *) { if (dispIdMember == DISPID_DOCUMENTCOMPLETE) return OnCompleted(pDispParams); + else if (dispIdMember == DISPID_NAVIGATECOMPLETE2) + return AddCustomObject(GetIHTMLDocument2(), jsobj, "LUNAJSObject"), S_OK; else return S_OK; } -HRESULT MWebBrowser::OnCompleted(DISPPARAMS* args) { - HRESULT hr; +HRESULT MWebBrowser::OnCompleted(DISPPARAMS *args) +{ + HRESULT hr; - IDispatch *pDispatch = 0; - IHTMLDocument2 *pHtmlDoc2 = 0; - IPersistStreamInit *pPSI = 0; - IStream *pStream = 0; - HGLOBAL hHTMLContent; + IDispatch *pDispatch = 0; + IHTMLDocument2 *pHtmlDoc2 = 0; + IPersistStreamInit *pPSI = 0; + IStream *pStream = 0; + HGLOBAL hHTMLContent; - - if (htmlSource.empty()) return S_OK; + if (htmlSource.empty()) + return S_OK; hr = m_web_browser2->get_Document(&pDispatch); - if (SUCCEEDED(hr) && pDispatch) hr = pDispatch->QueryInterface(IID_IHTMLDocument2, (void **)&pHtmlDoc2); - if (SUCCEEDED(hr) && pHtmlDoc2) hr = pHtmlDoc2->QueryInterface(IID_IPersistStreamInit, (void **)&pPSI); - + if (SUCCEEDED(hr) && pDispatch) + hr = pDispatch->QueryInterface(IID_IHTMLDocument2, (void **)&pHtmlDoc2); + if (SUCCEEDED(hr) && pHtmlDoc2) + hr = pHtmlDoc2->QueryInterface(IID_IPersistStreamInit, (void **)&pPSI); // allocate global memory to copy the HTML content to hHTMLContent = ::GlobalAlloc(GMEM_MOVEABLE, (htmlSource.size() + 1) * sizeof(TCHAR)); if (hHTMLContent) { - wchar_t * p_content(static_cast(GlobalLock(hHTMLContent))); + wchar_t *p_content(static_cast(GlobalLock(hHTMLContent))); ::wcscpy(p_content, htmlSource.c_str()); GlobalUnlock(hHTMLContent); // create a stream object based on the HTML content - if (SUCCEEDED(hr) && pPSI) hr = ::CreateStreamOnHGlobal(hHTMLContent, TRUE, &pStream); + if (SUCCEEDED(hr) && pPSI) + hr = ::CreateStreamOnHGlobal(hHTMLContent, TRUE, &pStream); - if (SUCCEEDED(hr) && pStream) hr = pPSI->InitNew(); - if (SUCCEEDED(hr)) hr = pPSI->Load(pStream); + if (SUCCEEDED(hr) && pStream) + hr = pPSI->InitNew(); + if (SUCCEEDED(hr)) + hr = pPSI->Load(pStream); } - if (pStream) pStream->Release(); - if (pPSI) pPSI->Release(); - if (pHtmlDoc2) pHtmlDoc2->Release(); - if (pDispatch) pDispatch->Release(); - htmlSource=L""; + if (pStream) + pStream->Release(); + if (pPSI) + pPSI->Release(); + if (pHtmlDoc2) + pHtmlDoc2->Release(); + if (pDispatch) + pDispatch->Release(); + htmlSource = L""; return S_OK; } -HRESULT MWebBrowser::SetHtml(const wchar_t* html){ - htmlSource=html; +HRESULT MWebBrowser::SetHtml(const wchar_t *html) +{ + htmlSource = html; Navigate(L"about:blank"); return S_OK; } diff --git a/cpp/winsharedutils/MWebBrowser.hpp b/cpp/winsharedutils/MWebBrowser.hpp index 11a84976..3eea299f 100644 --- a/cpp/winsharedutils/MWebBrowser.hpp +++ b/cpp/winsharedutils/MWebBrowser.hpp @@ -3,38 +3,65 @@ // This file is public domain software. #ifndef MWEB_BROWSER_HPP_ -#define MWEB_BROWSER_HPP_ 13 // Version 13 +#define MWEB_BROWSER_HPP_ 13 // Version 13 #define INITGUID -class MWebBrowser : - public IDispatch, - public IOleClientSite, - public IOleInPlaceSite, - public IStorage, - public IServiceProvider, - public IHttpSecurity, - public IDocHostUIHandler +class JSObject : public IDispatch { +private: + typedef std::function functiontype; + std::map funcmap; + std::map funcnames; + long ref = 0; + public: + void bindfunction(const std::wstring &, functiontype); + + // IUnknown + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppv); + virtual ULONG STDMETHODCALLTYPE AddRef(); + virtual ULONG STDMETHODCALLTYPE Release(); + + // IDispatch + virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT *pctinfo); + virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo, LCID lcid, + ITypeInfo **ppTInfo); + virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid, + LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId); + virtual HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid, + LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, UINT *puArgErr); +}; + +class MWebBrowser : public IDispatch, + public IOleClientSite, + public IOleInPlaceSite, + public IStorage, + public IServiceProvider, + public IHttpSecurity, + public IDocHostUIHandler +{ + +public: + JSObject *jsobj; static MWebBrowser *Create(HWND hwndParent); - HRESULT OnCompleted(DISPPARAMS* args); - + HRESULT OnCompleted(DISPPARAMS *args); + // ---------- IDispatch ---------- virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(__RPC__out UINT *pctinfo) override; virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT, LCID, __RPC__deref_out_opt ITypeInfo **) override; virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(__RPC__in REFIID riid, __RPC__in_ecount_full(cNames) LPOLESTR *rgszNames, __RPC__in_range(0, 16384) UINT cNames, LCID lcid, __RPC__out_ecount_full(cNames) DISPID *rgDispId) override; - virtual HRESULT STDMETHODCALLTYPE Invoke(_In_ DISPID dispIdMember, _In_ REFIID, _In_ LCID, _In_ WORD, _In_ DISPPARAMS *pDispParams, _Out_opt_ VARIANT *pVarResult, _Out_opt_ EXCEPINFO*, _Out_opt_ UINT*) override; - + virtual HRESULT STDMETHODCALLTYPE Invoke(_In_ DISPID dispIdMember, _In_ REFIID, _In_ LCID, _In_ WORD, _In_ DISPPARAMS *pDispParams, _Out_opt_ VARIANT *pVarResult, _Out_opt_ EXCEPINFO *, _Out_opt_ UINT *) override; std::wstring htmlSource; - IConnectionPoint* callback; + IConnectionPoint *callback; DWORD eventCookie; - RECT PixelToHIMETRIC(const RECT& rc); + RECT PixelToHIMETRIC(const RECT &rc); HWND GetControlWindow(); HWND GetIEServerWindow(); - void MoveWindow(const RECT& rc); + void MoveWindow(const RECT &rc); void GoHome(); void GoBack(); @@ -44,7 +71,7 @@ public: void Refresh(); HRESULT Navigate(const WCHAR *url = L"about:blank"); HRESULT Navigate2(const WCHAR *url, DWORD dwFlags = 0); - HRESULT SetHtml(const wchar_t* html); + HRESULT SetHtml(const wchar_t *html); void Print(BOOL bBang = FALSE); void PrintPreview(); void PageSetup(); @@ -67,8 +94,10 @@ public: // IUnknown interface STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj); - STDMETHODIMP_(ULONG) AddRef(); - STDMETHODIMP_(ULONG) Release(); + STDMETHODIMP_(ULONG) + AddRef(); + STDMETHODIMP_(ULONG) + Release(); // IOleWindow interface STDMETHODIMP GetWindow(HWND *phwnd); @@ -228,8 +257,8 @@ protected: BOOL IsCreated() const; private: - MWebBrowser(const MWebBrowser&); - MWebBrowser& operator=(const MWebBrowser&); + MWebBrowser(const MWebBrowser &); + MWebBrowser &operator=(const MWebBrowser &); }; -#endif // ndef MWEB_BROWSER_HPP_ +#endif // ndef MWEB_BROWSER_HPP_ diff --git a/cpp/winsharedutils/SimpleBrowser.cpp b/cpp/winsharedutils/SimpleBrowser.cpp index 99327b3c..41ebb936 100644 --- a/cpp/winsharedutils/SimpleBrowser.cpp +++ b/cpp/winsharedutils/SimpleBrowser.cpp @@ -281,3 +281,11 @@ DECLARE_API const wchar_t *html_get_select_text(void *web) } return L""; } + +DECLARE_API void html_bind_function(void *web, const wchar_t *name, void (*function)(wchar_t **, int)) +{ + if (!web) + return; + auto ww = static_cast(web); + ww->jsobj->bindfunction(name, function); +} diff --git a/py/LunaTranslator/cishu/mdict.py b/py/LunaTranslator/cishu/mdict.py index 2eff414a..86e6f3c5 100644 --- a/py/LunaTranslator/cishu/mdict.py +++ b/py/LunaTranslator/cishu/mdict.py @@ -2307,7 +2307,9 @@ class mdict(cishubase): func = url.split(r"://")[0] if func == "entry": - return 3, "javascript:(function(){{if(mdict_entry_call)mdict_entry_call(`{}`)}})()".format(url.split(r"://")[1]) + return 3, "javascript:safe_mdict_entry_call('{w}')".format( + w=url.split(r"://")[1] + ) url1 = url.split(r"://")[1] url1 = url1.replace("/", "\\") @@ -2643,10 +2645,21 @@ if (content.style.display === 'block') { if len(allres) == 0: return allres.sort(key=lambda _: -_[0]) + func = """ +""" if self.config["stylehv"] == 0: - return self.generatehtml_tabswitch(allres) + return self.generatehtml_tabswitch(allres) + func elif self.config["stylehv"] == 1: - return self.generatehtml_flow(allres) + return self.generatehtml_flow(allres) + func def tree(self): if len(self.builders) == 0: diff --git a/py/LunaTranslator/gui/usefulwidget.py b/py/LunaTranslator/gui/usefulwidget.py index d869f107..20db21b0 100644 --- a/py/LunaTranslator/gui/usefulwidget.py +++ b/py/LunaTranslator/gui/usefulwidget.py @@ -1458,6 +1458,19 @@ class QWebWrap(abstractwebview): class mshtmlWidget(abstractwebview): CommandBase = 10086 + def bindhelper(self, func, ppwc, argc): + argv = [] + for i in range(argc): + argv.append(ppwc[argc - 1 - i]) + func(*argv) + + def bind(self, fname, func): + __f = winsharedutils.html_bind_function_FT( + functools.partial(self.bindhelper, func) + ) + self.bindfs.append(__f) + winsharedutils.html_bind_function(self.browser, fname, __f) + def __del__(self): if not self.browser: return @@ -1466,6 +1479,7 @@ class mshtmlWidget(abstractwebview): def __init__(self, parent=None) -> None: super().__init__(parent) self.callbacks = {} + self.bindfs = [] iswine = checkisusingwine() if iswine or (winsharedutils.html_version() < 10001): # ie10之前,sethtml会乱码 self.html_limit = 0 diff --git a/py/LunaTranslator/windows.py b/py/LunaTranslator/windows.py index a18b7191..5bfd9e1b 100644 --- a/py/LunaTranslator/windows.py +++ b/py/LunaTranslator/windows.py @@ -860,7 +860,7 @@ IsZoomed = _user32.IsZoomed IsZoomed.argtypes = (HWND,) IsZoomed.restype = BOOL -WNDPROCTYPE = CFUNCTYPE(INT, HWND, INT, WPARAM, LPARAM) +WNDPROCTYPE = WINFUNCTYPE(INT, HWND, INT, WPARAM, LPARAM) GWLP_WNDPROC = -4 if sizeof(c_void_p) == 8: @@ -920,7 +920,7 @@ def MonitorFromWindow(hwnd, dwFlags=MONITOR_DEFAULTTONEAREST): return _MonitorFromWindow(hwnd, dwFlags) -WINEVENTPROC = CFUNCTYPE( +WINEVENTPROC = WINFUNCTYPE( None, HANDLE, DWORD, diff --git a/py/LunaTranslator/winsharedutils.py b/py/LunaTranslator/winsharedutils.py index 2cf18531..0f8a5b59 100644 --- a/py/LunaTranslator/winsharedutils.py +++ b/py/LunaTranslator/winsharedutils.py @@ -136,6 +136,9 @@ html_add_menu.argtypes = (c_void_p, c_int, c_int, c_wchar_p) html_get_select_text = utilsdll.html_get_select_text html_get_select_text.argtypes = (c_void_p,) html_get_select_text.restype = c_wchar_p +html_bind_function_FT = CFUNCTYPE(None, POINTER(c_wchar_p), c_int) +html_bind_function = utilsdll.html_bind_function +html_bind_function.argtypes = c_void_p, c_wchar_p, html_bind_function_FT _GetLnkTargetPath = utilsdll.GetLnkTargetPath