Win32: как получить процесс / поток, которому принадлежит мьютекс?
Я работаю с приложением, в котором в любой момент времени должен существовать только один экземпляр. Для этого есть несколько возможностей:
- Проверьте запущенные процессы на соответствие имени нашего EXE (ненадежно)
- найти главное окно (ненадежно, и у меня не всегда есть главное окно)
- Создайте мьютекс с уникальным именем (GUID)
Вариант мьютекса кажется мне наиболее надежным и элегантным.
Однако, прежде чем мой второй экземпляр завершится, Я хочу отправить сообщение в уже запущенный экземпляр. Для этого мне нужен дескриптор потока (или процесса), которому принадлежит мьютекс.
Однако, похоже, нет никакой функции API, чтобы получить создателя / владельца данного мьютекса. Неужели я просто не замечаю этого? Есть ли другой способ добраться до этого потока/процесса? Есть ли другой способ сделать это?
обновление: Этот парень просто передает сообщение всем запущенным процессам. Наверное, это возможно, но я ... мне это не очень нравится...
5 ответов:
Я не думаю, что существует тривиальный способ решить вопрос о фактическом владельце мьютекса, но процесс, которому он принадлежит, может создавать другие вторичные элементы, время жизни которых связано с ним. Существует множество механизмов, которые подходят для обратного вызова через весь процесс без наличия главного окна.
- зарегистрируйте объект в таблице com Running Object. Клиенты, которые не могут стать владельцами мьютекса, могут искать владельца через ROT и перезванивать владельцу. Имя файла должно быть подходит для регистрации здесь.
- Создайте фрагмент общей памяти, содержащий сведения о местоположении для процесса владельца. Оттуда запишите в буфер дескриптор процесса и дескриптор потока потока, который может получать сообщения windows, а затем используйте PostThreadMessage() для отправки уведомления. Любой другой конкурирующий процесс может открыть общую память только для чтения, чтобы определить, куда отправить сообщение windows.
- прослушивание в процессе владельца сокета или именованного канала. Наверное, перебор и не очень подходит для ваших нужд.
- Используйте общий файл с блокировкой. Мне это не нравится, потому что владельцу нужно будет опрашивать, и он не будет изящно обрабатывать N потенциальных других процессов, которые могут одновременно пытаться связаться с владельцем.
Здесь приведены ссылки на первые два варианта.
Это должно помочь вам начать работу над исходным запросом, чтобы получить процесс, которому принадлежит мьютекс.
Это в 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("@ Offset\tProcess Id\tHandle Id\tHandleType"); 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); } }
Я никогда по-настоящему не понимал рациональности использования мьютекса, который не имеет сигнальной способности. Вместо этого я бы создал событие (используя CreateEvent), которое имеет те же свойства, что и создание мьютекса (т. е. с именем, которое он может вернуть, что объект уже существовал), но вы можете установить флаг события в новом процессе, пока исходный процесс ожидает флаг события, он может быть уведомлен, когда ему нужно проснуться.
Создайте разделяемую область памяти с фиксированным именем:
Http://msdn.microsoft.com/en-us/library/aa366551%28VS.85%29.aspx
После этого вы можете поместить любую структуру, которая вам нравится, включая идентификатор процесса, HWND и т. д.
Есть переносная опция : Создайте сокет на порту (с фиксированным номером) и подождите (примите) на нем. Второй экземпляр приложения завершится неудачей, так как порт уже занят. Затем второй экземпляр может подключиться к разъему первичный экземпляр и отправить любую желаемую информацию.
Надеюсь, это поможет...
Вы всегда можете сделать это способом UNIX и создать файл "pid", поместив в этот файл идентификатор процесса текущего запущенного экземпляра. Затем попросите приложение удалить файл при выходе.
Когда запускается новый экземпляр, он должен проверить, что процесс в файле PID действительно жив (в случае, если приложение завершает работу ненормально и файл не удаляется)
Comments