Wie kann ich Ereignisse eines ActiveX-Controls abfangen

Nutzung, Komponenten, .NET

Moderator: Moderatoren

Antworten
Benutzeravatar
Markus Walter
Programmier-Gott
Programmier-Gott
Beiträge: 1018
Registriert: Di, 24. Jan 2006 10:22
Wohnort: Saarland

Wie kann ich Ereignisse eines ActiveX-Controls abfangen

Beitrag von Markus Walter »

Hi,

lt. Dokumentation sollten sich doch Mausereignisse, die auf einem ActiveX-Control ausgelöst werden, über die "normalen" Xbase-Callback-Slots abfangen lassen?!

Das funktioniert aber offensichtlich nicht (zumindest nicht beim xbpHtmlViewer).

Hat jemand eine Idee?

Ich habe das Sample aus der Hilfe des HtmlViewers entsprechend verändert...

Code: Alles auswählen

  #include "XBP.CH"
  #include "AppEvent.CH"


  PROCEDURE Main() 
   LOCAL oDlg
   LOCAL oHTML
   LOCAL nEvent, mp1, mp2, oXbp
   LOCAL oDA

    //
    // Erzeugen des Hauptfensters der Anwendung
    //

    oDlg := XbpDialog():new( Appdesktop() ) 
    oDlg:title 	  := "HTMLViewer-Beispiel"
    oDlg:taskList := .T.
    oDlg:close    := {|| PostAppEvent(xbeP_Quit,,, oDlg) }
    oDA           := oDlg:drawingArea
    oDlg:create( ,, {50,50}, {640,480},, .F. )

    oDA:resize    := {|| ResizeControl(oHTML)}


    //
    // Erzeugen des XbpHTMLViewer-Objekts
    //

    oHTML := XbpHTMLViewer():new( oDA ) 

    oHTML:create( ,, {10,10},{450,300}  )


    // Warum geht`s nicht?????
    oHtml:rbclick := {| aPos, uNIL, self | tone(100,3) }

 
    //
    // Navigieren zur Seite "www.alaska-software.com"
    //
    oHTML:navigate( "www.alaska-software.com" )


    // 
    // Anzeigen des Hauptfenster und bearbeiten
    // von Ereignissen, bis das Fenster geschlossen
    // wird
    //
    ResizeControl( oHTML )

    oDlg:show() 

    SetAppWindow( oDlg ) 
    SetAppFocus( oHTML )


    nEvent := xbeP_Quit 

    DO WHILE nEvent != xbeP_Close 
      nEvent := AppEvent( @mp1, @mp2, @oXbp )
      oXbp:handleEvent( nEvent, mp1, mp2 )
    ENDDO

    oDlg:destroy()

  RETURN 


  // Anpassen der Größe des XbpHTMLViewer-Objekts,
  // sodass es immer die gesamte Fläche der
  // Drawing Area des Dialogs einnimmt
  PROCEDURE ResizeControl( oHTML )
    LOCAL oParent := oHTML:setParent()
      oHTML:setPosAndSize( {0,0}, oParent:currentSize() )
  RETURN

  // Überladene AppSys()-Prozedur zur Unterdrückung
  // der Erzeugung des Standard-XbpCrt-Fensters
  PROCEDURE AppSys()
  RETURN 
Gruß
Markus

Mitglied der XUG Saarland-Pfalz
Benutzeravatar
Martin Altmann
Foren-Administrator
Foren-Administrator
Beiträge: 16501
Registriert: Fr, 23. Sep 2005 4:58
Wohnort: Berlin
Hat sich bedankt: 111 Mal
Danksagung erhalten: 48 Mal
Kontaktdaten:

Beitrag von Martin Altmann »

Hallo Markus,
ich meine, dass man dazu erst mal eine entsprechende Option setzen muss - habe selber noch nicht viel mit ActiveX (abgesehen von RMChart) gemacht, kommt aber noch!
Ich meine aber, dass ähnliches auch bei dem RTF-Control nötig ist...

Viele Grüße,
Martin
:grommit:
Webseite mit XB2.NET und ausschließlich statischem Content in Form von HTML-Dateien: https://www.altem.de/
Webseite mit XB2.NET und ausschließlich dynamischem Content in Form von in-memory-HTML: https://meldungen.altem.de/

Mitglied der XUG Osnabrück
Vorsitzender des Deutschsprachige Xbase-Entwickler e. V.
Benutzeravatar
Martin Altmann
Foren-Administrator
Foren-Administrator
Beiträge: 16501
Registriert: Fr, 23. Sep 2005 4:58
Wohnort: Berlin
Hat sich bedankt: 111 Mal
Danksagung erhalten: 48 Mal
Kontaktdaten:

Beitrag von Martin Altmann »

So,
habe mal gestöbert - ist dafür nicht :subscribeEvent() der ActiveXObject()-Klasse gedacht?

Viele Grüße,
Martin
:grommit:
Webseite mit XB2.NET und ausschließlich statischem Content in Form von HTML-Dateien: https://www.altem.de/
Webseite mit XB2.NET und ausschließlich dynamischem Content in Form von in-memory-HTML: https://meldungen.altem.de/

Mitglied der XUG Osnabrück
Vorsitzender des Deutschsprachige Xbase-Entwickler e. V.
Benutzeravatar
Markus Walter
Programmier-Gott
Programmier-Gott
Beiträge: 1018
Registriert: Di, 24. Jan 2006 10:22
Wohnort: Saarland

Beitrag von Markus Walter »

Hallo Martin,

da war ich in der Doku auch schon, aber da steht:

Code: Alles auswählen

Hinweis: Die Methode :subscribeEvent() wird intern vom Ereignisbehandlungsmechnismus der Klasse ActiveXObject verwendet. Die Methode wird in einer Xbase++-Anwendung normalerweise nicht direkt verwendet. 
Nach meinem Verständnis müsste da auch eher :suspendEvent( ) verwendet werden...

Aber davon ab: beide Methoden verlangen eine <nDISPID> die gibt es für "rechten Mausclick" nicht...

Aber beim XbpActiveXControl() ist ja der
Slot: :rbClick := {| aPos, uNIL, self | ... }
extra "ganz normal beschrieben", so dass mein Code-Beispiel eigentlich funktionieren müsste...

Es sein denn...

Code: Alles auswählen

Hinweis: Nicht alle ActiveX-Steuerelemente unterstützen Mausereignisse. Wird das ActiveX-Ereignis "Click" durch das Steuerelement nicht generiert, wird die Methode :click() nicht ausgeführt. 
Benutzt irgendjemand ein anderes ActiveXControl, dass Mausereignisse weitergibt? Falls es der IE wirklich nicht tun sollte...
Gruß
Markus

Mitglied der XUG Saarland-Pfalz
Benutzeravatar
andreas
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 1902
Registriert: Mi, 28. Sep 2005 10:53
Wohnort: Osnabrück
Hat sich bedankt: 4 Mal
Kontaktdaten:

Beitrag von andreas »

Hallo Markus,

das solte die richtige Methode sein: dynamicCast

Hier ist Ausschnitt aus der Hilfe:
Ähnlich den Callback Slots, die von Xbase Parts zur Verfügung gestellt werden, nutzen COM/ActiveX-Komponenten oftmals Nachrichten, um mit dem Nutzer der Komponente zu kommunizieren. Die zusätzlichen Merkmale, die zur Verarbeitung von COM/ActiveX-Nachrichten erforderlich sind, werden von der Klasse ActiveXObject() zur Verfügung gestellt. Diese Klasse ist von der Klasse AutomationObject abgeleitet.
Um auf COM/ActiveX Ereignisse reagieren zu können, muß ein Codeblock definiert werden, der immer dann ausgewertet wird, wenn das Ereignis ausgelöst wird. Der Codeblock muß einer Instanzvariablen zugewiesen werden, die den selben Namen wie das COM/ActiveX-Ereignis besitzt.

Alternativ kann für die Bearbeitung eines COM/ActiveX-Ereignisses auch eine Ereignisbehandlungsmethode in einer von ActiveXObject abgeleiteten Klasse implementiert werden. Diese Callback-Methode muß den selben Namen haben wie das COM/ActiveX-Ereignis, und wird immer dann ausgeführt, wenn das COM/ActiveX-Ereignis ausgelöst wird.
Erzeugen eines Objektes der Klasse ActiveXObject
Instanzen der Klasse ActiveXObject können auf zwei Arten erzeugt werden. Um ein solches Objekt direkt zu erzeugen, kann die Klassenmethode :create() gerufen werden. Bereits erzeugte Objekte, beispielsweise durch einen Aufruf der Funktionen CreateObject() oder GetObject(), müssen hingegen durch eine Typwandlung (cast) in ein Objekt der Klasse ActiveXObject überführt werden. Hierfür wird die Methode :dynamicCast verwendet. Dieser Methode muß das Klassenobjekt der Zielklasse oder eine Zeichenkette, welche die Zielklasse bezeichnet, als Parameter übergeben werden.

#pragma library( "ascom10.lib" )
PROCEDURE MAIN
LOCAL oWord, cMsg

oWord := GetObject( NIL, "Word.Application" )
IF NIL == oWord
? "Fehler"
? ComLastError()
? ComLastMessage()
ENDIF

oWord:visible := .T.

//
// Typenwandlung des AutomationObject in eine Instanz
// der Klasse ActiveXObject. Ein ActiveXObject wird
// benötigt, um auf COM/ActiveX Ereignisse zu
// reagieren.
//
//
oWord := oWord:dynamicCast( "ActiveXObject" )


//
// Zuweisen eines Codeblockes an den Callback-Slot
// des COM/ActiveX-Ereignisses "quit"
//
oWord:quit := { || MsgBox("In Word ist das Quit-Ereignis aufgetreten") }

cMsg := "Beenden Sie Word, um den Nachrichtendialog zu sehen. "
cMsg += "Drücken Sie eine Taste, um die Anwendung zu beenden."

WAIT cMsg


RETURN
Gruß,

Andreas
VIP der XUG Osnabrück
Benutzeravatar
Markus Walter
Programmier-Gott
Programmier-Gott
Beiträge: 1018
Registriert: Di, 24. Jan 2006 10:22
Wohnort: Saarland

Beitrag von Markus Walter »

Hallo Andreas,

XbpHtmlViewer ist ja bereits von ActiveXControl abgeleitet.

:dynamicCast wird verwendet um aus einem AutomationObjekt ein ActiveXObjekt zu machen (so habe ich es zumindest verstanden...)
Gruß
Markus

Mitglied der XUG Saarland-Pfalz
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12903
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 44 Mal

Beitrag von AUGE_OHR »

hi,
Markus Walter hat geschrieben:

Code: Alles auswählen

Hinweis: Die Methode :subscribeEvent() wird intern vom Ereignisbehandlungsmechnismus der Klasse ActiveXObject verwendet. Die Methode wird in einer Xbase++-Anwendung normalerweise nicht direkt verwendet. 
richtig.
Markus Walter hat geschrieben: Aber davon ab: beide Methoden verlangen eine <nDISPID> die gibt es für "rechten Mausclick" nicht...
hm ... versuch mal

Code: Alles auswählen

cEventName := "Click"
xVar := oWmp:isEventPublished( cEventName )
IF xVar <> Nil
lSuccess := oWmp:SubscribeEvent( xVar, { |nButton, nShiftState, fX , fY | ;
    IF(nButton=4,PostAppEvent(xbeM_MbClick),NIL) } ) // Wheel = middle
MSGBOX("hat geclickt"+STR(nButton)+" "+STR(nShiftState)+" "+STR(fX)+" "+STR(fY) ) } )
Markus Walter hat geschrieben: Aber beim XbpActiveXControl() ist ja der
Slot: :rbClick := {| aPos, uNIL, self | ... }
extra "ganz normal beschrieben", so dass mein Code-Beispiel eigentlich funktionieren müsste...
nope, du kannst ein den Slot nicht einfach überschreiben da er
"abgefangen" wird. speziell beim :rbClick wirst du ohne entsprechende
Property diesen nicht "überschreiben" können. Wenn du also z.b. keine
Property :enableContextMenu hast welche du auf .F. setzten kannst so
denke ich, das du aus Xbase++ nicht :rbClick setzten kannst.
Markus Walter hat geschrieben: Es sein denn...

Code: Alles auswählen

Hinweis: Nicht alle ActiveX-Steuerelemente unterstützen Mausereignisse. Wird das ActiveX-Ereignis "Click" durch das Steuerelement nicht generiert, wird die Methode :click() nicht ausgeführt. 
Benutzt irgendjemand ein anderes ActiveXControl, dass Mausereignisse weitergibt? Falls es der IE wirklich nicht tun sollte...
yup, den M$ Mediaplayer ... da gibt es massig solche Events, teilweise
sehr "tricki" ... so gibt es z.b. den Event "keypress", ABER der funktioniert
nur im Fullscreen Modus ... bis ich das raus hatte ...

gruss by OHR
Jimmy
Günter Beyes
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 315
Registriert: Mo, 16. Okt 2006 13:04
Wohnort: Region Stuttgart

Beitrag von Günter Beyes »

Hallo Markus,
Markus hat geschrieben:lt. Dokumentation sollten sich doch Mausereignisse, die auf einem ActiveX-Control ausgelöst werden, über die "normalen" Xbase-Callback-Slots abfangen lassen?!

Das funktioniert aber offensichtlich nicht (zumindest nicht beim xbpHtmlViewer).
beim Webbrowser kommen alle Maus- und Tastaturereignisse im HTML-Dokument an, auf das du über ::BrowserControl:Document zugreifen kannst.

Dahinter steht das HTMLDocument-Objekt aus der mshtml.dll.

Die Aktivierung des Kontextmenüs zum Beispiel kannst du am einfachsten über den "oncontextmenu"-Event abfangen. Hat den Vorteil, dass die Kontextmenü-Taste mit berücksichtigt wird.

Code: Alles auswählen

XbpWebBrowser erweitern:

neue IVAR oDocument (EXPORTED)
neue Methode onContextMenu() (EXPORTED)

#define DISPID_ONCONTEXTMENU  1023                  

// unterdrückt das Kontextmenü
METHOD XbpWebBrowser:onContextMenu()

IF ::oDocument <> NIL
    ::oDocument:parentWindow:event:returnValue := FALSE
ENDIF

RETURN TRUE

// folgendes in XbpWebBrowser:DocumentComplete() einbauen:

IF ::oDocument <> NIL
   // Ob das wirklich nötig ist, weiss ich nicht...
   ::oDocument:unsubscribeEvent( DISPID_ONCONTEXTMENU )
   ::oDocument:destroy()
   ::oDocument := NIL
ENDIF
 
// wir brauchen den Event "oncontextmenu"
::oDocument := ::BrowserControl:Document
::oDocument := ::oDocument:dynamicCast( ActiveXObject() )
   
::oDocument:subscribeEvent( "oncontextmenu", {||::onContextMenu() } ) 

Falls dynamisch erzeugter HTML-Code angezeigt wird, muss eventuell :DocumentComplete() manuell aufgerufen werden, je nach dem wie man den HTML-Code an den Browser übergibt.

Nachtrag:
Nach einigem Testen muss ich sagen -- Alles gut und schön, funktioniert aber nur nach dem ersten Aufruf einer URL. Navigiert man zu einer anderen URL, hängt der Browser. :?

Hat jemand eine Idee, was da los ist?


Viele Grüße,
Günter
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12903
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 44 Mal

Beitrag von AUGE_OHR »

hi,
Günter Beyes hat geschrieben:

Code: Alles auswählen

#define DISPID_ONCONTEXTMENU  1023                  
 
// wir brauchen den Event "oncontextmenu"
::oDocument := ::BrowserControl:Document
::oDocument := ::oDocument:dynamicCast( ActiveXObject() )
   
::oDocument:subscribeEvent( "oncontextmenu", {||::onContextMenu() } ) 
müsste es nicht

Code: Alles auswählen

::oDocument:subscribeEvent( DISPID_ONCONTEXTMENU,;
                                           {||::onContextMenu() } ) 
also nDISPID heissen ?

ich habe deinen Gedanke aufgenommen und weitere Test gemacht.
Resultat : noch nicht mal "Click", "onClick" oder sonstwas mich click
funktioniert alles nicht d.h. ich bekomme bei o:isEventPublished immer
nur 0 zurück (nicht vorhanden).

Code: Alles auswählen

ALTD()
cEventName := "Click" 
nVar := ::isEventPublished( cEventName ) 
IF nVar > 0 
     lSuccess := ::SubscribeEvent( nVar, { |nButton, nShiftState, fX , fY | ; 
     MSGBOX("click"+STR(nButton)+" "+STR(nShiftState)+" "+STR(fX)+" "+STR(fY) )  })
ENDIF
Wenn ich mir das ganze im Debugger ansehe hab ich nur IWebBrowser2
als Interface was ich mit Xbase++ ansprechen kann. Alle anderen Class(en)
kann man zwar mit C++ oder IE benutzen, aber wohl nicht mit Xbase++.

gruss by OHR
Jimmy
Günter Beyes
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 315
Registriert: Mo, 16. Okt 2006 13:04
Wohnort: Region Stuttgart

Beitrag von Günter Beyes »

Hallo Jimmy,
Jimmy hat geschrieben:Wenn ich mir das ganze im Debugger ansehe hab ich nur IWebBrowser2 als Interface was ich mit Xbase++ ansprechen kann. Alle anderen Class(en) kann man zwar mit C++ oder IE benutzen, aber wohl nicht mit Xbase++.
nach meiner Meinung müsste vieles davon auch mit Xbase++ gehen.

Probier mal, wie ich geschrieben habe,

Code: Alles auswählen

oDocument := ::BrowserControl:Document
Der Debugger zeigt:

oDocument:InterfaceName ist "DispHTMLDocument"

und nun:

Code: Alles auswählen

oDocument := oDocument:dynamicCast( ActiveXObject() )

nDispId := oDocument:isEventPublished( "onclick" ) 
nDispId enthält -600 -- "onclick" wird unterstützt.

In der Helpkit-Dokumentation der mshtml.dll findest du unter "HTMLDocument" die Namen aller unterstützten Ereignisse.
müsste es nicht

Code: Alles auswählen

::oDocument:subscribeEvent( DISPID_ONCONTEXTMENU, {||::onContextMenu() } ) 
also nDISPID heissen?

Stimmt. Danke! Aber auch wenn ich korrekterweise nDISPID statt des Eventnamens verwende, ändert das leider nichts an der Problemlage...

Der Codeblock wird tatsächlich aufgerufen, wenn das Ereignis eintritt. So weit so gut. Aber nach dem ersten Navigieren funktionieren Hyperlinks nicht mehr, und es kann passieren, dass der Browser regelrecht "hängt" und nur über den Taskmanager beendet werden kann. :?

Meine Überlegung ist, dass jeder erfolgreiche Navigationsvorgang ein neues HTMLDocument erzeugt. Also muss ich beim vorherigen HTMLDocument :unsubscribeEvent() ausführen, eventuell gefolgt von :destroy(). Für das aktuelle HTMLDocument muss dann :subscribeEvent() aufs Neue aufgerufen werden.

Tue ich dieses, gibt es die beschriebenen Probleme. Tue ich es nicht, sieht es aber auch nicht besser aus. :?

Viele Grü0e,
Günter
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12903
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 44 Mal

Beitrag von AUGE_OHR »

hi,
Günter Beyes hat geschrieben: Der Debugger zeigt:
oDocument:InterfaceName ist "DispHTMLDocument"
hm ... soweit bin ich wohl nicht gekommen
Günter Beyes hat geschrieben: und nun:

Code: Alles auswählen

oDocument := oDocument:dynamicCast( ActiveXObject() )
nDispId := oDocument:isEventPublished( "onclick" ) 
nDispId enthält -600 -- "onclick" wird unterstützt.
hm ... jetzt muss ich doch noch mal nachfragen: Das HtmlViewer Interface
verwendet IWebBrowser2 welches die ::BrowserControl enthält, richtig ?

Nun verwendest du :dynamicCast( ActiveXObject() ) auf das "aktive"(?)
Interface und fügst eine neues hinzu ??? d.h. man hat dann 2 ?
Günter Beyes hat geschrieben: In der Helpkit-Dokumentation der mshtml.dll findest du
em, äh ... wo finde ich die ?
auch kann ich mit COMM Assistant nicht die Datei \system32\mshtml.dll
bearbeiten und mir ein help files erstellen lassen ... :(
dafür gibt es aber ein mshtml.TLB file, wohl für Event Constanten.
Günter Beyes hat geschrieben: Der Codeblock wird tatsächlich aufgerufen, wenn das Ereignis eintritt. So weit so gut. Aber nach dem ersten Navigieren funktionieren Hyperlinks nicht mehr, und es kann passieren, dass der Browser regelrecht "hängt" und nur über den Taskmanager beendet werden kann. :?
ich hab mal in der Richtung bei MSDN weiter gesucht :
http://msdn2.microsoft.com/en-us/library/aa741313.aspx

nach der Grundeinführung in die WebControls gibt es dann den Abschnitt
"Providing Extra Control" wo von "MSHTML components" gesprochen wird.
"Hosts of either component can obtain extra control over functionality by implementing the IDocHostUIHandler and IDocHostShowUI interfaces. These interfaces are commonly used to override the context menus that are supplied by default for the browser."
... und woher bekomme ich die IDocHostxxx ?
"The component obtains these interfaces from the host by calling QueryInterface on the IOleClientSite interface implemented by the hosting application"
... und nun auch noch ein IOleClientSite ...
aber zurück zum eigendlichen Problem
"Overriding the Context Menus
The WebBrowser Control's context menus can be overridden entirely by implementing the IDocHostUIHandler::ShowContextMenu method. Returning E_NOTIMPL or S_FALSE from this method indicates to the WebBrowser Control that it should display its own standard context menu. However, returning S_OK causes the WebBrowser Control not to display its menus, and it assumes that the host has performed the appropriate action. "
also sollte man sich mal die :ShowContextMenu Methode ansehen
http://msdn2.microsoft.com/en-us/library/aa753264.aspx

aber auch das bringt mich nicht richtig weiter. geht man aber ein wenig
rauf im Tree an der linken Seite so kommt man nach
http://msdn2.microsoft.com/en-us/library/aa768380.aspx

zumindest kann ich da die angesprochenen Interface "sehen", aber es
sieht völlig anders aus wie die mit COM Assistant erzeugte help Datei ?

meine Frage wäre nun, wie kommt man an die ganzen anderen aktiveX
Interface mit Xbase++ ran oder geht das (wieder mal) nur mit C/C++ ?

gruss by OHR
Jimmy
Günter Beyes
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 315
Registriert: Mo, 16. Okt 2006 13:04
Wohnort: Region Stuttgart

Beitrag von Günter Beyes »

Hallo Jimmy,

erstmal vorab: Das Problem ist gelöst :D

Ich hatte geschrieben:
Meine Überlegung ist, dass jeder erfolgreiche Navigationsvorgang ein neues HTMLDocument erzeugt. Also muss ich beim vorherigen HTMLDocument :unsubscribeEvent() ausführen, eventuell gefolgt von :destroy(). Für das aktuelle HTMLDocument muss dann :subscribeEvent() aufs Neue aufgerufen werden.
Voll daneben! Das HTMLDocument bleibt als Objekt offenbar immer dasselbe, nur sein Inhalt ändert sich beim Navigieren. Es reicht also, wenn :subscribeEvent() ein einziges Mal aufgerufen wird. Kein :unsubscribeEvent(), kein :destroy().

Kurz gesagt: Am XbpWebBrowser-Sample sind lediglich folgende minimalen Änderungen nötig, um das Kontextmenü zu unterdrücken.

Code: Alles auswählen

#define DISPID_ONCONTEXTMENU 1023

// zwei neue IVARs
VAR    oDocument       READONLY

VAR    enableContextMenu // in ::init() mit TRUE vorbelegen

// eine neue Methode
INLINE METHOD ContextMenuHandler()

LOCAL oEvent

IF ! ::enableContextMenu
   oEvent := ::oDocument:parentWindow:event
   oEvent:returnValue := FALSE
ENDIF

RETURN TRUE

// Erweiterung in der Methode :DocumentComplete() :
IF ::BrowserControl:IsBusy() == FALSE
   ::lIsNavigating := .F.
   lAddToHistory := .T.
		
   IF ::oDocument = NIL
      ::oDocument := ::BrowserControl:Document
      ::oDocument := ::oDocument:dynamicCast( ActiveXObject() )
			
      ::oDocument:subscribeEvent( DISPID_ONCONTEXTMENU, {||::ContextMenuHandler() } )
   ENDIF
ENDIF

// und im aufrufenden Code:

XbpWebBrowser:enableContextMenu := FALSE
Jimmy hat geschrieben:Jetzt muss ich doch noch mal nachfragen: Das HtmlViewer Interface verwendet IWebBrowser2 welches die ::BrowserControl enthält, richtig ?
Genau. XbpWebBrowser:BrowserControl enthält ein XbpHtmlViewer-Objekt, und dahinter steht das IWebBrowser2-Interface.
Jimmy hat geschrieben:Nun verwendest du :dynamicCast( ActiveXObject() ) auf das "aktive"(?) Interface und fügst eine neues hinzu ??? d.h. man hat dann 2 ?
Genauer gesagt wende ich :dynamicCast( ActiveXObject() ) auf das AutomationObject an, welches XbpHtmlViewer:Document mir zurückliefert ! Damit wird das AutomationObject zum ActiveXObject, so dass nun die Methode :subscribeEvent() zur Verfügung steht.

Wie ich das verstehe, ändert :dynamicCast() am zugrundeliegenden COM-Interface gar nichts, und verdoppelt es auch nicht. Es ändert sich lediglich die Verpackung.
Jimmy hat geschrieben:Auch kann ich mit COM Assistant nicht die Datei \system32\mshtml.dll bearbeiten und mir ein help files erstellen lassen...
Hmm... Das funktioniert bei mir zur Zeit auch nicht mehr. Sehr merkwürdig. Mshtml.dll und mshtml.tlb haben völlig unterschiedliches Datum und unterschiedliche Versionsnummern. Wer war das?! Windows-Update??? :iconbiggrin:

Bei Bedarf kann ich dir mshtml.chm zur Verfügung stellen (3,2 MB).
IDocHostUIHandler, IDocHostShowUI, IOleClientSite...
Ja, die sind ein Fall für C/C++, oder für Cockpit. Zumindest im vorliegenden Fall aber nicht unbedingt erforderlich.

Viele Grüße,
Günter
Benutzeravatar
Markus Walter
Programmier-Gott
Programmier-Gott
Beiträge: 1018
Registriert: Di, 24. Jan 2006 10:22
Wohnort: Saarland

Beitrag von Markus Walter »

Hallo Günter,

super, funktioniert wie gewünscht.

Da ich aber unverschämt bin... :wink:

Wie kann ich denn jetzt bestimmte Tastatur-Events abfangen (z. B. möchte ich, dass wenn ESC gedrückt wird, der Dialog geschlossen wird, in den der XbpHtmlViewer eingebettet ist)?

Gruß
Markus
Gruß
Markus

Mitglied der XUG Saarland-Pfalz
Günter Beyes
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 315
Registriert: Mo, 16. Okt 2006 13:04
Wohnort: Region Stuttgart

Beitrag von Günter Beyes »

Hallo Markus,

da müsstest du den Event "onkeypress" von HTMLDocument abfangen und
im Eventhandler ::oDocument:parentWindow:event darauf untersuchen, ob ESC gedrückt worden ist. Als DISPID probier mal DISPID_ONKEYPRESS (=13).

Habe leider im Moment keine Zeit.. versuch mal in MSDN die Beschreibung von onkeypress und das erwähnte Event-Objekt zu finden.

Viele Grüße,
Günter
Benutzeravatar
Markus Walter
Programmier-Gott
Programmier-Gott
Beiträge: 1018
Registriert: Di, 24. Jan 2006 10:22
Wohnort: Saarland

Beitrag von Markus Walter »

Hallo Günter,

super, es klappt.

Man muss allerdings
#define DISPID_KEYPRESS -603

verwenden...
Gruß
Markus

Mitglied der XUG Saarland-Pfalz
J.Renseler
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 151
Registriert: Do, 15. Nov 2007 11:40
Wohnort: Krefeld
Kontaktdaten:

Re: Wie kann ich Ereignisse eines ActiveX-Controls abfangen

Beitrag von J.Renseler »

Hallo,

ich muss den Thread leider nochmal nach vorne holen.

Ich muss wie Markus auch die ESC Taste abfragen. Wie ich das Event des Tastendrucks an sich abfange habe ich dank euch schon verstanden. Wie aber kann ich dann abfragen ob die ESC Taste gedrückt wurde?

Wäre nett wenn mir jemand das noch etwas näher erklären könnte.

Danke und Gruß Jannik
Kassensysteme für den Einzelhande http://ab-software.de
Mitglied der XUG-Cologne http://www.xug-cologne.de
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12903
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 44 Mal

Re: Wie kann ich Ereignisse eines ActiveX-Controls abfangen

Beitrag von AUGE_OHR »

J.Renseler hat geschrieben:ich muss den Thread leider nochmal nach vorne holen.
das ist doch kein Problem
J.Renseler hat geschrieben:Ich muss wie Markus auch die ESC Taste abfragen. Wie ich das Event des Tastendrucks an sich abfange habe ich dank euch schon verstanden. Wie aber kann ich dann abfragen ob die ESC Taste gedrückt wurde?
du solltes nochmal genau sagen was du meinst, den HTMLviewer ?

c:\ALASKA\XPPW32\Source\SYS\axctrls.prg das ist der Source zur HTMLviewer Class.

ganz "allgemein"

Code: Alles auswählen

CASE nEvent == xbeP_Keyboard .AND. mp1 == xbeK_ESC
   PostAppEvent( xbeP_Close,,,SetAppWindow() )
oder meinst du es "allgemein" mit activeX ? :subscribeEvent()


wenn mal "viele" Event hat, wie bei den Codejock ActiveX dann wird man "nicht jeden einzeln" codieren.

Code: Alles auswählen

// alle #define fangen mit "Ev" an
#define EvClick               "Click"
#define EvDblClick            "DblClick"

#define EvDropDown            "DropDown"
#define EvKeyDown             "KeyDown"
#define EvKeyPress            "KeyPress"
#define EvKeyUp               "KeyUp"
#define EvMouseDown           "MouseDown"
#define EvMouseMove           "MouseMove"
#define EvMouseUp             "MouseUp"
ich lege für den Event "click" die #define EvClick an

Code: Alles auswählen

METHOD HX_Combo:DefEvent()
   ::SubscribeEvent( EvClick       , {|| ::_itemSelected()  })
   ::SubscribeEvent( EvDblClick    , {|| ::_itemSelected()  })
nun wird bei Events oft "Parameter" angegeben ... was mache ich damit ?

Code: Alles auswählen

   ::SubscribeEvent( EvMouseDown   , {|Button,Shift,X,Y|::_MouseDown(Button,Shift,X,Y) })
   ::SubscribeEvent( EvMouseMove   , {|Button,Shift,X,Y|::_MouseMove(Button,Shift,X,Y) })
   ::SubscribeEvent( EvMouseUp     , {|Button,Shift,X,Y|::_MouseUp  (Button,Shift,X,Y) })
an diesem Beispiel kann man sehen das man die "Parameter" zwischen die || zu setzt sind und man dann Zugriff darauf hat.
gruss by OHR
Jimmy
J.Renseler
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 151
Registriert: Do, 15. Nov 2007 11:40
Wohnort: Krefeld
Kontaktdaten:

Re: Wie kann ich Ereignisse eines ActiveX-Controls abfangen

Beitrag von J.Renseler »

Hallo Jimmy,

danke für deine schnelle Hilfe. Werde es mit deinen Hinweisen direkt nochmal ausprobieren.

Um es nochmal ganz konkret zu formulieren. Ich muss Tasten die im XbpHTMLViewer gedrückt werden auswerten können.

Gruß,
Jannik
Kassensysteme für den Einzelhande http://ab-software.de
Mitglied der XUG-Cologne http://www.xug-cologne.de
J.Renseler
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 151
Registriert: Do, 15. Nov 2007 11:40
Wohnort: Krefeld
Kontaktdaten:

Re: Wie kann ich Ereignisse eines ActiveX-Controls abfangen

Beitrag von J.Renseler »

Hallo,

*hmm* funktioniert leider so noch nicht.

Hier mal mein Code

Code: Alles auswählen

CLASS absHTMLViewer FROM XbpHTMLViewer

  EXPORTED:
            VAR oDocument

            METHOD DocumentComplete()
            METHOD keyboard()

ENDCLASS

#define DISPID_ONCONTEXTMENU 1023
#define DISPID_ONKEYPRESS 13
#define DISPID_KEYPRESS -603
METHOD absHTMLViewer:DocumentComplete()

  IF .NOT. ::IsBusy()
    IF Empty( ::oDocument)
      IF .NOT. Empty( ::Document)

        ::oDocument := ::Document:dynamicCast( ActiveXObject() )
        ::oDocument:subscribeEvent( DISPID_KEYPRESS, {|nKey| ::keyboard(nKey) } )

      ENDIF

    ENDIF
  ENDIF
RETURN(SELF)

METHOD absHTMLViewer:keyboard( nKey)

  IF .NOT. Empty( nKey)
    MsgBox("nKey:" + CHR( nkey) )
  ENDIF

RETURN(SELF)

In der Methode keyboard kommt nie ein Tastendruck an. (Ich habe auch schon probiert die Methode anders zu benennen, aber dadran liegt es auch nicht)
Kassensysteme für den Einzelhande http://ab-software.de
Mitglied der XUG-Cologne http://www.xug-cologne.de
Antworten