• Winform 程序嵌入WPF程序 并发送消息


    废话不多说,先看解决方案目录

    WindowsFormsDemo是主程序,WpfApp是嵌入的WPF程序,先看WPF程序,程序默认启动的页面是MainWindow.xaml,这里注释掉App.xaml里的StartupUri="MainWindow.xaml",后台设置启动的Uri,将原来的空的App类改成一些内容(也可以不改)

    /// <summary>
        /// App.xaml 的交互逻辑
        /// </summary>
        public partial class App : Application
        {
            public App()
            {
                Application.Current.DispatcherUnhandledException += Current_DispatcherUnhandledException;
            }
    
            void Current_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
            {
                // 这里通常需要给用户一些较为友好的提示,并且后续可能的操作
                MessageBox.Show(e.Exception.Message, "意外的操作", MessageBoxButton.OK, MessageBoxImage.Information);
    
                e.Handled = true;//我们很抱歉,当前应用程序遇到一些问题,该操作已经终止,请进行重试,如果问题继续存在,请联系管理员.
            }
        }

    添加Program启动类并加入主方法Main,尽管修改了但是启动程序仍然会报错,需要右键设置工程属性设置启动对象

    下面看看启动类里的东西

    class Program
        {
            [STAThread]
            static void Main(string[] args)
            {
                // 校验启动的参数,未设置参数为非法启动
                if (null == args || args.Length <= 0)
                {
                    MessageBox.Show("非法启动!");
                    return;
                }
                // 获取参数,在WindowsFormsDemo里启动的时候设置,参数的规则自己设置
                string activeParameter = args[0];
                string[] parameters = activeParameter.Split(',');
    
                try
                {
                    App app = new App();
                    string activeName = parameters[0];
                    if (activeName == "UploadFile")
                    {
                        MainWindow mainWindow = new MainWindow();
                        // 获取主界面的句柄(最后一个参数),向主窗体发送消息需要根据主窗体的句柄来发送
                        // 在启动这个WpfApp 进程的时候设置最后一个参数为主窗体句柄
                        OperationContainer.ContainerPlayPtr = new IntPtr(Convert.ToInt32(parameters[parameters.Length - 1]));
                        app.MainWindow = mainWindow;
                        app.StartupUri = new Uri("MainWindow.xaml", UriKind.Relative);
                    }
                    // 参数就是拼接的字符串,看WindowsFormsDemo主窗体的拼接方式
                    GetParameters(parameters[1]);
                    app.Run();
                    App.Main();
                }
                catch (Exception e)
                {
                    MessageBox.Show(e.Message);
                }
            }
    
            /// <summary>
            /// 分割参数(参数规则看WindowsFormsDemo启动时设置的参数字符串)
            /// </summary>
            /// <param name="param"></param>
            static void GetParameters(string param)
            {
                string[] strs = param.Split('&'); ;
                Dictionary<string, string> dic = new Dictionary<string, string>();
                foreach (var item in strs)
                {
                    string[] key = item.Split('=');
                    dic.Add(key[0], key[1]);
                }
    
                // 静态来存放参数值
                OperationContainer.ServerIP = dic["ServerIP"];
                OperationContainer.Type = dic["Type"];
                OperationContainer.UserID = dic["UserID"];
                OperationContainer.CaseID = dic["CaseID"];
            }

    这个地方要注意的是,我开始设置参数值的时候是给MainWindow.xaml.cs里的MainWindow设置属性的方式传的,在启动App并对MainWindow对象实例化,取得参数赋给MainWindow的属性,但是程序启动之后过了一会儿才会赋值过去,不知道是不是窗体渲染的次序问题

     操作容器缓存类OperationContainer

    /// <summary>
        /// 常见操作缓存类
        /// </summary>
        public class OperationContainer
        {
            /// <summary>
            /// 主容器窗口句柄
            /// </summary>
            public static IntPtr ContainerPlayPtr = IntPtr.Zero;
    
            #region 长连接属性
            public static string ServerIP = "";
    
            public static string Type = "";
    
            public static string UserID = "";
    
            public static string UserName = "admin";
    
            public static string CaseID = "";
            #endregion
        }

    MainWindow.xaml里的内容,一个按钮和按钮的点击事件,点击的时候向主窗体发送消息

    <Window x:Class="WpfApp.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
        <Grid Background="#FFA1E5DB">
            <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="10,10,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="btn_Upload" />
        </Grid>
    </Window>

    MainWindow.xaml里的后台代码,消息发送

    /// <summary>
        /// MainWindow.xaml 的交互逻辑
        /// </summary>
        public partial class MainWindow : Window
        {
            /// <summary>
            /// 当前进程句柄
            /// </summary>
            //public IntPtr CurWindows { get; set; }
    
            /// <summary>
            /// 主进程句柄
            /// </summary>
            public IntPtr ContainerPlayPtr { get; set; }
    
            public int UploadType { get; set; }
    
            public string CaseID { get; set; }
    
            #region 进程消息处理
    
            [DllImport("User32.dll", EntryPoint = "SendMessage")]
            private static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);
    
            /// <summary>
            /// 向主窗体发送消息
            /// </summary>
            /// <param name="success">标识是否操作成功,可根据自己使用情况来定</param>
            private void Send(int success)
            {
                // 需要根据主窗体的句柄来发送,OperationContainer.ContainerPlayPtr在App程序初始化的时候已经取得的主窗体的句柄
                SendMessage(OperationContainer.ContainerPlayPtr, Message.WM_MSG, success, 0);
            }
    
            #endregion
    
            public MainWindow()
            {
                InitializeComponent();
            }
    
            private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                //MsgForm form = new MsgForm();
                //CurWindows = form.Handle;
                //ContainerPlayPtr = OperationContainer.ContainerPlayPtr;
                //MessageBox.Show("容器窗体句柄:" + ContainerPlayPtr.ToInt32());
                // 取得参数
                UploadType = Convert.ToInt32(OperationContainer.Type);
                CaseID = OperationContainer.CaseID;
            }
    
            private void btn_Upload(object sender, RoutedEventArgs e)
            {
                MessageBox.Show(CaseID);
                // 向主窗体发送消息
                Send(0);
            }
        }

    其中的消息枚举

    /// <summary>
        /// 消息枚举
        /// </summary>
        public class Message
        {
            public const int USER = 0x0400;
            public const int WM_MSG = USER + 101;
        }

    至于Controls里的内容暂时还没用到

    有了上面的内容,这个时候启动WpfApp应该会提示非法启动,给启动参数赋初始值  args = new string[] { "UploadFile,ServerIP=127.0.0.1&Type=2&UserID=xx&CaseID=604dffdd-0f8f-430d-8ca4-1d9714ba7609,11202" };即可成功启动

    下面看看主窗体里的内容,先看下容器类AppContainer

    public class AppContainer
        {
            #region 注册API函数
            [DllImport("user32.dll", EntryPoint = "GetWindowThreadProcessId", SetLastError = true,
                 CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
            private static extern long GetWindowThreadProcessId(long hWnd, long lpdwProcessId);
            [DllImport("user32.dll")]
            private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
            [DllImport("user32.dll", SetLastError = true)]
            public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
            [DllImport("user32.dll", EntryPoint = "GetWindowLongA", SetLastError = true)]
            private static extern long GetWindowLong(IntPtr hwnd, int nIndex);
            [DllImport("user32.dll", EntryPoint = "SetWindowLong", CharSet = CharSet.Auto)]
            private static extern IntPtr SetWindowLongPtr32(HandleRef hWnd, int nIndex, int dwNewLong);
            [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", CharSet = CharSet.Auto)]
            internal static extern IntPtr SetWindowLongPtr64(HandleRef hWnd, int nIndex, int dwNewLong);
            [DllImport("user32.dll", SetLastError = true)]
            private static extern long SetWindowPos(IntPtr hwnd, long hWndInsertAfter, long x, long y, long cx, long cy, long wFlags);
            [DllImport("user32.dll", SetLastError = true)]
            private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);
            [DllImport("user32.dll", EntryPoint = "PostMessageA", SetLastError = true)]
            private static extern bool PostMessage(IntPtr hwnd, uint Msg, uint wParam, uint lParam);
            [DllImport("user32.dll", SetLastError = true)]
            private static extern IntPtr GetParent(IntPtr hwnd);
            [DllImport("user32.dll", EntryPoint = "ShowWindow", SetLastError = true)]
            static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
            [DllImport("user32.dll")]
            private static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
    
    
    
            private const int SWP_NOOWNERZORDER = 0x200;
            private const int SWP_NOREDRAW = 0x8;
            private const int SWP_NOZORDER = 0x4;
            private const int SWP_SHOWWINDOW = 0x0040;
            private const int WS_EX_MDICHILD = 0x40;
            private const int SWP_FRAMECHANGED = 0x20;
            private const int SWP_NOACTIVATE = 0x10;
            private const int SWP_ASYNCWINDOWPOS = 0x4000;
            private const int SWP_NOMOVE = 0x2;
            private const int SWP_NOSIZE = 0x1;
            private const int GWL_STYLE = (-16);
            private const int WS_VISIBLE = 0x10000000;
            private const int WM_CLOSE = 0x10;
            private const int WS_CHILD = 0x40000000;
    
            private const int SW_HIDE = 0; //{隐藏, 并且任务栏也没有最小化图标}
            private const int SW_SHOWNORMAL = 1; //{用最近的大小和位置显示, 激活}
            private const int SW_NORMAL = 1; //{同 SW_SHOWNORMAL}
            private const int SW_SHOWMINIMIZED = 2; //{最小化, 激活}
            private const int SW_SHOWMAXIMIZED = 3; //{最大化, 激活}
            private const int SW_MAXIMIZE = 3; //{同 SW_SHOWMAXIMIZED}
            private const int SW_SHOWNOACTIVATE = 4; //{用最近的大小和位置显示, 不激活}
            private const int SW_SHOW = 5; //{同 SW_SHOWNORMAL}
            private const int SW_MINIMIZE = 6; //{最小化, 不激活}
            private const int SW_SHOWMINNOACTIVE = 7; //{同 SW_MINIMIZE}
            private const int SW_SHOWNA = 8; //{同 SW_SHOWNOACTIVATE}
            private const int SW_RESTORE = 9; //{同 SW_SHOWNORMAL}
            private const int SW_SHOWDEFAULT = 10; //{同 SW_SHOWNORMAL}
            private const int SW_MAX = 10; //{同 SW_SHOWNORMAL}
            private const int HWND_TOP = 0x0;
            private const int WM_COMMAND = 0x0112;
            private const int WM_QT_PAINT = 0xC2DC;
            private const int WM_PAINT = 0x0001;
            private const int WM_SIZE = 0x0001;
    
            #endregion
    
            [SecuritySafeCritical]
            internal static void MoveWindow(Process app, Control control)
            {
                if (app != null)
                {
                    MoveWindow(app.MainWindowHandle, 0, 0, control.Width, control.Height, true);
                }
            }
    
            [SecuritySafeCritical]
            internal static void SetWindowLong(HandleRef handleRef)
            {
                SetWindowLong(handleRef, GWL_STYLE, WS_VISIBLE);
            }
    
            [SecuritySafeCritical]
            internal static IntPtr SetWindowLong(HandleRef hWnd, int nIndex, int dwNewLong)
            {
                if (IntPtr.Size == 4)
                {
                    return SetWindowLongPtr32(hWnd, nIndex, dwNewLong);
                }
    
                return SetWindowLongPtr64(hWnd, nIndex, dwNewLong);
            }
        }

    这段代码是一同事写的,拿来直接用就可以了,其中上半段是windows的函数,下面的三个方法是拖动主窗体改变主窗体大小时,设置嵌套的窗体内容

    看下主窗体里的代码

    public partial class MainForm : Form
        {
            public MainForm()
            {
                InitializeComponent();
            }
    
            Process _process;
            bool isFirst = false;
    
            private void MainForm_Load(object sender, EventArgs e)
            {
                Process[] processs = Process.GetProcessesByName("WpfApp.exe");
                foreach (var item in processs)
                {
                    item.Kill();
                }
    
                //string strPath = this.GetType().Assembly.Location;
                //string baseDir = Path.Combine(strPath.Substring(0, strPath.LastIndexOf("\")), "");
                string fileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "WpfApp.exe");
    
                if (File.Exists(fileName))
                {
                    // 设置消息参数
                    string param = "ServerIP=127.0.0.1&Type=2&UserID=xx&CaseID=604dffdd-0f8f-430d-8ca4-1d9714ba7609";
                    ProcessStartInfo startInfo = new ProcessStartInfo(fileName);
    
                    startInfo.Arguments = "UploadFile," + param + "," + this.Handle;
                    startInfo.UseShellExecute = true;
                    startInfo.CreateNoWindow = true;
                    startInfo.WorkingDirectory = "";
                    startInfo.WindowStyle = ProcessWindowStyle.Hidden;
    
                    _process = Process.Start(startInfo);
                    _process.EnableRaisingEvents = true;
                    WaitForInputIdle();
                    EmbedProcess(_process);
                }
                else
                    MessageBox.Show("未找到需要启动的exe文件");
                isFirst = true;
            }
    
            private void WaitForInputIdle()
            {
                while (_process.MainWindowHandle == IntPtr.Zero)
                {
                    _process.Refresh();
                    _process.MainWindowHandle.ToInt32();
                }
            }
    
            /// <summary>
            /// 嵌入程序
            /// </summary>
            private void EmbedProcess(Process process)
            {
                if (process != null && !(process.MainWindowHandle == IntPtr.Zero))
                {
                    try
                    {
                        // Put it into this form
                        AppContainer.SetParent(process.MainWindowHandle, panel1.Handle);
                        // Remove border and whatnot               
                        AppContainer.SetWindowLong(new HandleRef(this, process.MainWindowHandle));
                        // Move the window to overlay it on this window
                        AppContainer.MoveWindow(_process, panel1);
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                }
            }
    
            private void MainForm_Resize(object sender, EventArgs e)
            {
                // 设置窗体填充主窗体
                if (isFirst)
                    AppContainer.MoveWindow(_process, this);
            }
    
            public string Prams { get; set; }
    
            [DllImport("User32.dll", EntryPoint = "SendMessage")]
            private static extern int SendMessage(IntPtr hWnd, int msg, uint wParam, uint lParam);
    
            // 响应和处理自定义消息
            protected override void DefWndProc(ref System.Windows.Forms.Message m)
            {
                switch (m.Msg)
                {
                    case Message.WM_MSG://处理接收到的消息
                        int success = m.WParam.ToInt32();
                        if (success == 0)
                            MessageBox.Show("成功");
                        break;
                    default:
                        base.DefWndProc(ref m);
                        break;
                }
            }
    
            public class Message
            {
                public const int USER = 0x0400;
                public const int WM_MSG = USER + 101;
            }
        }

    以上就是所有的代码,这个主要是最近开发ActiveX控件,考虑Winform 实现特效比较麻烦,所以用嵌入WPF的方式实现

     demo 代码 http://download.csdn.net/detail/huayun1010/9609988

  • 相关阅读:
    排序算法-简单选择排序
    pygame模块的简介
    python设计模式之工厂模式
    一次完整的HTTP请求流程(当我们在浏览器输入一个URL后,发生了什么)
    HTTP协议,TCP、UDP协议
    Django rest framework框架中有哪些组件
    flask
    Flask上下文管理
    mac如何开启两个vmware虚拟机
    HTTP状态码
  • 原文地址:https://www.cnblogs.com/zhouxiaoyun/p/5797485.html
Copyright © 2020-2023  润新知