// Main functions for an example program that executes a VBscript.
#include <windows.h>
#include <stdio.h>
#include <initguid.h>
#include <objbase.h>
#include <activscp.h>
#include <tchar.h>
#include "IActiveScriptSite.h"
#include "extern.h"
// This is our VBscript that we will run. For the sake of simplicity,
// we hard-code it inside of our app. NOTE: It must be UNICODE text
// format (ie, wchar_t, not char) because the script engine's
// ParseScriptText expects that. All this script does is display
// a "Hello world" messagebox
static const wchar_t VBscript[] = L"MsgBox \"Hello world\"";
// For getting the engine's GUID from registry
static const TCHAR CLSIDStr[] = _T("CLSID");
static const TCHAR ScriptEngineStr[] = _T("ScriptEngine");
// Error message box
static const TCHAR ErrorStr[] = _T("Error");
/********************** display_COM_error() ********************
* Displays a messagebox for a COM error.
*
* msg = Format string for sprintf().
* hr = COM error number.
*
* NOTE: Total size of error msg must be < 256 TCHARs.
*/
void display_COM_error(LPCTSTR msg, HRESULT hr)
{
TCHAR buffer[256];
wsprintf(&buffer[0], msg, hr);
MessageBox(0, &buffer[0], &ErrorStr[0], MB_OK|MB_ICONEXCLAMATION);
}
/************************** runScript() ***********************
* Runs our VBscript.
*
* guid = GUID of the script engine that runs the script.
*
* NOTE: Our VBscript is hard-coded into the static variable
* named VBscript[].
*
* If an error, this displays a message box.
*/
void runScript(GUID *guid)
{
register HRESULT hr;
IActiveScriptParse *activeScriptParse;
IActiveScript *activeScript;
// Create an instance of the script engine, and get its IActiveScript object
if ((hr = CoCreateInstance(guid, 0, CLSCTX_ALL, &IID_IActiveScript, (void **)&activeScript)))
display_COM_error("Can't get engine's IActiveScript: %08X", hr);
else
{
// Get the script engine's IActiveScriptParse object (which we can do from its
// IActiveScript's QueryInterface since IActiveScriptParse is a
// sub-object of the IActiveScript)
if ((hr = activeScript->lpVtbl->QueryInterface(activeScript, &IID_IActiveScriptParse, (void **)&activeScriptParse)))
display_COM_error("Can't get engine's IActiveScriptParse: %08X", hr);
else
{
// Initialize the engine. This just lets the engine internally
// initialize some stuff in preparation of us adding scripts to it
// for the first time
if ((hr = activeScriptParse->lpVtbl->InitNew(activeScriptParse)))
display_COM_error("Can't initialize engine : %08X", hr);
else
{
// Give the engine our IActiveScriptSite object. If all goes well,
// the engine will call its QueryInterface (which will AddRef it)
if ((hr = activeScript->lpVtbl->SetScriptSite(activeScript, (IActiveScriptSite *)&MyActiveScriptSite)))
display_COM_error("Can't set our IScriptSite : %08X", hr);
else
{
// Have the script engine parse the script and add it to its internal
// list of scripts to run
hr = activeScriptParse->lpVtbl->ParseScriptText(activeScriptParse, &VBscript[0], 0, 0, 0, 0, 0, 0, 0, 0);
// NOTE: If the script engine has a problem parsing/tokenizing the script, it will
// have called our IActiveScriptSite's OnScriptError() to display an error msg, so
// we don't need to do that here
if (!hr)
{
// Set engine's state to CONNECTED. Our above script will run now
if ((hr = activeScript->lpVtbl->SetScriptState(activeScript, SCRIPTSTATE_CONNECTED)))
display_COM_error("Engine can't connect events: %08X", hr);
}
}
}
// Release script engine's IActiveScriptParse
activeScriptParse->lpVtbl->Release(activeScriptParse);
}
// We're supposed to Close() the engine before we Release() the IActiveScript
activeScript->lpVtbl->Close(activeScript);
// Release script engine's IActiveScript
activeScript->lpVtbl->Release(activeScript);
}
}
/************************ getEngineGuid() ***********************
* Gets the GUID of the script engine associated with the
* specified filename extension.
*
* extension = The filename extension.
* guidBuffer = Where to return the engine's GUID.
*
* RETURNS: S_OK if success, other for error.
*
* NOTE: Displays a messagebox for an error.
*/
static 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 (!RegOpenKeyEx(hk, &CLSIDStr[0], 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 (!RegOpenKeyEx(hk, &ScriptEngineStr[0], 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)))
display_COM_error("Can't convert engine GUID: %08X", size);
return(size);
}
}
}
MessageBox(0, "Can't get engine GUID from registry", &ErrorStr[0], MB_OK|MB_ICONEXCLAMATION);
return(E_FAIL);
}
/************************** main() **************************
* Our EXE's entry point. This is called by Windows when our
* EXE first starts up.
*/
int main(int argc, char **argv)
{
HRESULT hr;
// Initialize COM DLL
if ((hr = CoInitialize(0)))
display_COM_error("Failed to initialize COM: %08X", hr);
else
{
GUID guidBuffer;
// Initialize MyRealIActiveScriptSite object
initIActiveScriptSiteObject();
// Find the script engine to use for files that end with a .VBS extension.
// NOTE: Microsoft's VBscript engine sets up an association in the
// registry for this extension.
if (!getEngineGuid(".vbs", &guidBuffer))
{
// Now that we've got the engine GUID, run the script
runScript(&guidBuffer);
}
// Allow our IActiveScriptSite to free any resources
MyActiveScriptSite.site.lpVtbl->Release((IActiveScriptSite *)&MyActiveScriptSite);
}
// Free COM
CoUninitialize();
return(0);
}