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

PostMessage problem

P: n/a
In my code I have a problem in abtaining a windows handle. I do not
know the namespace to obtain the windows hanle. here is the code.

using System;
using System.Collections;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace mynamespace
public class HandleMessage : System.Windows.Forms.NativeWindow
{
[DllImport("user32.dll", CharSet=CharSet.Auto,
SetLastError=true)]

public static extern bool PostMessage(
IntPtr hWnd,
[MarshalAs(UnmanagedType.U4)] int Msg,
IntPtr wParam,
IntPtr lParam);

private Queue myqueue;
private CMsgDelegate ReceiveMessage;

public HandleMessage(MsgDelegate ReceiveMessage)
{
myqueue = new Queue();
this.ReceiveMessage = ReceiveMessage;
}

public void PutinQue(Message msg)
{
queue.PutElement(msg);

System.Windows.Forms.Message msg =
System.Windows.Forms.Message.Create(this.Hwnd,0

,(IntPtr)0,(IntPtr)0);
PostMessage (******);

private Message GetFromQue()
{
return (Message)queue.GetElement();
}

protected override void WndProc(ref

System.Windows.Forms.Message msg)
{

this.ReceiveMessage(GetFromQue());
}
}

Having inherited the class from System.Windows.Forms.NativeWindow does
not give me windows handle. Can anyone help.

Thanks in advance
Nov 15 '05 #1
Share this Question
Share on Google+
15 Replies


P: n/a
You can use GetForegroundWindow() function in user32.dll to get the window
handle for the active window.
--
With Regards,
Deepak
[I code, therefore I am]
http://deepakictim.blogspot.com
"James" <ja*****************@yahoo.com.au> wrote in message
news:e6**************************@posting.google.c om...
In my code I have a problem in abtaining a windows handle. I do not
know the namespace to obtain the windows hanle. here is the code.

using System;
using System.Collections;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace mynamespace
public class HandleMessage : System.Windows.Forms.NativeWindow
{
[DllImport("user32.dll", CharSet=CharSet.Auto,
SetLastError=true)]

public static extern bool PostMessage(
IntPtr hWnd,
[MarshalAs(UnmanagedType.U4)] int Msg,
IntPtr wParam,
IntPtr lParam);

private Queue myqueue;
private CMsgDelegate ReceiveMessage;

public HandleMessage(MsgDelegate ReceiveMessage)
{
myqueue = new Queue();
this.ReceiveMessage = ReceiveMessage;
}

public void PutinQue(Message msg)
{
queue.PutElement(msg);

System.Windows.Forms.Message msg =
System.Windows.Forms.Message.Create(this.Hwnd,0

,(IntPtr)0,(IntPtr)0);
PostMessage (******);

private Message GetFromQue()
{
return (Message)queue.GetElement();
}

protected override void WndProc(ref

System.Windows.Forms.Message msg)
{

this.ReceiveMessage(GetFromQue());
}
}

Having inherited the class from System.Windows.Forms.NativeWindow does
not give me windows handle. Can anyone help.

Thanks in advance

Nov 15 '05 #2

P: n/a
Hi James,
I'm not quite getting your problem and what you are trying to achieve with
the code you posted.
However,
In my code I have a problem in abtaining a windows handle. I do not
know the namespace to obtain the windows hanle. here is the code.
What window handle do you want to obtain? I'm not quite sure what do
namespaces have to do with the window handle.

Having inherited the class from System.Windows.Forms.NativeWindow does
not give me windows handle. Can anyone help.


Having your class inherited form NativeWindow you have property called
Handle. This very property gives you the window handle of the underlying
Windows OS native window. However it is your responsibility to give that
property value (its default value is 0 (NULL))

Instantiating your class with the *new* operator doesn't create the Windows
OS native window (and respectively the handle (HWND)). You have to create
either new Windows OS native windows calling NativeWindow.CreateHandle
method or attach the object to already existing one -
NativeWindow.AssignHandle.

I don't see such calls in your code.

Maybe I'm not getting your question correctly so it will be helpful if you
provide more information about what you are trying to achieve.

B\rgds
100
Nov 15 '05 #3

P: n/a
I think I did not state the problem clearly. I have a separate form
and that form is on a seperate thread started by a main program. In
the form I am sending messages. And I need a way to call a receive
method to process those messages. So what I do is once I send a
message through the form I call Enque()method and inside I Post a
dummy message to windows and when I capture that message in WndProc I
will call the Receic\ve method to process that message. The problem I
am having is that the PostMessage method. I need a way to get the
handle of the parent window which is the form(Form calls Enque() in
MessageHandler).How do I do that, I need that in CreateParams.
using System;
using System.Collections;
using System.Windows.Forms;
using System.Runtime.InteropServices;

public class CMessageHandler : System.Windows.Forms.NativeWindow
{
[DllImport("user32.dll", CharSet=CharSet.Auto, SetLastError=true)]

public static extern bool PostMessage(
IntPtr hWnd,
[MarshalAs(UnmanagedType.U4)] int Msg,
IntPtr wParam,
IntPtr lParam);

private Queue queue;
private CMessageDelegate receiveMessage;

public CMessageHandler(CMessageDelegate receiveMessage)
{
queue = new Queue();
this. receiveMessage = receiveMessage;
}

public void Enqueue(CMessage message)
{
queue.Enqueue(message);

CreateParams cp = new CreateParams();
cp.Parent = this.Handle; ?????? here is the problem how do I
get the handle for the form????
CreateHandle(cp);

PostMessage(this.Handle,99999,(IntPtr)0,(IntPtr)0) ;

}

private CMessage GetMessage()
{
return (CMessage)queue.Dequeue();
}
protected override void WndProc(ref Message msg)
{
if (msg.Msg == 99999)
{
this.decodeMessage(GetMessage());
base.WndProc(ref msg);

}
}
}
Nov 15 '05 #4

P: n/a
I actually changed the code a bit. What happens is once it reaches
this.CreateHandle(cp); statement it jumps to WndProc() without
executing the PostMessage((IntPtr)this.Handle,1234,(IntPtr)2,(In tPtr)3)
statement. What am I doing wrong.

Thanks
using System.Collections;
using System.Windows.Forms;
using System.Runtime.InteropServices;

public class CMessageHandler : System.Windows.Forms.NativeWindow
{

[DllImport("user32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool PostMessage(
IntPtr hWnd,
[MarshalAs(UnmanagedType.U4)] int Msg,
IntPtr wParam,
IntPtr lParam);

private Queue queue;
private CMessageDelegate receiveMessage;

public CMessageHandler(CMsgDelegate receiveMessage)
{
queue = new Queue();
this.receiveMessage = receiveMessage;
}

public void Enqueue(CMessage message)
{
queue.Enqueue(message);

CreateParams cp = new CreateParams();

cp.Parent = (IntPtr)this.Handle;

this.CreateHandle(cp);

PostMessage((IntPtr)this.Handle,1234,(IntPtr)2,(In tPtr)3);

}

private CMessage GetMessage()
{
return (CMessage)queue.Dequeue();
}

protected override void WndProc(ref Message msg)
{
if (msg.Msg == 1234)
{
this.receiveMessage(GetMessage());
}
}
}
Nov 15 '05 #5

P: n/a
Hi James,

I think I got your idea. What I got is:
You have a form and you want this very form to send messages to the others.
You want each receiver to have its own queue of messages. Each receiver will
create a CMeassageHandler object and will register that object with the
form. When the form wants to send a message it goes thru all registered
receivers and call their Enqueue methods. But you don't want the form to be
blocked in waiting the reveivers to process the message that's why you want
to have a queue. The form just queue the message and continue. The message
will be process in some moment when it times come (up to the receiver).

Tell me if I got your idea right.

Do you need CMessageHandler to be a window in order to be able to implement
this enqueue-and-go feature or you have some other issues (like switchng
threads or so)?

Is the receiver-CMessageHandler relation one-to-one? In other words can more
then one receivers share the same CMessageHandler object (receiveMessage
delegate to be actualy a chain of delegates).

It is possible that you don't need CMessageHandler to be window at all.

IMHO your code of creating CMessageHandler window is not correct.
--
B\rgds
100
"James" <ja*****************@yahoo.com.au> wrote in message
news:e6**************************@posting.google.c om...
I actually changed the code a bit. What happens is once it reaches
this.CreateHandle(cp); statement it jumps to WndProc() without
executing the PostMessage((IntPtr)this.Handle,1234,(IntPtr)2,(In tPtr)3)
statement. What am I doing wrong.

Thanks
using System.Collections;
using System.Windows.Forms;
using System.Runtime.InteropServices;

public class CMessageHandler : System.Windows.Forms.NativeWindow
{

[DllImport("user32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool PostMessage(
IntPtr hWnd,
[MarshalAs(UnmanagedType.U4)] int Msg,
IntPtr wParam,
IntPtr lParam);

private Queue queue;
private CMessageDelegate receiveMessage;

public CMessageHandler(CMsgDelegate receiveMessage)
{
queue = new Queue();
this.receiveMessage = receiveMessage;
}

public void Enqueue(CMessage message)
{
queue.Enqueue(message);

CreateParams cp = new CreateParams();

cp.Parent = (IntPtr)this.Handle;

this.CreateHandle(cp);

PostMessage((IntPtr)this.Handle,1234,(IntPtr)2,(In tPtr)3);

}

private CMessage GetMessage()
{
return (CMessage)queue.Dequeue();
}

protected override void WndProc(ref Message msg)
{
if (msg.Msg == 1234)
{
this.receiveMessage(GetMessage());
}
}
}

Nov 15 '05 #6

P: n/a
I think you have got the basic idea from my "not quite fully explained
messages", for that thank you!

I logic is a bit different. I will explain,

I have a form, and that form needs to process incommimg
messages(forget about sending messages for now). For that I have
created a message handler which I have shown you before. The reason
for creating a seperate message handler is, to not interrupt the forms
activities. The messages would be put in a que and we need to get them
from the que. If we were not in a form we simple could have read the
que in a class running on a separate thread such as,

while(running)
{
try
{
getmessage((CMessage)Mailbox.Dequeue());
}
catch(Exception e)
{
}

here the que will block the thread, but since we are not doing
anything it is ok.

But my case since I am working with a form I cannot block the
Application.Run
since then then my form would be idle.

So when a message arrives I call the messagehanlers enque method, and
the message will be put in the que, then I will post a windows message
in the handler, this message will be received by the WndProc method,
in WndProc method I call a Deque method to get the received message
which will be returned to the forms message handling function through
a function delegate which was set up at the startup.

Thats why I need to set the MessageHanler to derive from nativeWindow
and thats where I am having problems with getting the parent.Handle

Thanks

I hope this made sense.
Nov 15 '05 #7

P: n/a
James,

Do you need that NativeWindow at all.
why you don't implement all queue logic in your form
for example

class MyForm:Form
{
void Engue(CMessage msg)
{
//Puts message in queue queue. Notify the form for new message in
the queue
//PostMessage to this.Handle or call this.BeginInvoke, which will
have similar effect
//However if you use BeginInvoke the message processing method will
be the next think run in the form when it finishes it current work. If you
use PostMessage notification will be qeued in the windows message queue
along with the other messages
//Both techniques won't block the sender
}

CMessage GetMessage()
{
}

//In case you use PoseMessage insted of this.BeginInvoke
protected override WndProc(....)
{
//Call procedure to process the message
switch(m.Msg)
{
case SPECIALMSG:
//call for processing the next enqueued message
return;
}
}
}

Tell me what you think about this
--
B\rgds
100

"James" <ja*****************@yahoo.com.au> wrote in message
news:e6**************************@posting.google.c om...
I think you have got the basic idea from my "not quite fully explained
messages", for that thank you!

I logic is a bit different. I will explain,

I have a form, and that form needs to process incommimg
messages(forget about sending messages for now). For that I have
created a message handler which I have shown you before. The reason
for creating a seperate message handler is, to not interrupt the forms
activities. The messages would be put in a que and we need to get them
from the que. If we were not in a form we simple could have read the
que in a class running on a separate thread such as,

while(running)
{
try
{
getmessage((CMessage)Mailbox.Dequeue());
}
catch(Exception e)
{
}

here the que will block the thread, but since we are not doing
anything it is ok.

But my case since I am working with a form I cannot block the
Application.Run
since then then my form would be idle.

So when a message arrives I call the messagehanlers enque method, and
the message will be put in the que, then I will post a windows message
in the handler, this message will be received by the WndProc method,
in WndProc method I call a Deque method to get the received message
which will be returned to the forms message handling function through
a function delegate which was set up at the startup.

Thats why I need to set the MessageHanler to derive from nativeWindow
and thats where I am having problems with getting the parent.Handle

Thanks

I hope this made sense.

Nov 15 '05 #8

P: n/a
Thank you for your reply. The problem I have is if I have the WndProc
method in the same form class would be that if I post a message it
will hold up my form. Thats what made me to have a different class to
have WndProc. I actually coded the way you mentioned to show that it
actually holds up the form, If you know any solution let me know.
Thanks for the help.

using System;
using System.Threading;
using System.Collections;
using System.Windows.Forms;
using System.Runtime.InteropServices;

public class form2 : System.Windows.Forms.Form
{
[DllImport("user32.dll", CharSet=CharSet.Auto,SetLastError=true)]
public static extern bool PostMessage(System.Windows.Forms.Message
Msg);

private Queue queue;

public form2(CMessageDelegate PostMessagetoRoot)
{
InitializeComponent();
queue = new Queue();
this.PostMessagetoRoot = PostMessagetoRoot;
}

private void InitializeComponent()
{
........
}
private Common.CMsgDelegate PostMessagetoRoot;
private System.Windows.Forms.Button button1;

public void Start()
{
Application.Run(this);

}

public void PostMessage(CMessage message)
{
Enqueue(message);
}

public void Enqueue(CMessage message)
{
queue.Enqueue(message);
System.Windows.Forms.Message msg =
System.Windows.Forms.Message.Create(this.Handle,12 34,(IntPtr)0,(IntPtr)0);
PostMessage(msg);
}

public void Shutdown()
{
this.Close();
}

private void button1_Click_1(object sender, System.EventArgs e)
{
PostMessageToCore("............");
}

protected override void WndProc(ref Message msg)
{

if (msg.Msg == 1234)
{

//for(int i=0;i<10000000000000;i++)
// i++;

CMessage message = GetMessage();

Message Handlers can go here!!!!!!

base.WndProc(ref msg);

}
}
private CMessage GetMessage()
{
return (CMessage)queue.Dequeue();
}
}
Nov 15 '05 #9

P: n/a
Hi stoitcho,

Just one more thing I forgot to mention. Actually thats the main
reason. I have separated the form and the message receiver is to
separate the que from the form, so that it will not hold up the form
while its processing. And also message handling will go here as well.
Tell me what you think.

Regards

James
Nov 15 '05 #10

P: n/a
Hi James,

Let me cover some points.

1) If the MessageHandler and the form are created by the same UI thread any
processing in the MessageHandler will hold up your form. Don't forget that
they share the same message loop. If they are not created by the same thread
you can not have parent/child releationship between them.

2) Let suppose that MessageHandler and the form are created from different
UI threads. When I send a message to the MessageHandler (Enque) it will keep
the form up and running But this is very cheap operation You just put the
message in the queue and post the message to the form to notify for a new
message arrival.

Eventually, the form will receive the windows message (in form's WndProc)
and will pull the message and start the message processing. This process is
executed in the form's UI thread so this will hold up the form as long as
the processing goes. In this case you don't gain anything having the
MessageHandler a separate window. Bear in mind that both SendMessage and
PostMessage API functions when the message cross the threads boundaries use
the message queue of the receiving thread and they do thread switching.

3) In case 2) one may thing "Yes, but when the form process the message the
objects in my applications can still posting (Enquing) messages". Think of
it. The code from the form's UI thread cannot post a message because the
thread is busy processing a message. Thus, only code running in different
thread of the form's UI thread can post a message. The same is true, as
well, in the scenario when all post(enque) logic is build-in the form
class. No sepparate MessageHandler is necessary.

To summarize (according to the information I have) the only advantage of
having MessageHandler as a separate window running in separate UI thread is
that you execute 'queue.Enqueue(message);' operation on separate thread.
This operation is so cheap that you don't have to even think of it.

Finally, whatever technique you may choose to implement your message handler
(as a separate window or build-in in the form class) in multithread
environment the operation of queue.Enqueue(message); has to be done in
protected fashion

Queue.Synchronized(queue.).Enqueue(message);

or

lock(queue.SyncRoot)
{
queue.Enqueue(message);
}

or any other method that will guarantee that no two or more thread will try
to add messages at the same time.

GetMessage operation dosn't have to be protected because it is executed only
form one thread

If you want to send/post private messages you should use messages in the
range of 0x0400 - 0xBFFF otherwise you can get in conflict with some system
messages(1234 is safe :-) )

Let me know what do you feel about this.
--
HTH
B\rgds
100
Nov 15 '05 #11

P: n/a
hello Stoitcho,

Thank you for the comments. They were very valuable for me.

I though about the comment you made about having two separate thread
one for the form and the message handler running on a separate thread.
You stated that that would make no difference since the message
handling function in the form would not allow any posting of messages
from the form until the form completes its message handling work.

But cant we make the message handling function in the form to be
defined as a function delegate and from the message handler class we
could execute this function, and hence would be executed on the
message handlers thread so the form would be free to do what ever it
wants. This is code. Your comments are welcome.

This is the message handler function. I have defined it to be a form.
using System;
using System.Collections;
using System.Windows.Forms;
using System.Runtime.InteropServices;
public class CMessageHandler : System.Windows.Forms.Form
{

[DllImport("user32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool PostMessage(System.Windows.Forms.Message
Msg);

private Queue queue;

private CMessageDelegate decodeMessage;
public CMessageHandler(CMessageDelegate decodeMessage)
{
queue = new Queue();
this.decodeMessage = decodeMessage;
}
public void Enqueue(CMessage message)
{
queue.Enqueue(message);

System.Windows.Forms.Message msg =
System.Windows.Forms.Message.Create((IntPtr)this.H andle,1234,(IntPtr)0,(IntPtr)0);

PostMessage(msg);
}

private CMessage GetMessage()
{
return (CMessage)queue.Dequeue();
}

protected override void WndProc(ref Message msg)
{
if (msg.Msg == 1234)
{
this.decodeMessage(GetMessage());

base.WndProc(ref msg);

}
}
}

here is the Form where all UI function is carried out. This Ui
application is Run by a separate program which is Wndows application.
using System;
using System.Threading;
using System.Windows.Forms;

public class form1 : System.Windows.Forms.Form
{
public form1(CMessageDelegate PostMessageToCore)
{
InitializeComponent();

msg_handler = new Thread(new ThreadStar(InitializeMessageHandler));
msg_handler.Start();

this.PostMessageToCore = PostMessageToCore;
}

private void InitializeMessageHandler()
{
CMessageHandler = new CMessageHandler(new
CMessageDelegate(DecodeMessage));

}

protected void DecodeMessage(CMessage message)
{
....message handling will be done here
}

private void InitializeComponent()
{
..........
}

private Common.CMessageDelegate PostMessageToCore;
private System.Windows.Forms.Button button1;
private CMessageHandler CMessageHandler;
private System.Windows.Forms.Button button2;
private Thread msg_handler;

public void Start()
{
Application.Run(this);
}

public void PostMessage(CMessage message)
{
CMessageHandler.Enqueue(message);
}

public void Shutdown()
{

this.Close();
}
}
Nov 15 '05 #12

P: n/a
Hi James,
I though about the comment you made about having two separate thread
one for the form and the message handler running on a separate thread.
You stated that that would make no difference since the message
handling function in the form would not allow any posting of messages
from the form until the form completes its message handling work.
Yes, if you notify the form with PostMessage. I tought this was your idea
since you wanted to have the handler of the form.

But cant we make the message handling function in the form to be
defined as a function delegate and from the message handler class we
could execute this function, and hence would be executed on the
message handlers thread so the form would be free to do what ever it
wants. This is code. Your comments are welcome.


Yes that is perfectly right. However, bare in mind that the message handling
function will be executed by a thread different from the one created the
form. this means that if you want to manipulate the form or any controls on
the form you need to call Form.Invoke method and switch the execution in the
form's UI thread, which if you do for all message processing you will get
almost what we have with the PostMessage notification

Ok. I think I got your idea so I'll post some working code. I'll make two
posts. One is using NativeWindow as a message handler and executing the
message processing function in the MessageHandler's thread.
However I'm little worried about the fact that we create an UI thread, which
is more expensive that the normal worker thread and a window. I'm not sure
if it's worth. Then I'll make a second post with a working example that do
the same thing but uses only a worker thread. I would recomend the second
one.

The first code (using the NativeWindow) follows. At the end of the code
there are some well-known problems that have to be taken care of.

---------------- Form class -------------------------------
using System;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;
using System.Threading;

namespace TestMessageHandler
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
private System.Windows.Forms.Button button1;
private CMessageHandler msg_handler;
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

Thread t = new Thread(new ThreadStart(InitializeMessageHandler));
t.Start();

}

private void InitializeMessageHandler()
{
msg_handler = new CMessageHandler(new CMessageDelegate(DecodeMessage));
//runns the message loop in the current thread.
Application.Run();
}

void DecodeMessage(string msg)
{
Console.WriteLine(msg);
Thread.Sleep(3000); //simulate long processing
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(112, 224);
this.button1.Name = "button1";
this.button1.TabIndex = 0;
this.button1.Text = "Post";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 273);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);

}
#endregion

public void PostMessage(string msg)
{
msg_handler.Enqueue(msg);
}

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}

private int mMessageNum = 0;
private void button1_Click(object sender, System.EventArgs e)
{
this.PostMessage(string.Format("Message #{0}", mMessageNum++));
}
}
}

----------------------- MessageHandler class ----------------------------

using System;
using System.Collections;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace TestMessageHandler
{
public delegate void CMessageDelegate(string msg);
public class CMessageHandler : System.Windows.Forms.NativeWindow
{

[DllImport("user32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool PostMessage(System.Windows.Forms.Message
Msg);

private Queue queue;

private CMessageDelegate decodeMessage;
public CMessageHandler(CMessageDelegate decodeMessage)
{
queue = new Queue();
this.decodeMessage = decodeMessage;
CreateParams cp = new CreateParams();

this.CreateHandle(cp);
}
public void Enqueue(string message)
{
queue.Enqueue(message);

System.Windows.Forms.Message msg =

System.Windows.Forms.Message.Create((IntPtr)this.H andle,1234,(IntPtr)0,(IntP
tr)0);

PostMessage(msg);
}

private string GetMessage()
{
return (string)queue.Dequeue();
}

protected override void WndProc(ref Message msg)
{
if (msg.Msg == 1234)
{
this.decodeMessage(GetMessage());

}
base.WndProc(ref msg);
}
}
}

Problems:
----------
The form has to destroy the MessageHandler when it's closing.
This could be not so easy, though. Imagine that you have several messages
waitng in the queue to be processed.
If you close the form the handler will keep sending the messages for
processing. So you might end up with disposed form in the middle of
processing a message.
Destroying the window should be done by calling NativeWindow object
DestroyHandle method. Internaly, I believe, it uses DestroyWindow API call.

In MSDN you can read about that API:
"...A thread cannot use DestroyWindow to destroy a window created by a
different thread. ...."

That's why you can't destroy the MessageHandler from inside the form's UI
thread.
You might have some special flag or message for closing the handler. Put
that message at the queue's head because otherwise you will have to wait for
the all messages in the queue to be processed and then the MessageHandler
will be shuted down. Of course it could be what exactly you are going for.

Either ways the form should wait the MessageHandler to be destroyed and then
it can proceed with its own closing. Otherwise, how I said, you may end up
with disposed form in the middle of a message processing.

In my next post I'll give you my other solution, which I BTW would recomend
because it is cheaper resource wise.

HTH
B\rgds
100
Nov 15 '05 #13

P: n/a
Hi James,
This is my second solution for implementing that message handler. This
solution uses only one worker thread that waits for the message to be posted
in the queue and calls the message processing function. Message processing
function is executed by this worker thread so if you want to manipulate the
form or its controls you have to switch the execution to the UI thread. You
can do that using Form's Invoke method.
----------------- Form class -------------------
using System;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;
using System.Data;

namespace MessageHandler2
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
private CMessageHandler mMsgHandler;

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

mMsgHandler = new CMessageHandler(new CMessageDelegate(ProcessMessage));
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(112, 224);
this.button1.Name = "button1";
this.button1.TabIndex = 0;
this.button1.Text = "Post";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 273);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);

}
#endregion
private void ProcessMessage(string msg)
{
Console.WriteLine(msg);
System.Threading.Thread.Sleep(1000);
}
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}

private int mMsgCount = 0;

private void button1_Click(object sender, System.EventArgs e)
{
mMsgHandler.Enqueue(string.Format("Message #{0}", mMsgCount++));
}
}
}

-------------------------- Message Handler class -----------------
using System;
using System.Collections;
using System.Threading;

namespace MessageHandler2
{
/// <summary>
/// Summary description for MessageHandler.
/// </summary>
public delegate void CMessageDelegate(string msg);
public class CMessageHandler
{
private Queue queue = new Queue();
CMessageDelegate mMsgHandler = null;
ManualResetEvent mMsgInTheQueue = new ManualResetEvent(false);
public CMessageHandler(CMessageDelegate msgHandler)
{
mMsgHandler = msgHandler;
Thread t = new Thread(new ThreadStart(MessageLoop));
t.IsBackground = true;
t.Start();
}

public void Enqueue(string message)
{
lock(queue.SyncRoot)
{
queue.Enqueue(message);
mMsgInTheQueue.Set();
}

}

private string GetMessage()
{
string msg;
lock(queue.SyncRoot)
{
msg = (string)queue.Dequeue();
if(queue.Count == 0) mMsgInTheQueue.Reset();
}
return msg;
}

void MessageLoop()
{
while(true)
{
mMsgInTheQueue.WaitOne();
mMsgHandler(GetMessage());
}

}
}
}
Problems:
------------
This solution has the same problems as the one with NativeWindows
class(problems that may arise during the form closing)

Tell me what you think about both solutions.

--
HTH
B\rgds
100
Nov 15 '05 #14

P: n/a
Hi Stoitcho,

excellent work, thank you for spending so much time and for a the work.
Nov 15 '05 #15

P: n/a
Thanks James,

Thanx, I appreciate that. Tell me if you like one of the solutions.
If you have further questions or difficulties with solving some of the
problems I mentioned or any others of course don't hesitate to post them. I
and the rest of the community members we are here to help you.

--
B\rgds
100

"James" <ja*****************@yahoo.com.au> wrote in message
news:e6*************************@posting.google.co m...
Hi Stoitcho,

excellent work, thank you for spending so much time and for a the work.

Nov 15 '05 #16

This discussion thread is closed

Replies have been disabled for this discussion.