如何在 Citrix 系统上获得用户的 UNIQUE window?

How can I get a UNIQUE window of the user on a Citrix system?

我正在创建一个将 运行 在 Citrix 上的应用程序,该应用程序将 运行 在多用户登录的计算机上。

场景如下:用户 A 登录到机器 1。用户 B 登录到机器 1 我们的程序在用户 A 登录时启动。用户 B 然后打开任何程序(我们正在监视)并且应该收到询问问题的对话。但是,不是用户 B 收到对话,而是用户 A 收到对话。

我怎样才能将我们的对话框显示给正确的用户?

我尝试将对话框设置为桌面,认为每个用户都有自己独特的桌面,但这没有用。 (参见 this

如有任何建议/想法/示例,我们将不胜感激。

谢谢

事实证明,在 citrix 系统(和 windows OS)上,每个进程都与一个用户 SID 相关联。但是,在 citrix 系统上,当我设置 WMI 查询以监视特定进程时,我会收到与该进程交互的任何用户的通知。

所以我的应用程序不仅需要跟踪我感兴趣的进程,还需要跟踪与该进程交互的用户。

此代码找出谁拥有该进程:(当然,缺少的是检测进程 activity 并调用 'GetProcessOwnerInformation' 的代码,但这留作 reader :-) )

    private ProcessOwnerInformation GetProcessOwnerInformation(uint processId)
    {
        WindowsIdentity _user = WindowsIdentity.GetCurrent();
        string stringSID = string.Empty;
        string process = ExGetProcessInfoByPID((int)processId, out stringSID);

        bool bIgnoreCase = true;

        ProcessOwnerInformation retval = new ProcessOwnerInformation();
        bool bOwnsProcess = string.Compare(stringSID, _user.User.Value, bIgnoreCase) == 0;
        if(bOwnsProcess)
        {
            retval.procID = processId;
            retval.OwnsProcess = bOwnsProcess;
            retval.SID = stringSID;
        }

        return retval;
    }


    public const int TOKEN_QUERY = 0X00000008;

    const int ERROR_NO_MORE_ITEMS = 259;

    enum TOKEN_INFORMATION_CLASS
    {
        TokenUser = 1,
        TokenGroups,
        TokenPrivileges,
        TokenOwner,
        TokenPrimaryGroup,
        TokenDefaultDacl,
        TokenSource,
        TokenType,
        TokenImpersonationLevel,
        TokenStatistics,
        TokenRestrictedSids,
        TokenSessionId
    }

    [StructLayout(LayoutKind.Sequential)]
    struct TOKEN_USER
    {
        public _SID_AND_ATTRIBUTES User;
    }


    [StructLayout(LayoutKind.Sequential)]
    public struct _SID_AND_ATTRIBUTES
    {
        public IntPtr Sid;
        public int Attributes;
    }

    [DllImport("advapi32")]
    static extern bool OpenProcessToken(
        IntPtr ProcessHandle, // handle to process
        int DesiredAccess, // desired access to process
        ref IntPtr TokenHandle // handle to open access token
    );

    [DllImport("kernel32")]
    static extern IntPtr GetCurrentProcess();

    [DllImport("advapi32", CharSet = CharSet.Auto)]
    static extern bool GetTokenInformation(
        IntPtr hToken,
        TOKEN_INFORMATION_CLASS tokenInfoClass,
        IntPtr TokenInformation,
        int tokeInfoLength,
        ref int reqLength
    );

    [DllImport("kernel32")]
    static extern bool CloseHandle(IntPtr handle);

    [DllImport("advapi32", CharSet = CharSet.Auto)]
    static extern bool ConvertSidToStringSid(
        IntPtr pSID,
        [In, Out, MarshalAs(UnmanagedType.LPTStr)] ref string pStringSid
    );

    [DllImport("advapi32", CharSet = CharSet.Auto)]
    static extern bool ConvertStringSidToSid(
        [In, MarshalAs(UnmanagedType.LPTStr)] string pStringSid,
        ref IntPtr pSID
    );


    public static bool DumpUserInfo(IntPtr pToken, out IntPtr SID)
    {
        int Access = TOKEN_QUERY;
        IntPtr procToken = IntPtr.Zero;
        bool ret = false;
        SID = IntPtr.Zero;
        try
        {
            if (OpenProcessToken(pToken, Access, ref procToken))
            {
                ret = ProcessTokenToSid(procToken, out SID);
                CloseHandle(procToken);
            }
            return ret;
        }
        catch (Exception err)
        {
            return false;
        }
    }

    private static bool ProcessTokenToSid(IntPtr token, out IntPtr SID)
    {
        TOKEN_USER tokUser;
        const int bufLength = 256;
        IntPtr tu = Marshal.AllocHGlobal(bufLength);
        bool ret = false;
        SID = IntPtr.Zero;
        try
        {
            int cb = bufLength;
            ret = GetTokenInformation(token, TOKEN_INFORMATION_CLASS.TokenUser, tu, cb, ref cb);
            if (ret)
            {
                tokUser = (TOKEN_USER)Marshal.PtrToStructure(tu, typeof(TOKEN_USER));
                SID = tokUser.User.Sid;
            }
            return ret;
        }
        catch (Exception err)
        {
            return false;
        }
        finally
        {
            Marshal.FreeHGlobal(tu);
        }
    }

    public static string ExGetProcessInfoByPID(int PID, out string SID)//, out string OwnerSID)
    {
        IntPtr _SID = IntPtr.Zero;
        SID = String.Empty;
        try
        {
            Process process = Process.GetProcessById(PID);
            if (DumpUserInfo(process.Handle, out _SID))
            {
                ConvertSidToStringSid(_SID, ref SID);
            }
            return process.ProcessName;
        }
        catch
        {
            return "Unknown";
        }
    }