Builder 2009: In einem Word Dokument Text ersetzen



  • Hallo,

    mit dem Builder 2009 funktioniert folgender Code nicht mehr

    Variant vOLEWord;
    	String strDatei, strMarke, strText;
    
    	strDatei = "c:\\111\\test.doc";
    
    	try
    	{
    		vOLEWord = Variant::CreateObject("Word.Application");
    
    		vOLEWord.OlePropertySet("Visible", true);
    
    		Variant vDokuments = vOLEWord.OlePropertyGet("Documents");
    
    		vDokuments.OleProcedure("Open", strDatei.t_str());
    
    		Variant vSelection = vOLEWord.OlePropertyGet("Selection");
    		Variant vFind = vSelection.OlePropertyGet("Find");
    
    		strMarke = "[name]";
    		strText = "Sepp";
    
    		// bis hier funktioniert alles wie gehabt, Word ist gestartet, das Dokument wurde geöffnet
    		// und mit der nächsten Funktion möchte ich den Text "[name]" durch "Sepp" ersetzten
    		vFind.OleProcedure("Execute",
    							StringToOleStr(strMarke),
    							EmptyParam,
    							EmptyParam,
    							EmptyParam,
    							EmptyParam,
    							EmptyParam,
    							EmptyParam,
    							EmptyParam,
    							EmptyParam,
    							StringToOleStr(strText),
    							2);
    	}
    	catch (Exception& e)
    	{
    		Application->MessageBox(e.Message.c_str(), L"OLE-Error", MB_ICONERROR);
    	}
    

    Die Funktion vFind.OleProcedure("Execute", ...
    liefert die vielsagende Exception "Ausnahmefehler aufgetreten" 😕

    Gruß und vielen Dank im voraus,

    Tom



  • Miedorf schrieb:

    [cpp] vDokuments.OleProcedure("Open", strDatei.t_str());

    Bei mir scheiterte es schon hier; vermutlich, weil ich das TCHAR-Mapping auf wchar_t gesetzt hatte.

    Es ist allgemein empfehlenswert, String::t_str() NICHT zu verwenden, da es unter gewissen Umständen Strings korrumpieren kann. In deinem Fall könntest du einfach, wie sonst ja auch, StringToOleStr() benutzen.

    Deinen Fehler kann ich auch mit nur vier "EmptyParam"-Parametern reproduzieren, aber woran es liegt, kann ich dir auch nicht sagen; in Word tritt jedenfalls eine Exception auf, die den Fehler verursacht.

    Du könntest versuchen, diesen Code nach Delphi zu portieren, um zu sehen, ob das Problem dort auch auftritt. Falls nicht, dann liegt möglicherweise ein Problem mit den C++-Wrapperklassen vor.



  • Danke audacia.

    gibt es eine andere (unter Builder 2009 funktionierende) Lösung in einem Word Dokument Text zu ersetzten? 🙄



  • Nachdem ich mir den Code nochmal genauer angesehen hatte, fiel mir auf, was EmptyParam eigentlich ist:

    // OleCtrls.hpp
    extern PACKAGE System::OleVariant __fastcall EmptyParam();
    

    Variant::OleProcedure() sind aber Funktionstemplates und übernehmen daher jeden beliebigen Typen - auch Funktionszeiger. Diese lassen sich implizit nach bool konvertieren; jeder Zeiger ungleich 0 ergibt den Wert True. Wenn du in Delphi (dort sind OLE-Fehlermeldungen aus einem Grund, den ich noch suche, ausführlicher) entsprechend Find.Execute ('someString', True, True, True, True); aufrufst, bekommst du prompt die passende Fehlermeldung zurück:

    Nur einer der Parameter für Mustervergleich, Ähnliche Schreibweise, Alle Wortformen oder Nicht bestimmt kann auf "Wahr" gesetzt werden.

    Die Lösung: Rufe EmptyParam auf, anstatt dessen Adresse zu übergeben.
    (Mithilfe von Sync Edit kannst du leicht für einen ganzen Abschnitt EmptyParam durch EmptyParam() ersetzen.)



  • Vielen Dank audacia ... Du hast wirklich Ahnung 👍



  • audacia schrieb:

    in Delphi (dort sind OLE-Fehlermeldungen aus einem Grund, den ich noch suche, ausführlicher)

    Grund gefunden, QC-Report erstellt:
    QC #71090: Variant::OleProcedure does not handle DISP_E_EXCEPTION properly
    Workaround ist im Report beschrieben.



  • Hallo,

    es geht auch dank der OfficeXP Server Komponente mit diesen Zeilen :

    --------------------------------
    // Definiton der Variablen für die Übergabe an "GoTo"-Funktion
    typedef enum WdGoToItem
    {
    wdGoToBookmark = 0xFFFFFFFF,
    wdGoToSection = 0,
    wdGoToPage = 1,
    wdGoToTable = 2,
    wdGoToLine = 3,
    wdGoToFootnote = 4,
    wdGoToEndnote = 5,
    wdGoToComment = 6,
    wdGoToField = 7,
    wdGoToGraphic = 8,
    wdGoToObject = 9,
    wdGoToEquation = 10,
    wdGoToHeading = 11,
    wdGoToPercent = 12,
    wdGoToSpellingError = 13,
    wdGoToGrammaticalError = 14,
    wdGoToProofreadingError = 15
    } WdGoToItem;
    //---------------------------------------------------------------------------
    __fastcall TForm4::TForm4(TComponent* Owner)
    : TForm(Owner)
    {
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm4::Button1Click(TObject *Sender)
    {
    AnsiString Filename ;

    try
    {

    if (OpenDialog1->Execute())
    Filename = OpenDialog1->FileName;
    else
    exit(1);

    WordApplication1->Connect();
    WordApplication1->set_Visible(true);
    // WordApplication1->Documents->Open(OleVariant(StringToOleStr(Filename)));

    WordApplication1->Documents->Add(OleVariant(StringToOleStr(Filename))) ;

    // WordDocument1->ConnectTo(WordApplication1->ActiveDocument);

    WordApplication1->Selection->GoTo(OleVariant(wdGoToBookmark),TNoParam(),TNoParam(),OleVariant(StringToOleStr((AnsiString)"Adresse"))) ;
    WordApplication1->Selection->set_Text(StringToOleStr((AnsiString)"Therese-Giehse-Str. 4"));

    WordApplication1->Disconnect();
    }
    catch (Exception& e)
    {
    ShowMessage("Word error: "+e.Message );
    WordApplication1->Disconnect();
    }

    --------------------------------

    Diese setzten ein Formular mit den Komponenten WordApplication, OpenDialog voraus. Ausserdem ein Word-Dokument mit einer Textmarke [Adresse] , die dann
    durch den Strassennamen ersetzt wird.

    Gruß
    Bernd Sawatzki



  • bsawatzki schrieb:

    es geht auch dank der OfficeXP Server Komponente mit diesen Zeilen

    Schon, aber die Dispinterface-Variante hat ja gewisse Vorteile, beispielsweise die Versionsunabhängigkeit. (Und natürlich auch Nachteile, etwa in der Performance und bei der Typsicherheit.)

    Außerdem wäre besonders in C++Builder 2009 die explizite Verwendung von AnsiString unangebracht. In den meisten Fällen ist der Cast nach AnsiString oder nach OleVariant ohnehin überflüssig.


Anmelden zum Antworten