Create basic html based launcher
This commit is contained in:
parent
95972929f2
commit
a3a04079e4
@ -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)
|
||||
|
37
src/launcher/html/html_argument.cpp
Normal file
37
src/launcher/html/html_argument.cpp
Normal 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;
|
||||
}
|
18
src/launcher/html/html_argument.hpp
Normal file
18
src/launcher/html/html_argument.hpp
Normal 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_;
|
||||
};
|
61
src/launcher/html/html_dispatch.cpp
Normal file
61
src/launcher/html/html_dispatch.cpp
Normal 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, ¶ms);
|
||||
return S_OK;
|
||||
}
|
24
src/launcher/html/html_dispatch.hpp
Normal file
24
src/launcher/html/html_dispatch.hpp
Normal 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;
|
||||
};
|
@ -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 = ¶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");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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();
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
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 |
Loading…
Reference in New Issue
Block a user