.NET에서 클립보드를 설정할 때 CLIPBRD_E_CANT_OPEN 오류가 발생합니다.

StackOverflow https://stackoverflow.com/questions/68666

  •  09-06-2019
  •  | 
  •  

문제

다음 코드에서 때때로 "CLIPBRD_E_CANT_OPEN" 내용의 예외가 발생하는 이유는 무엇입니까?

Clipboard.SetText(str);

이는 일반적으로 응용 프로그램에서 클립보드를 처음 사용할 때 발생하며 그 이후에는 발생하지 않습니다.

도움이 되었습니까?

해결책

사실 내 생각에는 이것이다. Win32 API의 결함.

클립보드에 데이터를 설정하려면 다음을 수행해야 합니다. 열어 봐 첫 번째.한 번에 하나의 프로세스만 클립보드를 열 수 있습니다.그래서 확인해 보면 다른 프로세스에서 클립보드가 열려 있으면 어떤 이유로, 열려는 시도가 실패합니다.

터미널 서비스는 클립보드를 추적하므로 이전 버전의 Windows(Vista 이전)에서는 클립보드를 열어서 내용을 확인해야 합니다.결국 당신을 차단하게 됩니다.유일한 해결책은 터미널 서비스가 클립보드를 닫을 때까지 기다렸다가 다시 시도하는 것입니다.

그러나 이것이 터미널 서비스에만 국한된 것은 아니라는 점을 인식하는 것이 중요합니다.그것은 무엇이든 일어날 수 있습니다.Win32에서 클립보드 작업은 엄청난 경쟁 조건입니다.그러나 설계상 사용자 입력에 대한 응답으로만 클립보드를 조작하도록 되어 있으므로 이는 일반적으로 문제가 되지 않습니다.

다른 팁

이는 터미널 서비스 클립보드(및 기타 가능한 사항)의 버그/기능과 클립보드의 .NET 구현으로 인해 발생합니다.클립보드 열기가 지연되면 오류가 발생하며 일반적으로 몇 밀리초 내에 발생합니다.

해결책은 루프 내에서 여러 번 시도하고 그 사이에 휴면하는 것입니다.

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

이 질문은 오래되었지만 문제는 여전히 존재합니다.앞서 언급했듯이 이 예외는 시스템 클립보드가 다른 프로세스에 의해 차단될 때 발생합니다.불행하게도 Windows 클립보드를 차단할 수 있는 캡처 도구, 스크린샷용 프로그램, 파일 복사 도구가 많이 있습니다.따라서 사용하려고 할 때마다 예외가 발생합니다. Clipboard.SetText(str) 이러한 도구가 PC에 설치되어 있는 경우.

해결책:

절대 사용하지 마세요

Clipboard.SetText(str);

대신 사용

Clipboard.SetDataObject(str);

사실 또 다른 문제가 있을 수도 있습니다.프레임워크 호출(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는 항상 true로 호출됩니다.

내부적으로는 win32 API에 대한 두 번의 호출을 트리거합니다. 하나는 데이터를 설정하고 다른 하나는 앱을 닫은 후에도 사용할 수 있도록 앱에서 데이터를 플러시하는 것입니다.

클립보드 이벤트를 수신하는 여러 앱(일부 Chrome 플러그인 및 다운로드 관리자)을 보았습니다.첫 번째 호출이 발생하자마자 앱은 클립보드를 열어 데이터를 조사하고 두 번째 플러시 호출은 실패합니다.

직접 win32 API를 사용하는 자체 클립보드 클래스를 작성하거나 앱이 닫힌 후 데이터를 유지하기 위해 false로 setDataObject를 직접 호출하는 것 외에는 좋은 솔루션을 찾지 못했습니다.

기본 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;
    }
}

내 WPF 응용 프로그램에서 이런 일이 발생합니다.OpenClipboard 실패가 발생했습니다(HRESULT 예외:0x800401D0(CLIPBRD_E_CANT_OPEN)).

나는 사용한다

ApplicationCommands.Copy.Execute(null, myDataGrid);

해결책은 먼저 클립보드를 지우는 것입니다

Clipboard.Clear();
ApplicationCommands.Copy.Execute(null, myDataGrid);
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top