2011-09-20 8 views
6

Tenemos clientes pidiendo que se llamen las funciones de VBScript cuando ocurren acciones particulares dentro de nuestro producto. He intentado investigar las tecnologías de secuencias de comandos de Windows, pero tengo dificultades para encontrar exactamente lo que necesito. Con suerte, algunos de ustedes pueden ayudar.Cómo cargar y llamar a una función de VBScript desde C++?

Nuestro producto es un producto nativo de C++ Windows. El cliente especificaría un archivo VBScript, que cargaríamos, y cada vez que ocurra un evento en particular, llamaremos a una función particular en el VBScript y dejaremos que haga su trabajo. Podemos proporcionar objetos dentro del espacio de nombre del guión para que también tenga acceso a información sobre nuestro producto.

Encontré información sobre MSDN sobre la interfaz IActiveScript y algunas cosas relacionadas, pero no encuentro ejemplos de creación de instancias de un objeto COM que implemente esta interfaz para VBScript.

Sé que PowerShell probablemente sea una mejor opción para esto en estos días, pero nuestros clientes están atrapados en una gran cantidad de sistemas heredados y VBScript es lo que saben.

¡Cualquier ayuda que pueda proporcionar (enlaces o de otro tipo) sería apreciada!

+0

Esta es una buena pregunta, pero podría ser más adecuada para StackOverflow. Este sitio es realmente para temas más subjetivos. IActiveScript es, en mi opinión, la dirección correcta para que investigue. – GrandmasterB

Respuesta

2

Tener un vistazo a esto desde hace algún código de ejemplo http://support.microsoft.com/kb/221992

Hay un msscript.ocx que podría ayudarle, pero es probablemente más problemas de lo que vale si se puede escribir C++ http://msdn.microsoft.com/en-us/magazine/cc302278.aspx

+0

Gracias. El código de ejemplo que apuntó (primer enlace) es muy útil. Tendré que descubrir cómo hacerlo sin MFC (ya que nuestro proyecto no usa MFC), pero es un excelente lugar para comenzar. – tyrel

+1

Ver http://www.codeproject.com/KB/COM/com_in_c6.aspx –

1

IActiveScript y las interfaces relacionadas funcionan muy bien. Los uso en mi producto exactamente de la misma manera que usted ha descrito. Algunos de nuestros clientes escriben sus propios scripts de VBScript y JScript para analizar y actualizar los datos de las aplicaciones antes de que se publiquen en una base de datos.

Utiliza CoCreateInstance() para instanciar IActiveScript, como lo haría con cualquier otro objeto COM. A continuación, debe llamar a su método QueryInterface() para obtener una interfaz IActiveScriptParse para cargar fragmentos de código de scripting, y luego actualizar el estado IActiveScript para ejecutar el código.

Puede agregar objetos personalizados a la secuencia de comandos implementando IDispatch -derivadas clases y luego pasarlos al motor utilizando IActiveScript::AddNamedItem() y una devolución de llamada IActiveScriptSite::GetItemInfo().

Hay ejemplos de uso de IActiveScript disponibles en MSDN.

+0

Gracias, aunque esto es básicamente lo que ya entendí. Tenga en cuenta que dije que encontré esta información en MSDN pero no pude encontrar ejemplos. Gracias por decirme que hay ejemplos, pero que no apuntan a ninguno. (La respuesta de Richard me brindó esto) – tyrel

10

He creado un "Hola Mundo" aplicación de consola ATL IActiveScript C++ que:

  • Definir CSimpleScriptSite clase
    • Implementar IActiveScriptSite interfaz (obligatorio)
    • Implementar IActiveScriptSiteWindow interfaz (opcional)
    • Implementación mínima con la mayoría de las funciones implementadas con un stummy dummy
    • No tiene ningún error de manejo. Consulte MSDN IActiveScriptError.
  • Uso CoCreateInstance un nuevo IActiveSite objeto
    • crear instancias de ambas VBScript y JScript
    • Enlace del IActiveSite a IActiveScriptSite usando IActiveSite::SetScriptSite
    • llamada QueryInterface para obtener una interfaz IActiveScriptParse
    • Uso IActiveScriptParse a ejecutar VBScript o JScript código
  • La muestra:
    • evalúa una expresión en JScript
    • Evalúa una expresión en VBScript
    • ejecuta un comando en VBScript

Código:

#include "stdafx.h" 
#include <atlbase.h> 
#include <activscp.h> 

class CSimpleScriptSite : 
    public IActiveScriptSite, 
    public IActiveScriptSiteWindow 
{ 
public: 
    CSimpleScriptSite() : m_cRefCount(1), m_hWnd(NULL) { } 

    // IUnknown 

    STDMETHOD_(ULONG, AddRef)(); 
    STDMETHOD_(ULONG, Release)(); 
    STDMETHOD(QueryInterface)(REFIID riid, void **ppvObject); 

    // IActiveScriptSite 

    STDMETHOD(GetLCID)(LCID *plcid){ *plcid = 0; return S_OK; } 
    STDMETHOD(GetItemInfo)(LPCOLESTR pstrName, DWORD dwReturnMask, IUnknown **ppiunkItem, ITypeInfo **ppti) { return TYPE_E_ELEMENTNOTFOUND; } 
    STDMETHOD(GetDocVersionString)(BSTR *pbstrVersion) { *pbstrVersion = SysAllocString(L"1.0"); return S_OK; } 
    STDMETHOD(OnScriptTerminate)(const VARIANT *pvarResult, const EXCEPINFO *pexcepinfo) { return S_OK; } 
    STDMETHOD(OnStateChange)(SCRIPTSTATE ssScriptState) { return S_OK; } 
    STDMETHOD(OnScriptError)(IActiveScriptError *pIActiveScriptError) { return S_OK; } 
    STDMETHOD(OnEnterScript)(void) { return S_OK; } 
    STDMETHOD(OnLeaveScript)(void) { return S_OK; } 

    // IActiveScriptSiteWindow 

    STDMETHOD(GetWindow)(HWND *phWnd) { *phWnd = m_hWnd; return S_OK; } 
    STDMETHOD(EnableModeless)(BOOL fEnable) { return S_OK; } 

    // Miscellaneous 

    HRESULT SetWindow(HWND hWnd) { m_hWnd = hWnd; return S_OK; } 

public: 
    LONG m_cRefCount; 
    HWND m_hWnd; 
}; 

STDMETHODIMP_(ULONG) CSimpleScriptSite::AddRef() 
{ 
    return InterlockedIncrement(&m_cRefCount); 
} 

STDMETHODIMP_(ULONG) CSimpleScriptSite::Release() 
{ 
    if (!InterlockedDecrement(&m_cRefCount)) 
    { 
     delete this; 
     return 0; 
    } 
    return m_cRefCount; 
} 

STDMETHODIMP CSimpleScriptSite::QueryInterface(REFIID riid, void **ppvObject) 
{ 
    if (riid == IID_IUnknown || riid == IID_IActiveScriptSiteWindow) 
    { 
     *ppvObject = (IActiveScriptSiteWindow *) this; 
     AddRef(); 
     return NOERROR; 
    } 
    if (riid == IID_IActiveScriptSite) 
    { 
     *ppvObject = (IActiveScriptSite *) this; 
     AddRef(); 
     return NOERROR; 
    } 
    return E_NOINTERFACE; 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    HRESULT hr = S_OK; 
    hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); 

    // Initialize 
    CSimpleScriptSite* pScriptSite = new CSimpleScriptSite(); 
    CComPtr<IActiveScript> spJScript; 
    CComPtr<IActiveScriptParse> spJScriptParse; 
    hr = spJScript.CoCreateInstance(OLESTR("JScript")); 
    hr = spJScript->SetScriptSite(pScriptSite); 
    hr = spJScript->QueryInterface(&spJScriptParse); 
    hr = spJScriptParse->InitNew(); 
    CComPtr<IActiveScript> spVBScript; 
    CComPtr<IActiveScriptParse> spVBScriptParse; 
    hr = spVBScript.CoCreateInstance(OLESTR("VBScript")); 
    hr = spVBScript->SetScriptSite(pScriptSite); 
    hr = spVBScript->QueryInterface(&spVBScriptParse); 
    hr = spVBScriptParse->InitNew(); 

    // Run some scripts 
    CComVariant result; 
    EXCEPINFO ei = { }; 
    hr = spJScriptParse->ParseScriptText(OLESTR("(new Date()).getTime()"), NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &result, &ei); 
    hr = spVBScriptParse->ParseScriptText(OLESTR("Now"), NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &result, &ei); 
    hr = spVBScriptParse->ParseScriptText(OLESTR("MsgBox \"Hello World! The current time is: \" & Now"), NULL, NULL, NULL, 0, 0, 0, &result, &ei); 

    // Cleanup 
    spVBScriptParse = NULL; 
    spVBScript = NULL; 
    spJScriptParse = NULL; 
    spJScript = NULL; 
    pScriptSite->Release(); 
    pScriptSite = NULL; 

    ::CoUninitialize(); 
    return 0; 
} 
Cuestiones relacionadas