python - क्या pywin32 में संख्यात्मक COM त्रुटि-कोड को डीकोड करने का कोई तरीका है




windows excel (4)

यहां पाइथन में लिखे गए एक अविश्वसनीय एप्लिकेशन के हालिया भाग से स्टैक-ट्रेस का हिस्सा है जो Excel में लिखे गए किसी अन्य एप्लिकेशन को नियंत्रित करता है:

pywintypes.com_error: (-2147352567, 'Exception occurred.', (0, None, None, None, 0, -2146788248), None)

जाहिर है कुछ गलत हो गया है ... लेकिन क्या? [1] ये COM त्रुटि कोड अत्यधिक गुप्त लगते हैं।

मैं इस त्रुटि संदेश को कैसे डीकोड कर सकता हूं? क्या वहां कोई टेबल है जो मुझे इस संख्यात्मक त्रुटि कोड को और अधिक सार्थक रूपांतरित करने की अनुमति देता है?

[1] मुझे वास्तव में पता है कि इस मामले में क्या गलत हुआ, यह एक रेंज ऑब्जेक्ट पर नाम प्रिंटर का उपयोग करने का प्रयास कर रहा था, जिसमें नाम संपत्ति नहीं थी ... सभी बग ढूंढना आसान नहीं है!

https://code.i-harness.com


आप कुछ भी गलत नहीं कर रहे हैं। आपके स्टैक ट्रेस (संख्या) में पहला आइटम COM ऑब्जेक्ट द्वारा लौटाए गए त्रुटि कोड है। दूसरा आइटम त्रुटि कोड से जुड़ा विवरण है जो इस मामले में "अपवाद हुआ" है। pywintypes.com_error पहले से ही Win32api.FormatMessage (errCode) के बराबर कहा जाता है। हम एक मिनट में दूसरे नंबर को देखेंगे।

वैसे, आप "त्रुटि लुकअप" उपयोगिता का उपयोग कर सकते हैं जो विजुअल स्टूडियो (सी: \ प्रोग्राम फ़ाइलें \ माइक्रोसॉफ्ट विजुअल स्टूडियो 9.0 \ कॉमन 7 \ टूल्स \ ErrLook.exe) में COM त्रुटि कोड जांचने के लिए त्वरित लॉन्चिंग पैड के रूप में आता है। वह उपयोगिता आपके लिए FormatMessage भी कॉल करती है और परिणाम प्रदर्शित करती है। सभी त्रुटि कोड इस तंत्र के साथ काम नहीं करेंगे, लेकिन कई लोग करेंगे। यह आमतौर पर मेरा पहला पड़ाव है।

COM में त्रुटि प्रबंधन और रिपोर्टिंग थोड़ा गन्दा है। मैं आपको कुछ पृष्ठभूमि देने की कोशिश करूंगा।

सभी COM विधि कॉल एक संख्यात्मक कोड लौटाएंगे जिसे HRESULT कहा जाता है जो सफलता या विफलता को इंगित कर सकता है। COM में त्रुटि रिपोर्टिंग के सभी रूपों के शीर्ष पर निर्माण।

कोड आमतौर पर हेक्स में व्यक्त किए जाते हैं, हालांकि कभी-कभी आप उन्हें अपने 32-बिट संख्याओं के रूप में देखेंगे, जैसे आपके स्टैक ट्रेस में। सामान्य परिणामों और समस्याओं के लिए सभी प्रकार के पूर्वनिर्धारित रिटर्न कोड हैं, या वस्तु विशेष स्थितियों के लिए कस्टम संख्यात्मक कोड वापस कर सकती है। उदाहरण के लिए, मान 0 (जिसे S_OK कहा जाता है) का सार्वभौमिक अर्थ है "कोई त्रुटि नहीं" और 0x80000002 E_OUTOFMEMORY है। कभी-कभी HRESULT कोड वस्तु द्वारा वापस आते हैं, कभी-कभी COM बुनियादी ढांचे द्वारा।

एक COM ऑब्जेक्ट IErrorInfo नामक इंटरफ़ेस को लागू करके अधिक समृद्ध त्रुटि जानकारी प्रदान करने का भी चयन कर सकता है। जब कोई ऑब्जेक्ट IErrorInfo लागू करता है, तो यह क्या हुआ, इसके बारे में सभी प्रकार के विवरण प्रदान कर सकते हैं, जैसे विस्तृत कस्टम त्रुटि संदेश और समस्या का वर्णन करने वाली सहायता फ़ाइल का नाम भी। वीबी 6 और वीबीए में। Err ऑब्जेक्ट आपको उस सारी जानकारी तक पहुंचने की अनुमति देता है ( Err.Description , आदि)।

मामलों को जटिल बनाने के लिए, देर से बाध्य COM ऑब्जेक्ट्स (जो COM Automation या IDispatch नामक एक तंत्र का उपयोग करते हैं) कुछ परतें जोड़ें जिन्हें जानकारी प्राप्त करने के लिए छीलने की आवश्यकता है। एक्सेल आमतौर पर देर से बाध्यकारी के माध्यम से छेड़छाड़ की जाती है।

अब चलो अपनी स्थिति फिर से देखें। जो आपको पहले नंबर के रूप में मिल रहा है वह काफी सामान्य त्रुटि कोड है: DISP_E_EXCEPTION। नोट: आप आमतौर पर संख्या को गुगल करके HRESULT का आधिकारिक नाम निकाल सकते हैं, हालांकि कभी-कभी आपको कुछ भी उपयोगी खोजने के लिए हेक्स संस्करण का उपयोग करना होगा।

DISP_ से शुरू होने वाली त्रुटियां IDISPATCH त्रुटि कोड हैं। त्रुटि का अर्थ है "ऑब्जेक्ट द्वारा फेंक दिया गया एक COM अपवाद था", और कहीं और पैक की गई जानकारी के साथ (हालांकि मुझे बिल्कुल पता नहीं है; मुझे इसे देखना होगा)।

जो मैं pywintypes.com_error के बारे में समझता हूं, आपके संदेश में अंतिम संख्या वास्तविक त्रुटि कोड है जिसे अपवाद के दौरान ऑब्जेक्ट द्वारा वापस किया गया था। यह वास्तविक संख्यात्मक कोड है जिसे आप Err.Number के Err.Number बाहर निकाल देंगे।

दुर्भाग्यवश, वह दूसरा कोड -2146788248 (0x800A9C68) कस्टम एप्लिकेशन-डिफ़ाइंड त्रुटि संदेशों (VBA: VbObjectError + someCustomErrorNumber ) के लिए आरक्षित श्रेणी में है, इसलिए कोई केंद्रीकृत अर्थ नहीं है। एक ही संख्या का मतलब विभिन्न कार्यक्रमों के लिए पूरी तरह से अलग चीजें हो सकता है।

इस मामले में, हम एक मृत अंत तक पहुंच गए हैं:

त्रुटि कोड "कस्टम" है, और एप्लिकेशन को यह दस्तावेज करने की आवश्यकता है कि यह क्या है, सिवाय इसके कि एक्सेल नहीं करता है। इसके अलावा, एक्सेल (या त्रुटि का वास्तविक स्रोत) IErrorInfo के माध्यम से कोई और जानकारी प्रदान नहीं कर रहा है।

एक्सेल स्वभाव और अस्पष्ट स्थितियों से गुप्त त्रुटि कोड के लिए कुख्यात (कम से कम मेरे लिए) है जो उन्हें कारण बनाता है। यह विशेष रूप से त्रुटियों के लिए है कि कोई "डिज़ाइन-टाइम त्रुटियों" पर विचार कर सकता है ("आपको उस विधि को कॉल करने से बेहतर जाना चाहिए जो ऑब्जेक्ट में मौजूद नहीं है")। एक अच्छा "नाम संपत्ति नहीं पढ़ सका" के बजाय, आपको " रन-टाइम त्रुटि '1004' प्राप्त होती है: एप्लिकेशन परिभाषित या ऑब्जेक्ट-डिफ़ाइंड त्रुटि " (जिसे मैं अभी एक श्रेणी पर नाम संपत्ति तक पहुंचने का प्रयास कर रहा हूं, वीबीए से एक्सेल में)। यह बहुत उपयोगी नहीं है।

समस्या को पायथन या एक्सेल के इंटरफ़ेस पर रूट नहीं किया गया है। एक्सेल स्वयं यह नहीं बताता कि क्या हुआ, यहां तक ​​कि वीबीए भी।

हालांकि, उपरोक्त सामान्य प्रक्रिया वैध बनी हुई है। यदि आपको भविष्य में एक्सेल से कोई त्रुटि मिलती है, तो आपको एक बेहतर त्रुटि संदेश मिल सकता है जिसे आप उसी तरह ट्रैक कर सकते हैं।

सौभाग्य!


इसको ऐसे करो:

try:
    [whatever code]
except pythoncom.com_error as error:
    print(win32api.FormatMessage(error.excepinfo[5]))

यहां pythoncom.com_error ऑब्जेक्ट को पचाने के बारे में अधिक जानकारी: http://docs.activestate.com/activepython/3.2/pywin32/com_error.html


विशेष रूप से pythoncom के लिए, त्रुटि कोड जो परिणाम गूढ़ से अधिक हैं। ऐसा इसलिए है क्योंकि पाइथनॉम 32 बिट हस्ताक्षरित पूर्णांक के रूप में आंतरिक रूप से उनका प्रतिनिधित्व करता है, जब सही प्रतिनिधित्व 32 बिट हस्ताक्षरित पूर्णांक होता है। नतीजतन, स्टैक ट्रेस में जो रूपांतरण आप समाप्त करते हैं वह गलत है।

विशेष रूप से, आपके अपवाद, पायथनकॉम के अनुसार, -2147352567 है, और आपका (बेहतर शब्द की कमी के लिए) Err.Number is -2146788248 है।

हालांकि यह कुछ त्रुटियों का कारण बनता है जब विशिष्ट त्रुटियों के लिए देख रहे हैं, जैसे नीचे:

DISP_E_EXCEPTION = 0x80020009
#...
#except pywintypes.com_error as e:
#    print repr(e)
#    #pywintypes.com_error: (-2147352567, 'Exception occurred.', (0, None, None, None, 0, -2146788248), None)
#    hr = e.hresult

hr = -2147352567
if hr == DISP_E_EXCEPTION:
    pass #This never occurs
else:
    raise

यह देखने के लिए कि इसमें समस्याएं क्यों हैं, इन त्रुटि कोडों को देखें:

>>> DISP_E_EXCEPTION = 0x80020009
>>> DISP_E_EXCEPTION
2147614729L
>>> my_hr = -2147352567
>>> my_hr == DISP_E_EXCEPTION
False

दोबारा, ऐसा इसलिए है क्योंकि पाइथन निरंतर सकारात्मक के रूप में घोषित करता है, और पायथनकॉम की गलत घोषणा ने इसे नकारात्मक बताया है। बेशक, सबसे स्पष्ट समाधान विफल रहता है:

>>> hex(my_hr)
'-0x7ffdfff7'

समाधान सही ढंग से संख्या की व्याख्या करना है। सौभाग्य से, Pythoncom का प्रतिनिधित्व उलटा है। हमें ऋणात्मक संख्या को 32 बिट हस्ताक्षरित पूर्णांक के रूप में समझने की आवश्यकता है, फिर इसे एक हस्ताक्षरित पूर्णांक के रूप में समझें:

def fix_com_hresult(hr):
    import struct
    return struct.unpack("L", struct.pack("l", hr))[0]

>>> DISP_E_EXCEPTION = 0x80020009
>>> my_hr = -2147352567
>>> my_hr == DISP_E_EXCEPTION
False
>>> fixed_hr = fix_com_hresult(my_hr)
>>> fixed_hr
2147614729L
>>> fixed_hr == DISP_E_EXCEPTION
True

तो, इसे सभी एक साथ रखकर, आपको निश्चित रूप से हर समय pythoncom से fix_com_hresult () को चलाने की आवश्यकता है।

चूंकि अपवादों की जांच करते समय आपको सामान्य रूप से ऐसा करने की आवश्यकता होती है, इसलिए मैंने इन कार्यों को बनाया:

def fix_com_exception(e):
    e.hresult = fix_com_hresult(e.hresult)
    e.args = [e.hresult] + list(e.args[1:])
    return e

def fix_com_hresult(hr):
    import struct
    return struct.unpack("L", struct.pack("l", hr))[0]

जिसका उपयोग तब किया जा सकता है कि आप कैसे उम्मीद करते हैं:

DISP_E_EXCEPTION = 0x80020009
try:
    #failing call
except pywintypes.com_error as e:
    print repr(e)
    #pywintypes.com_error: (-2147352567, 'Exception occurred.', (0, None, None, None, 0, -2146788248), None)
    fix_com_exception(e)
    print repr(e)
    #pywintypes.com_error: (2147614729L, 'Exception occurred.', (0, None, None, None, 0, -2146788248), None)
    if e.hresult == DISP_E_EXCEPTION:
        print "Got expected failure"
    else:
        raise

मैं सभी HRESULT सूचीबद्ध करने वाले एमएसडीएन दस्तावेज को खोजने में असमर्थ था, लेकिन मुझे यह मिला: http://www.megos.ch/support/doserrors_e.txt

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


हाँ win32api मॉड्यूल आज़माएं:

import win32api
e_msg = win32api.FormatMessage(-2147352567)

आप अपवाद से लौटाए गए किसी भी कोड को पकड़ सकते हैं और उन्हें फॉर्मेट मैसेज में भेज सकते हैं। आपके उदाहरण में 2 त्रुटि कोड थे।





pywin32