Meine erste Class -> wb (=WebBrowser)

Stelle Fragen zur Programmierung mit Autohotkey

Moderator: jNizM

User avatar
Gerdi
Posts: 185
Joined: 03 Aug 2015, 18:48
Location: Germany
Contact:

Meine erste Class -> wb (=WebBrowser)

08 Jan 2018, 07:06

Unten ist mein erster ernsthafter Versuch eine eigene Class zu erstellen.
Im momentanen Status der wb-Class, bitte ich um Rueckmeldungen, wenn grobe Fehler oder Ungeschicktheiten im Aufbau der wb-Class vorhanden sind. Ansonsten warte ich, bis es bei https://autohotkey.com/boards/viewtopic.php?f=7&t=41332 weiter geht, um dem Ziel naeher zu kommen, Browser-Steuerung einfacher zu ermoeglichen.

Code: Select all

; Danke nnnik	https://autohotkey.com/boards/viewtopic.php?f=7&t=41332
; Danke	Beteiligte	https://autohotkey.com/board/topic/64563-basic-ahk-v11-com-tutorial-for-webpages/
; Danke	Glines	http://the-automator.com/tag/web-scraping-intro-with-autohotkey/
; Danke justme	ohne den ich nicht so weit gekommen waere
; Mein erster ernsthafter Versuch, der Erstellung einer eigenen Class
class wb {
	__New( WbName ) {
		this.name := WbName
		if(WbName="IE_"){	; Wenn der New wb(Uebergabe-Parameter) exakt "IE_" enthaelt, dann wird das zuletzt benutzte IE_Reiter-Fenster uebernommen.
			this.Com := this.WBGet()
			; this.Com := WBGet()
		}
		else if (SubStr(WbName,1,3)="IE_")	; Wenn der New wb(Uebergabe-Parameter) mit "IE_" beginnt, dann wird ein neues IE_Reiter-Fenster erstellt.
		{
			this.Com := ComObjCreate("InternetExplorer.Application")
			Sleep 300
		}
		else		;  Wenn der New wb(Uebergabe-Parameter) nicht mit "IE_" beginnt, dann ... --> Reserviert fuer andere Browser
		{
			StringSplit,1Browser2RestName,WbName,_
			if (1Browser2RestName0 < 2 OR 1Browser2RestName1 <> "IE")
				MsgBox,0,% A_LineFile "[" A_LineNumber "]", Uebergabe-Parameter >%WbName%< nicht unterstuetzt. `n`nIE_`nIE_...`nerwartet. `n`nBrowser  >%1Browser2RestName1%<   noch nicht unterstuetzt!,10
		}
	}
	getUrl() {
		return this.com.LocationURL ;grab current url
	}
	getUrlAfterQuestionMark() {
		return this.com.document.location.Search ; gets substring of URL following question mark
	}
	getUrlPathname() {
		return this.com.document.location.pathname ;returns pathname
	}
	getLocationName() {
		return this.com.LocationName ;grab page Titlerite
	}
	getUrlHostName() {
		return this.com.document.location.hostname ;returns host
	}
	getUrlAfterHash() {
		return this.com.document.location.hash ;retreives everyting from the # on
	}
	getUserAgent() {
		return this.com.document.parentWindow.navigator.userAgent ;Get User Agent
	}
	getSourceCode(){
		SourceCode := this.com.document.documentElement.innerHtml
		this.NotBusy()
		return SourceCode
	}
	getAllText(){
		AllText:=this.com.document.documentElement.innerText ;Get All text on page
		this.NotBusy()
		return AllText
	}
	getUrlProtocol(){
		return this.com.document.location.protocol ;retreives the protocol (http, https, etc)
	}
	refresh() {
		this.com.refresh ;Reload page
		this.NotBusy()
		return
	}
	getAllLinks(){
		
		Links := this.Com.Document.Links ; collection of hyperlinks on the page
		Loop % Links.Length ; Loop through links
		If ((Link := Links[A_Index-1].InnerText) != "") { ; if the link is not blank
		   (OuterHTML := Links[A_Index-1].OuterHTML)  ; Grab outerHTML for each link
			  Link:=StrReplace(Link,"`n")
			  Link:=StrReplace(Link,"`r")
			  Link:=StrReplace(Link,"`t")
			  OuterHTML:=StrReplace(OuterHTML,"`n")
			  OuterHTML:=StrReplace(OuterHTML,"`r")
			  OuterHTML:=StrReplace(OuterHTML,"`t")

		Msg .= A_Index-1 A_Space A_Space A_Space Link A_Tab OuterHTML "`r`n" ; add items to the msg list
		}
	this.NotBusy()
	return Msg	
		
	}
	FocusClick(ID:="",Name:="",ClassName:="",TagName:=""){
		Dashes:=false
		if ID contains -,_,¯
			Dashes:=true
		if (ID<>"")
		{
			if Dashes
				this.Com.document.getElementByID(ID).focus() ; Acts like clicking the link
			else
				this.Com.document.all[ID].focus()
			this.NotBusy()
			if Dashes
				this.Com.document.getElementByID(ID).click() ; Acts like clicking the link
			else
				this.Com.document.all[ID].click()
			this.NotBusy()
		}
		if (Name<>"")
		{
			this.Com.document.GetElementsByName(Name)[0].focus()
			this.NotBusy()
			this.Com.document.GetElementsByName(Name)[0].click()
			this.NotBusy()
		}
		if (ClassName<>"")
		{
			this.Com.document.GetElementsByName(ClassName)[0].focus()
			this.NotBusy()
			this.Com.document.GetElementsByName(ClassName)[0].click()
			this.NotBusy()
		}
		if (TagName<>"")
		{
			this.Com.document.GetElementsByName(TagName)[0].focus()
			this.NotBusy()
			this.Com.document.GetElementsByName(TagName)[0].click()
			this.NotBusy()
		}
		; this.NotBusy()
	}
	FeldEintrag(SuchString,ID:="",Name:="",ClassName:="",TagName:="")	{
		try
		{
			SuchStringProbe:=this.Com.document.getElementByID(ID).Value ;Unique ID-with dashes	; Existiert die ID
			this.Com.document.getElementByID(ID).Value :=SuchString ;Unique ID-with dashes		; Wert eintragen
			this.NotBusy()
			SuchStringProbe:=this.Com.document.getElementByID(ID).Value ;Unique ID-with dashes	; eingetragenen Wet fuer Probe auslesen
		}
		if (SuchStringProbe=SuchString)
			Erfolreich.="ID = " ID
		else
		{
			Loop 100 {
				NullIndex:=A_Index-1
				try{
					; MsgBox %ID% nicht gefunden
					SuchStringProbe:=this.Com.document.GetElementsByName(Name)[NullIndex].Value ;Object Name- Get array value
					this.Com.document.GetElementsByName(Name)[NullIndex].Value := SuchString
					this.NotBusy()
					SuchStringProbe:=this.Com.document.GetElementsByName(Name)[NullIndex].Value ;Object Name- Get array value
					; MsgBox %SuchStringProbe%
					if (SuchStringProbe=SuchString)
					{
						; MsgBox % NullIndex "	" SuchStringProbe
						break
					}
				}
			}
			if (SuchStringProbe=SuchString)
				Erfolreich.="Name[" NullIndex "] = " Name
			else
			{
				Loop 100 {
					NullIndex:=A_Index-1
					try{
						SuchStringProbe:=this.Com.document.getElementsByClassName(ClassName)[NullIndex].Value ;Get classname and Array value
						this.Com.document.getElementsByClassName(ClassName)[NullIndex].Value := SuchString
						this.NotBusy()
						SuchStringProbe:=this.Com.document.getElementsByClassName(ClassName)[NullIndex].Value ;Get classname and Array value
						if (SuchStringProbe=SuchString)
						{
							; MsgBox % NullIndex "	" SuchStringProbe
							break
						}
					}
				}
				if (SuchStringProbe=SuchString)
					Erfolreich.="ClassName[" NullIndex "] = " ClassName
				else
				{
					Loop 100 {
						NullIndex:=A_Index-1
						try{
							SuchStringProbe:=this.Com.document.GetElementsByTagName(TagName)[NullIndex].Value ;Get Tagname and Array value
							this.Com.document.GetElementsByTagName(TagName)[NullIndex].Value := SuchString
							this.NotBusy()
							SuchStringProbe:=this.Com.document.GetElementsByTagName(TagName)[NullIndex].Value ;Get Tagname and Array value
							if (SuchStringProbe=SuchString)
							{
								; MsgBox % NullIndex "	" SuchStringProbe
								break
							}
						}
					}
					if (SuchStringProbe=SuchString)
						Erfolreich.="TagName[" NullIndex "] = " TagName
					else
					{
						; MsgBox Der Text konnte nicht ins Feld eingetragen werden.
						Erfolreich:=false
					}
				}
			}
		}
		this.NotBusy()
		return Erfolreich
	}
	Visible(flag:=true){
		this.Com.Visible := flag	
		; this.NotBusy() ; Achtung, darf nicht rein. Ohne visible kein busy-Ende !!!!!!!!!!!!!!!!!!
	}
	Navigate(Url){
		this.Com.Navigate(Url)
		this.NotBusy()
	}
	Help(Methode){
		if(Methode="")
			return "geplant:	wb-Class-Hilfe + Liste aller Methoden + Beschreibungen"
		else
			return "geplant:	Liste aller Methoden + Beschreibungen, gefiltert nach >" Methode "<"
	}
	NotBusy(){
		while this.Com.busy or this.Com.ReadyState != 4
			Sleep 10	
	}
	delete() {
		; %ObjName%:=""
		this.Com:=""
	}
	; Folgende Funktion (danke Glines) ist hier fuer den Class-internen Aufruf vorgesehen.
		;************Pointer to Open IE Window******************
	WBGet(WinTitle="ahk_class IEFrame", Svr#=1) {               ;// based on ComObjQuery docs
	   static msg := DllCall("RegisterWindowMessage", "str", "WM_HTML_GETOBJECT")
			, IID := "{0002DF05-0000-0000-C000-000000000046}"   ;// IID_IWebBrowserApp
	;//     , IID := "{332C4427-26CB-11D0-B483-00C04FD90119}"   ;// IID_IHTMLWindow2
	   SendMessage msg, 0, 0, Internet Explorer_Server%Svr#%, %WinTitle%

	   if (ErrorLevel != "FAIL") {
		  lResult:=ErrorLevel, VarSetCapacity(GUID,16,0)
		  if DllCall("ole32\CLSIDFromString", "wstr","{332C4425-26CB-11D0-B483-00C04FD90119}", "ptr",&GUID) >= 0 {
			 DllCall("oleacc\ObjectFromLresult", "ptr",lResult, "ptr",&GUID, "ptr",0, "ptr*",pdoc)
			 return ComObj(9,ComObjQuery(pdoc,IID,IID),1), ObjRelease(pdoc)
		  }
	   }
	}	; written by Glines
}
; 
; S1 := new wb("Edge_S1")	; Test nicht unterstuetzter Browser
WinActivate,ahk_exe iexplore.exe
WinWaitActive,ahk_exe iexplore.exe,,10
Sleep 100
IfWinActive,ahk_exe iexplore.exe
{
	SoundBeep
	S1 := new wb("IE_")
	MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUrl(),4
}
else
{
	S1 := new wb("IE_S1")
	S1.Visible(1)
}
; S2 := new wb("IE_S2")		; 2. Browser Sitzung
; S2.Visible(1)
S1.Navigate("https://autohotkey.com/boards/viewtopic.php?f=7&t=41332")
; S2.Navigate("www.conrad.de")
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUrl() "	" S1.getLocationName() "	alle Links:`r`n" S1.getAllLinks(),5
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUrl() "	" S1.getLocationName() "	GesammtText:`r`n" S1.getAllText(),5
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUrl() "	" S1.getLocationName() "	QuellText:`r`n" S1.getSourceCode(),5
sleep 300
S1.Navigate("https://autohotkey.com/boards/viewtopic.php?f=7&t=41332&p=192787#p192787")
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUrlAfterHash()	,2
S1.refresh()
; sleep 2000
S1.Navigate("Google.de")
MsgBox,0,% A_LineFile "[" A_LineNumber "]", % S1.FeldEintrag("Hugo","lst-ib","q","gsfi","input"),2
; sleep 1000
S1.FocusClick("gsr") 
S1.FocusClick("","btnK")
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUrlAfterQuestionMark(),3
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUrlPathname(),2
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUrlHostname(),2
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getLocationName(),2
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUserAgent(),4

S1.delete("S1")
Win 10 Home (x64) and Win 11 Pro N
https://github.com/Grrdi/ZackZackOrdner/archive/master.zip --> get folders on the quick
just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Meine erste Class -> wb (=WebBrowser)

08 Jan 2018, 09:19

Moin,

auf den ersten Blick sieht alles korrekt aus. Meine einzige Anregung zielt überwiegend auf die 'Zukunftssicherheit' (auch wenn es sich da möglicherweise um einen Zeitraum von Jahren handelt).

Code: Select all

		else		;  Wenn der New wb(Uebergabe-Parameter) nicht mit "IE_" beginnt, dann ... --> Reserviert fuer andere Browser
		{
			StringSplit,1Browser2RestName,WbName,_
			if (1Browser2RestName0 < 2 OR 1Browser2RestName1 <> "IE")
				MsgBox,0,% A_LineFile "[" A_LineNumber "]", Uebergabe-Parameter >%WbName%< nicht unterstuetzt. `n`nIE_`nIE_...`nerwartet. `n`nBrowser  >%1Browser2RestName1%<   noch nicht unterstuetzt!,10
		}
Hier würde ich statt des Kommandos die Funktion StrSplit() verwenden. Variablennamen mit führenden Ziffern werden in AHK v2 auch nicht mehr erlaubt sein. Und so, wie es z.Zt. ist, ist 1Browser2RestName1 <> "IE" immer wahr.

Doch noch etwas: Ich würde keine selbstdefinierte Delete() Methode vorgeben, die das innenliegende COM-Objekt freigibt, ohne dass die umschließende Klasseninstanz ebenfalls zerstört wird. Und wenn das Browserobjekt eine Methode wie Quit oder Close enthält, ist es nicht verkehrt, die vor der Freigabe des Objekts aufzurufen, z.B. innerhalb des Destructors __Delete().
User avatar
Gerdi
Posts: 185
Joined: 03 Aug 2015, 18:48
Location: Germany
Contact:

Re: Meine erste Class -> wb (=WebBrowser)

09 Jan 2018, 06:06

Danke justme,

habe Deine Vorschlaege eingearbeitet.

beim __Delete -Thema bin ich allerdings unsicher, was von den Zeilen 29 bis 33 benoetigt wird.

Code: Select all

; Danke nnnik	https://autohotkey.com/boards/viewtopic.php?f=7&t=41332
; Danke	Beteiligte	https://autohotkey.com/board/topic/64563-basic-ahk-v11-com-tutorial-for-webpages/
; Danke	Glines	http://the-automator.com/tag/web-scraping-intro-with-autohotkey/
; Danke justme	ohne den ich nicht so weit gekommen waere
; Mein erster ernsthafter Versuch, der Erstellung einer eigenen Class
class wb {
	__New( WbName ) {
		this.name := WbName
		if(WbName="IE_"){	; Wenn der New wb(Uebergabe-Parameter) exakt "IE_" enthaelt, dann wird das zuletzt benutzte IE_Reiter-Fenster uebernommen.
			this.Com := this.WBGet()
			; this.Com := WBGet()
		}
		else if (SubStr(WbName,1,3)="IE_")	; Wenn der New wb(Uebergabe-Parameter) mit "IE_" beginnt, dann wird ein neues IE_Reiter-Fenster erstellt.
		{
			this.Com := ComObjCreate("InternetExplorer.Application")
			Sleep 300
		}
		else		;  Wenn der New wb(Uebergabe-Parameter) nicht mit "IE_" beginnt, dann ... --> Reserviert fuer andere Browser
		{
			Ae1Browser_Ae2RestName:=StrSplit(WbName,"_")
			if ((Ae1Browser_Ae2RestName.MaxIndex() < 2) OR (Ae1Browser_Ae2RestName[1] <> "IE"))
				MsgBox,0,% A_LineFile "[" A_LineNumber "]",%  "Uebergabe-Parameter >" WbName "< nicht unterstuetzt. `n`nIE_`nIE_...`nerwartet. `n`nBrowser  >" Ae1Browser_Ae2RestName[1] "<   noch nicht unterstuetzt!",10
		}
	}
	__Delete()
    {
		if (&this.Com > 0)
		{
			; this.Com.Close()    ; bringt Fehlermeldung
			this.Com.Quit()    ; bringt keine Fehlermeldung, ich sehe aber auch keine Wirkung im Debugger
			; MsgBox % "Delete GMem auf der Adresse " &this.Com "."	&Temp	;  Diese Zeile auskommentieren.
			DllCall("GlobalFree", "ptr", &this.Com)
			this.Com:=""
		}
    }

	getUrl() {
		return this.com.LocationURL ;grab current url
	}
	getUrlAfterQuestionMark() {
		return this.com.document.location.Search ; gets substring of URL following question mark
	}
	getUrlPathname() {
		return this.com.document.location.pathname ;returns pathname
	}
	getLocationName() {
		return this.com.LocationName ;grab page Titlerite
	}
	getUrlHostName() {
		return this.com.document.location.hostname ;returns host
	}
	getUrlAfterHash() {
		return this.com.document.location.hash ;retreives everyting from the # on
	}
	getUserAgent() {
		return this.com.document.parentWindow.navigator.userAgent ;Get User Agent
	}
	getSourceCode(){
		SourceCode := this.com.document.documentElement.innerHtml
		this.NotBusy()
		return SourceCode
	}
	getAllText(){
		AllText:=this.com.document.documentElement.innerText ;Get All text on page
		this.NotBusy()
		return AllText
	}
	getUrlProtocol(){
		return this.com.document.location.protocol ;retreives the protocol (http, https, etc)
	}
	refresh() {
		this.com.refresh ;Reload page
		this.NotBusy()
		return
	}
	getAllLinks(){
		
		Links := this.Com.Document.Links ; collection of hyperlinks on the page
		Loop % Links.Length ; Loop through links
		If ((Link := Links[A_Index-1].InnerText) != "") { ; if the link is not blank
		   (OuterHTML := Links[A_Index-1].OuterHTML)  ; Grab outerHTML for each link
			  Link:=StrReplace(Link,"`n")
			  Link:=StrReplace(Link,"`r")
			  Link:=StrReplace(Link,"`t")
			  OuterHTML:=StrReplace(OuterHTML,"`n")
			  OuterHTML:=StrReplace(OuterHTML,"`r")
			  OuterHTML:=StrReplace(OuterHTML,"`t")

		Msg .= A_Index-1 A_Space A_Space A_Space Link A_Tab OuterHTML "`r`n" ; add items to the msg list
		}
	this.NotBusy()
	return Msg	
		
	}
	FocusClick(ID:="",Name:="",ClassName:="",TagName:=""){
		Dashes:=false
		if ID contains -,_,¯
			Dashes:=true
		if (ID<>"")
		{
			if Dashes
				this.Com.document.getElementByID(ID).focus() ; Acts like clicking the link
			else
				this.Com.document.all[ID].focus()
			this.NotBusy()
			if Dashes
				this.Com.document.getElementByID(ID).click() ; Acts like clicking the link
			else
				this.Com.document.all[ID].click()
			this.NotBusy()
		}
		if (Name<>"")
		{
			this.Com.document.GetElementsByName(Name)[0].focus()
			this.NotBusy()
			this.Com.document.GetElementsByName(Name)[0].click()
			this.NotBusy()
		}
		if (ClassName<>"")
		{
			this.Com.document.GetElementsByName(ClassName)[0].focus()
			this.NotBusy()
			this.Com.document.GetElementsByName(ClassName)[0].click()
			this.NotBusy()
		}
		if (TagName<>"")
		{
			this.Com.document.GetElementsByName(TagName)[0].focus()
			this.NotBusy()
			this.Com.document.GetElementsByName(TagName)[0].click()
			this.NotBusy()
		}
		; this.NotBusy()
	}
	FeldEintrag(SuchString,ID:="",Name:="",ClassName:="",TagName:="")	{
		try
		{
			SuchStringProbe:=this.Com.document.getElementByID(ID).Value ;Unique ID-with dashes	; Existiert die ID
			this.Com.document.getElementByID(ID).Value :=SuchString ;Unique ID-with dashes		; Wert eintragen
			this.NotBusy()
			SuchStringProbe:=this.Com.document.getElementByID(ID).Value ;Unique ID-with dashes	; eingetragenen Wet fuer Probe auslesen
		}
		if (SuchStringProbe=SuchString)
			Erfolreich.="ID = " ID
		else
		{
			Loop 100 {
				NullIndex:=A_Index-1
				try{
					; MsgBox %ID% nicht gefunden
					SuchStringProbe:=this.Com.document.GetElementsByName(Name)[NullIndex].Value ;Object Name- Get array value
					this.Com.document.GetElementsByName(Name)[NullIndex].Value := SuchString
					this.NotBusy()
					SuchStringProbe:=this.Com.document.GetElementsByName(Name)[NullIndex].Value ;Object Name- Get array value
					; MsgBox %SuchStringProbe%
					if (SuchStringProbe=SuchString)
					{
						; MsgBox % NullIndex "	" SuchStringProbe
						break
					}
				}
			}
			if (SuchStringProbe=SuchString)
				Erfolreich.="Name[" NullIndex "] = " Name
			else
			{
				Loop 100 {
					NullIndex:=A_Index-1
					try{
						SuchStringProbe:=this.Com.document.getElementsByClassName(ClassName)[NullIndex].Value ;Get classname and Array value
						this.Com.document.getElementsByClassName(ClassName)[NullIndex].Value := SuchString
						this.NotBusy()
						SuchStringProbe:=this.Com.document.getElementsByClassName(ClassName)[NullIndex].Value ;Get classname and Array value
						if (SuchStringProbe=SuchString)
						{
							; MsgBox % NullIndex "	" SuchStringProbe
							break
						}
					}
				}
				if (SuchStringProbe=SuchString)
					Erfolreich.="ClassName[" NullIndex "] = " ClassName
				else
				{
					Loop 100 {
						NullIndex:=A_Index-1
						try{
							SuchStringProbe:=this.Com.document.GetElementsByTagName(TagName)[NullIndex].Value ;Get Tagname and Array value
							this.Com.document.GetElementsByTagName(TagName)[NullIndex].Value := SuchString
							this.NotBusy()
							SuchStringProbe:=this.Com.document.GetElementsByTagName(TagName)[NullIndex].Value ;Get Tagname and Array value
							if (SuchStringProbe=SuchString)
							{
								; MsgBox % NullIndex "	" SuchStringProbe
								break
							}
						}
					}
					if (SuchStringProbe=SuchString)
						Erfolreich.="TagName[" NullIndex "] = " TagName
					else
					{
						; MsgBox Der Text konnte nicht ins Feld eingetragen werden.
						Erfolreich:=false
					}
				}
			}
		}
		this.NotBusy()
		return Erfolreich
	}
	Visible(flag:=true){
		this.Com.Visible := flag	
		; this.NotBusy() ; Achtung, darf nicht rein. Ohne visible kein busy-Ende !!!!!!!!!!!!!!!!!!
	}
	Navigate(Url){
		this.Com.Navigate(Url)
		this.NotBusy()
	}
	History(Number){
		this.Com.document.parentWindow.history.go(Number) ; if Number is negativ Go Backward one page
		this.NotBusy()
	}
	HistoryLen(){
		return this.Com.document.parentWindow.history.length	
	}
	Help(Methode){
		if(Methode="")
			return "geplant:	wb-Class-Hilfe + Liste aller Methoden + Beschreibungen"
		else
			return "geplant:	Liste aller Methoden + Beschreibungen, gefiltert nach >" Methode "<"
	}
	NotBusy(){
		while this.Com.busy or this.Com.ReadyState != 4
			Sleep 10	
	}
 	CloseTab(force=0) {
		if force
		{
			SchliessenBestaetigenAhk=
(
WinWaitActive,Windows Internet Explorer ahk_class #32770,,1
ControlClick,Button1,Windows Internet Explorer ahk_class #32770
)
			FileDelete,%A_Temp%\SB.ahk
			FileAppend,%SchliessenBestaetigenAhk%,%A_Temp%\SB.ahk
			Run %A_Temp%\SB.ahk
		}
		sleep 20
		this.Com.document.parentWindow.window.Close()		; Reiter Schliessen mit Rueckfrage
	}
	; Folgende Funktion (danke Glines) ist hier fuer den Class-internen Aufruf vorgesehen.
		;************Pointer to Open IE Window******************
	WBGet(WinTitle="ahk_class IEFrame", Svr#=1) {               ;// based on ComObjQuery docs
	   static msg := DllCall("RegisterWindowMessage", "str", "WM_HTML_GETOBJECT")
			, IID := "{0002DF05-0000-0000-C000-000000000046}"   ;// IID_IWebBrowserApp
	;//     , IID := "{332C4427-26CB-11D0-B483-00C04FD90119}"   ;// IID_IHTMLWindow2
	   SendMessage msg, 0, 0, Internet Explorer_Server%Svr#%, %WinTitle%

	   if (ErrorLevel != "FAIL") {
		  lResult:=ErrorLevel, VarSetCapacity(GUID,16,0)
		  if DllCall("ole32\CLSIDFromString", "wstr","{332C4425-26CB-11D0-B483-00C04FD90119}", "ptr",&GUID) >= 0 {
			 DllCall("oleacc\ObjectFromLresult", "ptr",lResult, "ptr",&GUID, "ptr",0, "ptr*",pdoc)
			 return ComObj(9,ComObjQuery(pdoc,IID,IID),1), ObjRelease(pdoc)
		  }
	   }
	}	; written by Glines
}
; 
; ################# Class Tests: ###################
S1 := new wb("Edge")	; Test nicht unterstuetzter Browser
S1 := new wb("Edge_S1")	; Test nicht unterstuetzter Browser
WinActivate,ahk_exe iexplore.exe
WinWaitActive,ahk_exe iexplore.exe,,2
Sleep 100
IfWinActive,ahk_exe iexplore.exe
{
	SoundBeep
	S1 := new wb("IE_")
	MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUrl(),4
	NewTab:=false
}
else
{
	S1 := new wb("IE_S1")
	S1.Visible(1)
	NewTab:=true
}
; S2 := new wb("IE_S2")		; 2. Browser Sitzung
; S2.Visible(1)
S1.Navigate("https://autohotkey.com/boards/viewtopic.php?f=7&t=41332")
S1:=""
ExitApp
; S2.Navigate("www.conrad.de")
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUrl() "	" S1.getLocationName() "	alle Links:`r`n" S1.getAllLinks(),5
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUrl() "	" S1.getLocationName() "	GesammtText:`r`n" S1.getAllText(),5
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUrl() "	" S1.getLocationName() "	QuellText:`r`n" S1.getSourceCode(),5
sleep 300
S1.Navigate("https://autohotkey.com/boards/viewtopic.php?f=7&t=41332&p=192787#p192787")
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUrlAfterHash()	,2
S1.refresh()
; sleep 2000
S1.Navigate("Google.de")
MsgBox,0,% A_LineFile "[" A_LineNumber "]", % S1.FeldEintrag("Hugo","lst-ib","q","gsfi","input"),2
; sleep 1000
S1.FocusClick("gsr") 
S1.FocusClick("","btnK")
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUrlAfterQuestionMark(),3
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUrlPathname(),2
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUrlHostname(),2
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getLocationName(),2
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % "Die Seitenhistorie hat " S1.HistoryLen() " Eintraege",2
S1.History(-1)
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUserAgent(),4
S1.History(1)
sleep 2000
; if NewTab		; Auskommentieren wenn urspruenglich geoeffneter Reiter offen bleiben solll
S1.CloseTab(NewTab)		; Nur schliess-Nachfrage wenn nicht selbst geoeffnet. Statt NewTab eine 1 eintragen, wenn Reiter ohne Nachfrage geschlossen werden soll.
S1:=""
; MsgBox Skript Ende
Win 10 Home (x64) and Win 11 Pro N
https://github.com/Grrdi/ZackZackOrdner/archive/master.zip --> get folders on the quick
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Meine erste Class -> wb (=WebBrowser)

09 Jan 2018, 07:41

Hi es freut mich zu sehen, dass jemand mein Tutorial gelesen hat und umsetzt :)
Recommends AHK Studio
just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Meine erste Class -> wb (=WebBrowser)

09 Jan 2018, 11:43

Hallo Gerdi,

was ich meinte:

Wenn ein COM-Objekt eine eigene Methode für einen sauberen Abgang anbietet (wie z.B. Quit()), sollte man die meiner Meinung nach aufrufen, bevor das Objekt freigegeben wird, und das selbst dann, wenn es im Augenblick auch ohne zu gehen scheint. Dinge und Objekte können ihe Verhalten ändern wie es Microsoft oder anderen Softwareentwicklern gerade gefällt.

In Deiner __Delete() Methode würde ich mich auf Folgendes beschränken:

Code: Select all

	__Delete()
    {
		if IsObject(this.Com)
		{
			; this.Com.Close()    ; bringt Fehlermeldung
			this.Com.Quit()    ; bringt keine Fehlermeldung, ich sehe aber auch keine Wirkung im Debugger
		}
    }
Den Rest erledigt AHK für Dich.
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Meine erste Class -> wb (=WebBrowser)

09 Jan 2018, 12:19

Die Wirkung sieht man wenn man den TaskManager aufmacht nachdem man ein InternetExplorer Objekt beendet oder nicht beendet hat.
Wenn man .quit() nicht aufruft bleiben ie.exe Prozesse erhalten.
Recommends AHK Studio
just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Meine erste Class -> wb (=WebBrowser)

09 Jan 2018, 13:40

Danke für den Hinweis, nnnik. Dann ist es ja tatsächlich sinnvoll und nicht einfach nur einem Prinzip geschuldet. ;)
User avatar
Gerdi
Posts: 185
Joined: 03 Aug 2015, 18:48
Location: Germany
Contact:

Re: Meine erste Class -> wb (=WebBrowser)

11 Jan 2018, 06:36

Danke,

es sind noch ein paar Funktionen hinzu gekommen,
ob ich allerdings mit

Code: Select all

S1.setOnErrorExit(true)	; bei Fehler Thread beenden
gluecklich werde, muss ich noch herausfinden.
Jedoch die Funktion GetSetOneOfAllTags() koennte auch fuer Andere nuetzlich sein.

Code: Select all

; Danke nnnik	https://autohotkey.com/boards/viewtopic.php?f=7&t=41332 ;{
; Danke	Beteiligte	https://autohotkey.com/board/topic/64563-basic-ahk-v11-com-tutorial-for-webpages/
; Danke	Glines	http://the-automator.com/tag/web-scraping-intro-with-autohotkey/
; Danke justme	ohne den ich nicht so weit gekommen waere
; https://msdn.microsoft.com/en-us/library/aa752084(v=vs.85).aspx
; Mein erster ernsthafter Versuch, der Erstellung einer eigenen Class
;}	
class wb {
	__New( WbName ) {
		this.name := WbName
		if(WbName="IE_"){	; Wenn der New wb(Uebergabe-Parameter) exakt "IE_" enthaelt, dann wird das zuletzt benutzte IE_Reiter-Fenster uebernommen.
			this.Com := this.WBGet()
			this.WinHwnd:=this.Com.HWND
		}
		else if (SubStr(WbName,1,3)="IE_")	; Wenn der New wb(Uebergabe-Parameter) mit "IE_" beginnt, dann wird ein neues IE_Reiter-Fenster erstellt.
		{
			this.Com := ComObjCreate("InternetExplorer.Application")
			Sleep 300
			this.WinHwnd:=this.Com.HWND
		}
		else		;  Wenn der New wb(Uebergabe-Parameter) nicht mit "IE_" beginnt, dann ... --> Reserviert fuer andere Browser
		{
			Ae1Browser_Ae2RestName:=StrSplit(WbName,"_")
			if ((Ae1Browser_Ae2RestName.MaxIndex() < 2) OR (Ae1Browser_Ae2RestName[1] <> "IE"))
				MsgBox,0,% A_LineFile "[" A_LineNumber "]",%  "Uebergabe-Parameter >" WbName "< nicht unterstuetzt. `n`nIE_`nIE_...`nerwartet. `n`nBrowser  >" Ae1Browser_Ae2RestName[1] "<   noch nicht unterstuetzt!",10
		}
		this.OnError:={}
		this.OnError.Exit:={}
		this.OnError.Exit:=false
	}
	__Delete() {
		ExitThreadOnClose:=false
		if this.OnError.Exit
			ExitThreadOnClose:=true
		if IsObject(this.Com)
		{
			try
				this.Com.Quit()    ; bringt keine Fehlermeldung, ich sehe aber die Wirkung im TaskManager. Danke nnnik
		}
		if ExitThreadOnClose
			Exit
    }
	getUrl() {
		try
			return this.com.LocationURL ;grab current url
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	getUrlAfterQuestionMark() {
		try
			return this.com.document.location.Search ; gets substring of URL following question mark
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	getUrlPort() {
		try
			return this.com.document.location.port
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	getUrlPathname() {		
		try
			return this.com.document.location.pathname ; returns pathname
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	getLocationName() {
		try
			return this.com.LocationName ; grab page Titlerite
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	getUrlHostName() {
		try
			return this.com.document.location.hostname ; returns host
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	getUrlAfterHash() {
		try
			return this.com.document.location.hash ; retreives everyting from the # on
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	getUserAgent() {
		try
			return this.com.document.parentWindow.navigator.userAgent ; Get User Agent
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	getSourceCode(){
		try{
			SourceCode := this.com.document.documentElement.innerHtml
			this.NotBusy()
			return SourceCode
		}
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	getAllText(){
		try{
			AllText:=this.com.document.documentElement.innerText ; Get All text on page
			this.NotBusy()
			return AllText
		}
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	getUrlProtocol(){
		try
			return this.com.document.location.protocol ; retreives the protocol (http, https, etc)
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	getWinHwnd() {
		return this.WinHwnd
	}
	getIeControlHwnd() {
		MsgBox Implementierung gesucht
	}
	DuplicateTab() { ; -> ^k
		Sleep 1000
		this.NotBusy()
		WinHwnd := this.WinHwnd
		if (WinHwnd="" OR WinHwnd=0)
			SoundBeep 500
		WinActivate,ahk_id %WinHwnd%
		WinWaitActive,ahk_id %WinHwnd%,,1
		sleep 300
		ControlFocus,,ahk_id %WinHwnd%
		sleep 300
		ControlSend,,^k,ahk_id %WinHwnd%
		Sleep 1000
		this.NotBusy()
		Sleep 1000
	}
	refresh() {
		try{
			this.com.refresh ;Reload page
			this.NotBusy()
			return
		}
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	getAllLinks(){
		try{
			Links := this.Com.Document.Links ; collection of hyperlinks on the page
			Loop % Links.Length ; Loop through links
				If ((Link := Links[A_Index-1].InnerText) != "") { ; if the link is not blank
					(OuterHTML := Links[A_Index-1].OuterHTML)  ; Grab outerHTML for each link
					Link:=StrReplace(Link,"`n")
					Link:=StrReplace(Link,"`r")
					Link:=StrReplace(Link,"`t")
					OuterHTML:=StrReplace(OuterHTML,"`n")
					OuterHTML:=StrReplace(OuterHTML,"`r")
					OuterHTML:=StrReplace(OuterHTML,"`t")
					Msg .= A_Index-1 A_Space A_Space A_Space Link A_Tab OuterHTML "`r`n" ; add items to the msg list
				}
			this.NotBusy()
			return Msg
		}
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	GetSetOneOfAllTags(Tag="",Suchliste="",NachDot="",InKlammenValue="KlammerLos",setValue=""){			; Universal-Methode
		try	; Parameter 1 = Tag-Filer	2 = QuellTextSuchWoerter-Pipe|getrennt	3 = Aktion mit gefundenem Element	4 = KlammerInhalt	5 = Leer fuer get's	5 = Value fuer set's
		{	;	z.B.	"input"			"Anmelden|Button"						"click"								""					""
			if (Tag="") ; "a"			"Das sind Ihre Vorteile"				"click"								""
				Tag:= "*"		; 		"LoginLink|Anmelden|Anmelden|Button"	"outerHtml"
			Alle := this.Com.document.getElementsByTagName(Tag)		;			"innerText"
			Anz:=Alle.Length	; oder ab Parameter 3 leerlassen, um ein Element-Object zu erhalten, weches dann ausserhalb dieser Class weiter bearbeitet werden kann.
			Loop % Alle.Length { ; Loop through links
				TagIndex:=A_Index
				If ((All := Alle[A_Index-1].OuterHTML) != "") { ; if the link is not blank
					Funde:=0
					SuchStr:=StrSplit(Suchliste,"|")
					loop % SuchStr.MaxIndex()
					{
						Funstellen:=StrSplit(All,SuchStr[A_Index])
						Funde+=Funstellen.MaxIndex() -1
					}
					ges .= ((Funde * Funde)/Strlen(All)) / SuchStr.MaxIndex() . A_Tab . TagIndex . "`n" ; Falls die Bewertungen hier nicht direkt zum gewuenschten Element fuerhren, kann auch mit mehrfach-Nennung eines Suchbegriffes, zu dessen Gunsten beeinflusst werden.
				}
			}
			sort,ges, N U R			; nach Bewertung sortieren
			Loop,Parse,ges,`n
			{
				FuerTagIndex:=StrSplit(A_LoopField,A_Tab)		; best bewerteten Index holen
				break
			}
			DieserTagIndex:=FuerTagIndex[2] -1			; Index auf basis 0 korrigieren
			; MsgBox %DieserTagIndex%`n%ges%
			if (InKlammenValue="KlammerLos")
			{
				if (setValue="")
					return this.Com.document.getElementsByTagName(Tag)[DieserTagIndex][NachDot]
				else
					return this.Com.document.getElementsByTagName(Tag)[DieserTagIndex][NachDot] := setValue				
			}
			else
			{
				if (setValue="")
					return this.Com.document.getElementsByTagName(Tag)[DieserTagIndex][NachDot](InKlammenValue)
				else
					return this.Com.document.getElementsByTagName(Tag)[DieserTagIndex][NachDot](InKlammenValue) := setValue				
			}
		}
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	FocusClick(ID:="",Name:="",ClassName:="",TagName:=""){
		try{
			Dashes:=false
			if ID contains -,_,¯
				Dashes:=true
			if (ID<>"")
			{
				if Dashes
					this.Com.document.getElementByID(ID).focus() ; Acts like clicking the link
				else
					this.Com.document.all[ID].focus()
				this.NotBusy()
				if Dashes
					this.Com.document.getElementByID(ID).click() ; Acts like clicking the link
				else
					this.Com.document.all[ID].click()
				this.NotBusy()
			}
			if (Name<>"")
			{
				this.Com.document.GetElementsByName(Name)[0].focus()
				this.NotBusy()
				this.Com.document.GetElementsByName(Name)[0].click()
				this.NotBusy()
			}
			if (ClassName<>"")
			{
				try
					this.Com.document.GetElementsByName(ClassName)[0].focus()
				this.NotBusy()
				try
					this.Com.document.GetElementsByName(ClassName)[0].click()
				this.NotBusy()
			}
			if (TagName<>"")
			{
				this.Com.document.GetElementsByName(TagName)[0].focus()
				this.NotBusy()
				this.Com.document.GetElementsByName(TagName)[0].click()
				this.NotBusy()
			}
			; this.NotBusy()
		}
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	FeldEintrag(SuchString,ID:="",Name:="",ClassName:="",TagName:="")	{
		try
		{
			SuchStringProbe:=this.Com.document.getElementByID(ID).Value ;Unique ID-with dashes	; Existiert die ID
			this.Com.document.getElementByID(ID).Value :=SuchString ;Unique ID-with dashes		; Wert eintragen
			this.NotBusy()
			SuchStringProbe:=this.Com.document.getElementByID(ID).Value ;Unique ID-with dashes	; eingetragenen Wet fuer Probe auslesen
		}
		if (SuchStringProbe=SuchString)
			Erfolreich.="ID = " ID
		else
		{
			Loop 100 {
				NullIndex:=A_Index-1
				try{
					; MsgBox %ID% nicht gefunden
					SuchStringProbe:=this.Com.document.GetElementsByName(Name)[NullIndex].Value ;Object Name- Get array value
					this.Com.document.GetElementsByName(Name)[NullIndex].Value := SuchString
					this.NotBusy()
					SuchStringProbe:=this.Com.document.GetElementsByName(Name)[NullIndex].Value ;Object Name- Get array value
					; MsgBox %SuchStringProbe%
					if (SuchStringProbe=SuchString)
					{
						; MsgBox % NullIndex "	" SuchStringProbe
						break
					}
				}
			}
			if (SuchStringProbe=SuchString)
				Erfolreich.="Name[" NullIndex "] = " Name
			else
			{
				Loop 100 {
					NullIndex:=A_Index-1
					try{
						SuchStringProbe:=this.Com.document.getElementsByClassName(ClassName)[NullIndex].Value ;Get classname and Array value
						this.Com.document.getElementsByClassName(ClassName)[NullIndex].Value := SuchString
						this.NotBusy()
						SuchStringProbe:=this.Com.document.getElementsByClassName(ClassName)[NullIndex].Value ;Get classname and Array value
						if (SuchStringProbe=SuchString)
						{
							break
						}
					}
				}
				if (SuchStringProbe=SuchString)
					Erfolreich.="ClassName[" NullIndex "] = " ClassName
				else
				{
					Loop 100 {
						NullIndex:=A_Index-1
						try{
							SuchStringProbe:=this.Com.document.GetElementsByTagName(TagName)[NullIndex].Value ;Get Tagname and Array value
							this.Com.document.GetElementsByTagName(TagName)[NullIndex].Value := SuchString
							this.NotBusy()
							SuchStringProbe:=this.Com.document.GetElementsByTagName(TagName)[NullIndex].Value ;Get Tagname and Array value
							if (SuchStringProbe=SuchString)
								break
						}
					}
					if (SuchStringProbe=SuchString)
						Erfolreich.="TagName[" NullIndex "] = " TagName
					else
					{
						; MsgBox Der Text konnte nicht ins Feld eingetragen werden.
						Erfolreich:=false
					}
				}
			}
		}
		this.NotBusy()
		if Erfolreich
			return Erfolreich
		else
			this.ifOnErrorDoExit(this.OnError.Exit)			
	}
	Visible(flag:=true){
		try
			this.Com.Visible := flag	
			; this.NotBusy() ; Achtung, darf nicht rein. Ohne visible kein busy-Ende !!!!!!!!!!!!!!!!!!
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	Navigate(Url){
		try{
			this.Com.Navigate(Url)
			this.NotBusy()
		}
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	setOnErrorExit(Flag=0){
		this.OnError.Exit := Flag
		if Flag
			Critical,Off
	}
	History(Number){
		try{
			this.Com.document.parentWindow.history.go(Number) ; if Number is negativ Go Backward one page
			this.NotBusy()
		}
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	HistoryLen(){
		try
			return this.Com.document.parentWindow.history.length	
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	Help(Methode){
		if(Methode="")
			return "geplant:	wb-Class-Hilfe + Liste aller Methoden + Beschreibungen"
		else
			return "geplant:	Liste aller Methoden + Beschreibungen, gefiltert nach >" Methode "<"
	}
	NotBusy(){
		try{
			while this.Com.busy or this.Com.ReadyState != 4
				Sleep 10	
		}
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
 	CloseTab(force=1) {		; wirkung wie WebBroserObjekt := "" 	bei 1 ohne Rueckfrage
		if force
		{		; Rueckfrage wird 8 Zeilen weiter unten mit ja beantwortet.
			SchliessenBestaetigenAhk=
(
WinWaitActive,Windows Internet Explorer ahk_class #32770,,1
ControlClick,Button1,Windows Internet Explorer ahk_class #32770
)
			FileDelete,%A_Temp%\SB.ahk
			FileAppend,%SchliessenBestaetigenAhk%,%A_Temp%\SB.ahk
			Run %A_Temp%\SB.ahk
		}
		sleep 20
		try{
			this.Com.document.parentWindow.window.Close()		; Reiter Schliessen mit Rueckfrage
		}
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	ifOnErrorDoExit(Flag){	; Diese Funktion hier ist nur fuer den Class-internen Aufruf vorgesehen.
		if this.OnError.Exit{
			if IsObject(this.Com){
				try
					this.Com.Quit()		; auch IE.exe beenden
			}
			Exit					; aktuellen Thread beenden
		}
	}
	; Folgende Funktion (danke Glines) ist hier fuer den Class-internen Aufruf vorgesehen.
		;************Pointer to Open IE Window******************
	WBGet(WinTitle="ahk_class IEFrame", Svr#=1) {               ;// based on ComObjQuery docs
	   static msg := DllCall("RegisterWindowMessage", "str", "WM_HTML_GETOBJECT")
			, IID := "{0002DF05-0000-0000-C000-000000000046}"   ;// IID_IWebBrowserApp
	;//     , IID := "{332C4427-26CB-11D0-B483-00C04FD90119}"   ;// IID_IHTMLWindow2
	   SendMessage msg, 0, 0, Internet Explorer_Server%Svr#%, %WinTitle%

	   if (ErrorLevel != "FAIL") {
		  lResult:=ErrorLevel, VarSetCapacity(GUID,16,0)
		  if DllCall("ole32\CLSIDFromString", "wstr","{332C4425-26CB-11D0-B483-00C04FD90119}", "ptr",&GUID) >= 0 {
			 DllCall("oleacc\ObjectFromLresult", "ptr",lResult, "ptr",&GUID, "ptr",0, "ptr*",pdoc)
			 return ComObj(9,ComObjQuery(pdoc,IID,IID),1), ObjRelease(pdoc)
		  }
	   }
	}	; written by Glines
}
; 
; ################# Class Tests: ################### ;{
; S1 := new wb("Edge")	; Test nicht unterstuetzter Browser
; S1 := new wb("Edge_S1")	; Test nicht unterstuetzter Browser
WinActivate,ahk_exe iexplore.exe
WinWaitActive,ahk_exe iexplore.exe,,2
Sleep 100
IfWinActive,ahk_exe iexplore.exe
{
	S1 := new wb("IE_")
	MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUrl(),4
	NewTab:=false
}
else
{
	S1 := new wb("IE_S1")
	S1.Visible(1)
	NewTab:=true
}
; S1.setOnErrorExit(true)	; bei Fehler Thread beenden
; S2 := new wb("IE_S2")		; paralele 2. Browser Sitzung
; S2.Visible(1)
S1.Navigate("https://autohotkey.com:443/boards/viewtopic.php?f=7&t=41332")
; WinHwnd := S1.getWinHwnd()
; <strong>General:</strong>
Sleep 1000
MsgBox,0,% A_LineFile "[" A_LineNumber "]", % S1.GetSetOneOfAllTags("strong","General","outerHtml"),2
MsgBox,0,% A_LineFile "[" A_LineNumber "]", % S1.GetSetOneOfAllTags("strong","General","innerhtml"),2
MsgBox,0,% A_LineFile "[" A_LineNumber "]", % S1.GetSetOneOfAllTags("strong","General","innerhtml",,"<marquee>G e n e r a <i>l</i> :</marquee>"),11
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUrl() "	" S1.getLocationName() "	alle Links:`r`n" S1.getAllLinks(),5
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUrl() "	" S1.getLocationName() "	GesammtText:`r`n" S1.getAllText(),5
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUrl() "	" S1.getLocationName() "	QuellText:`r`n" S1.getSourceCode(),5
S1.Navigate("https://autohotkey.com/boards/viewtopic.php?f=7&t=41332&p=192787#p192787")
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUrlAfterHash()	,2
S1.refresh()
S1.Navigate("Google.de")
MsgBox,0,% A_LineFile "[" A_LineNumber "]", % S1.FeldEintrag("Hugo","lst-ib","q","gsfi","input"),2
S1.FocusClick("gsr") 
S1.FocusClick("","btnK")
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUrlAfterQuestionMark(),3
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUrlPathname(),2
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUrlHostname(),2
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getLocationName(),2
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % "Die Seitenhistorie hat " S1.HistoryLen() " Eintraege",2
S1.History(-1)
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUserAgent(),4
S1.History(1)
if Not NewTab
	S1.DuplicateTab()


sleep 2000
S1:=""
; MsgBox Skript Ende
;}	



Win 10 Home (x64) and Win 11 Pro N
https://github.com/Grrdi/ZackZackOrdner/archive/master.zip --> get folders on the quick
just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Meine erste Class -> wb (=WebBrowser)

12 Jan 2018, 04:24

Moin Gerdi,

meine Anmerkungen:
  • __New()
    Wenn __New() nicht etwas Anderes zurückgibt, wird eine neue Instanz erstellt. Die Hilfe formuliert das so:
    Konstruktion und Destruktion wrote:... Diese Methode kann Parameter akzeptieren, das Objekt initialisieren und das Ergebnis des new-Operators durch Zurückgeben eines Wertes überschreiben.
    In Deiner Klasse wird kein COM-Objekt erstellt, wenn ein 'falscher' Parameter übergeben wird (Stellen 1-3 <> "IE_"). Du gibst in diesem Fall zwar eine Fehlermeldung aus, lässt dann aber einfach weiterlaufen. Damit wird eine neue Klasseninstanz erstellt, die mangels eingebettetem COM-Objekt nicht funktionieren kann. Ich würde deshalb nach der Fehlermeldung ein Return False einfügen.

    Und noch eine Kleinigkeit:

    Code: Select all

    		this.OnError:={}
    		this.OnError.Exit:={}
    		this.OnError.Exit:=false
    
    Wenn die OnError Eigenschaft unbedingt ein eigenes Objekt mit der Eigenschaft Exit sein soll, macht this.OnError.Exit:={} keinen Sinn, weil das so zugewiesene leere Objekt mit der folgenden Zuweisung this.OnError.Exit:=false sofort wieder zerstört wird. Für die gesamte Zuweisung würde auch Folgendes reichen

    Code: Select all

    	this.OnError:={Exit: False}
  • ifOnErrorDoExit()
    Der Sinn erschließt sich mir nicht. Bestenfalls wird damit ein meiner Meinung nach oft nicht zweckmäßiges Verhalten von AHK v1 imitiert, das sogenannte 'lautlose Sterben'. Der Anwender sieht keine Fehlermeldung, weil die in Deiner Klasse überwiegend per Try abgefangen wird, und steht dann mit dem nicht gelieferten Ergebnis seines Methodenaufrufs allein im Regen.
    Wenn Du die Kontrolle über die Fehlermeldungen haben willst (Try ... Catch), solltest Du bei Fehlern auch Meldungen ausgeben. Dafür reicht eine simple MsgBox. Ich würde aber einen Ausnahmefehler per Throw generieren. Der Anwender kann dann selbst entscheiden, ob es weitergehen soll.
Das war's auch schon,

just me
User avatar
Gerdi
Posts: 185
Joined: 03 Aug 2015, 18:48
Location: Germany
Contact:

Re: Meine erste Class -> wb (=WebBrowser)

12 Jan 2018, 20:17

Danke just me,
just me wrote:[*]ifOnErrorDoExit()
Der Sinn erschließt sich mir nicht.
Mit hife der Klasse sollen Web-Auftritte unbeaufsichtigt ueberwacht werden.
Dies war und ist noch ein schlecht gelungener Versuch auf dem Weg dorthin.

Code: Select all

; Danke nnnik	https://autohotkey.com/boards/viewtopic.php?f=7&t=41332 ;{
; Danke	Beteiligte	https://autohotkey.com/board/topic/64563-basic-ahk-v11-com-tutorial-for-webpages/
; Danke	Glines	http://the-automator.com/tag/web-scraping-intro-with-autohotkey/
; Danke justme	ohne den ich nicht so weit gekommen waere
; https://msdn.microsoft.com/en-us/library/aa752084(v=vs.85).aspx
; HTML Befehlsuebersicht	http://www.webhinweis.de/html/html_tabelle.html	
; Mein erster ernsthafter Versuch, der Erstellung einer eigenen Class
;}	

class wBr {
	__New( WbName ) {
		this.name := WbName
		if(WbName="IE_"){	; Wenn der New wb(Uebergabe-Parameter) exakt "IE_" enthaelt, dann wird das zuletzt benutzte IE_Reiter-Fenster uebernommen.
			this.Com := this.WBGet()
			this.WinHwnd:=this.Com.HWND
		}
		else if (SubStr(WbName,1,3)="IE_")	; Wenn der New wb(Uebergabe-Parameter) mit "IE_" beginnt, dann wird ein neues IE_Reiter-Fenster erstellt.
		{
			this.Com := ComObjCreate("InternetExplorer.Application")
			Sleep 300
			this.WinHwnd:=this.Com.HWND
		}
		else		;  Wenn der New wb(Uebergabe-Parameter) nicht mit "IE_" beginnt, dann ... --> Reserviert fuer andere Browser
		{
			Ae1Browser_Ae2RestName:=StrSplit(WbName,"_")
			if ((Ae1Browser_Ae2RestName.MaxIndex() < 2) OR (Ae1Browser_Ae2RestName[1] <> "IE"))
				MsgBox,0,% A_LineFile "[" A_LineNumber "]",%  "Uebergabe-Parameter >" WbName "< nicht unterstuetzt. `n`nIE_`nIE_...`nerwartet. `n`nBrowser  >" Ae1Browser_Ae2RestName[1] "<   noch nicht unterstuetzt!",10
			return false
		}
		this.OnError:={Exit: False}
	}
	__Delete() {
		ExitThreadOnClose:=false
		if this.OnError.Exit
			ExitThreadOnClose:=true
		if IsObject(this.Com)
		{
			try
				this.Com.Quit()    ; bringt keine Fehlermeldung, ich sehe aber die Wirkung im TaskManager. Danke nnnik
		}
		if ExitThreadOnClose
			Exit
    }
	getUrl() {
		try
			return this.com.LocationURL ;grab current url
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	getUrlAfterQuestionMark() {
		try
			return this.com.document.location.Search ; gets substring of URL following question mark
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	getUrlPort() {
		try
			return this.com.document.location.port
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	getUrlPathname() {		
		try
			return this.com.document.location.pathname ; returns pathname
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	getLocationName() {
		try
			return this.com.LocationName ; grab page Titlerite
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	getUrlHostName() {
		try
			return this.com.document.location.hostname ; returns host
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	getUrlAfterHash() {
		try
			return this.com.document.location.hash ; retreives everyting from the # on
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	getUserAgent() {
		try
			return this.com.document.parentWindow.navigator.userAgent ; Get User Agent
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	getSourceCode(){
		try{
			SourceCode := this.com.document.documentElement.innerHtml
			this.NotBusy()
			return SourceCode
		}
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	getAllText(){
		try{
			AllText:=this.com.document.documentElement.innerText ; Get All text on page
			this.NotBusy()
			return AllText
		}
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	getUrlProtocol(){
		try
			return this.com.document.location.protocol ; retreives the protocol (http, https, etc)
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	getWinHwnd() {
		return this.WinHwnd
	}
	getIeControlHwnd() {
		MsgBox Implementierung gesucht
	}
	DuplicateTab() { ; -> ^k
		Sleep 1000
		this.NotBusy()
		WinHwnd := this.WinHwnd
		if (WinHwnd="" OR WinHwnd=0)
			SoundBeep 500
		WinActivate,ahk_id %WinHwnd%
		WinWaitActive,ahk_id %WinHwnd%,,1
		sleep 300
		ControlFocus,,ahk_id %WinHwnd%
		sleep 300
		ControlSend,,^k,ahk_id %WinHwnd%
		Sleep 1000
		this.NotBusy()
		Sleep 1000
	}
	refresh() {
		try{
			this.com.refresh ;Reload page
			this.NotBusy()
			return
		}
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	getAllLinks(){
		try{
			Links := this.Com.Document.Links ; collection of hyperlinks on the page
			Loop % Links.Length ; Loop through links
				If ((Link := Links[A_Index-1].InnerText) != "") { ; if the link is not blank
					(OuterHTML := Links[A_Index-1].OuterHTML)  ; Grab outerHTML for each link
					Link:=StrReplace(Link,"`n")
					Link:=StrReplace(Link,"`r")
					Link:=StrReplace(Link,"`t")
					OuterHTML:=StrReplace(OuterHTML,"`n")
					OuterHTML:=StrReplace(OuterHTML,"`r")
					OuterHTML:=StrReplace(OuterHTML,"`t")
					Msg .= A_Index-1 A_Space A_Space A_Space Link A_Tab OuterHTML "`r`n" ; add items to the msg list
				}
			this.NotBusy()
			return Msg
		}
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	getParent(Obj,Tiefe="6") {
									; this.Com.document.getElementsByTagName(TagP)[0].getElementsByTagName(Tag)[0]...  ergibt auch eine Vater-Beziehung 
		; ParentKnoten:={}
		ParentKnoten:=Obj
		Loop, % Tiefe {
			; MsgBox % ParentKnoten.OuterHTML
			; Probe:=ParentKnoten.innerHtml
			; MsgBox % Probe
			if(SubStr(Probe,1,5)="<head" OR SubStr(ParentKnoten.OuterHTML,1,5)="<body")
			{
				return ParentKnoten
			}
			ParentKnoten:=ParentKnoten.ParentNode
		}
		return ParentKnoten
	}
	getParents(Obj,Tiefe="30",quick="1") {
		Parents:={}
		ParentKnoten:=Obj
		ParentTagName:=ParentKnoten.TagName
		if(ParentTagName="html")
			return
		ParentAnz:=0
		Loop, % Tiefe {
			; MsgBox % ParentKnoten.OuterHTML
			ParentKnoten:=ParentKnoten.ParentNode
			ParentTagName:=ParentKnoten.TagName
			ParentPath:=ParentTagName "/" ParentPath
			++ParentAnz
			ParentVersatzt.= "."
			if(ParentTagName="html")
			{
				break
			}
		}
		if quick
			return ParentPath
		else
		{
			Parents.ParentPath:=ParentPath
			Parents.ParentVersatzt:=ParentVersatzt
			Parents.ParentAnz:=ParentAnz
			return Parents
		}
	}
	ElementFilter(Obj,FilterName="",Filter="",INr="0") {
									; this.Com.document.getElementsByTagName(TagP)[0].getElementsByTagName(Tag)[0]...  ergibt auch eine Vater-Beziehung 
		Knoten:=Obj
		if (FilterName="Tag")
		{
			if(INr="free")
				Knoten:=Knoten.getElementsByTagName(Filter)
			else
				Knoten:=Knoten.getElementsByTagName(Filter)[INr]
		}
		else if (FilterName="ID")
			Knoten:=Knoten.getElementByID(Filter)
		else if (FilterName="") {
		}
		else
		{
			MsgBox,0,% A_LineFile "[" A_LineNumber "]",Der Element-Filter %FilterName% wird noch nicht unterstuetzt.`nUnterstuetzte Filter:`nID,20
			return false
		}
		return Knoten
	}
	GetElementsHtmlByTagName(Tag="",ParentTiefe="",quick="1"){
		short:=false
		if(SubStr(Tag,1,1)="-")
		{
			short:=true
			StringTrimLeft,Tag,Tag,1
		}
		if (Tag="")
			Tag:= "*"
		B:={}
		this.Element:={}
		
		Alle := this.Com.document.getElementsByTagName(Tag)
		Anz:=Alle.Length
		Loop % Anz
		{
			TagIndex:=A_Index - 1
			Parents := this.getParents(Alle[TagIndex])

			if not quick
			{
				this.Element[TagIndex]:={}
				
				this.Element[TagIndex].outerHtml := Alle[TagIndex].OuterHTML
				this.Element[TagIndex].ParentVersatzt := Parents.ParentVersatzt					;	
				this.Element[TagIndex].ParentPath := Parents.ParentPath
			}
			; ParentPathElementsText .= Parents.ParentPath . "   " . StrReplace(StrReplace(Alle[TagIndex].OuterHTML,"`n",A_Space,All),"`t",A_Space,All) . "`r`n"
			if short
			{
				TagA:=Alle[TagIndex].OuterHTML
				EckZuPos:=InStr(TagA,">")
				ParentPathElementsText .= TagIndex A_Space Parents . "   " . SubStr(TagA,1,EckZuPos) . "`r`n"
			}
			else
				ParentPathElementsText .= TagIndex A_Tab Parents . "   " . StrReplace(StrReplace(Alle[TagIndex].OuterHTML,"`n",A_Space,All),"`t",A_Space,All) . "`r`n"
		}
		if quick
		{
			StringTrimRight,ParentPathElementsText,ParentPathElementsText,2
			return ParentPathElementsText
		}
		this.ParentPathElementsText := ParentPathElementsText
		return this.ElementsHtml:=B
	}
	GetSetOneOfAllTags(getElementsBy="",Suchliste="",NachDot="",InKlammenValue="KlammerLos",setValue="",TagIndexVorrang=""){			; Universal-Methode
; 		try	; Parameter 1 = Tag-Filer	2 = QuellTextSuchWoerter-Pipe|getrennt	3 = Aktion mit gefundenem Element	4 = KlammerInhalt	5 = Leer fuer get's	5 = Value fuer set's
		{	;	z.B.	"input"			"Anmelden|Button"						"click"								""					""
			; 			"a"				"Das sind Ihre Vorteile"				"click"								""
			;					 		"LoginLink|Anmelden|Anmelden|Button"	"outerHtml"
			;																	"innerText"
			; wenn tags und Tag-Inhalte gleich sind, kann man versuchen einen Suchbegriff des zugehoerigen Elternknoten in die Suchliste hinzu zu fuegen.
			; dieeser wird jedoch nur wirksam wenn es einen Suchbegriff links angrenzend davon gibt der im Tag Inhalt zu finden ist. Beispiel:
			; 			"+cite",		"nnnik|OOP",							"outerHtml"
			; das + vor cite ist bei der Einrichtung hilfreich. Es werden Tags + Eltern zum Blaettern angezeigt, und die betreffende Stelle in den sichtbaren Bereich gebracht.
			; 			"cite",			"nnnik|OOP",							"scrollIntoView",					""
			; 
			; das Not Zeichen ¬ erreichbar via Alt-Down 0172 Alt-Up, sorgt fuer eine Sortierung nach unten. Ein alleinstehender Begriff mit fuerendem ¬ wird nicht unterstuetzt. Beispiel: 
			;							AnkerKette|Kette|Edelstahl|¬Schmuck|¬Halskette
			; fuer technische Ketten.
			; return	this.Com.document.getElementsByTagName("h3")[0].outerHtml  "`n" this.Com.document.getElementByID("p193153").getElementsByTagName("h3")[0].outerHtml "`n"
			; return	 this.Com.document.getElementByID("p188368").getElementsByTagName("cite")[0].outerHtml "`n"this.Com.document.getElementsByTagName("cite")[0].outerHtml "`n"
			if (SubStr(getElementsBy,1,1)="+") {								;	"" -> getEl2[1]		ID -> getEl2[2]		"Tag" -> getEl1[1]	Tag -> getEl1[2]
				Info:=true 
				getElementsBy:=SubStr(getElementsBy,2)
			}
			B:={}
			if (InStr(getElementsBy,"/"))
			{											; +ID=a4711/Tag=div
				getElZu := StrSplit(getElementsBy,"/")
				Loop % getElZu.MaxIndex()
				{
					getEl%A_Index% := StrSplit(getElZu[A_Index],"=")
					
				}
			}
			else
			{
				if (getElementsBy="")
					getElementsBy:= "*"
				if (InStr(getElementsBy,"="))
				{											; +ID=a4711/Tag=div
					getEl := StrSplit(getElementsBy,"=")
					getE2[1] := 	, getE2[2] :=
				}
				else
				{
					getEl1:={}			, getEl2:={}
					getEl1[1] :=  		, getEl1[2] := 
					getEl2[1] := "Tag"	, getEl2[2] := getElementsBy
				}
			}
			if (INr="")
				INr:="free"
			Loop 2
			{
				if (getE%A_Index%[1]="ID")
					INr:="free"
				else if (getE%A_Index%[1]="Tag"){
					if (TagIndexVorrang="")
						INr:="free"
					else
						INr:=TagIndexVorrang
				}
			}
			Alle := this.Com.document
			Loop 2
				ElementFilter(Alle,getEl%A_Index%[1],getEl%A_Index%[2],INr)
			
			Anz:=Alle.Length
			; MsgBox % "0	" Alle.0.outerHtml "`n" "1	" Alle.1.outerHtml "`n" "2	" Alle.2.outerHtml "`n" "3	" Alle.3.outerHtml "`n"
			gesAnz:=0
			indexFuerGes:=-1
			if (Suchliste="")
				AddKor:=0.01
			else
				AddKor:=0
			Loop % Anz { ; Loop through Tags
				TagIndex:=A_Index - 1
				If ((All := Alle[TagIndex].OuterHTML) != "") { ; if the Tag is not blank
					Funde:=0
					PlusMinus1:=1
					SuchStr:=StrSplit(Suchliste,"|")
					SuchWortAnz:=SuchStr.MaxIndex()
					if (SuchWortAnz="")
						SuchWortAnz=0
					ParentMulti:=1
					loop % SuchWortAnz {
						PlusMinus1:=1
						if(SubStr(SuchStr[A_Index],1,1)="¬") {
							SuchStr[A_Index]:=SubStr(SuchStr[A_Index],2)
							PlusMinus1:=-10
						}
						Funstellen:=StrSplit(All,SuchStr[A_Index])
						Funde+=(Funstellen.MaxIndex() -1) ; * PlusMinus1
						; if TagIndex
						{
							; ParentFunstellen:=StrSplit(ParentNode,SuchStr[A_Index])
							; ParentFunde:=(ParentFunstellen.MaxIndex() -1) ; * PlusMinus1
							; MsgBox % ParentMulti "	" TagIndex "	" Funde "	" SuchStr[A_Index] "	" SuchStr[A_Index+1] "	" All "`n`n" ParentNode "`n`n" ges
							; if (Funde AND InStr(this.getParent(this.Com.document.getElementsByTagName(Tag)[TagIndex]).OuterHTML,SuchStr[A_Index+1]))
							; 	ParentMulti*=1.1
							; else
							;	ParentMulti*=1
						}
;						else
							; ParentFunde+=0
					}
					if (Strlen(All)<15000 AND (Funde OR Suchliste="")) {
						; ges .= ((PlusMinus1 * Funde * Funde + AddKor)*(ParentMulti)/Strlen(All))  / (SuchWortAnz ) . A_Tab . gesAnz . A_Tab . StrLen(All) "`n" ; Falls die Bewertungen hier nicht direkt zum gewuenschten Element fuerhren, kann auch mit mehrfach-Nennung eines Suchbegriffes, zu dessen Gunsten beeinflusst werden.
						ges .= ((PlusMinus1 * Funde * Funde + AddKor)*(ParentMulti)/Strlen(All))  / (SuchWortAnz ) . A_Tab . TagIndex . A_Tab . StrLen(All) "`n" ; Falls die Bewertungen hier nicht direkt zum gewuenschten Element fuerhren, kann auch mit mehrfach-Nennung eines Suchbegriffes, zu dessen Gunsten beeinflusst werden.
						B[TagIndex] :=all
						++gesAnz
					}
				}
			}
			this.Elements := B
			StringTrimRight,ges,ges,1
			sort,ges, N  R			; nach Bewertung sortieren
			Loop,Parse,ges,`n
			{
				FuerTagIndex:=StrSplit(A_LoopField,A_Tab)		; best bewerteten Index holen
				break
			}
			DieserTagIndex:=FuerTagIndex[2] ; -1			; Index auf basis 0 korrigieren
			IndexOfBest:=DieserTagIndex
			; MsgBox %DieserTagIndex%`n%ges%
			if Info
			{									;	"" -> getEl2[1]		ID -> getEl2[2]		"Tag" -> getEl1[1]	Tag -> getEl1[2]
				IfExist,%A_Temp%\wb_ges.txt				
					FileDelete,%A_Temp%\wb_ges.txt
				FileAppend,%ges%,%A_Temp%\wb_ges.txt
				BlaetternRunter:=true
				Loop{
					if (i="")
						i:=1
					FileReadLine,ges_Line,%A_Temp%\wb_ges.txt,i
					FuerTagIndex:=StrSplit(ges_Line,A_Tab)	
					DieserAnsichtTagIndex:=FuerTagIndex[2] ; -1			; Index auf basis 0 korrigieren
					; All := this.Com.document.getElementsByTagName(Tag)[DieserAnsichtTagIndex].ParentNode.ParentNode.ParentNode.ParentNode.OuterHTML
					; this.Com.document.getElementsByTagName(Tag)[DieserAnsichtTagIndex].scrollIntoView()		; in den sichtbaren Bereich damit
					; sleep 3000
					; this.Com.document.getElementsByTagName(Tag)[DieserAnsichtTagIndex].innerHTML.selectext()		; in den sichtbaren Bereich damit
					; sleep 3000
					; this.Com.document.getElementsByTagName(Tag)[DieserAnsichtTagIndex].selectext()		; this.Com.ExecWB(selectAll:=17) this.Com.ExecWB(17,0) wuerde alles Selektieren, 18 entfernt die Selection		http://www.programering.com/a/MzM3UDNwATc.html)
					; SoundBeep
					; Sleep 3000
					temp := this.Com.document
					; Loop 2
					{
						ElementFilter(temp,getEl1[1],getEl1[2])
						tempZwischen := temp
						ElementFilter(temp,getEl2[1],getEl2[2],DieserAnsichtTagIndex)
tempEnde:=temp
						; ElementFilter(temp,getEl%A_Index%[1],getEl%A_Index%[2],DieserAnsichtTagIndex)
						; if(A_Index=1)
							; tempZwischen := temp
					}
					; temp := this.ElementFilter(this.ElementFilter(this.Com.document,getEl1[1],getEl1[2]),getEl2[1],getEl2[2],DieserAnsichtTagIndex)
					
					if info
					{
						; tempEnde.offsetTop := -300		; in den sichtbaren Bereich damit
						tempEnde.parentNode.scrollIntoView()		; in den sichtbaren Bereich damit
; ControlGetFocus, Steuerelement, A
WinActivate,% "ahk_id " this.WinHwnd
WinWaitActive,% "ahk_id " this.WinHwnd,,1
; Eine Zeile nach unten scrollen:
ControlGetFocus, Steuerelement, A
SendMessage, 0x115, 0, 0, %Steuerelement%, A
SendMessage, 0x115, 0, 0, %Steuerelement%, A

Loop 7
SendMessage, 0x115, 0, 0, , % "ahk_id " this.WinHwnd
						; tempEnde.parentNode.scrollElmVert(el,-90)		; in den sichtbaren Bereich damit
						; tempEnde.scrollTop += 100		; in den sichtbaren Bereich damit
						; tempEnde.scrollDown()		; in den sichtbaren Bereich damit
						Wert:=tempEnde.outerHtml 
						tempEnde.outerHtml := "<mark>" Wert "</mark>"
					}
					; temp.value := "<marquee>" Wert "</marquee>"
					; MsgBox % wert
					; temp := this.ElementFilter(this.ElementFilter(this.Com.document,""       ,ID)       ,"Tag"    ,Tag      ,DieserAnsichtTagIndex)
					; temp:=this.Com.document.getElementsByTagName(Tag)[DieserAnsichtTagIndex]
					; TagAnzeige := this.Com.document
					TagAnzeige := temp.outerHtml
					; Loop 2
					;	ElementFilter(TagAnzeige,getEl%A_Index%[1],getEl%A_Index%[2],INr)
					; TagAnzeige := this.ElementFilter(this.ElementFilter(this.Com.document,getEl2[1],getEl2[2]),getEl1[1],getEl1[2],DieserAnsichtTagIndex).OuterHTML
					; TagAnzeige:=this.Com.document.getElementsByTagName(Tag)[DieserAnsichtTagIndex].OuterHTML
;					All := this.getParent(temp).OuterHTML
					try
						All := tempZwischen.OuterHTML
					All_Anzeige := A_Tab SubStr(StrReplace(StrReplace(All,"`n",A_Space,All),"`t",A_Space,All),1,1500)
					gesAnzeige:=StrReplace(ges,A_Tab DieserAnsichtTagIndex A_Tab,A_Tab "#" DieserAnsichtTagIndex "#" A_Tab,markiert)
					if (NOT markiert)
						break		; wenn index nicht vorhanden, d.h. oberes oder uteres Ende erreicht.
					Anzeige= % i	A_Tab	All_Anzeige "`n`nTag	Suchliste`n" getEl1[2] A_Tab	Suchliste "`n`n" TagAnzeige "`n`nBew.	index	Len`n`n" gesAnzeige
					; Anzeige= %i%	%All_Anzeige% `n`nTag	Suchliste`n%Tag%	%Suchliste%`n`n%TagAnzeige% `n`nBew.	index	Len`n`n%gesAnzeige%
					if BlaetternRunter
						MsgBox,8195 , Blättern, % "Element tiefer ansehen	Ja	höher	Nein`n`n" Anzeige "`n`n"	;	GetObjectDetails(B,"B")
					else
						MsgBox,8451 , Blättern, % "Element tiefer ansehen	Ja	höher	Nein`n`n" Anzeige "`n`n"	; 	GetObjectDetails(B,"B")

					IfMsgBox,Yes
					{
						++i
						if (i>gesAnz)
							break
						BlaetternRunter:=true
					}
					else IfMsgBox,No
					{
						--i
						if (i<1)
							break
						BlaetternRunter:=false
					}
					else
						break
				}
			}
			if(TagIndexVorrang<>"")
				DieserTagIndex := TagIndexVorrang
			else
			DieserTagIndex := IndexOfBest
			
			
			if (InKlammenValue="InKlammern")
				InKlammenValue:=
			if (InKlammenValue="KlammerLos")
			{
				InKlammenValue:=
				if (setValue="")
				{
					temp2 := this.Com.document
					; Loop 2
						; ElementFilter(temp2,getEl%A_Index%[1],getEl%A_Index%[2],DieserTagIndex,NachDot)
						ElementFilter(temp2,getEl1[1],getEl1[2],DieserTagIndex)
						ElementFilter(temp2,getEl2[1],getEl2[2],DieserTagIndex,NachDot)
					; return temp2
					; return this.ElementFilter(this.ElementFilter(this.Com.document,getEl1[1],getEl1[2]),getEl2[1],getEl2[2],DieserTagIndex)[NachDot]
				}
				else
				{
					temp2 := this.Com.document
					; Loop 2
						; ElementFilter(temp2,getEl%A_Index%[1],getEl%A_Index%[2],DieserTagIndex,NachDot) := setValue
						ElementFilter(temp2,getEl1[1],getEl1[2],DieserTagIndex)
						ElementFilter(temp2,getEl2[1],getEl2[2],DieserTagIndex,NachDot,,setValue) ; := setValue
					; return temp2
				}
			}
			else
			{
				if (setValue="")
				{
					temp2 := this.Com.document
					; Loop 2
						; ElementFilter(temp2,getEl%A_Index%[1],getEl%A_Index%[2],DieserTagIndex,NachDot,InKlammenValue)
						ElementFilter(temp2,getEl1[1],getEl1[2],DieserTagIndex)
						ElementFilter(temp2,getEl2[1],getEl2[2],DieserTagIndex,NachDot,InKlammenValue)
					; return temp2
				}
				else
				{
					temp2 := this.Com.document
					; Loop 2
						; ElementFilter(temp2,getEl%A_Index%[1],getEl%A_Index%[2],DieserTagIndex,NachDot,InKlammenValue) := setValue
						ElementFilter(temp2,getEl1[1],getEl1[2],DieserTagIndex)
						ElementFilter(temp2,getEl2[1],getEl2[2],DieserTagIndex,NachDot,InKlammenValue,setValue) ; := setValue

				
				}			; ElementFilter(ByRef Knoten,FilterName="",Filter="",INr="",TagIndex="",NachDot="",InKlammenValue="") 
			}
		}
		return temp2
;		catch
;			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	FocusClick(ID:="",Name:="",ClassName:="",TagName:=""){
		try{
			Dashes:=false
			if ID contains -,_,¯
				Dashes:=true
			if (ID<>"")
			{
				if Dashes
					this.Com.document.getElementByID(ID).focus() ; Acts like clicking the link
				else
					this.Com.document.all[ID].focus()
				this.NotBusy()
				if Dashes
					this.Com.document.getElementByID(ID).click() ; Acts like clicking the link
				else
					this.Com.document.all[ID].click()
				this.NotBusy()
			}
			if (Name<>"")
			{
				this.Com.document.GetElementsByName(Name)[0].focus()
				this.NotBusy()
				this.Com.document.GetElementsByName(Name)[0].click()
				this.NotBusy()
			}
			if (ClassName<>"")
			{
				try
					this.Com.document.GetElementsByName(ClassName)[0].focus()
				this.NotBusy()
				try
					this.Com.document.GetElementsByName(ClassName)[0].click()
				this.NotBusy()
			}
			if (TagName<>"")
			{
				this.Com.document.GetElementsByName(TagName)[0].focus()
				this.NotBusy()
				this.Com.document.GetElementsByName(TagName)[0].click()
				this.NotBusy()
			}
			; this.NotBusy()
		}
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	FeldEintrag(SuchString,ID:="",Name:="",ClassName:="",TagName:="")	{
		try
		{
			SuchStringProbe:=this.Com.document.getElementByID(ID).Value ;Unique ID-with dashes	; Existiert die ID
			this.Com.document.getElementByID(ID).Value :=SuchString ;Unique ID-with dashes		; Wert eintragen
			this.NotBusy()
			SuchStringProbe:=this.Com.document.getElementByID(ID).Value ;Unique ID-with dashes	; eingetragenen Wet fuer Probe auslesen
		}
		if (SuchStringProbe=SuchString)
			Erfolreich.="ID = " ID
		else
		{
			Loop 100 {
				NullIndex:=A_Index-1
				try{
					; MsgBox %ID% nicht gefunden
					SuchStringProbe:=this.Com.document.GetElementsByName(Name)[NullIndex].Value ;Object Name- Get array value
					this.Com.document.GetElementsByName(Name)[NullIndex].Value := SuchString
					this.NotBusy()
					SuchStringProbe:=this.Com.document.GetElementsByName(Name)[NullIndex].Value ;Object Name- Get array value
					; MsgBox %SuchStringProbe%
					if (SuchStringProbe=SuchString)
					{
						; MsgBox % NullIndex "	" SuchStringProbe
						break
					}
				}
			}
			if (SuchStringProbe=SuchString)
				Erfolreich.="Name[" NullIndex "] = " Name
			else
			{
				Loop 100 {
					NullIndex:=A_Index-1
					try{
						SuchStringProbe:=this.Com.document.getElementsByClassName(ClassName)[NullIndex].Value ;Get classname and Array value
						this.Com.document.getElementsByClassName(ClassName)[NullIndex].Value := SuchString
						this.NotBusy()
						SuchStringProbe:=this.Com.document.getElementsByClassName(ClassName)[NullIndex].Value ;Get classname and Array value
						if (SuchStringProbe=SuchString)
						{
							break
						}
					}
				}
				if (SuchStringProbe=SuchString)
					Erfolreich.="ClassName[" NullIndex "] = " ClassName
				else
				{
					Loop 100 {
						NullIndex:=A_Index-1
						try{
							SuchStringProbe:=this.Com.document.GetElementsByTagName(TagName)[NullIndex].Value ;Get Tagname and Array value
							this.Com.document.GetElementsByTagName(TagName)[NullIndex].Value := SuchString
							this.NotBusy()
							SuchStringProbe:=this.Com.document.GetElementsByTagName(TagName)[NullIndex].Value ;Get Tagname and Array value
							if (SuchStringProbe=SuchString)
								break
						}
					}
					if (SuchStringProbe=SuchString)
						Erfolreich.="TagName[" NullIndex "] = " TagName
					else
					{
						; MsgBox Der Text konnte nicht ins Feld eingetragen werden.
						Erfolreich:=false
					}
				}
			}
		}
		this.NotBusy()
		if Erfolreich
			return Erfolreich
		else
			this.ifOnErrorDoExit(this.OnError.Exit)			
	}
	Visible(flag:=true){
		try
			this.Com.Visible := flag	
			; this.NotBusy() ; Achtung, darf nicht rein. Ohne visible kein busy-Ende !!!!!!!!!!!!!!!!!!
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	Navigate(Url){
		try{
			this.Com.Navigate(Url)
			this.NotBusy()
		}
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	setOnErrorExit(Flag=0){
		this.OnError.Exit := Flag
		if Flag
			Critical,Off
	}
	History(Number){
		try{
			this.Com.document.parentWindow.history.go(Number) ; if Number is negativ Go Backward one page
			this.NotBusy()
		}
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	HistoryLen(){
		try
			return this.Com.document.parentWindow.history.length	
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	Help(Methode){
		if(Methode="")
			return "geplant:	wb-Class-Hilfe + Liste aller Methoden + Beschreibungen"
		else
			return "geplant:	Liste aller Methoden + Beschreibungen, gefiltert nach >" Methode "<"
	}
	NotBusy(){
		try{
			while this.Com.busy or this.Com.ReadyState != 4	
				Sleep 10	
		}
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
 	CloseTab(force=1) {		; wirkung wie WebBroserObjekt := "" 	bei 1 ohne Rueckfrage
		if force
		{		; Rueckfrage wird 8 Zeilen weiter unten mit ja beantwortet.
			SchliessenBestaetigenAhk=
(
WinWaitActive,Windows Internet Explorer ahk_class #32770,,1
ControlClick,Button1,Windows Internet Explorer ahk_class #32770
)
			FileDelete,%A_Temp%\SB.ahk
			FileAppend,%SchliessenBestaetigenAhk%,%A_Temp%\SB.ahk
			Run %A_Temp%\SB.ahk
		}
		sleep 20
		try{
			this.Com.document.parentWindow.window.Close()		; Reiter Schliessen mit Rueckfrage
		}
		catch
			this.ifOnErrorDoExit(this.OnError.Exit)
	}
	ifOnErrorDoExit(Flag){	; Diese Funktion hier ist nur fuer den Class-internen Aufruf vorgesehen.
		if this.OnError.Exit{
			if IsObject(this.Com){
				try
					this.Com.Quit()		; auch IE.exe beenden
			}
			Exit					; aktuellen Thread beenden
		}
	}
	; Folgende Funktion (danke Glines) ist hier fuer den Class-internen Aufruf vorgesehen.
		;************Pointer to Open IE Window******************
	WBGet(WinTitle="ahk_class IEFrame", Svr#=1) {               ;// based on ComObjQuery docs
	   static msg := DllCall("RegisterWindowMessage", "str", "WM_HTML_GETOBJECT")
			, IID := "{0002DF05-0000-0000-C000-000000000046}"   ;// IID_IWebBrowserApp
	;//     , IID := "{332C4427-26CB-11D0-B483-00C04FD90119}"   ;// IID_IHTMLWindow2
	   SendMessage msg, 0, 0, Internet Explorer_Server%Svr#%, %WinTitle%

	   if (ErrorLevel != "FAIL") {
		  lResult:=ErrorLevel, VarSetCapacity(GUID,16,0)
		  if DllCall("ole32\CLSIDFromString", "wstr","{332C4425-26CB-11D0-B483-00C04FD90119}", "ptr",&GUID) >= 0 {
			 DllCall("oleacc\ObjectFromLresult", "ptr",lResult, "ptr",&GUID, "ptr",0, "ptr*",pdoc)
			 return ComObj(9,ComObjQuery(pdoc,IID,IID),1), ObjRelease(pdoc)
		  }
	   }
	}	; written by Glines
}
; 
; ################# Class Tests: ################### ;{
; S1 := new wb("Edge")	; Test nicht unterstuetzter Browser
; S1 := new wb("Edge_S1")	; Test nicht unterstuetzter Browser
WinActivate,ahk_exe iexplore.exe
WinWaitActive,ahk_exe iexplore.exe,,2
Sleep 100
IfWinActive,ahk_exe iexplore.exe
{
	S1 := new wbr("IE_")
	MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUrl(),4
	NewTab:=false
}
else
{
	S1 := new wbr("IE_S1")
	S1.Visible(1)
	NewTab:=true
}
; S1.GetSetOneOfAllTags("+ID=a4711/Tag=div","¬body|General|strong","outerHtml"),200
; S1.setOnErrorExit(true)	; bei Fehler Thread beenden
; S2 := new wb("IE_S2")		; paralele 2. Browser Sitzung
; S2.Visible(1)
S1.Navigate("http://autohotkey.com")

MsgBox,0,% A_LineFile "[" A_LineNumber "]", % S1.GetElementsHtmlByTagName("a",,"outerHtml",0),6
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUrl() "	" S1.getLocationName() "	alle Links:`r`n" S1.getAllLinks(),5
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUrl() "	" S1.getLocationName() "	GesammtText:`r`n" S1.getAllText(),5
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUrl() "	" S1.getLocationName() "	QuellText:`r`n" S1.getSourceCode(),5
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUrlAfterHash()	,2
S1.refresh()
S1.Navigate("Google.de")
MsgBox,0,% A_LineFile "[" A_LineNumber "]", % S1.FeldEintrag("Hugo","lst-ib","q","gsfi","input"),2
S1.FocusClick("gsr") 
S1.FocusClick("","btnK")
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUrlAfterQuestionMark(),3
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUrlPathname(),2
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUrlHostname(),2
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getLocationName(),2
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % "Die Seitenhistorie hat " S1.HistoryLen() " Eintraege",2
S1.History(-1)
MsgBox,0,% A_LineFile "[" A_LineNumber "]",  % S1.getUserAgent(),4
S1.History(1)
Sleep 1000
S1.Navigate("https://autohotkey.com/boards/viewtopic.php?f=7&t=41332")

; MsgBox,0,% A_LineFile "[" A_LineNumber "]", % S1.GetSetOneOfAllTags(/"Tag=html")
MsgBox,0,% A_LineFile "[" A_LineNumber "]", % S1.GetSetOneOfAllTags("strong","General","innerhtml",,"<marquee><mark>G e n e r a <i>l</i> :   G e n e r a <i>l</i> :   G e n e r a <i>l</i></mark></marquee>"),10
MsgBox % S1.GetSetOneOfAllTags("+ID=profile188328/Tag=a","nnnik","outerHtml")
; MsgBox,0,% A_LineFile "[" A_LineNumber "]", % S1.GetSetOneOfAllTags("+strong","General","OuterHtml",,"General",0),10
; MsgBox,0,% A_LineFile "[" A_LineNumber "]", % S1.GetSetOneOfAllTags("strong","General","innerhtml.selectedText",,"General",0),10
; MsgBox % S1.GetSetOneOfAllTags("+ID=profile188328/Tag=a",,"outerHtml")
; WinHwnd := S1.getWinHwnd()
; MsgBox % S1.document.getElementByID("p188368").outerHtml
; MsgBox % S1.document.getElementByID("p188368").getElementsByTagName("cite")[0].outerHtml
; <strong>General:</strong>
; MsgBox % GetDom(S1.Com,"cite","")
; MsgBox,0,% A_LineFile "[" A_LineNumber "]", % S1.GetSetOneOfAllTags("+div","¬body|General|strong","outerHtml"),200
Sleep 1000
; MsgBox,0,% A_LineFile "[" A_LineNumber "]", % S1.GetSetOneOfAllTags("+","General","outerHtml"),2
; MsgBox % S1.getParent(S1.GetSetOneOfAllTags("+cite","nnnik"),5).outerHtml
; S1.GetSetOneOfAllTags("cite",			"nnnik wrote|prototype based languages",							"scrollIntoView",					"")	; zielt auf 13.12.2017  14:59
; Sleep 2000
; S1.GetSetOneOfAllTags("cite",			"nnnik wrote|prototype based languages",							"scrollIntoView"					)	; zielt auf 13.12.2017  14:59
; Sleep 2000
; S1.GetSetOneOfAllTags("+cite",			"nnnik wrote|prototype based languages",							"scrollIntoView",					"")	; zielt auf 13.12.2017  14:59
; Sleep 8000
; S1.GetSetOneOfAllTags("cite",			"nnnik wrote|prototype based languages",							"scrollIntoView"					)	; zielt auf 13.12.2017  14:59
; ExitApp
; S1.GetSetOneOfAllTags("+cite",			"nnnik wrote|prototype based languages",							"scrollIntoView",					"")




if Not NewTab
	S1.DuplicateTab()
sleep 2000
S1:=""
; MsgBox Skript Ende
;}	

ElementFilter(ByRef Knoten,FilterName="",Filter="",INr="",NachDot="",InKlammenValue="",setValue="") {
;	if (INr="")
;		INr:="free"
	if (FilterName="Tag")
	{
		if (INr="free"  AND NachDot="" AND InKlammenValue="")
			Knoten:=Knoten.getElementsByTagName(Filter)
		else if(INr<>"free")
		{
			if (NachDot="" AND InKlammenValue="")
				Knoten:=Knoten.getElementsByTagName(Filter)[INr]
			else if(NachDot<>"")
			{
				if (InKlammenValue="")
					if(setValue="")
						Knoten:=Knoten.getElementsByTagName(Filter)[INr][NachDot]
					else
						Knoten:=Knoten.getElementsByTagName(Filter)[INr][NachDot]	:= setValue
				else if (InKlammenValue<>"")			
					if(setValue="")
						Knoten:=Knoten.getElementsByTagName(Filter)[INr][NachDot]([InKlammenValue])
					else
						Knoten:=Knoten.getElementsByTagName(Filter)[INr][NachDot]([InKlammenValue])	:= setValue
			}
			else
				Fehlermeldung:=true
		}
		else
			Fehlermeldung:=true
	}
	else if (FilterName="ID")
	{
		if(NachDot="" AND InKlammenValue="")
			Knoten:=Knoten.getElementByID(Filter)
		else if (NachDot<>"")
		{
			if (InKlammenValue="")
				Knoten:=Knoten.getElementByID(Filter)[NachDot]
			else
				Knoten:=Knoten.getElementByID(Filter)[NachDot]([InKlammenValue])
		}
		else
			Fehlermeldung:=true
	}
	else if(FilterName="")
	{
	}
	else
	{
		Fehlermeldung:=true
		; MsgBox,0,% A_LineFile "[" A_LineNumber "]",Der Element-Filter %FilterName% wird noch nicht unterstuetzt.`nUnterstuetzte Filter:`nID,20
	}
	if Fehlermeldung
	{
		MsgBox,0,% A_LineFile "[" A_LineNumber "]",Der Element-Filter %FilterName% %Filter% %INr% %NachDot% %InKlammenValue% wird noch nicht unterstuetzt.`nUnterstuetzte Filter:`nID,20
		return false
	}
}
Anbei auch die weiter ueberarbeitete Funktion

GetSetOneOfAllTags(Tag_Name,SuchbegriffsListe,Aktion,Aktions_Option,Zuzuweisender_Wert,Tag_Index)

die nach folgendem Grundprinzip funktioniert:
Suche ein Tag-Objekt mittels Tag-Name und enthaltenen Suchbegriffen,
Frage Details des Tag-Objektes ab, fuehre eine Aktion damit aus und/oder manipuliere es.
Alle Uebergabe-Parameter sind optional, besonders je weiter rechts sie liegen.
Hinweis fuer den Parameter Aktion_Option: Es besteht ein Unterschied ob der Parameter ganz weggelassen wird, oder ob "" eine leere Zeichenkette uebergeben wird.
Bei ersterem wird der Default-Wert sinngemaess interne Klammern weglassen wirksam bei zweiterem wird intern eine leerer Wert umgeben von Klammern verwendet.

Aufrufbeispiele finden sich im Anfangskommentar zur Funktion
sowie hinter dem Class wb Funktions-Ende.

Nachtrag: der Parameter Tag_Name laesst inzwischen mehr zu:
"ID=ID_eines_Vaters/Tag=Tag_des_gewuenschten_Elements" um die Suche auf die Kinder des Vaters zu begrenzen. Ein + davor hilft beim Einrichten.

Die aktuelle wBr-Class findet man zukuenftig unter:
https://github.com/Grrdi/ZackZackOrdner ... Br/wBr.ahk
Win 10 Home (x64) and Win 11 Pro N
https://github.com/Grrdi/ZackZackOrdner/archive/master.zip --> get folders on the quick

Return to “Ich brauche Hilfe”

Who is online

Users browsing this forum: No registered users and 26 guests