HTMLWindow_(Put|Del)Var()

Post your working scripts, libraries and tools
Coco
Posts: 771
Joined: 29 Sep 2013, 20:37
GitHub: cocobelgica

HTMLWindow_(Put|Del)Var()

29 Nov 2014, 07:11

Dynamically put or delete(see remarks) a property in the window(HTMLWindow) object's global namespace
Edit: I just realized that this can also be used for COM objects that implement IDispatchEx - should be renamed to something like DispEx_PutProperty or similar... :)

ScriptControl has the AddObject method which is very handy(esp. when using ComDispatch/ComDispatch0). This is similar to the AddObject method.

HTMLWindow_PutVar
Syntax: dispid := HTMLWindow_PutVar( window, name [ , value ] )
Remark(s):
  • Requires ComDispatch/ComDispatch0 if value is an AHK object.
Code:
edit: (fixed) value is now set after calling InvokeEx

Code: Select all

HTMLWindow_PutVar(window, name, value*)
{
	DISPID := "" ;// for #Warn
	;// Query window object for IDispatchEx interface - http://goo.gl/ClYyU
	if pIDispatchEx := ComObjQuery(window, "{A6EF9860-C720-11D0-9337-00A0C90DCAA9}") ;// IID_IDispatchEx
	{
		GetDispID := NumGet(NumGet(pIDispatchEx + 0) + 7*A_PtrSize) ;// http://goo.gl/4NNY9A
		if !DllCall(GetDispID, "Ptr", pIDispatchEx, "Str", name, "UInt", 2, "Int*", DISPID) ;// fdexNameEnsure:=0x00000002
		{
			arr := ComObjArray(0xC, 1) ;// VT_VARIANT:=0xC
			pVARIANTARG := NumGet(ComObjValue(arr) + 12 + (A_PtrSize == 8 ? 4 : 0)) ;// + padding
			; OR VarSetCapacity(VARIANTARG, 8 + 2*A_PtrSize, 0) ;// http://goo.gl/Kqf11m

			VarSetCapacity(DISPPARAMS, 16, 0) ; http://goo.gl/btTQFl
			NumPut(1, NumPut(pVARIANTARG, DISPPARAMS), A_PtrSize, "UInt") ; *rgvarg, cArgs

			InvokeEx := NumGet(NumGet(pIDispatchEx + 0) + 8*A_PtrSize) ;// http://goo.gl/fNGaaI
			if !DllCall(InvokeEx, "Ptr", pIDispatchEx, "Int", DISPID
			          , "UInt", 1024, "UShort", 4, "Ptr", &DISPPARAMS ;// DISPATCH_PROPERTYPUT:=0x4 | DISPATCH_PROPERTYPUTREF:=0x8
			          , "Ptr", 0, "Ptr", 0, "Ptr", 0, "UInt")
			&& value[A_AhkVersion < "2" ? "MaxIndex" : "Length"]()
				window[name] := value[1]
		}
		ObjRelease(pIDispatchEx)
	}
	return DISPID
}
HTMLWindow_DelVar
Syntax: bSuccess := HTMLWindow_DelVar( window, name [ , cs := false ] )
Remark(s):
  • cs - case sensitivity
  • Somehow HRESULT returns S_FALSE which indicates that the member exists but cannot be deleted. I need to investigate further on this
Code:

Code: Select all

HTMLWindow_DelVar(window, name, cs:=false)
{
	pIDispatchEx := ComObjQuery(window, "{A6EF9860-C720-11D0-9337-00A0C90DCAA9}")
	DeleteMemberByName := NumGet(NumGet(pIDispatchEx + 0) + 9*A_PtrSize)
	grfdex := cs ? 0x00000001 : 0x00000008 ;// fdexNameCaseSensitive : fdexNameCaseInsensitive
	HRESULT := DllCall(DeleteMemberByName, "Ptr", pIDispatchEx, "WStr", name, "UInt", grfdex) ;// http://goo.gl/fNZu9a
	ObjRelease(pIDispatchEx)
	return !HRESULT ;// S_OK=0, S_FALSE=1
}
Example:

Code: Select all

#Include <HTMLWindow_PutVar>

Gui New
Gui Margin, 0, 0
Gui Add, ActiveX, w600 h400 vWB, Shell.Explorer

WB.Navigate("about:blank")
while (WB.ReadyState != 4)
	Sleep 10

html := "
(
<!DOCTYPE html>
<html>
<head>
<meta http-equiv='X-UA-Compatible' content='IE=edge'/>
<script type='text/javascript'></script>
</head>
<body>
<h1>Hello World</h1>
</body>
</html>
)"

document := WB.Document
document.open(), document.write(html), document.close()

window := document.parentWindow
HTMLWindow_PutVar(window, "Hello", "Hello World")

Gui Show

MsgBox %  window.Hello ;// show the value of the added property
return
GuiClose:
	ExitApp
Last edited by Coco on 06 Dec 2014, 02:07, edited 4 times in total.
User avatar
joedf
Posts: 8589
Joined: 29 Sep 2013, 17:08
Facebook: J0EDF
Google: +joedf
GitHub: joedf
Location: Canada
Contact:

Re: HTMLWindow_(Put|Del)Var()

29 Nov 2014, 12:05

Very nice!
lexikos
Posts: 8577
Joined: 30 Sep 2013, 04:07
GitHub: Lexikos

Re: HTMLWindow_(Put|Del)Var()

06 Dec 2014, 01:48

If GetDispID fails, your function fails to release pIDispatchEx.

What's CWebDisp()?

DelVar probably isn't very useful.
JScript has a delete operator which does not work at all like C++'s delete operator. Rather, JScript's delete operator removes an expando field from an object. It's pretty useless actually, because doing so does not free up any memory beyond simply clearing the field. Why not? Because implementers must ensure that if the property is re-added that it gets the same dispatch identifier the second time; someone might be caching the dispid. That means that the property bucket and its name has to be kept around, and worse, that every property bucket needs a flag that marks whether it's deleted or not. (The implementer must also ensure that property enumeration continues to work even if the enumerator -- see below -- is presently sitting on a property that was just deleted.) Use DeleteMemberByName or DeleteMemberByDispID in the unlikely event that you want to use this feature.
Source: Wherefore IDispatchEx? - Fabulous Adventures In Coding - Site Home - MSDN Blogs
For adding variables to a window object, I tend to do things like window.execScript("var Hello"), window.Hello := ..., or just design around it (i.e. avoid the need to add variables from outside JScript). I wrote a function like yours years ago, but never actually used it. It's outdated now.
Coco
Posts: 771
Joined: 29 Sep 2013, 20:37
GitHub: cocobelgica

Re: HTMLWindow_(Put|Del)Var()

06 Dec 2014, 01:57

lexikos wrote:If GetDispID fails, your function fails to release pIDispatchEx.
Oops, thanks for spotting that one.
lexikos wrote:What's CWebDisp()?
That shouldn't be in there, copy-paste artifact. :)

Thanks for the reference on JScript's delete operator...

Return to “Scripts and Functions”

Who is online

Users browsing this forum: No registered users and 30 guests