2013-05-25 66 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会照顾到你的。) –

相关问题