Create basic html based launcher

This commit is contained in:
momo5502 2019-01-05 17:32:34 +01:00
parent 95972929f2
commit a3a04079e4
15 changed files with 433 additions and 47 deletions

View File

@ -88,8 +88,8 @@ HRESULT doc_host_ui_handler::GetDropTarget(IDropTarget* /*pDropTarget*/, IDropTa
HRESULT doc_host_ui_handler::GetExternal(IDispatch** ppDispatch)
{
*ppDispatch = nullptr;
return S_FALSE;
*ppDispatch = this->frame_->get_html_dispatch();
return (*ppDispatch) ? S_OK : S_FALSE;
}
HRESULT doc_host_ui_handler::FilterDataObject(IDataObject* /*pDO*/, IDataObject** ppDORet)

View File

@ -0,0 +1,37 @@
#include <std_include.hpp>
#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;
}

View File

@ -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_;
};

View File

@ -0,0 +1,61 @@
#include <std_include.hpp>
#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, &params);
return S_OK;
}

View File

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

View File

@ -1,12 +1,25 @@
#include <std_include.hpp>
#include "html_frame.hpp"
#include "utils/nt.hpp"
html_frame::html_frame() : in_place_frame_(this), in_place_site_(this), ui_handler_(this), client_site_(this)
html_frame::callback_params::callback_params(DISPPARAMS* params, VARIANT* res) : result(res)
{
for (auto i = params->cArgs; i > 0; --i)
{
auto param = &params->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");
}
this->emulate_browser();
}
html_frame::~html_frame()
@ -14,6 +27,14 @@ 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_;
@ -44,21 +65,42 @@ 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<IWebBrowser2> html_frame::get_web_browser() const
{
IWebBrowser2* web_browser;
if (!this->browser_object_->QueryInterface(IID_IWebBrowser2, reinterpret_cast<void**>(&web_browser)))
{
return std::shared_ptr<IWebBrowser2>(web_browser, [](IWebBrowser2* web_browser)
{
if (web_browser)
{
web_browser->Release();
}
});
}
if (!this->browser_object_) return {};
return {};
IWebBrowser2* web_browser = nullptr;
if (this->browser_object_->QueryInterface(IID_IWebBrowser2, reinterpret_cast<void**>(&web_browser)) || !web_browser)
return {};
return std::shared_ptr<IWebBrowser2>(web_browser, object_deleter);
}
std::shared_ptr<IDispatch> 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<IDispatch>(dispatch, object_deleter);
}
std::shared_ptr<IHTMLDocument2> html_frame::get_document() const
{
const auto dispatch = this->get_dispatch();
if (!dispatch) return {};
IHTMLDocument2* document = nullptr;
if (dispatch->QueryInterface(IID_IHTMLDocument2, reinterpret_cast<void**>(&document)) || !document) return {};
return std::shared_ptr<IHTMLDocument2>(document, object_deleter);
}
void html_frame::initialize(const HWND window)
@ -93,7 +135,7 @@ void html_frame::create_browser()
if (browser_object)
{
browser_object->Close(OLECLOSE_NOSAVE);
browser_object->Release();
object_deleter(browser_object);
}
});
}
@ -111,6 +153,22 @@ void html_frame::initialize_browser()
this->resize(rect.right, rect.bottom);
}
void html_frame::emulate_browser()
{
utils::nt::module self;
HKEY key = nullptr;
if (RegOpenKeyExA(
HKEY_CURRENT_USER, R"(SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION)", 0,
KEY_ALL_ACCESS, &key) != ERROR_SUCCESS) return;
DWORD value = 11001;
const auto name = self.get_name();
RegSetValueExA(key, name.data(), 0, REG_DWORD, reinterpret_cast<const BYTE*>(&value), sizeof(value));
RegCloseKey(key);
}
void html_frame::resize(const DWORD width, const DWORD height) const
{
auto web_browser = this->get_web_browser();
@ -123,20 +181,74 @@ void html_frame::resize(const DWORD width, const DWORD height) const
}
}
void html_frame::load_url(std::string url) const
bool html_frame::load_url(const std::string& url) const
{
auto web_browser = this->get_web_browser();
if (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<void**>(&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)
{
std::wstring wide_url(url.begin(), url.end());
if (this->callbacks_[i].first == name)
{
return i;
}
}
VARIANT my_url;
VariantInit(&my_url);
my_url.vt = VT_BSTR;
my_url.bstrVal = SysAllocString(wide_url.data());
return -1;
}
web_browser->Navigate2(&my_url, nullptr, nullptr, nullptr, nullptr);
VariantClear(&my_url);
void html_frame::invoke_callback(const int id, callback_params* params)
{
if (id >= 0 && static_cast<unsigned int>(id) < this->callbacks_.size())
{
this->callbacks_[id].second(params);
}
}
void html_frame::register_callback(const std::string& name, const std::function<void(callback_params*)>& callback)
{
this->callbacks_.emplace_back(name, callback);
}

View File

@ -1,30 +1,49 @@
#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"
#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<html_argument> arguments;
html_argument result;
};
html_frame();
~html_frame();
void initialize(const HWND window);
void resize(DWORD width, DWORD height) const;
void load_url(std::string url) const;
bool load_url(const std::string& url) const;
bool load_html(const std::string& html) const;
HWND get_window() const;
std::shared_ptr<IOleObject> get_browser_object() const;
std::shared_ptr<IWebBrowser2> get_web_browser() const;
std::shared_ptr<IDispatch> get_dispatch() const;
std::shared_ptr<IHTMLDocument2> 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<void(callback_params*)>& callback);
private:
HWND window_ = nullptr;
@ -34,7 +53,13 @@ private:
ole_in_place_site in_place_site_;
doc_host_ui_handler ui_handler_;
ole_client_site client_site_;
html_dispatch html_dispatch_;
std::vector<std::pair<std::string, std::function<void(callback_params*)>>> callbacks_;
void create_browser();
void initialize_browser();
static void emulate_browser();
static void object_deleter(IUnknown* object);
};

View File

@ -1,14 +1,29 @@
#include <std_include.hpp>
#include "launcher.hpp"
#include "html_frame.hpp"
#include "utils/nt.hpp"
launcher::launcher()
{
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<mode>(number));
}
});
this->window_.create("Open-IW5", 615, 300);
this->html_frame_.load_url("https://google.com");
this->html_frame_.load_html(load_content());
}
launcher::mode launcher::run() const
@ -40,3 +55,14 @@ void launcher::select_mode(const mode mode)
this->mode_ = mode;
this->window_.close();
}
std::string launcher::load_content()
{
const auto res = FindResource(::utils::nt::module(), MAKEINTRESOURCE(MAIN_MENU), RT_RCDATA);
if (!res) return {};
const auto handle = LoadResource(nullptr, res);
if (!handle) return {};
return std::string(LPSTR(LockResource(handle)), SizeofResource(nullptr, res));
}

View File

@ -25,4 +25,6 @@ private:
LRESULT handler(const UINT message, const WPARAM w_param, const LPARAM l_param);
void select_mode(mode mode);
static std::string load_content();
};

View File

@ -27,9 +27,6 @@ void window::create(const std::string& title, const int width, const int height)
this->handle_ = CreateWindowExA(NULL, this->wc_.lpszClassName, title.data(),
(WS_OVERLAPPEDWINDOW | WS_VISIBLE) & ~(WS_THICKFRAME | WS_MAXIMIZEBOX), x, y, width,
height, nullptr, nullptr, this->wc_.hInstance, this);
ShowWindow(this->handle_, SW_SHOW);
UpdateWindow(this->handle_);
}
window::~window()
@ -50,10 +47,12 @@ void window::close()
void window::run() const
{
MSG msg;
while (this->handle_ && IsWindow(*this) && GetMessage(&msg, nullptr, 0, 0))
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
//if(!this->handle_) break;
}
}

View File

@ -1,15 +1,14 @@
#pragma once
#define IMAGE_SP 300
#define IMAGE_MP 301
#define BINARY_SP 302
#define BINARY_MP 303
#define MAIN_MENU 300
#define BINARY_SP 301
#define BINARY_MP 302
#define DW_HEATMAP 304
#define DW_MOTD 305
#define DW_IMG 306
#define DW_WAD 307
#define DW_PLAYLIST 308
#define DW_CONFIG 309
#define DW_IOTD_TXT 310
#define DW_IOTD_IMG 311
#define DW_HEATMAP 303
#define DW_MOTD 304
#define DW_IMG 305
#define DW_WAD 306
#define DW_PLAYLIST 307
#define DW_CONFIG 308
#define DW_IOTD_TXT 309
#define DW_IOTD_IMG 310

View File

@ -83,8 +83,8 @@ END
//
102 ICON "resources/icon.ico"
IMAGE_SP BITMAP "resources/singleplayer.bmp"
IMAGE_MP BITMAP "resources/multiplayer.bmp"
MAIN_MENU RCDATA "resources/main.html"
BINARY_SP RCDATA "resources/iw5sp.exe.diff"
BINARY_MP RCDATA "resources/iw5mp.exe.diff"

83
src/resources/main.html Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 169 KiB