Macos 如何检测OS X应用程序是否已启动
通常,OS X上的应用程序捆绑包只能启动一次,但是,通过简单地复制捆绑包,同一应用程序可以启动两次。检测和阻止这种可能性的最佳策略是什么 在Windows上,此效果可以通过应用程序在启动时创建命名资源来实现,如果无法创建命名资源,则退出,这表示正在运行另一个已创建相同资源的进程。当应用程序退出时,这些资源在Windows上以可靠的方式释放 我在研究这一点时看到的问题是,OS X上的API在文件系统中保持状态,从而使windows上使用的策略不可靠,即在不正确的退出后,文件的延迟可能会错误地表明应用程序已经在运行 我可以在OSX上使用的API有:posix、carbon和boost 想法?怎么样?您可以打开一个套接字并与另一个启动的实例协商。不过,你必须小心,如果两个应用程序同时启动,它就会起作用Macos 如何检测OS X应用程序是否已启动,macos,boost,resources,macos-carbon,launch,Macos,Boost,Resources,Macos Carbon,Launch,通常,OS X上的应用程序捆绑包只能启动一次,但是,通过简单地复制捆绑包,同一应用程序可以启动两次。检测和阻止这种可能性的最佳策略是什么 在Windows上,此效果可以通过应用程序在启动时创建命名资源来实现,如果无法创建命名资源,则退出,这表示正在运行另一个已创建相同资源的进程。当应用程序退出时,这些资源在Windows上以可靠的方式释放 我在研究这一点时看到的问题是,OS X上的API在文件系统中保持状态,从而使windows上使用的策略不可靠,即在不正确的退出后,文件的延迟可能会错误地表明应
我无法提供示例代码,因为我还没有(但我很快就会)使用它。首先,它是“MacOSX”或“OSX”。没有“OS/X”这样的东西 第二,MacOSX没有附带Boost;您需要将其与应用程序捆绑在一起 第三,大部分碳元素在64位中不可用。这是一个明确的信号,表明这些碳元素有一天会消失(当苹果放弃其32位硬件时)。迟早,你要么用Cocoa重写你的应用程序,要么放弃Mac 通常,OS/X上的应用程序捆绑包只能启动一次,但是,通过简单地重命名捆绑包,相同的应用程序可以启动两次 不,不能。启动重命名或移动的应用程序只需激活(放在前面)已经运行的进程;它不会在第一个流程的基础上启动新的第二个流程
有几种方法可以判断应用程序是否已经在运行。在每种情况下,您都可以在启动时执行以下操作:
在响应通知的观察回调中,退出 因此,当第一个进程启动时,它将调用并没有得到响应;当第二个进程启动时,它将调用,从第一个进程获得响应,并根据第一个进程退出
低级解决方案是使用flock() 每个实例将尝试在启动时锁定一个文件,如果锁定失败,则另一个实例已在运行。程序退出时,羊群会自动释放,所以不用担心过时的锁
请注意,无论您选择什么解决方案,您都需要有意识地决定“多个实例”的含义。具体来说,如果多个用户同时运行您的应用程序,可以吗?正如前面提到的,Cocoa应用程序通常不允许您一次运行多个实例
通常,解决此问题的一种方法是在NSWorkspace中启动应用程序。这将返回一个NSArray,其中包含每个已启动应用程序的字典。您可以在阵列中循环,查看您正在查找的应用程序是否已在运行。我建议您将该值与键NSApplicationBundleIdentifier一起使用,该键的值类似于“com.mycompany.myapp”,而不是查找名称。如果您需要查找应用程序的捆绑标识,可以查看应用程序包中的info.plist文件。这在Snow Leopard中非常容易:
- (void)deduplicateRunningInstances {
if ([[NSRunningApplication runningApplicationsWithBundleIdentifier:[[NSBundle mainBundle] bundleIdentifier]] count] > 1) {
[[NSAlert alertWithMessageText:[NSString stringWithFormat:@"Another copy of %@ is already running.", [[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleNameKey]]
defaultButton:nil alternateButton:nil otherButton:nil informativeTextWithFormat:@"This copy will now quit."] runModal];
[NSApp terminate:nil];
}
}
有关更多信息,请参阅。有一个神秘的Info.plist键,名为“应用程序禁止多个实例”,但它似乎对我不起作用。我正在编写一个CLI应用程序,并在捆绑包中执行它。也许它可以在GUI应用程序中工作,但我还没有尝试。检测具有相同bundleID的应用程序是否正在运行,激活它并关闭启动的程序
- (id)init method of < NSApplicationDelegate >
NSArray *apps = [NSRunningApplication runningApplicationsWithBundleIdentifier:[[NSBundle mainBundle] bundleIdentifier]];
if ([apps count] > 1)
{
NSRunningApplication *curApp = [NSRunningApplication currentApplication];
for (NSRunningApplication *app in apps)
{
if(app != curApp)
{
[app activateWithOptions:NSApplicationActivateAllWindows|NSApplicationActivateIgnoringOtherApps];
break;
}
}
[NSApp terminate:nil];
return nil;
}
-(id)的init方法
NSArray*应用程序=[NSRunningApplication runningApplicationsWithBundleIdentifier:[[NSBundle mainBundle]bundleIdentifier]];
如果([应用计数]>1)
{
NSRunningApplication*curApp=[NSRunningApplication currentApplication];
用于(NSRunningApplication*应用程序中的应用程序)
{
如果(app!=curApp)
{
[应用程序激活选项:非应用程序激活所有窗口|非应用程序激活信号或其他应用程序];
打破
}
}
[NSApp终止:无];
返回零;
}
这是Romans和Jeff对Swift 2.0的回答的组合:如果具有相同捆绑ID的应用程序的另一个实例已在运行,则显示警报,激活另一个实例并退出重复实例
func applicationDidFinishLaunching(aNotification: NSNotification) {
/* Check if another instance of this app is running. */
let bundleID = Bundle.main.bundleIdentifier!
if NSRunningApplication.runningApplications(withBundleIdentifier: bundleID).count > 1 {
/* Show alert. */
let alert = NSAlert()
alert.addButton(withTitle: "OK")
let appName = Bundle.main.object(forInfoDictionaryKey: kCFBundleNameKey as String) as! String
alert.messageText = "Another copy of \(appName) is already running."
alert.informativeText = "This copy will now quit."
alert.alertStyle = NSAlert.Style.critical
alert.runModal()
/* Activate the other instance and terminate this instance. */
let apps = NSRunningApplication.runningApplications(withBundleIdentifier: bundleID)
for app in apps {
if app != NSRunningApplication.current {
app.activate(options: [.activateAllWindows, .activateIgnoringOtherApps])
break
}
}
NSApp.terminate(nil)
}
/* ... */
}
func applicationdFinishLaunching(通知:NSNotification){
/*检查此应用程序的另一个实例是否正在运行*/
让bundleID=NSBundle.mainBundle(