Win32:如何获得拥有互斥量的进程/线程?

我正在开发一个应用程序,其中只有一个实例必须在任何给定时间存在。 有几种可能性来实现这一点:

  • 检查正在运行的进程是否与我们的EXE名称相匹配(不可靠)
  • 找到主窗口(不可靠的,我并不总是有一个主窗口)
  • 创建一个唯一名称的互斥体(GUID)
  • 互斥选项在我看来最可靠和优雅。

    但是,在我的第二个实例终止之前,我想向已经运行的实例发布消息。 为此,我需要一个拥有互斥锁的线程(或进程)的句柄。

    但是,似乎没有API函数来获取给定互斥体的创建者/所有者。 我只是俯视它吗? 是否有另一种方法可以进入该线程/进程? 还有另外一种方法可以解决这个问题吗?

    更新:这家伙只是向所有正在运行的进程广播一条消息。 我想这是可能的,但我不太喜欢它...


    我认为解决Mutex的实际所有者并不是一个简单的方法,但拥有它的过程可以创建其生命周期与其相关的其他次要项目。 有很多机制适合跨进程回调而不需要主窗口。

  • 在COM运行对象表中注册一个对象。 无法取得Mutex所有权的客户可以通过ROT查找所有者,并回复所有者。 File Moniker应该适合在这里注册。
  • 创建一个包含所有者进程位置详细信息的共享内存块。 从那里,将可以接收Windows消息的线程的进程句柄和线程句柄写入缓冲区,然后使用PostThreadMessage()发送通知。 任何其他竞争进程可能会打开共享内存以进行只读以确定发送Windows消息的位置。
  • 在套接字或命名管道上监听所有者进程。 可能矫枉过正,不适合您的需求。
  • 使用锁定的共享文件。 我不喜欢这样做,因为业主需要投票,而且它不会优雅地处理可能试图与业主同时联系的其他潜在业务流程。
  • 以下是前两个选项的参考链接。

  • IRunningObjectTable @ MSDN,File Monikers @ MSDN
  • 创建命名的共享内存@ MSDN

  • 这应该让您开始获取拥有互斥锁的进程的原始请求。

    它在C#中,但Win32调用是相同的。

    class HandleInfo
    {
        [DllImport("ntdll.dll", CharSet = CharSet.Auto)]
        public static extern uint NtQuerySystemInformation(int SystemInformationClass, IntPtr SystemInformation, int SystemInformationLength, out int ReturnLength);
    
        [DllImport("kernel32.dll", SetLastError = true)]
        internal static extern IntPtr VirtualAlloc(IntPtr address, uint numBytes, uint commitOrReserve, uint pageProtectionMode);
    
        [DllImport("kernel32.dll", SetLastError=true)]
        internal static extern bool VirtualFree(IntPtr address, uint numBytes, uint pageFreeMode);
    
        [StructLayout(LayoutKind.Sequential)]
        public struct SYSTEM_HANDLE_INFORMATION
        {
            public int ProcessId;
            public byte ObjectTypeNumber;
            public byte Flags; // 1 = PROTECT_FROM_CLOSE, 2 = INHERIT
            public short Handle;
            public int Object;
            public int GrantedAccess;
        }
    
        static uint MEM_COMMIT = 0x1000;
        static uint PAGE_READWRITE = 0x04;
        static uint MEM_DECOMMIT = 0x4000;
        static int SystemHandleInformation = 16;
        static uint STATUS_INFO_LENGTH_MISMATCH = 0xC0000004;
    
        public HandleInfo()
        {
            IntPtr memptr = VirtualAlloc(IntPtr.Zero, 100, MEM_COMMIT, PAGE_READWRITE);
    
            int returnLength = 0;
            bool success = false;
    
            uint result = NtQuerySystemInformation(SystemHandleInformation, memptr, 100, out returnLength);
            if (result == STATUS_INFO_LENGTH_MISMATCH)
            {
                success = VirtualFree(memptr, 0, MEM_DECOMMIT);
                memptr = VirtualAlloc(IntPtr.Zero, (uint)(returnLength + 256), MEM_COMMIT, PAGE_READWRITE);
                result = NtQuerySystemInformation(SystemHandleInformation, memptr, returnLength, out returnLength);
            }
    
            int handleCount = Marshal.ReadInt32(memptr);
            SYSTEM_HANDLE_INFORMATION[]  returnHandles = new SYSTEM_HANDLE_INFORMATION[handleCount];
    
            using (StreamWriter sw = new StreamWriter(@"C:NtQueryDbg.txt"))
            {
                sw.WriteLine("@ OffsettProcess IdtHandle IdtHandleType");
                for (int i = 0; i < handleCount; i++)
                {
                    SYSTEM_HANDLE_INFORMATION thisHandle = (SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(
                        new IntPtr(memptr.ToInt32() + 4 + i * Marshal.SizeOf(typeof(SYSTEM_HANDLE_INFORMATION))),
                        typeof(SYSTEM_HANDLE_INFORMATION));
                    sw.WriteLine("{0}t{1}t{2}t{3}", i.ToString(), thisHandle.ProcessId.ToString(), thisHandle.Handle.ToString(), thisHandle.ObjectTypeNumber.ToString());
                }
            }
    
            success = VirtualFree(memptr, 0, MEM_DECOMMIT);
        }
    }
    

    我从来没有真正理解使用无信号能力的Mutex的理由。 相反,我会创建一个事件(使用CreateEvent),它具有与创建互斥体相同的属性(例如,可以返回该对象已存在的名称),但您可以在新流程中设置事件标志,只要原始进程正在等待事件标志,它可以在需要唤醒自己时通知它。

    链接地址: http://www.djcxy.com/p/51215.html

    上一篇: Win32: How to get the process/thread that owns a mutex?

    下一篇: throw an exception in C#?