Loading ...
Sorry, an error occurred while loading the content.
 

Re: Getting the Popup menu handle. It may work but it's hedious

Expand Messages
  • Piotr Kaluski
    Hi, Some time ago I was trying to find a solution for the same problem. I was thinking on the way to handle IE menu bar and its submenus. This problem is
    Message 1 of 7 , Sep 8, 2005
      Hi,
      Some time ago I was trying to find a solution for the same problem. I
      was thinking on the way to handle IE menu bar and its submenus.
      This problem is related to what you write about, since IE menu is a
      toolbar with popup menus.
      And yes, you are right about the main problem - how to get a menu
      handle. Win32 API provides many fancy functions for managing menus
      but most of them expect menu handle as a parameter. I have found one
      promising function - GetMenuBarInfo. However I could not make the
      function work. I was getting really strange error messages
      (including "Function was successful", with an indication that there
      is an error). I tried to post the question to win32 programming
      newsgroup, but did not get any help. It would be good to have some
      real windows guru to have a look at it.
      -Piotr

      --- In perlguitest@yahoogroups.com, "rafelafrance"
      <rafelafrance@y...> wrote:
      > *Ugh* The current method (I'll space you the XS code): THERE HAS TO
      > BE A BETTER WAY!
      >
      > 1) Call up the context menu using MouseClick() or SendKeys()
      > 2) Set up an event trap to look for the WM_MENUSELECT event
      > 3) SendKeys('{DOWN}'); #Which will post the WM_MENUSELECT
      > 4) In the callback HookProc() get the popup handle from lParam.
      > 5) Call another routine to retrive the popup handle GetPopupHandle()
      >
      > This should sound like nails on a chalkboard by about now. The
      > problems are legion and here are just a few.
      >
      > - If you never call GetPopupHandle() the hook isn't released. BAD!
      > Sure I test & release it if I can but there's no guarantee.
      > - You have to dirty the menu by pressing {DOWN} to get its handle
      >
      > ==================================
      > I've tried to get the popup handle all in one fell swoop by doing
      the
      > SendKeys() etc in the C code but that wasn't working. Tho it seems
      > like the way to go. Maybe...
      >
      > I'm looking for other events to trap that don't dirty the menu but
      I
      > haven't found any that would be generally useful. Any suggestions?
      >
      > Maybe I can set up an XS object so that the trap will be set up
      once
      > during New(). Have all popups post to this object and release the
      > hook during the DESTROY method. A lot of work for little reward.
      > =====================================
      >
      > Any ideas please.
    • rafelafrance
      Thank you for your reply. After sleeping on it I realized that I can... 1) Set up a trap to WM_INITMENUPOPUP 2) Call a mouse right click (the hot key should
      Message 2 of 7 , Sep 9, 2005
        Thank you for your reply.

        After sleeping on it I realized that I can...

        1) Set up a trap to WM_INITMENUPOPUP
        2) Call a mouse right click (the hot key should work too) from the C
        XS code. That will put the handle into wparam
        3) I may need to sleep my process a bit (I haven't yet but I may?)
        4) Pick the handle returned from the callback
        5) Double check to make sure that the hook is released
        6) return the popup handle back up to perl

        ** It's working but i haven't been using it long

        Pros:
        1) It's done all in one call
        2) It doesn't dirty the menu

        Cons:
        1) I'm not 100% on how long i'll have to wait for a popup after the R-
        click. Maybe I should have use a timer as an optional argument? Right
        now the interface is GetPopupHandle($hwnd, $x, $y)
        2) Right now the $hwnd is the dialog's & not the control's handle.
        It's working but it does seem off.

        I can post code if anyone wants. More suggestions are welcome.

        Thanks again.

        --- In perlguitest@yahoogroups.com, "Piotr Kaluski" <pkaluski@p...>
        wrote:
        > Hi,
        > Some time ago I was trying to find a solution for the same problem.
        I
        > was thinking on the way to handle IE menu bar and its submenus.
        > This problem is related to what you write about, since IE menu is a
        > toolbar with popup menus.
        > And yes, you are right about the main problem - how to get a menu
        > handle. Win32 API provides many fancy functions for managing menus
        > but most of them expect menu handle as a parameter. I have found
        one
        > promising function - GetMenuBarInfo. However I could not make the
        > function work. I was getting really strange error messages
        > (including "Function was successful", with an indication that there
        > is an error). I tried to post the question to win32 programming
        > newsgroup, but did not get any help. It would be good to have some
        > real windows guru to have a look at it.
        > -Piotr
        >
        > --- In perlguitest@yahoogroups.com, "rafelafrance"
        > <rafelafrance@y...> wrote:
        > > *Ugh* The current method (I'll space you the XS code): THERE HAS
        TO
        > > BE A BETTER WAY!
        > >
        > > 1) Call up the context menu using MouseClick() or SendKeys()
        > > 2) Set up an event trap to look for the WM_MENUSELECT event
        > > 3) SendKeys('{DOWN}'); #Which will post the WM_MENUSELECT
        > > 4) In the callback HookProc() get the popup handle from lParam.
        > > 5) Call another routine to retrive the popup handle GetPopupHandle
        ()
        > >
        > > This should sound like nails on a chalkboard by about now. The
        > > problems are legion and here are just a few.
        > >
        > > - If you never call GetPopupHandle() the hook isn't released. BAD!
        > > Sure I test & release it if I can but there's no guarantee.
        > > - You have to dirty the menu by pressing {DOWN} to get its handle
        > >
        > > ==================================
        > > I've tried to get the popup handle all in one fell swoop by doing
        > the
        > > SendKeys() etc in the C code but that wasn't working. Tho it
        seems
        > > like the way to go. Maybe...
        > >
        > > I'm looking for other events to trap that don't dirty the menu
        but
        > I
        > > haven't found any that would be generally useful. Any suggestions?
        > >
        > > Maybe I can set up an XS object so that the trap will be set up
        > once
        > > during New(). Have all popups post to this object and release the
        > > hook during the DESTROY method. A lot of work for little reward.
        > > =====================================
        > >
        > > Any ideas please.
      • Piotr Kaluski
        ... R- ... Right ... Timing is a recurring problem in GUI testing. I would just add a 4th optional parameter (as you suggest). If later on someone finds a
        Message 3 of 7 , Sep 9, 2005
          >
          > Cons:
          > 1) I'm not 100% on how long i'll have to wait for a popup after the
          R-
          > click. Maybe I should have use a timer as an optional argument?
          Right
          > now the interface is GetPopupHandle($hwnd, $x, $y)

          Timing is a recurring problem in GUI testing. I would just add a 4th
          optional parameter (as you suggest). If later on someone finds a
          cleaner solution, we will not use this timeout paramater any more.


          > 2) Right now the $hwnd is the dialog's & not the control's handle.
          > It's working but it does seem off.

          I don't get your point here. What do you mean by "control's handle" -
          control ID? What is exactly the problem you describe in point 2?


          > I can post code if anyone wants. More suggestions are welcome.

          Sure, go ahead - I want it very much :-). It would be great if you
          also send a documentation of the function you added, so I can add it
          in the module's documentation.

          --Piotr
        • rafelafrance
          ... the ... Done. ... handle. ... - ... Newbie mistake, sorry. Hwnd can be either the main dialog s or the control s handle in this case. ... Oops... I have
          Message 4 of 7 , Sep 11, 2005
            --- In perlguitest@yahoogroups.com, "Piotr Kaluski" <pkaluski@p...>
            wrote:
            > >
            > > Cons:
            > > 1) I'm not 100% on how long i'll have to wait for a popup after
            the
            > R-
            > > click. Maybe I should have use a timer as an optional argument?
            > Right
            > > now the interface is GetPopupHandle($hwnd, $x, $y)
            >
            > Timing is a recurring problem in GUI testing. I would just add a 4th
            > optional parameter (as you suggest). If later on someone finds a
            > cleaner solution, we will not use this timeout paramater any more.
            >

            Done.

            >
            > > 2) Right now the $hwnd is the dialog's & not the control's
            handle.
            > > It's working but it does seem off.
            >
            > I don't get your point here. What do you mean by "control's handle"
            -
            > control ID? What is exactly the problem you describe in point 2?

            Newbie mistake, sorry. Hwnd can be either the main dialog's or the
            control's handle in this case.

            >
            > > I can post code if anyone wants. More suggestions are welcome.
            >
            > Sure, go ahead - I want it very much :-). It would be great if you
            > also send a documentation of the function you added, so I can add it
            > in the module's documentation.
            >

            Oops... I have made many changes, backing out the other changes for
            this post.

            Submitted for your approval. NB: I had to use the 'mickey' coordinate
            transformation. The comments suggest that this is an XP only thing.

            I hope unix style diffs are OK.

            $ diff -U5 Win32-GuiTest-1.50.3-ad/guitest.xs guitest_popuphandle.xs

            --- Win32-GuiTest-1.50.3-ad/guitest.xs 2005-02-02 19:06:52.000000000
            -0500
            +++ guitest_popuphandle.xs 2005-09-11 22:57:42.000000000 -0400
            @@ -36,10 +36,11 @@

            #pragma data_seg(".shared")
            // Used by hooking/injected routines
            HWND g_hWnd = 0;
            HHOOK g_hHook = NULL;
            +HWND g_popup = 0; //Hold's popup menu's handle
            BOOL g_bRetVal = 0;
            char g_szBuffer[MAX_DATA_BUF+1] = {NUL};
            UINT WM_LV_GETTEXT = 0;
            UINT WM_LV_SELBYINDEX = 0;
            UINT WM_LV_SELBYTEXT = 0;
            @@ -48,10 +49,11 @@
            UINT WM_TC_SELBYINDEX = 0;
            UINT WM_TC_SELBYTEXT = 0;
            UINT WM_TC_ISSEL = 0;
            UINT WM_TV_SELBYPATH = 0;
            UINT WM_TV_GETSELPATH = 0;
            +UINT WM_INITMENUPOPUPX = WM_INITMENUPOPUP; //Only needed to conform
            with SetHook()'s calling convention
            #pragma data_seg()
            #pragma comment(linker, "/SECTION:.shared,RWS")

            BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call,
            LPVOID lpReserved)
            @@ -292,10 +294,13 @@
            if (lstrcmpi(g_szBuffer, szName) == 0) {
            // Yes, selected
            g_bRetVal = TRUE;
            }
            UnhookWindowsHookEx(g_hHook);
            + } else if (pCW->message == WM_INITMENUPOPUP) {
            + g_popup = (HWND) pCW->wParam;
            + UnhookWindowsHookEx(g_hHook);
            }

            return CallNextHookEx(g_hHook, code, wParam, lParam);
            }

            @@ -801,11 +806,26 @@
            safefree(text);
            }
            return sv;
            }

            -
            +/////////////////////////////////////////////////
            ///////////////////////////
            +HWND PopupHandleGet(HWND hWnd, int x, int y, int wait) {
            + g_popup = 0;
            + if (SetHook(hWnd, WM_INITMENUPOPUPX, "WM_INITMENUPOPUP_RM") ==
            NULL)
            + return 0;
            + int mickey_x = MulDiv(x, 0x10000, GetSystemMetrics(SM_CXSCREEN));
            + int mickey_y = MulDiv(y, 0x10000, GetSystemMetrics(SM_CYSCREEN));
            + simple_mouse(MOUSEEVENTF_MOVE|MOUSEEVENTF_ABSOLUTE, mickey_x,
            mickey_y);
            + simple_mouse(MOUSEEVENTF_RIGHTDOWN, 0, 0);
            + simple_mouse(MOUSEEVENTF_RIGHTUP, 0, 0);
            + Sleep(wait);
            + if (g_popup == 0)
            + UnhookWindowsHookEx(g_hHook);
            + return g_popup;
            +}
            +/////////////////////////////////////////////////
            ///////////////////////////

            MODULE = Win32::GuiTest PACKAGE = Win32::GuiTest

            PROTOTYPES: DISABLE

            @@ -1708,10 +1728,22 @@
            pt.y = y;
            RETVAL = WindowFromPoint(pt);
            OUTPUT:
            RETVAL

            +#################################################
            ###########################
            +HWND
            +GetPopupHandle(hWnd, x, y, wait=50)
            + HWND hWnd;
            + int x;
            + int y;
            + int wait;
            +CODE:
            + RETVAL = PopupHandleGet(hWnd, x, y, wait);
            +OUTPUT:
            + RETVAL
            +#################################################
            ###########################

            MODULE = Win32::GuiTest PACKAGE =
            Win32::GuiTest::DibSect

            PROTOTYPES: DISABLE


            **********************************************
            Now the guitest.pm
            **********************************************
            $ diff -U5 Win32-GuiTest-1.50.3-ad/guitest.pm guitest_popuphandle.pm
            --- Win32-GuiTest-1.50.3-ad/guitest.pm 2005-02-02 18:43:15.000000000
            -0500
            +++ guitest_popuphandle.pm 2005-09-11 23:41:21.000000000 -0400
            @@ -121,10 +121,11 @@
            GetSubMenu GetMenuItemIndex GetMenuItemId GetMenuItemCount
            GetMenuItemInfo
            GetListViewContents SelListViewItem SelListViewItemText
            IsListViewItemSel
            GetTabItems SelTabItem SelTabItemText IsTabItemSel
            SelTreeViewItemPath GetTreeViewSelPath MouseMoveWheel
            SelComboItem SelComboItemText
            + GetPopupHandle
            )],
            VARS => [ qw(
            $debug
            )],
            SW => [ qw(
            @@ -1042,10 +1043,18 @@
            SelTreeViewItemPath($window, "Parent|Child");
            SelTreeViewItemPath($window, $oldpath);

            =cut

            +=item $hpopup = GetPopupHandle($hwnd, $x, $y, [$wait])
            +
            + This function gets the handle of a popup window generated by
            + right-clicking at the $x and $y screen coordinates (absolute). An
            + optional delay can be entered which will wait the given number of
            + milliseconds after the right-click for the window to appear
            (default
            + is 50). Zero is returned when no popup menu is found.
            +
            =back

            =head2 DibSect

            A class to manage a Windows DIB section. Currently limited in
            functionality to
          • Piotr Kaluski
            Thank you very much, Please allow some time for reviewing your changes and putting them in the code base (it may take 2 weeks). I have just committed some
            Message 5 of 7 , Sep 11, 2005
              Thank you very much,
              Please allow some time for reviewing your changes and putting them in
              the code base (it may take 2 weeks). I have just committed some
              changes in the code and I am updating documentation. Once it is done
              I will have a look at your changes.

              -Piotr

              --- In perlguitest@yahoogroups.com, "rafelafrance"
              <rafelafrance@y...> wrote:
              > --- In perlguitest@yahoogroups.com, "Piotr Kaluski" <pkaluski@p...>
              > wrote:
              > > >
              > > > Cons:
              > > > 1) I'm not 100% on how long i'll have to wait for a popup after
              > the
              > > R-
              > > > click. Maybe I should have use a timer as an optional argument?
              > > Right
              > > > now the interface is GetPopupHandle($hwnd, $x, $y)
              > >
              > > Timing is a recurring problem in GUI testing. I would just add a
              4th
              > > optional parameter (as you suggest). If later on someone finds a
              > > cleaner solution, we will not use this timeout paramater any more.
              > >
              >
              > Done.
              >
              > >
              > > > 2) Right now the $hwnd is the dialog's & not the control's
              > handle.
              > > > It's working but it does seem off.
              > >
              > > I don't get your point here. What do you mean by "control's
              handle"
              > -
              > > control ID? What is exactly the problem you describe in point 2?
              >
              > Newbie mistake, sorry. Hwnd can be either the main dialog's or the
              > control's handle in this case.
              >
              > >
              > > > I can post code if anyone wants. More suggestions are welcome.
              > >
              > > Sure, go ahead - I want it very much :-). It would be great if you
              > > also send a documentation of the function you added, so I can add
              it
              > > in the module's documentation.
              > >
              >
              > Oops... I have made many changes, backing out the other changes for
              > this post.
              >
              > Submitted for your approval. NB: I had to use the 'mickey'
              coordinate
              > transformation. The comments suggest that this is an XP only thing.
              >
              > I hope unix style diffs are OK.
              >
              > $ diff -U5 Win32-GuiTest-1.50.3-ad/guitest.xs
              guitest_popuphandle.xs
              >
              > --- Win32-GuiTest-1.50.3-ad/guitest.xs 2005-02-02
              19:06:52.000000000
              > -0500
              > +++ guitest_popuphandle.xs 2005-09-11 22:57:42.000000000 -0400
              > @@ -36,10 +36,11 @@
              >
              > #pragma data_seg(".shared")
              > // Used by hooking/injected routines
              > HWND g_hWnd = 0;
              > HHOOK g_hHook = NULL;
              > +HWND g_popup = 0; //Hold's popup menu's handle
              > BOOL g_bRetVal = 0;
              > char g_szBuffer[MAX_DATA_BUF+1] = {NUL};
              > UINT WM_LV_GETTEXT = 0;
              > UINT WM_LV_SELBYINDEX = 0;
              > UINT WM_LV_SELBYTEXT = 0;
              > @@ -48,10 +49,11 @@
              > UINT WM_TC_SELBYINDEX = 0;
              > UINT WM_TC_SELBYTEXT = 0;
              > UINT WM_TC_ISSEL = 0;
              > UINT WM_TV_SELBYPATH = 0;
              > UINT WM_TV_GETSELPATH = 0;
              > +UINT WM_INITMENUPOPUPX = WM_INITMENUPOPUP; //Only needed to
              conform
              > with SetHook()'s calling convention
              > #pragma data_seg()
              > #pragma comment(linker, "/SECTION:.shared,RWS")
              >
              > BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call,
              > LPVOID lpReserved)
              > @@ -292,10 +294,13 @@
              > if (lstrcmpi(g_szBuffer, szName) == 0) {
              > // Yes, selected
              > g_bRetVal = TRUE;
              > }
              > UnhookWindowsHookEx(g_hHook);
              > + } else if (pCW->message == WM_INITMENUPOPUP) {
              > + g_popup = (HWND) pCW->wParam;
              > + UnhookWindowsHookEx(g_hHook);
              > }
              >
              > return CallNextHookEx(g_hHook, code, wParam, lParam);
              > }
              >
              > @@ -801,11 +806,26 @@
              > safefree(text);
              > }
              > return sv;
              > }
              >
              > -
              > +/////////////////////////////////////////////////
              > ///////////////////////////
              > +HWND PopupHandleGet(HWND hWnd, int x, int y, int wait) {
              > + g_popup = 0;
              > + if (SetHook(hWnd, WM_INITMENUPOPUPX, "WM_INITMENUPOPUP_RM") ==
              > NULL)
              > + return 0;
              > + int mickey_x = MulDiv(x, 0x10000, GetSystemMetrics
              (SM_CXSCREEN));
              > + int mickey_y = MulDiv(y, 0x10000, GetSystemMetrics
              (SM_CYSCREEN));
              > + simple_mouse(MOUSEEVENTF_MOVE|MOUSEEVENTF_ABSOLUTE, mickey_x,
              > mickey_y);
              > + simple_mouse(MOUSEEVENTF_RIGHTDOWN, 0, 0);
              > + simple_mouse(MOUSEEVENTF_RIGHTUP, 0, 0);
              > + Sleep(wait);
              > + if (g_popup == 0)
              > + UnhookWindowsHookEx(g_hHook);
              > + return g_popup;
              > +}
              > +/////////////////////////////////////////////////
              > ///////////////////////////
              >
              > MODULE = Win32::GuiTest PACKAGE = Win32::GuiTest
              >
              > PROTOTYPES: DISABLE
              >
              > @@ -1708,10 +1728,22 @@
              > pt.y = y;
              > RETVAL = WindowFromPoint(pt);
              > OUTPUT:
              > RETVAL
              >
              > +#################################################
              > ###########################
              > +HWND
              > +GetPopupHandle(hWnd, x, y, wait=50)
              > + HWND hWnd;
              > + int x;
              > + int y;
              > + int wait;
              > +CODE:
              > + RETVAL = PopupHandleGet(hWnd, x, y, wait);
              > +OUTPUT:
              > + RETVAL
              > +#################################################
              > ###########################
              >
              > MODULE = Win32::GuiTest PACKAGE =
              > Win32::GuiTest::DibSect
              >
              > PROTOTYPES: DISABLE
              >
              >
              > **********************************************
              > Now the guitest.pm
              > **********************************************
              > $ diff -U5 Win32-GuiTest-1.50.3-ad/guitest.pm
              guitest_popuphandle.pm
              > --- Win32-GuiTest-1.50.3-ad/guitest.pm 2005-02-02
              18:43:15.000000000
              > -0500
              > +++ guitest_popuphandle.pm 2005-09-11 23:41:21.000000000 -0400
              > @@ -121,10 +121,11 @@
              > GetSubMenu GetMenuItemIndex GetMenuItemId GetMenuItemCount
              > GetMenuItemInfo
              > GetListViewContents SelListViewItem SelListViewItemText
              > IsListViewItemSel
              > GetTabItems SelTabItem SelTabItemText IsTabItemSel
              > SelTreeViewItemPath GetTreeViewSelPath MouseMoveWheel
              > SelComboItem SelComboItemText
              > + GetPopupHandle
              > )],
              > VARS => [ qw(
              > $debug
              > )],
              > SW => [ qw(
              > @@ -1042,10 +1043,18 @@
              > SelTreeViewItemPath($window, "Parent|Child");
              > SelTreeViewItemPath($window, $oldpath);
              >
              > =cut
              >
              > +=item $hpopup = GetPopupHandle($hwnd, $x, $y, [$wait])
              > +
              > + This function gets the handle of a popup window generated by
              > + right-clicking at the $x and $y screen coordinates (absolute).
              An
              > + optional delay can be entered which will wait the given number
              of
              > + milliseconds after the right-click for the window to appear
              > (default
              > + is 50). Zero is returned when no popup menu is found.
              > +
              > =back
              >
              > =head2 DibSect
              >
              > A class to manage a Windows DIB section. Currently limited in
              > functionality to
            • Piotr Kaluski
              Rafe, Your code changes work for me. Good job. I commited your changes in CVS. Now we have to wait until the next package is released. Dear project
              Message 6 of 7 , Sep 25, 2005
                Rafe,
                Your code changes work for me. Good job.
                I commited your changes in CVS. Now we have to wait until the next
                package is released.
                Dear project administrators,
                Pleeeeeeaaaaaaase :-))
                Once the package is released I will update documentation.

                -Piotr
              Your message has been successfully submitted and would be delivered to recipients shortly.