.Net結合PInvoke超簡單實現程式單一例項執行
程式的例項(Application Instance)我們可以簡單將其理解為程式。假設有個沒有任何關於例項判斷程式碼的可執行檔案Test.exe,我們一旦執行了它,那麼也意味著 Windows啟動了一個新程式,這時Test.exe就有了一個例項,如果我們再次雙擊Test.exe,Windows就有了兩個同名的程式,並且 Test.exe也有了兩個例項,在Windows工作管理員中我們就會看到兩個Test.exe程式。這足以證明Windows是支援多程式和多執行緒的,哈哈,這還用說!
多例項肯定要消耗不必要的記憶體,而且假設某些龐大的管理系統的一個例項也許會鎖定某些資源,譬如資料庫連線、檔案讀寫等等,當啟動另外一個例項時那麼肯定會報錯,我們不可能指望使用者來理解這種情況,因為使用者的水平參差不齊,我們必須加以應對。這就要求我們:
1、程式只執行一個例項;
2、當不慎啟動第二個例項時,無論前一個例項是何種狀態(最小化或者未前臺顯示),程式應有能力還原前一例項的主窗體(Restore)並將其前臺顯示,同時終止第二個例項的執行,以始終保持單一例項。
我們結合.Net框架和平臺呼叫來實現上述需求。Process 類在我們的示例中很關鍵,我們將用該類透過檢索程式名來獲取程式資訊並檢測其是否已經執行,除了使用Process我們還可以使用互斥物件(Mutex)以及記憶體對映檔案來達到同樣的結果,但是後者同前者比起來要複雜很多,而且記憶體對映檔案不被.Net原生支援,後者雖然複雜但程式檢測絕對準確,而透過檢索程式名來獲取程式資訊則有一定風險,因為可能存在兩個相同程式名卻完全不同的兩個程式,雖然這種可能性極小。本文先以檢索程式名為例,後續博文將會探索互斥物件和記憶體對映檔案結合使用來絕對保證程式的唯一性。
若已存在同名例項,則利用PInvoke平臺呼叫,透過呼叫Win32API還原前一例項的主窗體並前臺顯示。
我們建立一個預設的Windows Form. Application,雙擊Program.cs,更新程式碼如下:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices;
......
static class Program
{
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll")]
private static extern bool IsIconic(IntPtr hWnd);
private const int SW_RESTORE = 9;
///
/// 應用程式的主入口點。
///
[STAThread]
static void Main()
{
string proc = Process.GetCurrentProcess().ProcessName;
Process[] processes = Process.GetProcessesByName(proc);
if (processes.Length > 1)
{
Process p = Process.GetCurrentProcess();
int n = 0;
if (processes[0].Id == p.Id)
{
n = 1;
}
IntPtr hWnd = processes[n].MainWindowHandle;
if (IsIconic(hWnd))
{
ShowWindowAsync(hWnd, SW_RESTORE);
}
SetForegroundWindow(hWnd);
return;
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new frmMain());
}
}
只要在任何專案的Program.cs中按照上述程式碼更新,都能輕鬆實現程式的單一例項執行。也許有網友會疑問:我們怎麼沒看到終止程式的程式碼呢?請注意上述程式碼中的 return 語句!第二個例項的程式碼將會一直執行到在return語句之前,當我們獲取了已經執行的例項的主窗體控制程式碼並將其前臺實現之後,實際上現在在Windows 上執行了兩個同名例項!前一例項的主窗體顯示後,main函式就返回了。c/c++程式設計師會清楚main函式是程式的入口點,一個程式有且僅有一個 main函式,除非程式退出,main函式是決不會返回的!所以,return也就等於終止了程式,第二個例項就此執行結束。
上述程式碼在Windows XP SP3 + Visual Studio 2008 SP1下編譯除錯透過。
多例項肯定要消耗不必要的記憶體,而且假設某些龐大的管理系統的一個例項也許會鎖定某些資源,譬如資料庫連線、檔案讀寫等等,當啟動另外一個例項時那麼肯定會報錯,我們不可能指望使用者來理解這種情況,因為使用者的水平參差不齊,我們必須加以應對。這就要求我們:
1、程式只執行一個例項;
2、當不慎啟動第二個例項時,無論前一個例項是何種狀態(最小化或者未前臺顯示),程式應有能力還原前一例項的主窗體(Restore)並將其前臺顯示,同時終止第二個例項的執行,以始終保持單一例項。
我們結合.Net框架和平臺呼叫來實現上述需求。Process 類在我們的示例中很關鍵,我們將用該類透過檢索程式名來獲取程式資訊並檢測其是否已經執行,除了使用Process我們還可以使用互斥物件(Mutex)以及記憶體對映檔案來達到同樣的結果,但是後者同前者比起來要複雜很多,而且記憶體對映檔案不被.Net原生支援,後者雖然複雜但程式檢測絕對準確,而透過檢索程式名來獲取程式資訊則有一定風險,因為可能存在兩個相同程式名卻完全不同的兩個程式,雖然這種可能性極小。本文先以檢索程式名為例,後續博文將會探索互斥物件和記憶體對映檔案結合使用來絕對保證程式的唯一性。
若已存在同名例項,則利用PInvoke平臺呼叫,透過呼叫Win32API還原前一例項的主窗體並前臺顯示。
我們建立一個預設的Windows Form. Application,雙擊Program.cs,更新程式碼如下:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices;
......
static class Program
{
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll")]
private static extern bool IsIconic(IntPtr hWnd);
private const int SW_RESTORE = 9;
///
/// 應用程式的主入口點。
///
[STAThread]
static void Main()
{
string proc = Process.GetCurrentProcess().ProcessName;
Process[] processes = Process.GetProcessesByName(proc);
if (processes.Length > 1)
{
Process p = Process.GetCurrentProcess();
int n = 0;
if (processes[0].Id == p.Id)
{
n = 1;
}
IntPtr hWnd = processes[n].MainWindowHandle;
if (IsIconic(hWnd))
{
ShowWindowAsync(hWnd, SW_RESTORE);
}
SetForegroundWindow(hWnd);
return;
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new frmMain());
}
}
只要在任何專案的Program.cs中按照上述程式碼更新,都能輕鬆實現程式的單一例項執行。也許有網友會疑問:我們怎麼沒看到終止程式的程式碼呢?請注意上述程式碼中的 return 語句!第二個例項的程式碼將會一直執行到在return語句之前,當我們獲取了已經執行的例項的主窗體控制程式碼並將其前臺實現之後,實際上現在在Windows 上執行了兩個同名例項!前一例項的主窗體顯示後,main函式就返回了。c/c++程式設計師會清楚main函式是程式的入口點,一個程式有且僅有一個 main函式,除非程式退出,main函式是決不會返回的!所以,return也就等於終止了程式,第二個例項就此執行結束。
上述程式碼在Windows XP SP3 + Visual Studio 2008 SP1下編譯除錯透過。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/14325734/viewspace-536377/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- java多執行緒結合單例模式例項,簡單實用易理解Java執行緒單例模式
- jQuery實現的簡單投票簡單程式碼例項jQuery
- C#實現單例項執行C#單例
- CSS並不簡單--結合SVG實現簡單的載入動畫CSSSVG動畫
- EasyUI實現的form表單提交簡單程式碼例項UIORM
- jQuery結合ul和li實現的下拉選單例項程式碼jQuery單例
- Kotlin超簡單實現StepViewKotlinView
- Python簡單實現多執行緒例子Python執行緒
- 用單連結串列實現多項式加,減,乘,簡單微分
- linux執行緒池簡單例項Linux執行緒單例
- html實現簡單ListViews效果的例項程式碼HTMLView
- javascript實現的動畫效果簡單例項程式碼JavaScript動畫單例
- 簡單的Java實現Netty進行通訊JavaNetty
- 執行緒池的介紹及簡單實現執行緒
- javascript 物件合併程式碼例項簡單分析JavaScript物件
- C++:用棧實現反轉連結串列,超簡單!C++
- jQuery實現的動畫簡單例項jQuery動畫單例
- 實現一個簡單的在瀏覽器執行Dotnet編輯器瀏覽器
- jQuery實現的自動播放簡單程式碼例項jQuery
- arguments.callee實現遞迴簡單程式碼例項遞迴
- canvas實現的簡單餅狀圖程式碼例項Canvas
- canvas實現的簡單塗鴉板程式碼例項Canvas
- css實現的div旋轉簡單程式碼例項CSS
- canvas實現的簡單畫板效果程式碼例項Canvas
- 簡單實現Laravel獲取當前執行的SQLLaravelSQL
- 超簡單實現iOS列表的索引功能iOS索引
- 超簡單整合ML kit 實現聽寫單詞播報
- 60行程式碼實現簡單模板語法行程
- javascript實現的圖片簡單切換程式碼例項JavaScript
- javascript實現的簡單驗證碼效果程式碼例項JavaScript
- 透過簡單示例瞭解執行緒池實現原理執行緒
- angular雙向繫結簡單實現Angular
- css合併減少重複程式碼簡單例項CSS單例
- netty 實現簡單的rpc呼叫NettyRPC
- 簡單實現.NET Hook與事件模擬Hook事件
- 結合 CSS3 transition transform 實現簡單的跑馬燈效果CSSS3ORM
- 64行程式碼實現簡單人臉識別行程
- jQuery結合PHP+MySQL實現二級聯動下拉選單[例項]jQueryPHPMySql