2015-10-07 5 views
6

हम एक देशी सी ++ आवेदन जो COM से अधिक विभिन्न प्रकार के कुछ VBA मैक्रो का समर्थन करता है है के माध्यम से लागू बुला। इन प्रकार में से एक, VBAExtension, कोर सी ++ आवेदन के साथ ही पंजीकृत करता है (एक वर्ग से प्राप्त) IConnectionPointImpl<Extension, &DIID_IExtensionEvents, CComDynamicUnkArray> का एक उदाहरण हो जाती है। यह ठीक काम करता है; कोर और अन्य वीबीए मैक्रोज़ दोनों उपयुक्त VBAExtension ऑब्जेक्ट दिए गए, IxtensionEvents पर विधियों तक पहुंच सकते हैं।समस्याएं सी से IConnectionPointImpl इंटरफ़ेस ++ मोडल WinForms

हम यह भी एक .NET विधानसभा (सी # में लिखा) है, जिसकी रन-टाइम में कोर आवेदन करने के लिए लोड किया जाता है है। ऐतिहासिक कारणों से, असेंबली एक ऑटो-रनिंग वीबीए मैक्रो द्वारा लोड की जाती है; फिर, जब उपयोगकर्ता एक विशेष बटन दबाता है, तो दूसरा वीबीए मैक्रो असेंबली का मुख्य प्रवेश बिंदु चलाता है, जो आगे की बातचीत के लिए System.Windows.Forms संवाद लाता है।

सेटअप है कि। मैं .NET असेंबली के भीतर से VBAExtension विधियों तक पहुंचने वाले कुछ अजीब व्यवहार को देख रहा हूं। विशेष रूप से, मैं विधानसभा में विभिन्न स्थानों से निम्नलिखित कोड चला रहा हूँ:

foreach (VBAExtension ve in app.Extensions) 
{ 
    System.Diagnostics.Debug.Print("Ext: " + ve.Name); 
} 

अगर मैं विधानसभा के मुख्य वस्तु के निर्माता से चलाने के; या असेंबली के मुख्य प्रवेश बिंदु से (संवाद प्रदर्शित होने से पहले), सबकुछ ठीक है - मुझे VBAExtension प्रिंट किए गए नाम मिलते हैं।

हालांकि, अगर मैं एक आदेश से एक ही कोड को चलाने के विधानसभा के दशक में एक बटन से शुरू हुआ (मोडल - हम कॉल कर रहे हैं form.ShowDialog()) WinForm, ve.Name सब खाली कर रहे हैं। pDispatch->Invoke कॉल IConnectionPointImpl उपवर्ग द्वारा किए गए सफल होता है (S_OK रिटर्न), लेकिन किसी भी वापसी वार्स निर्धारित नहीं करता है।

अगर मैं संवाद बदल होने की गैर मोडल (form.Show() साथ लागू), तो नाम फिर से काम करते हैं। प्रपत्र की विधि (मोडलनेस?) इस बात को प्रभावित करती है कि IConnectionPointImpl कॉल सफल हैं या नहीं।

किसी को भी पता है कि क्या हो रहा है?

संपादित करें: पहली पोस्टिंग के बाद से, मैंने दिखाया है कि यह आविष्कार कॉल स्टैक नहीं है; इसके बजाए, यह है कि कॉल एक मोडल संवाद से बना है या नहीं। मैंने मुख्य पाठ अपडेट किया है।

संपादित करें 2: प्रति हंस Passant का जवाब है, यहाँ अपने नैदानिक ​​प्रश्नों के उत्तर दिए गए हैं:

  • जैसी उम्मीद थी, अच्छा (मोडहीन) मामले में कोई त्रुटि है, तो मैं VBA ईवेंट हैंडलर का नाम बदलने । कॉल बस कोई डेटा नहीं देता है।
  • मैंने वीबीए हैंडलर में एक संदेश बॉक्स कॉल किया है; यह मॉडल केस में प्रदर्शित होता है, लेकिन मोडल मामले में नहीं है। Ergo, हैंडलर मोडल मामले में निष्पादित नहीं किया गया है।
  • Err के उपयोग से, मैं बता सकता हूं कि यदि हमने वीबीए हैंडलर में अपवाद मारा है तो हमें वीबीए त्रुटि संवाद मिलता है। एक बार इसे साफ़ करने के बाद, C++ Invoke कॉल में 0x80020009 ("अपवाद हुआ") रिटर्न कोड के रूप में है, और सामान्य विफलता मानों के साथ भरने वाले PExcepInfo (VBA ने वास्तविक विवरण निगल लिया है)
  • ईवेंट दूसरे प्रदर्शन पर आग नहीं लगाता है मोडल डायलॉग, या तो तुरंत पहले संवाद के बाद या सी # एड-इन के दूसरे आमंत्रण के दौरान।

मैं अगले संदेश के रूप में हमारे संदेश loops में खोदने की कोशिश करूंगा।

+1

'IConnectionPointImpl' घटनाओं के बारे में है और अपने foreach पाश विस्तार संपत्ति सीधे तक पहुँच रहा है, तो आप क्यों लगता है कि' IConnectionPointImpl' यहां शामिल कर रहा है? इसे और अधिक समझ बनाने यदि आपका कोड स्निपेट था सी ++ कोड कुछ ईवेंट हैंडलर के अंदर चल रहा है और कि बाहरी नाम संपत्ति क्वेरी होगा, लेकिन इस स्निपेट सी ++ तो और सी # में तुम्हारा होना होगा। –

+0

क्योंकि मैं आगे बढ़ सकता हूं और देख सकता हूं कि यह है। ध्यान दें कि 've' सी # में एक .NET ऑब्जेक्ट है जो 'नाम' संपत्ति का खुलासा करता है; कि संपत्ति ++ एक तरीका है जिसके VBA मैक्रो और 'Dispatch'es द्वारा पंजीकृत ICPI इंटरफ़ेस पाता द्वारा सी में समर्थित है प्रासंगिक ... उह ... _thing_, जो VBA कॉल जो नाम देता है बनाता है। यही है, कॉल सी # - (.NET) -> सी ++ - (IConnectionPointImp) -> वीबीए है। सी # -> वीबीए नहीं। – Chowlett

+0

बस सुनिश्चित करें कि मैं इस अधिकार मिल गया बनाने के लिए: 've.Name' सी # कार्यान्वयन है, तो यह कुछ सी ++ कोड (COM इंटरफेस विधि?) कहता है, तो सी ++ कोड किसी भी तरह अपनी बातें, और यह के भाग के रूप में यह एक COM घटना मुद्दों करता है , जिसे कुछ वीबीए हैंडलर द्वारा नियंत्रित किया जाता है और यह हैंडलर प्रश्न में स्ट्रिंग का स्रोत होगा? फिर आप देखते हैं कि स्ट्रिंग गुम हो गई है (पहले से ही C++ कोड में 'आईडीस्पैच :: Invoke' के पूरा होने के बाद) जब यह सब निर्दिष्ट परिदृश्य में कहा जाता है। –

उत्तर

4

इस प्रश्न में उत्तर देने के लिए अत्यधिक कठिन तथ्य हैं। कुछ बहुत आसान हो सकता है, थ्रेड स्टेटस पर वीबीए दुभाषिया के अंदर एक बुरा स्मृति भ्रष्टाचार समस्या या अस्पष्ट निर्भरता हो सकती है। मोटा नैदानिक ​​यह है कि वीबीए इवेंट हैंडलर बस नहीं चला था। यह आम तौर पर एक असामान्य दुर्घटना नहीं है, घटना संचालक घोषित करने के लिए बेसिक में उपयोग की जाने वाली घोषणात्मक शैली सदस्यता समस्याओं का निदान करने के लिए बहुत कम अच्छा तरीका छोड़ देती है। कई वीबीए प्रोग्रामर ने इस तरह की समस्या "इवेंट हैंडलर क्यों नहीं चला" समस्या निवारण करने की कोशिश कर रहे बालों के झुंड खो दिए हैं।

पहले कुछ मुश्किल तथ्यों को इकट्ठा करने और उन्हें अपने प्रश्न का जोड़ें:

  • पहले सत्यापित करें कि आपके सी ++ कोड वास्तव में देख सकते हैं वहाँ कोई ईवेंट हैंडलर बिल्कुल है। अच्छे संस्करण का प्रयोग करें, ईवेंट हैंडलर का नाम बदलें। उम्मीद यह है कि आप ऐसा नहीं करते हैं, जिस पर सिंक सदस्यता नहीं लेता है, वह कोई त्रुटि नहीं है।
  • सत्यापित करें कि ईवेंट हैंडलर वास्तव में खराब संस्करण में निष्पादित है। यह BSTR तर्क असाइन करने से कुछ और करें, कुछ आप डिस्क पर फ़ाइल की तरह आसानी से देख सकते हैं।
  • सत्यापित करें कि आप इवेंट हैंडलर में अपवाद का सही तरीके से निदान कर सकते हैं। एर ऑब्जेक्ट असाइन करें और सत्यापित करें कि आपका सी ++ कोड उचित डायग्नोस्टिक उत्पन्न करता है। ध्यान दें कि आपका आईडीस्पैच :: Invoke() कॉल pExcepInfo के लिए NULL पास करता है, डायग्नोस्टिक उत्पन्न करने का एक अच्छा तरीका नहीं है।
  • जांचें कि क्या ईवेंट दूसरा चलाता है जब आप खिड़की प्रदर्शित करते हैं, यदि ऐसा होता है तो आपके पास निष्पादन आदेश समस्या होती है।

ShowDialog() पर थोड़ा ध्यान केंद्रित करना। इस विधि में बहुत से साइड इफेक्ट्स हैं। पहली चीज जो अब काम नहीं करती है वह आपके सी ++ कोड में संदेश लूप है। अब यह .NET संदेश लूप है जो संदेशों को प्रेषित करता है। साइड इफेक्ट्स के लिए अपनी तरफ देखो, GetMessage/DispatchMessage() से अधिक काम कर रहे हैं। वह काम अब नहीं किया जाता है। PostThreadMessage() के लिए अपना कोडबेस भी खोजें, .NET कोड पंप होने पर वे संदेश फ़्लोर पर गिरते हैं।

और ध्यान रखें कि आपका मूल C++ कोड नियंत्रण खो देता है जब C# कोड ShowDialog() को कॉल करता है। जब तक आप विंडो बंद नहीं करते हैं तब तक यह नियंत्रण प्राप्त नहीं करता है। यह एक साधारण ऑर्डर-ऑफ-निष्पादन समस्या को ट्रिगर कर सकता है, आपके C++ कोड को C# कोड चलने के लिए जो कुछ भी करता है उसके बाद कुछ भी महत्वपूर्ण नहीं करना चाहिए।

+0

पॉइंटर्स के लिए धन्यवाद। जैसा कि आपने अनुमान लगाया होगा, मैं वीबीए/कॉम विशेषज्ञ नहीं हूं, इसलिए आपके डायग सुझावों का बहुत स्वागत है। मैंने अपना जवाब अपडेट कर लिया है - मुख्य बिंदु विफलता के मामले में प्रतीत होता है कि वीबीए कार्यक्रम बिल्कुल निष्पादित नहीं किया जा रहा है। – Chowlett

+0

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

+0

हम्म, उस पर बेचा नहीं। दो प्रविष्टि बिंदुओं के साथ एक सी # असेंबली को देखते हुए, जिसमें से एक संवाद को मॉडल के रूप में प्रदर्शित करता है और एक मॉडलेस के रूप में; और दो वीबीए मैक्रोज़ प्रत्येक प्रविष्टि बिंदुओं में से एक को बुलाते हैं; घटना मॉडेलिस मामले में आग लगती है और उसी एप्लिकेशन निष्पादन_ के भीतर किसी भी क्रम में प्रदर्शन करते समय मोडल केस में विफल हो जाती है। तो यह निश्चित रूप से बाध्य है, क्योंकि मॉडेलिस केस इसे कॉल कर सकता है। – Chowlett

संबंधित मुद्दे