最近在寫一款軟件
軟件是用來接收其他程序傳遞過來的命令行,並形成列表
大概的最終效果就像下圖一樣
原本為了程序美觀是打算用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
做完這些我們想要的效果就完全實現了,每次我們的程序被運行都只會有一個窗口,並且所有的數據會匯總在這里
以上文章都乃小生的個人見解,可能會有小的錯誤或者更好的方法來實現.也希望大家能評論出來讓我學習
另外,希望有會自繪列表中帶有按鈕的大大們,可以指導一下小生