zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    hdu 1028 Ignatius and the Princess III (n的划分)
    CodeForces
    poj 3254 Corn Fields (状压DP入门)
    HYSBZ 1040 骑士 (基环外向树DP)
    PAT 1071 Speech Patterns (25)
    PAT 1077 Kuchiguse (20)
    PAT 1043 Is It a Binary Search Tree (25)
    PAT 1053 Path of Equal Weight (30)
    c++ 常用标准库
    常见数学问题
  • 原文地址:https://www.cnblogs.com/zhouxiaoyun/p/5797485.html
Copyright © 2011-2022 走看看