John Pietrar John Pietrar - 2 months ago 22
C# Question

Using handles and System watcher in c#

I am having a really hard time to understand handles and really I am not getting anywhere even tho I am trying to do this for days .My problem is like this,I want my code to be running when a window is opened,for example "Untitled - Notepad" ,so when I open the notepad my code should be running.I have a windows Form app and saw there is an event called ManagementEventWatcher that seems to not be working.
I got to something like this until now.

[DllImport("user32.dll", EntryPoint = "FindWindowEx")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, string lParam);
private void send_Click(object sender, EventArgs e)
{
Process[] notepads = Process.GetProcessesByName("Notepad");
if (notepads.Length == 0)
{
MessageBox.Show("No test running","Why u do dis?");
}
else if (notepads[0] != null)
{
IntPtr child = FindWindowEx(notepads[0].MainWindowHandle, new IntPtr(0), "Edit", null);
string text = "";
foreach (var item in listBox1.Items)
{
text += item.ToString() ;
SendMessage(child, 0x000C, 0, text);

}
}
}


Which sends my listbox1.Items to an opened notepad when I press the send button,but this is not what I want,I want my app to detect the Opened
Untitled - Notepad
window and do that automatically .It would help me if someone would show me exactly how this is done and explain it also to me with documentations.

Edit



---------------------------------------------------------------------------------------------------------------------------------
From Matthew Watson answer I got answered to most of my question with even more improvisation that I did not ask for but I will take them dearly :) .But still one question remains.How can I create an event using
ManagementEventWatcher
so it will automatically detect when a
Untitled - Notepad
is opened instead of clicking a button.
Code after update:

[DllImport("User32", CharSet = CharSet.Auto)]
public static extern int ShowWindow(IntPtr hWnd, int cmdShow);

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsIconic(IntPtr hwnd);

[DllImport("user32.dll")]
public static extern int SetForegroundWindow(IntPtr hWnd);
var notepad = Process.GetProcessesByName("Notepad").FirstOrDefault(p => p.MainWindowTitle == "Untitled - Notepad");

if (notepad != null)
{
if (IsIconic(notepad.MainWindowHandle))
ShowWindow(notepad.MainWindowHandle, 9);

SetForegroundWindow(notepad.MainWindowHandle);
string text = "";

foreach (var item in listBox1.Items)
{
text += item.ToString();

}

Clipboard.SetText(text);
SendKeys.Send("^V");

}


---------------------------------------------------------------------------------------------------------------------------------

Edit 2



enter image description here

Answer

You could use a different approach for this:

  1. Find a Notepad window with the title "Untitled - Notepad"
  2. If it is minimised, unminimise it.
  3. Bring it to the foreground.
  4. Populate the system clipboard with the text you want to paste into Notepad.
  5. Use SendKeys() to send Ctrl+V to Notepad, to paste the clipboard contents.

Something like this:

[DllImport("User32", CharSet = CharSet.Auto)]
public static extern int ShowWindow(IntPtr hWnd, int cmdShow);

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsIconic(IntPtr hwnd);

[DllImport("user32.dll")]
public static extern int SetForegroundWindow(IntPtr hWnd);

private void send_Click(object sender, EventArgs e)
{
    var notepad = Process.GetProcessesByName("Notepad").FirstOrDefault(p => p.MainWindowTitle == "Untitled - Notepad");

    if (notepad != null)
    {
        if (IsIconic(notepad.MainWindowHandle))
            ShowWindow(notepad.MainWindowHandle, 9);

        SetForegroundWindow(notepad.MainWindowHandle);

        Clipboard.SetText("Here's some text to paste into the Notepad window");
        SendKeys.Send("^V");
    }
}

In order to determine when a process has been started, you can use class ManagementEventWatcher:

var query = new WqlEventQuery("SELECT * FROM Win32_ProcessStartTrace WHERE ProcessName = 'Notepad.exe'");
var mew = new ManagementEventWatcher(query) {Query = query};
mew.EventArrived += (sender, args) => { notepadStarted(); };
mew.Start();

However, note that watching for processes to start requires elevated permissions. In other words, if you do this then your application will need to run as an administrator.

Here's a complete example Form implementation that will paste some text into Notepad when it is opened:

using System;
using System.Diagnostics;
using System.Linq;
using System.Management;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            var query = new WqlEventQuery("SELECT * FROM Win32_ProcessStartTrace WHERE ProcessName = 'Notepad.exe'");
            var mew = new ManagementEventWatcher(query) {Query = query};
            mew.EventArrived += (sender, args) => { notepadStarted(); };
            mew.Start();
        }

        void notepadStarted()
        {
            BeginInvoke(new Action(pasteIntoNotepad));
        }

        [DllImport("User32", CharSet = CharSet.Auto)]
        public static extern int ShowWindow(IntPtr hWnd, int cmdShow);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool IsIconic(IntPtr hwnd);

        [DllImport("user32.dll")]
        public static extern int SetForegroundWindow(IntPtr hWnd);

        void pasteIntoNotepad()
        {
            var notepad = Process.GetProcessesByName("Notepad").FirstOrDefault(p => p.MainWindowTitle == "Untitled - Notepad");

            if (notepad != null)
            {
                notepad.WaitForInputIdle();

                if (IsIconic(notepad.MainWindowHandle))
                    ShowWindow(notepad.MainWindowHandle, 9);

                SetForegroundWindow(notepad.MainWindowHandle);

                Clipboard.SetText("Here's some text to paste\r\ninto the Notepad window");
                SendKeys.Send("^V");
            }
        }
    }
}

You will need to run this as an administrator, otherwise it will throw an access denied exception.

Also note that this does NOT handle multiple instances of Notepad all with the same title "Untitled - Notepad"!