首页 > 解决方案 > 跨同一台计算机上的用户会话的 WCF 命名管道。可能的?

问题描述

要求 我正在尝试创建一个“单实例”winforms 应用程序,如果调用第二个实例,则传递参数。我希望Mutex不会像这样工作。我已经在 winform 应用程序上创建了一个 WCF 管道,这样如果另一个实例来了,它将通知主实例并带有所需的参数,我将根据需要处理主实例上的参数,并在通知后关闭第二个实例。

问题: 上面的代码似乎工作正常,当涉及多个用户会话时出现问题,当我以“用户 A”身份登录机器并打开我的应用程序时,它打开了应用程序(主实例)。同时,如果另一个用户登录说“用户 B”并尝试打开应用程序,它很高兴打开 :(

代码:

这是我的 WCF 单实例代码。

public static class SingleInstanceManager
{
    /// <summary>
    /// Raised when another instance attempts to start up.
    /// </summary>
    public static event StartupEventHandler OtherInstanceStarted;

    /// <summary>
    /// Checks to see if this instance is the first instance running on this machine.  If it is not, this method will
    /// send the main instance this instance's startup information.
    /// </summary>
    /// <param name="guid">The application's unique identifier.</param>
    /// <returns>True if this instance is the main instance.</returns>
    public static bool VerifySingleInstance(Guid guid)
    {
        if (!AttemptPublishService(guid))
        {
            NotifyMainInstance(guid);

            return false;
        }

        return true;
    }

    /// <summary>
    /// Attempts to publish the service.
    /// </summary>
    /// <param name="guid">The application's unique identifier.</param>
    /// <returns>True if the service was published successfully.</returns>
    private static bool AttemptPublishService(Guid guid)
    {
        try
        {
            ServiceHost serviceHost = new ServiceHost(typeof(SingleInstance));
            NetNamedPipeBinding binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
            serviceHost.AddServiceEndpoint(typeof(ISingleInstance), binding, CreateAddress(guid));
            serviceHost.Open();

            return true;
        }
        catch
        {
            return false;
        }
    }

    /// <summary>
    /// Notifies the main instance that this instance is attempting to start up.
    /// </summary>
    /// <param name="guid">The application's unique identifier.</param>
    private static void NotifyMainInstance(Guid guid)
    {
        NetNamedPipeBinding binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
        EndpointAddress remoteAddress = new EndpointAddress(CreateAddress(guid));
        using (ChannelFactory<ISingleInstance> factory = new ChannelFactory<ISingleInstance>(binding, remoteAddress))
        {
            ISingleInstance singleInstance = factory.CreateChannel();
            singleInstance.NotifyMainInstance(Environment.GetCommandLineArgs());
        }
    }

    /// <summary>
    /// Creates an address to publish/contact the service at based on a globally unique identifier.
    /// </summary>
    /// <param name="guid">The identifier for the application.</param>
    /// <returns>The address to publish/contact the service.</returns>
    private static string CreateAddress(Guid guid)
    {
        return string.Format(CultureInfo.CurrentCulture, "net.pipe://localhost/{0}", guid);
    }

    /// <summary>
    /// The interface that describes the single instance service.
    /// </summary>
    [ServiceContract]
    private interface ISingleInstance
    {
        /// <summary>
        /// Notifies the main instance that another instance of the application attempted to start.
        /// </summary>
        /// <param name="args">The other instance's command-line arguments.</param>
        [OperationContract]
        void NotifyMainInstance(string[] args);
    }

    /// <summary>
    /// The implementation of the single instance service interface.
    /// </summary>
    private class SingleInstance : ISingleInstance
    {
        /// <summary>
        /// Notifies the main instance that another instance of the application attempted to start.
        /// </summary>
        /// <param name="args">The other instance's command-line arguments.</param>
        public void NotifyMainInstance(string[] args)
        {
            if (OtherInstanceStarted != null)
            {
                Type type = typeof(StartupEventArgs);
                ConstructorInfo constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
                StartupEventArgs e = (StartupEventArgs)constructor.Invoke(null);
                FieldInfo argsField = type.GetField("_args", BindingFlags.Instance | BindingFlags.NonPublic);
                Debug.Assert(argsField != null);
                argsField.SetValue(e, args);

                OtherInstanceStarted(null, e);
            }
        }
    }
}

在 Winforms Main 上:

static void Main()
{
  //bool isSingle;
  //var mut = new Mutex(true, "MarketFeeder", out isSingle);
  var applicationId = new Guid("08f21b4e-86d7-4ddf-abcb-9a72cd2bbd4f");

   if (SingleInstanceManager.VerifySingleInstance(applicationId))
    {
        SingleInstanceManager.OtherInstanceStarted += OnOtherInstanceStarted;
            // Start the application

        System.Windows.Forms.Application.EnableVisualStyles();
        System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false);
        main = new MainForm();
        System.Windows.Forms.Application.Run(main);
    }     

}

需要帮助

有没有办法通过 Namedpipe 在同一台机器上的用户之间进行通信?,我不想为我的要求去寻求“Windows 服务”,我觉得我的要求太过分了。

已经通过以下链接但没有运气。他们也太老了,我觉得我们最近有更好的解决方案。我希望有一些像我一样的开发人员仍在开发 Windows 应用程序:P

终端服务器会话中的隔离命名管道

标签: c#wcfnamed-pipes

解决方案


推荐阅读