9

在delphi中,我可以像这样创建自己的消息,

const MY_MESSAGE = WM_USER+100;
procedure MyMessage(var Msg: TMessage); message MY_MESSAGE;

procedure TForm1.MyMessage(var Msg: TMessage);
begin
....
end;

bu在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() 函数,当我发布消息时它会运行。

我怎样才能做到这一点?谢谢。

4

2 回答 2

16

这是 Delphi 的一个特殊功能,在 C# 中没有类似的功能。在 C# 中,您需要覆盖WndProc().

于 2011-04-18T19:30:32.627 回答
9

看起来非常相似的事情可以使用.NET反射和自定义属性来完成。我认为性能可以用于生产用途,但不值得,因为这仍然需要覆盖WndProc调用自定义调度程序,并且一旦WndProc到位,调用自定义调度程序需要一行代码或 3 行代码写一个适当的switch陈述。如果代码是从“基”类调用的,那么从它继承可能是值得的。

以防万一您想知道,我这样做是因为我正在学习 C# + .NET,并且很好奇可以做什么。

完成“管道”后,代码如下所示:

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);
        }
    }
    
}
于 2011-04-19T07:23:58.423 回答