Read DirectUIHWND class window and select item.[solved]

For everything that's not in any way related to PureBasic. General chat etc...
User avatar
Bisonte
Addict
Addict
Posts: 1305
Joined: Tue Oct 09, 2007 2:15 am

Re: pay task

Post by Bisonte »

A little bit OT, but....
alfa wrote:EnableExplicit - it is possible make this code without this EnableExplicit? I mean main code of program creates without this EnableExplicit. If i will turn on this command - it will need to define whooooole variables (for 4000 strings of code it will many many many variables) If is not, hmm, i do it.
...you can put a - DisableExplicit - after this section, and then you must not redefine all your.... ;)

I mean :

Code: Select all

String.s = "User"
EnableExplicit
Define.s Hello
Hello = "Hello"
String = " alfa"
DisableExplicit

Debug Hello + String
PureBasic 6.21 (Windows x64) | Windows 11 Pro | AsRock B850 Steel Legend Wifi | R7 9800x3D | 64GB RAM | RTX 5080 | ThermaltakeView 270 TG ARGB | build by vannicom​​
English is not my native language... (I often use DeepL.)
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: pay task

Post by luis »

Maybe the problem is here: *enum = *aAccessible

Again there is some kind of cast involved in the delphi code: Enum := aAccessible as IEnumVARIANT;

But since query interface returns ok, this means *eAccessible could be accessed using the IEnumVARIANT interface used for *enum. So I think *enum = *aAccessible should be a valid equivalence (practically that's a cast in PB, one pointer var to another type of pointer var).

But none of this code is never executed on my system (win7) with the main "computer" window open, so I cannot look into this easily. Maybe if you could tell me how you made this code to execute.
"Have you tried turning it off and on again ?"
A little PureBasic review
alfa
User
User
Posts: 18
Joined: Mon Sep 10, 2012 6:50 am

Re: pay task

Post by alfa »

I try to find some analog command in another language. Maybe it will help to you?

(Delphi)
(Sender as TButton) := 'Button0';

(C++ Builder)
((TButton*)(Sender))->Caption = "Button0";
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: pay task

Post by luis »

No, I understand that's a cast, and I think it should work as it is.
But as I said that code is never executed on my PC, so maybe you should try to tell me what your settings were when you got that IMA. Maybe you didn't open the "Computer" main window but something else ?
Or maybe you have different items then mine listed there.
In "Computer" I have fixed local drives, a floppy, a virtual dvdrom and a real one.

Moreover, does the IMA happen at the first iteration ? (i = 0 ) ?
Looking to enum using the tooltip with the debugger active, what is the value associated to Next ? The same value of the address causing the IMA ?

But sorry, if it does not happen here I don't know how to help you beyond this.
"Have you tried turning it off and on again ?"
A little PureBasic review
alfa
User
User
Posts: 18
Joined: Mon Sep 10, 2012 6:50 am

Re: pay task

Post by alfa »

Yes i = 0 - error.
Image


I open My Computer and compile this code. It start show items, and after few enumaration stops and show this IMA. Unicode compiler check, threat safe check. Windows is XP. PB have o Droopy - it can be problem?


I try to start this code on virtual windows 7 - works fine. On my XP is IMA.


And i think something wrong with my "vt" parametr. If *aAccessible\get_accName(vt, @BSTR_wsText) = #S_OK - youre first IMA. When i start code on W7 and that exe file with original delphi - i see difference:
Image


Tooltips:
Image

Image


C++ variant:

Code: Select all

HRESULT WalkTreeWithAccessibleChildren(IAccessible* pAcc, int depth)
{
    HRESULT hr;
    long childCount;
    long returnCount;
 
    if (!pAcc)
    {
        return E_INVALIDARG;
    }
    hr = pAcc->get_accChildCount(&childCount);
    if (FAILED(hr))
    {
        return hr;
    };
    if (childCount == 0)
    {
        return S_FALSE;
    }
    VARIANT* pArray = new VARIANT[childCount];
    hr = AccessibleChildren(pAcc, 0L, childCount, pArray, &returnCount);
    if (FAILED(hr))
    {
        return hr;
    };
 
    // Iterate through children.
    for (int x = 0; x < returnCount; x++)
    {
        VARIANT vtChild = pArray[x];
        // If it's an accessible object, get the IAccessible, and recurse.
        if (vtChild.vt == VT_DISPATCH)
        {
            IDispatch* pDisp = vtChild.pdispVal;
            IAccessible* pChild = NULL;
            hr = pDisp->QueryInterface(IID_IAccessible, (void**) &pChild);
            if (hr == S_OK)
            {
                for (int y = 0; y <depth; y++)
                {
                    printf(" ");
                }
                PrintName(pChild, CHILDID_SELF);
                printf("(Object) ");
                PrintRole(pChild, CHILDID_SELF);
                WalkTreeWithAccessibleChildren(pChild, depth + 1);
                pChild->Release();
            }
            pDisp->Release();
        }
        // Else it's a child element so we have to call accNavigate on the parent,
        //   and we don't recurse since child elements can't have children.
        else
        {
            for (int y = 0; y <depth; y++)
            {
                printf(" ");
            }
            PrintName(pAcc, vtChild.lVal);
            printf("(Child element) ");
            PrintRole(pAcc, vtChild.lVal);
        }
    }
    delete[] pArray;
    return S_OK;
}
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: pay task

Post by luis »

I found this: http://hallvards.blogspot.it/2005/01/in ... casts.html

So the direct copy of the two pointers should qualify as a hard-cast (PB-code) while in the original we have a AS cast who probably do some conversion under the hood (DELPHI).

Since enum is a IEnumVARIANT this make me also suspect maybe it should be a way to call the _NewEnum method to retrieve a enumerable object from aAccessible, but iAccessible doesn't seem to expose that method.

To me this code:

Code: Select all

  end else if aAccessible.QueryInterface(IEnumVARIANT, Enum) = S_OK then begin
              Enum := aAccessible as IEnumVARIANT;
              for i := 0 to iChildCount - 1 do
                if Enum.Next(1, Child, dwNum) = S_OK then
doesn't make much sense anyway. If it does query for a specific interface (IEnumVARIANT) inside the object aAccessible exposing the iAccessible interface, then why doesn't use the Enum directly if the call returned S_OK ? I don't understand why is overwriting the interface just retrieved with the address of the original object.

But if this does actually work under XP (?) maybe I simply don't understand the delphi code.

Sorry, I don't have further ideas, especially since I'm not quite sure what this code should accomplish in end (I have just blindly converted it). Would be useful to have a delphi compiler and look at the original code with a debugger to understand the missing pieces (the snippet above).
"Have you tried turning it off and on again ?"
A little PureBasic review
alfa
User
User
Posts: 18
Joined: Mon Sep 10, 2012 6:50 am

Re: pay task

Post by alfa »

I found why on windows 7 this code is work. This part of code even not used! :)

Try to change:

Code: Select all

        If AccessibleChildren(*aAccessible, 0, count, @ChildArray(0), @iObtained) = #S_OK    
            For i = 0 To iObtained - 1
                ProcessChild(*aAccessible, aOffset$, ChildArray(i))         
            Next
        ElseIf *aAccessible\QueryInterface(@IID_IEnumVARIANT, @*enum) = #S_OK  
          *enum = *aAccessible 
            For i = 0 To count - 1                
                If *enum\Next(1, @Child, @dwnum) = #S_OK
                    ProcessChild(*aAccessible, aOffset$, @Child)
                ElseIf *aAccessible\accNavigate(#NAVDIR_FIRSTCHILD, vt, @CurrentChild) = #S_OK 
                    Repeat
                        ProcessChild(*aAccessible, aOffset$, @CurrentChild)
                    Until *aAccessible\accNavigate(#NAVDIR_NEXT, @CurrentChild, @CurrentChild) <> #S_OK
                EndIf   
            Next 
        EndIf
to

Code: Select all

        If *aAccessible\QueryInterface(@IID_IEnumVARIANT, @*enum) = #S_OK  
          *enum = *aAccessible 
          Debug *enum
          Debug *aAccessible
            For i = 0 To count - 1                
                If *enum\Next(1, @Child, @dwnum) = #S_OK
                    ProcessChild(*aAccessible, aOffset$, @Child)
                ElseIf *aAccessible\accNavigate(#NAVDIR_FIRSTCHILD, vt, @CurrentChild) = #S_OK 
                    Repeat
                        ProcessChild(*aAccessible, aOffset$, @CurrentChild)
                    Until *aAccessible\accNavigate(#NAVDIR_NEXT, @CurrentChild, @CurrentChild) <> #S_OK
                EndIf   
            Next 
        EndIf
Without AccessibleChildren
alfa
User
User
Posts: 18
Joined: Mon Sep 10, 2012 6:50 am

Re: pay task

Post by alfa »

And one more: i think If-Else a little wrong.
Your code two If's:

Code: Select all

        If AccessibleChildren(*aAccessible, 0, count, @ChildArray(0), @iObtained) = #S_OK    
            For i = 0 To iObtained - 1
                ProcessChild(*aAccessible, aOffset$, ChildArray(i))         
            Next
        ElseIf *aAccessible\QueryInterface(@IID_IEnumVARIANT, @*enum) = #S_OK  
            *enum = *aAccessible        
            For i = 0 To count - 1                
                If *enum\Next(1, @Child, @dwnum) = #S_OK
                    ProcessChild(*aAccessible, aOffset$, @Child)
                ElseIf *aAccessible\accNavigate(#NAVDIR_FIRSTCHILD, vt, @CurrentChild) = #S_OK 
                    Repeat
                        ProcessChild(*aAccessible, aOffset$, @CurrentChild)
                    Until *aAccessible\accNavigate(#NAVDIR_NEXT, @CurrentChild, @CurrentChild) <> #S_OK
                EndIf   
            Next 
        EndIf 

In delphi i see 3 If's:

Code: Select all

          if AccessibleChildren(Pointer(aAccessible), 0, iChildCount, ChildArray[0], iObtained) = S_OK then begin
              for i := 0 to iObtained - 1 do
                ProcessChild(ChildArray[i])
            end else if aAccessible.QueryInterface(IEnumVARIANT, Enum) = S_OK then begin
              Enum := aAccessible as IEnumVARIANT;
              for i := 0 to iChildCount - 1 do
                if Enum.Next(1, Child, dwNum) = S_OK then
                  ProcessChild(Child);
            end else begin
              if aAccessible.accNavigate(NAVDIR_FIRSTCHILD, CHILDID_SELF, CurrentChild) = S_OK then begin
                  repeat
                    ProcessChild(CurrentChild)
                  until aAccessible.accNavigate(NAVDIR_NEXT, CurrentChild, CurrentChild) <> S_OK;
                end
            end
So it means final variant must be:

Code: Select all

        If AccessibleChildren(*aAccessible, 0, count, @ChildArray(0), @iObtained) = #S_OK    
          ok = 1
          For i = 0 To iObtained - 1
            ProcessChild(*aAccessible, aOffset$, ChildArray(i))         
          Next
        ElseIf *aAccessible\QueryInterface(@IID_IEnumVARIANT, @*enum) = #S_OK  
          *enum = *aAccessible 
          For i = 0 To count - 1                
            If *enum\Next(1, @*aAccessible, @*enum) = #S_OK
              ProcessChild(*aAccessible, aOffset$, @Child)
            EndIf
          Next 
        Else
          If *aAccessible\accNavigate(#NAVDIR_FIRSTCHILD, vt, @CurrentChild) = #S_OK 
            Repeat
              ProcessChild(*aAccessible, aOffset$, @CurrentChild)
            Until *aAccessible\accNavigate(#NAVDIR_NEXT, @CurrentChild, @CurrentChild) <> #S_OK
          EndIf   
            
        EndIf
Anyway IMA...


Or If i missed this second "If" with IMA - code is repeats forever on last third "If"...
*aAccessible\accNavigate(#NAVDIR_NEXT, @CurrentChild, @CurrentChild) <> #S_OK is dont switch to next child.
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: pay task

Post by luis »

Yes, I noticed that branch of code wasn't executed on win7, I wrote it above :wink:

And yes, one of my if/then was wrong, your version is correct, for some reason I mixed up in my head "if then ;" with "if then end."

About the IMA, as I said, I don't understand the meaning of that piece of code (the overwrite of the just retrieved enum). That code works under XP ? If I understood correctly you have that source (the 1st post) and the compiled exe built by someone else is that correct ?
And if it is, the exe works as expected under XP too ?
"Have you tried turning it off and on again ?"
A little PureBasic review
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: pay task

Post by luis »

Try this "variant", no pun intended.

Code: Select all

EnableExplicit

CompilerIf (#PB_Compiler_Unicode = 0)
 CompilerError "Turn on: Create Unicode executable"
CompilerEndIf

Macro DEFINE_GUID(Name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8)
  CompilerIf Defined(Name, #PB_Variable)
  If SizeOf(Name) = SizeOf(GUID)
    Name\Data1    = l
    Name\Data2    = w1
    Name\Data3    = w2
    Name\Data4[0] = b1
    Name\Data4[1] = b2
    Name\Data4[2] = b3
    Name\Data4[3] = b4
    Name\Data4[4] = b5
    Name\Data4[5] = b6
    Name\Data4[6] = b7
    Name\Data4[7] = b8
  EndIf
  CompilerEndIf
EndMacro

Global IID_IAccessible.GUID
DEFINE_GUID(IID_IAccessible, $618736e0, $3c3d, $11cf, $81, $0c, $00, $aa, $00, $38, $9b, $71)

Global IID_IEnumVARIANT.GUID ; 00020404-0000-0000-C000-000000000046 
DEFINE_GUID(IID_IEnumVARIANT, $00020404, $0000, $0000, $c0, $00, $00, $00, $00, $00, $00, $46)
;http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.comtypes.ienumvariant.aspx


Prototype.l ProtoAccessibleObjectFromWindow(hwnd.i,dwObjectID.l, riid, *ppvObject)
Global AccessibleObjectFromWindow.ProtoAccessibleObjectFromWindow

Prototype.l ProtoAccessibleChildren(*paccContainer,iChildStart.l,cChildren.l,*rgvarChildren,*pcObtained)
Global AccessibleChildren.ProtoAccessibleChildren

Define hdll, hwnd
Define *Accessible.IAccessible

CoInitialize_(0)

hdll=OpenLibrary(#PB_Any,"Oleacc.dll")

AccessibleObjectFromWindow = GetFunction(hdll,"AccessibleObjectFromWindow")
AccessibleChildren = GetFunction(hdll,"AccessibleChildren")

#NAVDIR_DOWN = 2
#NAVDIR_FIRSTCHILD = 7
#NAVDIR_LASTCHILD = 8
#NAVDIR_LEFT = 3
#NAVDIR_NEXT = 5
#NAVDIR_PREVIOUS = 6
#NAVDIR_RIGHT = 4
#NAVDIR_UP = 1

#CHILDID_SELF = 0

Declare    ProcessChild (*aAccessible.IAccessible, aOffset$, *aChild.VARIANT)
Declare    DisplayInfo (*aAccessible.IAccessible, aOffset$ )

Procedure ProcessChild (*aAccessible.IAccessible, aOffset$, *aChild.VARIANT)
 Protected *ChildAccessible.IAccessible
 Protected *ChildDispatch.IDispatch
 
 Select *aChild\vt
    Case #VT_INT ; varInteger
        *aAccessible\get_accChild(*aChild, @*ChildDispatch)
    Case #VT_DISPATCH ; varDispatch
        *ChildDispatch = *aChild\pdispVal
 EndSelect
 
 If *ChildDispatch <> #Null And *ChildDispatch\QueryInterface(@IID_IAccessible, @*ChildAccessible) = #S_OK 
     DisplayInfo(*ChildAccessible, aOffset$ + " ")
 EndIf
EndProcedure

Procedure DisplayInfo (*aAccessible.IAccessible, aOffset$ )
 Protected count, iObtained
 Protected BSTR_wsText 
 Protected vt.VARIANT, i
 Protected *enum.IEnumVARIANT
 
 vt\iVal = #CHILDID_SELF 
 
 If *aAccessible
    BSTR_wsText = SysAllocString_("")
   
    If *aAccessible\get_accName(vt, @BSTR_wsText) = #S_OK 
        Debug aOffset$ + "Name: " + PeekS(BSTR_wsText)
    Else
        Debug aOffset$ + "Name: Empty"
    EndIf

    If *aAccessible\get_AccValue(vt, @BSTR_wsText) = #S_OK
        Debug aOffset$ + "Value: " + PeekS(BSTR_wsText)
    EndIf
   
    If *aAccessible\get_AccDescription(vt, @BSTR_wsText) = #S_OK
        Debug aOffset$ + "Description: " + PeekS(BSTR_wsText)
    EndIf
   
    If *aAccessible\get_accChildCount(@count) = #S_OK And count > 0      
        Debug aOffset$ + "Children: " + Str(count)
           
        Dim ChildArray.VARIANT(count) 
        Protected Child.VARIANT, CurrentChild.VARIANT
        Protected dwNum.l
        
        If AccessibleChildren(*aAccessible, 0, count, @ChildArray(0), @iObtained) = #S_OK    
            For i = 0 To iObtained - 1
                ProcessChild(*aAccessible, aOffset$, ChildArray(i))         
            Next
        ElseIf *aAccessible\QueryInterface(@IID_IEnumVARIANT, @*enum) = #S_OK  
            ;*enum = *aAccessible ; let's try to throw this away
            *enum\Reset() ; for good measure
            For i = 0 To count - 1                
                If *enum\Next(1, @Child, @dwnum) = #S_OK
                    ProcessChild(*aAccessible, aOffset$, @Child)
                EndIf
            Next
        Else
            If *aAccessible\accNavigate(#NAVDIR_FIRSTCHILD, vt, @CurrentChild) = #S_OK 
                Repeat
                    ProcessChild(*aAccessible, aOffset$, @CurrentChild)
                Until *aAccessible\accNavigate(#NAVDIR_NEXT, @CurrentChild, @CurrentChild) <> #S_OK
            EndIf                
       EndIf
    EndIf

    SysFreeString_(BSTR_wsText)
    
 EndIf
EndProcedure


hwnd = FindWindow_( "CabinetWClass", 0)

If hwnd       
    If AccessibleObjectFromWindow(hwnd, 0, @IID_IAccessible, @*Accessible) = #S_OK      
        DisplayInfo(*Accessible, "")
    EndIf
EndIf
Does the output make sense under XP ? I don't have the slightest idea of what this thing should do apart from enumerating some weird stuff.
"Have you tried turning it off and on again ?"
A little PureBasic review
alfa
User
User
Posts: 18
Joined: Mon Sep 10, 2012 6:50 am

Re: pay task

Post by alfa »

Yes. I have code and exe file by compiled someone on another forum. On XP and on 7 this exe works fine. And it reads some item, that our code marks like "Empty Name".

Your new code works on XP, but missed some item:
Image

Why some items on W7 not read correctly?

exe file is here: http://seregaz.hotmail.ru/files/WSpy.rar

One more:

Code: Select all

 Select *aChild\vt     
    Case #VT_INT ; varInteger
      *aAccessible\get_accChild(*aChild, @*ChildDispatch)
    Case #VT_DISPATCH ; varDispatch
      *ChildDispatch = *aChild\pdispVal
 EndSelect
*aChild\vt, as i understand (http://msdn.microsoft.com/en-us/library ... s.85).aspx), can be two constant. #VT_DISPATCH - 9 or #VT_I4 - 3. But you have #VT_INT - 22 - i think this part of code not used too. In XP and 7 shows only 9 and 3, without 22 case. It can be problem missed some items? Or wrong read item name? (marks like Empty)
I try to change Case #VT_INT to #VT_I4 but *ChildDispatch is Null.
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: pay task

Post by luis »

Yup, #VT_INT is definitely wrong and must be replace by #VT_I4

I found this: http://delphi.about.com/library/weekly/aa122104a.htm

so now we know the value of the delphi constants and varInteger match with #VT_I4 (even if #VT_INT seemed a better name equivalent, go figure !)

Now that I have the exe this should be a great help, I'll look into it when I have a little time. If you make it work please post it here so I will not waste my time for nothing :)
"Have you tried turning it off and on again ?"
A little PureBasic review
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: pay task

Post by luis »

This seem to work better than the original delphi exe if that's possible (if I'm not dreaming).

Code: Select all

EnableExplicit

CompilerIf (#PB_Compiler_Unicode = 0)
 CompilerError "Turn on: Create Unicode executable"
CompilerEndIf

Macro DEFINE_GUID(Name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8)
  CompilerIf Defined(Name, #PB_Variable)
  If SizeOf(Name) = SizeOf(GUID)
    Name\Data1    = l
    Name\Data2    = w1
    Name\Data3    = w2
    Name\Data4[0] = b1
    Name\Data4[1] = b2
    Name\Data4[2] = b3
    Name\Data4[3] = b4
    Name\Data4[4] = b5
    Name\Data4[5] = b6
    Name\Data4[6] = b7
    Name\Data4[7] = b8
  EndIf
  CompilerEndIf
EndMacro

Global IID_IAccessible.GUID
DEFINE_GUID(IID_IAccessible, $618736e0, $3c3d, $11cf, $81, $0c, $00, $aa, $00, $38, $9b, $71)

Global IID_IEnumVARIANT.GUID ; 00020404-0000-0000-C000-000000000046
DEFINE_GUID(IID_IEnumVARIANT, $00020404, $0000, $0000, $c0, $00, $00, $00, $00, $00, $00, $46)
;http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.comtypes.ienumvariant.aspx


Prototype.l ProtoAccessibleObjectFromWindow(hwnd.i,dwObjectID.l, riid, *ppvObject)
Global AccessibleObjectFromWindow.ProtoAccessibleObjectFromWindow

Prototype.l ProtoAccessibleChildren(*paccContainer,iChildStart.l,cChildren.l,*rgvarChildren,*pcObtained)
Global AccessibleChildren.ProtoAccessibleChildren

Define hdll, hwnd
Define *Accessible.IAccessible

CoInitialize_(0)

hdll=OpenLibrary(#PB_Any,"Oleacc.dll")

AccessibleObjectFromWindow = GetFunction(hdll,"AccessibleObjectFromWindow")
AccessibleChildren = GetFunction(hdll,"AccessibleChildren")

#NAVDIR_DOWN = 2
#NAVDIR_FIRSTCHILD = 7
#NAVDIR_LASTCHILD = 8
#NAVDIR_LEFT = 3
#NAVDIR_NEXT = 5
#NAVDIR_PREVIOUS = 6
#NAVDIR_RIGHT = 4
#NAVDIR_UP = 1

#CHILDID_SELF = 0

Declare    ProcessChild (*aAccessible.IAccessible, aOffset$, *aChild.VARIANT)
Declare    DisplayInfo (*aAccessible.IAccessible, aOffset$ )

Procedure.s GetBSTR (*BSTR_wsText) ; needed to trap NULL BSTR (seem it's possible and valid)
  If *BSTR_wsText 
    ProcedureReturn PeekS(*BSTR_wsText)
  EndIf
  ProcedureReturn ""
EndProcedure

Procedure ProcessChild (*aAccessible.IAccessible, aOffset$, *aChild.VARIANT)
 Protected *ChildAccessible.IAccessible
 Protected *ChildDispatch.IDispatch
 
 Select *aChild\vt
    Case #VT_I4 ; varInteger (was #VT_INT, wrong, see http://delphi.about.com/library/weekly/aa122104a.htm)
        *aAccessible\get_accChild(*aChild, @*ChildDispatch)
    Case #VT_DISPATCH ; varDispatch
        *ChildDispatch = *aChild\pdispVal
 EndSelect
 
 If *ChildDispatch <> #Null And *ChildDispatch\QueryInterface(@IID_IAccessible, @*ChildAccessible) = #S_OK
     DisplayInfo(*ChildAccessible, aOffset$ + " ")
 EndIf
EndProcedure

Procedure DisplayInfo (*aAccessible.IAccessible, aOffset$ )
 Protected count, iObtained
 Protected BSTR_wsText
 Protected vt.VARIANT, i
 Protected *enum.IEnumVARIANT
 
 vt\vt = #VT_I4 ; needed here too
 vt\lVal = #CHILDID_SELF ; lVal (was iVal, wrong)
 
 If *aAccessible
    BSTR_wsText = SysAllocString_("")
   
    If *aAccessible\get_accName(vt, @BSTR_wsText) = #S_OK
        Debug aOffset$ + "Name: " + GetBSTR(BSTR_wsText) 
    Else
        Debug aOffset$ + "Name: Empty"
    EndIf

    If *aAccessible\get_AccValue(vt, @BSTR_wsText) = #S_OK
        Debug aOffset$ + " Value: " + GetBSTR(BSTR_wsText) 
    EndIf
   
    If *aAccessible\get_AccDescription(vt, @BSTR_wsText) = #S_OK
        Debug aOffset$ + " Description: " + GetBSTR(BSTR_wsText) 
    EndIf
   
    If *aAccessible\get_accChildCount(@count) = #S_OK And count > 0     
        aOffset$ + " " ; fix indenting
        Debug aOffset$ + "Children: " + Str(count)
           
        Dim ChildArray.VARIANT(count)
        Protected Child.VARIANT, CurrentChild.VARIANT
        Protected dwNum.l
       
        If AccessibleChildren(*aAccessible, 0, count, @ChildArray(0), @iObtained) = #S_OK   
            For i = 0 To iObtained - 1
                ProcessChild(*aAccessible, aOffset$, ChildArray(i))         
            Next
        ElseIf *aAccessible\QueryInterface(@IID_IEnumVARIANT, @*enum) = #S_OK 
            ;
            ;*enum = *aAccessible ; this look definitely wrong, don't know how this did work in delphi
            ;
            
            ;now we use the returned *enum as was logical
            
            *enum\Reset() ; for good measure 
            
            For i = 0 To count - 1               
                If *enum\Next(1, @Child, @dwnum) = #S_OK
                    ProcessChild(*aAccessible, aOffset$, @Child)
                EndIf
            Next
        Else
            If *aAccessible\accNavigate(#NAVDIR_FIRSTCHILD, vt, @CurrentChild) = #S_OK
                Repeat
                    ProcessChild(*aAccessible, aOffset$, @CurrentChild)
                Until *aAccessible\accNavigate(#NAVDIR_NEXT, @CurrentChild, @CurrentChild) <> #S_OK
            EndIf               
       EndIf
    EndIf

    SysFreeString_(BSTR_wsText)
   
 EndIf
EndProcedure


hwnd = FindWindow_( "CabinetWClass", 0)

If hwnd       
    If AccessibleObjectFromWindow(hwnd, 0, @IID_IAccessible, @*Accessible) = #S_OK     
        DisplayInfo(*Accessible, "")
    EndIf
EndIf

The delphi exe give this result on my virtualized XP

Code: Select all

Name: My Computer
 Children: 7
   Name: System
     Description: Contains commands to manipulate the window
    Children: 1
      Name: System
       Children: 1
         Name: System
          Children: 7
   Name: Empty
     Value: My Computer
     Description: Displays the name of the window and contains controls to manipulate it
    Children: 5
   Name: Application
    Children: 6
      Name: Edit
        Description: Edit
       Children: 1
      Name: View
        Description: View
       Children: 1
      Name: Favorites
        Description: Favorites
       Children: 1
         Name: 
          Children: 5
            Name: Organize Favorites...
              Description: Organize Favorites...
            Name: Separator
              Description: Separator
            Name: Favorites Bar
              Description: Favorites Bar
             Children: 1
            Name: Microsoft Websites
              Description: Microsoft Websites
             Children: 1
      Name: Tools
        Description: Tools
       Children: 1
      Name: Help
        Description: Help
       Children: 1

... continue

My last code give this:

Code: Select all

Name: My Computer
 Children: 7
  Name: System
   Description: Contains commands to manipulate the window
   Children: 1
    Name: System
     Children: 1
      Name: System
       Children: 7
  Name: Empty
   Value: My Computer
   Description: Displays the name of the window and contains controls to manipulate it
   Children: 5
  Name: Application
   Children: 6
    Name: File
     Description: File
     Children: 1
    Name: Edit
     Description: Edit
     Children: 1
    Name: View
     Description: View
     Children: 1
    Name: Favorites
     Description: Favorites
     Children: 1
      Name: 
       Children: 5
        Name: Add to Favorites...
         Description: Add to Favorites...
        Name: Organize Favorites...
         Description: Organize Favorites...
        Name: Separator
         Description: Separator
        Name: Favorites Bar
         Description: Favorites Bar
         Children: 1
        Name: Microsoft Websites
         Description: Microsoft Websites
         Children: 1
    Name: Tools
     Description: Tools
     Children: 1
    Name: Help
     Description: Help
     Children: 1

... continue

In the original there is a "File" missing

Code: Select all

    Name: File
     Description: File
     Children: 1
In "My Computer" I have in the menu: File, Edit, View, Favorites, Tools, Help

The delphi exe seem to miss the first one: "File", the latest PB code get this one too.

Does it happen on your system too ?

И зачем нужен @dwnum, если он нигде не используется?
Because the Next() method needs it. It can works with arrays so the first param is the num of childs you want retrieve, the second is the base address of the array and the last (dwnum) will contain the actual number of children retrieved. The docs says for that param:
The number of elements returned in rgVar, or NULL.
So the sentence is poorly written IMHO and it's not clear if it will be set to null if there are no children returned OR if it can be replaced by null if you are not interested in its value. Replacing @dwnum with 0 seems to work anyway, but I'm not sure it is worth the risk.
"Have you tried turning it off and on again ?"
A little PureBasic review
alfa
User
User
Posts: 18
Joined: Mon Sep 10, 2012 6:50 am

Re: pay task

Post by alfa »

Unbelievable! I am a sleep and i see a dream! Work, even better than original!

Last one ask - how to make select function? I mean:

Code: Select all

 #SELFLAG_TAKESELECTION = 2
 #SELFLAG_TAKEFOCUS = 1
 ;http://msdn.microsoft.com/en-us/library/windows/desktop/dd318474(v=vs.85).aspx

   If *aAccessible\get_accName(vt, @BSTR_wsText) = #S_OK
      Debug aOffset$ + "Name: " + GetBSTR(BSTR_wsText)
      If GetBSTR(BSTR_wsText) = "someitem"
        *aAccessible\accSelect(#SELFLAG_TAKESELECTION | #SELFLAG_TAKEFOCUS, vt)
        ;stop = 1
      EndIf
      
    Else
alfa
User
User
Posts: 18
Joined: Mon Sep 10, 2012 6:50 am

Re: pay task

Post by alfa »

luiiiiiiiiiiiiiiiiiiiiiiiiiis!!! Say something! I dont know what i must to put in replace 'vt' in this command. It dont want to make select.
Post Reply