Skip to content

Instantly share code, notes, and snippets.

@caiorss
Created January 2, 2019 07:44
Show Gist options
  • Save caiorss/32900fc65b3f75a81dc60be1a1660f39 to your computer and use it in GitHub Desktop.
Save caiorss/32900fc65b3f75a81dc60be1a1660f39 to your computer and use it in GitHub Desktop.
Add scripting capability to your C++ project using Windows Script Host
#include <windows.h>
#include <objbase.h>
#include <activscp.h>
#include <atomic>
#include <cassert>
#include <cstdio>
class ScriptSite : public IActiveScriptSite
{
public:
HRESULT QueryInterface(REFIID interface_id, void **object) override
{
if (object == nullptr)
{
return E_POINTER;
}
if (interface_id == IID_IUnknown || interface_id == IID_IActiveScript)
{
*object = this;
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
ULONG AddRef() override
{
return ++reference_counter;
}
ULONG Release() override
{
if (--reference_counter == 0)
{
delete this;
return 0;
}
return reference_counter;
}
HRESULT STDMETHODCALLTYPE GetLCID(LCID *local_id) override
{
(void)local_id;
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE GetItemInfo(LPCOLESTR item_name,
DWORD return_mask,
IUnknown **item,
ITypeInfo **type_info) override
{
(void)item_name;
(void)return_mask;
(void)item;
(void)type_info;
return TYPE_E_ELEMENTNOTFOUND;
}
HRESULT STDMETHODCALLTYPE GetDocVersionString(BSTR *document_version) override
{
(void)document_version;
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnScriptTerminate(const VARIANT *result, const EXCEPINFO *exception_information) override
{
(void)result;
(void)exception_information;
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnStateChange(SCRIPTSTATE script_state) override
{
(void)script_state;
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnScriptError(IActiveScriptError *script_error) override
{
(void)script_error;
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnEnterScript() override
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnLeaveScript() override
{
return S_OK;
}
private:
virtual ~ScriptSite() = default;
std::atomic<DWORD> reference_counter {1};
};
int main()
{
HRESULT hr;
hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
assert(SUCCEEDED(hr));
CLSID script_class_id;
hr = CLSIDFromProgID(L"JScript", &script_class_id);
assert(SUCCEEDED(hr));
IActiveScript *active_script;
hr = CoCreateInstance(script_class_id, nullptr, CLSCTX_SERVER, IID_IActiveScript, reinterpret_cast<void **>(&active_script));
assert(SUCCEEDED(hr));
IActiveScriptSite *active_script_site = new ScriptSite;
hr = active_script->SetScriptSite(active_script_site);
assert(SUCCEEDED(hr));
active_script_site->Release();
// uuid.lib on MinGW does not export IID_IActiveScriptParse* class IDs
#if 1
const GUID IID_IActiveScriptParse64_MingwFix {0xc7ef7658, 0xe1ee, 0x480e, {0x97, 0xea, 0xd5, 0x2c, 0xb4, 0xd7, 0x6d, 0x17}};
#elif 0
const GUID IID_IActiveScriptParse32_MingwFix {0xbb1a2ae2, 0xa4f9, 0x11cf, {0x8f, 0x20, 0x00, 0x80, 0x5f, 0x2c, 0xd0, 0x64}};
#endif
IActiveScriptParse *active_script_parse;
hr = active_script->QueryInterface(IID_IActiveScriptParse64_MingwFix, reinterpret_cast<void **>(&active_script_parse));
assert(SUCCEEDED(hr));
hr = active_script_parse->InitNew();
assert(SUCCEEDED(hr));
VARIANT result;
VariantInit(&result);
EXCEPINFO exception_information;
hr = active_script_parse->ParseScriptText(L"(function() { (new ActiveXObject('WScript.Shell')).Run('calc.exe'); return 1337; })()",
nullptr,
nullptr,
nullptr,
0,
0,
SCRIPTTEXT_ISEXPRESSION,
&result,
&exception_information);
assert(SUCCEEDED(hr));
assert(V_VT(&result) == VT_I4);
std::printf("%ld\n", V_I4(&result));
VariantClear(&result);
active_script_parse->Release();
active_script->Release();
CoUninitialize();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment