System.Windows.Forms.Clipboard.GetDataObject()
다른 스레드에서 호출 할 때 및 주 스레드가 중지되기 전에 주 스레드 내에서 System.Windows.Forms.Clipboard.Clear()
을 호출 한 후 그 이유를 아는 사람이 있습니까?System.Windows.Forms.Clipboard.GetDataObject() doesnt 응답
:
public class ClipboardDemo
{
[STAThread]
public static void Main(string[] args)
{
Thread.CurrentThread.Name = "MAIN_THREAD";
Thread clipboardViewerThread = new Thread(RunClipboardViewer);
clipboardViewerThread.Name = "CLIPBOARD_VIEWER_THREAD";
clipboardViewerThread.SetApartmentState(ApartmentState.STA);
Thread clipboardClearerThread = new Thread(RunClipboardClearer);
clipboardClearerThread.Name = "CLIPBOARD_CLEARER_THREAD";
clipboardClearerThread.SetApartmentState(ApartmentState.STA);
Console.WriteLine("Starting " + clipboardViewerThread.Name + ", expecting initial WM_DRAWCLIPBOARD message...");
clipboardViewerThread.Start();
Thread.Sleep(1000);
Console.WriteLine("Clearing clipboard from " + clipboardClearerThread.Name + ", expecting WM_DRAWCLIPBOARD message...");
clipboardClearerThread.Start();
clipboardClearerThread.Join();
Console.WriteLine("Clearing clipboard from " + Thread.CurrentThread.Name + ", expecting WM_DRAWCLIPBOARD message...");
Clipboard.Clear();
Thread.Sleep(1000);
Application.Exit();
Console.WriteLine("\t" + Thread.CurrentThread.Name + " stopped!");
}
private static void RunClipboardViewer()
{
ClipboardViewer viewer = new ClipboardViewer();
viewer.ViewClipboard();
viewer.Dispose();
}
private static void RunClipboardClearer()
{
Clipboard.Clear();
}
}
internal class ClipboardViewer : NativeWindow, IDisposable
{
private const int WM_CREATE = 0x0001;
private const int WM_DRAWCLIPBOARD = 0x0308;
private const int WM_CHANGECBCHAIN = 0x030D;
private IntPtr nextViewer;
public void ViewClipboard()
{
base.CreateHandle(new CreateParams());
Application.Run();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
switch (m.Msg)
{
case WM_CREATE:
nextViewer = User32Interop.SetClipboardViewer(base.Handle);
break;
case WM_DRAWCLIPBOARD:
if (nextViewer != IntPtr.Zero)
{
User32Interop.SendMessage(nextViewer, WM_DRAWCLIPBOARD, m.WParam, m.LParam);
}
Console.WriteLine("\tClipboard changed in " + Thread.CurrentThread.Name + ". Trying to receive data object...");
Clipboard.GetDataObject();
Console.WriteLine("\tData object received!");
break;
case WM_CHANGECBCHAIN:
if (m.WParam == nextViewer)
{
nextViewer = m.LParam;
}
else if (nextViewer != IntPtr.Zero)
{
User32Interop.SendMessage(nextViewer, WM_CHANGECBCHAIN, m.WParam, m.LParam);
}
break;
}
}
private void Dispose(bool disposing)
{
if (disposing)
{
User32Interop.ChangeClipboardChain(base.Handle, nextViewer);
}
base.DestroyHandle();
}
~ClipboardViewer()
{
Dispose(false);
}
}
internal static class User32Interop
{
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
}
이의 형식화 된 출력은 다음과 같습니다
Starting CLIPBOARD_VIEWER_THREAD, expecting initial WM_DRAWCLIPBOARD message...
Clipboard changed in CLIPBOARD_VIEWER_THREAD. Trying to receive data object...
Data object received!
Clearing clipboard from CLIPBOARD_CLEARER_THREAD, expecting WM_DRAWCLIPBOARD message...
Clipboard changed in CLIPBOARD_VIEWER_THREAD. Trying to receive data object...
Data object received!
Clearing clipboard from MAIN_THREAD, expecting WM_DRAWCLIPBOARD message...
Clipboard changed in CLIPBOARD_VIEWER_THREAD. Trying to receive data object...
MAIN_THREAD stopped!
Data object received!
지난 3 개 라인에서 볼 수 있듯이, System.Windows.Forms.Clipboard.GetDataObject()
반환 할 때 주 스레드는 멈추지 만 이전에는 그렇지 않습니다. 아무도이 문제에 대한 해결책을 알고 있습니까?
미리 감사드립니다.
빠른 답장을 보내 주셔서 감사합니다. 모든 스레드에 대해 Thread.SetApartmentState (ApartmentState.STA)를 호출했고 주 스레드의 Main() 메서드에 STAThreadAttribute를 추가하여 모든 스레드가 STA 모드로 실행되도록했습니다. 하나의 프로세스에서 여러 개의 STA 스레드를 가질 수는 없습니까? 내 접근 방식은 클립 보드 변경 이벤트를 잡기위한 클래스 라이브러리를 작성하는 것이므로 모든 UI가 havent ... –
실례합니다 Jon Skeet, 저는 stackoverflow에 새로운 것 같습니다. 실수로 게시물을 삭제 한 것으로 보입니다. S 가능한 한 당신은 내가 STA 스레드 내에서만 클립 보드에 액세스 할 수 있고 Control.Invoke() 접근 방식을 권유한다고 말한 msdn에 대해 기억하고 있다는 것을 기억하십시오. –