invoke ???



  • hi Leute

    Ich experimentere immer noch an meiner Office Automation
    und versuche erst einmal zu verstehen was dabei geschieht.
    Aber irgendwie blicke ich einfach nicht durch.Dabei benutze ich
    die Dateien von J.Kalmbach.

    Invoke(LPDISPATCH pdisp,
    WORD wFlags,
    LPVARIANT pvRet,
    EXCEPINFO FAR* pexcepinfo,
    UINT FAR* pnArgErr,
    LPOLESTR pszName,
    LPCTSTR pszFmt,
    ...)

    so möchte ich zB nachfolgende Zeile rechtsbündig schreiben

    Invoke(pdispWord, DISPATCH_METHOD, NULL, NULL, NULL, 
        OLESTR("ParagraphFormat.Alignment"), TEXT("s"),CT2OLE
        ("wdAlignParagraphLeft"));
    

    Aufruf der Methode ParagraphFormat.Alignment
    Parameter format ist ein String darum TEXT("s")
    Parameter ist wdAlignParagraphLeftaber irgendwie klappt das nicht

    Danke für jede Hilfe
    Gruß Linus



  • Die Methode heisst mit Sicherheit *nicht* so!
    Du musst AFAIK zuerst das IDispathc-Interface von "ParagraphFormat" holen und dann dort das "Alignment" Property setzen (aber nicht auf einen String sondern auf eine Zahl).
    Schau Dir doch mal am besten die tlb-Datei von Word an, dann sollte es eigentlich deutlich werden...



  • Danke für die Antwort

    Habe NULL Ahnung von Wordbasic,
    daher habe ich es über die Makros in Word versucht
    aber das scheint dann doch etwas anders zu gehen

    Was meinst Du mit tlb-datei von Word ??



  • linus schrieb:

    Was meinst Du mit tlb-datei von Word ??

    Rufe OleView.exe (im Common7\bin-Verzeichnis von VS) auf und schau Dir unter "Type Libraries" das "Microsoft Word x.x Objet Library" an (doppel-click).
    Das kopierst Du Dir dann raus, druckst es aus und hängst es Dir an die Wand. Dann sieht Du z.B. dass wdAlignParagraphLeft dem Wert 0 entspricht. Und das "ParagraphFormat" ein IDispatch-Objekt zurückliefert...



  • Das ist ja toll

    Gibt es eigentlich eine gute Literatur zu diesem Thema
    Meine Bücher schweigen sich zu diesem Thema aus

    Danke
    Gruß Linus



  • Ich kann auch nur bei amazon suchen... selber hab ich keines...
    http://www.amazon.de/exec/obidos/ASIN/0735612420/ref=si_1_1/302-0334205-1208028

    Nur noch als Ergänzung: Late-Binding ist schon der richtige Weg für Office-Automation (man könnte ja auch early Binding machen):
    INFO: Use DISPID Binding to Automate Office Applications Whenever Possible
    http://support.microsoft.com/kb/247579/EN-US/



  • Oder man macht es in C# und spart sich einen Haufen "Ärger".



  • Was soll da der grosse Unterschied sein??? Late-Binding ist in C# fast genau gleich wie in C++... IMHO sogar nich schlimmer...



  • Es ist einfach netter handzuhaben 🙂
    Ich finde es echt übel in C++ mit COM rumzumachen, macht einfach keinen Spaß das zu programmieren, ständig diese Umwandelei und so.



  • Jochen Kalmbach schrieb:

    Nur noch als Ergänzung: Late-Binding ist schon der richtige Weg für Office-Automation (man könnte ja auch early Binding machen):

    Danke für die Links

    Ich habe es vorher mit early binding versucht jedoch gibt es ein Problem
    wenn das Programm auf verschiedenen Rechnern installiert wird, da ich nicht weis
    welche Office-Version implementiert ist. Ich glaube sogar , dass einige
    noch Office 95 oä. haben .

    btw Bis zu welcher Ofice Version funktioniert der o.g. Ansatz des late Bindings eingentlich ?



  • dEUs schrieb:

    Es ist einfach netter handzuhaben 🙂
    Ich finde es echt übel in C++ mit COM rumzumachen, macht einfach keinen Spaß das zu programmieren, ständig diese Umwandelei und so.

    Naja... es ist beides gleich blöd....

    Type t = Type.GetTypeFromProgID(progID);
    late = Activator.CreateInstance(t);
    

    und
    das C++-Pedant sind doch sehr ähnlich...
    Auch

    totalNoOfObjects = 0;
    ParameterModifier pm = new ParameterModifier(2);
    pm[0] = false;
    pm[1] = true;
    ParameterModifier [] pmArray = { pm };
    object [] args = {(int) objectTyp, totalNoOfObjects};
    object res = late.GetType().InvokeMember(
      "StartObjectQuery", 
      BindingFlags.InvokeMethod, 
      null, 
      late, 
      args,
      pmArray, 
      null,
      null);
    totalNoOfObjects = Convert.ToInt32(args[1]);
    return Convert.ToBoolean(res);
    

    Ist nicht sonderlich übersichtlicher...

    Oder wie machst Du es in C#???????



  • linus schrieb:

    btw Bis zu welcher Ofice Version funktioniert der o.g. Ansatz des late Bindings eingentlich ?

    Das Late-Binding-Ansatz funktioniert mit allen Windows-Office Versionen.
    Aus den von Dir beschriebenen Gründen ist es ja der Empfohlene Weg über Late-Binding zu gehen 😉



  • Ich füge das COM-Objekt als Referenz hinzu und benutze das ganze dann ganz normal wie jeden anderen Typ auch. Stichwort: Interop

    Aber das ist wohl early-Binding, wenn mich nciht alles täuscht.



  • dEUs schrieb:

    Ich füge das COM-Objekt als Referenz hinzu und benutze das ganze dann ganz normal wie jeden anderen Typ auch. Stichwort: Interop

    Und was hat das mit "Late-Binding" zu tun???
    Wenn Du das Objekt als Referenz hinzufügst, ist das IMHO Early-Binding...



  • Jochen Kalmbach schrieb:

    dEUs schrieb:

    Ich füge das COM-Objekt als Referenz hinzu und benutze das ganze dann ganz normal wie jeden anderen Typ auch. Stichwort: Interop

    Und was hat das mit "Late-Binding" zu tun???

    Jaja, habs ja auch grad gemerkt (siehe mein edit) 🤡



  • Sorry ! 😕 Ich blick immer noch nicht richtig durch.

    Jochen Kalmbach schrieb:

    Du musst AFAIK zuerst das IDispathc-Interface von "ParagraphFormat" holen und dann dort das "Alignment" Property setzen (aber nicht auf einen String sondern auf eine Zahl).

    Ich habe folgendes unter Microsoft Word im OleView gefunden:

    pdispinterface _ParagraphFormat
    

    darunter
    methods: Alignment :

    [id(0x00000065), proput , helpcontext(0x09530065)]
               void Alignment([in] WdParagraphAlignment rhs);
    
    typedef enum {
            wdAlignParagraphLeft = 0,
            wdAlignParagraphCenter = 1,
            wdAlignParagraphRight = 2,
            wdAlignParagraphJustify = 3,
            wdAlignParagraphDistribute = 4,
            wdAlignParagraphJustifyMed = 5,
            wdAlignParagraphJustifyHi = 7,
            wdAlignParagraphJustifyLow = 8,
            wdAlignParagraphThaiJustify = 9
        } WdParagraphAlignment;
    

    Wenn Du sagst IDispatch-inteface holen verstehe ich folgendes:

    LPDISPATCH pdispFormat; 
    
    		::CreateObject(OLESTR("_ParagraphFormat"), &pdispFormat);
    

    Dabei erstelle ich doch eine neues COM-SchnittstellenObjekt.
    Andererseits denke ich doch , dass du über WordBasic Word steuern möchtest

    weiter müsste ich dann mit invoke die Methode Alignment (DISPATCH_METHOD)aufrufen?
    und dann die Parameter setzen (DISPATCH_PROPERTYPUT) WdParagraphAlignment=0 (für left)

    Irgendwie denke ich z Zt völlig daneben und liege wahrscheinlich auch völlig falsch.

    PS Ich habe dazu in einem Buch ein Kapitel über Com und automatisierung gelesen. Danach war ich reichlich benebelt 😞



  • Mit meinem Satz habe ich gemeint:
    - via Invoke mit PROPERY_GET die Methode "ParagraphFormat" aufrufen; dann bekommst Du ein IDispatch-Interface zurück, welches Du bei dem *nächsten* Aufruf von Invoke verwendest (hier hast Du ja "pdispWord" verwendet)
    - Jetzt mit dem zurückgegebenen IDispatch-Interfave wieder via Invoke und PROPERTY_PUT mit dem Namen "Alignment" z.B. den Wert 2 (wdAlignParagraphRight) aufrufen.



  • Sei mir nicht böse aber ich sehe nicht wo ich ein IDispatch-Interface
    über Invoke zurückbekomme.

    /* 
     * Invoke 
     * 
     * Purpose: 
     *  Invokes a property accessor function or method of an automation object. Uses Unicode with OLE. 
     * 
     * Parameters: 
     *  pdisp         IDispatch* of automation object. 
     *  wFlags        Specfies if property is to be accessed or method to be invoked. 
     *                Can hold DISPATCH_PROPERTYGET, DISPATCH_PROPERTYPUT, DISPATCH_METHOD, 
     *                DISPATCH_PROPERTYPUTREF or DISPATCH_PROPERTYGET|DISPATCH_METHOD.    
     *  pvRet         NULL if caller excepts no result. Otherwise returns result. 
     *  pexcepinfo    Returns exception info if DISP_E_EXCEPTION is returned. Can be NULL if 
     *                caller is not interested in exception information.  
     *  pnArgErr      If return is DISP_E_TYPEMISMATCH, this returns the index (in reverse 
     *                order) of argument with incorrect type. Can be NULL if caller is not interested 
     *                in this information.  
     *  pszName       Name of property or method. 
     *  pszFmt        Format string that describes the variable list of parameters that  
     *                follows. The format string can contain the follwoing characters. 
     *                & = mark the following format character as VT_BYREF  
     *                b = VT_BOOL 
     *                i = VT_I2 
     *                I = VT_I4 
     *                r = VT_R2 
     *                R = VT_R4 
     *                c = VT_CY  
     *                s = VT_BSTR (far string pointer can be passed, BSTR will be allocated by this function). 
     *                e = VT_ERROR 
     *                d = VT_DATE 
     *                v = VT_VARIANT. Use this to pass data types that are not described in  
     *                                the format string. (For example SafeArrays). 
     *                D = VT_DISPATCH 
     *                U = VT_UNKNOWN 
     *     
     *  ...           Arguments of the property or method. Arguments are described by pszFmt.   
     *                ****FAR POINTERS MUST BE PASSED FOR POINTER ARGUMENTS in Win16.**** 
     * Return Value: 
     *  HRESULT indicating success or failure         
     *
    

    Rückgabewert von Invoke ist HRESULT
    und der einzige Parameter der einen Wert zurückgibt ist pvRet
    der ist jedoch vom Typ VARIANT .

    Tut mir ja leid aber ich sehe das einfach nicht .
    (im Voraus: Danke für Deine Geduld 😉 )



  • Na, vermutlich in

    *  pvRet         NULL if caller excepts no result. Otherwise returns result.
    

    Simples Beispiel:

    LPDISPATCH pdispParagraphFormat;
      HRESULT hrRes;
      VARIANT vRet;
      VariantInit(&vRet);
      hrRes = Invoke(pdispWord, DISPATCH_PROPERTYGET, &vRet, NULL, NULL, 
        OLESTR("ParagraphFormat"), NULL);
      if FAILED(hrRes)
        return hrRes;
      if (V_VT(&vRet) != VT_DISPATCH)
        return E_FAIL;
      *ppdispRoot = V_DISPATCH(&vRet);
      if ((*ppdispRoot) == NULL)
        return E_FAIL;
      pdispParagraphFormat->AddRef();  // keep a reference to the object
      VariantClear(&vRet);
    
      // Now use this object to do the Invoke for "Alignment"
    


  • Danke für den Source. Ich glaub langsam komme ich dahinter.

    Jedoch habe ich doch noch ein paar Fragen und Probleme

    VARIANT vRet;
    VariantInit(&vRet); 
    hrRes = Invoke(pdispWord, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,OLESTR("ParagraphFormat"), NULL);
    

    Wenn ich es so ausführe bekomme ich nichts zurück
    vRet={VT_EMPTY}
    Wahrscheinlich ist "ParagraphFormat" bzw "_ParagraphFormat" nicht korrekt.
    Habe beides ausprobiert.

    Wenn ich das richtig verstehe muss ich doch

    LPDISPATCH *ppdispRoot;
    

    deklarieren?

    Nachhilfe in c++ 😉
    Wie mmuss ich

    *ppdispRoot = V_DISPATCH(&vRet);
      if ((*ppdispRoot) == NULL)
        return E_FAIL;
      pdispParagraphFormat->AddRef();  // keep a reference to the object
      VariantClear(&vRet)
    

    verstehen?



  • Hab den Source von einem bestehenden Projekt zusammenkopiert... musst Dur *ppdispRoot durch pdispParagraphFormat ersetzen:

    pdispParagraphFormat = V_DISPATCH(&vRet);
      if (pdispParagraphFormat == NULL)
        return E_FAIL;
      pdispParagraphFormat->AddRef();  // keep a reference to the object
      VariantClear(&vRet)
    

    Hab es nicht wirklich mit Word getestet...


Anmelden zum Antworten