2011-09-20 4 views
6

Nous avons des clients qui demandent que des fonctions VBScript soient appelées lorsque des actions particulières se produisent dans notre produit. J'ai essayé de rechercher les technologies Windows Scripting mais j'ai de la difficulté à trouver exactement ce dont j'ai besoin. J'espère que certains d'entre vous peuvent aider.Comment charger et appeler une fonction VBScript depuis C++?

Notre produit est un produit Windows C++ natif. Le client spécifierait un fichier VBScript, que nous chargerions, et chaque fois qu'un événement particulier se produirait, nous appellerions une fonction particulière dans le VBScript et le laisserions faire. Nous pouvons fournir des objets dans l'espace de nom du script pour qu'il puisse également accéder à des informations sur notre produit.

J'ai trouvé des informations sur MSDN à propos de l'interface IActiveScript et d'autres choses connexes, mais je ne trouve aucun exemple d'instanciation d'un objet COM qui implémente cette interface pour VBScript. Je sais que PowerShell serait probablement une meilleure option pour cela ces jours-ci, mais nos clients sont bloqués dans beaucoup de systèmes hérités et VBScript est ce qu'ils savent.

Toute aide que vous pouvez fournir (liens ou autres) serait appréciée!

+0

C'est une bonne question, mais peut-être mieux adapté pour StackOverflow. Ce site est vraiment pour des sujets plus subjectifs. IActiveScript est, imo, la bonne direction pour vous d'enquêter. – GrandmasterB

Répondre

2

Jetez un oeil à ce pour un exemple de code http://support.microsoft.com/kb/221992

Il y a un msscript.ocx qui pourrait vous aider, mais est probablement plus de soucis que si vous pouvez écrire C++ http://msdn.microsoft.com/en-us/magazine/cc302278.aspx

+0

Merci. L'exemple de code que vous avez pointé (premier lien) est très utile. Je vais devoir comprendre comment le faire sans MFC (puisque notre projet n'utilise pas MFC), mais c'est un bon endroit pour commencer. – tyrel

+1

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

1

IActiveScript et les interfaces connexes fonctionnent très bien. Je les utilise dans mon produit exactement de la même manière que vous l'avez décrite. Certains de nos clients écrivent leurs propres scripts VBScript et JScript pour analyser et mettre à jour les données de l'application avant qu'elles ne soient publiées dans une base de données.

Vous utilisez CoCreateInstance() pour instancier IActiveScript, comme vous le feriez avec n'importe quel autre objet COM. Vous appelez ensuite sa méthode QueryInterface() pour obtenir une interface IActiveScriptParse pour charger des extraits de code de script, puis vous mettez à jour l'état IActiveScript pour exécuter le code.

Vous pouvez ajouter des objets personnalisés au script en implémentant des classes dérivées IDispatch, puis en les transmettant au moteur à l'aide de IActiveScript::AddNamedItem() et d'un rappel IActiveScriptSite::GetItemInfo().

Il existe des exemples d'utilisation de IActiveScript sur MSDN.

+0

Merci, mais c'est essentiellement ce que j'ai déjà compris. Notez que j'ai dit que j'ai trouvé cette information sur MSDN mais que je n'ai pas pu trouver d'exemples. Merci de m'avoir dit qu'il y a des exemples mais que je n'en ai pas indiqué. (La réponse de Richard a fourni ceci pour moi) – tyrel

10

J'ai mis en place une demande "Bonjour tout le monde" console ATL de IActiveScript C que:

  • Define CSimpleScriptSite classe
    • Mettre en oeuvre l'interface IActiveScriptSite (obligatoire)
    • Mettre en œuvre IActiveScriptSiteWindow interface (en option)
    • Implémentation minimale avec la plupart des fonctions implémentées avec un embout factice
    • N'a aucune erreur de gestion. Consultez MSDN IActiveScriptError.
  • Utilisez CoCreateInstance un nouveau IActiveSite objet
    • Créer des instances des deux VBScript et JScript
    • Lien le IActiveSite à IActiveScriptSite en utilisant IActiveSite::SetScriptSite
    • Appel QueryInterface pour obtenir une interface IActiveScriptParse
    • Utilisez IActiveScriptParse pour exécuter VBScript ou JScript Code
  • L'échantillon:
    • évalue une expression dans JScript
    • évalue une expression dans VBScript
    • exécute une commande dans VBScript

code:

#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; 
} 
Questions connexes