2008-09-16 18 views
32

से क्लिपबोर्ड क्यों करता है निम्न कोड कभी कभी सामग्री "CLIPBRD_E_CANT_OPEN" के साथ एक अपवाद का कारण बनता है की स्थापना: यह आमतौर पर पहली बार क्लिपबोर्ड आवेदन में और नहीं प्रयोग किया जाता है तब होता हैCLIPBRD_E_CANT_OPEN त्रुटि जब नेट

Clipboard.SetText(str); 

उसके बाद।

+0

एक बहुत kludgey समाधान है कि स्पष्ट करने के लिए कर रहा है - यह वास्तव में एक ही रास्ता है? – Blorgbeard

+0

ऐसा लगता है कि एमएस ने फॉर्म में इसे लागू किया था। यह सवाल डब्ल्यूपीएफ के बारे में था (हालांकि मुझे इसका एहसास नहीं हुआ था)। –

उत्तर

29

दरअसल, मुझे लगता है कि यह fault of the Win32 API है।

क्लिपबोर्ड में डेटा सेट करने के लिए, आपको पहले open it करना होगा। केवल एक प्रक्रिया में क्लिपबोर्ड एक समय में खुल सकता है। इसलिए, जब आप जांचते हैं, तो किसी अन्य प्रक्रिया में किसी भी कारण के लिए क्लिपबोर्ड खुला है, तो इसे खोलने का आपका प्रयास विफल हो जाएगा।

ऐसा ही होता है कि टर्मिनल सेवा क्लिपबोर्ड का ट्रैक रखती है, और विंडोज़ (प्री-विस्टा) के पुराने संस्करणों पर, आपको क्लिपबोर्ड खोलना है कि अंदर क्या है ... जो आपको अवरुद्ध कर देता है। एकमात्र समाधान तब तक प्रतीक्षा करना है जब तक टर्मिनल सेवा क्लिपबोर्ड को बंद न करे और पुनः प्रयास करें।

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

30

यह टर्मिनल सेवा क्लिपबोर्ड (और संभव अन्य चीजों) में एक बग/फीचर और क्लिपबोर्ड के .NET कार्यान्वयन के कारण होता है। क्लिपबोर्ड खोलने में देरी त्रुटि का कारण बनती है, जो आम तौर पर कुछ मिलीसेकंड के भीतर गुजरती है।

समाधान लूप के भीतर कई बार कोशिश करना और बीच में सोना है।

for (int i = 0; i < 10; i++) 
{ 
    try 
    { 
     Clipboard.SetText(str); 
     return; 
    } 
    catch { } 
    System.Threading.Thread.Sleep(10); 
} 
+4

यदि आप कम से कम .NET 2.0 SP1 पर क्लिपबोर्ड.SetText के आंतरिक को देखते हैं, तो आप देखेंगे कि इसमें पहले से ही एक पुनः प्रयास/प्रतीक्षा लूप है। 100ms देरी के साथ 10 गुना तक retries। –

+12

@ माइक: System.Windows.Forms.Clipboard में एक पुनः प्रयास है, लेकिन WPF से System.Windows.Clipboard नहीं है। –

+0

यह हमारे डब्ल्यूपीएफ आवेदन के लिए चाल है, धन्यवाद! –

5

दरअसल हाथ में एक और मुद्दा हो सकता है। ढांचा कॉल करें (दोनों WPF और WinForm जायके) कुछ इस तरह करने के लिए (कोड परावर्तक से है):

private static void SetDataInternal(string format, object data) 
{ 
    bool flag; 
    if (IsDataFormatAutoConvert(format)) 
    { 
     flag = true; 
    } 
    else 
    { 
     flag = false; 
    } 
    IDataObject obj2 = new DataObject(); 
    obj2.SetData(format, data, flag); 
    SetDataObject(obj2, true); 
} 

ध्यान दें कि SetDataObject हमेशा इस मामले में सच के साथ कहा जाता है।

आंतरिक रूप से Win32 एपीआई में दो कॉल ट्रिगर करता है, एक डेटा सेट करने के लिए और इसे अपने ऐप से फ़्लश करने के लिए, ताकि ऐप बंद होने के बाद यह उपलब्ध हो।

मैंने क्लिपबोर्ड ईवेंट को सुनने वाले कई ऐप्स (कुछ क्रोम प्लगइन और एक डाउनलोड मैनेजर) को देखा है। जैसे ही पहली कॉल हिट हो जाती है, ऐप डेटा देखने के लिए क्लिपबोर्ड खोल देगा, और फ्लश करने वाला दूसरा कॉल विफल हो जाएगा।

मेरे स्वयं के क्लिपबोर्ड क्लास को लिखने के अलावा एक अच्छा समाधान नहीं मिला है जो सीधे Win32 API का उपयोग करता है या ऐप बंद होने के बाद डेटा रखने के लिए सीधे सेटडेटा ऑब्जेक्ट को कॉल करने के लिए कॉल करता है।

4

मैंने देशी Win32 फ़ंक्शंस: OpenClipboard(), CloseClipboard() और SetClipboardData() का उपयोग करके अपने स्वयं के ऐप के लिए इस समस्या को हल किया।

मैंने बनाया रैपर वर्ग के नीचे। क्या कोई भी कृपया इसकी समीक्षा कर सकता है और बताएं कि यह सही है या नहीं। विशेष रूप से जब प्रबंधित कोड x64 ऐप के रूप में चल रहा है (मैं प्रोजेक्ट विकल्पों में किसी भी CPU का उपयोग करता हूं)। क्या होता है जब मैं x64 ऐप से x86 पुस्तकालयों से लिंक करता हूं?

धन्यवाद!

कोड यह रहा:

public static class ClipboardNative 
{ 
    [DllImport("user32.dll")] 
    private static extern bool OpenClipboard(IntPtr hWndNewOwner); 

    [DllImport("user32.dll")] 
    private static extern bool CloseClipboard(); 

    [DllImport("user32.dll")] 
    private static extern bool SetClipboardData(uint uFormat, IntPtr data); 

    private const uint CF_UNICODETEXT = 13; 

    public static bool CopyTextToClipboard(string text) 
    { 
     if (!OpenClipboard(IntPtr.Zero)){ 
      return false; 
     } 

     var global = Marshal.StringToHGlobalUni(text); 

     SetClipboardData(CF_UNICODETEXT, global); 
     CloseClipboard(); 

     //------------------------------------------- 
     // Not sure, but it looks like we do not need 
     // to free HGLOBAL because Clipboard is now 
     // responsible for the copied data. (?) 
     // 
     // Otherwise the second call will crash 
     // the app with a Win32 exception 
     // inside OpenClipboard() function 
     //------------------------------------------- 
     // Marshal.FreeHGlobal(global); 

     return true; 
    } 
} 
+0

पीएस: मैंने" देशी "फ़ंक्शन को कॉल करने से पहले प्रबंधित 'क्लिपबोर्ड.SetText()' कॉल का उपयोग करने का भी प्रयास किया (यानी केवल तभी देशी तरीके से उपयोग किया जाता है जब प्रबंधित कोई काम नहीं करता)। लेकिन अगर प्रबंधित संस्करण विफल रहता है तो यह क्लिपबोर्ड को लॉक करता है और उसके बाद मूल संस्करण भी क्लिपबोर्ड खोलने में विफल रहता है। – Mar

9

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

समाधान:

का उपयोग कभी नहीं

Clipboard.SetText(str); 

उपयोग बजाय

Clipboard.SetDataObject(str); 
+2

यह बहुत अच्छा है। SetDataObject तब क्यों काम करता है? – Carol

+0

@K_Rol: ऐसा लगता है कि यिशई गलाटेज़र के जवाब ने इसे समझाया। – Cameron

0

यह मेरी WPF आवेदन में मेरा क्या। मुझे OpenClipboard विफल मिला (HRESULT से अपवाद: 0x800401D0 (CLIPBRD_E_CANT_OPEN))।

मैं का उपयोग

ApplicationCommands.Copy.Execute(null, myDataGrid); 

समाधान क्लिपबोर्ड पहले

Clipboard.Clear(); 
ApplicationCommands.Copy.Execute(null, myDataGrid); 
संबंधित मुद्दे