2009-12-22 13 views
7

मैं एक आवेदन कर रहा हूं जिसमें किसी भी समय केवल एक उदाहरण मौजूद होना चाहिए। वहाँ कई संभावनाओं यह पूरा करने के हैं: एक हमारे EXE का नाम (अविश्वसनीय) Win32: एक mutex के मालिक/प्रक्रिया को कैसे प्राप्त करें?

  • मुख्य विंडो का पता लगाएं मिलान के लिए

    • चेक प्रक्रिया चल (अविश्वसनीय है, और मैं हमेशा एक मुख्य विंडो नहीं है)
    • एक अद्वितीय नाम (GUID)

    म्यूटेक्स विकल्प मुझे सबसे विश्वसनीय और सुरुचिपूर्ण लगता है।

    हालांकि, मेरे दूसरे उदाहरण को समाप्त करने से पहले, मैं पहले से चल रहे उदाहरण पर एक संदेश पोस्ट करना चाहता हूं। इसके लिए, मुझे थ्यूट (या प्रक्रिया) के लिए एक हैंडल की आवश्यकता है जो म्यूटेक्स का मालिक है।

    हालांकि, किसी दिए गए म्यूटेक्स के निर्माता/मालिक को प्राप्त करने के लिए कोई एपीआई फ़ंक्शन नहीं लगता है। क्या मैं बस इसे देख रहा हूँ? क्या इस धागे/प्रक्रिया को पाने का कोई और तरीका है? क्या इस बारे में जाने का कोई और तरीका है?

    अद्यतन: This guy बस के लिए एक संदेश प्रसारित सभी प्रक्रिया चल। मुझे लगता है कि यह संभव है, लेकिन मुझे वास्तव में यह पसंद नहीं है ...

  • +0

    डुप्लिकेट? http://stackoverflow.com/questions/19147/what-is-the-correct-way-to-create-a-single-instance-plication –

    +0

    वास्तव में नहीं। कोई भी जवाब मुझे बताता है कि प्रक्रिया संभाल कैसे प्राप्त करें। – Thomas

    +0

    यहां एक डुप्लिकेट है, हालांकि इसका कभी जवाब नहीं दिया गया था: http://stackoverflow.com/questions/541477/c-how-can-i-get-owners-name-for-a-mutex –

    उत्तर

    4

    मुझे नहीं लगता कि म्यूटेक्स के वास्तविक मालिक को हल करने का एक छोटा रास्ता है, लेकिन जिस प्रक्रिया का स्वामित्व है वह अन्य माध्यमिक वस्तुओं को बना सकता है जिनके जीवनकाल इसके साथ बंधे होते हैं। वहां बहुत सारी तंत्र हैं जो मुख्य विंडो के बिना पूरी प्रक्रिया को वापस कॉल करने के लिए उपयुक्त हैं।

    1. COM रनिंग ऑब्जेक्ट टेबल में किसी ऑब्जेक्ट को पंजीकृत करें। ग्राहक जो म्यूटेक्स के स्वामित्व लेने में असमर्थ हैं, मालिक को आरओटी के माध्यम से देख सकते हैं और मालिक को वापस कॉल कर सकते हैं। यहां एक फ़ाइल मोनिकर पंजीकरण के लिए उपयुक्त होना चाहिए।
    2. स्वामी की प्रक्रिया के लिए स्थान विवरण वाले साझा मेमोरी का एक हिस्सा बनाएं। वहां से, बफर में प्रक्रिया संभाल और थ्रेड के थ्रेड हैंडल को लिखें जो विंडोज संदेशों को प्राप्त कर सकता है, और उसके बाद अधिसूचना भेजने के लिए PostThreadMessage() का उपयोग करें। कोई भी अन्य प्रतिस्पर्धी प्रक्रिया केवल पढ़ने के लिए साझा स्मृति को खोल सकती है ताकि यह निर्धारित किया जा सके कि विंडोज संदेश कहां भेजना है।
    3. सॉकेट या नामांकित पाइप पर मालिक प्रक्रिया में सुनो। शायद आपकी जरूरतों के लिए एक अच्छा मैच और अधिक नहीं।
    4. लॉकिंग के साथ साझा फ़ाइल का उपयोग करें। मुझे इसका शौक नहीं है क्योंकि मालिक को मतदान करने की आवश्यकता होगी, और यह एन संभावित अन्य प्रक्रियाओं को अच्छी तरह से संभाल नहीं पाएगा जो एक ही समय में मालिक से संपर्क करने का प्रयास कर सकते हैं।

    यहां पहले दो विकल्पों के संदर्भ लिंक हैं।

    1. IRunningObjectTable @ MSDN, File Monikers @ MSDN
    2. Creating Named Shared Memory @ MSDN
    2

    मैंने कभी म्यूटेक्स का उपयोग करने के पीछे तर्कसंगत नहीं समझा है जिसमें कोई सिग्नलिंग क्षमता नहीं है। मैं इसके बजाय एक ईवेंट (CreateEvent का उपयोग करके) बनाउंगा जिसमें एक म्यूटेक्स बनाने के समान गुण होते हैं (यानी एक नाम के साथ यह वस्तु वापस आ सकती है कि ऑब्जेक्ट पहले से मौजूद है) लेकिन आप ईवेंट को ध्वज को नई प्रक्रिया में सेट कर सकते हैं, जब तक मूल प्रक्रिया घटना ध्वज पर इंतजार कर रही है जिसे इसे स्वयं जागने की आवश्यकता होने पर अधिसूचित किया जा सकता है।

    +0

    बेशक, मूल प्रक्रिया किसी घटना के लिए प्रतीक्षा अवरुद्ध नहीं कर रही है; यह सिर्फ अपने संदेश पाश में सर्किल चला रहा है। (मैं लूप के माध्यम से हर बार म्यूटेक्स की जांच कर सकता हूं, लेकिन यह बुरा लगता है।) – Thomas

    +0

    आप हमेशा एक और थ्रेड चला सकते हैं, इसे घटना पर सो सकते हैं, और कुछ होने पर संदेश लूप पर पोस्ट कर सकते हैं। – Thanatos

    +2

    वहाँ MsgWaitForMultipleObjects भी है जो आपको या तो एक विंडोज संदेश आने या प्रतीक्षा करने योग्य हैंडल (कहने और ईवेंट या म्यूटेक्स) के लिए इंतजार करने की अनुमति देता है ताकि आप इसे एक थ्रेड में करने की अनुमति दे सकें। – tyranid

    1

    आप इसे हमेशा यूनिक्स तरीके से कर सकते हैं और एक "पिड" फ़ाइल बना सकते हैं, जो उस फ़ाइल में वर्तमान में चल रहे इंस्टेंस की प्रक्रिया आईडी डाल रहा है। फिर ऐप बाहर निकलने पर फ़ाइल को हटा दें।

    एक नया उदाहरण शुरू होता है यह सत्यापित करना चाहिए कि पीआईडी ​​फ़ाइल में प्रक्रिया के रूप में अच्छी तरह से वास्तव में जिंदा है (मामले में एप्लिकेशन असामान्य रूप से बाहर निकल जाता है और फ़ाइल हटा दिया जाता है नहीं है)

    +0

    +1। आप एक अलग म्यूटेक्स की बजाय इस फ़ाइल पर फ़ाइल लॉक का भी उपयोग कर सकते हैं। –

    +0

    इसी तरह, क्या आप साझा स्मृति का उपयोग कर सकते हैं, और वहां पीआईडी ​​लिख सकते हैं? – Thanatos

    +0

    फाइल सिस्टम के माध्यम से जाने की कोई ज़रूरत नहीं है, असल में ... साझा स्मृति का एक टुकड़ा ('CreateFileMapping') ठीक काम करेगा। मुझे इस ट्रैक पर रखने के लिए धन्यवाद। मैं इसे तब तक स्वीकार करूंगा जब तक कि कोई बेहतर समाधान न करे। – Thomas

    10

    यह मिलना चाहिए आप एक प्रक्रिया है कि एक म्युटेक्स मालिक प्राप्त करने के लिए मूल अनुरोध पर शुरू कर दिया।

    यह सी # में है, लेकिन 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); 
        } 
    } 
    
    +0

    "विंडोज़ के भविष्य के संस्करणों में NtQuerySystemInformation को बदला या अनुपलब्ध किया जा सकता है। अनुप्रयोगों को इस विषय में सूचीबद्ध वैकल्पिक कार्यों का उपयोग करना चाहिए।" और SystemHandleInformation पूरी तरह से अनियंत्रित है। ओह! – Thomas

    +8

    असल में, मैं बस आपकी मदद करने की कोशिश कर रहा था।मुझे अपने कुछ गूढ़ सी ++ कोड को वापस रास्ते से खोदना पड़ा, लेकिन वीसी 6 में वापस घुसने की बजाए, मैंने इसे आपके और दूसरों के लिए सी # पर बंद करने का फैसला किया (इसे थोड़ा और अधिक चालू करने के लिए)। मुझे लगता है कि मुझे नहीं पता था कि आप अनियंत्रित सामान का उपयोग नहीं कर सके, आपने अभी पूछा कि क्या यह संभव था ... – GalacticJello

    +0

    इस कोड से आप मालिक की स्थिति और पीआईडी ​​/ थ्रेड आईडी प्राप्त करने के लिए 'NtQueryMutant' पर कॉल करेंगे और कॉल करेंगे मालिक। –

    2

    तय नाम के साथ एक साझा स्मृति क्षेत्र बनाएँ: HWND

    http://msdn.microsoft.com/en-us/library/aa366551%28VS.85%29.aspx

    तो फिर तुम प्रक्रिया आईडी सहित किसी भी संरचना आप के अंदर की तरह, डाल सकते हैं, आदि

    एक पोर्टेबल विकल्प है: पोर्ट पर एक सॉकेट बनाएं (एक निश्चित संख्या के साथ) और उस पर प्रतीक्षा करें (स्वीकार करें)। ऐप का दूसरा उदाहरण विफल हो जाएगा क्योंकि बंदरगाह पहले ही लिया जा चुका है। फिर दूसरा उदाहरण प्राथमिक उदाहरण की सॉकेट से कनेक्ट हो सकता है और वांछित जानकारी भेज सकता है।

    मुझे उम्मीद है कि यह मदद करता है ...

    +0

    सामान्य रूप से, इसके लिए सॉकेट खराब हैं। उन्हें कुछ पोर्ट नंबर की आवश्यकता होती है ताकि हार्ड-कोड किया जा सके; क्या होगा यदि यह संख्या पहले से ही कब्जा कर लिया जाएगा? सुनवाई कनेक्शन बनाना भी एक ऐप को बहुत संदिग्ध बनाता है अगर उसके कार्यों की आवश्यकता नहीं है। मैं विचार करता हूं, कहता हूं, नोटपैड जो इनकमिंग कनेक्शन को 100% दुर्भावनापूर्ण सॉफ़्टवेयर स्वीकार करता है। जब तक कि अंतिम उपयोगकर्ता सॉफ़्टवेयर पर विचार किया जाता है, सॉकेट संचार केवल विशिष्ट ऐप्स जैसे FileZilla सर्वर और इंटरफ़ेस के लिए ठीक है। बेशक, एंटरप्राइज़ सॉफ़्टवेयर को किसी भी विकल्प की आवश्यकता हो सकती है। मैं इसके लिए नामित पाइप की सिफारिश करता हूं। – Fr0sT