Read DirectUIHWND class window and select item.[solved]

For everything that's not in any way related to PureBasic. General chat etc...
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: pay task

Post by luis »

alfa wrote:luiiiiiiiiiiiiiiiiiiiiiiiiiis!!! Say something!
Hi.

Uhm... the vt is already initialized with the right values

Code: Select all

vt\vt = #VT_I4 
vt\lVal = #CHILDID_SELF 
At least according to the docs. The flags looks correct. The only thing I thought is the explorer window has not the focus and this *COULD* be a problem when using automation (especially tricky when using the program in debug mode, writing to the debug window). I changed the prog accordingly but it still doesn't work.

I'm not even sure which UI items are supposed to implement this select method, but I imagine the pull down menus should, so I tried with the "File" menu.

"All objects that support selection or receive the keyboard focus must support this method."

It return a strange error code (negative) I didn't find on MSDN.

FYI this is the code I tried:

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

;http://msdn.microsoft.com/en-us/library/windows/desktop/dd318474(v=vs.85).aspx
#SELFLAG_TAKEFOCUS = 1
#SELFLAG_TAKESELECTION = 2
     
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, err
 Protected *enum.IEnumVARIANT
 
 vt\vt = #VT_I4
 vt\lVal = #CHILDID_SELF
 
 If *aAccessible
    ;;; allocation not needed, see post below by Josh
    ;;; BSTR_wsText = SysAllocString_("")
   
    If *aAccessible\get_accName(vt, @BSTR_wsText) = #S_OK
        Debug aOffset$ + "Name: " + GetBSTR(BSTR_wsText)
       
        If GetBSTR(BSTR_wsText) = "File"
          err = *aAccessible\accSelect(#SELFLAG_TAKEFOCUS | #SELFLAG_TAKESELECTION, vt)       
          Debug err
        EndIf           
        
        SysFreeString_(BSTR_wsText) 
    Else
        Debug aOffset$ + "Name: Empty"
    EndIf

    If *aAccessible\get_AccValue(vt, @BSTR_wsText) = #S_OK
        Debug aOffset$ + " Value: " + GetBSTR(BSTR_wsText)
        SysFreeString_(BSTR_wsText) 
    EndIf
   
    If *aAccessible\get_AccDescription(vt, @BSTR_wsText) = #S_OK
        Debug aOffset$ + " Description: " + GetBSTR(BSTR_wsText)
        SysFreeString_(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
            ;         
            *enum\Reset() ; for good measure
           
            For i = 0 To count - 1               
                If *enum\Next(1, @Child, 0) = #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
   
   
    
    VariantClear_(vt) 
   
 EndIf
EndProcedure


hwnd = FindWindow_( "CabinetWClass", 0)

If hwnd       
    SetForegroundWindow_(hwnd)
    If AccessibleObjectFromWindow(hwnd, 0, @IID_IAccessible, @*Accessible) = #S_OK     
        DisplayInfo(*Accessible, "")
    EndIf
EndIf
I didn't even find some real, working example code using this select method on the net.

So, I don't know.

EDIT: removed BSTR allocation
Last edited by luis on Mon Oct 08, 2012 1:50 pm, edited 1 time in total.
"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 »

Code: Select all

       If GetBSTR(BSTR_wsText) = "File"
          err = *aAccessible\accSelect(#SELFLAG_TAKEFOCUS, vt)        
          Debug err
          err = *aAccessible\accDoDefaultAction(vt)        
          Debug err
          End
        EndIf 
the VT is correct, in fact the accSelect fails but accDoDefaultAction opens the "File" menu.

See http://msdn.microsoft.com/en-us/library ... 85%29.aspx
The accSelect method with SELFLAG_TAKEFOCUS does not cause a menu item to open or close a pop-up menu. Clients use the accDoDefaultAction method to open or close a pop-up menu.
Anyway I stop here, I really had enough of this mess (it's really a garbled mess).

BTW: the SetForegroundWindow_() hunch I had was right, without it the menu selection doesn't work :wink:
"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 »

In Windows 7 i think can be selected harddisk drive C for example.

And about errors:

Code: Select all

        If GetBSTR(BSTR_wsText) = "File"
          ErrorCode = *aAccessible\accSelect(#SELFLAG_TAKEFOCUS | #SELFLAG_TAKESELECTION, vt)        
          Debug ErrorCode
          ErrorBuffer$ = Space(255)
          FormatMessage_(#FORMAT_MESSAGE_FROM_SYSTEM, 0, ErrorCode, 0, @ErrorBuffer$, Len(ErrorBuffer$), 0)
          MessageRequester("Warning", ErrorBuffer$, #PB_MessageRequester_Ok)
        EndIf 
It will show description of error, not the number.
BTW: the SetForegroundWindow_() hunch I had was right, without it the menu selection doesn't work
So you made it? First must to setup window on top, and after that do selection?
Last edited by alfa on Mon Sep 17, 2012 5:15 pm, edited 1 time in total.
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: pay task

Post by luis »

alfa wrote: It will show description of error, not the number.
Right, good idea, it was a "Member not found" (whatever that means).
It wasn't listed in the msdn doc about the possible return codes. As I said it's a mess this thing.
alfa wrote: So you made it? First must to setup window on top, and after that do selection?
I was able to select the menu and open it. I stopped there.
"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 »

Thanks a lot :) This is the last function for my program. A few month we search how to made it.




Dear moderator - can you rename topic to:
Read DirectUIHWND class window and select item.[solved]
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: pay task

Post by luis »

If I'm not mistaken you should be able to rename it by yourself.
Just edit your first post and change the subject.
"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: Read DirectUIHWND class window and select item.[solved]

Post by alfa »

Oh! I see :) So i done it :)
User avatar
Josh
Addict
Addict
Posts: 1183
Joined: Sat Feb 13, 2010 3:45 pm

Re: Read DirectUIHWND class window and select item.[solved]

Post by Josh »

I think the following line can be canceled. This B-String does nothing and maybe makes a memory leak.

Code: Select all

BSTR_wsText = SysAllocString_("")
*aAccessible\get_.... makes it's own B-String and imho you have to free.
sorry for my bad english
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Read DirectUIHWND class window and select item.[solved]

Post by luis »

Yes you are right, the address is overwritten by the address of the BSTR string allocated by the method.

The doc isn't clear though:
pszName [out, retval]
Type: BSTR*

Address of a BSTR that receives a string that contains the specified object's name.
"Address of a BSTR" seem to mean to me you have to pass the address of a BSTR. Not that the BSTR will be internally allocated and stored in the empty pointer. Could have been written in a better way: "Address to a BSTR pointer that will receive the address of the internally allocated BSTR string".

I'll edit the post to remove the allocation, thanks.

BTW: Why this thread was moved from coding questions to off-topic ? Not that I care, it just seem random.
"Have you tried turning it off and on again ?"
A little PureBasic review
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Re: Read DirectUIHWND class window and select item.[solved]

Post by rsts »

luis wrote: BTW: Why this thread was moved from coding questions to off-topic ? Not that I care, it just seem random.
I agree. It belongs in Coding Questions.
User avatar
Josh
Addict
Addict
Posts: 1183
Joined: Sat Feb 13, 2010 3:45 pm

Re: Read DirectUIHWND class window and select item.[solved]

Post by Josh »

@luis

if you don't know the length of the string, you are not able to predefine the b-string. the b-string is a null terminated string. previous to the string, the length of the string is stored in a word variable (try also with unicode):

Code: Select all

bstr = SysAllocString_ ("Test")
Debug PeekW (bstr-4)
So it is clear, the b-string can only be set by the api. What is not clear, do you have to free the b-string? In the most times, this is written in MSDN, but i didn't see anything. I'm not sure. I tried the following code:

Code: Select all

*aAccessible\get_accName(vt, @BSTR_wsText)
Debug @BSTR_wsText
*aAccessible\get_accName(vt, @BSTR_wsText)
Debug @BSTR_wsText
I got two times the same pointer. so i would say, this b-string is not specially made for my request. In this case, i wouldn't have to free the b-string. What now :?: :?: :?:
sorry for my bad english
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Read DirectUIHWND class window and select item.[solved]

Post by luis »

@josh, both good points.

About the BSTR, yes I know it's "made" that way, when I read the docs I didn't try to think beyond the meaning of the words in the docs. You are right, reallocating it to the right size internally in the API would change the address anyway so my assumption it needed to be prepared in advance was illogical (I was also tired as hell of this thing eh eh eh).

About the need to free it or not: your test makes sense. It doesn't seem to be allocated for you, and look as it was already there for some other internal use by the OS. Freeing doesn't seem to cause a problem either.

I also tried to call get_accName, free the BSTR, and call get_accName again.
The address is always the same. SysFreeString on other end does not return a value so who knows if it was successful or not.

Considering what we can see PROBABLY it is wiser to not try to free it. I will not edit the post again and leave the question open :)
"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: Read DirectUIHWND class window and select item.[solved]

Post by luis »

On the other end in this code SysFreeString is called: http://blogs.msdn.com/b/oldnewthing/arc ... 18893.aspx
"Have you tried turning it off and on again ?"
A little PureBasic review
User avatar
Josh
Addict
Addict
Posts: 1183
Joined: Sat Feb 13, 2010 3:45 pm

Re: Read DirectUIHWND class window and select item.[solved]

Post by Josh »

One of my old braincells sayed, there was something about this topic. I found a old statement from freak. This means:

COM objects are always to be freed by the caller, if there is no other statement in the documentation. :D
sorry for my bad english
SeregaZ
Enthusiast
Enthusiast
Posts: 628
Joined: Fri Feb 20, 2009 9:24 am
Location: Almaty (Kazakhstan. not Borat, but Triple G)
Contact:

Re: Read DirectUIHWND class window and select item.[solved]

Post by SeregaZ »

after this time, when we done with alfa our programm, we have more than 3k of downloading. so by your wisdom luis we have so usefull software. so we want to say thanks one more time :)
Post Reply