diff --git a/src/launcher/html/doc_host_ui_handler.cpp b/src/launcher/html/doc_host_ui_handler.cpp new file mode 100644 index 0000000..ceab8d9 --- /dev/null +++ b/src/launcher/html/doc_host_ui_handler.cpp @@ -0,0 +1,115 @@ +#include +#include "../html_frame.hpp" + +doc_host_ui_handler::doc_host_ui_handler(html_frame* frame): frame_(frame) +{ +} + +HRESULT doc_host_ui_handler::QueryInterface(REFIID riid, LPVOID* ppvObj) +{ + auto client_site = this->frame_->get_client_site(); + if (client_site) + { + return client_site->QueryInterface(riid, ppvObj); + } + + return E_NOINTERFACE; +} + +ULONG doc_host_ui_handler::AddRef() +{ + return 1; +} + +ULONG doc_host_ui_handler::Release() +{ + return 1; +} + +HRESULT doc_host_ui_handler::ShowContextMenu(DWORD /*dwID*/, POINT* /*ppt*/, IUnknown* /*pcmdtReserved*/, + IDispatch* /*pdispReserved*/) +{ + return S_OK; +} + +HRESULT doc_host_ui_handler::ShowUI(DWORD /*dwID*/, IOleInPlaceActiveObject* /*pActiveObject*/, + IOleCommandTarget* /*pCommandTarget*/, + IOleInPlaceFrame* /*pFrame*/, IOleInPlaceUIWindow* /*pDoc*/) +{ + return S_OK; +} + +HRESULT doc_host_ui_handler::HideUI() +{ + return S_OK; +} + +HRESULT doc_host_ui_handler::UpdateUI() +{ + return S_OK; +} + +HRESULT doc_host_ui_handler::EnableModeless(BOOL /*fEnable*/) +{ + return S_OK; +} + +HRESULT doc_host_ui_handler::OnDocWindowActivate(BOOL /*fActivate*/) +{ + return S_OK; +} + +HRESULT doc_host_ui_handler::OnFrameWindowActivate(BOOL /*fActivate*/) +{ + return S_OK; +} + +HRESULT doc_host_ui_handler::ResizeBorder(LPCRECT /*prcBorder*/, IOleInPlaceUIWindow* /*pUIWindow*/, + BOOL /*fRameWindow*/) +{ + return S_OK; +} + +HRESULT doc_host_ui_handler::TranslateAcceleratorA(LPMSG /*lpMsg*/, const GUID* pguidCmdGroup, DWORD /*nCmdID*/) +{ + pguidCmdGroup = nullptr; + return S_FALSE; +} + +HRESULT doc_host_ui_handler::GetOptionKeyPath(LPOLESTR* /*pchKey*/, DWORD /*dw*/) +{ + return S_FALSE; +} + +HRESULT doc_host_ui_handler::GetDropTarget(IDropTarget* /*pDropTarget*/, IDropTarget** /*ppDropTarget*/) +{ + return S_FALSE; +} + +HRESULT doc_host_ui_handler::GetExternal(IDispatch** ppDispatch) +{ + *ppDispatch = nullptr; + return S_FALSE; +} + +HRESULT doc_host_ui_handler::FilterDataObject(IDataObject* /*pDO*/, IDataObject** ppDORet) +{ + *ppDORet = nullptr; + return S_FALSE; +} + +HRESULT STDMETHODCALLTYPE doc_host_ui_handler::TranslateUrl(DWORD /*dwTranslate*/, OLECHAR __RPC_FAR* /*pchURLIn*/, + OLECHAR __RPC_FAR* __RPC_FAR* ppchURLOut) +{ + *ppchURLOut = nullptr; + return S_FALSE; +} + +HRESULT doc_host_ui_handler::GetHostInfo(DOCHOSTUIINFO __RPC_FAR * pInfo) +{ + pInfo->cbSize = sizeof(DOCHOSTUIINFO); + pInfo->dwFlags = DOCHOSTUIFLAG_NO3DBORDER | DOCHOSTUIFLAG_DPI_AWARE | DOCHOSTUIFLAG_SCROLL_NO; + pInfo->dwDoubleClick = DOCHOSTUIDBLCLK_DEFAULT; + + return S_OK; +} diff --git a/src/launcher/html/doc_host_ui_handler.hpp b/src/launcher/html/doc_host_ui_handler.hpp new file mode 100644 index 0000000..0b538b4 --- /dev/null +++ b/src/launcher/html/doc_host_ui_handler.hpp @@ -0,0 +1,47 @@ +#pragma once + +class html_frame; + +class doc_host_ui_handler final : public IDocHostUIHandler +{ +public: + doc_host_ui_handler(html_frame* frame); + virtual ~doc_host_ui_handler() = default; + +private: + html_frame* frame_; + +public: // IDocHostUIHandler interface + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID* ppvObj) override; + ULONG STDMETHODCALLTYPE AddRef() override; + ULONG STDMETHODCALLTYPE Release() override; + HRESULT STDMETHODCALLTYPE ShowContextMenu( + DWORD dwID, + POINT __RPC_FAR * ppt, + IUnknown __RPC_FAR * pcmdtReserved, + IDispatch __RPC_FAR * pdispReserved) override; + HRESULT STDMETHODCALLTYPE ShowUI( + DWORD dwID, + IOleInPlaceActiveObject __RPC_FAR * pActiveObject, + IOleCommandTarget __RPC_FAR * pCommandTarget, + IOleInPlaceFrame __RPC_FAR * pFrame, + IOleInPlaceUIWindow __RPC_FAR * pDoc) override; + HRESULT STDMETHODCALLTYPE GetHostInfo(DOCHOSTUIINFO __RPC_FAR * pInfo) override; + HRESULT STDMETHODCALLTYPE HideUI() override; + HRESULT STDMETHODCALLTYPE UpdateUI() override; + HRESULT STDMETHODCALLTYPE EnableModeless(BOOL fEnable) override; + HRESULT STDMETHODCALLTYPE OnDocWindowActivate(BOOL fActivate) override; + HRESULT STDMETHODCALLTYPE OnFrameWindowActivate(BOOL fActivate) override; + HRESULT STDMETHODCALLTYPE ResizeBorder(LPCRECT prcBorder, IOleInPlaceUIWindow __RPC_FAR * pUIWindow, + BOOL fRameWindow) override; + HRESULT STDMETHODCALLTYPE TranslateAccelerator(LPMSG lpMsg, const GUID __RPC_FAR * pguidCmdGroup, DWORD nCmdID) + override; + HRESULT STDMETHODCALLTYPE GetOptionKeyPath(LPOLESTR __RPC_FAR * pchKey, DWORD dw) override; + HRESULT STDMETHODCALLTYPE GetDropTarget(IDropTarget __RPC_FAR * pDropTarget, + IDropTarget __RPC_FAR *__RPC_FAR * ppDropTarget) override; + HRESULT STDMETHODCALLTYPE GetExternal(IDispatch __RPC_FAR *__RPC_FAR * ppDispatch) override; + HRESULT STDMETHODCALLTYPE TranslateUrl(DWORD dwTranslate, OLECHAR __RPC_FAR * pchURLIn, + OLECHAR __RPC_FAR *__RPC_FAR * ppchURLOut) override; + HRESULT STDMETHODCALLTYPE FilterDataObject(IDataObject __RPC_FAR * pDO, IDataObject __RPC_FAR *__RPC_FAR * ppDORet) + override; +}; diff --git a/src/launcher/html/ole_client_site.cpp b/src/launcher/html/ole_client_site.cpp new file mode 100644 index 0000000..2bc2b11 --- /dev/null +++ b/src/launcher/html/ole_client_site.cpp @@ -0,0 +1,77 @@ +#include +#include "../html_frame.hpp" + +ole_client_site::ole_client_site(html_frame* frame): frame_(frame) +{ +} + +HRESULT ole_client_site::QueryInterface(REFIID riid, LPVOID* ppvObject) +{ + if (!memcmp(&riid, &IID_IUnknown, sizeof(GUID)) || + !memcmp(&riid, &IID_IOleClientSite, sizeof(GUID))) + { + *ppvObject = this; + this->AddRef(); + return S_OK; + } + + if (!memcmp(&riid, &IID_IOleInPlaceSite, sizeof(GUID))) + { + auto in_place_site = this->frame_->get_in_place_site(); + in_place_site->AddRef(); + *ppvObject = in_place_site; + return S_OK; + } + + if (!memcmp(&riid, &IID_IDocHostUIHandler, sizeof(GUID))) + { + auto ui_handler = this->frame_->get_ui_handler(); + ui_handler->AddRef(); + *ppvObject = ui_handler; + return S_OK; + } + + *ppvObject = nullptr; + return E_NOINTERFACE; +} + +ULONG ole_client_site::AddRef() +{ + return 1; +} + +ULONG ole_client_site::Release() +{ + return 1; +} + +HRESULT ole_client_site::SaveObject() +{ + return E_NOTIMPL; +} + +HRESULT ole_client_site::GetMoniker(DWORD /*dwAssign*/, DWORD /*dwWhichMoniker*/, IMoniker** /*ppmk*/) +{ + return E_NOTIMPL; +} + +HRESULT ole_client_site::GetContainer(LPOLECONTAINER* ppContainer) +{ + *ppContainer = nullptr; + return E_NOINTERFACE; +} + +HRESULT ole_client_site::ShowObject() +{ + return NOERROR; +} + +HRESULT ole_client_site::OnShowWindow(BOOL /*fShow*/) +{ + return E_NOTIMPL; +} + +HRESULT ole_client_site::RequestNewObjectLayout() +{ + return E_NOTIMPL; +} diff --git a/src/launcher/html/ole_client_site.hpp b/src/launcher/html/ole_client_site.hpp new file mode 100644 index 0000000..d0adc80 --- /dev/null +++ b/src/launcher/html/ole_client_site.hpp @@ -0,0 +1,24 @@ +#pragma once + +class html_frame; + +class ole_client_site final : public IOleClientSite +{ +public: + ole_client_site(html_frame* frame); + virtual ~ole_client_site() = default; + +private: + html_frame* frame_; + +public: + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID* ppvObject) override; + ULONG STDMETHODCALLTYPE AddRef() override; + ULONG STDMETHODCALLTYPE Release() override; + HRESULT STDMETHODCALLTYPE SaveObject() override; + HRESULT STDMETHODCALLTYPE GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker** ppmk) override; + HRESULT STDMETHODCALLTYPE GetContainer(LPOLECONTAINER FAR* ppContainer) override; + HRESULT STDMETHODCALLTYPE ShowObject() override; + HRESULT STDMETHODCALLTYPE OnShowWindow(BOOL fShow) override; + HRESULT STDMETHODCALLTYPE RequestNewObjectLayout() override; +}; diff --git a/src/launcher/html/ole_in_place_frame.cpp b/src/launcher/html/ole_in_place_frame.cpp new file mode 100644 index 0000000..b9612d5 --- /dev/null +++ b/src/launcher/html/ole_in_place_frame.cpp @@ -0,0 +1,82 @@ +#include +#include "../html_frame.hpp" + +ole_in_place_frame::ole_in_place_frame(html_frame* frame): frame_(frame) +{ +} + +HRESULT ole_in_place_frame::QueryInterface(REFIID /*riid*/, LPVOID* /*ppvObj*/) +{ + return E_NOTIMPL; +} + +ULONG ole_in_place_frame::AddRef() +{ + return 1; +} + +ULONG ole_in_place_frame::Release() +{ + return 1; +} + +HRESULT ole_in_place_frame::GetWindow(HWND* lphwnd) +{ + *lphwnd = this->frame_->get_window(); + return S_OK; +} + +HRESULT ole_in_place_frame::ContextSensitiveHelp(BOOL /*fEnterMode*/) +{ + return E_NOTIMPL; +} + +HRESULT ole_in_place_frame::GetBorder(LPRECT /*lprectBorder*/) +{ + return E_NOTIMPL; +} + +HRESULT ole_in_place_frame::RequestBorderSpace(LPCBORDERWIDTHS /*pborderwidths*/) +{ + return E_NOTIMPL; +} + +HRESULT ole_in_place_frame::SetBorderSpace(LPCBORDERWIDTHS /*pborderwidths*/) +{ + return E_NOTIMPL; +} + +HRESULT ole_in_place_frame::SetActiveObject(IOleInPlaceActiveObject* /*pActiveObject*/, LPCOLESTR /*pszObjName*/) +{ + return S_OK; +} + +HRESULT ole_in_place_frame::InsertMenus(HMENU /*hmenuShared*/, LPOLEMENUGROUPWIDTHS /*lpMenuWidths*/) +{ + return E_NOTIMPL; +} + +HRESULT ole_in_place_frame::SetMenu(HMENU /*hmenuShared*/, HOLEMENU /*holemenu*/, HWND /*hwndActiveObject*/) +{ + return S_OK; +} + +HRESULT ole_in_place_frame::RemoveMenus(HMENU /*hmenuShared*/) +{ + return E_NOTIMPL; +} + +HRESULT ole_in_place_frame::SetStatusText(LPCOLESTR /*pszStatusText*/) +{ + return S_OK; +} + +HRESULT ole_in_place_frame::EnableModeless(BOOL /*fEnable*/) +{ + return S_OK; +} + +HRESULT ole_in_place_frame::TranslateAcceleratorA(LPMSG /*lpmsg*/, WORD /*wID*/) +{ + return E_NOTIMPL; +} diff --git a/src/launcher/html/ole_in_place_frame.hpp b/src/launcher/html/ole_in_place_frame.hpp new file mode 100644 index 0000000..4a39d7f --- /dev/null +++ b/src/launcher/html/ole_in_place_frame.hpp @@ -0,0 +1,30 @@ +#pragma once + +class html_frame; + +class ole_in_place_frame final : public IOleInPlaceFrame +{ +public: + ole_in_place_frame(html_frame* frame); + virtual ~ole_in_place_frame() = default; + +private: + html_frame* frame_; + +public: // IOleInPlaceFrame interface + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID FAR* ppvObj) override; + ULONG STDMETHODCALLTYPE AddRef() override; + ULONG STDMETHODCALLTYPE Release() override; + HRESULT STDMETHODCALLTYPE GetWindow(HWND FAR* lphwnd) override; + HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode) override; + HRESULT STDMETHODCALLTYPE GetBorder(LPRECT lprectBorder) override; + HRESULT STDMETHODCALLTYPE RequestBorderSpace(LPCBORDERWIDTHS pborderwidths) override; + HRESULT STDMETHODCALLTYPE SetBorderSpace(LPCBORDERWIDTHS pborderwidths) override; + HRESULT STDMETHODCALLTYPE SetActiveObject(IOleInPlaceActiveObject* pActiveObject, LPCOLESTR pszObjName) override; + HRESULT STDMETHODCALLTYPE InsertMenus(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths) override; + HRESULT STDMETHODCALLTYPE SetMenu(HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject) override; + HRESULT STDMETHODCALLTYPE RemoveMenus(HMENU hmenuShared) override; + HRESULT STDMETHODCALLTYPE SetStatusText(LPCOLESTR pszStatusText) override; + HRESULT STDMETHODCALLTYPE EnableModeless(BOOL fEnable) override; + HRESULT STDMETHODCALLTYPE TranslateAccelerator(LPMSG lpmsg, WORD wID) override; +}; diff --git a/src/launcher/html/ole_in_place_site.cpp b/src/launcher/html/ole_in_place_site.cpp new file mode 100644 index 0000000..0623eb2 --- /dev/null +++ b/src/launcher/html/ole_in_place_site.cpp @@ -0,0 +1,105 @@ +#include +#include "../html_frame.hpp" + +ole_in_place_site::ole_in_place_site(html_frame* frame) : frame_(frame) +{ +} + +HRESULT ole_in_place_site::QueryInterface(REFIID riid, LPVOID FAR* ppvObj) +{ + auto client_site = this->frame_->get_client_site(); + if (client_site) + { + return client_site->QueryInterface(riid, ppvObj); + } + + return E_NOINTERFACE; +} + +ULONG ole_in_place_site::AddRef() +{ + return 1; +} + +ULONG ole_in_place_site::Release() +{ + return 1; +} + +HRESULT ole_in_place_site::GetWindow(HWND* lphwnd) +{ + *lphwnd = this->frame_->get_window(); + return S_OK; +} + +HRESULT ole_in_place_site::ContextSensitiveHelp(BOOL /*fEnterMode*/) +{ + return E_NOTIMPL; +} + +HRESULT ole_in_place_site::CanInPlaceActivate() +{ + return S_OK; +} + +HRESULT ole_in_place_site::OnInPlaceActivate() +{ + return S_OK; +} + +HRESULT ole_in_place_site::OnUIActivate() +{ + return S_OK; +} + +HRESULT ole_in_place_site::GetWindowContext(LPOLEINPLACEFRAME* lplpFrame, LPOLEINPLACEUIWINDOW* lplpDoc, + LPRECT /*lprcPosRect*/, LPRECT /*lprcClipRect*/, + LPOLEINPLACEFRAMEINFO lpFrameInfo) +{ + *lplpFrame = this->frame_->get_in_place_frame(); + *lplpDoc = nullptr; + + lpFrameInfo->fMDIApp = FALSE; + lpFrameInfo->hwndFrame = this->frame_->get_window(); + lpFrameInfo->haccel = nullptr; + lpFrameInfo->cAccelEntries = 0; + + return S_OK; +} + +HRESULT ole_in_place_site::Scroll(SIZE /*scrollExtent*/) +{ + return E_NOTIMPL; +} + +HRESULT ole_in_place_site::OnUIDeactivate(BOOL /*fUndoable*/) +{ + return S_OK; +} + +HRESULT ole_in_place_site::OnInPlaceDeactivate() +{ + return S_OK; +} + +HRESULT ole_in_place_site::DiscardUndoState() +{ + return E_NOTIMPL; +} + +HRESULT ole_in_place_site::DeactivateAndUndo() +{ + return E_NOTIMPL; +} + +HRESULT ole_in_place_site::OnPosRectChange(LPCRECT lprcPosRect) +{ + IOleInPlaceObject* in_place = nullptr; + if (!this->frame_->get_browser_object()->QueryInterface(IID_IOleInPlaceObject, reinterpret_cast(&in_place))) + { + in_place->SetObjectRects(lprcPosRect, lprcPosRect); + in_place->Release(); + } + + return S_OK; +} diff --git a/src/launcher/html/ole_in_place_site.hpp b/src/launcher/html/ole_in_place_site.hpp new file mode 100644 index 0000000..3dad18c --- /dev/null +++ b/src/launcher/html/ole_in_place_site.hpp @@ -0,0 +1,32 @@ +#pragma once + +class html_frame; + +class ole_in_place_site final : public IOleInPlaceSite +{ +public: + ole_in_place_site(html_frame* frame); + virtual ~ole_in_place_site() = default; + +private: + html_frame* frame_; + +public: // IOleInPlaceSite interface + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID FAR* ppvObj) override; + ULONG STDMETHODCALLTYPE AddRef() override; + ULONG STDMETHODCALLTYPE Release() override; + HRESULT STDMETHODCALLTYPE GetWindow(HWND FAR* lphwnd) override; + HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode) override; + HRESULT STDMETHODCALLTYPE CanInPlaceActivate() override; + HRESULT STDMETHODCALLTYPE OnInPlaceActivate() override; + HRESULT STDMETHODCALLTYPE OnUIActivate() override; + HRESULT STDMETHODCALLTYPE GetWindowContext(LPOLEINPLACEFRAME FAR* lplpFrame, LPOLEINPLACEUIWINDOW FAR* lplpDoc, + LPRECT lprcPosRect, LPRECT lprcClipRect, + LPOLEINPLACEFRAMEINFO lpFrameInfo) override; + HRESULT STDMETHODCALLTYPE Scroll(SIZE scrollExtent) override; + HRESULT STDMETHODCALLTYPE OnUIDeactivate(BOOL fUndoable) override; + HRESULT STDMETHODCALLTYPE OnInPlaceDeactivate() override; + HRESULT STDMETHODCALLTYPE DiscardUndoState() override; + HRESULT STDMETHODCALLTYPE DeactivateAndUndo() override; + HRESULT STDMETHODCALLTYPE OnPosRectChange(LPCRECT lprcPosRect) override; +}; diff --git a/src/launcher/html_frame.cpp b/src/launcher/html_frame.cpp new file mode 100644 index 0000000..a35e42d --- /dev/null +++ b/src/launcher/html_frame.cpp @@ -0,0 +1,142 @@ +#include +#include "html_frame.hpp" + +html_frame::html_frame() : in_place_frame_(this), in_place_site_(this), ui_handler_(this), client_site_(this) +{ + if (OleInitialize(nullptr) != S_OK) + { + throw std::runtime_error("Unable to initialize the OLE library"); + } +} + +html_frame::~html_frame() +{ + OleUninitialize(); +} + +HWND html_frame::get_window() const +{ + return this->window_; +} + +std::shared_ptr html_frame::get_browser_object() const +{ + return this->browser_object_; +} + +ole_in_place_frame* html_frame::get_in_place_frame() +{ + return &this->in_place_frame_; +} + +ole_in_place_site* html_frame::get_in_place_site() +{ + return &this->in_place_site_; +} + +doc_host_ui_handler* html_frame::get_ui_handler() +{ + return &this->ui_handler_; +} + +ole_client_site* html_frame::get_client_site() +{ + return &this->client_site_; +} + +std::shared_ptr html_frame::get_web_browser() const +{ + IWebBrowser2* web_browser; + if (!this->browser_object_->QueryInterface(IID_IWebBrowser2, reinterpret_cast(&web_browser))) + { + return std::shared_ptr(web_browser, [](IWebBrowser2* web_browser) + { + if (web_browser) + { + web_browser->Release(); + } + }); + } + + return {}; +} + +void html_frame::initialize(const HWND window) +{ + if (this->window_) return; + this->window_ = window; + + this->create_browser(); + this->initialize_browser(); +} + +void html_frame::create_browser() +{ + LPCLASSFACTORY class_factory = nullptr; + if (CoGetClassObject(CLSID_WebBrowser, CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, nullptr, IID_IClassFactory, + reinterpret_cast(&class_factory)) || !class_factory) + { + throw std::runtime_error("Unable to get the class factory"); + } + + IOleObject* browser_object = nullptr; + class_factory->CreateInstance(nullptr, IID_IOleObject, reinterpret_cast(&browser_object)); + class_factory->Release(); + + if (!browser_object) + { + throw std::runtime_error("Unable to create browser object"); + } + + this->browser_object_ = std::shared_ptr(browser_object, [](IOleObject* browser_object) + { + if (browser_object) + { + browser_object->Close(OLECLOSE_NOSAVE); + browser_object->Release(); + } + }); +} + +void html_frame::initialize_browser() +{ + this->browser_object_->SetClientSite(this->get_client_site()); + this->browser_object_->SetHostNames(L"Hostname", nullptr); + + RECT rect; + GetClientRect(this->get_window(), &rect); + OleSetContainedObject(this->browser_object_.get(), TRUE); + + this->browser_object_->DoVerb(OLEIVERB_SHOW, nullptr, this->get_client_site(), -1, this->get_window(), &rect); + this->resize(rect.right, rect.bottom); +} + +void html_frame::resize(const DWORD width, const DWORD height) const +{ + auto web_browser = this->get_web_browser(); + if (web_browser) + { + web_browser->put_Left(0); + web_browser->put_Top(0); + web_browser->put_Width(width); + web_browser->put_Height(height); + } +} + +void html_frame::load_url(std::string url) const +{ + auto web_browser = this->get_web_browser(); + if (web_browser) + { + std::wstring wide_url(url.begin(), url.end()); + + VARIANT my_url; + VariantInit(&my_url); + my_url.vt = VT_BSTR; + my_url.bstrVal = SysAllocString(wide_url.data()); + + web_browser->Navigate2(&my_url, nullptr, nullptr, nullptr, nullptr); + + VariantClear(&my_url); + } +} diff --git a/src/launcher/html_frame.hpp b/src/launcher/html_frame.hpp new file mode 100644 index 0000000..aaee1b7 --- /dev/null +++ b/src/launcher/html_frame.hpp @@ -0,0 +1,40 @@ +#pragma once +#include "window.hpp" +#include "html/ole_in_place_frame.hpp" +#include "html/ole_in_place_site.hpp" +#include "html/doc_host_ui_handler.hpp" +#include "html/ole_client_site.hpp" + +class html_frame final +{ +public: + html_frame(); + ~html_frame(); + + void initialize(const HWND window); + + void resize(DWORD width, DWORD height) const; + void load_url(std::string url) const; + + HWND get_window() const; + + std::shared_ptr get_browser_object() const; + std::shared_ptr get_web_browser() const; + + ole_in_place_frame* get_in_place_frame(); + ole_in_place_site* get_in_place_site(); + doc_host_ui_handler* get_ui_handler(); + ole_client_site* get_client_site(); + +private: + HWND window_ = nullptr; + std::shared_ptr browser_object_; + + ole_in_place_frame in_place_frame_; + ole_in_place_site in_place_site_; + doc_host_ui_handler ui_handler_; + ole_client_site client_site_; + + void create_browser(); + void initialize_browser(); +}; diff --git a/src/launcher/image.cpp b/src/launcher/image.cpp deleted file mode 100644 index afcf3c3..0000000 --- a/src/launcher/image.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include -#include "image.hpp" - -image::image(const size_t resource) -{ - this->bitmap_ = LoadBitmapA(GetModuleHandleA(nullptr), MAKEINTRESOURCEA(resource)); -} - -image::~image() -{ - DeleteBitmap(this->bitmap_); -} - -void image::set_position(const POINT& position) -{ - this->position_ = position; -} - -void image::set_size(const POINT& size) -{ - this->size_ = size; -} - -bool image::is_hovered(const POINT& mouse) const -{ - return mouse.x >= this->position_.x && mouse.x < (this->position_.x + this->size_.x) - && mouse.y >= this->position_.y && mouse.y < (this->position_.y + this->size_.y); -} - -void image::paint(const HDC hdc, const POINT& mouse) const -{ - BITMAP bitmap; - GetObject(this->bitmap_, sizeof(bitmap), &bitmap); - - const auto dc = CreateCompatibleDC(hdc); - SelectObject(dc, this->bitmap_); - - const LONG modifier = 2; - LONG size_offset = 0; - LONG position_offset = 0; - if (this->is_hovered(mouse)) - { - size_offset = modifier * 2; - position_offset = -modifier; - } - - SetStretchBltMode(hdc, HALFTONE); - StretchBlt(hdc, this->position_.x + position_offset, this->position_.y + position_offset, - this->size_.x + size_offset, this->size_.y + size_offset, dc, 0, 0, bitmap.bmWidth, - bitmap.bmHeight, SRCCOPY); - - DeleteDC(dc); -} - -void image::set_click_listener(std::function callback) -{ - this->callback_ = callback; -} - -void image::click(const POINT& mouse, const bool down) -{ - if (down) - { - this->down_handled_ = this->is_hovered(mouse); - } - else - { - if (this->down_handled_ && this->is_hovered(mouse) && this->callback_) - { - this->callback_(); - } - - this->down_handled_ = false; - } -} diff --git a/src/launcher/image.hpp b/src/launcher/image.hpp deleted file mode 100644 index ff54759..0000000 --- a/src/launcher/image.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -class image final -{ -public: - image(size_t resource); - ~image(); - - void set_position(const POINT& position); - void set_size(const POINT& size); - - bool is_hovered(const POINT& mouse) const; - - void paint(HDC hdc, const POINT& mouse) const; - - void set_click_listener(std::function callback); - - void click(const POINT& mouse, bool down); - -private: - POINT size_{}; - POINT position_{}; - HBITMAP bitmap_; - - bool down_handled_ = false; - std::function callback_; -}; diff --git a/src/launcher/launcher.cpp b/src/launcher/launcher.cpp index ea66228..34b402f 100644 --- a/src/launcher/launcher.cpp +++ b/src/launcher/launcher.cpp @@ -1,19 +1,14 @@ #include #include "launcher.hpp" +#include "html_frame.hpp" -launcher::launcher() : window_("Open-IW5", 615, 300), image_sp_(IMAGE_SP), image_mp_(IMAGE_MP) +launcher::launcher() { - this->image_sp_.set_position({100, 90}); - this->image_mp_.set_position({401, 90}); - - this->image_sp_.set_size({100, 100}); - this->image_mp_.set_size({100, 100}); - - this->image_sp_.set_click_listener(std::bind(&launcher::select_mode, this, mode::singleplayer)); - this->image_mp_.set_click_listener(std::bind(&launcher::select_mode, this, mode::multiplayer)); - this->window_.set_callback(std::bind(&launcher::handler, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + + this->window_.create("Open-IW5", 615, 300); + this->html_frame_.load_url("https://google.com"); } launcher::mode launcher::run() const @@ -25,27 +20,16 @@ launcher::mode launcher::run() const LRESULT launcher::handler(const UINT message, const WPARAM w_param, const LPARAM l_param) { - if (message == WM_PAINT) + if (message == WM_SIZE) { - this->paint(); + this->html_frame_.resize(LOWORD(l_param), HIWORD(l_param)); + return 0; } - else if (message == WM_MOUSEMOVE) + + if (message == WM_CREATE) { - this->mouse_move(l_param); - } - else if (message == WM_LBUTTONDOWN) - { - this->image_sp_.click(this->mouse_, true); - this->image_mp_.click(this->mouse_, true); - } - else if (message == WM_LBUTTONUP) - { - this->image_sp_.click(this->mouse_, false); - this->image_mp_.click(this->mouse_, false); - } - else if (message == WM_ERASEBKGND) - { - return TRUE; + this->html_frame_.initialize(this->window_); + return 0; } return DefWindowProc(this->window_, message, w_param, l_param); @@ -56,65 +40,3 @@ void launcher::select_mode(const mode mode) this->mode_ = mode; this->window_.close(); } - -void launcher::draw_text(const HDC hdc) -{ - Gdiplus::Graphics graphics(hdc); - Gdiplus::SolidBrush color(Gdiplus::Color(255, 150, 150, 150)); - Gdiplus::FontFamily font_family(L"Segoe UI"); - Gdiplus::Font font(&font_family, 20, Gdiplus::FontStyleRegular, Gdiplus::UnitPixel); - const auto stringformat = Gdiplus::StringFormat::GenericTypographic(); - - std::wstring sp(L"Singleplayer"); - std::wstring mp(L"Multiplayer"); - - Gdiplus::RectF rect{}; - graphics.MeasureString(sp.data(), -1, &font, rect, stringformat, &rect); - - const Gdiplus::PointF pos{150 - (rect.Width / 2 + 2), 45}; - graphics.DrawString(sp.data(), -1, &font, pos, &color); - - rect = {}; - graphics.MeasureString(mp.data(), -1, &font, rect, stringformat, &rect); - graphics.DrawString(mp.data(), -1, &font, {451 - (rect.Width / 2 + 4), 45}, &color); - - Gdiplus::Pen pen(Gdiplus::Color(50, 255, 255, 255), 1); - graphics.DrawLine(&pen, 300, 0, 300, 600); -} - -void launcher::paint() const -{ - RECT rect; - GetClientRect(this->window_, &rect); - const int width = rect.right - rect.left; - const int height = rect.bottom + rect.left; - - PAINTSTRUCT ps; - const auto hdc = BeginPaint(this->window_, &ps); - - const auto hdc_copy = CreateCompatibleDC(hdc); - const auto bitmap = CreateCompatibleBitmap(hdc, width, height); - SelectObject(hdc_copy, bitmap); - - this->window_.clear(hdc_copy); - - this->draw_text(hdc_copy); - - this->image_sp_.paint(hdc_copy, this->mouse_); - this->image_mp_.paint(hdc_copy, this->mouse_); - - BitBlt(hdc, 0, 0, width, height, hdc_copy, 0, 0, SRCCOPY); - - DeleteObject(bitmap); - DeleteDC(hdc_copy); - - EndPaint(this->window_, &ps); -} - -void launcher::mouse_move(const LPARAM l_param) -{ - this->mouse_.x = GET_X_LPARAM(l_param); - this->mouse_.y = GET_Y_LPARAM(l_param); - - InvalidateRect(this->window_, nullptr, FALSE); -} diff --git a/src/launcher/launcher.hpp b/src/launcher/launcher.hpp index ff25d08..8b757fe 100644 --- a/src/launcher/launcher.hpp +++ b/src/launcher/launcher.hpp @@ -1,6 +1,6 @@ #pragma once #include "window.hpp" -#include "image.hpp" +#include "html_frame.hpp" class launcher final { @@ -21,17 +21,8 @@ private: mode mode_ = none; window window_; - - image image_sp_; - image image_mp_; - - POINT mouse_{}; + html_frame html_frame_; LRESULT handler(const UINT message, const WPARAM w_param, const LPARAM l_param); - void select_mode(mode mode); - - static void draw_text(const HDC hdc); - void paint() const; - void mouse_move(LPARAM l_param); }; diff --git a/src/launcher/window.cpp b/src/launcher/window.cpp index adfd7cf..f2c1224 100644 --- a/src/launcher/window.cpp +++ b/src/launcher/window.cpp @@ -1,36 +1,35 @@ #include #include "window.hpp" -window::window(const std::string& title, const int width, const int height) +window::window() { - Gdiplus::GdiplusStartupInput input; - GdiplusStartup(&this->token_, &input, nullptr); - - const auto handle = GetModuleHandle(nullptr); - ZeroMemory(&this->wc_, sizeof(this->wc_)); - this->classname = "window-base-" + std::to_string(time(nullptr)); + this->classname_ = "window-base-" + std::to_string(time(nullptr)); this->wc_.cbSize = sizeof(this->wc_); this->wc_.style = CS_HREDRAW | CS_VREDRAW; this->wc_.lpfnWndProc = static_processor; - this->wc_.hInstance = handle; + this->wc_.hInstance = GetModuleHandle(nullptr); this->wc_.hCursor = LoadCursor(nullptr, IDC_ARROW); - this->wc_.hIcon = LoadIcon(handle, MAKEINTRESOURCE(102)); + this->wc_.hIcon = LoadIcon(this->wc_.hInstance, MAKEINTRESOURCE(102)); this->wc_.hIconSm = this->wc_.hIcon; - this->wc_.hbrBackground = CreateSolidBrush(RGB(35, 35, 35)); - this->wc_.lpszClassName = this->classname.data(); + this->wc_.hbrBackground = HBRUSH(COLOR_WINDOW); + this->wc_.lpszClassName = this->classname_.data(); RegisterClassEx(&this->wc_); +} +void window::create(const std::string& title, const int width, const int height) +{ const auto x = (GetSystemMetrics(SM_CXSCREEN) - width) / 2; const auto y = (GetSystemMetrics(SM_CYSCREEN) - height) / 2; this->handle_ = CreateWindowExA(NULL, this->wc_.lpszClassName, title.data(), (WS_OVERLAPPEDWINDOW | WS_VISIBLE) & ~(WS_THICKFRAME | WS_MAXIMIZEBOX), x, y, width, - height, nullptr, nullptr, handle, nullptr); + height, nullptr, nullptr, this->wc_.hInstance, this); - SetWindowLongPtrA(*this, GWLP_USERDATA, LONG_PTR(this)); + ShowWindow(this->handle_, SW_SHOW); + UpdateWindow(this->handle_); } window::~window() @@ -38,8 +37,6 @@ window::~window() this->close(); UnregisterClass(this->wc_.lpszClassName, this->wc_.hInstance); DeleteObject(this->wc_.hbrBackground); - - Gdiplus::GdiplusShutdown(this->token_); } void window::close() @@ -53,27 +50,13 @@ void window::close() void window::run() const { MSG msg; - while (this->handle_ && IsWindow(*this)) + while (this->handle_ && IsWindow(*this) && GetMessage(&msg, nullptr, 0, 0)) { - if (PeekMessageA(&msg, nullptr, NULL, NULL, PM_REMOVE)) - { - TranslateMessage(&msg); - DispatchMessageA(&msg); - } - else - { - std::this_thread::sleep_for(1ms); - } + TranslateMessage(&msg); + DispatchMessage(&msg); } } -void window::clear(const HDC hdc) const -{ - RECT rc; - GetClientRect(*this, &rc); - FillRect(hdc, &rc, this->wc_.hbrBackground); -} - void window::set_callback(const std::function& callback) { this->callback_ = callback; @@ -81,6 +64,12 @@ void window::set_callback(const std::function& ca LRESULT CALLBACK window::processor(const UINT message, const WPARAM w_param, const LPARAM l_param) const { + if (message == WM_DESTROY) + { + PostQuitMessage(0); + return TRUE; + } + if (message == WM_KILL_WINDOW) { DestroyWindow(*this); @@ -97,6 +86,14 @@ LRESULT CALLBACK window::processor(const UINT message, const WPARAM w_param, con LRESULT CALLBACK window::static_processor(HWND hwnd, UINT message, WPARAM w_param, LPARAM l_param) { + if (message == WM_CREATE) + { + auto data = reinterpret_cast(l_param); + SetWindowLongPtrA(hwnd, GWLP_USERDATA, LONG_PTR(data->lpCreateParams)); + + reinterpret_cast(data->lpCreateParams)->handle_ = hwnd; + } + const auto self = reinterpret_cast(GetWindowLongPtr(hwnd, GWLP_USERDATA)); if (self) return self->processor(message, w_param, l_param); diff --git a/src/launcher/window.hpp b/src/launcher/window.hpp index ef6327a..3bbc1d2 100644 --- a/src/launcher/window.hpp +++ b/src/launcher/window.hpp @@ -5,23 +5,22 @@ class window final { public: - window(const std::string& title, int width, int height); + window(); ~window(); + void create(const std::string& title, int width, int height); + void close(); void run() const; - void clear(const HDC hdc) const; - void set_callback(const std::function& callback); operator HWND() const; private: - ULONG_PTR token_; WNDCLASSEX wc_{}; HWND handle_ = nullptr; - std::string classname; + std::string classname_; std::function callback_; LRESULT CALLBACK processor(UINT message, WPARAM w_param, LPARAM l_param) const; diff --git a/src/module/command.cpp b/src/module/command.cpp index c40447a..dc5f40d 100644 --- a/src/module/command.cpp +++ b/src/module/command.cpp @@ -23,7 +23,10 @@ void command::add(const std::string& name, const std::function -#include -#include -#include +#include +#include +#include #include #include #include