जवाबों:
यह एक संसाधन, अक्सर स्मृति या एक खुली फ़ाइल, या एक पाइप के लिए एक सार संदर्भ मूल्य है।
ठीक से , विंडोज में, (और आम तौर पर कंप्यूटिंग में) एक हैंडल एक अमूर्त है जो एपीआई उपयोगकर्ता से एक वास्तविक मेमोरी एड्रेस को छुपाता है, जिससे सिस्टम को प्रोग्राम के लिए पारदर्शी रूप से भौतिक मेमोरी को पुनर्गठित करने की अनुमति मिलती है। एक पॉइंटर में एक हैंडल को हल करने से मेमोरी लॉक हो जाती है, और हैंडल को रिलीज़ करने से पॉइंटर को अमान्य कर दिया जाता है। इस मामले में इसे पॉइंटर्स टेबल में एक इंडेक्स के रूप में सोचें ... आप सिस्टम एपीआई कॉल के लिए इंडेक्स का उपयोग करते हैं, और सिस्टम मेज पर पॉइंटर को इच्छानुसार बदल सकता है।
वैकल्पिक रूप से एक वास्तविक पॉइंटर को हैंडल के रूप में दिया जा सकता है जब एपीआई लेखक का इरादा है कि एपीआई का उपयोगकर्ता उस पते की बारीकियों से अछूता हो जो पते को लौटाता है; इस स्थिति में यह विचार किया जाना चाहिए कि किसी भी समय हैंडल पॉइंट क्या बदल सकता है (एपीआई संस्करण से संस्करण तक या यहां तक कि एपीआई को कॉल करने से लेकर हैंडल को वापस करने तक) - इसलिए हैंडल को केवल अपारदर्शी मान के रूप में माना जाना चाहिए केवल एपीआई के लिए सार्थक ।
मुझे यह जोड़ना चाहिए कि किसी भी आधुनिक ऑपरेटिंग सिस्टम में, यहां तक कि तथाकथित "रियल पॉइंटर्स" अभी भी प्रक्रिया के आभासी मेमोरी स्पेस में अपारदर्शी हैंडल हैं, जो प्रक्रिया के भीतर पॉइंटर्स को अमान्य किए बिना O / S को मेमोरी को प्रबंधित और पुनर्व्यवस्थित करने में सक्षम बनाता है। ।
A HANDLE
एक संदर्भ-विशिष्ट विशिष्ट पहचानकर्ता है। संदर्भ-विशेष से मेरा तात्पर्य यह है कि एक संदर्भ से प्राप्त एक हैंडल को आवश्यक रूप से किसी भी अन्य संदर्भ में उपयोग नहीं किया जा सकता है जो HANDLE
एस पर भी काम करता है ।
उदाहरण के लिए, GetModuleHandle
वर्तमान में लोड किए गए मॉड्यूल के लिए एक विशिष्ट पहचानकर्ता देता है। लौटे हुए हैंडल का उपयोग अन्य कार्यों में किया जा सकता है जो मॉड्यूल हैंडल को स्वीकार करते हैं। यह उन कार्यों को नहीं दिया जा सकता है जिन्हें अन्य प्रकार के हैंडल की आवश्यकता होती है। उदाहरण के लिए, यदि आप एक हैंडल से लौटे नहीं दे सकता है GetModuleHandle
करने के लिए HeapDestroy
और यह कुछ समझदार करने की उम्मीद।
HANDLE
खुद सिर्फ एक अभिन्न प्रकार है। आमतौर पर, लेकिन जरूरी नहीं कि यह कुछ अंतर्निहित प्रकार या स्मृति स्थान का सूचक हो। उदाहरण के लिए, वास्तव में मॉड्यूल के आधार वर्चुअल मेमोरी पते के लिए एक संकेतक HANDLE
द्वारा लौटाया गया GetModuleHandle
है। लेकिन यह कहते हुए कोई नियम नहीं है कि हैंडल पॉइंटर्स होना चाहिए। एक हैंडल भी एक साधारण पूर्णांक हो सकता है (जो संभवतः कुछ Win32 एपीआई द्वारा एक सरणी में एक सूचकांक के रूप में इस्तेमाल किया जा सकता है)।
HANDLE
s जानबूझकर अपारदर्शी अभ्यावेदन हैं जो आंतरिक 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 लाइब्रेरी के आंतरिक अभ्यावेदन के बीच एक अपारदर्शी दीवार प्रदान करता है।
handle
के बजाय void *
है कि वास्तव में क्या शून्य * अंक के लिए यह पता लगाने की कोशिश कर रहा से हतोत्साहित उपयोगकर्ता कोड । क्या मैं सही हूँ?
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 की स्थिति को संशोधित करता है।
देखें हैंडल और डेटा प्रकार अधिक जानकारी के लिए।
HANDLE
ADT के माध्यम से संदर्भित ऑब्जेक्ट कर्नेल द्वारा प्रबंधित किए जाते हैं। HWND
दूसरी ओर आपके द्वारा नाम ( , आदि) के अन्य हैंडल प्रकार USER ऑब्जेक्ट हैं। जिन्हें विंडोज कर्नेल द्वारा प्रबंधित नहीं किया जाता है।
एक हैंडल विंडोज द्वारा प्रबंधित ऑब्जेक्ट के लिए एक अद्वितीय पहचानकर्ता है। यह एक पॉइंटर की तरह है , लेकिन एक पॉइंटर में नहीं है कि यह एक ऐसा पता नहीं है जिसे कुछ डेटा तक पहुंच प्राप्त करने के लिए उपयोगकर्ता कोड द्वारा डीरफेर किया जा सकता है। इसके बजाय एक हैंडल को फ़ंक्शंस के एक सेट में पारित किया जाना है जो उस ऑब्जेक्ट पर कार्रवाई कर सकता है जिसे हैंडल पहचानता है।
तो सबसे बुनियादी स्तर पर किसी भी प्रकार का एक हेंडल एक पॉइंटर को पॉइंटर है या
#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 संपादित करें: ठीक है, क्यों डाउनवोट, एक प्राथमिक कुंजी विशिष्ट रूप से एक डेटाबेस रिकॉर्ड की पहचान करता है, और विंडोज सिस्टम में एक हैंडल विशिष्ट रूप से एक खिड़की, एक खुली हुई फ़ाइल, आदि की पहचान करता है, यही मैं कह रहा हूं।
विंडोज में एक ऐसी संरचना के रूप में सोचें जो इसका वर्णन करती है। यह संरचना विंडोज का एक आंतरिक हिस्सा है और आपको इसका विवरण जानने की आवश्यकता नहीं है। इसके बजाय, Windows उस संरचना के लिए पॉइंटर को टाइप करने के लिए एक टाइपफेड प्रदान करता है। वह "हैंडल" है जिसके द्वारा आप विंडो पर पकड़ बना सकते हैं।