C# wpf 实现窗体间消息传输

C# wpf 实现窗体间消息传输

       本文介绍WPF使用windows 自带的User32.dll中的SendMessage和FindWindow函数实现两个窗体应用程序的消息传递。
       其中发送消息和winform的实现方式类似,但接收消息由于wpf的windows类没有类似于Form类的DefWndProc来处理消息,所以会略显复杂。

一、导入外部dll

       User32.dll在c盘windows\system32目录下,将它复制到VS的wpf项目中bin\debug文件夹下即可。WM_COPYDATA作为系统消息。

//定义一个全局变量作为消息,WM_COPYDATA消息的标识符为0x004A
        public const int WM_COPYDATA = 0x004A;

        //使用windows系统提供的user32.dll
        [DllImport("User32.dll", EntryPoint = "SendMessage")]
        private static extern int SendMessage(int hWnd, int Msg, int wParam, IntPtr lParam);

        [DllImport("User32.dll", EntryPoint = "FindWindow")]
        private static extern int FindWindow(string lpClassName, string lpWindowName);

二、定义传递信息的结构体

这个结构体承载消息的信息,之后以Intptr的形式作为SendMessage的参数。

//定义传递信息的结构体,之后将其转化为Intptr后作为SendMessage的一个参数
    public struct COPYDATASTRUCT
    {
        public IntPtr dwData;
        public int cbData;
        [MarshalAs(UnmanagedType.LPStr)]
        public string lpData;
    }

三、发送消息窗体按钮函数

       点击发送消息的窗体的发送按钮,发送textbox1中的消息。
       需要注意的是其中用了c#自带的marshal类来实现struct与Inptr之间的转化。

//发送消息
        private void Button_Click(object sender, RoutedEventArgs e)
        {
        	//通过窗体类名获取被发送对象的句柄,此处该对象为window2
            int hWnd = FindWindow(null, "Window2");
            if (hWnd == 0)
            {
                MessageBox.Show("未找到消息接受者!");
            }
            else
            {
                byte[] sarr = System.Text.Encoding.Default.GetBytes(textBox1.Text);
                int len = sarr.Length;
                COPYDATASTRUCT cds;
                cds.dwData = (IntPtr)Convert.ToInt16(0);//可以是任意值,本例中不用到
                cds.cbData = len + 1;//指定lpData内存区域的字节数
                cds.lpData = "MainWindow:" + textBox1.Text;//发送给目标窗口所在进程的数据
                
                //使用marshal将struct转化为intptr
                // Initialize unmanged memory to hold the struct.
                IntPtr pnt = Marshal.AllocHGlobal(Marshal.SizeOf(cds));
                Marshal.StructureToPtr(cds, pnt, false);
                SendMessage(hWnd, WM_COPYDATA, 0, pnt);
                richTextBox1.AppendText("MainWindow:" + textBox1.Text + "\n");
            }
            textBox1.Text = "";
        }

四、接收消息窗体函数

4.1 创建HwndSource对象

       创建HwndSource对象,然后利用其AddHook方法来将所有的windows消息附加到一个现有的事件中。
       WndProc函数就是WPF中类似于winform重载DefWndProc来处理消息的步骤。

//将此函数注册到window2窗体的SourceInitialized事件后,WndProc函数就会被用于处理收到的消息
void WSInitialized(object sender, EventArgs e)
        {
            HwndSource hs = PresentationSource.FromVisual(this) as HwndSource;
            hs.AddHook(new HwndSourceHook(WndProc));
        }

4.2 WndProc消息处理函数

       根据msg消息值决定如何处理消息,仍然用Marshal类将Intptr句柄转化回struct。

//消息处理
        protected IntPtr  WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            switch (msg)
            {
                case WM_COPYDATA:
                    COPYDATASTRUCT cds = new COPYDATASTRUCT();
                    Type t = cds.GetType();
                    //使用marshal将intptr转换为struct
                    cds = (COPYDATASTRUCT )Marshal.PtrToStructure (lParam , typeof(COPYDATASTRUCT)); 
                    string strResult = cds.lpData + "\n";
                    richTextBox1.AppendText(strResult);
                    break;
            }
            return IntPtr.Zero;
        }

参考文献:
在WPF中使用WindowProc处理消息
WPF中的WndProc
C# byte[]、struct、intptr的相互转换

好的,我可以为您提供这样的实现思路: 1. 创建一个WPF窗体作为登录窗体,并添加用户名和密码的输入框以及登录按钮。 2. 在登录按钮的Click事件中,验证用户名和密码是否正确,如果正确则将一个bool类型的变量设置为true,并关闭登录窗体。 3. 在主窗体中,在窗体的Loaded事件中添加一个判断,如果bool变量为true,则执行mainload方法。 4. 在主窗体中创建一个方法mainload,实现窗体的初始化操作。 下面是一个简单的示例代码: LoginWindow.xaml.cs ``` public partial class LoginWindow : Window { public bool IsLoginSuccess { get; set; } public LoginWindow() { InitializeComponent(); } private void btnLogin_Click(object sender, RoutedEventArgs e) { // 验证用户名和密码是否正确 bool isUserValid = true; // 假设用户名和密码都正确 if (isUserValid) { IsLoginSuccess = true; this.Close(); } else { MessageBox.Show("用户名或密码错误!"); } } } ``` MainWindow.xaml.cs ``` public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); this.Loaded += MainWindow_Loaded; } private void MainWindow_Loaded(object sender, RoutedEventArgs e) { LoginWindow loginWindow = new LoginWindow(); loginWindow.ShowDialog(); if (loginWindow.IsLoginSuccess) { mainload(); } else { this.Close(); } } private void mainload() { // TODO: 执行主窗体的初始化操作 } } ``` 希望这个示例代码能够对您有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值