Win32 : 뮤텍스를 소유 한 프로세스/스레드를 얻는 방법은 무엇입니까?
-
20-09-2019 - |
문제
주어진 시간에 하나의 인스턴스 만 존재 해야하는 응용 프로그램을 중단하고 있습니다. 이를 달성 할 수있는 몇 가지 가능성이 있습니다.
- EXE 이름과 일치하는 하나의 실행 프로세스를 확인하십시오 (신뢰할 수없는)
- 기본 창을 찾으십시오 (신뢰할 수없고 항상 기본 창이있는 것은 아닙니다)
- 고유 한 이름 (Guid)으로 Mutex를 만듭니다.
Mutex 옵션은 나에게 가장 신뢰할 수 있고 우아한 것 같습니다.
그러나 두 번째 인스턴스가 종료되기 전에 이미 실행중인 인스턴스에 메시지를 게시하고 싶습니다. 이를 위해서는 뮤텍스를 소유 한 스레드 (또는 프로세스)에 대한 핸들이 필요합니다.
그러나 주어진 뮤트의 제작자/소유자를 얻는 API 기능이없는 것 같습니다. 방금 간과하고 있습니까? 이 스레드/프로세스에 도달하는 또 다른 방법이 있습니까? 이것에 대해 다른 방법이 있습니까?
업데이트: 이 남자 메시지를 간단히 방송합니다 모두 실행 프로세스. 가능하다고 생각하지만 정말 좋아하지 않습니다 ...
해결책
나는 뮤텍스의 실제 소유자를 해결하는 사소한 방법이 없다고 생각하지만, 그것을 소유 한 프로세스는 평생이 묶인 다른 2 차 항목을 만들 수 있다고 생각합니다. 기본 창이없는 채로 처리하기에 적합한 메커니즘이 많이 있습니다.
- COM 실행 객체 테이블에 객체를 등록하십시오. Mutex의 소유권을 얻을 수없는 고객은 부패를 통해 소유자를 조회하고 소유자에게 다시 전화 할 수 있습니다. 파일 모니 커는 여기에서 등록하기에 적합해야합니다.
- 소유자 프로세스에 대한 위치 세부 정보가 포함 된 공유 메모리 덩어리를 만듭니다. 거기에서 Wind 다른 경쟁 프로세스는 공유 메모리를 읽기 전용으로 열어 Windows 메시지를 보낼 위치를 결정할 수 있습니다.
- 소켓이나 이름이 지정된 파이프에서 소유자 프로세스를 듣습니다. 아마도 과잉과 당신의 요구에 잘 어울리지 않을 것입니다.
- 잠금이있는 공유 파일을 사용하십시오. 소유자가 여론 조사를해야하기 때문에 나는 이것을 좋아하지 않으며, 동시에 소유자에게 연락 할 수있는 잠재적 인 다른 프로세스를 우아하게 처리하지는 않을 것입니다.
다음은 처음 두 옵션에 대한 참조 링크입니다.
다른 팁
이를 통해 원래 요청을 시작하여 뮤텍스를 소유 한 프로세스를 얻을 수 있습니다.
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);
}
}
나는 신호 전달 능력이없는 뮤텍스를 사용하여 합리적인 것을 이해하지 못했습니다. 대신 뮤트를 만드는 것과 동일한 속성을 가진 이벤트 (즉, 이름을 가진 이름을 가진 객체가 이미 존재하는 객체를 반환 할 수 있음)를 사용하는 이벤트를 만듭니다. 프로세스가 이벤트 플래그에서 기다리고 있습니다.
a 공유 메모리 영역 고정 이름으로 :
http://msdn.microsoft.com/en-us/library/aa366551%28vs.85%29.aspx
그런 다음 프로세스 ID, HWND 등을 포함하여 원하는 구조를 내부에 넣을 수 있습니다.
휴대용 옵션이 있습니다: 포트에 소켓을 생성 (고정 번호)를 대기 (수락). 포트가 이미 사용 된 상태에서 앱의 두 번째 인스턴스가 실패합니다. 그런 다음 두 번째 인스턴스는 기본 인스턴스의 소켓에 연결하여 원하는 정보를 보낼 수 있습니다.
이게 도움이 되길 바란다...
항상 Unix 방식을 수행하고 "PID"파일을 만들 수 있으며 현재 실행중인 인스턴스의 프로세스 ID를 해당 파일에 넣을 수 있습니다. 그런 다음 앱이 종료 될 때 파일을 삭제하도록하십시오.
새 인스턴스가 시작되면 PID 파일의 프로세스가 실제로 살아 있는지 확인해야합니다 (앱이 비정상적으로 종료되고 파일이 삭제되지 않는 경우).