locked
PostMessage & Findwindow not working on win 7? RRS feed

  • Question

  • Hi 

    I have windows 7 64bit. I'm trying to send keys to a window using PostMessage and Findwindow but it's not even working on notepad. Though it works fine for my friend who has XP. 

    [DllImport("user32.dll", SetLastError = true)]
    static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    IntPtr hWnd = FindWindow(null, "Untitled - Notepad");
    
    [DllImport("user32.dll", SetLastError = true)]
    static extern bool PostMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
    
        const int WM_KEYDOWN = 0x0100;
        const int WM_KEYUP = 0x0101;
        const int WM_CHAR = 0x0102;
    
        private void Form1_Load(object sender, EventArgs e)
        {
          FindWindow(null, "Untitled - Notepad");  
        }
        private void button1_Click(object sender, EventArgs e)
        {
          FindWindow(null, "Untitled - Notepad");  
          PostMessage(hWnd, WM_KEYDOWN, 0x38, 0x90001);
        }
    

    Are there any solutions to this?

    Thanks

     

     

    Thursday, October 28, 2010 3:32 PM

Answers

  • And a working example:

      public partial class Form1 : Form
      {
        [DllImport("user32")]
    
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr i);
    
        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
    
        [DllImport("user32.dll", SetLastError = true)]
        static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
        IntPtr hWnd = FindWindow(null, "Untitled - Notepad");
    
        [DllImport("user32.dll", SetLastError = true)]
        static extern bool PostMessage(IntPtr hWnd, [MarshalAs(UnmanagedType.U4)] uint Msg, IntPtr wParam, IntPtr lParam);
    
        const int WM_KEYDOWN = 0x0100;
        const int WM_KEYUP = 0x0101;
        const int WM_CHAR = 0x0102;
    
        public Form1()
        {
          InitializeComponent();
          foreach (IntPtr child in GetChildWindows(FindWindow(null, "Untitled - Notepad")))
          {
            StringBuilder sb = new StringBuilder(100);
            GetClassName(child, sb, sb.Capacity);
    
            if (sb.ToString() == "Edit")
            {
              uint wparam = 0 << 29 | 0;
              PostMessage(child, WM_KEYDOWN, (IntPtr)Keys.H, (IntPtr)wparam);
            }
          }
        }
    
        /// <summary>
        /// Returns a list of child windows
        /// </summary>
        /// <param name="parent">Parent of the windows to return</param>
        /// <returns>List of child windows</returns>
        public static List<IntPtr> GetChildWindows(IntPtr parent)
        {
          List<IntPtr> result = new List<IntPtr>();
          GCHandle listHandle = GCHandle.Alloc(result);
          try
          {
            EnumWindowProc childProc = new EnumWindowProc(EnumWindow);
            EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
          }
          finally
          {
            if (listHandle.IsAllocated)
              listHandle.Free();
          }
          return result;
        }
    
        /// <summary>
        /// Callback method to be used when enumerating windows.
        /// </summary>
        /// <param name="handle">Handle of the next window</param>
        /// <param name="pointer">Pointer to a GCHandle that holds a reference to the list to fill</param>
        /// <returns>True to continue the enumeration, false to bail</returns>
        private static bool EnumWindow(IntPtr handle, IntPtr pointer)
        {
          GCHandle gch = GCHandle.FromIntPtr(pointer);
          List<IntPtr> list = gch.Target as List<IntPtr>;
          if (list == null)
          {
            throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
          }
          list.Add(handle);
          // You can modify this to check to see if you want to cancel the operation, then return a null here
          return true;
        }
    
        /// <summary>
        /// Delegate for the EnumChildWindows method
        /// </summary>
        /// <param name="hWnd">Window handle</param>
        /// <param name="parameter">Caller-defined variable; we use it for a pointer to our list</param>
        /// <returns>True to continue enumerating, false to bail.</returns>
        public delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter);
    
        
      }
    

     

    Regards,

    Fábio


    "To alcohol! The cause of and solution to all of life's problems." - Homer Simpson
    • Marked as answer by NoobieMe Saturday, October 30, 2010 12:30 PM
    Friday, October 29, 2010 10:51 PM
  • Check this to enumerate the child windows/controls of the application, this way you may find the handle to the appropriate control:

    http://stackoverflow.com/questions/280818/enumerating-windows-controls-of-another-application-from-net

     

    And here to get the class name, which is "Edit" for the notepad textBox:

    http://www.pinvoke.net/default.aspx/user32.getclassname

     

    Regards,

    Fábio


    "To alcohol! The cause of and solution to all of life's problems." - Homer Simpson
    • Marked as answer by NoobieMe Saturday, October 30, 2010 12:31 PM
    Friday, October 29, 2010 10:45 PM

All replies

  • I don't know... Can you pist the error you're getting? If no error is supplied, check if the return type is  null, if it is, call Marshal.GetLastWin32Error() method after the call to FindWindow to get the error code and post it back here.

     

    Regards,

    Fábio


    "To alcohol! The cause of and solution to all of life's problems." - Homer Simpson
    Thursday, October 28, 2010 9:13 PM
  • I'm not getting any errors, and GetLastWin32Error() shows me "0". It's just doesn't do anything when I click the button...
    Thursday, October 28, 2010 11:13 PM
  • Uhhhmm... Try changing this:

       private void button1_Click(object sender, EventArgs e)
      {
       FindWindow(null, "Untitled - Notepad"); 
       PostMessage(hWnd, WM_KEYDOWN, 0x38, 0x90001);
      }
    
    

    to this:

       private void button1_Click(object sender, EventArgs e)
      { 
       PostMessage(FindWindow(null, "Untitled - Notepad"), WM_KEYDOWN, 0x38, 0x90001);
      }
    
    

     

    Regards,

    Fábio


    "To alcohol! The cause of and solution to all of life's problems." - Homer Simpson
    Friday, October 29, 2010 11:48 AM
  • Please, also check if you're building to AnyCpu
    "To alcohol! The cause of and solution to all of life's problems." - Homer Simpson
    Friday, October 29, 2010 11:49 AM
  • Hi, 

    I tried changing it but it still doesn't do anything. 

    And how do I check if I am building to any cpu? I'm kinda new to programming...

     

    Friday, October 29, 2010 3:38 PM
  • In Visual Studio, next to the "play" button, the three common options in a combo box are:

    - Any CPU

    - x86

    - x64

     

    Make sure it's either x64 or Any CPU. In any case, use the modification I provided. Second, make sure notepad has the exact same title as as the one in your code.

     

    Regards,

    Fábio


    "To alcohol! The cause of and solution to all of life's problems." - Homer Simpson
    Friday, October 29, 2010 4:32 PM
  • Well, since your new to programming, let's make another check:

     

    Select the button in the designer, go to the properties window and navigate to events (lightning button). Check there if the Click event has the following text on it: button1_Click.

    If not, click the drop down button and select the "button1_Click" option that will appear there.

     

    Regards,

    Fábio


    "To alcohol! The cause of and solution to all of life's problems." - Homer Simpson
    Friday, October 29, 2010 4:42 PM
  • Ok, I think I know what's wrong:

    The wParam and lParam should for the PostMessage method declaration should be IntPtr. Because IntPtr in 32 bit OS has 4 bytes only the int type will work. However IntPtr has 8 bytes on 64 bit OS and the int will probably make two parameters as one (not sure if the effects are that, but I beleive it is). IntPtr maps apropriately no matter the OS bittage your using. So your code should look like this:

        [DllImport("user32.dll", SetLastError = true)]
        static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
        IntPtr hWnd = FindWindow(null, "Untitled - Notepad");
    
        [DllImport("user32.dll", SetLastError = true)]
        static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
    
        const int WM_KEYDOWN = 0x0100;
        const int WM_KEYUP = 0x0101;
        const int WM_CHAR = 0x0102;
    
        private void Form1_Load(object sender, EventArgs e)
        {
          FindWindow(null, "Untitled - Notepad");
        }
        private void button1_Click(object sender, EventArgs e)
        {
          PostMessage(FindWindow(null, "Untitled - Notepad"), WM_KEYDOWN, (IntPtr)0x38, (IntPtr)0x90001);
        }
    

     

    Regards,

    Fábio


    "To alcohol! The cause of and solution to all of life's problems." - Homer Simpson
    • Marked as answer by NoobieMe Friday, October 29, 2010 8:22 PM
    • Unmarked as answer by NoobieMe Friday, October 29, 2010 8:23 PM
    Friday, October 29, 2010 4:49 PM
  • Thank you for trying to help me

    I tried everything you advised, but it still doesnt work. I think both PostMessage & FindWindow don`t work. 

     

    Friday, October 29, 2010 9:00 PM
  • Ahhh, I see what's going on. You see, by sending a key to the Notepad "window", nothing will happen. Because you have to send the key down to the textBox control. Use Spy++ to get the Handle to the text area of the notepad, and supply that instead of the Notepad window handle.

    It will work.


    "To alcohol! The cause of and solution to all of life's problems." - Homer Simpson
    Friday, October 29, 2010 10:30 PM
  • Check this to enumerate the child windows/controls of the application, this way you may find the handle to the appropriate control:

    http://stackoverflow.com/questions/280818/enumerating-windows-controls-of-another-application-from-net

     

    And here to get the class name, which is "Edit" for the notepad textBox:

    http://www.pinvoke.net/default.aspx/user32.getclassname

     

    Regards,

    Fábio


    "To alcohol! The cause of and solution to all of life's problems." - Homer Simpson
    • Marked as answer by NoobieMe Saturday, October 30, 2010 12:31 PM
    Friday, October 29, 2010 10:45 PM
  • And a working example:

      public partial class Form1 : Form
      {
        [DllImport("user32")]
    
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr i);
    
        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
    
        [DllImport("user32.dll", SetLastError = true)]
        static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
        IntPtr hWnd = FindWindow(null, "Untitled - Notepad");
    
        [DllImport("user32.dll", SetLastError = true)]
        static extern bool PostMessage(IntPtr hWnd, [MarshalAs(UnmanagedType.U4)] uint Msg, IntPtr wParam, IntPtr lParam);
    
        const int WM_KEYDOWN = 0x0100;
        const int WM_KEYUP = 0x0101;
        const int WM_CHAR = 0x0102;
    
        public Form1()
        {
          InitializeComponent();
          foreach (IntPtr child in GetChildWindows(FindWindow(null, "Untitled - Notepad")))
          {
            StringBuilder sb = new StringBuilder(100);
            GetClassName(child, sb, sb.Capacity);
    
            if (sb.ToString() == "Edit")
            {
              uint wparam = 0 << 29 | 0;
              PostMessage(child, WM_KEYDOWN, (IntPtr)Keys.H, (IntPtr)wparam);
            }
          }
        }
    
        /// <summary>
        /// Returns a list of child windows
        /// </summary>
        /// <param name="parent">Parent of the windows to return</param>
        /// <returns>List of child windows</returns>
        public static List<IntPtr> GetChildWindows(IntPtr parent)
        {
          List<IntPtr> result = new List<IntPtr>();
          GCHandle listHandle = GCHandle.Alloc(result);
          try
          {
            EnumWindowProc childProc = new EnumWindowProc(EnumWindow);
            EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
          }
          finally
          {
            if (listHandle.IsAllocated)
              listHandle.Free();
          }
          return result;
        }
    
        /// <summary>
        /// Callback method to be used when enumerating windows.
        /// </summary>
        /// <param name="handle">Handle of the next window</param>
        /// <param name="pointer">Pointer to a GCHandle that holds a reference to the list to fill</param>
        /// <returns>True to continue the enumeration, false to bail</returns>
        private static bool EnumWindow(IntPtr handle, IntPtr pointer)
        {
          GCHandle gch = GCHandle.FromIntPtr(pointer);
          List<IntPtr> list = gch.Target as List<IntPtr>;
          if (list == null)
          {
            throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
          }
          list.Add(handle);
          // You can modify this to check to see if you want to cancel the operation, then return a null here
          return true;
        }
    
        /// <summary>
        /// Delegate for the EnumChildWindows method
        /// </summary>
        /// <param name="hWnd">Window handle</param>
        /// <param name="parameter">Caller-defined variable; we use it for a pointer to our list</param>
        /// <returns>True to continue enumerating, false to bail.</returns>
        public delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter);
    
        
      }
    

     

    Regards,

    Fábio


    "To alcohol! The cause of and solution to all of life's problems." - Homer Simpson
    • Marked as answer by NoobieMe Saturday, October 30, 2010 12:30 PM
    Friday, October 29, 2010 10:51 PM
  • Woha it worked!!!!! :D

    Thank you very much!!!

    Saturday, October 30, 2010 12:31 PM
  • Could this possibly work with FindWindowEx ? so far it fails for me (with FindWindowEx) the handle is never > 0

    And I'm trying to find the explorer's left nav pane's tree which is SysTreeView32 class and also has a title of  "Namespace Tree Control" as reported by Inspect.exe under win7 64bit (from SDK). I am able to find explorer's window with hWnd=FindWindowByCaption(0,"Computer")

    but then

     [DllImport("user32.dll", EntryPoint = "FindWindowEx")]
            private static extern int FindWindowEx(int _Parent, int _ChildAfter, string _ClassName, string _WindowName);

    ...

    int tree=FindWindowEx(hWnd,0, "SysTreeView32", "Namespace Tree Control");

    ...

    tree is never over 0, but hWnd is

    and I also tried the FindWindowEx version with IntPtr instead of ints

    What am I missing? btw, I'm new xD

     

    EDIT: apparently FindWindowEx searches only in children of parent, not children of children as in not deeper than 1 level. For that I had to use UIAutomation AutomationElement and FindFirst and FindAll, I didn't use EnumChildWindows because I didn't know how to transform IntPtr into Control to access properties like Name and classNN. Anyway I've a working example here: http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/086e63f0-d6e2-469d-8cde-af2ff86d4455/#1d8a378f-8d18-415c-98a9-725557eb5502


    what is you talking aboot?
    • Edited by escirllel Monday, December 27, 2010 9:49 AM not FindWindowEx for recursion
    Sunday, December 26, 2010 1:25 PM
  • I tried to get to the URL

    http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/086e63f0-d6e2-469d-8cde-af2ff86d4455/#1d8a378f-8d18-415c-98a9-725557eb5502


    and get a not found error?

    Thanks for any help getting to this!

    Tuesday, January 11, 2011 7:36 PM
  • it works for me! but how to send a combination of keys like shift + H?

    Thursday, January 13, 2011 12:22 AM
  • Please follow this thread:

    http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/77bb488a-3270-461c-abc8-5a1c4f242518

    Regards,

    Fábio


    "To alcohol! The cause of and solution to all of life's problems." - Homer Simpson
    Thursday, January 13, 2011 3:46 PM
  • Thanks!
    Thursday, January 13, 2011 7:59 PM