好久没写博客了,抓住四月的小尾巴,分享一篇利用c++提供的com接口,来执行各种脚本语言
直接上代码,下面demo使用vs2019编译,功能是通过c++执行vbscript脚本,创建进程:
#include <iostream>
#include <windows.h>
#include <objbase.h>
#include <activscp.h>
using namespace std;
HRESULT getEngineGuid(LPCTSTR extension, GUID* guidBuffer)
{
wchar_t buffer[100];
HKEY hk;
DWORD size;
HKEY subKey;
DWORD type;
// See if this file extension is associated
// with an ActiveX script engine
if (!RegOpenKeyEx(HKEY_CLASSES_ROOT, extension, 0,
KEY_QUERY_VALUE | KEY_READ, &hk))
{
type = REG_SZ;
size = sizeof(buffer);
size = RegQueryValueEx(hk, 0, 0, &type,
(LPBYTE)&buffer[0], &size);
RegCloseKey(hk);
if (!size)
{
// The engine set an association.
// We got the Language string in buffer[]. Now
// we can use it to look up the engine's GUID
// Open HKEY_CLASSES_ROOT\{LanguageName}
again: size = sizeof(buffer);
if (!RegOpenKeyEx(HKEY_CLASSES_ROOT, (LPCTSTR)&buffer[0], 0,
KEY_QUERY_VALUE | KEY_READ, &hk))
{
// Read the GUID (in string format)
// into buffer[] by querying the value of CLSID
if (!RegOpenKeyExA(hk, "CLSID", 0,
KEY_QUERY_VALUE | KEY_READ, &subKey))
{
size = RegQueryValueExW(subKey, 0, 0, &type,
(LPBYTE)&buffer[0], &size);
RegCloseKey(subKey);
}
else if (extension)
{
// If an error, see if we have a "ScriptEngine"
// key under here that contains
// the real language name
if (!RegOpenKeyExA(hk, "ScriptEngine", 0,
KEY_QUERY_VALUE | KEY_READ, &subKey))
{
size = RegQueryValueEx(subKey, 0, 0, &type,
(LPBYTE)&buffer[0], &size);
RegCloseKey(subKey);
if (!size)
{
RegCloseKey(hk);
extension = 0;
goto again;
}
}
}
}
RegCloseKey(hk);
if (!size)
{
// Convert the GUID string to a GUID
// and put it in caller's guidBuffer
if ((size = CLSIDFromString(&buffer[0], guidBuffer)))
MessageBoxA(0, "Can't convert engine GUID",
"Error", MB_OK | MB_ICONEXCLAMATION);
return(size);
}
}
}
MessageBoxA(0, "Can't get engine GUID from registry",
"Error", MB_OK | MB_ICONEXCLAMATION);
return(E_FAIL);
}
class CMyActiveScriptSite : public IActiveScriptSite
{
public:
HRESULT STDMETHODCALLTYPE GetLCID(__RPC__out LCID* plcid)
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE GetItemInfo(
/* [in] */ __RPC__in LPCOLESTR pstrName,
/* [in] */ DWORD dwReturnMask,
/* [out] */ __RPC__deref_out_opt IUnknown** ppiunkItem,
/* [out] */ __RPC__deref_out_opt ITypeInfo** ppti)
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE GetDocVersionString(
/* [out] */ __RPC__deref_out_opt BSTR* pbstrVersion)
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnScriptTerminate(
/* [in] */ __RPC__in const VARIANT* pvarResult,
/* [in] */ __RPC__in const EXCEPINFO* pexcepinfo)
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnStateChange(
/* [in] */ SCRIPTSTATE ssScriptState)
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnScriptError(
/* [in] */ __RPC__in_opt IActiveScriptError* pscripterror)
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnEnterScript(void)
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnLeaveScript(void)
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE QueryInterface(
/* [in] */ REFIID riid,
/* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject)
{
if (riid == IID_IActiveScriptSite || (riid == IID_IUnknown))
{
*ppvObject = this;
AddRef();
return S_OK;
}
*ppvObject = NULL;
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE AddRef(void)
{
return S_OK;
}
ULONG STDMETHODCALLTYPE Release(void)
{
return S_OK;
}
};
int main()
{
GUID guidBuffer = { 0 };
IActiveScript* activeScript = NULL;
IActiveScriptParse* activeScriptParse = NULL;
CMyActiveScriptSite MyActiveScriptSite;
wchar_t VBscript[] = L"Set Sh = CreateObject(\"WScript.Shell\")\r\n\
Sh.Run \"calc.exe\", 0";
do
{
HRESULT res = getEngineGuid(L".vbs", &guidBuffer);
if (res != ERROR_SUCCESS)
{
break;
}
res = CoInitialize(0);
res = CoCreateInstance(guidBuffer, 0, CLSCTX_ALL, (const IID)IID_IActiveScript, (void**)&activeScript);
if (res != ERROR_SUCCESS)
{
break;
}
res = activeScript->QueryInterface(IID_IActiveScriptParse,(void**)&activeScriptParse);
if (res != ERROR_SUCCESS)
{
break;
}
res = activeScriptParse->InitNew();
if (res != ERROR_SUCCESS)
{
break;
}
res = activeScript->SetScriptSite((IActiveScriptSite*)&MyActiveScriptSite);
if (res != ERROR_SUCCESS)
{
break;
}
res = activeScriptParse->ParseScriptText(&VBscript[0],0,0,0,0,0,0,0,0);
if (res != ERROR_SUCCESS)
{
break;
}
res = activeScript->SetScriptState(SCRIPTSTATE_CONNECTED);
if (res != ERROR_SUCCESS)
{
break;
}
res = activeScript->Close();
if (res != ERROR_SUCCESS)
{
break;
}
activeScript->Release();
activeScriptParse->Release();
CoUninitialize();
} while (0);
std::cout << "Hello World!\n";
}
参考资料:
https://www.codeproject.com/Articles/14905/COM-in-plain-C-Part-6
https://modexp.wordpress.com/2019/07/21/inmem-exec-script/