Prepare launcher

This commit is contained in:
momo5502 2023-01-30 18:47:51 +01:00
parent f2924eee05
commit e60ffbc9ee
24 changed files with 1733 additions and 8 deletions

View File

@ -0,0 +1,19 @@
#pragma once
class dispatch : public IDispatch
{
public:
virtual ~dispatch() = default;
HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT* pctinfo) override
{
return S_FALSE;
}
HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) override
{
return S_FALSE;
}
};

View File

@ -0,0 +1,92 @@
#pragma once
class doc_host_ui_handler /*_boilerplate*/ : public IDocHostUIHandler
{
public:
virtual ~doc_host_ui_handler() = default;
HRESULT STDMETHODCALLTYPE ShowContextMenu(
DWORD,
POINT*,
IUnknown*,
IDispatch*) override
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE ShowUI(
DWORD,
IOleInPlaceActiveObject*,
IOleCommandTarget*,
IOleInPlaceFrame*,
IOleInPlaceUIWindow*) override
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE HideUI() override
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE UpdateUI() override
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE EnableModeless(BOOL) override
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnDocWindowActivate(BOOL) override
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnFrameWindowActivate(BOOL) override
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE ResizeBorder(
LPCRECT,
IOleInPlaceUIWindow*,
BOOL) override
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE TranslateAccelerator(
LPMSG,
const GUID*,
DWORD) override
{
return S_FALSE;
}
HRESULT STDMETHODCALLTYPE GetOptionKeyPath(LPOLESTR __RPC_FAR* pchKey, DWORD dw) override
{
return S_FALSE;
}
HRESULT STDMETHODCALLTYPE GetDropTarget(
IDropTarget*,
IDropTarget**) override
{
return S_FALSE;
}
HRESULT STDMETHODCALLTYPE TranslateUrl(DWORD, OLECHAR*, OLECHAR** ppchURLOut) override
{
*ppchURLOut = nullptr;
return S_FALSE;
}
HRESULT STDMETHODCALLTYPE FilterDataObject(IDataObject*, IDataObject** ppDORet) override
{
*ppDORet = nullptr;
return S_FALSE;
}
};

View File

@ -0,0 +1,79 @@
#include <std_include.hpp>
#include "html_argument.hpp"
html_argument::html_argument(VARIANT* val)
: html_argument(*val)
{
}
html_argument::html_argument(CComVariant val)
: value_(std::move(val))
{
}
bool html_argument::is_empty() const
{
return 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;
}
bool html_argument::is_bool() const
{
if (this->is_empty()) return false;
return this->value_.vt == VT_BOOL;
}
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;
}
bool html_argument::get_bool() const
{
if (!this->is_bool()) return false;
return this->value_.boolVal != FALSE;
}
void html_argument::copy_to(VARIANT& var) const
{
if (this->is_empty())
{
VariantInit(&var);
}
else
{
(void)VariantCopy(&var, &this->value_);
}
}
void html_argument::move_to(VARIANT* var)
{
if (!var)
{
return;
}
VARIANT& src_var = this->value_;
memcpy(var, &src_var, sizeof(*var));
VariantInit(&this->value_);
}

View File

@ -0,0 +1,32 @@
#pragma once
#pragma once
class html_argument final
{
public:
html_argument() = default;
html_argument(VARIANT* val);
html_argument(CComVariant val);
bool is_empty() const;
bool is_string() const;
bool is_number() const;
bool is_bool() const;
std::string get_string() const;
int get_number() const;
bool get_bool() const;
const CComVariant& get() const
{
return this->value_;
}
void copy_to(VARIANT& var) const;
void move_to(VARIANT* var);
private:
CComVariant value_{};
};

View File

@ -0,0 +1,371 @@
#include <std_include.hpp>
#include "html_frame.hpp"
#include "utils/nt.hpp"
#include "utils/hook.hpp"
namespace
{
void* original_func{};
GUID browser_emulation_guid{0xac969931, 0x3566, 0x4b50, {0xae, 0x48, 0x71, 0xb9, 0x6a, 0x75, 0xc8, 0x79}};
int WINAPI co_internet_feature_value_internal_stub(const GUID* guid, uint32_t* result)
{
const auto res = static_cast<decltype(co_internet_feature_value_internal_stub)*>(original_func)(guid, result);
if (IsEqualGUID(*guid, browser_emulation_guid))
{
*result = 11000;
return 0;
}
return res;
}
void setup_ie_hook()
{
static const auto _ = []
{
const auto urlmon = utils::nt::library::load("urlmon.dll"s);
const auto target = urlmon.get_iat_entry("iertutil.dll", MAKEINTRESOURCEA(700));
original_func = *target;
utils::hook::set(target, co_internet_feature_value_internal_stub);
return 0;
}();
(void)_;
}
void setup_ole()
{
static struct ole_initialzer
{
ole_initialzer()
{
if (OleInitialize(nullptr) != S_OK)
{
throw std::runtime_error("Unable to initialize the OLE library");
}
}
~ole_initialzer()
{
OleUninitialize();
}
} init;
(void)init;
}
}
html_frame::html_frame()
{
setup_ie_hook();
setup_ole();
}
HRESULT html_frame::GetHostInfo(DOCHOSTUIINFO* pInfo)
{
pInfo->cbSize = sizeof(DOCHOSTUIINFO);
pInfo->dwFlags = DOCHOSTUIFLAG_NO3DBORDER | DOCHOSTUIFLAG_DPI_AWARE | DOCHOSTUIFLAG_SCROLL_NO;
pInfo->dwDoubleClick = DOCHOSTUIDBLCLK_DEFAULT;
return S_OK;
}
HRESULT html_frame::GetWindow(HWND* lphwnd)
{
*lphwnd = this->window_;
return S_OK;
}
HRESULT html_frame::QueryInterface(REFIID riid, void** ppvObject)
{
if (IsEqualGUID(riid, IID_IDispatch))
{
*ppvObject = static_cast<IDispatch*>(this);
return S_OK;
}
if (IsEqualGUID(riid, IID_IDispatch))
{
const auto d = get_dispatch();
if (!d)
{
return E_NOINTERFACE;
}
(*d).AddRef();
*ppvObject = &*d;
return S_OK;
}
if (IsEqualGUID(riid, IID_IServiceProvider))
{
*ppvObject = static_cast<IServiceProvider*>(this);
return S_OK;
}
if (IsEqualGUID(riid, IID_IInternetSecurityManager))
{
*ppvObject = static_cast<IInternetSecurityManager*>(this);
return S_OK;
}
if (IsEqualGUID(riid, IID_IUnknown))
{
*ppvObject = static_cast<IUnknown*>(static_cast<IOleClientSite*>(this));
return S_OK;
}
if (IsEqualGUID(riid, IID_IOleClientSite))
{
*ppvObject = static_cast<IOleClientSite*>(this);
return S_OK;
}
if (IsEqualGUID(riid, IID_IOleInPlaceSite))
{
*ppvObject = static_cast<IOleInPlaceSite*>(this);
return S_OK;
}
if (IsEqualGUID(riid, IID_IOleInPlaceFrame))
{
*ppvObject = static_cast<IOleInPlaceFrame*>(this);
return S_OK;
}
if (IsEqualGUID(riid, IID_IDocHostUIHandler))
{
*ppvObject = static_cast<IDocHostUIHandler*>(this);
return S_OK;
}
if (IsEqualGUID(riid, IID_IOleInPlaceObject) && this->browser_object_)
{
return this->browser_object_->QueryInterface(riid, ppvObject);
}
*ppvObject = nullptr;
return E_NOINTERFACE;
}
HWND html_frame::get_window() const
{
return this->window_;
}
CComPtr<IOleObject> html_frame::get_browser_object() const
{
return this->browser_object_;
}
CComPtr<IWebBrowser2> html_frame::get_web_browser() const
{
CComPtr<IWebBrowser2> web_browser{};
if (!this->browser_object_ || FAILED(this->browser_object_.QueryInterface(&web_browser)))
{
return {};
}
return web_browser;
}
CComPtr<IDispatch> html_frame::get_dispatch() const
{
const auto web_browser = this->get_web_browser();
CComPtr<IDispatch> dispatch{};
if (!web_browser || FAILED(web_browser->get_Document(&dispatch)))
{
return {};
}
return dispatch;
}
CComPtr<IHTMLDocument2> html_frame::get_document() const
{
const auto dispatch = this->get_dispatch();
CComPtr<IHTMLDocument2> document{};
if (!dispatch || FAILED(dispatch.QueryInterface(&document)))
{
return {};
}
return document;
}
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()
{
CComPtr<IClassFactory> class_factory{};
if (FAILED(
CoGetClassObject(CLSID_WebBrowser, CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, nullptr, IID_IClassFactory,
reinterpret_cast<void **>(&class_factory))))
{
throw std::runtime_error("Unable to get the class factory");
}
class_factory->CreateInstance(nullptr, IID_IOleObject, reinterpret_cast<void**>(&this->browser_object_));
if (!this->browser_object_)
{
throw std::runtime_error("Unable to create browser object");
}
}
void html_frame::initialize_browser()
{
this->browser_object_->SetClientSite(this);
this->browser_object_->SetHostNames(L"Hostname", nullptr);
RECT rect;
GetClientRect(this->get_window(), &rect);
OleSetContainedObject(this->browser_object_, TRUE);
this->browser_object_->DoVerb(OLEIVERB_SHOW, nullptr, this, -1, this->get_window(), &rect);
this->resize(rect.right, rect.bottom);
}
void html_frame::resize(const DWORD width, const DWORD height) const
{
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;
CComVariant my_url(url.data());
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;
CComSafeArrayBound bound{};
bound.SetCount(1);
bound.SetLowerBound(0);
CComSafeArray<VARIANT> array(&bound, 1);
array[0] = CComVariant(html.data());
document->write(array);
document->close();
return true;
}
html_argument html_frame::evaluate(const std::string& javascript) const
{
auto dispDoc = this->get_dispatch();
CComPtr<IHTMLDocument2> htmlDoc;
dispDoc->QueryInterface(&htmlDoc);
CComPtr<IHTMLWindow2> htmlWindow;
htmlDoc->get_parentWindow(&htmlWindow);
CComDispatchDriver dispWindow;
htmlWindow->QueryInterface(&dispWindow);
CComPtr<IDispatchEx> dispexWindow;
htmlWindow->QueryInterface(&dispexWindow);
DISPID dispidEval = -1;
dispexWindow->GetDispID(CComBSTR("eval"), fdexNameCaseSensitive, &dispidEval);
CComVariant result{};
CComVariant code(javascript.data());
(void)dispWindow.Invoke1(dispidEval, &code, &result);
return result;
}
int html_frame::get_callback_id(const std::string& name) const
{
for (auto i = 0u; i < this->callbacks_.size(); ++i)
{
if (this->callbacks_[i].first == name)
{
return i;
}
}
return -1;
}
html_argument html_frame::invoke_callback(const int id, const std::vector<html_argument>& params) const
{
if (id >= 0 && static_cast<unsigned int>(id) < this->callbacks_.size())
{
return this->callbacks_[id].second(params);
}
return {};
}
void html_frame::register_callback(const std::string& name, const std::function<CComVariant(const std::vector<html_argument>&)>& callback)
{
this->callbacks_.emplace_back(name, callback);
}
HRESULT html_frame::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->get_callback_id(name);
}
return S_OK;
}
HRESULT html_frame::Invoke(const DISPID dispIdMember, const IID& /*riid*/, LCID /*lcid*/, WORD /*wFlags*/,
DISPPARAMS* pDispParams,
VARIANT* pVarResult, EXCEPINFO* /*pExcepInfo*/, UINT* /*puArgErr*/)
{
std::vector<html_argument> params{};
for (auto i = pDispParams->cArgs; i > 0; --i)
{
auto& param = pDispParams->rgvarg[i - 1];
params.emplace_back(param);
}
auto res = this->invoke_callback(dispIdMember, params);
res.move_to(pVarResult);
return S_OK;
}
HRESULT html_frame::GetExternal(IDispatch** ppDispatch)
{
*ppDispatch = this;
return *ppDispatch ? S_OK : S_FALSE;
}

View File

@ -0,0 +1,82 @@
#pragma once
#include "ole_in_place_frame.hpp"
#include "ole_in_place_site.hpp"
#include "doc_host_ui_handler.hpp"
#include "ole_client_site.hpp"
#include "service_provider.hpp"
#include "internet_security_manager.hpp"
#include "dispatch.hpp"
#include "html_argument.hpp"
class html_frame
: doc_host_ui_handler
, service_provider
, internet_security_manager
, ole_client_site
, ole_in_place_frame
, ole_in_place_site
, dispatch
{
public:
html_frame();
html_frame(const html_frame&) = delete;
html_frame& operator=(const html_frame&) = delete;
html_frame(html_frame&&) = delete;
html_frame& operator=(html_frame&&) = delete;
~html_frame() override = default;
void initialize(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;
html_argument evaluate(const std::string& javascript) const;
HWND get_window() const;
CComPtr<IOleObject> get_browser_object() const;
CComPtr<IWebBrowser2> get_web_browser() const;
CComPtr<IDispatch> get_dispatch() const;
CComPtr<IHTMLDocument2> get_document() const;
int get_callback_id(const std::string& name) const;
html_argument invoke_callback(int id, const std::vector<html_argument>& params) const;
void register_callback(const std::string& name, const std::function<CComVariant(const std::vector<html_argument>&)>& callback);
HRESULT STDMETHODCALLTYPE QueryInterface(
REFIID riid,
void** ppvObject) override;
private:
HWND window_ = nullptr;
CComPtr<IOleObject> browser_object_;
std::vector<std::pair<std::string, std::function<html_argument(const std::vector<html_argument>&)>>> callbacks_;
void create_browser();
void initialize_browser();
HRESULT STDMETHODCALLTYPE GetHostInfo(DOCHOSTUIINFO* pInfo) override;
HRESULT STDMETHODCALLTYPE GetWindow(HWND* lphwnd) override;
ULONG STDMETHODCALLTYPE AddRef() override
{
return 1;
}
ULONG STDMETHODCALLTYPE Release() override
{
return 1;
}
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;
HRESULT STDMETHODCALLTYPE GetExternal(IDispatch** ppDispatch) override;
};

View File

@ -0,0 +1,37 @@
#include <std_include.hpp>
#include "html_window.hpp"
html_window::html_window(const std::string& title, int width, int height, long flags)
: window_(title, width, height,
[this](window*, const UINT message, const WPARAM w_param, const LPARAM l_param) -> std::optional<LRESULT> {
return this->processor(message, w_param, l_param);
}, flags)
{
}
window* html_window::get_window()
{
return &this->window_;
}
html_frame* html_window::get_html_frame()
{
return &this->frame_;
}
std::optional<LRESULT> html_window::processor(const UINT message, const WPARAM w_param, const LPARAM l_param)
{
if (message == WM_SIZE)
{
this->frame_.resize(LOWORD(l_param), HIWORD(l_param));
return 0;
}
if (message == WM_CREATE)
{
this->frame_.initialize(this->window_);
return 0;
}
return {};
}

View File

@ -0,0 +1,21 @@
#pragma once
#include "../window.hpp"
#include "html_frame.hpp"
class html_window final
{
public:
html_window(const std::string& title, int width, int height,
long flags = (WS_OVERLAPPEDWINDOW & ~(WS_THICKFRAME | WS_MAXIMIZEBOX)));
~html_window() = default;
window* get_window();
html_frame* get_html_frame();
private:
html_frame frame_{};
window window_;
std::optional<LRESULT> processor(UINT message, WPARAM w_param, LPARAM l_param);
};

View File

@ -0,0 +1,76 @@
#pragma once
class internet_security_manager : public IInternetSecurityManager
{
public:
HRESULT STDMETHODCALLTYPE SetSecuritySite(
IInternetSecurityMgrSite*) override
{
return INET_E_DEFAULT_ACTION;
}
virtual HRESULT STDMETHODCALLTYPE GetSecuritySite(
IInternetSecurityMgrSite**) override
{
return INET_E_DEFAULT_ACTION;
}
virtual HRESULT STDMETHODCALLTYPE MapUrlToZone(
LPCWSTR,
DWORD* pdwZone,
DWORD) override
{
*pdwZone = URLZONE_TRUSTED;
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE GetSecurityId(
LPCWSTR,
BYTE*,
DWORD*,
DWORD_PTR) override
{
return INET_E_DEFAULT_ACTION;
}
virtual HRESULT STDMETHODCALLTYPE ProcessUrlAction(
LPCWSTR,
DWORD,
BYTE*,
DWORD,
BYTE*,
DWORD,
DWORD,
DWORD) override
{
return INET_E_DEFAULT_ACTION;
}
virtual HRESULT STDMETHODCALLTYPE QueryCustomPolicy(
LPCWSTR,
REFGUID,
BYTE**,
DWORD*,
BYTE*,
DWORD,
DWORD) override
{
return INET_E_DEFAULT_ACTION;
}
HRESULT STDMETHODCALLTYPE SetZoneMapping(
DWORD,
LPCWSTR,
DWORD) override
{
return INET_E_DEFAULT_ACTION;
}
HRESULT STDMETHODCALLTYPE GetZoneMappings(
DWORD,
IEnumString**,
DWORD) override
{
return INET_E_DEFAULT_ACTION;
}
};

View File

@ -0,0 +1,38 @@
#pragma once
class ole_client_site : public IOleClientSite
{
public:
virtual ~ole_client_site() = default;
HRESULT STDMETHODCALLTYPE SaveObject() override
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE GetMoniker(DWORD, DWORD, IMoniker**) override
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE GetContainer(LPOLECONTAINER* ppContainer) override
{
*ppContainer = nullptr;
return E_NOINTERFACE;
}
HRESULT STDMETHODCALLTYPE ShowObject() override
{
return NOERROR;
}
HRESULT STDMETHODCALLTYPE OnShowWindow(BOOL) override
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE RequestNewObjectLayout() override
{
return E_NOTIMPL;
}
};

View File

@ -0,0 +1,62 @@
#pragma once
class ole_in_place_frame : public IOleInPlaceFrame
{
public:
virtual ~ole_in_place_frame() = default;
HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL) override
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE GetBorder(LPRECT) override
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE RequestBorderSpace(LPCBORDERWIDTHS) override
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE SetBorderSpace(LPCBORDERWIDTHS) override
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE SetActiveObject(IOleInPlaceActiveObject* pActiveObject, LPCOLESTR pszObjName) override
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE InsertMenus(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths) override
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE SetMenu(HMENU, HOLEMENU, HWND) override
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE RemoveMenus(HMENU hmenuShared) override
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE SetStatusText(LPCOLESTR) override
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE EnableModeless(BOOL) override
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE TranslateAccelerator(LPMSG lpmsg, WORD wID) override
{
return E_NOTIMPL;
}
};

View File

@ -0,0 +1,89 @@
#pragma once
class ole_in_place_site : public IOleInPlaceSite
{
public:
virtual ~ole_in_place_site() = default;
HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL) override
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE CanInPlaceActivate() override
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnInPlaceActivate() override
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnUIActivate() override
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE GetWindowContext(LPOLEINPLACEFRAME* lplpFrame, LPOLEINPLACEUIWINDOW* lplpDoc,
const LPRECT lprcPosRect, const LPRECT lprcClipRect,
const LPOLEINPLACEFRAMEINFO lpFrameInfo) override
{
ZeroMemory(lprcPosRect, sizeof(*lprcPosRect));
ZeroMemory(lprcClipRect, sizeof(*lprcClipRect));
CComPtr<IOleInPlaceFrame> ole_in_place_frame{};
if (FAILED(QueryInterface(IID_IOleInPlaceFrame, reinterpret_cast<void**>(&ole_in_place_frame))))
{
*lplpFrame = nullptr;
*lplpDoc = nullptr;
return E_FAIL;
}
*lplpFrame = ole_in_place_frame;
*lplpDoc = nullptr;
lpFrameInfo->fMDIApp = FALSE;
lpFrameInfo->haccel = nullptr;
lpFrameInfo->cAccelEntries = 0;
GetWindow(&lpFrameInfo->hwndFrame);
return S_OK;
}
HRESULT STDMETHODCALLTYPE Scroll(SIZE) override
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE OnUIDeactivate(BOOL) override
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnInPlaceDeactivate() override
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE DiscardUndoState() override
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE DeactivateAndUndo() override
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE OnPosRectChange(const LPCRECT lprcPosRect) override
{
CComPtr<IOleInPlaceObject> in_place{};
if (SUCCEEDED(QueryInterface(IID_IOleInPlaceObject, reinterpret_cast<void**>(&in_place))))
{
in_place->SetObjectRects(lprcPosRect, lprcPosRect);
}
return S_OK;
}
};

View File

@ -0,0 +1,22 @@
#pragma once
class service_provider : public IServiceProvider
{
public:
virtual ~service_provider() = default;
HRESULT STDMETHODCALLTYPE QueryService(
REFGUID guidService,
REFIID riid,
void** ppvObject) override
{
if (IsEqualGUID(riid, IID_IInternetSecurityManager))
{
return QueryInterface(riid, ppvObject);
}
*ppvObject = nullptr;
return E_NOINTERFACE;
}
};

View File

@ -0,0 +1,43 @@
#include <std_include.hpp>
#include <utils/nt.hpp>
#include "launcher.hpp"
#include "html/html_window.hpp"
#include "resource.hpp"
namespace launcher
{
bool run()
{
bool run_game = false;
html_window window("BOIII", 750, 430);
window.get_html_frame()->register_callback(
"openUrl", [](const std::vector<html_argument>& params) -> CComVariant
{
if (params.empty()) return {};
const auto& param = params[0];
if (!param.is_string()) return {};
const auto url = param.get_string();
ShellExecuteA(nullptr, "open", url.data(), nullptr, nullptr, SW_SHOWNORMAL);
return {};
});
window.get_html_frame()->register_callback(
"runGame", [&](const std::vector<html_argument>& /*params*/) -> CComVariant
{
run_game = true;
window.get_window()->close();
return {};
});
window.get_html_frame()->load_html(utils::nt::load_resource(MENU_MAIN));
window::run();
return run_game;
}
}

View File

@ -0,0 +1,6 @@
#pragma once
namespace launcher
{
bool run();
}

View File

@ -0,0 +1,127 @@
#include <std_include.hpp>
#include "window.hpp"
namespace
{
thread_local uint32_t window_count = 0;
}
window::window(const std::string& title, const int width, const int height,
std::function<std::optional<LRESULT>(window*, UINT, WPARAM, LPARAM)> callback,
const long flags)
: callback_(std::move(callback))
{
ZeroMemory(&this->wc_, sizeof(this->wc_));
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 = GetModuleHandle(nullptr);
this->wc_.hCursor = LoadCursor(nullptr, IDC_ARROW);
this->wc_.hIcon = LoadIcon(this->wc_.hInstance, MAKEINTRESOURCE(102));
this->wc_.hIconSm = this->wc_.hIcon;
this->wc_.hbrBackground = HBRUSH(COLOR_WINDOW);
this->wc_.lpszClassName = this->classname_.data();
RegisterClassEx(&this->wc_);
const auto x = (GetSystemMetrics(SM_CXSCREEN) - width) / 2;
const auto y = (GetSystemMetrics(SM_CYSCREEN) - height) / 2;
++window_count;
this->handle_ = CreateWindowExA(NULL, this->wc_.lpszClassName, title.data(), flags, x, y, width, height, nullptr,
nullptr, this->wc_.hInstance, this);
SendMessageA(this->handle_, WM_DPICHANGED, 0, 0);
ShowWindow(this->handle_, SW_SHOW);
}
window::~window()
{
this->close();
UnregisterClass(this->wc_.lpszClassName, this->wc_.hInstance);
}
void window::close()
{
if (!this->handle_) return;
DestroyWindow(this->handle_);
this->handle_ = nullptr;
}
void window::run()
{
MSG msg{};
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
LRESULT window::processor(const UINT message, const WPARAM w_param, const LPARAM l_param)
{
if (message == WM_DPICHANGED)
{
const auto dpi = GetDpiForWindow(*this);
if (dpi != this->last_dpi_)
{
RECT rect;
GetWindowRect(*this, &rect);
const auto scale = dpi * 1.0 / this->last_dpi_;
this->last_dpi_ = dpi;
const auto width = rect.right - rect.left;
const auto height = rect.bottom - rect.top;
MoveWindow(*this, rect.left, rect.top, int(width * scale), int(height * scale), TRUE);
}
}
if (message == WM_DESTROY)
{
if (--window_count == 0)
{
PostQuitMessage(0);
}
return TRUE;
}
if (this->callback_)
{
const auto res = this->callback_(this, message, w_param, l_param);
if (res)
{
return *res;
}
}
return DefWindowProc(*this, message, w_param, l_param);
}
LRESULT CALLBACK window::static_processor(HWND hwnd, UINT message, WPARAM w_param, LPARAM l_param)
{
if (message == WM_CREATE)
{
auto data = reinterpret_cast<LPCREATESTRUCT>(l_param);
SetWindowLongPtrA(hwnd, GWLP_USERDATA, LONG_PTR(data->lpCreateParams));
reinterpret_cast<window*>(data->lpCreateParams)->handle_ = hwnd;
}
const auto self = reinterpret_cast<window*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
if (self) return self->processor(message, w_param, l_param);
return DefWindowProc(hwnd, message, w_param, l_param);
}
window::operator HWND() const
{
return this->handle_;
}

View File

@ -0,0 +1,29 @@
#pragma once
class window
{
public:
window(const std::string& title, int width, int height,
std::function<std::optional<LRESULT>(window*, UINT, WPARAM, LPARAM)> callback,
long flags = (WS_OVERLAPPEDWINDOW & ~(WS_THICKFRAME | WS_MAXIMIZEBOX)));
virtual ~window();
void close();
operator HWND() const;
static void run();
LRESULT processor(UINT message, WPARAM w_param, LPARAM l_param);
private:
uint32_t last_dpi_ = 96;
WNDCLASSEX wc_{};
HWND handle_ = nullptr;
std::string classname_;
std::function<std::optional<LRESULT>(window*, UINT, WPARAM, LPARAM)> callback_;
static LRESULT CALLBACK static_processor(HWND hwnd, UINT message, WPARAM w_param, LPARAM l_param);
};

View File

@ -12,6 +12,7 @@
#include <steam/steam.hpp>
#include "game/game.hpp"
#include "launcher/launcher.hpp"
namespace
{
@ -172,11 +173,11 @@ namespace
void enable_dpi_awareness()
{
const utils::nt::library user32{ "user32.dll" };
const utils::nt::library user32{"user32.dll"};
const auto set_dpi = user32
? user32.get_proc<BOOL(WINAPI*)(DPI_AWARENESS_CONTEXT)>(
"SetProcessDpiAwarenessContext")
: nullptr;
? user32.get_proc<BOOL(WINAPI*)(DPI_AWARENESS_CONTEXT)>(
"SetProcessDpiAwarenessContext")
: nullptr;
if (set_dpi)
{
set_dpi(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
@ -209,6 +210,11 @@ namespace
{
remove_crash_file();
if (!launcher::run())
{
return 0;
}
const auto client_binary = "BlackOps3.exe"s;
const auto server_binary = "BlackOps3_UnrankedDedicatedServer.exe"s;
const auto has_server = !utils::io::file_exists(client_binary) || utils::flags::has_flag("dedicated");

View File

@ -13,3 +13,4 @@
#define DW_QOSCONFIG 307
#define TLS_DLL 308
#define MENU_MAIN 309

View File

@ -102,6 +102,8 @@ DW_FASTFILE RCDATA "resources/dw/core_ffotd_tu32_593.ff"
DW_KEYS RCDATA "resources/dw/keys.txt"
DW_QOSCONFIG RCDATA "resources/dw/qosconfig4.csv"
MENU_MAIN RCDATA "resources/main.html"
#ifdef _DEBUG
TLS_DLL RCDATA "../../build/bin/x64/Debug/tlsdll.dll"
#else

File diff suppressed because one or more lines are too long

View File

@ -47,6 +47,7 @@
#include <Psapi.h>
#include <urlmon.h>
#include <atlbase.h>
#include <atlsafe.h>
#include <iphlpapi.h>
#include <wincrypt.h>

View File

@ -72,6 +72,11 @@ namespace utils::nt
return &this->get_nt_headers()->OptionalHeader;
}
void** library::get_iat_entry(const std::string& module_name, std::string proc_name) const
{
return this->get_iat_entry(module_name, proc_name.data());
}
std::vector<PIMAGE_SECTION_HEADER> library::get_section_headers() const
{
std::vector<PIMAGE_SECTION_HEADER> headers;
@ -162,7 +167,7 @@ namespace utils::nt
return this->module_;
}
void** library::get_iat_entry(const std::string& module_name, const std::string& proc_name) const
void** library::get_iat_entry(const std::string& module_name, const char* proc_name) const
{
if (!this->is_valid()) return nullptr;

View File

@ -54,10 +54,16 @@ namespace utils::nt
[[nodiscard]] HMODULE get_handle() const;
template <typename T>
[[nodiscard]] T get_proc(const std::string& process) const
[[nodiscard]] T get_proc(const char* process) const
{
if (!this->is_valid()) T{};
return reinterpret_cast<T>(GetProcAddress(this->module_, process.data()));
return reinterpret_cast<T>(GetProcAddress(this->module_, process));
}
template <typename T>
[[nodiscard]] T get_proc(const std::string& process) const
{
return get_proc<T>(process.data());
}
template <typename T>
@ -97,7 +103,8 @@ namespace utils::nt
[[nodiscard]] PIMAGE_DOS_HEADER get_dos_header() const;
[[nodiscard]] PIMAGE_OPTIONAL_HEADER get_optional_header() const;
[[nodiscard]] void** get_iat_entry(const std::string& module_name, const std::string& proc_name) const;
[[nodiscard]] void** get_iat_entry(const std::string& module_name, std::string proc_name) const;
[[nodiscard]] void** get_iat_entry(const std::string& module_name, const char* proc_name) const;
private:
HMODULE module_;