3

I am trying to make a global multi value Clipboard. I have used a stack to store the values. I am using WinProc() to capture the global Copy operation where I push the value on stack. Similarly I am using a windows keyboard hook to capture the Ctrl-V (Paste) operation. The code for both the functions is as below. I have copied and modified the code from this.

        private int KbHookProc(int nCode, IntPtr wParam, IntPtr lParam)
    {
        if (nCode >= 0)
        {
            var hookStruct = (KbLLHookStruct)Marshal.PtrToStructure(lParam, typeof(KbLLHookStruct));

            // Quick and dirty check. You may need to check if this is correct. See GetKeyState for more info.
            bool ctrlDown = GetKeyState(VK_LCONTROL) != 0 || GetKeyState(VK_RCONTROL) != 0;

            if (ctrlDown && hookStruct.vkCode == 0x56) // Ctrl+V
            {
                if (clipBoardStack.Count > 0)
                {
                    lock (this)
                    {
                        localChange = true;
                        RemoveClipboardFormatListener(this.Handle);     // Remove our window from the clipboard's format listener list.
                        System.Threading.Thread.Sleep(200);
                        Clipboard.SetText(clipBoardStack.Pop());
                        AddClipboardFormatListener(this.Handle);
                        System.Threading.Thread.Sleep(200);
                    }

                }

            }
        }

        // Pass to other keyboard handlers. Makes the Ctrl+V pass through.
        return CallNextHookEx(_hookHandle, nCode, wParam, lParam);
    }

My WinProc override is as follows. I have copied it from SO as well but dont remember the link.

        protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);

        if (m.Msg == WM_CLIPBOARDUPDATE)
        {
            if (!localChange)//Only store the data in stack when it comes from outside. Just to prevent the side effect of Paste Operation
            {
                IDataObject iData = Clipboard.GetDataObject();      // Clipboard's data.

                if (iData.GetDataPresent(DataFormats.Text))
                {
                    lock (this)
                    {
                        string text = (string)iData.GetData(DataFormats.Text);
                        clipBoardStack.Push(text);                            
                    }
                }
            }
            else
            {
                localChange = false;
            }
        }

The copy operation is working well. It populates the stack, but when I use a paste operation, it triggers the WM_CLIPBOARDUPDATE event. Which makes the stack populated again with the most recent value.

I think when I change the Clipboard value in the Paste intercept, it triggers the WM_CLIPBOARDUPDATE event.I have tried to Unregister the listner, I have tried to use a flag variable 'localChange', I have tried to use block(), but nothing is working.

What can be done to solve it.

Community
  • 1
  • 1
ResVict
  • 312
  • 2
  • 12

2 Answers2

5

You can still listen for the clipboard updates, but you need to ignore them when they are created by you. i.e. don't react to your own echo.

You may be able to use the clipboard ownership, or you can inject a private clipboard format to "flag" it as yours. Here is an article (by me, long ago) explaining how to do that, which is intended for the purpose of telling clipboard viewers to NOT capture the data. http://www.clipboardextender.com/developing-clipboard-aware-programs-for-windows/ignoring-clipboard-updates-with-the-cf_clipboard_viewer_ignore-clipboard-format

The basic idea of that article, is to create a private clipboard format called CF_CLIPBOARD_VIEWER_IGNORE, and add it to the clipboard at the same time (in the same open/update/close sequence) that you put the real data. Programs like web browsers, word processors, notepad, etc., will not care. But clipboard viewers (such as your own, or my ClipMate) would see the CF_CLIPBOARD_VIEWER_IGNORE format present on the clipboard, and then ignore the data. This is also a way for apps like password managers to avoid cluttering clipboard managers with sensitive data.

Chris Thornton
  • 15,620
  • 5
  • 37
  • 62
1

You may register HotKey (Ctrl-V) with the system, so that the system can send control to the HotKey handler in your application. There you can update the Clipboard.

Since registering the HotKey will make system to notify only your application, therefore you will have control on what you do with the ClipBoard. Later on you will have to send the Ctrl-V combination to the target (intended) application. This will simulate as if the paste command has been issued by the user for the target application.

The downside of this is that you will have to know which application was in focus to send the key combination to later on.

Novice
  • 515
  • 7
  • 22