如何在C代码中内嵌运行VBS代码,而非调用外部文件?
在C代码中内嵌执行VBScript的方法
在Windows平台上,你可以通过调用Active Scripting相关的COM接口,直接在C代码里内嵌并执行VBScript,完全不需要依赖外部VBS文件。下面是两种可行的实现方案:
方案一:用IScriptControl组件(简单易上手)
IScriptControl是微软提供的高层脚本宿主控件,专门用来快速嵌入VBScript或JScript,代码量少,适合简单场景。
示例代码
#include <windows.h> #include <ocidl.h> #include <script.h> int main() { HRESULT hr; IScriptControl *pScriptControl = NULL; // 初始化COM环境 hr = CoInitialize(NULL); if (FAILED(hr)) { printf("COM初始化失败\n"); return 1; } // 创建ScriptControl实例 hr = CoCreateInstance(CLSID_ScriptControl, NULL, CLSCTX_INPROC_SERVER, IID_IScriptControl, (void**)&pScriptControl); if (FAILED(hr)) { printf("创建ScriptControl实例失败\n"); CoUninitialize(); return 1; } // 指定脚本语言为VBScript hr = pScriptControl->put_Language(_bstr_t("VBScript")); if (FAILED(hr)) { printf("设置脚本语言失败\n"); pScriptControl->Release(); CoUninitialize(); return 1; } // 这里就是你要内嵌的VBS代码,直接写在宽字符串里 const wchar_t* vbsCode = L"Function Calculate(a, b)\n" L" Calculate = a * b + a - b\n" L"End Function\n" L"MsgBox \"计算结果:\" & Calculate(15, 6)"; // 执行内嵌的VBS代码 hr = pScriptControl->ExecuteStatement(_bstr_t(vbsCode)); if (FAILED(hr)) { printf("执行脚本失败\n"); pScriptControl->Release(); CoUninitialize(); return 1; } // 清理资源 pScriptControl->Release(); CoUninitialize(); return 0; }
编译说明
用MSVC编译时,需要链接oleaut32.lib和scrrun.lib,命令如下:
cl your_code.c oleaut32.lib scrrun.lib
方案二:用IActiveScript接口(底层灵活)
如果需要更精细的控制(比如处理脚本错误、自定义宿主对象、双向数据交互),可以直接用底层的IActiveScript接口,这是Active Scripting的核心API。
示例代码
#include <windows.h> #include <activscp.h> // 实现最小化的IActiveScriptSite,用来和脚本引擎交互 class CSimpleScriptSite : public IActiveScriptSite { private: ULONG m_refCount; public: CSimpleScriptSite() : m_refCount(1) {} // IUnknown接口方法 STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj) { if (riid == IID_IUnknown || riid == IID_IActiveScriptSite) { *ppvObj = static_cast<IActiveScriptSite*>(this); AddRef(); return S_OK; } *ppvObj = NULL; return E_NOINTERFACE; } STDMETHODIMP_(ULONG) AddRef() { return InterlockedIncrement(&m_refCount); } STDMETHODIMP_(ULONG) Release() { ULONG count = InterlockedDecrement(&m_refCount); if (count == 0) delete this; return count; } // IActiveScriptSite接口方法 STDMETHODIMP GetLCID(LCID *plcid) { *plcid = LOCALE_USER_DEFAULT; return S_OK; } STDMETHODIMP GetItemInfo(LPCOLESTR pstrName, DWORD dwReturnMask, IUnknown **ppunkItem, ITypeInfo **ppti) { *ppunkItem = NULL; *ppti = NULL; return TYPE_E_ELEMENTNOTFOUND; } STDMETHODIMP GetDocVersionString(BSTR *pbstrVersion) { *pbstrVersion = SysAllocString(L"1.0"); return S_OK; } STDMETHODIMP OnScriptTerminate(const VARIANT *pvarResult, const EXCEPINFO *pexcepinfo) { return S_OK; } STDMETHODIMP OnStateChange(SCRIPTSTATE ssScriptState) { return S_OK; } STDMETHODIMP OnScriptError(IActiveScriptError *pError) { DWORD lineNum; BSTR errorDesc; pError->GetSourceLineNumber(&lineNum); pError->GetDescription(&errorDesc); printf("脚本出错:第%d行,%S\n", lineNum, errorDesc); SysFreeString(errorDesc); return S_OK; } STDMETHODIMP OnEnterScript(void) { return S_OK; } STDMETHODIMP OnLeaveScript(void) { return S_OK; } }; int main() { HRESULT hr; IActiveScript *pScriptEngine = NULL; IActiveScriptParse *pScriptParser = NULL; CSimpleScriptSite *pScriptSite = new CSimpleScriptSite(); // 初始化COM hr = CoInitialize(NULL); if (FAILED(hr)) { printf("COM初始化失败\n"); return 1; } // 创建VBScript引擎实例 hr = CoCreateInstance(CLSID_VBScript, NULL, CLSCTX_INPROC_SERVER, IID_IActiveScript, (void**)&pScriptEngine); if (FAILED(hr)) { printf("创建VBScript引擎失败\n"); delete pScriptSite; CoUninitialize(); return 1; } // 设置脚本站点 hr = pScriptEngine->SetScriptSite(pScriptSite); if (FAILED(hr)) { printf("设置脚本站点失败\n"); pScriptEngine->Release(); delete pScriptSite; CoUninitialize(); return 1; } // 获取脚本解析接口 hr = pScriptEngine->QueryInterface(IID_IActiveScriptParse, (void**)&pScriptParser); if (FAILED(hr)) { printf("获取解析接口失败\n"); pScriptEngine->Release(); delete pScriptSite; CoUninitialize(); return 1; } // 初始化脚本引擎 hr = pScriptParser->InitNew(); if (FAILED(hr)) { printf("初始化引擎失败\n"); pScriptParser->Release(); pScriptEngine->Release(); delete pScriptSite; CoUninitialize(); return 1; } // 内嵌的VBS代码 const wchar_t* vbsCode = L"Dim userName\n" L"userName = InputBox(\"请输入你的名字:\")\n" L"MsgBox \"你好,\" & userName & \"!\""; // 解析并执行脚本 hr = pScriptParser->ParseScriptText(vbsCode, NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISVISIBLE, NULL, NULL); if (FAILED(hr)) { printf("解析脚本失败\n"); pScriptParser->Release(); pScriptEngine->Release(); delete pScriptSite; CoUninitialize(); return 1; } // 启动脚本执行 hr = pScriptEngine->SetScriptState(SCRIPTSTATE_CONNECTED); if (FAILED(hr)) { printf("启动脚本失败\n"); pScriptParser->Release(); pScriptEngine->Release(); delete pScriptSite; CoUninitialize(); return 1; } // 清理资源 pScriptParser->Release(); pScriptEngine->Release(); delete pScriptSite; CoUninitialize(); return 0; }
编译说明
用MSVC编译时,需要链接oleaut32.lib和activscp.lib,命令如下:
cl your_code.c oleaut32.lib activscp.lib
补充说明
- 这两种方案都只适用于Windows平台,因为VBScript是Windows专属的脚本语言。
- 内嵌的VBS代码可以直接写在C的宽字符串里,注意转义换行符和特殊字符。
- 如果需要在C和VBS之间传递数据,可以通过
IScriptControl::AddObject方法(方案一)或者自定义IActiveScriptSite::GetItemInfo方法(方案二)实现双向交互。
内容的提问来源于stack exchange,提问作者tediouscreator
相关产品推荐
相关产品推荐

