1 (изменено: mozers, 2017-04-07 11:27:40)

Тема: AHK: Подключение к DOM внешнего HTML документа

Вообще связка ahk + html открывает весьма интересные возможности. Оказывается возможно - невозможное - подключение не только к встроенному контролу, а и к DOM стуктуре любой внешней страницы!:

IE := % Connect("page.html")
MsgBox % IE.document.body.innerHTML
IE.document.body.innerHTML := "<font color=red>New text on page!</font>"

Connect(fname) {
	For win in ComObjCreate( "Shell.Application" ).Windows
		If % InStr(win.LocationURL, fname)
			Return win
}

Страничку page.html надо до запуска скрипта открыть в IE

<html><body>Text on page.</body></html>

Блеск, да и только! Но вот что то с hta я обломался. Не хочет подключаться ни в какую...

2 (изменено: Malcev, 2017-04-06 23:39:18)

Re: AHK: Подключение к DOM внешнего HTML документа

Так еще можно:

f5::
ControlGet, hwnd, HWND, , Internet Explorer_Server1, ahk_class IEFrame
pwin := WBGet(hwnd)
MsgBox % pwin.document.body.outerHTML
 
WBGet(hwnd)   {
    static msg := DllCall("RegisterWindowMessage", "str", "WM_HTML_GETOBJECT")
        , IID_IHTMLWindow2 := "{332C4427-26CB-11D0-B483-00C04FD90119}"
    SendMessage, msg,,,, ahk_id %hwnd%
    DllCall("oleacc\ObjectFromLresult", "Ptr", ErrorLevel, "Ptr", 0, "Ptr", 0, PtrP, pdoc)
    Return ComObj(9,ComObjQuery(pdoc,IID_IHTMLWindow2,IID_IHTMLWindow2),1), ObjRelease(pdoc)
}

3 (изменено: mozers, 2017-04-07 00:22:11)

Re: AHK: Подключение к DOM внешнего HTML документа

Malcev, похоже это - как раз то о чем я так долго мечтал. Вот только ругается, гад. на предпоследнюю строчку. "Error: No valid COM object!"

4

Re: AHK: Подключение к DOM внешнего HTML документа

Странно. А хендл IE получаете?

ControlGet, hwnd, HWND, , Internet Explorer_Server1, ahk_class IEFrame
msgbox % hwnd

5 (изменено: mozers, 2017-04-07 00:54:43)

Re: AHK: Подключение к DOM внешнего HTML документа

Да, получаю нормально. Еще более странно, что AhkSpy, используя идентичный механизм, подключается без проблем.
Завтра на Win7 попробую... Должно подключаться по-любому. Я Ваш код несколько раз перепроверил - все правильно. Странно...

6 (изменено: Malcev, 2017-04-07 01:12:05)

Re: AHK: Подключение к DOM внешнего HTML документа

Завтра на Win7 попробую

А сейчас на чём пробуете?
Может такой код из справки пойдёт?

sURL := "https://autohotkey.com/boards/"
if webBrowser := GetWebBrowser()
   webBrowser.Navigate(sURL)
return

GetWebBrowser()
{
    ; Get a raw pointer to the document object of the top-most IE window.
    static msg := DllCall("RegisterWindowMessage", "str", "WM_HTML_GETOBJECT")
    SendMessage msg, 0, 0, Internet Explorer_Server1, ahk_class IEFrame
    if ErrorLevel = FAIL
        return  ; IE not found.
    lResult := ErrorLevel
    DllCall("oleacc\ObjectFromLresult", "ptr", lResult
        , "ptr", GUID(IID_IHTMLDocument2,"{332C4425-26CB-11D0-B483-00C04FD90119}")
        , "ptr", 0, "ptr*", pdoc)
    
    ; Query for the WebBrowserApp service. In this particular case,
    ; the SID and IID are the same, but it isn't always this way.
    static IID_IWebBrowserApp := "{0002DF05-0000-0000-C000-000000000046}"
    static SID_SWebBrowserApp := IID_IWebBrowserApp
    pweb := ComObjQuery(pdoc, SID_SWebBrowserApp, IID_IWebBrowserApp)
    
    ; Release the document object pointer.
    ObjRelease(pdoc)
    
    ; Return the WebBrowser object, wrapped for usability:
    static VT_DISPATCH := 9, F_OWNVALUE := 1
    return ComObject(VT_DISPATCH, pweb, F_OWNVALUE)
}

GUID(ByRef GUID, sGUID) ; Converts a string to a binary GUID and returns its address.
{
    VarSetCapacity(GUID, 16, 0)
    return DllCall("ole32\CLSIDFromString", "wstr", sGUID, "ptr", &GUID) >= 0 ? &GUID : ""
}

7 (изменено: mozers, 2017-04-07 17:06:48)

Re: AHK: Подключение к DOM внешнего HTML документа

На работе неинтересно (Win7) и все приведенные примеры работают без вопросов. Домой (Win10) вернусь - буду разбираться почему AhkSpy работает, а скрипт - нет.

Жаль, конечно, что serzh82saratov (автор AhkSpy) игнорирует данную тему. Он то научился и к HTA подключаться. Вот только кроме самых основных параметров окна он не пошёл. Да и зачем DOM структура ahk-щику? Меня же, напротив, интересует именно DOM.

На работе удалось даже к HTA подключиться.

ControlGet, hwnd, HWND, , Internet Explorer_Server1, ahk_class HTML Application Host Window Class
MsgBox % hwnd
IE := WBGet(hwnd)

jstext = 
(
	document.body.onclick = function(){
		ShowElementProps(event.srcElement);
	}
	function ShowElementProps(obj) {
		var props = [];
		for (var p in obj){
			try {
				var v = obj[p];
				if (v) props.push(p + ' = ' + String(v).substr(0,25));
			} catch (e) {}
		}
		alert(obj.tagName + '\n---------------\n' + props.sort().join('\n'));
	}
	alert('JavaScripts loaded!');
)
jscript := IE.document.createElement("script")
jscript.text := jstext
head := IE.document.getElementsByTagName("head")[0]
head.appendChild(jscript, head)

WBGet(hwnd) {
	Static IID_IWebBrowserApp := "{0002DF05-0000-0000-C000-000000000046}"
	Static Msg := DllCall("RegisterWindowMessage", "Str", "WM_HTML_GETOBJECT")
		, IID_IHTMLWindow2 := "{332C4427-26CB-11D0-B483-00C04FD90119}"
	SendMessage, Msg, , , , ahk_id %hwnd%
	DllCall("oleacc\ObjectFromLresult", "Ptr", ErrorLevel, "Ptr", 0, "Ptr", 0, PtrP, pdoc)
	Return ComObj(9, ComObjQuery(pdoc, IID_IHTMLWindow2, IID_IHTMLWindow2), 1), ObjRelease(pdoc)
}

Цепляется к последнему запущенному приложению, внедряет в приложение js скрипт и приложение уже работает не как задумано разработчиком, а как надо нам (по щелчку на любом элементе выводит перечень его свойств).

8

Re: AHK: Подключение к DOM внешнего HTML документа

Докладываю: На Win10 мой предыдущий код не работает. Походу он возвращает не COM объект. Пример из справки, который привел Malcev - работает, но только с окном IE. C HTA-шкой - ни в какую.

Сейчас пытаюсь выдрать из кода AhkSpy или AccViewer универсальную процедуру, которая находит и IE и HTA окна. Как, там, ё-мое, все заморочано...
Цель всего этого садомазохизма - обеспечить возможность простого (а не такого как сейчас) подключения моего DOM Explorer-а к любому выбранному HTA/IE окну. Может быть кого то заинтересует? - станете соавтором?

9

Re: AHK: Подключение к DOM внешнего HTML документа

Нудным тестированием всех найденных на просторах инета вариантов нашел таки рабочее решение:

+ открыть спойлер
pwin := WBGet("ahk_class HTML Application Host Window Class")
; pwin := WBGet()
If (pwin){
	MsgBox % pwin.document.title
} else {
	MsgBox % "IE or HTA not found!"
	return
}

jstext = 
(
	document.body.onclick = function(){
		ShowElementProps(event.srcElement);
	}
	function ShowElementProps(obj) {
		var props = [];
		for (var p in obj){
			try {
				var v = obj[p];
				if (v) props.push(p + ' = ' + String(v).substr(0,25));
			} catch (e) {}
		}
		alert(obj.tagName + '\n---------------\n' + props.sort().join('\n'));
	}
	alert('JavaScripts loaded!');
)
jscript := pwin.document.createElement("script")
jscript.text := jstext
head := pwin.document.getElementsByTagName("head")[0]
head.appendChild(jscript, head)

; https://autohotkey.com/board/topic/47052-basic-webpage-controls-with-javascript-com-tutorial/
WBGet(WinTitle="ahk_class IEFrame", Svr#=1) {               ; based on ComObjQuery docs
	static msg := DllCall("RegisterWindowMessage", "str", "WM_HTML_GETOBJECT")
		, IID := "{332C4427-26CB-11D0-B483-00C04FD90119}"   ; IID_IHTMLWindow2 (работает и IE и с HTA)
; 		, IID := "{0002DF05-0000-0000-C000-000000000046}"   ; IID_IWebBrowserApp  (работает только с IE)
	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)
		}
	}
}

Теперь надо научиться выводить список всех окон HTA приложений и окон IE в какой нить ListView дабы потом выбирать из него одно, к которому и будет произведено подключение...

10 (изменено: mozers, 2017-04-12 16:50:17)

Re: AHK: Подключение к DOM внешнего HTML документа

Выкладываю рабочий вариант (может кому пригодится).
Выводит список открытых окон Internet Explorer и HTA приложений. После выбора нужного окна выдирает из него HTML содержимое (или все, если на странице отсутствует выделенный фрагмент) и открывает его в редакторе, заданном в IE как дефолтовый HTML редактор (если не задан - то в Блокноте).

+ открыть спойлер
#Warn
#NoEnv
#SingleInstance Force
SetBatchLines -1

arr := []
WinGet, id, list,,, Program Manager
Loop, %id%
{
	this_id := id%A_Index%
	WinGetClass, this_class, ahk_id %this_id%
	If (this_class = "IEFrame") {
		WinGetTitle, this_title, ahk_id %this_id%
		arr.push(["IE",this_title])
	}
	Else If (this_class = "HTML Application Host Window Class") {
		WinGetTitle, this_title, ahk_id %this_id%
		arr.push(["HTA",this_title])
	}
}

acount := arr.MaxIndex()
If (!acount) {
	MsgBox 0x30, , Not HTA or Internet Explorer window found!
	ExitApp
}
Else If (acount = 1){
	COM_Connect(arr[1][2])
	ExitApp
}
Else {
	Loop % acount {
		Menu, MyMenu, Add, % arr[A_Index][1] "`t" arr[A_Index][2], MenuHandler
	}
	Menu, MyMenu, Show
	return
}

MenuHandler:
	COM_Connect(RegExReplace(A_ThisMenuItem, "^\S*?\t", ""))
ExitApp

COM_Connect(win_title){
	pwin := WBGet(win_title)
	If (pwin){
		doc := pwin.document
		; Извлекаем со страницы выделенный текст (если ничего не выделено, то весь)
		html := doc.selection.createRange().htmlText
		If (!html)
			html := doc.documentElement.outerHTML
		; Записываем полученный текст во временный файл
		EnvGet, TEMP, TEMP
		EnvGet, WINDIR, WINDIR
		tmp := % TEMP "\$tmp.html"
		FileDelete, % tmp
		FileAppend, % html, % tmp
		; Находим редактор, заданный для редактирования HTML
		RegRead, editor, HKEY_LOCAL_MACHINE, SOFTWARE\Microsoft\Internet Explorer\View Source Editor\Editor Name
		If (!editor)
			editor := % WINDIR "\notepad.exe"
		Run % editor " " tmp
	} else {
		MsgBox 0x30, , Could not connect to DOM!
	}
}

; https://autohotkey.com/board/topic/47052-basic-webpage-controls-with-javascript-com-tutorial/
WBGet(WinTitle="ahk_class IEFrame", Svr#=1) {               ; based on ComObjQuery docs
	static msg := DllCall("RegisterWindowMessage", "str", "WM_HTML_GETOBJECT")
		, IID := "{332C4427-26CB-11D0-B483-00C04FD90119}"   ; IID_IHTMLWindow2 (работает с IE и с HTA)
; 		, IID := "{0002DF05-0000-0000-C000-000000000046}"   ; IID_IWebBrowserApp  (работает только с IE)
	SendMessage msg, 0, 0, Internet Explorer_Server%Svr#%, %WinTitle%
	if (ErrorLevel != "FAIL") {
		lResult:=ErrorLevel, VarSetCapacity(GUID,16,0), pdoc:=""
		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)
		}
	}
}

Мой DOM Explorer тоже сейчас подключается к окнам по такому же принципу. Осталось внести лишь несколько косметических правок.

Ну и задача - максимум: Научиться так же подключаться к DOM структуре документа открытого в Chrome, FireFox и Opera.
Буду рад любым идеям и замечаниям по коду.

11

Re: AHK: Подключение к DOM внешнего HTML документа

Ну и задача - максимум: Научиться так же подключаться к DOM структуре документа открытого в Chrome, FireFox и Opera.

Насколько мне известно - только через Selenium:
http://forum.script-coding.com/viewtopic.php?id=11530

12

Re: AHK: Подключение к DOM внешнего HTML документа

Malcev, жаль... Установка дополнительного ПО меня совсем не вдохновляет.
А за ссылочку - спасибо. Интересный топик, как то я эту темку пропустил...

13 (изменено: Malcev, 2017-04-12 17:40:51)

Re: AHK: Подключение к DOM внешнего HTML документа

Если цель просто получить исходный код страницы, то можно через буфер обмена.
http://forum.script-coding.com/viewtopic.php?id=9515

14

Re: AHK: Подключение к DOM внешнего HTML документа

Malcev, опять спасибо, сходил, посмотрел, ответил там...
А получение исходного кода страницы - это я привел лишь для примера использования подключения к DOM.