This commit is contained in:
恍兮惚兮 2024-12-22 01:02:46 +08:00
parent 566ec24b7b
commit f4f337474c
8 changed files with 298 additions and 55 deletions

View File

@ -1,7 +1,7 @@
set(VERSION_MAJOR 6) set(VERSION_MAJOR 6)
set(VERSION_MINOR 14) set(VERSION_MINOR 14)
set(VERSION_PATCH 7) set(VERSION_PATCH 8)
set(VERSION_REVISION 0) set(VERSION_REVISION 0)
set(LUNA_VERSION "{${VERSION_MAJOR},${VERSION_MINOR},${VERSION_PATCH},${VERSION_REVISION}}") set(LUNA_VERSION "{${VERSION_MAJOR},${VERSION_MINOR},${VERSION_PATCH},${VERSION_REVISION}}")
add_library(VERSION_DEF ${CMAKE_CURRENT_LIST_DIR}/version_def.cpp) add_library(VERSION_DEF ${CMAKE_CURRENT_LIST_DIR}/version_def.cpp)

View File

@ -16,6 +16,105 @@ MWebBrowser::Create(HWND hwndParent)
} }
return pBrowser; 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<IDispatch *>(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<BSTR> 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), MWebBrowser::MWebBrowser(HWND hwndParent) : m_nRefCount(0),
m_hwndParent(NULL), m_hwndParent(NULL),
@ -34,14 +133,16 @@ MWebBrowser::MWebBrowser(HWND hwndParent) : m_nRefCount(0),
m_hr = CreateBrowser(hwndParent); m_hr = CreateBrowser(hwndParent);
htmlSource = L""; htmlSource = L"";
IConnectionPointContainer* container = nullptr; IConnectionPointContainer *container = nullptr;
m_web_browser2->QueryInterface(IID_IConnectionPointContainer, (void**)&container); m_web_browser2->QueryInterface(IID_IConnectionPointContainer, (void **)&container);
container->FindConnectionPoint(__uuidof(DWebBrowserEvents2), &callback); container->FindConnectionPoint(__uuidof(DWebBrowserEvents2), &callback);
IUnknown* punk = nullptr; IUnknown *punk = nullptr;
QueryInterface(IID_IUnknown, (void**)&punk); QueryInterface(IID_IUnknown, (void **)&punk);
callback->Advise(punk, &eventCookie); callback->Advise(punk, &eventCookie);
punk->Release(); punk->Release();
container->Release(); container->Release();
jsobj = new JSObject();
jsobj->AddRef();
} }
BOOL MWebBrowser::IsCreated() const BOOL MWebBrowser::IsCreated() const
@ -71,6 +172,12 @@ MWebBrowser::~MWebBrowser()
m_web_browser2->Release(); m_web_browser2->Release();
m_web_browser2 = NULL; m_web_browser2 = NULL;
} }
if (jsobj)
{
jsobj->Release();
delete jsobj;
jsobj = NULL;
}
} }
IWebBrowser2 *MWebBrowser::GetIWebBrowser2() 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::GetTypeInfo(UINT, LCID, ITypeInfo **) { return E_FAIL; }
HRESULT MWebBrowser::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) { 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, &params, NULL, NULL, NULL);
winEx->Release();
if (FAILED(hr))
{
return;
}
}
HRESULT MWebBrowser::Invoke(DISPID dispIdMember, REFIID, LCID, WORD, HRESULT MWebBrowser::Invoke(DISPID dispIdMember, REFIID, LCID, WORD,
DISPPARAMS *pDispParams, VARIANT *pVarResult, DISPPARAMS *pDispParams, VARIANT *pVarResult,
EXCEPINFO *, UINT *) EXCEPINFO *, UINT *)
{ {
if (dispIdMember == DISPID_DOCUMENTCOMPLETE) if (dispIdMember == DISPID_DOCUMENTCOMPLETE)
return OnCompleted(pDispParams); return OnCompleted(pDispParams);
else if (dispIdMember == DISPID_NAVIGATECOMPLETE2)
return AddCustomObject(GetIHTMLDocument2(), jsobj, "LUNAJSObject"), S_OK;
else else
return S_OK; return S_OK;
} }
HRESULT MWebBrowser::OnCompleted(DISPPARAMS* args) { HRESULT MWebBrowser::OnCompleted(DISPPARAMS *args)
HRESULT hr; {
HRESULT hr;
IDispatch *pDispatch = 0; IDispatch *pDispatch = 0;
IHTMLDocument2 *pHtmlDoc2 = 0; IHTMLDocument2 *pHtmlDoc2 = 0;
IPersistStreamInit *pPSI = 0; IPersistStreamInit *pPSI = 0;
IStream *pStream = 0; IStream *pStream = 0;
HGLOBAL hHTMLContent; HGLOBAL hHTMLContent;
if (htmlSource.empty())
if (htmlSource.empty()) return S_OK; return S_OK;
hr = m_web_browser2->get_Document(&pDispatch); hr = m_web_browser2->get_Document(&pDispatch);
if (SUCCEEDED(hr) && pDispatch) hr = pDispatch->QueryInterface(IID_IHTMLDocument2, (void **)&pHtmlDoc2); if (SUCCEEDED(hr) && pDispatch)
if (SUCCEEDED(hr) && pHtmlDoc2) hr = pHtmlDoc2->QueryInterface(IID_IPersistStreamInit, (void **)&pPSI); 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 // allocate global memory to copy the HTML content to
hHTMLContent = ::GlobalAlloc(GMEM_MOVEABLE, (htmlSource.size() + 1) * sizeof(TCHAR)); hHTMLContent = ::GlobalAlloc(GMEM_MOVEABLE, (htmlSource.size() + 1) * sizeof(TCHAR));
if (hHTMLContent) if (hHTMLContent)
{ {
wchar_t * p_content(static_cast<wchar_t *>(GlobalLock(hHTMLContent))); wchar_t *p_content(static_cast<wchar_t *>(GlobalLock(hHTMLContent)));
::wcscpy(p_content, htmlSource.c_str()); ::wcscpy(p_content, htmlSource.c_str());
GlobalUnlock(hHTMLContent); GlobalUnlock(hHTMLContent);
// create a stream object based on the HTML content // 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) && pStream)
if (SUCCEEDED(hr)) hr = pPSI->Load(pStream); hr = pPSI->InitNew();
if (SUCCEEDED(hr))
hr = pPSI->Load(pStream);
} }
if (pStream) pStream->Release(); if (pStream)
if (pPSI) pPSI->Release(); pStream->Release();
if (pHtmlDoc2) pHtmlDoc2->Release(); if (pPSI)
if (pDispatch) pDispatch->Release(); pPSI->Release();
htmlSource=L""; if (pHtmlDoc2)
pHtmlDoc2->Release();
if (pDispatch)
pDispatch->Release();
htmlSource = L"";
return S_OK; return S_OK;
} }
HRESULT MWebBrowser::SetHtml(const wchar_t* html){ HRESULT MWebBrowser::SetHtml(const wchar_t *html)
htmlSource=html; {
htmlSource = html;
Navigate(L"about:blank"); Navigate(L"about:blank");
return S_OK; return S_OK;
} }

View File

@ -3,38 +3,65 @@
// This file is public domain software. // This file is public domain software.
#ifndef MWEB_BROWSER_HPP_ #ifndef MWEB_BROWSER_HPP_
#define MWEB_BROWSER_HPP_ 13 // Version 13 #define MWEB_BROWSER_HPP_ 13 // Version 13
#define INITGUID #define INITGUID
class MWebBrowser : class JSObject : public IDispatch
public IDispatch,
public IOleClientSite,
public IOleInPlaceSite,
public IStorage,
public IServiceProvider,
public IHttpSecurity,
public IDocHostUIHandler
{ {
private:
typedef std::function<void(wchar_t **, int)> functiontype;
std::map<DISPID, functiontype> funcmap;
std::map<std::wstring, DISPID> funcnames;
long ref = 0;
public: 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); static MWebBrowser *Create(HWND hwndParent);
HRESULT OnCompleted(DISPPARAMS* args); HRESULT OnCompleted(DISPPARAMS *args);
// ---------- IDispatch ---------- // ---------- IDispatch ----------
virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(__RPC__out UINT *pctinfo) override; virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(__RPC__out UINT *pctinfo) override;
virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT, LCID, __RPC__deref_out_opt ITypeInfo **) 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 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; std::wstring htmlSource;
IConnectionPoint* callback; IConnectionPoint *callback;
DWORD eventCookie; DWORD eventCookie;
RECT PixelToHIMETRIC(const RECT& rc); RECT PixelToHIMETRIC(const RECT &rc);
HWND GetControlWindow(); HWND GetControlWindow();
HWND GetIEServerWindow(); HWND GetIEServerWindow();
void MoveWindow(const RECT& rc); void MoveWindow(const RECT &rc);
void GoHome(); void GoHome();
void GoBack(); void GoBack();
@ -44,7 +71,7 @@ public:
void Refresh(); void Refresh();
HRESULT Navigate(const WCHAR *url = L"about:blank"); HRESULT Navigate(const WCHAR *url = L"about:blank");
HRESULT Navigate2(const WCHAR *url, DWORD dwFlags = 0); 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 Print(BOOL bBang = FALSE);
void PrintPreview(); void PrintPreview();
void PageSetup(); void PageSetup();
@ -67,8 +94,10 @@ public:
// IUnknown interface // IUnknown interface
STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj); STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj);
STDMETHODIMP_(ULONG) AddRef(); STDMETHODIMP_(ULONG)
STDMETHODIMP_(ULONG) Release(); AddRef();
STDMETHODIMP_(ULONG)
Release();
// IOleWindow interface // IOleWindow interface
STDMETHODIMP GetWindow(HWND *phwnd); STDMETHODIMP GetWindow(HWND *phwnd);
@ -228,8 +257,8 @@ protected:
BOOL IsCreated() const; BOOL IsCreated() const;
private: private:
MWebBrowser(const MWebBrowser&); MWebBrowser(const MWebBrowser &);
MWebBrowser& operator=(const MWebBrowser&); MWebBrowser &operator=(const MWebBrowser &);
}; };
#endif // ndef MWEB_BROWSER_HPP_ #endif // ndef MWEB_BROWSER_HPP_

View File

@ -281,3 +281,11 @@ DECLARE_API const wchar_t *html_get_select_text(void *web)
} }
return L""; 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<MWebBrowserEx *>(web);
ww->jsobj->bindfunction(name, function);
}

View File

@ -2307,7 +2307,9 @@ class mdict(cishubase):
func = url.split(r"://")[0] func = url.split(r"://")[0]
if func == "entry": 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 = url.split(r"://")[1]
url1 = url1.replace("/", "\\") url1 = url1.replace("/", "\\")
@ -2643,10 +2645,21 @@ if (content.style.display === 'block') {
if len(allres) == 0: if len(allres) == 0:
return return
allres.sort(key=lambda _: -_[0]) allres.sort(key=lambda _: -_[0])
func = """
<script>
function safe_mdict_entry_call(word){
if(window.mdict_entry_call)
window.mdict_entry_call(word)
else if(window.LUNAJSObject)
{
if(window.LUNAJSObject.mdict_entry_call)
window.LUNAJSObject.mdict_entry_call(word)
}
}</script>"""
if self.config["stylehv"] == 0: if self.config["stylehv"] == 0:
return self.generatehtml_tabswitch(allres) return self.generatehtml_tabswitch(allres) + func
elif self.config["stylehv"] == 1: elif self.config["stylehv"] == 1:
return self.generatehtml_flow(allres) return self.generatehtml_flow(allres) + func
def tree(self): def tree(self):
if len(self.builders) == 0: if len(self.builders) == 0:

View File

@ -1458,6 +1458,19 @@ class QWebWrap(abstractwebview):
class mshtmlWidget(abstractwebview): class mshtmlWidget(abstractwebview):
CommandBase = 10086 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): def __del__(self):
if not self.browser: if not self.browser:
return return
@ -1466,6 +1479,7 @@ class mshtmlWidget(abstractwebview):
def __init__(self, parent=None) -> None: def __init__(self, parent=None) -> None:
super().__init__(parent) super().__init__(parent)
self.callbacks = {} self.callbacks = {}
self.bindfs = []
iswine = checkisusingwine() iswine = checkisusingwine()
if iswine or (winsharedutils.html_version() < 10001): # ie10之前sethtml会乱码 if iswine or (winsharedutils.html_version() < 10001): # ie10之前sethtml会乱码
self.html_limit = 0 self.html_limit = 0

View File

@ -860,7 +860,7 @@ IsZoomed = _user32.IsZoomed
IsZoomed.argtypes = (HWND,) IsZoomed.argtypes = (HWND,)
IsZoomed.restype = BOOL IsZoomed.restype = BOOL
WNDPROCTYPE = CFUNCTYPE(INT, HWND, INT, WPARAM, LPARAM) WNDPROCTYPE = WINFUNCTYPE(INT, HWND, INT, WPARAM, LPARAM)
GWLP_WNDPROC = -4 GWLP_WNDPROC = -4
if sizeof(c_void_p) == 8: if sizeof(c_void_p) == 8:
@ -920,7 +920,7 @@ def MonitorFromWindow(hwnd, dwFlags=MONITOR_DEFAULTTONEAREST):
return _MonitorFromWindow(hwnd, dwFlags) return _MonitorFromWindow(hwnd, dwFlags)
WINEVENTPROC = CFUNCTYPE( WINEVENTPROC = WINFUNCTYPE(
None, None,
HANDLE, HANDLE,
DWORD, DWORD,

View File

@ -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 = utilsdll.html_get_select_text
html_get_select_text.argtypes = (c_void_p,) html_get_select_text.argtypes = (c_void_p,)
html_get_select_text.restype = c_wchar_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 _GetLnkTargetPath = utilsdll.GetLnkTargetPath