PInvoke PostMessage不适用于用户帐户

时间:2015-06-24 14:12:45

标签: c# .net wpf user32 inter-process-communicat

我正在为我的应用程序构建一个kill开关,这样一台计算机上一次只能运行一个实例。我是通过在正在运行的应用程序的进程和应用程序的新实例的进程之间发布消息来实现此目的的:

[DllImport("user32.dll", EntryPoint = "PostMessageA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int PostMessage(int hwnd, int wMsg, int wParam, int lParam);

我无法使用Process.Kill,因为如果另一个用户正在运行该应用程序并且当前用户没有足够的权限我会遇到问题。

在同一个用户帐户下运行2个实例时,我没有任何问题。消息正确发送并正确接收。但是,当从一个用户帐户运行一个实例,然后切换用户并运行第二个实例时,我的第一个实例没有收到消息。

这是订阅窗口消息的逻辑:

var wih = new WindowInteropHelper(this);
var hwndSource = HwndSource.FromHwnd(wih.Handle);
var hwndSourceHook = new HwndSourceHook(HookHandler);

if (hwndSource != null)
    hwndSource.AddHook(hwndSourceHook);

这是我的钩子处理程序:

private IntPtr HookHandler(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        handled = false;

        switch (msg)
        {
            case 0x400: // interprocess message received
                App.InterprocessManager.BuildString(lParam);
                break;
        }
        return IntPtr.Zero;
    }

这是发送消息的逻辑:

private void SendString()
    {
        //create byte array
        byte[] ba = null;
        //encode string to byte array
        if (object.ReferenceEquals(enc, Encoding.UTF8))
        {
            ba = Encoding.UTF8.GetBytes(lParam);
        }
        else if (object.ReferenceEquals(enc, Encoding.Unicode))
        {
            ba = Encoding.Unicode.GetBytes(lParam);
        }
        else if (object.ReferenceEquals(enc, Encoding.ASCII))
        {
            ba = Encoding.ASCII.GetBytes(lParam);
        }
        else
        {
            ba = Encoding.Default.GetBytes(lParam);
        }
        int i = 0;
        for (i = 0; i <= ba.Length - 1; i++)
        {
            //start post message
            PostMessage(hwnd, wMsg, wParam, ba[i]);
        }
        //post a terminator message to destination window
        PostMessage(hwnd, wMsg, wParam, 0);
    }

PostMessage函数没有设置Win32错误。我似乎找不到任何关于在跨用户帐户的进程之间发布消息的文档。这件事实际上无法完成吗?

1 个答案:

答案 0 :(得分:1)

您无法将窗口消息发送到其他会话中的进程。您必须使用基于内核而不是用户对象的IPC机制。

在您的场景中,可能只需要一个名为mutex和一个名为信号量的信号量。请注意,名称必须具有Global\前缀,以允许多个会话共享单个对象。

在流程启动时,首先创建或打开信号量。将初始计数设置为零。

然后创建名为mutex且bInitialOwner设置为TRUE,并检查上一个错误代码以查看互斥锁是否已存在。

如果互斥锁尚不存在,则您是第一个实例,因此创建一个线程以等待信号量。如果信号量已发出信号,请退出该过程。确保您不会释放互斥锁,直到其他进程运行安全为止;如果有疑问,根本不要发布它。一旦进程退出,Windows就会将其标记为已弃用。

如果互斥锁已经存在,则另一个实例正在运行。发信号通知信号量,然后等待互斥锁。一旦您获得互斥锁的所有权,就可以继续使用。然后,您需要创建一个线程来等待信号量,以防另一个实例出现并想要碰到你。

如果您需要在流程之间建立更复杂的通信渠道,例如,如果您需要移交通信渠道的当前状态,那么您的最佳选择可能是named pipes