car := {"name" : "Ferrari"} enum := ObjNewEnum(car) msgbox, % isObject(enum) ; 1 oExcel := ComObjCreate("Excel.Application") oExcel.Workbooks.Add oExcel.Visible := true enum := ObjNewEnum(oExcel.Range("A1", "A5")) msgbox, % isObject(enum) ; 0 - fails for c in oExcel.Range("A1", "A5") msgbox, % A_index ; 1,2,3,4,5 - works ; for in creates enum object internally
[solved] Why I fail to create an enum object of XL.Range()?
So it's like the ._NewEnum() method can be used 'externally' (in ahk script) only by ahk_object objects? (objects created by Object() function)
That is a little bit strange as it appears that .Next() should work with every object, not just ahk_object (at least that's how I understand the documentation). ... or maybe I'm wrong again. Link. Are 'additional parameters' the parameters I can use _when I overload the enum object [] operators_ inside ahk_object? (object[k, v]). When I've read this documentation page the first time, I've understood it in a way that .Next() can have i.e. more than two parameters _if_ there is for example _a COM object_ that supports three parameters (COM object that has some cumbersome internal data structure inside it). I wasn't interpreting the 'additional parameters' in terms of enum object operator overloading. Is .Next() also only available externally to ahk_objects?
:?: - I'm not sure you're getting at:So it's like the ._NewEnum() method can be used 'externally' (in ahk script) only by ahk_object objects? (objects created by Object() function)
oExcel := ComObjCreate("Excel.Application") oExcel.Workbooks.Add enum := oExcel.Range("A1", "A5")._NewEnum Loop 5 enum.next(c), t .= c.address "`n" oExcel.Quit MsgBox %t%
When I was testing a similar piece of code earlier, I wrote:
oExcel := ComObjCreate("Excel.Application") oExcel.Workbooks.Add enum := oExcel.Range("A1", "A5[color=red]").Ne[/color]wEnum MsgBox, % IsObject(enum) Loop 5 enum.next(c), t .= c.address "`n" oExcel.Quit MsgBox %t%and I was wondering why the code fails.
[quote name="Documentation]Related
For-loop, Object.NewEnum()
[/quote]
So ObjNewEnum() works for ahk_objects only, while any_object._NewEnum() may work with certain 'other' objects also?
The Com Object does not have a NewEnum property implemented. It does, however, have a _NewEnum property.... I was wondering why the code fails.
Ok.result := obj.Method(params)
result := obj.Assign(params)
result := obj.Remove(params)
result := obj._NewEnum(params)
Calling the method this way allows each object to implement its own behaviour for that method. However, if an object overrides a built-in method (i.e. an object overrides an Assign() method), it (the object) typically needs a way to access the original functionality (original functionality: the Assign built-in method). It (the object) can do that (access the original functionality) by using the function form:
result := ObjMethod(obj, params)
result := ObjAssign(obj, params)
result := ObjRemove(obj, params)
result := ObjNewEnum(obj, params)
//Lets suppose I have two kinds of objects: ahk_objects and oth_objects ({oth_objects} = {all objects} \ {ahk_objects}). Note that while I can override the 'ahk_object' built-in method, I can't overload 'oth_object' built-in method. That is why I _need_ ObjNewEnum() for ahk_objects and at the same time I _don't need_ ObjNewEnum() for oth_objects. ObjNewEnum() restores overriden built-in method functionality, oth_objects can't have overriden built-in methods (or can they?*).
Calling the function directly is marginally faster since the name can be resolved at load-time, but the syntax is generally less intuitive. Any custom behaviour implemented by the object is bypassed, so these functions should typically be used only by the object itself.
Just for the reference, see also: link. I've overextended Lexikos answer onto _NewEnum() method.
//Edit: * they can't:
car := { "name" : "Ferrari" } enum := cer.newEnum() ;MsgBox, % IsObject(enum) oExcel := ComObjCreate("Excel.Application") oExcel.Visible := true oExcel.Workbooks.Add ; add custom property / method to COM object oExcel.customFunc := Func("oExcel_customFunc") ; unknown name ; use ahk built-in method on COM object oExcel.Insert("Krysia", 987) ; unknown name oExcel_customFunc() { MsgBox, dupa } ; Conclusion: it is futile to either: ; add custom property to COM object ; use AHK built-in method on COM object ; I can see the contradiction now: how can COM object have AHK built-in method? ; once object X becomes a COM object (ComObjActive() or ComObjCreate() results are assigned to an object X) ; the object X now 'contains' only COM specific methods and none AHK built-in methods! ; Note: it is just a coincidence that both ahk_objects and COM objects both have _NewEnum() method. ; This is an 'exception' from the rule above (once ahk_object becomes COM object, ahk_object removes ; all ahk built-in methods from ahk_object's body (and adds COM specific methods to its body) ).
//edit2: note the difference between _NewEnum() and _NewEnum. COM objects don't have _NewEnum() method but COM objects have _NewEnum property. AHK objects have _NewEnum() method (and _NewEnum property?)
It depends on the specific Com Object. You pointed out the Excel Range object has a _NewEnum property, but the ShellWindows object has a _NewEnum() method. Hence why I refer to the _NewEnum member :wink:COM objects don't have _NewEnum() method but COM objects have _NewEnum property.
Certain Com Objects have a _NewEnum member, which will allow them to work with AHK's for-loop. The for-loop will internally call the _NewEnum() method, and fall back on the _NewEnum property if need be.
It wouldn't work with the for-loop if it didn't have a _NewEnum property.I'm also curious how did you know that COM Excel Range objects have _NewEnum property
... or you could enumerate the Range Members:
oExcel := ComObjCreate("Excel.Application") oExcel.Workbooks.Add pti := GetTypeInfo(oExcel.Range("A1", "A5")) Members := EnumComMembers(pti) oExcel.Quit Gui, Add, ListView, x12 y5 w250 h350, ID|Name|Type Loop Parse, Members, `n RegExMatch(A_LoopField, "(\S*)\t(\S*)\s(.*)", item) , LV_Add("", item1, item2, item3) LV_ModifyCol() Gui, Show, , Excel Range Members return GuiClose: ExitApp ; http://www.autohotkey.com/forum/topic76198.html&p=472279#472279 EnumComMembers(pti) { ; releases ITypeInfo Interface static InvKind := {1:"[method]", 2:"[get]", 4:"[put]", 8:"[putref]"} { ; Com Methods GetTypeAttr := vTable(pti, 3) ReleaseTypeAttr := vTable(pti, 19) GetRefTypeOfImplType := vTable(pti, 8) GetRefTypeInfo := vTable(pti, 14) GetFuncDesc := vTable(pti, 5) ReleaseFuncDesc := vTable(pti, 20) GetDocumentation := vTable(pti, 12) } { ; get cFuncs (number of functions) DllCall(GetTypeAttr, "ptr",pti, "ptr*",typeAttr) cFuncs := NumGet(typeAttr+0, 40+A_PtrSize, "short") cImplTypes := NumGet(typeAttr+0, 44+A_PtrSize, "short") DllCall(ReleaseTypeAttr, "ptr",pti, "ptr",typeAttr) } if cImplTypes { ; Get Inherited Class (cImplTypes should be true) DllCall(GetRefTypeOfImplType, "ptr",pti, "int",0, "int*",pRefType) DllCall(GetRefTypeInfo, "ptr",pti, "ptr",pRefType, "ptr*", pti2) DllCall(GetDocumentation, "ptr",pti2, "int",-1, "ptr*",Name, "ptr",0, "ptr",0, "ptr",0) ; get Interface Name if StrGet(Name) != "IDispatch" t .= EnumComMembers(pti2) "`n" else, ObjRelease(pti2) } Loop, %cFuncs% { ; get Member IDs DllCall(GetFuncDesc, "ptr",pti, "int",A_Index-1, "ptr*",FuncDesc) ID := NumGet(FuncDesc+0, "short") ; get Member ID n := NumGet(FuncDesc+0, 4+3*A_PtrSize, "int") ; get InvKind ; Args := NumGet(FuncDesc+0, 12+3*A_PtrSize, "short") ; get Num of Args ; Opt := NumGet(FuncDesc+0, 14+3*A_PtrSize, "short") ; get Num of Opt Args DllCall(ReleaseFuncDesc, "ptr",pti, "ptr",FuncDesc) DllCall(GetDocumentation, "ptr",pti, "int",ID, "ptr*",Name, "ptr",0, "ptr",0, "ptr",0) if StrGet(Name, "UTF-16") ; Exclude Members that didn't return a Name t .= ID "`t" StrGet(Name, "UTF-16") " " InvKind[n] "`n" } { ; formatting & cleanup t := SubStr(t,1,-1) Sort, t, ND`n ObjRelease(pti) } return, t } GetTypeInfo(ptr) { if ComObjType(ptr)=9 ptr := ComObjValue(ptr) { ; Check if *ptr* has ITypeInfo Interface GetTypeInfoCount := vtable(ptr, 3) DllCall(GetTypeInfoCount, "ptr",ptr, "ptr*",HasITypeInfo) if Not HasITypeInfo { MsgBox ITypeInfo Interface not supported Exit } } GetTypeInfo := vTable(ptr, 4) if DllCall(GetTypeInfo, "ptr",ptr, "uint",0, "uint",0, "ptr*",pti)=0 return, pti } vTable(ptr, n) { ; see ComObjQuery documentation return NumGet(NumGet(ptr+0), n*A_PtrSize) }
EDIT - updated per finc's post
Is it normal that the name of the member is only one letter?
ID Name ----------------------------- -4 _ [get] 0 _ [method] 0 _ [get] 0 _ [put] 0 _ [method] 6 V [put] 6 V [get] 46 G [method] 110 N [get] 110 N [put] 111 C [method] 112 C [method] 113 C [method] 114 A [method] 117 D [method] 118 C [get] 122 W [get] 123 H [get] 126 T [get] 127 L [get] 129 I [get] 134 O [put] 134 O [get] 136 H [put] 136 H [get] 137 V [put] 137 V [get] 138 T [get] 146 F [get] 148 A [get] 149 C [get] 150 P [get] 170 I [put] 170 I [get] 193 N [get] 193 N [put] 197 R [get] 201 I [get] 201 I [put] 208 M [get] 208 M [put] 209 S [put] 209 S [get] 213 C [method] 226 R [method] 235 S [method] 236 A [get] 237 A [method] 238 C [get] 239 C [method] 240 C [get] 241 C [get] 242 C [put] 242 C [get] 243 C [get] 244 U [method] 245 D [method] 246 E [get] 247 E [get] 248 F [method] 249 F [method] 250 F [method] 251 F [method] 252 I [method] 253 L [method] 254 O [get] 255 P [get] 255 P [put] 256 R [get] 257 R [get] 258 R [get] 259 R [method] 260 S [get] 260 S [put] 261 F [get] 261 F [put] 262 F [put] 262 F [get] 263 F [get] 263 F [put] 264 F [put] 264 F [get] 265 F [put] 265 F [get] 266 H [get] 267 H [get] 268 H [put] 268 H [get] 269 L [get] 269 L [put] 271 O [get] 271 O [put] 272 R [get] 272 R [put] 273 S [get] 274 U [get] 274 U [put] 275 U [put] 275 U [get] 276 W [put] 276 W [get] 279 C [method] 281 P [method] 304 A [method] 348 W [get] 398 F [method] 399 F [method] 400 F [method] 410 S [method] 435 B [get] 437 A [get] 441 A [method] 448 A [method] 449 A [method] 457 C [method] 458 C [method] 464 D [method] 472 G [method] 477 P [method] 481 S [method] 482 C [method] 495 J [method] 496 S [method] 497 T [method] 500 E [get] 501 C [get] 502 N [get] 503 P [get] 504 P [get] 505 C [method] 510 C [method] 511 R [method] 543 D [get] 544 P [get] 545 D [get] 546 D [get] 551 C [method] 564 M [method] 565 C [method] 568 A [get] 571 F [method] 585 S [get] 585 S [put] 586 F [get] 586 F [put] 603 C [get] 691 L [get] 716 P [get] 731 P [get] 740 P [get] 793 A [method] 876 A [method] 877 S [method] 878 S [method] 879 S [method] 880 S [method] 881 S [method] 882 S [method] 883 R [method] 905 _ [method] 910 C [get] 916 S [get] 975 R [get] 975 R [put] 1027 _ [method] 1032 N [method] 1036 A [method] 1037 C [method] 1040 T [method] 1063 A [put] 1063 A [get] 1067 B [method] 1097 N [put] 1097 N [get] 1127 N [method] 1131 E [method] 1152 C [method] 1185 A [method] 1187 L [get] 1380 F [put] 1380 F [get] 1381 I [method] 1384 U [method] 1385 M [get] 1386 Q [get] 1387 V [get] 1388 V [get] 1388 V [put] 1389 A [method] 1390 C [method] 1391 P [get] 1392 F [get] 1393 H [get] 1772 _ [method] 1811 P [get] 1812 S [method] 1813 I [put] 1813 I [get] 1928 P [method] 2013 P [get] 2014 D [method] 2015 E [get] 2016 S [get] 2017 S [method] 2020 A [get] 2123 M [get] 2257 L [get] 2258 X [get] 2361 P [method] 2364 C [method] 2491 S [get] 2492 R [method] 2493 E [method] 2499 C [get]
ID Name ----------------------------- -4 _NewEnum [get] 0 _Default [get] 0 _Default [put] 0 _Default [method] 0 _Default [method] 6 Value [get] 6 Value [put] 46 Group [method] 110 Name [get] 110 Name [put] 111 Clear [method] 112 ClearFormats [method] 113 ClearContents [method] 114 AutoFormat [method] 117 Delete [method] ...Thank you again for all the input jethrow.
if StrGet(Name[color=red], "UTF-16"[/color]) ; Exclude Members that didn't return a Name t .= ID "`t" StrGet(Name[color=red], "UTF-16"[/color]) " " InvKind[n] "`n"