Я работаю, приложение которого только один экземпляр должен существовать в любой момент времени. Существует несколько возможностей выполнить это:
Взаимоисключающая опция кажется мне самым надежным и изящным.
Однако, прежде чем мой второй экземпляр завершается, я хочу добавить сообщение к уже рабочему экземпляру. Для этого мне нужен дескриптор к потоку (или процесс), который владеет взаимным исключением.
Однако, кажется, нет никакой API-функции для получения создателя/владельца данного взаимного исключения. Я просто пропускаю его? Там другой путь состоит в том, чтобы добраться до этого потока/процесса? Там другой путь состоит в том, чтобы пойти об этом?
Обновление: Этот парень просто широковещательно передал сообщение ко всем рабочим процессам. Я предполагаю, что это возможно, но мне действительно не нравится он...
Я не думаю, что существует тривиальный способ решения вопроса о фактическом владельце Мьютекса, но процесс, который владеет им, может создать другие вторичные элементы, чья жизнь связана с ним. Существует множество механизмов, которые подходят для обратного вызова через процесс без наличия главного окна.
Вот ссылки на первые два варианта.
Это должно привести к началу выполнения первоначального запроса на получение процесса, которому принадлежит мьютекс.
Это на 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), которое имеет те же свойства, что и создание мьютекса (т.е. с именем, которое может вернуть, что объект уже существовал), но вы можете установить флаг события в новом процессе, пока исходный процесс ждет флага события, о котором он может быть уведомлен, когда ему понадобится разбудить себя.
.Вы всегда можете сделать это UNIX способом и создать "pid" файл, поместив в него идентификатор процесса выполняющегося в данный момент экземпляра. Затем заставить приложение удалить файл при выходе.
При запуске нового экземпляра оно должно проверить, что процесс в PID-файле на самом деле также жив (в случае, если приложение выходит аномально и файл не удаляется)
.