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_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)

View File

@ -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<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),
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, &params, 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<wchar_t *>(GlobalLock(hHTMLContent)));
wchar_t *p_content(static_cast<wchar_t *>(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;
}

View File

@ -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<void(wchar_t **, int)> functiontype;
std::map<DISPID, functiontype> funcmap;
std::map<std::wstring, DISPID> 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_

View File

@ -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<MWebBrowserEx *>(web);
ww->jsobj->bindfunction(name, function);
}

View File

@ -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 = """
<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:
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:

View File

@ -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

View File

@ -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,

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.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