如何将 Eclipse-RCP 应用程序限制为单个实例?

2022-01-16 00:00:00 eclipse-plugin java eclipse-rcp

我想将我的 Eclipse-RCP 应用程序限制为单个实例.我的意思是,一旦用户第一次打开应用程序,它会监听一个端口,而对于第二次访问,它应该打开前一个实例,而不是显示诸如已经有一个实例正在运行"之类的警告消息

I would like to restrict my Eclipse-RCP application to a single instance. By this, I mean that once a user opens the application for the first time, it listens on a port and for the second access it should open the previous instance instead of showing a warning message like "already an instance is running"

我的 RCP 应用程序代码:

My RCP Application code:

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$$
";

    /**
     * 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 媒体播放器,尽管它显示如下所示的警报

I've taken a simple RCP application with view as a template. The above code works fine but doesn't open previous instance like skype or windows media player despite it shows an alert like below

如何在应用程序第二次运行时显示或打开之前的实例?

How can I show or open the previous instance upon second run of the application?

推荐答案

我有一个应用程序可以做同样的事情.诀窍是新实例不能将旧实例带到前面.但是,旧实例在接触到新实例后可以将自己带到前面.

I have an app that does this same thing. The trick is that the new instance can't bring the old instance to the front. But, the old instance can bring itself to the front after it contacts the new instance.

所以你的旧实例需要调用

So your old instance needs to call

PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell().forceActive();

在它通知新实例之后.对于我的应用,新实例不会显示错误消息,它只是透明地关闭,旧实例会自行弹出.

after it notifies the new instance. For my app, the new instance doesn't show an error message, it just closes transparently and the old instance pops itself back up.

相关文章