2013-05-25 65 views
2

App.Previnstance返回的值爲TrueFalse,具體取決於此實例啓動時程序的先前是否正在運行。是否可以編寫App.PrevInstance替換以提供實時信息

隨後如果先前的實例終止的App.PrevInstance的值不改變。

是否有可能寫就能夠確定在任何時候的函數,如果以前 情況是存在?

我想,爲了這個,你需要的日期/時間開始的進程可用。 由於這些信息似乎無法從任務管理器獲得,我不知道Windows是否存儲它?

+1

最便宜的方法是使用具有GUID的'CreateMutex'作爲互斥體名稱。如果該功能失敗,則該應用程序的另一個實例已在運行。 – wqw

+0

@wqw我聽說過一個互斥體,但從來不知道它是什麼。希望我早點知道!基於這個評論和谷歌我已經發布了一些適合我的東西 – kjack

回答

2

你和看到的問題App.PrevInstance可能是因爲您使用調試器(即VB 6 IDE)下運行的應用測試。但我不完全確定。它可能只執行一次檢查並緩存該值,這使得它隨着環境狀態的變化而變得「陳舊」。正如你已經注意到的,App.PrevInstance屬性有很多限制。它的另一個常見問題是它的脆弱性。更改可執行文件的名稱是使其失敗的簡單方法。這並不總是理想的行爲。

所以這是一個替代的解決方案來代替它是一個好主意。像wqw在評論中所說的,最好的解決方案是在應用程序啓動時使用GUID創建一個互斥體名稱的互斥體。這應該是第一次成功,但隨後會失敗,因爲互斥體已被註冊(通過您的應用程序的前一個實例)。這個失敗是你的線索,你的應用程序的前一個實例正在運行。要在VB 6中執行此操作,您需要導入並調用一些Win32函數,如CreateMutexCloseHandleReleaseMutex。有a sample of how to use mutexes on MSDN,但這不會幫你編寫VB 6代碼,除非你已經非常熟悉Win32 API。我鏈接到一個教程,其中包含必要的代碼,在VB 6中my answer here

如果您對App.PrevInstance的行爲感到滿意,並且您只是希望它在每次調用它時執行檢查(而不是使用過時的緩存值),那麼您可以將其替換爲對您的調用自己的功能基本上是一樣的:遍歷所有當前正在運行的進程,並查找與可執行文件名稱匹配的內容。不幸的是,這不一定比涉及使用互斥體的「更好」解決方案少。您仍然需要導入許多Win32函數,包括EnumProcesses。在舊的knowledge base article中有對此的說明 - 顯然,您想專注於「Windows NT」部分並忽略「Windows 95/98」的內容。

我想爲此你需要日期/時間過程開始可用。由於這些信息似乎無法從任務管理器獲得,我不知道Windows是否存儲它?

你實際上並不需要這些信息。事實上,我不確定你想要採取什麼樣的方法。這個過程何時開始並不重要,它關係到它是否正在運行。這是兩個完全不同的東西。

然而,只是爲了好玩,視窗確實事實上店此信息。任務管理器不顯示它,但Process Explorer呢。您可以通過編程方式調用GetProcessTimes函數或querying WMI(具體而言,Win32_Process類的CreationDate屬性)來檢索它。

+0

@C代灰謝謝你。正如你所說的,使用互斥鎖是最好的選擇。至於流程開始的時間,我認爲我需要這樣做才能使其中一個流程能夠將自己標識爲最早的流程,從而能夠接管只有一個實例應該執行的任務。 – kjack

+1

順便說一句我剛剛確認,app.previnstance在先前的實例終止後保持爲真的問題並不侷限於IDE。 – kjack

2

感謝wqw的評論我擡頭看CreateMutex這正是我所需要的。

我發現下面here

'Code by Adam Verwijs 
Const ERROR_ALREADY_EXISTS = 183& 
Private Declare Function CreateMutex Lib "kernel32" Alias "CreateMutexA" (lpMutexAttributes As Any, ByVal bInitialOwner As Long, ByVal lpName As String) As Long 
Private Declare Function ReleaseMutex Lib "kernel32" (ByVal hMutex As Long) As Long 
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long 
Private Sub Form_Load() 
    Dim hMutex As Long 
    'Try to create a new Mutex 
    hMutex = CreateMutex(ByVal 0&, 1, App.Title) 
    'Did the mutex already exist? 
    If (Err.LastDllError = ERROR_ALREADY_EXISTS) Then 
     'Clean up 
     ReleaseMutex hMutex 
     CloseHandle hMutex 
     'More than one instance detected 
     MsgBox "More than one instance" 
     End 
    Else 
     'form load code 
    End If 
End Sub 

編輯代碼,以表明同一個非零互斥返回: 如果創建1個按鈕一個新的VB6項目,堅持下面的代碼中,使得該項目,然後運行多個實例,你會看到,所有具有相同的非零互斥體,至少在我的電腦(Windows Vista家庭基本)

Option Explicit 

Const ERROR_ALREADY_EXISTS = 183& 
Private Declare Function CreateMutex Lib "kernel32" Alias "CreateMutexA" (lpMutexAttributes As Any, ByVal bInitialOwner As Long, ByVal lpName As String) As Long 
Private Declare Function ReleaseMutex Lib "kernel32" (ByVal hMutex As Long) As Long 
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long 

Private Sub Command1_Click() 
Dim hMutex As Long 
    'Try to create a new Mutex 
    hMutex = CreateMutex(ByVal 0&, 1, App.Title) 
    MsgBox hMutex 
    'Did the mutex already exist? 
    If (Err.LastDllError = ERROR_ALREADY_EXISTS) Then 
     'Clean up 
     ReleaseMutex hMutex 
     CloseHandle hMutex 
     'More than one instance detected 
     MsgBox "More than one instance" 


    End If 
End Sub 

編輯2016年4月17日請勿使用此代碼! 我已經使用它,直到最近才發現問題,但現在已經發現,它不能跨多個用戶登錄到計算機上。使用wqw的答案this other thread instead

+0

在您的「已存在清理」中,您正在使用NULL句柄。沒有什麼可以發佈或關閉的。有趣的是,「大多數時間工作」的不正確代碼繼續傳播以誤導另一代人。根據文檔,你應該在查看LastDllError之前檢查NULL句柄返回。發生任何其他錯誤時,您也會成功。這種邏輯在多方面是錯誤的。 – Bob77

+0

@ Bob77有一點知識是危險的!我已將它編輯出來,但保留了API文檔中的代碼。 – kjack

+1

除了檢查'LastDllError'之外,你應該檢查'hMutex'是否爲0('NULL')。我會使用一個GUID或其他保證是唯一的互斥體ID,而不僅僅是你的應用程序的標題/名稱。這可能會與其他某個對象發生衝突。想象一下,如果你寫了一個叫做「記事本」的東西!是的,就像鮑勃說的,如果'CreateMutex'失敗了,沒有什麼可以發佈或清理的。清理代碼應該放在應用程序的終止序列中,以便在* first *實例關閉時執行。 (雖然Windows會照顧到你的。) –

相關問題