Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. How can I get handle (IntPtr) to a "sub"-form in another application?

How can I get handle (IntPtr) to a "sub"-form in another application?

Scheduled Pinned Locked Moved C#
questioncsharpwinforms
26 Posts 3 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • A Offline
    A Offline
    arnold_w
    wrote on last edited by
    #1

    I would like to show a WinForms MessageBox centered on top of another application's (TortoiseGit) "sub"-form, i.e. a form (the TortoiseGit checkout form) on top of the main form (the TortoiseGit log window). I am able to successfully find the process (TortoiseGitProc) and from there I can successfully get a MainWindowHandle to the main form, but how do get from there to the "sub"-form (the TortoiseGit checkout form)?

    L A Richard Andrew x64R 3 Replies Last reply
    0
    • A arnold_w

      I would like to show a WinForms MessageBox centered on top of another application's (TortoiseGit) "sub"-form, i.e. a form (the TortoiseGit checkout form) on top of the main form (the TortoiseGit log window). I am able to successfully find the process (TortoiseGitProc) and from there I can successfully get a MainWindowHandle to the main form, but how do get from there to the "sub"-form (the TortoiseGit checkout form)?

      L Offline
      L Offline
      Lost User
      wrote on last edited by
      #2

      EnumChildWindows function (winuser.h) - Win32 apps | Microsoft Docs[^], or enumwindows. Example here; pinvoke.net: enumchildwindows (user32)[^]

      Bastard Programmer from Hell :suss: If you can't read my code, try converting it here[^] "If you just follow the bacon Eddy, wherever it leads you, then you won't have to think about politics." -- Some Bell.

      A 1 Reply Last reply
      0
      • L Lost User

        EnumChildWindows function (winuser.h) - Win32 apps | Microsoft Docs[^], or enumwindows. Example here; pinvoke.net: enumchildwindows (user32)[^]

        Bastard Programmer from Hell :suss: If you can't read my code, try converting it here[^] "If you just follow the bacon Eddy, wherever it leads you, then you won't have to think about politics." -- Some Bell.

        A Offline
        A Offline
        arnold_w
        wrote on last edited by
        #3

        When I use the code from PINVOKE: Getting all child handles of window · Software adventures and thoughts[^] to get all the children, I get 30 pointers. When I then log the Window texts using the following

                List allChildWindows = new WindowHandleInfo(parentMainWindowHandle).GetAllChildHandles();
                for (int i = 0; i < allChildWindows.Count; i++)
                {
                    StringBuilder sb2 = new StringBuilder(1024);
                    GetClassName(allChildWindows\[i\], sb2, sb2.Capacity);
                    sb2 = new StringBuilder(1024);
                    GetWindowText(allChildWindows\[i\], sb2, sb2.Capacity);
                    Debug.WriteLine(sb2.ToString());
                }
        

        then I get mostly empty strings, but I do get some strings that appears to come from the main form's (not the "sub"-form's) components (buttons, labels, etc), e.g. "", "Help", "Refresh", "Walk Be&haviour", "&View", "OK", etc. What am I doing wrong, why do I get pointers to the main form's components and not to the "sub"-form?

        L 1 Reply Last reply
        0
        • A arnold_w

          When I use the code from PINVOKE: Getting all child handles of window · Software adventures and thoughts[^] to get all the children, I get 30 pointers. When I then log the Window texts using the following

                  List allChildWindows = new WindowHandleInfo(parentMainWindowHandle).GetAllChildHandles();
                  for (int i = 0; i < allChildWindows.Count; i++)
                  {
                      StringBuilder sb2 = new StringBuilder(1024);
                      GetClassName(allChildWindows\[i\], sb2, sb2.Capacity);
                      sb2 = new StringBuilder(1024);
                      GetWindowText(allChildWindows\[i\], sb2, sb2.Capacity);
                      Debug.WriteLine(sb2.ToString());
                  }
          

          then I get mostly empty strings, but I do get some strings that appears to come from the main form's (not the "sub"-form's) components (buttons, labels, etc), e.g. "", "Help", "Refresh", "Walk Be&haviour", "&View", "OK", etc. What am I doing wrong, why do I get pointers to the main form's components and not to the "sub"-form?

          L Offline
          L Offline
          Lost User
          wrote on last edited by
          #4

          See the parameter descriptions at EnumChildWindows function (winuser.h) - Win32 apps | Microsoft Docs[^].

          1 Reply Last reply
          0
          • A arnold_w

            I would like to show a WinForms MessageBox centered on top of another application's (TortoiseGit) "sub"-form, i.e. a form (the TortoiseGit checkout form) on top of the main form (the TortoiseGit log window). I am able to successfully find the process (TortoiseGitProc) and from there I can successfully get a MainWindowHandle to the main form, but how do get from there to the "sub"-form (the TortoiseGit checkout form)?

            A Offline
            A Offline
            arnold_w
            wrote on last edited by
            #5

            I made a dump of all windows using Spy++ and this what I got:

            Window 000C0678 "C:\\DummyRepo - Switch/Checkout - TortoiseGit" #32770 (Dialog)
            	Window 000B0670 "" ScrollBar
            	Window 00070482 "Switch To" Button
            	Window 001D065E "&Branch" Button
            	Window 000B01AE "" ComboBoxEx32
            		Window 0004036E "ⴀ辘ȡ" ComboBox
            	Window 0017069A "..." Button
            	Window 001303D2 "&Tag" Button
            	Window 000B04DE "" ComboBoxEx32
            		Window 001105D4 "" ComboBox
            	Window 00190620 "&Commit" Button
            	Window 000F06D8 "c288b35fcabf74c51270fff36db3387517beda53" ComboBoxEx32
            		Window 001406CE "Ɒ辘ȡ" ComboBox
            			Window 001005CE "c288b35fcabf74c51270fff36db3387517beda53" Edit
            	Window 00220458 "..." Button
            	Window 00170604 "Option" Button
            	Window 000E0684 "Create &New Branch" Button
            	Window 002503EA "Branch\_c288b35f" Edit
            	Window 00390628 "Overwrite working tree changes (&force)" Button
            	Window 004404EE "&Merge" Button
            	Window 00300666 "T&rack" Button
            	Window 0040045C "&Override branch if exists" Button
            	Window 001404DC "OK" Button
            	Window 0008025E "Cancel" Button
            	Window 00220396 "Help" Button
            Window 00040616 "C:\\DummyRepo - Log Messages - TortoiseGit" #32770 (Dialog)
            	Window 000D04E6 "" Static
            	Window 002A0602 "" Static
            	Window 00040622 "master" Static
            	Window 002204CA "From:" Static
            	Window 001104C2 "2020-07-31" SysDateTimePick32
            	Window 001904A4 "To:" Static
            	Window 001A0496 "2020-07-31" SysDateTimePick32
            	Window 000F0560 "" Edit
            	Window 00080638 "Author Email" ComboBox
            	Window 000F01F2 "" Button
            	Window 001904B0 "" Button
            	Window 00190498 "" SysListView32
            		Window 00150422 "" SysHeader32
            	Window 00350426 "SHA-1: c288b35fcabf74c51270fff36db3387517beda53
            

            * 1
            " RICHEDIT50W
            Window 005B04E4 "" Static
            Window 001104F0 "" SysListView32
            Window 0013045E "" SysHeader32
            Window 004A06CA "Showing 2 revision(s), from revision c288b35f to revision b7a040a4 - 1 revision(s) selected, 0 file(s) selected; line: 1(+) 0(-) files: modified = 0 added = 1 deleted = 0 replaced = 0" Edit
            Window 0017060A "Show &Whole Project" Button
            Window 001705FC "&All Branches" Button
            Window 00290424 "" Edit
            Window 00460660 "Help" Button
            Window 0019048C "Refresh" Button
            Window 004A065C "S&tatistics" Button
            Window 000D036A "Walk Be&haviour" Button
            Window 00160492 "&View" Button
            Window 0016048E "OK" Button
            Window 004B069E "OK" Button
            Window 0024064A "" msctls_progress32
            Window 0004061A "" ScrollBar

            So, it seems the Switch/Checkout window is not<

            L Richard Andrew x64R 2 Replies Last reply
            0
            • A arnold_w

              I made a dump of all windows using Spy++ and this what I got:

              Window 000C0678 "C:\\DummyRepo - Switch/Checkout - TortoiseGit" #32770 (Dialog)
              	Window 000B0670 "" ScrollBar
              	Window 00070482 "Switch To" Button
              	Window 001D065E "&Branch" Button
              	Window 000B01AE "" ComboBoxEx32
              		Window 0004036E "ⴀ辘ȡ" ComboBox
              	Window 0017069A "..." Button
              	Window 001303D2 "&Tag" Button
              	Window 000B04DE "" ComboBoxEx32
              		Window 001105D4 "" ComboBox
              	Window 00190620 "&Commit" Button
              	Window 000F06D8 "c288b35fcabf74c51270fff36db3387517beda53" ComboBoxEx32
              		Window 001406CE "Ɒ辘ȡ" ComboBox
              			Window 001005CE "c288b35fcabf74c51270fff36db3387517beda53" Edit
              	Window 00220458 "..." Button
              	Window 00170604 "Option" Button
              	Window 000E0684 "Create &New Branch" Button
              	Window 002503EA "Branch\_c288b35f" Edit
              	Window 00390628 "Overwrite working tree changes (&force)" Button
              	Window 004404EE "&Merge" Button
              	Window 00300666 "T&rack" Button
              	Window 0040045C "&Override branch if exists" Button
              	Window 001404DC "OK" Button
              	Window 0008025E "Cancel" Button
              	Window 00220396 "Help" Button
              Window 00040616 "C:\\DummyRepo - Log Messages - TortoiseGit" #32770 (Dialog)
              	Window 000D04E6 "" Static
              	Window 002A0602 "" Static
              	Window 00040622 "master" Static
              	Window 002204CA "From:" Static
              	Window 001104C2 "2020-07-31" SysDateTimePick32
              	Window 001904A4 "To:" Static
              	Window 001A0496 "2020-07-31" SysDateTimePick32
              	Window 000F0560 "" Edit
              	Window 00080638 "Author Email" ComboBox
              	Window 000F01F2 "" Button
              	Window 001904B0 "" Button
              	Window 00190498 "" SysListView32
              		Window 00150422 "" SysHeader32
              	Window 00350426 "SHA-1: c288b35fcabf74c51270fff36db3387517beda53
              

              * 1
              " RICHEDIT50W
              Window 005B04E4 "" Static
              Window 001104F0 "" SysListView32
              Window 0013045E "" SysHeader32
              Window 004A06CA "Showing 2 revision(s), from revision c288b35f to revision b7a040a4 - 1 revision(s) selected, 0 file(s) selected; line: 1(+) 0(-) files: modified = 0 added = 1 deleted = 0 replaced = 0" Edit
              Window 0017060A "Show &Whole Project" Button
              Window 001705FC "&All Branches" Button
              Window 00290424 "" Edit
              Window 00460660 "Help" Button
              Window 0019048C "Refresh" Button
              Window 004A065C "S&tatistics" Button
              Window 000D036A "Walk Be&haviour" Button
              Window 00160492 "&View" Button
              Window 0016048E "OK" Button
              Window 004B069E "OK" Button
              Window 0024064A "" msctls_progress32
              Window 0004061A "" ScrollBar

              So, it seems the Switch/Checkout window is not<

              L Offline
              L Offline
              Lost User
              wrote on last edited by
              #6

              Keep doing what you're doing; that's what it's all about. The documented and the undocumented. Maybe it's using a cloaking device. Sounds like a security hole otherwise. ("Masking") [automation - Enumerating Windows/Controls of another application from .Net - Stack Overflow](https://stackoverflow.com/questions/280818/enumerating-windows-controls-of-another-application-from-net)

              It was only in wine that he laid down no limit for himself, but he did not allow himself to be confused by it. ― Confucian Analects: Rules of Confucius about his food

              1 Reply Last reply
              0
              • A arnold_w

                I made a dump of all windows using Spy++ and this what I got:

                Window 000C0678 "C:\\DummyRepo - Switch/Checkout - TortoiseGit" #32770 (Dialog)
                	Window 000B0670 "" ScrollBar
                	Window 00070482 "Switch To" Button
                	Window 001D065E "&Branch" Button
                	Window 000B01AE "" ComboBoxEx32
                		Window 0004036E "ⴀ辘ȡ" ComboBox
                	Window 0017069A "..." Button
                	Window 001303D2 "&Tag" Button
                	Window 000B04DE "" ComboBoxEx32
                		Window 001105D4 "" ComboBox
                	Window 00190620 "&Commit" Button
                	Window 000F06D8 "c288b35fcabf74c51270fff36db3387517beda53" ComboBoxEx32
                		Window 001406CE "Ɒ辘ȡ" ComboBox
                			Window 001005CE "c288b35fcabf74c51270fff36db3387517beda53" Edit
                	Window 00220458 "..." Button
                	Window 00170604 "Option" Button
                	Window 000E0684 "Create &New Branch" Button
                	Window 002503EA "Branch\_c288b35f" Edit
                	Window 00390628 "Overwrite working tree changes (&force)" Button
                	Window 004404EE "&Merge" Button
                	Window 00300666 "T&rack" Button
                	Window 0040045C "&Override branch if exists" Button
                	Window 001404DC "OK" Button
                	Window 0008025E "Cancel" Button
                	Window 00220396 "Help" Button
                Window 00040616 "C:\\DummyRepo - Log Messages - TortoiseGit" #32770 (Dialog)
                	Window 000D04E6 "" Static
                	Window 002A0602 "" Static
                	Window 00040622 "master" Static
                	Window 002204CA "From:" Static
                	Window 001104C2 "2020-07-31" SysDateTimePick32
                	Window 001904A4 "To:" Static
                	Window 001A0496 "2020-07-31" SysDateTimePick32
                	Window 000F0560 "" Edit
                	Window 00080638 "Author Email" ComboBox
                	Window 000F01F2 "" Button
                	Window 001904B0 "" Button
                	Window 00190498 "" SysListView32
                		Window 00150422 "" SysHeader32
                	Window 00350426 "SHA-1: c288b35fcabf74c51270fff36db3387517beda53
                

                * 1
                " RICHEDIT50W
                Window 005B04E4 "" Static
                Window 001104F0 "" SysListView32
                Window 0013045E "" SysHeader32
                Window 004A06CA "Showing 2 revision(s), from revision c288b35f to revision b7a040a4 - 1 revision(s) selected, 0 file(s) selected; line: 1(+) 0(-) files: modified = 0 added = 1 deleted = 0 replaced = 0" Edit
                Window 0017060A "Show &Whole Project" Button
                Window 001705FC "&All Branches" Button
                Window 00290424 "" Edit
                Window 00460660 "Help" Button
                Window 0019048C "Refresh" Button
                Window 004A065C "S&tatistics" Button
                Window 000D036A "Walk Be&haviour" Button
                Window 00160492 "&View" Button
                Window 0016048E "OK" Button
                Window 004B069E "OK" Button
                Window 0024064A "" msctls_progress32
                Window 0004061A "" ScrollBar

                So, it seems the Switch/Checkout window is not<

                Richard Andrew x64R Offline
                Richard Andrew x64R Offline
                Richard Andrew x64
                wrote on last edited by
                #7

                Isn't this the window you want?

                arnold_w wrote:

                Window 000C0678 "C:\DummyRepo - Switch/Checkout - TortoiseGit" #32770 (Dialog)

                The difficult we do right away... ...the impossible takes slightly longer.

                A 1 Reply Last reply
                0
                • Richard Andrew x64R Richard Andrew x64

                  Isn't this the window you want?

                  arnold_w wrote:

                  Window 000C0678 "C:\DummyRepo - Switch/Checkout - TortoiseGit" #32770 (Dialog)

                  The difficult we do right away... ...the impossible takes slightly longer.

                  A Offline
                  A Offline
                  arnold_w
                  wrote on last edited by
                  #8

                  Yes, absolutely. But I don't want to have to use Spy++ to find it, I want to be able to find it in my C# application, but the C# application appears to find this window instead:

                  Window 00040616 "C:\DummyRepo - Log Messages - TortoiseGit" #32770 (Dialog)

                  It would be ok if I can find both, but then I would need to somehow obtain the heading strings ("C:\DummyRepo - Log Messages - TortoiseGit" and "C:\DummyRepo - Switch/Checkout - TortoiseGit") so that I have a way to distinguish which window (or actually, dialog) is which.

                  A 1 Reply Last reply
                  0
                  • A arnold_w

                    Yes, absolutely. But I don't want to have to use Spy++ to find it, I want to be able to find it in my C# application, but the C# application appears to find this window instead:

                    Window 00040616 "C:\DummyRepo - Log Messages - TortoiseGit" #32770 (Dialog)

                    It would be ok if I can find both, but then I would need to somehow obtain the heading strings ("C:\DummyRepo - Log Messages - TortoiseGit" and "C:\DummyRepo - Switch/Checkout - TortoiseGit") so that I have a way to distinguish which window (or actually, dialog) is which.

                    A Offline
                    A Offline
                    arnold_w
                    wrote on last edited by
                    #9

                    Instead of using Process.MainWindowHandle (which only returns the "C:\DummyRepo - Log Messages - TortoiseGit" window) I guess I could iterate through all windows using the technique described in Winforms-How can I make MessageBox appear centered on MainForm? - Stack Overflow[^]. However, when I do so and log the window texts, I never find the strings "C:\DummyRepo - Log Messages - TortoiseGit" and "C:\DummyRepo - Switch/Checkout - TortoiseGit":

                        \[DllImport("user32.dll", EntryPoint = "GetWindowText",
                        ExactSpelling = false, CharSet = CharSet.Auto, SetLastError = true)\]
                        public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpWindowText, int nMaxCount);
                    
                        private bool checkWindow(IntPtr hWnd, IntPtr lp)
                        {
                            // Checks if is a dialog
                            StringBuilder sb = new StringBuilder(260);
                            GetClassName(hWnd, sb, sb.Capacity);
                    
                            // My added code to log all window texts
                            StringBuilder strbTitle = new StringBuilder(255);
                            int nLength = GetWindowText(hWnd, strbTitle, strbTitle.Capacity + 1);
                            string strTitle = strbTitle.ToString();
                            Debug.WriteLine("The window text is: " + strTitle);
                    
                            if (sb.ToString() != "#32770")
                            {
                                return true;
                            }
                            return true;    // My modified code to check all windows
                    

                    The strings I find appear to be much more low-level, e.g "Form1", "MSCTFIME UI", "Default IME", etc. Does anybody know which function I should use instead to obtain the window headings, "C:\DummyRepo - Log Messages - TortoiseGit" and "C:\DummyRepo - Switch/Checkout - TortoiseGit"?

                    Richard Andrew x64R 1 Reply Last reply
                    0
                    • A arnold_w

                      Instead of using Process.MainWindowHandle (which only returns the "C:\DummyRepo - Log Messages - TortoiseGit" window) I guess I could iterate through all windows using the technique described in Winforms-How can I make MessageBox appear centered on MainForm? - Stack Overflow[^]. However, when I do so and log the window texts, I never find the strings "C:\DummyRepo - Log Messages - TortoiseGit" and "C:\DummyRepo - Switch/Checkout - TortoiseGit":

                          \[DllImport("user32.dll", EntryPoint = "GetWindowText",
                          ExactSpelling = false, CharSet = CharSet.Auto, SetLastError = true)\]
                          public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpWindowText, int nMaxCount);
                      
                          private bool checkWindow(IntPtr hWnd, IntPtr lp)
                          {
                              // Checks if is a dialog
                              StringBuilder sb = new StringBuilder(260);
                              GetClassName(hWnd, sb, sb.Capacity);
                      
                              // My added code to log all window texts
                              StringBuilder strbTitle = new StringBuilder(255);
                              int nLength = GetWindowText(hWnd, strbTitle, strbTitle.Capacity + 1);
                              string strTitle = strbTitle.ToString();
                              Debug.WriteLine("The window text is: " + strTitle);
                      
                              if (sb.ToString() != "#32770")
                              {
                                  return true;
                              }
                              return true;    // My modified code to check all windows
                      

                      The strings I find appear to be much more low-level, e.g "Form1", "MSCTFIME UI", "Default IME", etc. Does anybody know which function I should use instead to obtain the window headings, "C:\DummyRepo - Log Messages - TortoiseGit" and "C:\DummyRepo - Switch/Checkout - TortoiseGit"?

                      Richard Andrew x64R Offline
                      Richard Andrew x64R Offline
                      Richard Andrew x64
                      wrote on last edited by
                      #10

                      This is kind of a side point, but I see that your CheckWindow function will return true in any circumstance.

                      The difficult we do right away... ...the impossible takes slightly longer.

                      A 1 Reply Last reply
                      0
                      • A arnold_w

                        I would like to show a WinForms MessageBox centered on top of another application's (TortoiseGit) "sub"-form, i.e. a form (the TortoiseGit checkout form) on top of the main form (the TortoiseGit log window). I am able to successfully find the process (TortoiseGitProc) and from there I can successfully get a MainWindowHandle to the main form, but how do get from there to the "sub"-form (the TortoiseGit checkout form)?

                        Richard Andrew x64R Offline
                        Richard Andrew x64R Offline
                        Richard Andrew x64
                        wrote on last edited by
                        #11

                        See if this SO answer helps: c# - How to enumerate all windows belonging to a particular process using .NET? - Stack Overflow[^] (Particularly the second answer.)

                        The difficult we do right away... ...the impossible takes slightly longer.

                        A 1 Reply Last reply
                        0
                        • Richard Andrew x64R Richard Andrew x64

                          This is kind of a side point, but I see that your CheckWindow function will return true in any circumstance.

                          The difficult we do right away... ...the impossible takes slightly longer.

                          A Offline
                          A Offline
                          arnold_w
                          wrote on last edited by
                          #12

                          Yes, I added the line

                          return true; // My modified code to check all windows

                          on purpose because I wanted to log all window texts. My goals was to find the particular window that has the window text "C:\DummyRepo - Switch/Checkout - TortoiseGit", but all I found was windows having window texts such as "Form1", "MSCTFIME UI" and "Default IME".

                          1 Reply Last reply
                          0
                          • Richard Andrew x64R Richard Andrew x64

                            See if this SO answer helps: c# - How to enumerate all windows belonging to a particular process using .NET? - Stack Overflow[^] (Particularly the second answer.)

                            The difficult we do right away... ...the impossible takes slightly longer.

                            A Offline
                            A Offline
                            arnold_w
                            wrote on last edited by
                            #13

                            That's pretty much what I already do, I am able to get a bunch of windows but I can't tell which one corresponds to

                            Window 000C0678 "C:\DummyRepo - Switch/Checkout - TortoiseGit" #32770 (Dialog)

                            because I can't find any window that has the heading "C:\DummyRepo - Switch/Checkout - TortoiseGit" using GetWindowText. Now, on the other hand, the pure C# (no win32 pinvoke involved) property Process.MainWindowTitle seems to return the proper string, but I can only apply it to the de facto main window ("C:\DummyRepo - Log Messages - TortoiseGit"), not to the "secondary sibling"-window ("C:\DummyRepo - Switch/Checkout - TortoiseGit").

                            Richard Andrew x64R 1 Reply Last reply
                            0
                            • A arnold_w

                              That's pretty much what I already do, I am able to get a bunch of windows but I can't tell which one corresponds to

                              Window 000C0678 "C:\DummyRepo - Switch/Checkout - TortoiseGit" #32770 (Dialog)

                              because I can't find any window that has the heading "C:\DummyRepo - Switch/Checkout - TortoiseGit" using GetWindowText. Now, on the other hand, the pure C# (no win32 pinvoke involved) property Process.MainWindowTitle seems to return the proper string, but I can only apply it to the de facto main window ("C:\DummyRepo - Log Messages - TortoiseGit"), not to the "secondary sibling"-window ("C:\DummyRepo - Switch/Checkout - TortoiseGit").

                              Richard Andrew x64R Offline
                              Richard Andrew x64R Offline
                              Richard Andrew x64
                              wrote on last edited by
                              #14

                              That's not what you're already doing. You must be looking at the first answer to the question. Look at the SECOND answer to the question on that page. The second answer uses the function EnumThreadWindows.

                              The difficult we do right away... ...the impossible takes slightly longer.

                              A 1 Reply Last reply
                              0
                              • Richard Andrew x64R Richard Andrew x64

                                That's not what you're already doing. You must be looking at the first answer to the question. Look at the SECOND answer to the question on that page. The second answer uses the function EnumThreadWindows.

                                The difficult we do right away... ...the impossible takes slightly longer.

                                A Offline
                                A Offline
                                arnold_w
                                wrote on last edited by
                                #15

                                Ahhh, you mean this:

                                const uint WM_GETTEXT = 0x000D;
                                StringBuilder message = new StringBuilder(1000);
                                SendMessage(handle, WM_GETTEXT, message.Capacity, message);

                                Yes, that works great!!! Thank you! This is the complete code:

                                public partial class Form1 : Form
                                {
                                public Form1()
                                {
                                InitializeComponent();
                                WindowWrapper parentForm = ProcessWindowsHelper.getHandleToAnotherProcessWindow("TortoiseGitProc", "Switch/Checkout");
                                MessageBoxEx.Show(parentForm, "Hello on top of TortoiseGit Switch/Checkout dialog");
                                }
                                }
                                public class ProcessWindowsHelper
                                {
                                private delegate bool EnumThreadWndProc(IntPtr hWnd, IntPtr lp);
                                [DllImport("user32.dll")]
                                private static extern bool EnumThreadWindows(int tid, EnumThreadWndProc callback, IntPtr lp);
                                [DllImport("user32.dll", CharSet = CharSet.Auto)]
                                static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam, StringBuilder lParam);
                                delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam);

                                private const uint WM\_GETTEXT = 0x000D;
                                
                                public static WindowWrapper getHandleToAnotherProcessWindow(string processName, string substringInAnotherProcessWindow)
                                {
                                    Process myProcess = findProcessByName(processName);
                                    IEnumerable allHandlesInMyProcess = EnumerateProcessWindowHandles(myProcess.Id);
                                    foreach (IntPtr handle in allHandlesInMyProcess)
                                    {
                                        StringBuilder message = new StringBuilder(1000);
                                        SendMessage(handle, WM\_GETTEXT, message.Capacity, message);
                                        if (message.ToString().Contains(substringInAnotherProcessWindow))
                                        {
                                            Debug.WriteLine(message);
                                            return new WindowWrapper(handle);
                                        }
                                    }
                                    return null;
                                }
                                
                                private static IEnumerable EnumerateProcessWindowHandles(int processId)
                                {
                                    List handles = new List();
                                    ProcessThreadCollection processThreadCollection = Process.GetProcessById(processId).Threads;
                                    for (int i = 0; i < processThreadCollection.Count; i++)
                                    {
                                        ProcessThread thread;
                                        thread = processThreadCollection\[i\];
                                        EnumThreadWindows(thread.Id, 
                                            delegate(IntPtr hWnd, IntPtr lParam)
                                            {
                                                handles.Add(hWnd);
                                                return true;
                                            }, 
                                            IntPtr.Zero);
                                    }
                                    return handles;
                                }
                                
                                private static Process find
                                
                                Richard Andrew x64R A 2 Replies Last reply
                                0
                                • A arnold_w

                                  Ahhh, you mean this:

                                  const uint WM_GETTEXT = 0x000D;
                                  StringBuilder message = new StringBuilder(1000);
                                  SendMessage(handle, WM_GETTEXT, message.Capacity, message);

                                  Yes, that works great!!! Thank you! This is the complete code:

                                  public partial class Form1 : Form
                                  {
                                  public Form1()
                                  {
                                  InitializeComponent();
                                  WindowWrapper parentForm = ProcessWindowsHelper.getHandleToAnotherProcessWindow("TortoiseGitProc", "Switch/Checkout");
                                  MessageBoxEx.Show(parentForm, "Hello on top of TortoiseGit Switch/Checkout dialog");
                                  }
                                  }
                                  public class ProcessWindowsHelper
                                  {
                                  private delegate bool EnumThreadWndProc(IntPtr hWnd, IntPtr lp);
                                  [DllImport("user32.dll")]
                                  private static extern bool EnumThreadWindows(int tid, EnumThreadWndProc callback, IntPtr lp);
                                  [DllImport("user32.dll", CharSet = CharSet.Auto)]
                                  static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam, StringBuilder lParam);
                                  delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam);

                                  private const uint WM\_GETTEXT = 0x000D;
                                  
                                  public static WindowWrapper getHandleToAnotherProcessWindow(string processName, string substringInAnotherProcessWindow)
                                  {
                                      Process myProcess = findProcessByName(processName);
                                      IEnumerable allHandlesInMyProcess = EnumerateProcessWindowHandles(myProcess.Id);
                                      foreach (IntPtr handle in allHandlesInMyProcess)
                                      {
                                          StringBuilder message = new StringBuilder(1000);
                                          SendMessage(handle, WM\_GETTEXT, message.Capacity, message);
                                          if (message.ToString().Contains(substringInAnotherProcessWindow))
                                          {
                                              Debug.WriteLine(message);
                                              return new WindowWrapper(handle);
                                          }
                                      }
                                      return null;
                                  }
                                  
                                  private static IEnumerable EnumerateProcessWindowHandles(int processId)
                                  {
                                      List handles = new List();
                                      ProcessThreadCollection processThreadCollection = Process.GetProcessById(processId).Threads;
                                      for (int i = 0; i < processThreadCollection.Count; i++)
                                      {
                                          ProcessThread thread;
                                          thread = processThreadCollection\[i\];
                                          EnumThreadWindows(thread.Id, 
                                              delegate(IntPtr hWnd, IntPtr lParam)
                                              {
                                                  handles.Add(hWnd);
                                                  return true;
                                              }, 
                                              IntPtr.Zero);
                                      }
                                      return handles;
                                  }
                                  
                                  private static Process find
                                  
                                  Richard Andrew x64R Offline
                                  Richard Andrew x64R Offline
                                  Richard Andrew x64
                                  wrote on last edited by
                                  #16

                                  Glad you got it sorted! 😉

                                  The difficult we do right away... ...the impossible takes slightly longer.

                                  1 Reply Last reply
                                  0
                                  • A arnold_w

                                    Ahhh, you mean this:

                                    const uint WM_GETTEXT = 0x000D;
                                    StringBuilder message = new StringBuilder(1000);
                                    SendMessage(handle, WM_GETTEXT, message.Capacity, message);

                                    Yes, that works great!!! Thank you! This is the complete code:

                                    public partial class Form1 : Form
                                    {
                                    public Form1()
                                    {
                                    InitializeComponent();
                                    WindowWrapper parentForm = ProcessWindowsHelper.getHandleToAnotherProcessWindow("TortoiseGitProc", "Switch/Checkout");
                                    MessageBoxEx.Show(parentForm, "Hello on top of TortoiseGit Switch/Checkout dialog");
                                    }
                                    }
                                    public class ProcessWindowsHelper
                                    {
                                    private delegate bool EnumThreadWndProc(IntPtr hWnd, IntPtr lp);
                                    [DllImport("user32.dll")]
                                    private static extern bool EnumThreadWindows(int tid, EnumThreadWndProc callback, IntPtr lp);
                                    [DllImport("user32.dll", CharSet = CharSet.Auto)]
                                    static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam, StringBuilder lParam);
                                    delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam);

                                    private const uint WM\_GETTEXT = 0x000D;
                                    
                                    public static WindowWrapper getHandleToAnotherProcessWindow(string processName, string substringInAnotherProcessWindow)
                                    {
                                        Process myProcess = findProcessByName(processName);
                                        IEnumerable allHandlesInMyProcess = EnumerateProcessWindowHandles(myProcess.Id);
                                        foreach (IntPtr handle in allHandlesInMyProcess)
                                        {
                                            StringBuilder message = new StringBuilder(1000);
                                            SendMessage(handle, WM\_GETTEXT, message.Capacity, message);
                                            if (message.ToString().Contains(substringInAnotherProcessWindow))
                                            {
                                                Debug.WriteLine(message);
                                                return new WindowWrapper(handle);
                                            }
                                        }
                                        return null;
                                    }
                                    
                                    private static IEnumerable EnumerateProcessWindowHandles(int processId)
                                    {
                                        List handles = new List();
                                        ProcessThreadCollection processThreadCollection = Process.GetProcessById(processId).Threads;
                                        for (int i = 0; i < processThreadCollection.Count; i++)
                                        {
                                            ProcessThread thread;
                                            thread = processThreadCollection\[i\];
                                            EnumThreadWindows(thread.Id, 
                                                delegate(IntPtr hWnd, IntPtr lParam)
                                                {
                                                    handles.Add(hWnd);
                                                    return true;
                                                }, 
                                                IntPtr.Zero);
                                        }
                                        return handles;
                                    }
                                    
                                    private static Process find
                                    
                                    A Offline
                                    A Offline
                                    arnold_w
                                    wrote on last edited by
                                    #17

                                    Well, I guess no joy lasts forever... In case somebody is using bash.exe instead of TortoiseGit to Switch/Checkout, then I wanted to do the same thing with bash.exe as the parent form. But when I call

                                    parentForm = ProcessWindowsHelper.getHandleToAnotherProcessWindow("bash", "MING")

                                    then it seems the handles list inside the EnumerateProcessWindowHandles method doesn't get any elements.

                                    private static IEnumerable EnumerateProcessWindowHandles(int processId)
                                    {
                                        List handles = new List();
                                        ProcessThreadCollection processThreadCollection = Process.GetProcessById(processId).Threads;
                                        for (int i = 0; i < processThreadCollection.Count; i++)
                                        {
                                            ProcessThread thread;
                                            thread = processThreadCollection\[i\];
                                            EnumThreadWindows(thread.Id, 
                                                delegate(IntPtr hWnd, IntPtr lParam)
                                                {
                                                    handles.Add(hWnd);
                                                    return true;
                                                }, 
                                                IntPtr.Zero);
                                        }
                                        return handles;
                                    }
                                    

                                    The call to Process.GetProcessById(processId).Threads returns 3 threads, but nothing gets added to the handles list. Does anybody know why? When I look at the information in Spy++ I see the following:

                                    Window OOOA9B72 "MINGW64:/c/dummyRepo" mintty

                                    Windows Properties, General tab:

                                    Window Caption: MINGW64:/c/dummyRepo
                                    Window Handle: OOOA9B72
                                    Window Proc: (Unavailable)(Unicode)
                                    Rectangle: (86, 89)-(681, 466), 595x377
                                    Restored Rect: (86, 89)-(681, 466), 595x377
                                    Client Rect: (8, 31)-(570, 369), 562x338
                                    Instance Handle 00400000
                                    Menu Handle 00000000
                                    User Data 00000000
                                    Windows Bytes:

                                    Richard Andrew x64R 1 Reply Last reply
                                    0
                                    • A arnold_w

                                      Well, I guess no joy lasts forever... In case somebody is using bash.exe instead of TortoiseGit to Switch/Checkout, then I wanted to do the same thing with bash.exe as the parent form. But when I call

                                      parentForm = ProcessWindowsHelper.getHandleToAnotherProcessWindow("bash", "MING")

                                      then it seems the handles list inside the EnumerateProcessWindowHandles method doesn't get any elements.

                                      private static IEnumerable EnumerateProcessWindowHandles(int processId)
                                      {
                                          List handles = new List();
                                          ProcessThreadCollection processThreadCollection = Process.GetProcessById(processId).Threads;
                                          for (int i = 0; i < processThreadCollection.Count; i++)
                                          {
                                              ProcessThread thread;
                                              thread = processThreadCollection\[i\];
                                              EnumThreadWindows(thread.Id, 
                                                  delegate(IntPtr hWnd, IntPtr lParam)
                                                  {
                                                      handles.Add(hWnd);
                                                      return true;
                                                  }, 
                                                  IntPtr.Zero);
                                          }
                                          return handles;
                                      }
                                      

                                      The call to Process.GetProcessById(processId).Threads returns 3 threads, but nothing gets added to the handles list. Does anybody know why? When I look at the information in Spy++ I see the following:

                                      Window OOOA9B72 "MINGW64:/c/dummyRepo" mintty

                                      Windows Properties, General tab:

                                      Window Caption: MINGW64:/c/dummyRepo
                                      Window Handle: OOOA9B72
                                      Window Proc: (Unavailable)(Unicode)
                                      Rectangle: (86, 89)-(681, 466), 595x377
                                      Restored Rect: (86, 89)-(681, 466), 595x377
                                      Client Rect: (8, 31)-(570, 369), 562x338
                                      Instance Handle 00400000
                                      Menu Handle 00000000
                                      User Data 00000000
                                      Windows Bytes:

                                      Richard Andrew x64R Offline
                                      Richard Andrew x64R Offline
                                      Richard Andrew x64
                                      wrote on last edited by
                                      #18

                                      Have you stepped through it in the debugger? Does it find the correct process? Which line of code is failing?

                                      The difficult we do right away... ...the impossible takes slightly longer.

                                      A 1 Reply Last reply
                                      0
                                      • Richard Andrew x64R Richard Andrew x64

                                        Have you stepped through it in the debugger? Does it find the correct process? Which line of code is failing?

                                        The difficult we do right away... ...the impossible takes slightly longer.

                                        A Offline
                                        A Offline
                                        arnold_w
                                        wrote on last edited by
                                        #19

                                        Yes, I stepped it. I first rewrote the method EnumerateProcessWindowHandles according to this:

                                        private static List handles;

                                        private static IEnumerable EnumerateProcessWindowHandles(int processId)
                                        {
                                        handles = new List();
                                        ProcessThreadCollection processThreadCollection = Process.GetProcessById(processId).Threads;
                                        for (int i = 0; i < processThreadCollection.Count; i++)
                                        {
                                        ProcessThread thread; // If I put a breakpoint here, the debugger stops 3 times
                                        thread = processThreadCollection[i];
                                        EnumThreadWindows(thread.Id, myDelegate, IntPtr.Zero);
                                        }
                                        return handles;
                                        }

                                        private static bool myDelegate(IntPtr hWnd, IntPtr lParam)
                                        {
                                        handles.Add(hWnd); // If I put a breakpoint here, then the debugger never stops
                                        return true;
                                        }

                                        So, something seems to go wrong inside the call to EnumThreadWindows, but that's a Win32 function and I don't know how to put a breakpoint inside it or how to step through it.

                                        Richard Andrew x64R 1 Reply Last reply
                                        0
                                        • A arnold_w

                                          Yes, I stepped it. I first rewrote the method EnumerateProcessWindowHandles according to this:

                                          private static List handles;

                                          private static IEnumerable EnumerateProcessWindowHandles(int processId)
                                          {
                                          handles = new List();
                                          ProcessThreadCollection processThreadCollection = Process.GetProcessById(processId).Threads;
                                          for (int i = 0; i < processThreadCollection.Count; i++)
                                          {
                                          ProcessThread thread; // If I put a breakpoint here, the debugger stops 3 times
                                          thread = processThreadCollection[i];
                                          EnumThreadWindows(thread.Id, myDelegate, IntPtr.Zero);
                                          }
                                          return handles;
                                          }

                                          private static bool myDelegate(IntPtr hWnd, IntPtr lParam)
                                          {
                                          handles.Add(hWnd); // If I put a breakpoint here, then the debugger never stops
                                          return true;
                                          }

                                          So, something seems to go wrong inside the call to EnumThreadWindows, but that's a Win32 function and I don't know how to put a breakpoint inside it or how to step through it.

                                          Richard Andrew x64R Offline
                                          Richard Andrew x64R Offline
                                          Richard Andrew x64
                                          wrote on last edited by
                                          #20

                                          You need to put a breakpoint inside the "myDelegate" callback to see if ANY windows are being found, not just ones that match your substring. But first, verify that it is indeed finding the correct process. Compare the ProcessId to the one shown by Task Manager. EDIT: I'm sorry I didn't see that you had already tried the breakpoint inside the callback. The only thing I can think of at this moment is to make sure it is finding the correct process.

                                          The difficult we do right away... ...the impossible takes slightly longer.

                                          A 1 Reply Last reply
                                          0
                                          Reply
                                          • Reply as topic
                                          Log in to reply
                                          • Oldest to Newest
                                          • Newest to Oldest
                                          • Most Votes


                                          • Login

                                          • Don't have an account? Register

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • World
                                          • Users
                                          • Groups