Does get-event pump windows messages

Sep 21, 2007 at 8:02 AM
Edited Sep 21, 2007 at 8:14 AM
Does "get-event -wait" pump windows messages?

I'm finding that certain com objects aren't generating events as I'd expect and I'm guessing that this is because the thread isnt having it's message pump serviced during the call to get-event.

Coordinator
Sep 24, 2007 at 3:39 PM
Unfortunately no, it does not pump window messages. This is a good idea though I guess for the future.

You could try starting the included "Start-KeyHandler" cmdlet (with -CaptureKeys) as this spins up a message pump in the background which is needed to intercept keystrokes, but then you'd have to filter out the keystroke events in the queue.
Sep 26, 2007 at 4:28 PM
Thanks for the response Oisin, I'll try your suggestion.

I'll take this opportunity though to stress how common it is for objects to rely on a message pump. STA based COM objects in particular typically use it as their synchronisation mechanism; especially if they fire events. Such objects account for a substantial proportion of all objects that are out there - and without a message pump they're unlikely to work,

That said, I thoroughly appluade what you've done with your library - it's a great enhancement to Powershell.
Coordinator
Sep 30, 2007 at 7:28 PM
Hi Michael,

I'm not really a GUI guy, and my exposure to COM and window messages have been picked up from debugging other people's code, but having said that, I've spent the last week refreshing my knowledge on the in-and-outs of STA/MTA and the CLR regarding message pumping. It's a nasty pit of dirtiness, but if I didn't like that stuff I probably wouldn't have written this snap-in. I believe I've got a (wait)handle (har-har) on it now, so keep tuned for a 1.1 update very soon.

- Oisin

Coordinator
Sep 30, 2007 at 7:46 PM
Edited Sep 30, 2007 at 8:23 PM
Quick update - I just looked at the get-event code for v1.0 and if you use the -Wait switch, message pumping will happen:

        protected override void EndProcessing()
        {            
            Dump("Begin");
            PSEventQueue queue = PSEventQueue.Instance;
 
            try
            {
                List<PSEvent> eventList = null;
 
                if (Wait.IsPresent)
                {
                    if (queue.HasEvents == false)
                    {
                        Thread t = new Thread(new ThreadStart(WaitForEventOrBreak));
                        t.IsBackground = true;
                        t.Start();
                        t.Join(); // pump COM & window messages
                    }
                }
                eventList = queue.DequeueAll();
 
                if (eventList != null)
                {
                    WriteObject(eventList, true);
                }
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex.ToString(), "GetEvent Error");
            }
            Dump("End");
        }
 
        private static void WaitForEventOrBreak()
        {
            PSEventQueue queue = PSEventQueue.Instance;
            while (queue.HasEvents == false && (!queue.CtrlCHit))
            {
                Thread.Sleep(100);
            }
        }
...from GetEventCommand.cs

This happens on one of powershell's MTA threads though - not sure how that affects you, I guess it depends on the COM object. I'm not 100% sure of the interaction, but depending on how you created the COM object, the current thread executing your script may have been moved into an STA and the Join is blocking it from consuming messages. Anyway, I've refactored it to hopefully be more COM friendly by no longer blocking the calling thread:

                    ...
                    if (queue.HasEvents == false)
                    {
                        Thread t = new Thread(new ThreadStart(WaitForEventOrBreak));
                        t.IsBackground = true;
                        t.Start();
                        while (t.IsAlive)
                        {
                            // process window messages
                            Application.DoEvents();
                            Thread.Sleep(100);
                        }
                        t.Join();
                    }
                    ...
...while pumping messages in the child thread:

        private static void WaitForEventOrBreak()
        {
            PSEventQueue queue = PSEventQueue.Instance;
            while (queue.HasEvents == false && (!queue.CtrlCHit))
            {
                // perform com/sendmessage pumping
                Thread.CurrentThread.Join(0);
                Thread.Sleep(100);
            }
        }
I'll compile up a 1.1 Beta and place it in the downloads for you to try out. Please let me know how you get on.
Coordinator
Sep 30, 2007 at 8:37 PM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.