在delphi中,我可以像这样创建自己的消息,
const MY_MESSAGE = WM_USER+100;
procedure MyMessage(var Msg: TMessage); message MY_MESSAGE;
procedure TForm1.MyMessage(var Msg: TMessage);
begin
....
end;
在c#中我可以这样做
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);
}
但我不想覆盖WndProc(),我想创建自己的MyMessage()函数,当我发布消息时它会运行。
我该怎么做? 感谢。
答案 0 :(得分:16)
这是Delphi的一个特殊功能,它在C#中没有类似功能。在C#中,您需要覆盖WndProc()
。
答案 1 :(得分:9)
使用.NET
反射和自定义属性可以完成看起来非常相似的内容。我认为性能可以用于生产,但不值得,因为这仍然需要覆盖WndProc
来调用自定义调度程序,并且一旦WndProc
到位,它需要一行代码调用自定义调度程序或3行代码来编写正确的switch
语句。如果代码是从“基类”调用的,那么你继承它可能是值得的。
一旦“管道”完成,代码将如何显示:
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);
}
}
这是“管道”。一个很多更多的代码实现代码来识别所有Windows消息处理程序例程(基于自定义属性),并使用几个字典缓存所有这些结果(因此只需要完成繁重的工作一次)。
// 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);
}
}
}