線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:3186
推到 Plurk!
推到 Facebook!

C++ Builder中引用API函數禁止應用程序多次啟動

 
GrandRURU
站務副站長


發表:234
回覆:1651
積分:1742
註冊:2005-06-21

發送簡訊給我
#1 引用回覆 回覆 發表時間:2008-11-10 10:32:06 IP:203.75.xxx.xxx 未訂閱
C++ Builder中引用API函數禁止應用程序多次啟動

劉遵雄 (華東交通大學信息控制工程研究所330013) 江西.南昌:

鄭淑娟 (江西財經大學圖書館330013)

摘要:該文介紹了如何編制禁止多次啟動的應用程序的實現方法。

關鍵詞:C Builder API函數 應用程序啟動次數

現今普遍流行的PC機操作系統Windows支持多任務機制,允許同一個應用程序多次加載運行。但是有時候,如工業控制系統,多個應用程序實例的運行不僅浪費系統資源和影響系統的實時性,而且還可能造成系統混亂而危及系統的安全。所以在開發應用系統時應該考慮程序可能被多次啟動的問題。

C Builder是Borland公司推出的一種基於C 的優秀可視化快速開發RAD(Rapid Application Development)工具,採用基於控件的開發結構框架,其功能強大、使用方便,日益受到人們的青睞。這裡就如何禁止用C Builder開發的應用程序多次被啟動進行介紹,供各位參考。

用C Builder開發應用程序時通常存在項目.CPP文件,其包含WinMain( )函數,是應用程序的主要入口函數。項目.CPP文件是C Builder編譯和連接構成此項目的源文件的主程序。只需對項目.CPP文件的WinMain( )函數體進行適當的補充就能夠控制應用程序同時運行的個數,這裡討論四種引用Windows API函數的方法來創建一個防止其實例被多次運行的應用程序,它們分別是FindWindow API函數、使用mutexes、 CreateFileMapping函數和使用semaphores。它們都基於共同的前提,是從WinMain( )函數檢測程序的實例,如果存在一個運行實例就不運行TApplication的 Run()方法而返回。

1. 引用
FindWindow函數

API函數FindWindow查找基於標題(caption)或註冊的WndClass的窗口句柄。從WinMain函數內調用FindWindow查找具有相同窗口標題的程序,如果找到,就放棄本程序的運行。
[code cpp]
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)

{

Application->Title = "";

HWND hPrevApp = ::FindWindow(NULL, "實例運行");//(1)

if(hPrevApp) //(2)

{

PostMessage(hPrevApp, WM_SYSCOMMAND, SC_RESTORE, 0);

return 0;

}

else

Application->Title = "實例運行"; //(3)

try

{

Application->Initialize();

Application->CreateForm(__classid(TForm1), &Form1);

Application->Run();

}

catch (Exception &exception)

{

Application->ShowException(&exception);

}

return 0;

}
[/code]
其中首先對應用程序標題賦空字符串;(1)句調用FindWindow,若找到「運行實例」標題窗口,將返回非零的HWND;if…else語句表示如果FindWindow返回非零值,發送消息恢復已運行的窗口,並返回,停止程序的再啟動,否則給應用標題賦值「運行實例」,並執行運行應用程序語句段。

2. 調用
CreateMutex

FindWindow解決問題的方法簡單,且易於理解。但是也有自己的不足,它要求應用程序標題不可改變。而且如果點擊應用程序圖標多次,那麼可能出現即在FindWindow函數調用後第一個應用被第二個應用預置為空,兩者都躲過FindWindow的檢測。

CreateMutex函數是一種較為健壯的測試應用程序實例是否被創建的方法。Mutexes是系統範圍的對象,機器上運行的程序它們的mutex名字是唯一的,允許系統進程訪問。也就是說程序A創建一個mutex,程序B可以察覺它,而且其它的應用程序不能創建同名的mutex。使用CreateMutex來防止程序的多實例運行,首先在WinMain體的起始創建一個屬於自己的mutex,如果創建不了,就說明已有一個程序實例在運行,因為系統存在同名的mutex。
[code cpp]
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)

{

}
[/code]
其中(1)創建名字為PROJECT1的mutex,若系統存在該mutex,GetLastError函數將返回ERROR_ALREADY_EXISTS;(2)若指定名字的mutex存在,關閉定義句柄並返回(3)try …catch語句段同上例。(4)釋放定義的創建mutex的句柄。

操作系統對CreateMutex的調用進行排隊處理,確保同樣程序的兩個實例不能躲過CreateMutex的檢測,前一種方法可能會達不到要求。引用程序衝突時,操作系統將釋放該程序的mutex。

3. CreateFileMapping
函數

API函數CreateFileMapping用於為指定的文件生成命名的或非命名的文件鏡像對象,CreateFileMapping查詢系統數據庫中某個文件鏡像對象是否存在,若函數執行成功將返回一個指向文件鏡像對象的句柄,反之,如果指定對象在調用此函數之前已存在,GetLastError()將返回ERROR_ALREADY_EXISTS。應用程序編制時規定其被啟動運行一個實例時系統將生成一特定的文件鏡像對象,記錄在系統數據庫中。下次應用程序第二次被啟動,首先找到同名的鏡像文件,將放棄啟動該應用程序。
[code cpp]
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)

{

try

{

static HANDLE shFileMap = NULL; //(1)

shFileMap = CreateFileMapping((HANDLE)0xffffffff, NULL, PAGE_READWRITE, 0, 4,

"AppBCB"); //(2)

if (shFileMap != NULL && GetLastError() == ERROR_ALREADY_EXISTS) //(3)

{

ShowMessage("程序已運行!") //(4)

Application->Terminate();

}

else

{

Application->Initialize();

Application->CreateForm(__classid(TForm1), &Form1);

Application->Run();

}}

catch (Exception &exception) {}

return 0;

}
[/code]
其中語句(1)定義一靜態句柄變量,設定其初值為NULL;(2)句調用CreateFileMapping函數,為本應用程序創建名字為」AppBCB」的文件鏡像對象,參數0xffffffff表示需規定創建對象的大小,NULL表示此對象句柄不可繼承,PAGE_READWRITE設置文件鏡像視圖的頁域保護屬性為可讀寫;(3)表示如果」AppBCB」名的鏡像對象已存在,將終止程序的運行,否則執行該應用程序;(4)顯示提示信息;其它方面同前。

4. 使用
CreateSemaphore

假設需要指定一次應用程序實例同時運行的個數,可以使用API函數CreateSemaphore來處理。下面代碼說明如何將應用程序實例的運行數目限制為5個,不允許第六個實例運行。
[code cpp]
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)

{

HANDLE hSemaphore = ::CreateSemaphore(NULL,5,5, "SINGLE.SEMAPHORE");//(1)

if(hSemaphore && WaitForSingleObject(hSemaphore, 0) != WAIT_OBJECT_0)//(2)

{

CloseHandle(hSemaphore);

ShowMessage("You can only run 5 instances at a time");//(3)

return 0;

}

try {}

catch (Exception &exception) {}

ReleaseSemaphore(hSemaphore,1,NULL); //(4)

CloseHandle(hSemaphore);

return 0;

}
[/code]
其中(1)使用CreateSemaphore函數創建semaphore對象,如果該對象存在,操作系統將不創建新的,而返回前面的semaphore。CreateSemaphore函數的第三個參數確定實例的最大數目,第二個參數是semaphore的初始計數。每次調用WaitForSingeObject,semaphore計數將減小。(2)使用WaitForSingleObject函數檢測指定對象是否被標記信號,如果上句創建的句柄存在並進行標記,WaitForSingleObject函數返回WAIT_OBJECT_O,說明指定數目的程序實例已經運行,關閉定義的Semaphore句柄,不允許啟動程序運行下一個實例,否則運行應用程序下一個實例。(3)句顯示提示信息。(4)釋放定義的semaphore對象句柄。

以上的三種創建禁止多個實例運行的應用程序的方法都用到了Windows API函數,本文只是對用到的函數的用法及功能進行了簡要的表述,關於這些函數更詳盡的使用方法,請參考Microsoft Win32 SDK的幫助文件。

參考文獻

(1) Microsoft Win32 SDK

(2)《Delphi 2 程序設計大全》1997/12 機械工業出版社

資料來源:C Builder中引用API函數禁止應用程序多次啟動
系統時間:2017-10-17 15:56:54
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!