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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM