我想将Eclipse-RCP应用程序限制为单个实例。通过这种方式,我的意思是,一旦用户第一次打开应用程序,它就会侦听端口,对于第二次访问,它应该打开前一个实例,而不是显示“已经有一个实例正在运行”的警告消息
我的RCP申请代码:
ApplicationInstanceListener.java接口代码
public interface ApplicationInstanceListener
{
public void newInstanceCreated();
}
ApplicationInstanceManager.java代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
public class ApplicationInstanceManager {
private static ApplicationInstanceListener subListener;
/** Randomly chosen, but static, high socket number */
public static final int SINGLE_INSTANCE_NETWORK_SOCKET = 2020;
/** Must end with newline */
public static final String SINGLE_INSTANCE_SHARED_KEY = "$$NewInstance$$\n";
/**
* Registers this instance of the application.
*
* @return true if first instance, false if not.
*/
public static boolean registerInstance() {
// returnValueonerror should be true if lenient (allows app to run on network error) or false if strict.
boolean returnValueonerror = true;
// try to open network socket
// if success, listen to socket for new instance message, return true
// if unable to open, connect to existing and send new instance message, return false
try {
final ServerSocket socket = new ServerSocket(SINGLE_INSTANCE_NETWORK_SOCKET, 10, InetAddress
.getLocalHost());
System.out.println("Listening for application instances on socket " + SINGLE_INSTANCE_NETWORK_SOCKET);
Thread instanceListenerThread = new Thread(new Runnable() {
public void run() {
boolean socketClosed = false;
while (!socketClosed) {
if (socket.isClosed()) {
socketClosed = true;
} else {
try {
Socket client = socket.accept();
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
String message = in.readLine();
if (SINGLE_INSTANCE_SHARED_KEY.trim().equals(message.trim())) {
System.out.println("Shared key matched - new application instance found");
fireNewInstance();
}
in.close();
client.close();
} catch (IOException e) {
socketClosed = true;
}
}
}
}
});
instanceListenerThread.start();
// listen
} catch (UnknownHostException e) {
System.out.println(e.getMessage());
return returnValueonerror;
} catch (IOException e) {
System.out.println("Port is already taken. Notifying first instance.");
try {
Socket clientSocket = new Socket(InetAddress.getLocalHost(), SINGLE_INSTANCE_NETWORK_SOCKET);
OutputStream out = clientSocket.getOutputStream();
out.write(SINGLE_INSTANCE_SHARED_KEY.getBytes());
out.close();
clientSocket.close();
System.out.println("Successfully notified first instance.");
return false;
} catch (UnknownHostException e1) {
System.out.println(e.getMessage());
return returnValueonerror;
} catch (IOException e1) {
System.out.println("Error connecting to local port for single instance notification");
System.out.println(e1.getMessage());
return returnValueonerror;
}
}
return true;
}
public static void setApplicationInstanceListener(ApplicationInstanceListener listener) {
subListener = listener;
}
private static void fireNewInstance() {
if (subListener != null) {
subListener.newInstanceCreated();
}
}
}
Application.java代码
import org.eclipse.equinox.app.IApplication;
import org.eclipse.equinox.app.IApplicationContext;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.PlatformUI;
/**
* This class controls all aspects of the application's execution
*/
public class Application implements IApplication {
/*
* (non-Javadoc)
*
* @see org.eclipse.equinox.app.IApplication#start(org.eclipse.equinox.app.
* IApplicationContext)
*/
public Object start(IApplicationContext context) throws Exception {
if (!ApplicationInstanceManager.registerInstance()) {
// instance already running.
System.out
.println("Another instance of this application is already running. Exiting.");
MessageDialog
.openInformation(new Shell(), "Information",
"Another instance of this application is already running. Exiting.");
System.exit(0);
}
Display display = PlatformUI.createDisplay();
try {
int returnCode = PlatformUI.createAndRunWorkbench(display,
new ApplicationWorkbenchAdvisor());
if (returnCode == PlatformUI.RETURN_RESTART)
return IApplication.EXIT_RESTART;
else
return IApplication.EXIT_OK;
} finally {
display.dispose();
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.equinox.app.IApplication#stop()
*/
public void stop() {
if (!PlatformUI.isWorkbenchRunning())
return;
final IWorkbench workbench = PlatformUI.getWorkbench();
final Display display = workbench.getDisplay();
display.syncExec(new Runnable() {
public void run() {
if (!display.isDisposed())
workbench.close();
}
});
}
}
我采用了一个简单的RCP应用程序,其中包含视图作为模板。 上面的代码工作正常,但没有像 skype或windows media player 那样打开以前的实例,尽管它显示如下警告
如何在第二次运行应用程序时显示或打开上一个实例?
答案 0 :(得分:1)
我有一个应用程序可以做同样的事情。诀窍是新实例无法将旧实例带到前面。但是,旧实例在联系新实例后可以将自己带到前面。
所以你的旧实例需要调用
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell().forceActive();
通知新实例后。对于我的应用程序,新实例不显示错误消息,它只是透明地关闭,旧实例自动弹回。
答案 1 :(得分:0)
看一下这篇文章:Single instance of RCP application。作者描述了使用您询问的服务器套接字的相同模式。
答案 2 :(得分:0)
答案 3 :(得分:0)
基本上你可以拥有像eclipse这样的功能。 Eclipse维护一个.lock
文件来锁定工作区。您可以在工作区中创建一个空的.lock
文件。
在启动每个实例时,您应该检查是否存在.lock
文件,然后进一步继续。如果文件不存在,则应创建它,以便其他实例将发现该工作空间已锁定。