Reputation: 13441
In delphi, I can create my own message like this,
const MY_MESSAGE = WM_USER+100;
procedure MyMessage(var Msg: TMessage); message MY_MESSAGE;
procedure TForm1.MyMessage(var Msg: TMessage);
begin
....
end;
bu in c# I can do that like this
public static uint ms;
protected override void WndProc(ref Message m)
{
if(m.Msg == ms)
MessageBox.Show("example");
else
base.WndProc(ref m);
}
void Button1Click(object sender, EventArgs e)
{
PostMessage(HWND_BROADCAST,ms,IntPtr.Zero,IntPtr.Zero);
}
but I don't want to override WndProc(), I want to create my own MyMessage() function, and when I post message it will run.
How can I do that? Thanks.
Upvotes: 9
Views: 1198
Reputation: 25678
Something that looks very similar can be done using .NET
reflection and custom attributes. I think performance would be OK for production use, but not worth it since this still requires overriding WndProc
to call the custom dispatcher, and once the WndProc
is put into place, it takes one line of code to call the custom dispatcher OR 3 lines of code to write a proper switch
statement. If the code is called from a "base" class you then inherit from it might be worth it.
Here's how the code would look like, once the "plumbing" is done:
public partial class Form1 : Form
{
private const int WM_MOUSEMOVE = 0x0200;
// This is the Delphi-lookalike declaration for the WM_MOUSEMOVE handler.
// I'd say it looks very much "alike!"
[WinMessageHandler(WM_MOUSEMOVE)]
public bool UnHandler(ref Message X)
{
this.Text = "Movement";
return false;
}
// While simple, this is unfortunately a deal-breaker. If you need to go through the
// trouble of writing this stub WndProc, might as well write a proper switch statement
// and call the handler directly.
protected override void WndProc(ref Message m)
{
if (!WinMessageDispatcher.Dispatch(this, ref m)) base.WndProc(ref m);
}
}
And here's the "plumbing". A lot more code that implements the code to identify all windows message handler routines (based on custom attribute), and cache all those results using a couple of dictionaries (so the heavy-lifting only needs to be done once).
// Custom attribute to set message ID
class WinMessageHandler : System.Attribute
{
public int Msg;
public WinMessageHandler(int Msg) { this.Msg = Msg; }
}
class WinMessageDispatcher
{
// This is cached for the life of the application, it holds the required per-type
// dispatching information.
private class WinMessageDispatcher_PerType
{
private Dictionary<int, System.Reflection.MethodInfo> dict;
// generic handler
public bool HandleMessage(object OnInstance, ref Message msg)
{
System.Reflection.MethodInfo method;
if (dict.TryGetValue(msg.Msg, out method))
{
// Set up the call
object[] p = new object[1];
p[0] = msg;
return (bool)method.Invoke(OnInstance, p);
msg = p[0];
}
else
{
return false;
}
}
// Constructor, initializes the "dict"
public WinMessageDispatcher_PerType(Type t)
{
dict = new Dictionary<int, System.Reflection.MethodInfo>();
foreach (var method in t.GetMethods())
{
var attribs = method.GetCustomAttributes(typeof(WinMessageHandler), true);
if (attribs.Length > 0)
{
// Check return type
if (method.ReturnParameter.ParameterType != typeof(bool)) throw new Exception(string.Format("{0} doesn't return bool", method.Name));
// Check method parameters
var param = method.GetParameters();
if (param.Length != 1) throw new Exception(string.Format("{0} doesn't take 1 parameter", method.Name));
// Ooops! How do I check the TYPE of the "ref" parameter?
if (!param[0].ParameterType.IsByRef) throw new Exception(string.Format("{0} doesn't take a ref parameter of type System.Windows.Forms.Message but a parameter of type {1}", method.Name, param[0].ParameterType.ToString()));
// Add the method to the dictionary
dict.Add(((WinMessageHandler)attribs[0]).Msg, method);
}
}
}
}
// Dictionary to link "Types" to per-type cached implementations
private static Dictionary<Type, WinMessageDispatcher_PerType> dict;
// Static type initializer
static WinMessageDispatcher()
{
dict = new Dictionary<Type, WinMessageDispatcher_PerType>();
}
// Message dispatcher
public static bool Dispatch(object ObjInstance, ref Message msg)
{
if (ObjInstance == null) return false;
else
{
WinMessageDispatcher_PerType PerType;
lock (dict)
{
if (!dict.TryGetValue(ObjInstance.GetType(), out PerType))
{
PerType = new WinMessageDispatcher_PerType(ObjInstance.GetType());
dict.Add(ObjInstance.GetType(), PerType);
}
}
return PerType.HandleMessage(ObjInstance, ref msg);
}
}
}
Upvotes: 9
Reputation: 613412
That's a special feature of Delphi of which there is no analogue in C#. In C# you need to override WndProc()
.
Upvotes: 16