COM: 'RegExp' IID, IUnknown, QueryInterface



  • Hi,

    ich versuche schon seit ner Ewigkeit das COM-Object: 'VBScript Regular Expression' in mein Win32-Programm einzubinden.

    CLSID CLSID_RegExp;
        HRESULT hr;
        IUnknown* pRegExp;
        IID IID_RegExp;
    
        hr = CLSIDFromProgID( L"VBScript.RegExp",&CLSID_RegExp);
        if (FAILED(hr))
        {	
            MessageBox(0, "CLSID konnte nicht ermittelt werden", "Meldung", MB_OK); 
            return 1;
        }
        MessageBox(0, "CLSID OK", "Meldung", MB_OK); 
    
        hr = IIDFromString( L"VBScript.RegExp", &CLSID_RegExp);
        if (FAILED(hr))
        {
            MessageBox(0, "IID konnte nicht ermittelt werden", "Meldung", MB_OK); 
            return 1;
        }
        MessageBox(0, "IID OK", "Meldung", MB_OK); 
    
        if ( FAILED( CoInitialize(NULL)))  
        {
            MessageBox(0, "OLE Initialisierung gescheitert", "Meldung", MB_OK);  
            return 1;
        }
        MessageBox(0, "OLE Initialisierung OK", "Meldung", MB_OK); 
    
        hr = CoCreateInstance ( CLSID_RegExp, NULL, CLSCTX_INPROC_SERVER , IID_RegExp, (void**) &pRegExp ); 
        if ( FAILED(hr))  
        {
            MessageBox(0, "COM-Objekt-Erzeugung gescheitert","Meldung", MB_OK); 
            return 1;
        }
        MessageBox(0, "COM-Objekt-Erzeugung OK", "Meldung", MB_OK);  
    
        //??? und jetzt ? stichwort 'invoke'? wie?
    
        pRegExp->Release(); 
    
        CoUninitialize();
    

    Mein Problem: Wie komme ich an das Interface (IID) ran? Die Funktion CLSIDFromProgID funktioniert. IIDFromProgID gibt es nicht und mit IIDFromString funktioniert es so nicht (was für einen String muss ich da eigentlich mitgeben?). 😞

    Mal angenommen es würde funktionieren. Dann hätt ich noch das Problem, das ich ein unständliches IUnknown-Interface hätte. Weiß jemand wo ich nen Header für das Objekt 'RegExp' her bekomme, damit statt IUnknown IVBSRegExp(wie auch immer das dann hieße) nutzen kann?
    Über ein verständliches Beipsiel mit QueryInterface/Invoke würde ich mich auch freuen, denn fast alle Codes, die ich für Zugriffe auf die Objecte des Windows Scripting Hosts gefunden habe, sind in Jscript oder VBscript/VB (wo ein einfaches 'myRegExp = CreateObject("VBScript.RegExp.1")' ausreicht 😃 ).
    Was für C++ übrig blieb war nur Müll, fehlerhaft und mit bereits bekannten Interfaces.

    Danke!



  • illuminator schrieb:

    Dann hätt ich noch das Problem, das ich ein unständliches IUnknown-Interface hätte.

    Das IUnknown umständlich ist, höre ich gerade zum ersten Mal. Geht das auch etwas genauer?

    illuminator schrieb:

    Weiß jemand wo ich nen Header für das Objekt 'RegExp' her bekomme, damit statt IUnknown IVBSRegExp(wie auch immer das dann hieße) nutzen kann?

    Mir ist da kein offizieller Header bekannt. Da das Objekt für VBSricpt gedacht ist, ist das auch nicht nötig. Schau Dir das Object doch einfach in OLEView an. Dann kannst Du Dir in wenigen Minuten Deinen eigenen Header basteln:

    // {3F4DACA0-160D-11D2-A8E9-00104B365C9F}
    DEFINE_GUID(IID_IRegExp,
        0x3F4DACA0, 0x160D, 0x11D2, 0xA8, 0xE9, 0x00, 0x10, 0x4B, 0x36, 0x5C, 0x9F);
    
    #undef  INTERFACE
    #define INTERFACE  IRegExp
    DECLARE_INTERFACE_(IRegExp, IDispatch)
    {
        STDMETHOD(QueryInterface) (THIS_ REFIID riid, PVOID* ppvObj)PURE;
        STDMETHOD_(ULONG, AddRef) (THIS)PURE;
        STDMETHOD_(ULONG, Release)(THIS)PURE;
    
        STDMETHOD(GetTypeInfoCount)(THIS_ UINT* pctinfo)PURE;
        STDMETHOD(GetTypeInfo)(THIS_ UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)PURE;
        STDMETHOD(GetIDsOfNames)(THIS_ REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId)PURE;
        STDMETHOD(Invoke)(THIS_ DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr)PURE;
    
        STDMETHOD(get_Pattern)(THIS_ BSTR* pPattern)PURE;
        STDMETHOD(put_Pattern)(THIS_ BSTR  pPattern)PURE;
        STDMETHOD(get_IgnoreCase)(THIS_ VARIANT_BOOL* pIgnoreCase)PURE;
        STDMETHOD(put_IgnoreCase)(THIS_ VARIANT_BOOL  pIgnoreCase)PURE;
        STDMETHOD(get_Global)(THIS_ VARIANT_BOOL* pGlobal)PURE;
        STDMETHOD(put_Global)(THIS_ VARIANT_BOOL  pGlobal)PURE;
        STDMETHOD(Execute)(THIS_ BSTR sourceString, IDispatch** ppMatches)PURE;
        STDMETHOD(Test)(THIS_ BSTR sourceString, VARIANT_BOOL* pMatch)PURE;
        STDMETHOD(Replace)(THIS_ BSTR sourceString, BSTR replaceString, BSTR* pDestString)PURE;
    };
    

    Damit ist's dann auch einfach:

    CoInitialize(NULL);
    
    CLSID clsid;
    CLSIDFromProgID(OLESTR("VBScript.RegExp"), &clsid);
    
    IRegExp* pRegExp = NULL;
    CoCreateInstance(clsid, NULL, CLSCTX_SERVER, IID_IRegExp, (void**)&pRegExp);
    
    pRegExp->put_Global(VARIANT_TRUE);
    pRegExp->put_IgnoreCase(VARIANT_TRUE);
    
    BSTR bstrPattern = SysAllocString(L"xyz");
    pRegExp->put_Pattern(bstrPattern);
    SysFreeString(bstrPattern);
    
    BSTR bstrStringToTest = SysAllocString(L"abc");
    VARIANT_BOOL bMatch = VARIANT_FALSE;
    pRegExp->Test(bstrStringToTest, &bMatch);
    SysFreeString(bstrStringToTest);
    
    if(bMatch)
    {
    }
    else
    {
    }
    
    pRegExp->Release();
    CoUninitialize();
    

    Ansonsten solltest Du vielleicht überlegen, Dich erstmal mit COM als solches zu beschäftigen, bevor Du Dich an sowas heranwagst. Dann sollte Dir auch klar werden, daß es so Sachen wie IIDFromProgID gar nicht geben kann.



  • THX -King-

    Das ist doch schonmal gut!

    Nur: ich bekomm jetzt zwei Linker-Errors :
    "testproggie.obj : error LNK2001: Nichtaufgeloestes externes Symbol _IID_IRegExp
    Debug/testproggie.exe : fatal error LNK1120: 1 unaufgeloeste externe Verweise"

    Meine Reaktion auf solche Fehler war bisher immer: fehlende Lib einbinden.
    Die gibts aber nun nicht, vbscript.dll ist ja auch ne ActiveX-DLL. hm...

    und noch eine Frage: Wo bekommt man denn nun diese IID her?
    // {3F4DACA0-160D-11D2-A8E9-00104B365C9F}

    was mich mit kompliziert meine, sind solche Codeschnipsel die ich gefunden hatte:

    if (bMethodName.Length() > 0) 
          { 
            //build up paramaters to pass to Invoke() call 
            VARIANTARG vArg; 
            ::VariantInit(&vArg); 
            vArg.vt = VT_BSTR; 
            vArg.bstrVal = bInitArg; 
    
            DISPPARAMS dispparams; 
            dispparams.cArgs = 1; 
            dispparams.rgvarg = &vArg; 
            dispparams.cNamedArgs = 0; 
            dispparams.rgdispidNamedArgs = NULL; 
    
            //get the dispID for the function that we want to run on the passed interface 
            DISPID dispid; 
            OLECHAR FAR* szMember = bMethodName; 
            hr = pTargetDisp->GetIDsOfNames(IID_NULL, &szMember, 1, LOCALE_USER_DEFAULT, &dispid); 
    
            //now invoke the method on the passed interface 
            hr = pTargetDisp->Invoke( dispid, IID_NULL, LOCALE_USER_DEFAULT,DISPATCH_METHOD, &dispparams, &vResults, NULL, NULL);
    

    ich wollt halt lieber ein simples pRegExp->Execute("Teststring") statt so ein zusammengebastele

    öhm, ich hoffe ich nerv nicht zu sehr... ist das erste mal, dass ich COM/ActiveX außerhalb von VB nutzen will und momentan liegt meine Priorität aus Zeitgründen nicht bei Verstehen von COM, sondern bei erfolgreich benutzen. 🤡



  • illuminator schrieb:

    "testproggie.obj : error LNK2001: Nichtaufgeloestes externes Symbol _IID_IRegExp
    Debug/testproggie.exe : fatal error LNK1120: 1 unaufgeloeste externe Verweise"

    Ah, ja. Logisch. Hab ich vergessen, extra zu erwähnen: Das Macro DEFINE_GUID legt die Struktur per default nicht an, sondern deklariert sie als extern. Die Abhilfe ist ganz einfach. In einer Deiner Quelldateien (in einer, nicht in allen) inkludierst Du <initguid.h>, bevor Du den soeben selbsterstellten Header regexp.h (oder wie auch immer das bei Dir heisst) inkludierst. In <initguid.h> wird das Macro DEFINE_GUID so umdefiniert, daß auch eine Instanz der Struktur erstellt wird.

    illuminator schrieb:

    und noch eine Frage: Wo bekommt man denn nun diese IID her?
    // {3F4DACA0-160D-11D2-A8E9-00104B365C9F}

    Aus OLEView.exe. Du suchst zunächst das Objekt, z.B. unter Object Classes->All Objects. Dort markierst Du den Eintrag "VBScript Regular Expression". Jetzt noch schnell mit der rechten Maustaste geklickt und "View Type Information" gewählt. Jetzt wählst Du unter Interfaces IRegExp aus. Im Edit-Ctrl auf der rechten Seite siehst Du jetzt alles was Du wissen mußt.

    illuminator schrieb:

    was mich mit kompliziert meine, sind solche Codeschnipsel

    Da sehe ich die Verwendung von IDispatch, Du sprachst aber von IUnknown. Aber richtig, IDispatch ist unter C/++ einigermaßen umständlich. Da IRegExp aber glücklicherweise eine duale Schnittstelle ist, kannst Du Dir das sparen.

    illuminator schrieb:

    ... ist das erste mal, dass ich COM/ActiveX außerhalb von VB nutzen will und momentan liegt meine Priorität aus Zeitgründen nicht bei Verstehen von COM, sondern bei erfolgreich benutzen.

    Das merkt man. :p

    Edit: Mir fällt gerade ein, daß ich das zu Übungszwecken sogar mal in eine Klasse verbastelt habe. Also wenn Du das haben möchtest, lass es mich wissen.


Anmelden zum Antworten