विंडोज हैंडल क्या है?


153

विंडोज में संसाधनों की चर्चा करते समय "हैंडल" क्या है? वो कैसे काम करते है?

जवाबों:


167

यह एक संसाधन, अक्सर स्मृति या एक खुली फ़ाइल, या एक पाइप के लिए एक सार संदर्भ मूल्य है।

ठीक से , विंडोज में, (और आम तौर पर कंप्यूटिंग में) एक हैंडल एक अमूर्त है जो एपीआई उपयोगकर्ता से एक वास्तविक मेमोरी एड्रेस को छुपाता है, जिससे सिस्टम को प्रोग्राम के लिए पारदर्शी रूप से भौतिक मेमोरी को पुनर्गठित करने की अनुमति मिलती है। एक पॉइंटर में एक हैंडल को हल करने से मेमोरी लॉक हो जाती है, और हैंडल को रिलीज़ करने से पॉइंटर को अमान्य कर दिया जाता है। इस मामले में इसे पॉइंटर्स टेबल में एक इंडेक्स के रूप में सोचें ... आप सिस्टम एपीआई कॉल के लिए इंडेक्स का उपयोग करते हैं, और सिस्टम मेज पर पॉइंटर को इच्छानुसार बदल सकता है।

वैकल्पिक रूप से एक वास्तविक पॉइंटर को हैंडल के रूप में दिया जा सकता है जब एपीआई लेखक का इरादा है कि एपीआई का उपयोगकर्ता उस पते की बारीकियों से अछूता हो जो पते को लौटाता है; इस स्थिति में यह विचार किया जाना चाहिए कि किसी भी समय हैंडल पॉइंट क्या बदल सकता है (एपीआई संस्करण से संस्करण तक या यहां तक ​​कि एपीआई को कॉल करने से लेकर हैंडल को वापस करने तक) - इसलिए हैंडल को केवल अपारदर्शी मान के रूप में माना जाना चाहिए केवल एपीआई के लिए सार्थक ।

मुझे यह जोड़ना चाहिए कि किसी भी आधुनिक ऑपरेटिंग सिस्टम में, यहां तक ​​कि तथाकथित "रियल पॉइंटर्स" अभी भी प्रक्रिया के आभासी मेमोरी स्पेस में अपारदर्शी हैंडल हैं, जो प्रक्रिया के भीतर पॉइंटर्स को अमान्य किए बिना O / S को मेमोरी को प्रबंधित और पुनर्व्यवस्थित करने में सक्षम बनाता है। ।


4
मैं वास्तव में तेजी से प्रतिक्रिया की सराहना करता हूं। दुर्भाग्य से, मुझे लगता है कि मैं अभी भी पूरी तरह से इसे समझने के लिए एक नौसिखिया का बहुत अधिक हूं :-(
अल सी

4
क्या मेरा विस्तारित उत्तर किसी भी प्रकाश को बहाता है?
लॉरेंस डोल

100

A HANDLEएक संदर्भ-विशिष्ट विशिष्ट पहचानकर्ता है। संदर्भ-विशेष से मेरा तात्पर्य यह है कि एक संदर्भ से प्राप्त एक हैंडल को आवश्यक रूप से किसी भी अन्य संदर्भ में उपयोग नहीं किया जा सकता है जो HANDLEएस पर भी काम करता है ।

उदाहरण के लिए, GetModuleHandleवर्तमान में लोड किए गए मॉड्यूल के लिए एक विशिष्ट पहचानकर्ता देता है। लौटे हुए हैंडल का उपयोग अन्य कार्यों में किया जा सकता है जो मॉड्यूल हैंडल को स्वीकार करते हैं। यह उन कार्यों को नहीं दिया जा सकता है जिन्हें अन्य प्रकार के हैंडल की आवश्यकता होती है। उदाहरण के लिए, यदि आप एक हैंडल से लौटे नहीं दे सकता है GetModuleHandleकरने के लिए HeapDestroyऔर यह कुछ समझदार करने की उम्मीद।

HANDLEखुद सिर्फ एक अभिन्न प्रकार है। आमतौर पर, लेकिन जरूरी नहीं कि यह कुछ अंतर्निहित प्रकार या स्मृति स्थान का सूचक हो। उदाहरण के लिए, वास्तव में मॉड्यूल के आधार वर्चुअल मेमोरी पते के लिए एक संकेतक HANDLEद्वारा लौटाया गया GetModuleHandleहै। लेकिन यह कहते हुए कोई नियम नहीं है कि हैंडल पॉइंटर्स होना चाहिए। एक हैंडल भी एक साधारण पूर्णांक हो सकता है (जो संभवतः कुछ Win32 एपीआई द्वारा एक सरणी में एक सूचकांक के रूप में इस्तेमाल किया जा सकता है)।

HANDLEs जानबूझकर अपारदर्शी अभ्यावेदन हैं जो आंतरिक Win32 संसाधनों से अतिक्रमण और अमूर्तता प्रदान करते हैं। इस प्रकार, Win32 API संभावित रूप से एक HANDLE के पीछे अंतर्निहित प्रकार को बदल सकता है, इसके बिना किसी भी तरह से उपयोगकर्ता कोड को प्रभावित कर सकता है (कम से कम यह विचार है)।

Win32 एपीआई के इन तीन अलग-अलग आंतरिक कार्यान्वयनों पर विचार करें जो मैंने अभी बनाया है, और मान लें कि Widgetयह एक है struct

Widget * GetWidget (std::string name)
{
    Widget *w;

    w = findWidget(name);

    return w;
}
void * GetWidget (std::string name)
{
    Widget *w;

    w = findWidget(name);

    return reinterpret_cast<void *>(w);
}
typedef void * HANDLE;

HANDLE GetWidget (std::string name)
{
    Widget *w;

    w = findWidget(name);

    return reinterpret_cast<HANDLE>(w);
}

पहला उदाहरण एपीआई के बारे में आंतरिक विवरण को उजागर करता है: यह उपयोगकर्ता कोड को यह जानने की अनुमति देता है कि GetWidgetसूचक को ए वापस लौटाता है struct Widget। इसके कुछ परिणाम हैं:

  • उपयोगकर्ता कोड में हेडर फ़ाइल तक पहुंच होनी चाहिए जो Widgetसंरचना को परिभाषित करती है
  • उपयोगकर्ता कोड संभावित रूप से दिए गए Widgetसंरचना के आंतरिक भागों को संशोधित कर सकता है

ये दोनों परिणाम अवांछनीय हो सकते हैं।

दूसरा उदाहरण उपयोगकर्ता आंतरिक कोड से इस आंतरिक विवरण को छिपाता है, बस लौटकर void *। उपयोगकर्ता कोड को उस हेडर तक पहुंचने की आवश्यकता नहीं है जो Widgetसंरचना को परिभाषित करता है ।

तीसरा उदाहरण वास्तव में दूसरे रूप में ही है, लेकिन हम अभी फोन void *एक HANDLEके बजाय। शायद यह उपयोगकर्ता कोड को यह पता लगाने की कोशिश करने से हतोत्साहित करता है कि void *अंक क्या हैं ।

इस परेशानी से क्यों गुजरें? इसी API के नए संस्करण के चौथे उदाहरण पर विचार करें:

typedef void * HANDLE;

HANDLE GetWidget (std::string name)
{
    NewImprovedWidget *w;

    w = findImprovedWidget(name);

    return reinterpret_cast<HANDLE>(w);
}

ध्यान दें कि फ़ंक्शन का इंटरफ़ेस ऊपर दिए गए तीसरे उदाहरण के समान है। इसका अर्थ है कि उपयोगकर्ता कोड एपीआई के इस नए संस्करण का उपयोग करना जारी रख सकता है, बिना किसी बदलाव के, "पर्दे के पीछे" कार्यान्वयन के NewImprovedWidgetबजाय संरचना का उपयोग करने के लिए बदल गया है ।

इन उदाहरणों में हैंडल वास्तव में सिर्फ एक नया, संभवतः मित्रवत, नाम के लिए है void *, जो कि वास्तव HANDLEमें Win32 API में है (इसे MSDN पर देखें )। यह Win32 API का उपयोग करने वाले कोड के विंडोज के संस्करणों के बीच पोर्टेबिलिटी को बढ़ाने वाले यूजर कोड और Win32 लाइब्रेरी के आंतरिक अभ्यावेदन के बीच एक अपारदर्शी दीवार प्रदान करता है।


5
जानबूझकर या नहीं, आप सही हैं - अवधारणा निश्चित रूप से अपारदर्शी है (कम से कम मेरे लिए :-)
अल सी

5
मैंने कुछ ठोस उदाहरणों के साथ अपने मूल उत्तर पर विस्तार किया है। उम्मीद है कि यह अवधारणा को थोड़ा और पारदर्शी बना देगा।
डैन मोल्डिंग

2
बहुत उपयोगी विस्तार ... धन्यवाद!
अल सी

4
यह किसी भी सवाल का सबसे साफ, प्रत्यक्ष, और सबसे अच्छी तरह से लिखित प्रतिक्रिया में से एक है जो मैंने थोड़ी देर में देखा है। इसे लिखने के लिए समय निकालने के लिए ईमानदारी से धन्यवाद!
एंड्रयू

@DanMoulding: तो मुख्य कारण का उपयोग करने handleके बजाय void *है कि वास्तव में क्या शून्य * अंक के लिए यह पता लगाने की कोशिश कर रहा से हतोत्साहित उपयोगकर्ता कोड । क्या मैं सही हूँ?
सिंह लाई

37

Win32 प्रोग्रामिंग में एक हैंडल एक टोकन है जो विंडोज कर्नेल द्वारा प्रबंधित एक संसाधन का प्रतिनिधित्व करता है। एक हैंडल एक खिड़की, एक फ़ाइल, आदि के लिए हो सकता है।

हैंडल केवल एक कण संसाधन की पहचान करने का एक तरीका है जिसे आप Win32 APIs का उपयोग करके काम करना चाहते हैं।

उदाहरण के लिए, यदि आप एक विंडो बनाना चाहते हैं, और इसे स्क्रीन पर दिखा सकते हैं, तो आप निम्नलिखित कार्य कर सकते हैं:

// Create the window
HWND hwnd = CreateWindow(...); 
if (!hwnd)
   return; // hwnd not created

// Show the window.
ShowWindow(hwnd, SW_SHOW);

उपरोक्त उदाहरण में HWND का अर्थ है "एक खिड़की के लिए एक संभाल"।

यदि आप एक ऑब्जेक्ट ओरिएंटेड भाषा के लिए उपयोग किए जाते हैं, तो आप एक वर्ग के उदाहरण के रूप में एक HANDLE के बारे में सोच सकते हैं, जिसमें कोई भी विधि नहीं है, जो अन्य कार्यों द्वारा केवल राज्य के लिए संशोधित है। इस मामले में ShowWindow फ़ंक्शन विंडो HANDLE की स्थिति को संशोधित करता है।

देखें हैंडल और डेटा प्रकार अधिक जानकारी के लिए।


HANDLEADT के माध्यम से संदर्भित ऑब्जेक्ट कर्नेल द्वारा प्रबंधित किए जाते हैं। HWNDदूसरी ओर आपके द्वारा नाम ( , आदि) के अन्य हैंडल प्रकार USER ऑब्जेक्ट हैं। जिन्हें विंडोज कर्नेल द्वारा प्रबंधित नहीं किया जाता है।
IInspectable

1
@IInspectable यह अनुमान लगा रहा है कि User32.dll द्वारा प्रबंधित किया गया है?
the_endian

8

एक हैंडल विंडोज द्वारा प्रबंधित ऑब्जेक्ट के लिए एक अद्वितीय पहचानकर्ता है। यह एक पॉइंटर की तरह है , लेकिन एक पॉइंटर में नहीं है कि यह एक ऐसा पता नहीं है जिसे कुछ डेटा तक पहुंच प्राप्त करने के लिए उपयोगकर्ता कोड द्वारा डीरफेर किया जा सकता है। इसके बजाय एक हैंडल को फ़ंक्शंस के एक सेट में पारित किया जाना है जो उस ऑब्जेक्ट पर कार्रवाई कर सकता है जिसे हैंडल पहचानता है।


5

तो सबसे बुनियादी स्तर पर किसी भी प्रकार का एक हेंडल एक पॉइंटर को पॉइंटर है या

#define HANDLE void **

अब आप इसका उपयोग क्यों करना चाहेंगे

चलो एक सेटअप लेते हैं:

class Object{
   int Value;
}

class LargeObj{

   char * val;
   LargeObj()
   {
      val = malloc(2048 * 1000);
   }

}

void foo(Object bar){
    LargeObj lo = new LargeObj();
    bar.Value++;
}

void main()
{
   Object obj = new Object();
   obj.val = 1;
   foo(obj);
   printf("%d", obj.val);
}

इसलिए क्योंकि obj मान द्वारा पारित किया गया था (प्रतिलिपि बनाएं और फ़ंक्शन को दें) को फू करने के लिए, प्रिंटफ़ 1 के मूल मूल्य को प्रिंट करेगा।

अब अगर हम फू को अपडेट करते हैं:

void foo(Object * bar)
{
    LargeObj lo = new LargeObj();
    bar->val++;
}

एक मौका है कि प्रिंटफ़ 2. के अद्यतन मूल्य को प्रिंट करेगा। लेकिन इस बात की भी संभावना है कि फू कुछ स्मृति भ्रष्टाचार या अपवाद का कारण बनेगा।

इसका कारण यह है कि जब आप अब एक पॉइंटर का उपयोग कर रहे हैं, तो उस फ़ंक्शन को obj पास करने के लिए, जिसे आप 2 Megs की मेमोरी आवंटित कर रहे हैं, इससे OS को obj के स्थान को अपडेट करने के लिए स्मृति को स्थानांतरित करने का कारण हो सकता है। चूँकि आपने पॉइंटर को मान से पास कर दिया है, अगर obj स्थानांतरित हो जाता है, तो OS पॉइंटर को अपडेट करता है, लेकिन फ़ंक्शन में प्रतिलिपि नहीं बनाता है और संभावित रूप से समस्याएँ आती हैं।

के अंतिम अपडेट के लिए:

void foo(Object **bar){
    LargeObj lo = LargeObj();
    Object * b = &bar;
    b->val++;
}

यह हमेशा अपडेटेड वैल्यू को प्रिंट करेगा।

देखें, जब कंपाइलर पॉइंटर्स के लिए मेमोरी आवंटित करता है, तो यह उन्हें अचल के रूप में चिह्नित करता है, इसलिए बड़ी ऑब्जेक्ट द्वारा आवंटित मेमोरी के किसी भी पुनः फेरबदल के कारण फ़ंक्शन को दिया गया मान मेमोरी में अंतिम स्थान का पता लगाने के लिए सही पते पर इंगित करेगा। अपडेट करें।

किसी भी प्रकार के HANDLE (hWnd, FILE, आदि) डोमेन विशिष्ट हैं और स्मृति भ्रष्टाचार से बचाने के लिए एक निश्चित प्रकार की संरचना को इंगित करते हैं।


1
यह त्रुटिपूर्ण तर्क है; C मेमोरी आवंटन सबसिस्टम वसीयत में केवल सूचक को अमान्य नहीं कर सकता है। अन्यथा कोई C या C ++ प्रोग्राम कभी भी सही ढंग से सही नहीं हो सकता है; पर्याप्त जटिलता के किसी भी कार्यक्रम को परिभाषा द्वारा demonstrably गलत होगा। इसके अलावा, डबल इनडायरेक्शन मदद नहीं करता है अगर मेमोरी को सीधे इंगित किया जाता है, तो कार्यक्रम के नीचे ले जाया जाता है जब तक कि पॉइंटर वास्तव में स्वयं वास्तविक मेमोरी से एक अमूर्त नहीं है - जो इसे संभाल लेगा ।
लॉरेंस Dol

1
Macintosh ऑपरेटिंग सिस्टम (9 या 8 तक के संस्करणों में) बिल्कुल ऊपर दिया गया था। यदि आपने कुछ सिस्टम ऑब्जेक्ट आवंटित किया है, तो आपको अक्सर इसे संभालना होगा, ऑब्जेक्ट को चारों ओर ले जाने के लिए ओएस को स्वतंत्र छोड़ देगा। पहले मैक के सीमित मेमोरी साइज़ के साथ जो कि महत्वपूर्ण था।
रियाल्टो ने मोनिका का

5

एक डेटाबेस में एक रिकॉर्ड की एक प्राथमिक कुंजी मान की तरह एक हैंडल है।

1 संपादित करें: ठीक है, क्यों डाउनवोट, एक प्राथमिक कुंजी विशिष्ट रूप से एक डेटाबेस रिकॉर्ड की पहचान करता है, और विंडोज सिस्टम में एक हैंडल विशिष्ट रूप से एक खिड़की, एक खुली हुई फ़ाइल, आदि की पहचान करता है, यही मैं कह रहा हूं।


1
मुझे नहीं लगता कि आप यह कह सकते हैं कि हैंडल अद्वितीय है। यह उपयोगकर्ता के विंडोज स्टेशन के अनुसार अद्वितीय हो सकता है, लेकिन यह अद्वितीय होने की गारंटी नहीं है यदि एक ही समय में एक ही सिस्टम तक कई उपयोगकर्ता पहुँच रहे हैं। यही है, कई उपयोगकर्ताओं को एक हैंडल मान वापस मिल सकता है जो संख्यात्मक रूप से समान है, लेकिन उपयोगकर्ता के विंडोज स्टेशन के संदर्भ में वे विभिन्न चीजों के लिए मैप करते हैं ...
निक

2
@ दिए गए संदर्भ में यह अद्वितीय है। एक प्राथमिक कुंजी अलग-अलग तालिकाओं के बीच अद्वितीय नहीं होने वाली है ...
बेनी मैकेनी

2

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


यह सच है, लेकिन यह हमेशा याद रखने योग्य है कि संभाल आमतौर पर मेमोरी एड्रेस नहीं होता है और एक उपयोगकर्ता कोड को इसे नहीं करना चाहिए।
शार्प्यूट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.