C# 有相当于 Delphi 的 message 关键字吗?

发布于 2024-11-02 09:51:42 字数 627 浏览 1 评论 0原文

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

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

清泪尽 2024-11-09 09:51:42

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

That's a special feature of Delphi of which there is no analogue in C#. In C# you need to override WndProc().

不必你懂 2024-11-09 09:51:42

看起来非常相似的事情可以使用.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);
        }
    }
    
}

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.

Just in case you were wondering, I'm doing this because I'm lerarning C# + .NET and was curious what could be done.

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);
        }
    }
    
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文