控件进程化,32位程序做大内存消耗时存在内存不够用时,特此记录解决方案,控件进程化,模块进程化

控件进程化,32位程序做大内存消耗时存在内存不够用时,特此记录解决方案,控件进程化,模块进程化...

文章尾部有完整demo下载

前端时间公司做了图片视频分析处理的项目,图片支持4k,6k甚至勉强支持8k;因为处理的方式很多,各模块之前不能切换后销毁,用户需要来回切换的,针对这个问题,每个模块都会加载图片,图片过大后程序内存告急,且程序是32位的,即使开启了大内存(32位开启大内存)的支持依然不是很好的解决,内存占用过高很容易被360告警,所以项目上最后的解决方案就是进程化各个模块!

通俗点讲就是,主进程启动后,会再启动子进程,子进程上会加载局部模块,附属于主进程,主进程退出后,子进程也终止,且子进程悬浮在主进程界面之上,所以例如打开遮罩时,需要发送命令到子进程,子进程自己再开启遮罩才能解决。

公司封装了几个dll,服务于快捷进程化开发,为此我精简成2个库Cal.Wpf.Part、Cal.Wpf.PartHost

Cal.Wpf.Part  辅助代码

Cal.Wpf.PartHost 子进程依赖的启动程序exe,如果有多个,该程序会生成多个按进程分

先大致看下效果:

一个主进程,2个子进程

控件进程化,32位程序做大内存消耗时存在内存不够用时,特此记录解决方案,控件进程化,模块进程化_第1张图片

下面是所有相关的dll

 控件进程化,32位程序做大内存消耗时存在内存不够用时,特此记录解决方案,控件进程化,模块进程化_第2张图片

实现原理:主程序启动后,传递窗口句柄并启动子程序,设置子程序的所有者句柄为主程序的,让其绑定在一起;程序之间利用TcpChannel实现数据通讯,特别啰嗦一句就是子程序永远悬浮于主程序之上。

下面开始针对demo进行使用说明:

1、引用Cal.Wpf.Part.dll、Cal.Wpf.PartHost.exe

2、针对自定义的控件创建**Host.xaml(承载)、**Patrt.cs(辅助类)

3、**Host.xaml 引用 Cal.Wpf.Part.dll,并显示占位


    
        
    

using Cal.Wpf.Part.Remoting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace ProcessDemo
{
    /// 
    /// UserControlHostControl.xaml 的交互逻辑
    /// 
    public partial class CustomUserControlHostControl : UserControl, IDisposable
    {
        public CustomUserControlHostControl()
        {
            InitializeComponent();
        }

        ~CustomUserControlHostControl()
        {
            Dispose();
        }

        public void Dispose()
        {
            partHost.Dispose();
        }

        /// 
        /// 收到进程的事件推送时
        /// 
        public event MessageEventHandler ReceiveCommand
        {
            add
            {
                partHost.ReceiveCommand += value;
            }
            remove
            {
                partHost.ReceiveCommand -= value;
            }
        }

        /// 
        /// 设置在独立进程中运行的控件
        ///       
        /// 父窗口句柄
        public void InitPartControl(IntPtr parentWindowHandler)
        {
            partHost.InitPartControl(typeof(CustomUserControlPart), parentWindowHandler);
        }

        /// 
        /// 发送消息
        /// 
        /// 
        public void SendMsg(string msg)
        {
            partHost.SendCommand(new ProcessMessage()
            {
                Body = msg,
                Command = 1
            });
        }
    }
}

4、 **Patrt.cs实现接口IPart

using Cal.Wpf.Part;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace ProcessDemo
{
    public class CustomUserControlPart : IPart
    {
        /// 
        /// 逻辑主控件
        /// 
        private CustomUserControl control;

        /// 
        /// 向主进程发消息时
        /// 
        public event Cal.Wpf.Part.Remoting.MessageEventHandler SendCommand;

        /// 
        /// 进程调用,需要支援释放了
        /// 
        /// 
        public void Dispose()
        {
            if (control != null)
            {
                control.SendMsg -= Control_SendMsg;
            }
        }

        /// 
        /// 收到主进程消息时
        /// 
        /// 
        public void ExecuteCommand(Cal.Wpf.Part.Remoting.ProcessMessage message)
        {
            if (message == null || message.Body == null) return;

            control.SetMsg(message.Body.ToString());
        }

        /// 
        /// 进程调用,获取当前插件的展示界面
        /// 
        /// 
        public FrameworkElement GetPartControl()
        {
            if (control == null)
            {
                control = new CustomUserControl();
                control.SendMsg += Control_SendMsg;
            }
            return control;
        }

        /// 
        /// CustomUserControl 需要先外部进程发送消息时
        /// 
        /// 
        /// 
        private void Control_SendMsg(object sender, Tuple e)
        {
            SendCommand?.Invoke(new Cal.Wpf.Part.Remoting.ProcessMessage()
            {
                Command = e.Item1,
                Body = e.Item2
            });
        }

        public void Initialize()
        {
            //加载CustomUserControl 之前需要做的事情,可以在这里写,比如加载皮肤dll等...
        }
    }
}

 5、真实的自定义控件再原有的逻辑里,需要处理和主程序的消息通讯,因为当前控件是渲染在子控件上的

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace ProcessDemo
{
    /// 
    /// CustomUserControl.xaml 的交互逻辑
    /// 
    public partial class CustomUserControl : UserControl
    {
        public CustomUserControl()
        {
            InitializeComponent();

            if (!DesignerProperties.GetIsInDesignMode(this))
            {
                pid.Text = $"当前进程id:{Process.GetCurrentProcess().Id}";
            }
        }

        /// 
        /// 发送消息时
        /// 
        public event EventHandler> SendMsg;

        /// 
        /// 发送消息到主进程
        /// 
        /// 
        /// 
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            SendMsg?.Invoke(this, new Tuple(1, msg.Text));
        }

        /// 
        /// 收到主进程的消息时
        /// 
        /// 
        public void SetMsg(string msg)
        {
            Dispatcher.Invoke(() =>
            {
                msgstr.Text = $"收到主进程发来的消息:{msg}";
            });
        }
    }
}

6、最后就是在主进程上,把**Host占位,且在恰当的时候初始化子进程即可

 


    
        
            
                
                    
                    
                    
                        
                        

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace ProcessDemo
{
    /// 
    /// MainWindow.xaml 的交互逻辑
    /// 
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            if (!DesignerProperties.GetIsInDesignMode(this))
            {
                pid.Text = $"当前进程id:{Process.GetCurrentProcess().Id}";
                hostcontrol.ReceiveCommand += Hostcontrol_ReceiveCommand;
                Loaded += MainWindow_Loaded;
            }
        }

        /// 
        /// 窗口加载后
        /// 
        /// 
        /// 
        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            //获取当前句柄
            var parentWnd = Window.GetWindow(this);
            var winHelper = new WindowInteropHelper(parentWnd);
            IntPtr parentWindowHandler = winHelper.EnsureHandle();

            //初始化子进程
            hostcontrol.InitPartControl(parentWindowHandler);
            hostcontrol2.InitPartControl(parentWindowHandler);
        }

        /// 
        /// 当收到子进程发来消息时
        /// 
        /// 
        /// 
        private Cal.Wpf.Part.Remoting.ProcessMessage Hostcontrol_ReceiveCommand(Cal.Wpf.Part.Remoting.ProcessMessage message)
        {
            if (message == null || message.Body == null) return null;

            msgstr.Dispatcher.Invoke(() =>
            {
                msgstr.Text = $"子进程发来消息:{message.Body.ToString()}";
            });
            return null;
        }

        /// 
        /// 发给子进程
        /// 
        /// 
        /// 
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            hostcontrol.SendMsg(msg.Text);
        }
    }
}

有需要完整demo的,也可以异步下载,下面是解决方案摘要

控件进程化,32位程序做大内存消耗时存在内存不够用时,特此记录解决方案,控件进程化,模块进程化_第3张图片

你可能感兴趣的:(wpf)