AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein Webbrowser.OleObject mittels Vorfahren erreichen
Thema durchsuchen
Ansicht
Themen-Optionen

Webbrowser.OleObject mittels Vorfahren erreichen

Offene Frage von "oki"
Ein Thema von oki · begonnen am 14. Dez 2010 · letzter Beitrag vom 17. Jan 2011
Antwort Antwort
oki

Registriert seit: 30. Dez 2002
Ort: Brandshagen
1.819 Beiträge
 
Delphi 2007 Professional
 
#1

Webbrowser.OleObject mittels Vorfahren erreichen

  Alt 14. Dez 2010, 09:56
Hallo Leute,

ich hoffe, ich kann meine Frage verständlich formulieren. Ich möchte auf ein Textfeld in einem html-Document zugreifen. Das geht ja so:

wb.OleObject.Document.All.Item('ItemName').Value := 'Test';
Nun habe ich das Problem, dass ich nicht direkt über das BrowserControl zugreife sondern den Container Components nach dem Element durchsuche.
Und jetzt wirds kurz kompliziert. Warum nicht direkt. Ich benutze die TEmbeddedWb-Komponente. Binde ich EmbeddedWB in die uses ein, so bekomme ich eine Fehlermeldung des Compilers bei der Benutzung von Laufzeitbibliotheken. Das war so ne Sache mit zu vielen Pfaden, Zweigen? in der BPL-Nutzung. Ist schon ne' Zeit her, als ich mich darum gekümmert habe. Punkt ist, ich kann in der Unit EmbeddedWB nicht einbinden.

Jetzt dachte ich, egal, OleObject sollte durch einen Vorfahren implementiert werden und hab in einer kleinen Testanwendung mal mit Code-Folding geschaut wo das denn ist. Der Aufruf geht direkt zu TOleControl.OleObjekt. Na, dachte mir nichts leichter als das, da haben wir ja die Vererbung incl. Typ-Konvertierung.


TOleControl(Components[i]).OleObject.Document.All.Item('ItemName').Value := 'Test';
sollte die Lösung sein.

Nichts ist. Bis Item werden gültige Adressen angezeigt, dann ist Schluss. Exception mit Zugriff auf 0000.
Ich denke mal, die Typkonvertierung ist hier falsch. Vielleicht wird OleObject auch durch ein Interface eingebunden. Bin bei der ganzen Sache aber leider nicht fitt. Kann mir einer einen Weg zeigen wie ich das hinbekomme?
Das soll es aber nicht sein:


TEmbeddedWB(Components[i]).OleObject.Document.All.Item('ItemName').Value := 'Test';

Ich dank schon mal im Voraus,

Gruß oki
42
  Mit Zitat antworten Zitat
shmia

Registriert seit: 2. Mär 2004
5.508 Beiträge
 
Delphi 5 Professional
 
#2

AW: Webbrowser.OleObject mittels Vorfahren erreichen

  Alt 14. Dez 2010, 11:46
Ich möchte auf ein Textfeld in einem html-Document zugreifen.
Was verstehst du unter einem Textfeld?
Ist es ein Inputfield eines Webforms oder einfach nur ein HTML-Element mit einem gesetzen ID-Attribut.

Bis Item werden gültige Adressen angezeigt, dann ist Schluss.
Klarer Fall; es gibt das Item mit dem Namen "ItemName" in dem geladenen HTML nicht.
Andreas
  Mit Zitat antworten Zitat
Thom

Registriert seit: 19. Mai 2006
570 Beiträge
 
Delphi XE3 Professional
 
#3

AW: Webbrowser.OleObject mittels Vorfahren erreichen

  Alt 14. Dez 2010, 15:10
Da ich nur einmal kurz mit der TEmbeddedWb-Komponente gearbeitet hatte, bin ich dafür sicher kein Experte.

Ich habe allerdings das Beispiel aus Interesse einmal getestet: Und bei mir war schon nach Document Schluß. Also liefert OleObject schon keinen Zeiger auf Document. Da OleObject eine Variante als Ergebnis liefert, wird anschießend versucht, über _DispInvoke in der Unit Variants einen Zeiger auf Document zu erhalten. Das geschieht durch den Aufruf von VarDispInvoke in der Unit ComObj. Innerhalb dieser Prozedur wird mit GetIDsOfNames die DispatchID von Document innerhalb des Objektes OleObject ermittelt (203). Das funktioniert auch - deshalb wird im Anschluß DispatchInvoke aufgerufen. Hier treten die Probleme auf: Mein Delphi-Compiler (Delphi2010) interpretiert meinen Untersuchungen zufolge den Aufruf von Document aus den RTTI als Methode (DISPATCH_METHOD). Dabei hatte ich mein Formular mit dem Schalter {$METHODINFO ON} compiliert. Document ist aber eine Eigenschaft des übergeordneten Objektes (genauer gesagt: Es ist selbst wieder ein COM-Objekt). Und hier scheint der Fehler aufzutreten: Document wird aufgerufen, statt einen Zeiger auf dieses Objekt zu ermitteln. Dieser wäre nämlich notwendig, um sich zum nächsten Objekt (All) "durchzufragen".

Lange Rede, kurzer Sinn: So scheint das leider nicht zu funktionieren.

Da ich bei meinem aktuellen Projekt ebenfalls auf einige Bugs innerhalb der Ole-Umsetzung gestoßen bin, habe ich das anders gelöst:
Delphi-Quellcode:
procedure SetProperty(WebBrowser: TWebBrowser; NodeName, PropertyName: String; Value: OleVariant);
var
  All, Node: OleVariant;
begin
  //"All"-Objekt des Dokumentes ermitteln:
  All:=GetProp(WebBrowser.Document,'all');
  //HTML-Element aus dem "All"-Objekt ermitteln:
  Node:=GetProp(All,NodeName);
  //Eigenschaft des HTML-Elementes setzen:
  SetProp(Node,PropertyName,Value);
end;
Habe ich gerade getestet - funktioniert.
Die notwendigen Funktionen GetProp und SetProp habe ich aus der Unit BrowserTools im Downloadbereich der aktuellen Toolbox-Ausgabe. Dort die Source zum Beitrag Delphi und Google Maps.
Thomas Nitzschke
  Mit Zitat antworten Zitat
oki

Registriert seit: 30. Dez 2002
Ort: Brandshagen
1.819 Beiträge
 
Delphi 2007 Professional
 
#4

AW: Webbrowser.OleObject mittels Vorfahren erreichen

  Alt 15. Dez 2010, 08:24
Hallo und guten Morgen.

Sorry, dass ich gestern nicht mehr antworten konnte, ist der Stress ausgebrochen.
Shmia: Ich möchter auf ein Text-Eingabefeld zugreifen (input type Text). Grundsätzlich ist das für das aktuelle Problem wurscht, aber für alternative Wege vielleicht nicht. Zugriff auf ein Element Type button ist auch noch von nöten.

by Thom: Erst mal Dank für deine Mühe. Vorweg, in einem kleinen Testprojekt klappt der Zugriff:

wb.OleObject.Document.All.Item('ItemName').Value := 'Test';
ohne Probleme. WB ist dabei natürlich TEmbeddedWB. Das Problem steckt da, dass ich über einen Vorfahren/anderen Weg zugreifen will/muss. Also ohne Einbindung des Packages/Unit EmbeddedWB. In deiner Funktion übergibst du einen Parameter vom Typ TWebBrowser. Ich denke mal, du gehst davon aus, dass ich dann sicher TEmbeddedWB benutzen muss und die beiden nicht "kompatibel" sind. Damit bin ich dann wieder da wo ich vorher war, ich muss die entsprechenden Units einbinden. Konkret in Bezug auf deine Funktion suche ich jetzt für die Übergabe einen Typ, der einem Vorfahren entspricht. Dabei gehe ich davon aus, dass sowohl TWebBrowser wie auch TEmbeddedWB nicht die Klassen sind, die OleObjekt und somit Dokument einbinden. Das erfolgt doch sicher im Rahmen der Vererbung viel früher. Da ich an keinen anderen Eigenschaften interessiert bin will ich einfach auf diesen Vorfahren casten und somit auf die Eigenschaft zugreigen. Mal ein einfaches Beispiel, ich habe ein Panel und will den Namen haben. In meiner Funktion will ich den Parameter in dem ich das Panel übergebe aber auch für andere Komponenten benutzen. So definiere ich den Parameter als TComponent. Stopfe ich da das Panel rein (TComponent(MyPanel)), so kann ich innerhalb der Funktion mittels AComponent.Name den Namen des übergebenen Panels erreichen. Ja, und das nun mit dem Browser und zugriff auf OleObject. Mein Versuch mit TOleControl ging in die Hose. Welcher Klassentyp ist der richtige?


Gruß oki
42
  Mit Zitat antworten Zitat
Thom

Registriert seit: 19. Mai 2006
570 Beiträge
 
Delphi XE3 Professional
 
#5

AW: Webbrowser.OleObject mittels Vorfahren erreichen

  Alt 15. Dez 2010, 15:26
Hallo oki,
da hast Du natürlich Recht:
In deiner Funktion übergibst du einen Parameter vom Typ TWebBrowser. Ich denke mal, du gehst davon aus, dass ich dann sicher TEmbeddedWB benutzen muss und die beiden nicht "kompatibel" sind.
Da diese Prozedur aber nur das Interface von Document benötigt, könnte das einfach abgewandelt werden:
Delphi-Quellcode:
procedure SetProperty(Document: IDispatch; NodeName, PropertyName: String; Value: OleVariant);
var
  All, Node: OleVariant;
begin
  //"All"-Objekt des Dokumentes ermitteln:
  All:=GetProp(Document,'all');
  //HTML-Element aus dem "All"-Objekt ermitteln:
  Node:=GetProp(All,NodeName);
  //Eigenschaft des HTML-Elementes setzen:
  SetProp(Node,PropertyName,Value);
end;
Damit wäre es dann egal, ob das Dokument aus TWebBrowser.Document oder TEmbeddedWB.Document (bzw. TEmbeddedWB.OleObject.Document) stammt.

Ist aber unwichtig: Ich habe das Ganze heute noch einmal - im Gegensatz zu gestern - in einem neuen Projekt ausprobiert. Da hatte ich das einfach in mein aktuelles Projekt "integriert". Und siehe da: Es funktioniert! Das ist schon recht interessant, wie da der Compiler im Hintergrund "herumzaubert", so dass es - abhängig von den Randbedingungen - mal funktioniert und mal nicht...

Zu Deiner Frage: Du brauchst zum Zugriff auf das HTML-Element also nur - wie schon erwähnt - das Interface des Document-Objektes. Dabei ist es egal, ob es als IDispatch oder "verpackt" als (Ole-)Variant vorliegt. Damit der Compiler aber solchen Quelltext wie
Document.Irgendwas.NochWasAnderes akzeptiert, ist die Verwendung einer Variante besser. Schließlich generiert der Compiler hier den Code nur auf "gut Glück", da er noch nicht wissen kann, ob die Zeiger auch wirklich existieren. Erst zur Laufzeit "fragt" sich das Programm dann recht aufwändig (siehe mein erster Beitrag) von Objekt zu Objekt durch.

Praktisch bedeutet das: Du mußt von der Unit, die die Browser-Komponente beherbergt, das Document-Interface an die Unit, von der aus Du auf die Browser-Komponente zugreifen möchtes, weiterreichen:
Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
begin
  EmbeddedWB1.LoadFromFile('Test.html');
end;

procedure TForm1.FormShow(Sender: TObject);
begin
  Form2.Document:=EmbeddedWB1.Document;
end;
Von dort aus kannst Du dann ohne dem Wissen, aus welcher Browser-Komponente das Dokument stammt, darauf zugreifen:
Delphi-Quellcode:
procedure TForm2.Button1Click(Sender: TObject);
var
  Element: Variant;
begin
  if VarIsType(Document,varDispatch) then
  begin
    Element:=Document.All.Item('Test');
    if not VarIsClear(Element)
      then Element.InnerText:=Edit1.Text
      else ShowMessage('Element nicht gefunden');
  end;
end;
Ich habe das Ganze mal als Zip-Datei angehängt.
Miniaturansicht angehängter Grafiken
bild1.jpg   bild2.jpg  
Angehängte Dateien
Dateityp: zip EmbeddedWB_Test.zip (580,4 KB, 14x aufgerufen)
Thomas Nitzschke

Geändert von Thom (15. Dez 2010 um 15:38 Uhr)
  Mit Zitat antworten Zitat
shmia

Registriert seit: 2. Mär 2004
5.508 Beiträge
 
Delphi 5 Professional
 
#6

AW: Webbrowser.OleObject mittels Vorfahren erreichen

  Alt 15. Dez 2010, 17:37
...Ich möchter auf ein Text-Eingabefeld zugreifen (input type Text)
Dann gäbe es aber einen alternativen Weg durch das Objektmodell des IE (den ich für besser halte).
Ein Document kann ein oder mehrere "WebForms" enthalten.
Ein Form enthält dann ein (oder mehrere) Input Items.
Man kann dann z.B. mit einer Schleife über die Items und die Werte verändern.
Hier ein Beispiel:
Delphi-Quellcode:
procedure FillWebForm(document:OleVariant);
var
  FormItem, Element : OleVariant;
  j : integer;
  itemtype, itemname : string;
begin
  if document.forms.Length = then
    Exit; // keine WebForms vorhanden
  FormItem := document.forms.Item(0); // 1. Formular verwenden
  
  For j:= 0 to FormItem.Length-1 do
  begin
     Element := FormItem.Item(j);
     itemname := Element.Name;
     itemtype := UpperCase(Element.Type);
     if itemtype = 'TEXTthen
     begin
       maxlen := Element.MaxLength;
       Element.Value:= Copy('Hallo das ist ein Test', 1, maxlen);
     end
     else if itemtype = 'CHECKBOXthen
     begin
        // Checkbox zufällig setzen
        if system.Random > 0.5 then
           Element.Checked := True;
     end;

     // weitere Itemtypes sind BUTTON, CHECKBOX, SELECT-ONE, RADIO
  
  end;
  FormItem.Submit; // Webform absenden
end;
Andreas
  Mit Zitat antworten Zitat
oki

Registriert seit: 30. Dez 2002
Ort: Brandshagen
1.819 Beiträge
 
Delphi 2007 Professional
 
#7

AW: Webbrowser.OleObject mittels Vorfahren erreichen

  Alt 17. Jan 2011, 15:55
Hallo Leute,

es ist schon ein paar Tage her, aber ich bin an diesem Thema weiter gekommen. Es lag nicht an der Benutzung im speziellen sondern konkret an einer Stelle.

folgender Code arbeitet ohne Probleme:

Delphi-Quellcode:
  wb.OleObject.Document.All.Item('ItemName').Value := 'Test';
  wb.OleObject.Document.All.Item('ItemName').Value := Edit1.Text;

folgender nicht:

Delphi-Quellcode:
  NewText : String;
  ...
  NewText := 'Test';
  wb.OleObject.Document.All.Item('ItemName').Value := NewText;
aber so:

Delphi-Quellcode:
  NewText : String;
  ...
  NewText := 'Test';
  wb.OleObject.Document.All.Item('ItemName').Value := Variant(NewText);
Das schien das ganze Problem gewesen zu sein. Ich denke mal, dass mein Problem erst darurch aufgetaucht ist, dass ich in meiner kleinen Testanwendung Edit1.Text zugewiesen habe und in meinem eigentlichen Code einen String. Für mich war das das gleiche und so habe ich den Unterschied in der Zuweisung gar nicht erst beachtet. Nach dem ich mich durch die Hilfe mittels IXMLDocument2 ... Item usw. gehangelt hatte viel mir die variante Parameterverwendung auf. Naja, nun klappts mit der Typkonvertierung ohne Probleme. Zusätzlich hat mich natürlich noch der Compiler aus der Bahn geworfen, da er dann auch immer schon für die Prüfung auf Document Adresse 0000 ausgeworfen hatte. So ist das halt im Leben.

Wollte auf jeden Fall noch die Lösung posten, damit der Nächste nicht leer da steht.

Zusätzlich noch mal herzlichen Dank für die Code-Snippes zu testen.

Gruß oki

[edit] kurzer Nachtrag; das unter D2007; Gruß oki [/edit]
42
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:32 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz