IHTMLDocument interface - navigate callback
Posted: Mon Sep 26, 2005 5:09 pm
Hi all,
The following code was provided by Freak and it tracks the mouse movement over an existing istance of IE and it works fine.
I have added some additional code concerning mydispatch2 in order to try to track when the browser's state changes, for example when the user clicks on a link to go to another page. So far no luck.
You'll notice that I'm trying to use the "put_onreadystatechange" and that it returns OK. But it never actually calls my callback procedure "Navigated" when you click a link.
If you have any advice on how to get this to work I would appreciate it!
Here's the code. Don't forget you'll need an open IE window in order to run this.
The following code was provided by Freak and it tracks the mouse movement over an existing istance of IE and it works fine.
I have added some additional code concerning mydispatch2 in order to try to track when the browser's state changes, for example when the user clicks on a link to go to another page. So far no luck.
You'll notice that I'm trying to use the "put_onreadystatechange" and that it returns OK. But it never actually calls my callback procedure "Navigated" when you click a link.
If you have any advice on how to get this to work I would appreciate it!
Here's the code. Don't forget you'll need an open IE window in order to run this.
Code: Select all
Enumeration ; VARENUM
#VT_EMPTY = 0
#VT_NULL = 1
#VT_I2 = 2
#VT_I4 = 3
#VT_R4 = 4
#VT_R8 = 5
#VT_CY = 6
#VT_DATE = 7
#VT_BSTR = 8
#VT_DISPATCH = 9
#VT_ERROR = 10
#VT_BOOL = 11
#VT_VARIANT = 12
#VT_UNKNOWN = 13
#VT_DECIMAL = 14
#VT_I1 = 16
#VT_UI1 = 17
#VT_UI2 = 18
#VT_UI4 = 19
#VT_I8 = 20
#VT_UI8 = 21
#VT_INT = 22
#VT_UINT = 23
#VT_VOID = 24
#VT_HRESULT = 25
#VT_PTR = 26
#VT_SAFEARRAY = 27
#VT_CARRAY = 28
#VT_USERDEFINED = 29
#VT_LPSTR = 30
#VT_LPWSTR = 31
#VT_RECORD = 36
#VT_INT_PTR = 37
#VT_UINT_PTR = 38
#VT_FILETIME = 64
#VT_BLOB = 65
#VT_STREAM = 66
#VT_STORAGE = 67
#VT_STREAMED_OBJECT = 68
#VT_STORED_OBJECT = 69
#VT_BLOB_OBJECT = 70
#VT_CF = 71
#VT_CLSID = 72
#VT_VERSIONED_STREAM = 73
#VT_BSTR_BLOB = $FFF
#VT_VECTOR = $1000
#VT_ARRAY = $2000
#VT_BYREF = $4000
#VT_RESERVED = $8000
#VT_ILLEGAL = $FFFF
#VT_ILLEGALMASKED = $FFF
#VT_TYPEMASK = $FFF
EndEnumeration
Structure VARIANT1
vt.w
wReserved1.w
wReserved2.w
wReserved3.w
StructureUnion
llVal.LARGE_INTEGER
lVal.l
bVal.b
iVal.w
fltVal.f
dblVal.LARGE_INTEGER
boolVal.l
bool.l
scode.l
cyVal.l
date.l
bstrVal.l
*punkVal.IUnknown
*pdispVal.IDispatch
*parray.l
*pbVal.BYTE
*piVal.WORD
*plVal.LONG
*pllVal.LARGE_INTEGER
*pfltVal.FLOAT
*pdblVal.LARGE_INTEGER
*pboolVal.LONG
*pbool.LONG
*pscode.LONG
*pcyVal.LONG
*pdate.LONG
*pbstrVal.LONG
*ppunkVal.LONG
*ppdispVal.LONG
*pparray.LONG
*pvarVal.VARIANT1
byref.l
cVal.b
uiVal.w
ulVal.l
ullVal.LARGE_INTEGER
intVal.l
uintVal.l
*pdecVal.LONG
*pcVal.BYTE
*puiVal.WORD
*pulVal.LONG
*pullVal.LARGE_INTEGER
*pintVal.LONG
*puintVal.LONG
decVal.l
EndStructureUnion
EndStructure
Structure VARIANT_SPLIT
StructureUnion
VAriant.VARIANT1
split.l[4]
EndStructureUnion
EndStructure
Interface IHTMLElementCollection_FIXED
QueryInterface(a,b)
AddRef()
Release()
GetTypeInfoCount(a)
GetTypeInfo(a,b,c)
GetIDsOfNames(a,b,c,d,e)
Invoke(a,b,c,d,e,f,g,h)
toString(a)
put_length(a)
get_length(a)
get__newEnum(a)
item(a1,a2,a3,a4,b1,b2,b3,b4,c)
tags(a,b)
EndInterface
Procedure MakeBSTR(String$)
Unicode$ = Space(Len(String$)*2+2)
MultiByteToWideChar_(#CP_ACP, 0, @String$, -1, @Unicode$, Len(String$)*2+2)
ProcedureReturn SysAllocString_(@Unicode$)
EndProcedure
Procedure.s ReadBSTR(bstr)
length = WideCharToMultiByte_(#CP_ACP, 0, bstr, -1, 0, 0, 0, 0)
Text$ = Space(length)
WideCharToMultiByte_(#CP_ACP, 0, bstr, -1, @Text$, length, 0, 0)
ProcedureReturn Text$
EndProcedure
Procedure.l GetIHTMLDocument2(ExplorerServerWindow)
HtmlDoc.IHTMLDocument2 = 0
OleAcc = OpenLibrary(#PB_Any, "OLEACC.DLL")
If OleAcc And IsFunction(OleAcc, "ObjectFromLresult")
Message = RegisterWindowMessage_("WM_HTML_GETOBJECT")
SendMessageTimeout_(ExplorerServerWindow, Message, 0, 0, #SMTO_ABORTIFHUNG, 1000, @MessageResult)
CallFunction(OleAcc, "ObjectFromLresult", MessageResult, ?IID_IHTMLDocument2, 0, @HtmlDoc)
CloseLibrary(OleAcc)
EndIf
ProcedureReturn HtmlDoc
EndProcedure
Procedure EnumChildProc(hwnd, *hServer.LONG)
class$ = Space(100)
GetClassName_(hwnd, @class$, 100)
If class$ = "Internet Explorer_Server"
*hServer\l = hwnd ; server window found.
ProcedureReturn #False
Else
ProcedureReturn #True
EndIf
EndProcedure
DataSection
IID_IHTMLDocument2: ; {332C4425-26CB-11D0-B483-00C04FD90119}
Data.l $332C4425
Data.w $26CB, $11D0
Data.b $B4, $83, $00, $C0, $4F, $D9, $01, $19
IID_IHTMLElement: ; {3050F1FF-98B5-11CF-BB82-00AA00BDCE0B}
Data.l $3050F1FF
Data.w $98B5, $11CF
Data.b $BB, $82, $00, $AA, $00, $BD, $CE, $0B
IID_IHTMLElementCollection: ; {3050F21F-98B5-11CF-BB82-00AA00BDCE0B}
Data.l $3050F21F
Data.w $98B5, $11CF
Data.b $BB, $82, $00, $AA, $00, $BD, $CE, $0B
IID_NULL: ; {00000000-0000-0000-0000-000000000000}
Data.l $00000000
Data.w $0000, $0000
Data.b $00, $00, $00, $00, $00, $00, $00, $00
EndDataSection
Structure DISPPARAMS
*rgvarg; // Array of arguments.
*rgdispidNamedArgs; // Dispatch IDs of named arguments.
cArgs.l; // Number of arguments.
cNamedArgs.l; // Number of named arguments.
EndStructure
#DISPATCH_METHOD = $1
#DISPATCH_PROPERTYGET = $2
#DISPATCH_PROPERTYPUT = $4
#DISPATCH_PROPERTYPUTREF = $8
Structure IID Extends GUID: EndStructure
Structure IDispatchVtbl
QueryInterface.l
AddRef.l
Release.l
GetTypeInfoCount.l
GetTypeInfo.l
GetIDsOfNames.l
Invoke.l
EndStructure
Structure IDispatchObject
Vtbl.l
RefCount.l
UserData.l
Function.l
EndStructure
NewList IDispatchObjects.IDispatchObject()
DataSection
IID_IUnknown: ; {00000000-0000-0000-C000-000000000046}
Data.l $00000000
Data.w $0000, $0000
Data.b $C0, $00, $00, $00, $00, $00, $00, $46
IID_IDispatch: ; {00020400-0000-0000-C000-000000000046}
Data.l $00020400
Data.w $0000, $0000
Data.b $C0, $00, $00, $00, $00, $00, $00, $46
EndDataSection
Procedure IDispatch_QueryInterface(*THIS.IDispatchObject, *IID.IID, *Object.LONG)
If *Object = 0
ProcedureReturn #E_INVALIDARG
ElseIf CompareMemory(*IID, ?IID_IUnknown, SizeOf(IID)) Or CompareMemory(*IID, ?IID_IDispatch, SizeOf(IID))
*Object\l = *THIS
*THIS\RefCount + 1
ProcedureReturn #S_OK
Else
*Object\l = 0
ProcedureReturn #E_NOINTERFACE
EndIf
EndProcedure
Procedure IDispatch_AddRef(*THIS.IDispatchObject)
*THIS\RefCount + 1
ProcedureReturn *THIS\RefCount
EndProcedure
Procedure IDispatch_Release(*THIS.IDispatchObject)
*THIS\RefCount - 1
If *THIS\RefCount <= 0
ChangeCurrentElement(IDispatchObjects(), *THIS)
DeleteElement(IDispatchObjects())
ProcedureReturn 0
Else
ProcedureReturn *THIS\RefCount
EndIf
EndProcedure
Procedure IDispatch_GetTypeInfoCount(*THIS.IDispatchObject, *pctinfo.LONG)
If *pctinfo = 0
ProcedureReturn #E_INVALIDARG
Else
*pctinfo\l = 0
ProcedureReturn #S_OK
EndIf
EndProcedure
Procedure IDispatch_GetTypeInfo(*THIS.IDispatchObject, iTInfo, lcid, *pptInfo)
ProcedureReturn #E_NOTIMPL
EndProcedure
Procedure IDispatch_GetIDsOfNames(*THIS.IDispatchObject, *riid.IID, *rgszNames, cNames, lcid, *rgDispID.LONG)
If CompareMemory(*riid, ?IID_NULL, SizeOf(IID)) = 0
ProcedureReturn #DISP_E_UNKNOWNINTERFACE
ElseIf *rgDispID = 0 Or cNames = 0
ProcedureReturn #E_INVALIDARG
Else
While cNames > 0 ; we provide no names, so set all passed fields to DISPID_UNKNOWN (-1)
*rgDispID\l = -1
*rgDispID + 4
cNames - 1
Wend
ProcedureReturn #DISP_E_UNKNOWNNAME
EndIf
EndProcedure
Procedure IDispatch_Invoke(*THIS.IDispatchObject, dispIdMember, *riid.IID, lcid, wFlags.w, *pDispParams.DISPPARAMS, *pVarResult.VARIANT1, *pExcpInfo, *puArgErr)
If CompareMemory(*riid, ?IID_NULL, SizeOf(IID)) = 0
ProcedureReturn #DISP_E_UNKNOWNINTERFACE
ElseIf dispIdMember <> 0 Or wFlags <> #DISPATCH_METHOD
ProcedureReturn #DISP_E_MEMBERNOTFOUND
ElseIf *pDispParams = 0
ProcedureReturn #E_INVALIDARG
ElseIf *pDispParams\cNamedArgs > 0
ProcedureReturn #DISP_E_NONAMEDARGS
ElseIf *pDispParams\cArgs > 0
ProcedureReturn #DISP_E_BADPARAMCOUNT
Else
CallFunctionFast(*THIS\Function, *THIS\UserData)
ProcedureReturn #S_OK
EndIf
EndProcedure
Global IDispatchVtbl.IDispatchVtbl
IDispatchVtbl\QueryInterface = @IDispatch_QueryInterface()
IDispatchVtbl\AddRef = @IDispatch_AddRef()
IDispatchVtbl\Release = @IDispatch_Release()
IDispatchVtbl\GetTypeInfoCount = @IDispatch_GetTypeInfoCount()
IDispatchVtbl\GetTypeInfo = @IDispatch_GetTypeInfo()
IDispatchVtbl\GetIDsOfNames = @IDispatch_GetIDsOfNames()
IDispatchVtbl\Invoke = @IDispatch_Invoke()
Procedure CreateIDispatch(DefaultFunction, UserData)
AddElement(IDispatchObjects())
IDispatchObjects()\Vtbl = @IDispatchVtbl
IDispatchObjects()\RefCount = 1
IDispatchObjects()\UserData = UserData
IDispatchObjects()\Function = DefaultFunction
ProcedureReturn @IDispatchObjects()
EndProcedure
; =============================================================
Interface IHTMLDocument2_FIXED
QueryInterface(a,b)
AddRef()
Release()
GetTypeInfoCount(a)
GetTypeInfo(a,b,c)
GetIDsOfNames(a,b,c,d,e)
Invoke(a,b,c,d,e,f,g,h)
get_Script(a)
get_all(a)
get_body(a)
get_activeElement(a)
get_images(a)
get_applets(a)
get_links(a)
get_forms(a)
get_anchors(a)
put_title(a)
get_title(a)
get_scripts(a)
put_designMode(a)
get_designMode(a)
get_selection(a)
get_readyState(a)
get_frames(a)
get_embeds(a)
get_plugins(a)
put_alinkColor(a)
get_alinkColor(a)
put_bgColor(a)
get_bgColor(a)
put_fgColor(a)
get_fgColor(a)
put_linkColor(a)
get_linkColor(a)
put_vlinkColor(a)
get_vlinkColor(a)
get_referrer(a)
get_location(a)
get_lastModified(a)
put_URL(a)
get_URL(a)
put_domain(a)
get_domain(a)
put_cookie(a)
get_cookie(a)
put_expando(a)
get_expando(a)
put_charset(a)
get_charset(a)
put_defaultCharset(a)
get_defaultCharset(a)
get_mimeType(a)
get_fileSize(a)
get_fileCreatedDate(a)
get_fileModifiedDate(a)
get_fileUpdatedDate(a)
get_security(a)
get_protocol(a)
get_nameProp(a)
write(a)
writeln(a)
open(a,b,c,d,e)
close()
clear()
queryCommandSupported(a,b)
queryCommandEnabled(a,b)
queryCommandState(a,b)
queryCommandIndeterm(a,b)
queryCommandText(a,b)
queryCommandValue(a,b)
execCommand(a,b,c,d)
execCommandShowHelp(a,b)
createElement(a,b)
put_onhelp(a1,a2,a3,a4)
get_onhelp(a)
put_onclick(a1,a2,a3,a4)
get_onclick(a)
put_ondblclick(a1,a2,a3,a4)
get_ondblclick(a)
put_onkeyup(a1,a2,a3,a4)
get_onkeyup(a)
put_onkeydown(a1,a2,a3,a4)
get_onkeydown(a)
put_onkeypress(a1,a2,a3,a4)
get_onkeypress(a)
put_onmouseup(a1,a2,a3,a4)
get_onmouseup(a)
put_onmousedown(a1,a2,a3,a4)
get_onmousedown(a)
put_onmousemove(a1,a2,a3,a4)
get_onmousemove(a)
put_onmouseout(a1,a2,a3,a4)
get_onmouseout(a)
put_onmouseover(a1,a2,a3,a4)
get_onmouseover(a)
put_onreadystatechange(a1,a2,a3,a4)
get_onreadystatechange(a)
put_onafterupdate(a1,a2,a3,a4)
get_onafterupdate(a)
put_onrowexit(a1,a2,a3,a4)
get_onrowexit(a)
put_onrowenter(a1,a2,a3,a4)
get_onrowenter(a)
put_ondragstart(a1,a2,a3,a4)
get_ondragstart(a)
put_onselectstart(a1,a2,a3,a4)
get_onselectstart(a)
elementFromPoint(a,b,c)
get_parentWindow(a)
get_styleSheets(a)
put_onbeforeupdate(a1,a2,a3,a4)
get_onbeforeupdate(a)
put_onerrorupdate(a1,a2,a3,a4)
get_onerrorupdate(a)
toString(a)
createStyleSheet(a,b,c)
EndInterface
Interface IHTMLElement_FIXED
QueryInterface(a,b)
AddRef()
Release()
GetTypeInfoCount(a)
GetTypeInfo(a,b,c)
GetIDsOfNames(a,b,c,d,e)
Invoke(a,b,c,d,e,f,g,h)
setAttribute(a,b,c)
getAttribute(a,b,c)
removeAttribute(a,b,c)
put_className(a)
get_className(a)
put_id(a)
get_id(a)
get_tagName(a)
get_parentElement(a)
get_style(a)
put_onhelp(a1,a2,a3,a4)
get_onhelp(a)
put_onclick(a1,a2,a3,a4)
get_onclick(a)
put_ondblclick(a1,a2,a3,a4)
get_ondblclick(a)
put_onkeydown(a1,a2,a3,a4)
get_onkeydown(a)
put_onkeyup(a1,a2,a3,a4)
get_onkeyup(a)
put_onkeypress(a1,a2,a3,a4)
get_onkeypress(a)
put_onmouseout(a1,a2,a3,a4)
get_onmouseout(a)
put_onmouseover(a1,a2,a3,a4)
get_onmouseover(a)
put_onmousemove(a1,a2,a3,a4)
get_onmousemove(a)
put_onmousedown(a1,a2,a3,a4)
get_onmousedown(a)
put_onmouseup(a1,a2,a3,a4)
get_onmouseup(a)
get_document(a)
put_title(a)
get_title(a)
put_language(a)
get_language(a)
put_onselectstart(a1,a2,a3,a4)
get_onselectstart(a)
scrollIntoView(a)
contains(a,b)
get_sourceIndex(a)
get_recordNumber(a)
put_lang(a)
get_lang(a)
get_offsetLeft(a)
get_offsetTop(a)
get_offsetWidth(a)
get_offsetHeight(a)
get_offsetParent(a)
put_innerHTML(a)
get_innerhtml(a)
put_innerText(a)
get_innerText(a)
put_outerHTML(a)
get_outerHTML(a)
put_outerText(a)
get_outerText(a)
insertAdjacentHTML(a,b)
insertAdjacentText(a,b)
get_parentTextEdit(a)
get_isTextEdit(a)
click()
get_filters(a)
put_ondragstart(a1,a2,a3,a4)
get_ondragstart(a)
toString(a)
put_onbeforeupdate(a1,a2,a3,a4)
get_onbeforeupdate(a)
put_onafterupdate(a1,a2,a3,a4)
get_onafterupdate(a)
put_onerrorupdate(a1,a2,a3,a4)
get_onerrorupdate(a)
put_onrowexit(a1,a2,a3,a4)
get_onrowexit(a)
put_onrowenter(a1,a2,a3,a4)
get_onrowenter(a)
put_ondatasetchanged(a1,a2,a3,a4)
get_ondatasetchanged(a)
put_ondataavailable(a1,a2,a3,a4)
get_ondataavailable(a)
put_ondatasetcomplete(a1,a2,a3,a4)
get_ondatasetcomplete(a)
put_onfilterchange(a1,a2,a3,a4)
get_onfilterchange(a)
get_children(a)
get_all(a)
EndInterface
; code goes below
; This is our event callback.
; The 'UserData' field is used to pass the IHTMLWindow2 pointer
;
Procedure MouseMove(Window.IHTMLWindow2)
;CallDebugger
; we can get IHTMLEventObj from IHTMLWindow2. This only
; works during an event so do not try it outside of the event callback.
;
If Window\get_event(@Event.IHTMLEventObj) = #S_OK
; lets get the mouse position
;
Event\get_offsetX(@MouseX)
Event\get_offsetY(@MouseY)
SetGadgetText(0, Str(MouseY)+" x " +Str(MouseX))
Event\Release() ; make sure everything is properly released!
Else
SetGadgetText(0, "mouse moved")
EndIf
EndProcedure
Procedure Navigated(pDocument.IHTMLDocument2_FIXED)
CallDebugger
If pDocument\get_readyState(@state) = #S_OK
cState.s = ReadBSTR(state)
SetGadgetText(0, cState)
Else
SetGadgetText(0, "event get_readystate failed")
EndIf
EndProcedure
; **** CODE STARTS HERE ****
CoInitialize_(0)
; find the IE server window:
;
hwnd.l = FindWindow_("IEFrame", 0)
EnumChildWindows_(hwnd, @EnumChildProc(), @ServerWindow)
; get the interface:
;
Document.IHTMLDocument2_FIXED = GetIHTMLDocument2(ServerWindow)
Global Document.IHTMLDocument2_FIXED
OpenWindow(0, 0, 0, 200, 200, #PB_Window_SystemMenu, "mouse move")
CreateGadgetList(WindowID())
TextGadget(0, 5, 5, 190, 190, "", #PB_Text_Border)
If Document
; we get IHTMLWindow2 to later get the event object from it.
;
If Document\get_parentWindow(@Window.IHTMLWindow2) = #S_OK
; Here is where our own IDispatch is created. We use the 'UserData'
; parameter to pass the IHTMLWindow2 pointer to the callback.
;
MyDispatch.IDispatch = CreateIDispatch(@MouseMove(), Window)
MyDispatch2.IDispatch = CreateIDispatch(@Navigated(), Document)
; Ok, need a VARIANT of type VT_DISPATCH.
; The VARIANT_SPLIT workaround is needed for the below call.
;
varDispatch.VARIANT_SPLIT
varDispatch\VAriant\vt = #VT_DISPATCH
varDispatch\VAriant\pdispVal = MyDispatch
varDispatch2.VARIANT_SPLIT
varDispatch2\VAriant\vt = #VT_DISPATCH
varDispatch2\VAriant\pdispVal = MyDispatch2
; call the method to set the mouse move handler.
;
If Document\put_onmousemove(varDispatch\split[0],varDispatch\split[1],varDispatch\split[2],varDispatch\split[3]) = #S_OK
SetGadgetText(0, GetGadgetText(0) + "mouse callback set." + Chr(13) + Chr(10))
Else
SetGadgetText(0, GetGadgetText(0) + "mouse callback failure!" + Chr(13) + Chr(10))
EndIf
If Document\put_onreadystatechange(varDispatch2\split[0],varDispatch2\split[1],varDispatch2\split[2],varDispatch2\split[3]) = #S_OK
SetGadgetText(0, GetGadgetText(0) + "event callback set." + Chr(13) + Chr(10))
Else
SetGadgetText(0, GetGadgetText(0) + "event callback failure!" + Chr(13) + Chr(10))
EndIf
; lets just wait.
; WaitWindowEvent() or WindowEvent() MUST be called in order for the callback
; stuff to work correctly!
;
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
; release our own IDispatch (frees the LinkedList element)
;
MyDispatch\Release()
Window\Release()
EndIf
Document\Release()
EndIf
CoUninitialize_()
End