delphi中,讓程序只運(yùn)行一次的方法(1)

字號(hào):

公司開發(fā)的軟件需要對(duì)串口進(jìn)行*作,每次打開軟件后程序自動(dòng)去打開串口尋找連接到串口上的設(shè)備,但是如果用戶不知道打開了兩次,那么第二次打開的程序是不能正常使用的,因?yàn)閷?duì)串口的*作時(shí)獨(dú)占的,第一個(gè)程序獨(dú)占了串口的使用權(quán),其他程序無法再使用那一個(gè)串口,當(dāng)然如果PC機(jī)器上有兩個(gè)串口,那第二個(gè)程序也是可以用的。為了解決這個(gè)問題,必須限制對(duì)串口*作的軟件只能打開一個(gè)。打開軟件后用戶如果誤*作再次想打開該軟件,需要提示用戶軟件已經(jīng)打開,并讓已打開的軟件顯示在窗口最頂層。
    下面是Delphi版的解決方法。
    (方法一)
    利用互斥對(duì)象
    開發(fā)過多線程軟件的可能都使用過互斥對(duì)象,它常被用做線程間同步的技術(shù)手段。簡(jiǎn)要的提一下互斥對(duì)象:互斥對(duì)象把第一次建立它的程序作為主程序,這樣只用檢測(cè)互斥對(duì)象是否已經(jīng)有主程序就判斷程序是否已經(jīng)運(yùn)行過,這里需要涉及到一個(gè)api函數(shù):WaitForSingleObject,該函數(shù)的第一個(gè)參數(shù)為用以檢測(cè)的互斥對(duì)象,第2個(gè)參數(shù)的表示函數(shù)返回結(jié)果前的滯留時(shí)間,如果改函數(shù)返回wait_TimeOut就表明互斥對(duì)象已經(jīng)有了一個(gè)主程序。
    注意:以下的代碼都出現(xiàn)在工程文件中,而不是單元文件中。
    var
     myMutex:HWND;
    begin
        //CreateMutex建立互斥對(duì)象,并且給互斥對(duì)象起一個(gè)的名字。
        myMutex:=CreateMutex(nil,false,'hkOneCopy');
        //程序沒有被運(yùn)行過
        if WaitForSingleObject(myMutex,0)<>wait_TimeOut then
        begin
        Application.Initialize;
        Application.CreateForm(TForm1, Form1);
        Application.Run;
       End;
    End;
    [注釋]:
    當(dāng)應(yīng)用程序第一次運(yùn)行的時(shí)候,在應(yīng)用程序中會(huì)建立一個(gè)互斥對(duì)象,名稱為'hkOneCopy',然后判斷系統(tǒng)中有沒有這個(gè)互斥對(duì)象,如果沒有則初始化應(yīng)用程序。
    下面再完善一下這個(gè)程序。
    我們不希望程序被多次運(yùn)行,而是希望如果程序運(yùn)行過后,再運(yùn)行這個(gè)程序的時(shí)候,將已運(yùn)行的程序做出一些響應(yīng),比如說讓它變?yōu)樽钌蠈拥幕顒?dòng)窗口來提示用戶該程序正在運(yùn)行。為達(dá)到這個(gè)目的,必須要獲得正在運(yùn)行程序的句柄,然后用一個(gè)APISetForeGroundWindow(handle),來使程序的窗口最前并激活。為了得到程序的句柄,要使用windows枚舉函數(shù)EnumWindows來遍歷windows窗口列表,該函數(shù)需要一個(gè)回調(diào)函數(shù)作參數(shù),用這個(gè)回調(diào)函數(shù)來對(duì)每一個(gè)系統(tǒng)中的窗口進(jìn)行調(diào)用直到最后一個(gè)窗口或回調(diào)函數(shù)返回false為止[注:關(guān)于EnumWindows函數(shù)的介紹在篇尾]。只要編寫這個(gè)回調(diào)函數(shù)并在其中不斷的比較當(dāng)前遍歷到的窗口類名和我們的程序的主窗口類名,以及比較窗口可執(zhí)行文件的名稱和我們程序的名稱直到找到相同的為止,將這時(shí)的窗口句柄保存下來就行了。為獲得窗口的類名和句柄,需要一個(gè)APIGetClassName,為獲得可執(zhí)行文件的名稱,需要APIGetModuleFileName。
    下面是詳細(xì)代碼。
    注意:下面代碼在delphi7下運(yùn)行通過。但是如果窗口最小化后,再次運(yùn)行程序時(shí),原先已經(jīng)運(yùn)行的程序能夠被置前并激活但是標(biāo)題欄的最小化按鈕卻不能用了。當(dāng)嘗試了N中方法后估計(jì)是delphi自身TForm類的問題,下面給出一個(gè)解決方案:在窗口上放一個(gè)ApplicationEvents控件,它管理著應(yīng)用程序所有的消息。我們?cè)谒腛nMessage事件里寫上下面的代碼:
     if Msg.hwnd=Form1.Handle then
     begin
    //161 是在標(biāo)題欄按下鼠標(biāo)
    //8 是在標(biāo)題欄的最小化按鈕上按下鼠標(biāo)
        if (Msg.message= 161) and (msg.wParam= 8) then
        begin
        Form1.WindowState:= wsMinimized;
        end;
     end;