C#是否具有Delphi的消息关键字?

时间:2011-04-18 19:28:15

标签: c# delphi windows-messages

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

我该怎么做? 感谢。

2 个答案:

答案 0 :(得分:16)

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

答案 1 :(得分: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);
        }
    }

}