博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
c# 防止重复运行 弹出已运行窗口并传递消息
阅读量:6234 次
发布时间:2019-06-21

本文共 6036 字,大约阅读时间需要 20 分钟。

最近在写一款软件

软件是用来接收其他程序传递过来的命令行,并形成列表

大概的最终效果就像下图一样

原本为了程序美观是打算用listbox自绘列表,字和图片都绘制好了发现自己不会绘制按钮

所以最终采用了datagridview控件,这个直接就可以插入按钮,就省去了那些问题,不过界面美观就一直是遗憾了(希望有界面方面的大牛可以指导我!)

 

因为程序启动的方式是被其他程序启动并发送的有命令行

所以,如果有多条消息默认情况下会被打开多个程序,因此开始了如下的各种解决方法

 

1.命令行的读取

这个相对就比较简单了,修改Program的Main方法

[STAThread]        static void Main(string[] args)        {            Application.EnableVisualStyles();            Application.SetCompatibleTextRenderingDefault(false);            Application.Run(new Form1(args));        }

这样就实现了获取命令行,命令行中间用空格隔开,最终程序得到args文本数组

窗口新增获取数组的初始化方法

public Form1(string[] args)        {            InitializeComponent();            try            {            //这里是将args插入列表的操作                           }            catch (Exception)            {            }        }

当然这些都是十分简单的,网上随手查阅就能找到

接下来是程序禁止重复运行,因为我们想把列表显示在一个窗口中,而不是每个窗口都显示一条数据

所以程序是不可以被重复运行的.Program.cs新增代码如下

#region 防止重复运行        public static Process RunningInstance()        {                Process current = Process.GetCurrentProcess();            Process[] processes = Process.GetProcessesByName(current.ProcessName);            foreach (Process process in processes)            {                if (process.Id != current.Id)                {                    if (Assembly.GetExecutingAssembly().Location.Replace("/", "\\") == current.MainModule.FileName)                    {                        return process;                    }                }            }            return null;        }        public static void HandleRunningInstance(Process instance)        {            ShowWindowAsync(instance.MainWindowHandle, WS_SHOWNORMAL);            SetForegroundWindow(instance.MainWindowHandle);        }        [DllImport("User32.dll")]        private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);        [DllImport("User32.dll")]        private static extern bool SetForegroundWindow(IntPtr hWnd);        private const int WS_SHOWNORMAL = 1;         #endregion

新增之后再Main方法做判断,并且如果已经存在打开的窗口的话,就激活打开的窗口

static void Main(string[] args)        {             Process instance = RunningInstance();            if (instance == null)            { System.Windows.Forms.Application.EnableVisualStyles();                   System.Windows.Forms.Application.DoEvents();                System.Windows.Forms.Application.Run(new Form1(args));                            }                else            {                HandleRunningInstance(instance);            }        }

做完这些,程序已经不能被重复运行了,再测试,新的问题又来了...程序没有被多次打开,但是同样的,列表永远只会有一条数据,不会被更新

新运行的程序收到的命令行没能告知到旧的窗口,因此需要传递值到旧的窗口,这个方法也有很多,最终我采用的是SendMessage

新增代码如下

#region 发送消息        const int WM_COPYDATA = 0x004A;                [DllImport("User32.dll", EntryPoint = "SendMessage")]        private static extern int SendMessage(IntPtr hWnd, int msg, uint wParam, ref COPYDATASTRUCT lParam);        [DllImport("User32.dll", EntryPoint = "FindWindow")]        private static extern int FindWindow(string lpClassName, string lpWindowName);        public struct COPYDATASTRUCT        {            public IntPtr dwData;            public int cbData;            [MarshalAs(UnmanagedType.LPStr)]            public string lpData;        }        #endregion

然后再封装一个方法

static void Send(string[] args)        {            int WINDOW_HANDLER = FindWindow(null, @"这里要改成你的窗口标题,Form1的Text");            if (WINDOW_HANDLER != 0)            {                StringBuilder sb = new StringBuilder();                foreach (string item in args)                {                    sb.Append(item + " ");                }                byte[] sarr = System.Text.Encoding.Default.GetBytes(sb.ToString());            int len = sarr.Length;            COPYDATASTRUCT cds;            cds.dwData = (IntPtr)100;            cds.lpData = sb.ToString();            cds.cbData = len + 1;            int sendRet = SendMessage((IntPtr)WINDOW_HANDLER, WM_COPYDATA, 0, ref cds);            if (sendRet != 0)            {                MessageBox.Show("传递参数失败!");            }            }            else{            MessageBox.Show("没有发现旧窗口!");            }        }

接下来重新改动一下Main方法

static void Main(string[] args)        {            Process instance = RunningInstance();           //如果不存在旧窗口            if (instance == null)            {               System.Windows.Forms.Application.EnableVisualStyles();                   System.Windows.Forms.Application.DoEvents();                System.Windows.Forms.Application.Run(new Form1(args));                            }                else            {              //如果存在先激活                HandleRunningInstance(instance);                //如果收到的有参数就传递,没有就忽略                if (args.Length>0)                {                    Send(args);                    }                                            }        }

这样,发送参数的部分就完成了.还剩下最后一步,Form中接收传递过来的参数

在Form中新增如下代码

#region 接收消息        protected override void DefWndProc(ref System.Windows.Forms.Message m)        {            const int WM_COPYDATA = 0x004A;            switch (m.Msg)            {                case WM_COPYDATA:                    COPYDATASTRUCT mystr = new COPYDATASTRUCT();                    Type mytype = mystr.GetType();                    mystr = (COPYDATASTRUCT)m.GetLParam(mytype);                    string[] s = mystr.lpData.Split(new string[]{
" "},StringSplitOptions.RemoveEmptyEntries); if (s.Length>0) { //这里写收到参数的情况操作 //mystr.lpData为实际收到的文本,可以直接操作,我这里分割为数组来区分标题,网址等了 } break; default: base.DefWndProc(ref m); break; } } public struct COPYDATASTRUCT { public IntPtr dwData; public int cbData; [MarshalAs(UnmanagedType.LPStr)] public string lpData; } #endregion

 

做完这些我们想要的效果就完全实现了,每次我们的程序被运行都只会有一个窗口,并且所有的数据会汇总在这里

 

以上文章都乃小生的个人见解,可能会有小的错误或者更好的方法来实现.也希望大家能评论出来让我学习

另外,希望有会自绘列表中带有按钮的大大们,可以指导一下小生

转载于:https://www.cnblogs.com/jianzhan/p/4777678.html

你可能感兴趣的文章
PHP获取毫秒时间戳,利用microtime()函数
查看>>
动态规划复习-HDU1231
查看>>
串门赛: NOIP2016模拟赛——By Marvolo 丢脸记
查看>>
Webapck项目开发基本构建及配置
查看>>
poj2562
查看>>
用matplotlib绘制图像
查看>>
flex 整理 笔记
查看>>
Cocos2d-x之瓦片地图 Tiled
查看>>
对网卡中断绑定的脚本
查看>>
Android第二次作业
查看>>
Trie
查看>>
(Joomla)多功能健康模块
查看>>
基于CC2530的zigbee信道、PANID扫描设备
查看>>
前端基础之jquery
查看>>
You are beautiful
查看>>
GIS部分理论知识备忘随笔
查看>>
应用安装和卸载
查看>>
CSS深入理解学习笔记之border
查看>>
查找并替换中文字符
查看>>
GRU(Gated Recurrent Unit) 更新过程推导及简单代码实现
查看>>