2011-09-20 35 views
6

Abbiamo clienti che chiedono che vengano chiamate le funzioni VBScript quando si verificano azioni particolari all'interno del nostro prodotto. Ho provato a cercare le tecnologie di Windows Scripting ma ho difficoltà a trovare esattamente ciò di cui ho bisogno. Spero che alcuni di voi possano aiutare.Come caricare e chiamare una funzione VBScript da C++?

Il nostro prodotto è un prodotto Windows C++ nativo. Il cliente dovrebbe specificare un file VBScript, che caricaremmo, e ogni volta che si verifica un evento particolare, chiameremmo una funzione particolare in VBScript e lasceremo che faccia il suo caso. Possiamo fornire oggetti all'interno dello spazio dei nomi dello script per poter accedere alle informazioni sul nostro prodotto.

Ho trovato alcune informazioni su MSDN sull'interfaccia IActiveScript e alcune informazioni correlate, ma non riesco a trovare esempi di creazione di istanze di un oggetto COM che implementa questa interfaccia per VBScript.

So che PowerShell sarebbe probabilmente un'opzione migliore per questo in questi giorni, ma i nostri clienti sono bloccati in molti sistemi legacy e VBScript è ciò che sanno.

Qualsiasi aiuto che puoi fornire (link o altro) sarebbe apprezzato!

+0

Questa è una buona domanda, ma potrebbe essere più adatta per StackOverflow. Questo sito è per argomenti più soggettivi. IActiveScript è, imo, la giusta direzione per investigare. – GrandmasterB

risposta

2

Date un'occhiata a questo per un po 'di codice di esempio http://support.microsoft.com/kb/221992

C'è un msscript.ocx che potrebbe aiutare voi, ma è probabilmente più difficoltà che il suo valore se si può scrivere C++ http://msdn.microsoft.com/en-us/magazine/cc302278.aspx

+0

Grazie. Il codice di esempio che hai indicato (primo collegamento) è molto utile. Dovrò capire come farlo senza MFC (dato che il nostro progetto non usa MFC), ma è un ottimo punto di partenza. – tyrel

+1

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

1

IActiveScript e le interfacce correlate funzionano molto bene. Li uso nel mio prodotto esattamente nello stesso modo in cui li hai descritti. Alcuni dei nostri clienti scrivono i propri script VBScript e JScript per analizzare e aggiornare i dati dell'applicazione prima che vengano pubblicati su un database.

È possibile utilizzare CoCreateInstance() per creare un'istanza IActiveScript, come qualsiasi altro oggetto COM. Dovresti quindi chiamare il suo metodo QueryInterface() per ottenere un'interfaccia IActiveScriptParse per il caricamento di snippet di codice di script e quindi aggiornare lo stato di IActiveScript per eseguire il codice.

È possibile aggiungere oggetti personalizzati allo script implementando classi precedute da IDispatch e passandole al motore utilizzando IActiveScript::AddNamedItem() e una richiamata IActiveScriptSite::GetItemInfo().

Esistono esempi di utilizzo di IActiveScript disponibili su MSDN.

+0

Grazie, anche se questo è sostanzialmente ciò che ho già capito. Nota che ho detto di aver trovato queste informazioni su MSDN ma non sono riuscito a trovare esempi. Grazie per avermi detto che ci sono esempi ma che non ne indicano nessuno. (La risposta di Richard mi ha fornito questo) – tyrel

10

Ho messo insieme un "Ciao Mondo" IActiveScript C++ applicazione console ATL che:

  • Definire CSimpleScriptSite classe
    • Implementare IActiveScriptSite interfaccia (obbligatorio)
    • Implementare IActiveScriptSiteWindow interfaccia (opzionale)
    • Implementazione minima con la maggior parte delle funzioni implementate con uno stub fittizio
    • Non ha errori nella gestione. Consultare MSDN IActiveScriptError.
  • Usa CoCreateInstance un nuovo IActiveSite oggetto
    • creare istanze di entrambi VBScript e JScript
    • Collegamento del IActiveSite a IActiveScriptSite utilizzando IActiveSite::SetScriptSite
    • chiamata QueryInterface per ottenere un'interfaccia IActiveScriptParse
    • Usa IActiveScriptParse a eseguire VBScript o JScript codice
  • Il campione:
    • valuta un'espressione in JScript
    • Valuta un'espressione in VBScript
    • Esegue un comando in VBScript

Codice:

#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; 
} 
Problemi correlati