c# 防止重復運行 彈出已運行窗口並傳遞消息


最近在寫一款軟件

軟件是用來接收其他程序傳遞過來的命令行,並形成列表

大概的最終效果就像下圖一樣

原本為了程序美觀是打算用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

 

做完這些我們想要的效果就完全實現了,每次我們的程序被運行都只會有一個窗口,並且所有的數據會匯總在這里

 

以上文章都乃小生的個人見解,可能會有小的錯誤或者更好的方法來實現.也希望大家能評論出來讓我學習

另外,希望有會自繪列表中帶有按鈕的大大們,可以指導一下小生


免責聲明!

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



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