By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
457,727 Members | 1,165 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 457,727 IT Pros & Developers. It's quick & easy.

Problem implementing a message loop

P: n/a
I am trying to write an event-driven application with no main window that
runs "forever". It waits on a named event and then displays a window
depending on data pased in a memory-mapped file. I started with a standard
console application and it all works fine, except that it does not terminate
tidily when the user logs off/shuts down. So, I figured I needed a message
loop to pick up WM_QUIT. I studied the code in "Waiting in a message loop"
(http://msdn.microsoft.com/library/de...ssage_loop.asp) and implemented it in my Main(), using
MsgWaitForMultipleObjects(1, handles, false, INFINITE, QS_POSTMESSAGE +
QS_SENDMESSAGE);
to wait for either my named event (in 'handles') or a windows message. The
event fires fine, but no windows messages ever arrive. I am obviously doing
something wrong, Can anyone advise.
--
Dave
May 29 '06 #1
Share this Question
Share on Google+
8 Replies


P: n/a

"Dave" <Da**@discussions.microsoft.com> wrote in message
news:21**********************************@microsof t.com...
|I am trying to write an event-driven application with no main window that
| runs "forever". It waits on a named event and then displays a window
| depending on data pased in a memory-mapped file. I started with a standard
| console application and it all works fine, except that it does not
terminate
| tidily when the user logs off/shuts down. So, I figured I needed a message
| loop to pick up WM_QUIT. I studied the code in "Waiting in a message loop"
|
(http://msdn.microsoft.com/library/de...ssage_loop.asp)
and implemented it in my Main(), using
| MsgWaitForMultipleObjects(1, handles, false, INFINITE, QS_POSTMESSAGE +
| QS_SENDMESSAGE);
| to wait for either my named event (in 'handles') or a windows message. The
| event fires fine, but no windows messages ever arrive. I am obviously
doing
| something wrong, Can anyone advise.
| --
| Dave

This will not work, you need a main windows for the system to post/send
messages to, you just need to handle the SessionEnded event on the
Microsoft.Win32.SystemEvents class.

Willy.
May 29 '06 #2

P: n/a
Thanks Willy, but if I implement it as a Windows app with a main window,
execution then disappears into the main window (ie the main window's message
loop) so how do I then wait for my named event?
--
Dave
"Willy Denoyette [MVP]" wrote:

"Dave" <Da**@discussions.microsoft.com> wrote in message
news:21**********************************@microsof t.com...
|I am trying to write an event-driven application with no main window that
| runs "forever". It waits on a named event and then displays a window
| depending on data pased in a memory-mapped file. I started with a standard
| console application and it all works fine, except that it does not
terminate
| tidily when the user logs off/shuts down. So, I figured I needed a message
| loop to pick up WM_QUIT. I studied the code in "Waiting in a message loop"
|
(http://msdn.microsoft.com/library/de...ssage_loop.asp)
and implemented it in my Main(), using
| MsgWaitForMultipleObjects(1, handles, false, INFINITE, QS_POSTMESSAGE +
| QS_SENDMESSAGE);
| to wait for either my named event (in 'handles') or a windows message. The
| event fires fine, but no windows messages ever arrive. I am obviously
doing
| something wrong, Can anyone advise.
| --
| Dave

This will not work, you need a main windows for the system to post/send
messages to, you just need to handle the SessionEnded event on the
Microsoft.Win32.SystemEvents class.

Willy.

May 29 '06 #3

P: n/a

"Dave" <Da**@discussions.microsoft.com> wrote in message
news:C1**********************************@microsof t.com...
| Thanks Willy, but if I implement it as a Windows app with a main window,
| execution then disappears into the main window (ie the main window's
message
| loop) so how do I then wait for my named event?
| --
| Dave
|
|
| "Willy Denoyette [MVP]" wrote:
|

Sorry if I wasn't clear, point is that you don't need a main windows (a Form
instance), all you need is a message pump to handle this.
You can start a separate thread to handle your main task before you start
the message loop by calling Application.Run().

Something like this should do:
[STAThread]
static void Main()
{
SystemEvents.SessionEnded += new
SessionEndedEventHandler(SessionEnd);
// Start a new backgound thread to handle your main task here.
// Start a message pump.
Application.Run();
}
static void SessionEnd(object s, SessionEndedEventArgs e)
{
...
}

Willy.
May 29 '06 #4

P: n/a
Hi Willy
I was confused there as your original reply said "you need a main windows".
I have implemented the event (I used SessionEnding rather than SessionEnded)
but it still doesn't work - when I log off the SessionEnding event is never
fired, but I get a window ".NET-Broadcast Event Window 1.0.5 - This program
is not responding" etc. I would guess that this is because I am not calling
Application.Run because I need to run my own loop waiting for my named event.
Any further suggestions gratefully received. (Maybe I need to make it a
Windows application and override WndProc?)

BTW there seem to be a lot of problems with the newsgroups at the moment.
The "read the response" links in the notification emails haven't worked for
weeks, and 9 times out of 10 I get "page does not exist" when I try to access
a newsgroup. Can you pass the message on to MS.
--
Dave
"Willy Denoyette [MVP]" wrote:

"Dave" <Da**@discussions.microsoft.com> wrote in message
news:C1**********************************@microsof t.com...
| Thanks Willy, but if I implement it as a Windows app with a main window,
| execution then disappears into the main window (ie the main window's
message
| loop) so how do I then wait for my named event?
| --
| Dave
|
|
| "Willy Denoyette [MVP]" wrote:
|

Sorry if I wasn't clear, point is that you don't need a main windows (a Form
instance), all you need is a message pump to handle this.
You can start a separate thread to handle your main task before you start
the message loop by calling Application.Run().

Something like this should do:
[STAThread]
static void Main()
{
SystemEvents.SessionEnded += new
SessionEndedEventHandler(SessionEnd);
// Start a new backgound thread to handle your main task here.
// Start a message pump.
Application.Run();
}
static void SessionEnd(object s, SessionEndedEventArgs e)
{
...
}

Willy.

May 30 '06 #5

P: n/a
Dave <Da**@discussions.microsoft.com> wrote:
I was confused there as your original reply said "you need a main windows".
I have implemented the event (I used SessionEnding rather than SessionEnded)
but it still doesn't work - when I log off the SessionEnding event is never
fired, but I get a window ".NET-Broadcast Event Window 1.0.5 - This program
is not responding" etc. I would guess that this is because I am not calling
Application.Run because I need to run my own loop waiting for my named event.
Any further suggestions gratefully received. (Maybe I need to make it a
Windows application and override WndProc?)


I've tested this application and it works for me:

---8<---
using System;
using System.IO;
using System.Threading;
using System.Windows.Forms;
using Microsoft.Win32;

class App
{
static void Main()
{
EventWaitHandle closing = new ManualResetEvent(false);
bool running = true;

SystemEvents.SessionEnded += delegate
{
running = false;
closing.Set();
File.WriteAllText("\\Log.txt", "Session ended");
};

Thread worker = new Thread((ThreadStart)delegate
{
for (;;)
{
WaitHandle.WaitAny(new WaitHandle[] { closing
/* , X, etc. */ });
if (!running)
break;

// Do work because of event X or whatever
}
File.WriteAllText("\\Closed.txt", "Success!");
});
worker.Start();

Application.Run();
}
}
--->8---

Perhaps you can adapt your application along these lines?

-- Barry

--
http://barrkel.blogspot.com/
May 30 '06 #6

P: n/a
Dave <Da**@discussions.microsoft.com> wrote:
I would guess that this is because I am not calling
Application.Run because I need to run my own loop waiting for my named event.
Any further suggestions gratefully received.


I should point out that each thread is separate as far as message loops
are concerned. You can call Application.Run() on the main thread so that
the session ended event occurs, and create your own message loop (or
call Application.Run() again) on a different thread, without problems.

-- Barry

--
http://barrkel.blogspot.com/
May 30 '06 #7

P: n/a
Are you sure you compiled as a Windows application? Console applications
cannot receive Session ending messages.

Consider following sample to get you started.

public class Program
{
static int keepRunning;
[STAThread]
static void Main()
{
Program prog = new Program();
// Optionally install a tray icon and attached context memu
prog.InitializeTray();
Interlocked.Exchange(ref keepRunning, 1);
Thread t = new Thread(new ThreadStart(prog.ThreadJob));
t.Start();
// Register handler
SystemEvents.SessionEnding += new
SessionEndingEventHandler(prog.SessionEnd);
// Start the message loop, this one creates a parking window and
associated message queue,
// windows messages will be posted to this queue.
Application.Run();
}
void ThreadJob()
{
// Initialize thread invariants like synchronization handles
// ...
// keep running the loop until requested to terminate
while (Interlocked.Exchange(ref keepRunning, 1) == 1)
{
// this is your task loop, make sure you don't start blocking
operations in this loop, start another thread when needed.
}
// Clean-up thread invariants here
}
void InitializeTray()
{
// Initialize context menu
MenuItem cntxtMenuItem = new MenuItem();
cntxtMenuItem.Index = 0;
cntxtMenuItem.Text = "E&xit";
cntxtMenuItem.Click += new System.EventHandler(this.cntxtMenu_Click);
ContextMenu cntxtMenu = new ContextMenu();
cntxtMenu.MenuItems.AddRange(
new MenuItem[] {cntxtMenuItem});
// Attach context menu to notifyIcon
NotifyIcon notifyIcon;
notifyIcon = new NotifyIcon();
notifyIcon.Icon = new System.Drawing.Icon(@"whatever.ico");
notifyIcon.Visible = true;
notifyIcon.Text = "My program";
notifyIcon.ContextMenu = cntxtMenu;
}
void cntxtMenu_Click(object Sender, EventArgs e) {
Interlocked.Exchange(ref keepRunning, 0); // Ask threads to terminate
Application.Exit(); // exit application
}

void SessionEnd(object s, SessionEndingEventArgs e)
{
// signal auxiliary thread(s) to stop
Interlocked.Exchange(ref keepRunning, 0);
// cleanup program invariants when needed (constrained by session
end time-out)
//...
// and accept session to end
e.Cancel = true;
}
}
}
}

Willy.
PS. Can't help you with your newsreader issue, apparently you aren't using a
NNTP newsreader (and posting host), I suggest you try another posting host
and/or reader.

"Dave" <Da**@discussions.microsoft.com> wrote in message
news:7F**********************************@microsof t.com...
| Hi Willy
| I was confused there as your original reply said "you need a main
windows".
| I have implemented the event (I used SessionEnding rather than
SessionEnded)
| but it still doesn't work - when I log off the SessionEnding event is
never
| fired, but I get a window ".NET-Broadcast Event Window 1.0.5 - This
program
| is not responding" etc. I would guess that this is because I am not
calling
| Application.Run because I need to run my own loop waiting for my named
event.
| Any further suggestions gratefully received. (Maybe I need to make it a
| Windows application and override WndProc?)
|
| BTW there seem to be a lot of problems with the newsgroups at the moment.
| The "read the response" links in the notification emails haven't worked
for
| weeks, and 9 times out of 10 I get "page does not exist" when I try to
access
| a newsgroup. Can you pass the message on to MS.
| --
| Dave
|
|
| "Willy Denoyette [MVP]" wrote:
|
| >
| > "Dave" <Da**@discussions.microsoft.com> wrote in message
| > news:C1**********************************@microsof t.com...
| > | Thanks Willy, but if I implement it as a Windows app with a main
window,
| > | execution then disappears into the main window (ie the main window's
| > message
| > | loop) so how do I then wait for my named event?
| > | --
| > | Dave
| > |
| > |
| > | "Willy Denoyette [MVP]" wrote:
| > |
| >
| > Sorry if I wasn't clear, point is that you don't need a main windows (a
Form
| > instance), all you need is a message pump to handle this.
| > You can start a separate thread to handle your main task before you
start
| > the message loop by calling Application.Run().
| >
| > Something like this should do:
| >
| >
| > [STAThread]
| > static void Main()
| > {
| > SystemEvents.SessionEnded += new
| > SessionEndedEventHandler(SessionEnd);
| > // Start a new backgound thread to handle your main task here.
| > // Start a message pump.
| > Application.Run();
| > }
| > static void SessionEnd(object s, SessionEndedEventArgs e)
| > {
| > ...
| > }
| >
| > Willy.
| >
| >
| >
May 30 '06 #8

P: n/a
Brilliant. Thanks Barry, that gave me the clue I needed. All works fine now.
--
Dave
"Barry Kelly" wrote:
Dave <Da**@discussions.microsoft.com> wrote:
I was confused there as your original reply said "you need a main windows".
I have implemented the event (I used SessionEnding rather than SessionEnded)
but it still doesn't work - when I log off the SessionEnding event is never
fired, but I get a window ".NET-Broadcast Event Window 1.0.5 - This program
is not responding" etc. I would guess that this is because I am not calling
Application.Run because I need to run my own loop waiting for my named event.
Any further suggestions gratefully received. (Maybe I need to make it a
Windows application and override WndProc?)


I've tested this application and it works for me:

---8<---
using System;
using System.IO;
using System.Threading;
using System.Windows.Forms;
using Microsoft.Win32;

class App
{
static void Main()
{
EventWaitHandle closing = new ManualResetEvent(false);
bool running = true;

SystemEvents.SessionEnded += delegate
{
running = false;
closing.Set();
File.WriteAllText("\\Log.txt", "Session ended");
};

Thread worker = new Thread((ThreadStart)delegate
{
for (;;)
{
WaitHandle.WaitAny(new WaitHandle[] { closing
/* , X, etc. */ });
if (!running)
break;

// Do work because of event X or whatever
}
File.WriteAllText("\\Closed.txt", "Success!");
});
worker.Start();

Application.Run();
}
}
--->8---

Perhaps you can adapt your application along these lines?

-- Barry

--
http://barrkel.blogspot.com/

May 30 '06 #9

This discussion thread is closed

Replies have been disabled for this discussion.