Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 6549373
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 25, 20262026-05-25T12:05:07+00:00 2026-05-25T12:05:07+00:00

Why doesn’t System.Windows.Forms.Clipboard.GetDataObject() return when calling it from a different thread and before the

  • 0

Why doesn’t System.Windows.Forms.Clipboard.GetDataObject() return when calling it from a different thread and before the main thread stops, after calling System.Windows.Forms.Clipboard.Clear() within the main thread?

I have written a sample program to explain my question:

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);
}

The formatted output of this is:

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!

As you can see in the last three lines, System.Windows.Forms.Clipboard.GetDataObject() returns when the main thread stops, but not earlier. Is there a solution for this problem?

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-25T12:05:07+00:00Added an answer on May 25, 2026 at 12:05 pm

    You are doing it right, selecting STA for the worker threads and having them pump a message loop. Except in one: your main thread. It pumps only by accident. The Thread.Join() call makes the CLR pump. But Thread.Sleep() doesn’t pump. You can arbitrarily replace it with this and fix your problem:

        var dummy = new AutoResetEvent(false);
        dummy.WaitOne(1000);
    

    But that’s a hack. I realize this is just a test app, think about what your real one is going to look like.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

Doesn't value have to return toString() to be able to call value.toString()? When do
Why doesn't this work (when parameter is set to 1) : SELECT * FROM
Why doesn't ICloneable 's Clone method return a deep copy? Here is some sample
Why doesn't UITableViewCell background color work (set in interface builder)? I note from some
Why doesn't this work? I have bypassed this before but i can't remember how
Why doesn't this work? private ScrollView findScrollParent(View v) { if(v==null) { return null; }
Doesn't an ORM usually involve doing something like a select *? If I have
Doesn't seem to work for me, maybe I just doing it wrong
Doesn't the space occupied by a variable get deallocated as soon as the control
Doesn't object initialization outside of a constructor break encapsulation ? Given: class MyClass {

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.