diff --git a/.gitmodules b/.gitmodules index 760693b..4bf1865 100644 --- a/.gitmodules +++ b/.gitmodules @@ -14,3 +14,6 @@ path = deps/HDiffPatch url = https://github.com/sisong/HDiffPatch.git branch = master +[submodule "deps/GSL"] + path = deps/GSL + url = https://github.com/Microsoft/GSL.git diff --git a/deps/GSL b/deps/GSL new file mode 160000 index 0000000..0f68d13 --- /dev/null +++ b/deps/GSL @@ -0,0 +1 @@ +Subproject commit 0f68d133fa6fd2973951b8aaab481e34bbfd2cf4 diff --git a/deps/premake/gsl.lua b/deps/premake/gsl.lua new file mode 100644 index 0000000..7a2daf6 --- /dev/null +++ b/deps/premake/gsl.lua @@ -0,0 +1,19 @@ +gsl = { + source = path.join(dependencies.basePath, "GSL"), +} + +function gsl.import() + gsl.includes() +end + +function gsl.includes() + includedirs { + path.join(gsl.source, "include") + } +end + +function gsl.project() + +end + +table.insert(dependencies, gsl) 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..6dbbce1 --- /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 = this->frame_->get_html_dispatch(); + return (*ppDispatch) ? S_OK : 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/html_argument.cpp b/src/launcher/html/html_argument.cpp new file mode 100644 index 0000000..2857583 --- /dev/null +++ b/src/launcher/html/html_argument.cpp @@ -0,0 +1,37 @@ +#include +#include "html_argument.hpp" + +html_argument::html_argument(VARIANT* val) : value_(val) +{ + +} + +bool html_argument::is_empty() const +{ + return this->value_ == nullptr || this->value_->vt == VT_EMPTY; +} + +bool html_argument::is_string() const +{ + if(this->is_empty()) return false; + return this->value_->vt == VT_BSTR; +} + +bool html_argument::is_number() const +{ + if(this->is_empty()) return false; + return this->value_->vt == VT_I4; +} + +std::string html_argument::get_string() const +{ + if(!this->is_string()) return {}; + std::wstring wide_string(this->value_->bstrVal); + return std::string(wide_string.begin(), wide_string.end()); +} + +int html_argument::get_number() const +{ + if(!this->is_number()) return 0; + return this->value_->intVal; +} diff --git a/src/launcher/html/html_argument.hpp b/src/launcher/html/html_argument.hpp new file mode 100644 index 0000000..6eff151 --- /dev/null +++ b/src/launcher/html/html_argument.hpp @@ -0,0 +1,18 @@ +#pragma once + + class html_argument final + { + public: + html_argument(VARIANT* val); + + bool is_empty() const; + + bool is_string() const; + bool is_number() const; + + std::string get_string() const; + int get_number() const; + + private: + VARIANT* value_; + }; \ No newline at end of file diff --git a/src/launcher/html/html_dispatch.cpp b/src/launcher/html/html_dispatch.cpp new file mode 100644 index 0000000..7ca438f --- /dev/null +++ b/src/launcher/html/html_dispatch.cpp @@ -0,0 +1,61 @@ +#include +#include "../html_frame.hpp" + +html_dispatch::html_dispatch(html_frame* frame) : frame_(frame) +{ +} + +HRESULT html_dispatch::QueryInterface(const IID& riid, LPVOID* ppvObj) +{ + if (!memcmp(&riid, &IID_IUnknown, sizeof(GUID)) || + !memcmp(&riid, &IID_IDispatch, sizeof(GUID))) + { + *ppvObj = this; + this->AddRef(); + return S_OK; + } + + *ppvObj = nullptr; + return E_NOINTERFACE; +} + +ULONG html_dispatch::AddRef() +{ + return 1; +} + +ULONG html_dispatch::Release() +{ + return 1; +} + +HRESULT html_dispatch::GetTypeInfoCount(UINT* pctinfo) +{ + return S_FALSE; +} + +HRESULT html_dispatch::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) +{ + return S_FALSE; +} + +HRESULT html_dispatch::GetIDsOfNames(const IID& riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) +{ + for(unsigned int i = 0; i < cNames; ++i) + { + std::wstring wide_name(rgszNames[i]); + std::string name(wide_name.begin(), wide_name.end()); + + rgDispId[i] = this->frame_->get_callback_id(name); + } + + return S_OK; +} + +HRESULT html_dispatch::Invoke(DISPID dispIdMember, const IID& riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, + VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) +{ + html_frame::callback_params params(pDispParams, pVarResult); + this->frame_->invoke_callback(dispIdMember, ¶ms); + return S_OK; +} diff --git a/src/launcher/html/html_dispatch.hpp b/src/launcher/html/html_dispatch.hpp new file mode 100644 index 0000000..869af7a --- /dev/null +++ b/src/launcher/html/html_dispatch.hpp @@ -0,0 +1,24 @@ +#pragma once + +class html_frame; + +class html_dispatch final : public IDispatch +{ +public: + html_dispatch(html_frame* frame); + virtual ~html_dispatch() = default; + +private: + html_frame* frame_; + +public: // IDispatch interface + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID FAR* ppvObj) override; + ULONG STDMETHODCALLTYPE AddRef() override; + ULONG STDMETHODCALLTYPE Release() override; + HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT* pctinfo) override; + HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) override; + HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) + override; + HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, + VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) 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..60069cd --- /dev/null +++ b/src/launcher/html_frame.cpp @@ -0,0 +1,256 @@ +#include +#include "html_frame.hpp" +#include "utils/nt.hpp" + +html_frame::callback_params::callback_params(DISPPARAMS* params, VARIANT* res) : result(res) +{ + for (auto i = params->cArgs; i > 0; --i) + { + auto param = ¶ms->rgvarg[i - 1]; + this->arguments.emplace_back(param); + } +} + +html_frame::html_frame() : in_place_frame_(this), in_place_site_(this), ui_handler_(this), client_site_(this), + html_dispatch_(this) +{ + if (OleInitialize(nullptr) != S_OK) + { + throw std::runtime_error("Unable to initialize the OLE library"); + } + + set_browser_feature("FEATURE_BROWSER_EMULATION", 11000); + set_browser_feature("FEATURE_GPU_RENDERING", 1); +} + +html_frame::~html_frame() +{ + OleUninitialize(); +} + +void html_frame::object_deleter(IUnknown* object) +{ + if (object) + { + object->Release(); + } +} + +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_; +} + +html_dispatch* html_frame::get_html_dispatch() +{ + return &this->html_dispatch_; +} + +std::shared_ptr html_frame::get_web_browser() const +{ + if (!this->browser_object_) return {}; + + IWebBrowser2* web_browser = nullptr; + if (this->browser_object_->QueryInterface(IID_IWebBrowser2, reinterpret_cast(&web_browser)) || !web_browser) + return {}; + + return std::shared_ptr(web_browser, object_deleter); +} + +std::shared_ptr html_frame::get_dispatch() const +{ + const auto web_browser = this->get_web_browser(); + if (!web_browser) return {}; + + IDispatch* dispatch = nullptr; + if (web_browser->get_Document(&dispatch) || !dispatch) return {}; + + return std::shared_ptr(dispatch, object_deleter); +} + +std::shared_ptr html_frame::get_document() const +{ + const auto dispatch = this->get_dispatch(); + if (!dispatch) return {}; + + IHTMLDocument2* document = nullptr; + if (dispatch->QueryInterface(IID_IHTMLDocument2, reinterpret_cast(&document)) || !document) return {}; + + return std::shared_ptr(document, object_deleter); +} + +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); + object_deleter(browser_object); + } + }); +} + +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::set_browser_feature(const std::string& feature, DWORD value) +{ + const auto registry_path = R"(SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\)" + feature; + + HKEY key = nullptr; + if (RegOpenKeyExA( + HKEY_CURRENT_USER, registry_path.data(), 0, + KEY_ALL_ACCESS, &key) != ERROR_SUCCESS) + return; + + const utils::nt::module self; + const auto name = self.get_name(); + RegSetValueExA(key, name.data(), 0, REG_DWORD, reinterpret_cast(&value), sizeof(value)); + + RegCloseKey(key); +} + +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); + } +} + +bool html_frame::load_url(const std::string& url) const +{ + auto web_browser = this->get_web_browser(); + if (!web_browser) return false; + + 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()); + + const auto _ = gsl::finally([&my_url]() { VariantClear(&my_url); }); + if (!my_url.bstrVal) return false; + + return SUCCEEDED(web_browser->Navigate2(&my_url, nullptr, nullptr, nullptr, nullptr)); +} + +bool html_frame::load_html(const std::string& html) const +{ + if (!this->load_url("about:blank")) return false; + + const auto document = this->get_document(); + if (!document) return false; + + SAFEARRAYBOUND safe_array_bound = {1, 0}; + auto safe_array = SafeArrayCreate(VT_VARIANT, 1, &safe_array_bound); + if (!safe_array) return false; + + const auto _ = gsl::finally([safe_array]() { SafeArrayDestroy(safe_array); }); + + VARIANT* variant = nullptr; + if (SafeArrayAccessData(safe_array, reinterpret_cast(&variant)) || !variant) return false; + + std::wstring wide_html(html.begin(), html.end()); + + variant->vt = VT_BSTR; + variant->bstrVal = SysAllocString(wide_html.data()); + if (!variant->bstrVal) return false; + + document->write(safe_array); + document->close(); + + return true; +} + +int html_frame::get_callback_id(const std::string& name) +{ + for (auto i = 0u; i < this->callbacks_.size(); ++i) + { + if (this->callbacks_[i].first == name) + { + return i; + } + } + + return -1; +} + +void html_frame::invoke_callback(const int id, callback_params* params) +{ + if (id >= 0 && static_cast(id) < this->callbacks_.size()) + { + this->callbacks_[id].second(params); + } +} + +void html_frame::register_callback(const std::string& name, const std::function& callback) +{ + this->callbacks_.emplace_back(name, callback); +} diff --git a/src/launcher/html_frame.hpp b/src/launcher/html_frame.hpp new file mode 100644 index 0000000..fcb2cc8 --- /dev/null +++ b/src/launcher/html_frame.hpp @@ -0,0 +1,65 @@ +#pragma once +#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" +#include "html/html_dispatch.hpp" +#include "html/html_argument.hpp" + +class html_frame final +{ +public: + class callback_params final + { + public: + callback_params(DISPPARAMS* params, VARIANT* res); + + std::vector arguments; + html_argument result; + }; + + html_frame(); + ~html_frame(); + + void initialize(const HWND window); + + void resize(DWORD width, DWORD height) const; + bool load_url(const std::string& url) const; + bool load_html(const std::string& html) const; + + HWND get_window() const; + + std::shared_ptr get_browser_object() const; + std::shared_ptr get_web_browser() const; + std::shared_ptr get_dispatch() const; + std::shared_ptr get_document() 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(); + html_dispatch* get_html_dispatch(); + + int get_callback_id(const std::string& name); + void invoke_callback(int id, callback_params* params); + + void register_callback(const std::string& name, const std::function& callback); + +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_; + html_dispatch html_dispatch_; + + std::vector>> callbacks_; + + void create_browser(); + void initialize_browser(); + + static void set_browser_feature(const std::string& feature, DWORD value); + static void object_deleter(IUnknown* object); +}; 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..9338726 100644 --- a/src/launcher/launcher.cpp +++ b/src/launcher/launcher.cpp @@ -1,19 +1,29 @@ #include #include "launcher.hpp" +#include "html_frame.hpp" +#include "utils/nt.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->html_frame_.register_callback("selectMode", [this](html_frame::callback_params* params) + { + if(params->arguments.empty()) return; + + const auto param = params->arguments[0]; + if(!param.is_number()) return; + + const auto number = param.get_number(); + if(number == singleplayer || number == multiplayer) + { + this->select_mode(static_cast(number)); + } + }); + + this->window_.create("Open-IW5", 615, 300); + this->html_frame_.load_html(load_content()); } launcher::mode launcher::run() const @@ -25,27 +35,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); @@ -57,64 +56,13 @@ void launcher::select_mode(const mode mode) this->window_.close(); } -void launcher::draw_text(const HDC hdc) +std::string launcher::load_content() { - 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(); + const auto res = FindResource(::utils::nt::module(), MAKEINTRESOURCE(MAIN_MENU), RT_RCDATA); + if (!res) return {}; - std::wstring sp(L"Singleplayer"); - std::wstring mp(L"Multiplayer"); + const auto handle = LoadResource(nullptr, res); + if (!handle) return {}; - 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); + return std::string(LPSTR(LockResource(handle)), SizeofResource(nullptr, res)); } diff --git a/src/launcher/launcher.hpp b/src/launcher/launcher.hpp index ff25d08..9f3e880 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,10 @@ 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); + static std::string load_content(); }; diff --git a/src/launcher/window.cpp b/src/launcher/window.cpp index adfd7cf..06af416 100644 --- a/src/launcher/window.cpp +++ b/src/launcher/window.cpp @@ -1,36 +1,32 @@ #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); - - SetWindowLongPtrA(*this, GWLP_USERDATA, LONG_PTR(this)); + height, nullptr, nullptr, this->wc_.hInstance, this); } window::~window() @@ -38,8 +34,6 @@ window::~window() this->close(); UnregisterClass(this->wc_.lpszClassName, this->wc_.hInstance); DeleteObject(this->wc_.hbrBackground); - - Gdiplus::GdiplusShutdown(this->token_); } void window::close() @@ -53,25 +47,13 @@ void window::close() void window::run() const { MSG msg; - while (this->handle_ && IsWindow(*this)) + while (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); + //if(!this->handle_) break; + } } void window::set_callback(const std::function& callback) @@ -81,6 +63,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 +85,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/main.cpp b/src/main.cpp index afc91b9..1a94d49 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -55,7 +55,11 @@ int main() utils::nt::module self; const auto mode = launcher.run(); - if (mode == launcher::mode::none) return 0; + if (mode == launcher::mode::none) + { + module_loader::pre_destroy(); + return 0; + } loader loader(mode); loader.set_import_resolver([self](const std::string& module, const std::string& function) -> FARPROC @@ -81,6 +85,7 @@ int main() catch (std::exception& e) { MessageBoxA(nullptr, e.what(), "ERROR", MB_ICONERROR); + module_loader::pre_destroy(); return 1; } 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 + + + + + + Open-IW5 + + + + + +
+
+ Singleplayer + +
+ +
+ Multiplayer + +
+
+ + + + + \ No newline at end of file diff --git a/src/resources/multiplayer.bmp b/src/resources/multiplayer.bmp deleted file mode 100644 index 63a99d3..0000000 Binary files a/src/resources/multiplayer.bmp and /dev/null differ diff --git a/src/resources/singleplayer.bmp b/src/resources/singleplayer.bmp deleted file mode 100644 index 440e3b8..0000000 Binary files a/src/resources/singleplayer.bmp and /dev/null differ diff --git a/src/std_include.cpp b/src/std_include.cpp index 45f7a4d..26ca2df 100644 --- a/src/std_include.cpp +++ b/src/std_include.cpp @@ -7,6 +7,8 @@ #pragma comment(linker, "/section:.main,re") #pragma comment(linker, "/base:0x400000") +#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") + // Moved to main.cpp to enforce early linking //__declspec(thread) char tls_data[TLS_PAYLOAD_SIZE]; diff --git a/src/std_include.hpp b/src/std_include.hpp index 10c5560..c2373fb 100644 --- a/src/std_include.hpp +++ b/src/std_include.hpp @@ -9,9 +9,9 @@ #define WIN32_LEAN_AND_MEAN #include -#include -#include -#include +#include +#include +#include #include #include #include @@ -41,6 +41,8 @@ #include #include +#include + #pragma comment (lib, "gdiplus.lib") #pragma comment(lib, "ws2_32.lib")