문제

주어진 시간에 하나의 인스턴스 만 존재 해야하는 응용 프로그램을 중단하고 있습니다. 이를 달성 할 수있는 몇 가지 가능성이 있습니다.

  • EXE 이름과 일치하는 하나의 실행 프로세스를 확인하십시오 (신뢰할 수없는)
  • 기본 창을 찾으십시오 (신뢰할 수없고 항상 기본 창이있는 것은 아닙니다)
  • 고유 한 이름 (Guid)으로 Mutex를 만듭니다.

Mutex 옵션은 나에게 가장 신뢰할 수 있고 우아한 것 같습니다.

그러나 두 번째 인스턴스가 종료되기 전에 이미 실행중인 인스턴스에 메시지를 게시하고 싶습니다. 이를 위해서는 뮤텍스를 소유 한 스레드 (또는 프로세스)에 대한 핸들이 필요합니다.

그러나 주어진 뮤트의 제작자/소유자를 얻는 API 기능이없는 것 같습니다. 방금 간과하고 있습니까? 이 스레드/프로세스에 도달하는 또 다른 방법이 있습니까? 이것에 대해 다른 방법이 있습니까?

업데이트: 이 남자 메시지를 간단히 방송합니다 모두 실행 프로세스. 가능하다고 생각하지만 정말 좋아하지 않습니다 ...

도움이 되었습니까?

해결책

나는 뮤텍스의 실제 소유자를 해결하는 사소한 방법이 없다고 생각하지만, 그것을 소유 한 프로세스는 평생이 묶인 다른 2 차 항목을 만들 수 있다고 생각합니다. 기본 창이없는 채로 처리하기에 적합한 메커니즘이 많이 있습니다.

  1. COM 실행 객체 테이블에 객체를 등록하십시오. Mutex의 소유권을 얻을 수없는 고객은 부패를 통해 소유자를 조회하고 소유자에게 다시 전화 할 수 있습니다. 파일 모니 커는 여기에서 등록하기에 적합해야합니다.
  2. 소유자 프로세스에 대한 위치 세부 정보가 포함 된 공유 메모리 덩어리를 만듭니다. 거기에서 Wind 다른 경쟁 프로세스는 공유 메모리를 읽기 전용으로 열어 Windows 메시지를 보낼 위치를 결정할 수 있습니다.
  3. 소켓이나 이름이 지정된 파이프에서 소유자 프로세스를 듣습니다. 아마도 과잉과 당신의 요구에 잘 어울리지 않을 것입니다.
  4. 잠금이있는 공유 파일을 사용하십시오. 소유자가 여론 조사를해야하기 때문에 나는 이것을 좋아하지 않으며, 동시에 소유자에게 연락 할 수있는 잠재적 인 다른 프로세스를 우아하게 처리하지는 않을 것입니다.

다음은 처음 두 옵션에 대한 참조 링크입니다.

  1. irunningobjecttable @ msdn , 파일 monikers @ msdn
  2. 이름이 지정된 공유 메모리 생성 @ 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("@ 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 파일의 프로세스가 실제로 살아 있는지 확인해야합니다 (앱이 비정상적으로 종료되고 파일이 삭제되지 않는 경우).

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top