0

(Short Screen-Cast explaining the problem)

I'm making a Clipboard program, that allows you to see what's in your clipboard.

It looks like this: enter image description here

It seems to work fine copying on-the-fly.

The problem is that I want to be able to go back to a previous img/txt in clipboard and use it - that's when I use the check-mark button.

It works, the only problem is that it copies it twice into the list of images / listbox I'm using. It also happens when I initialize the listbox/picturebox.

Here's the code:

namespace Clipboard_Wizard
{
public partial class FormMain : Form
{
    //register the program in the clipboard viewer chain
    [DllImport("User32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);

    [DllImport("User32.dll", CharSet = CharSet.Auto)]
    public static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);

    private const int WM_DRAWCLIPBOARD = 0x0308;        // WM_DRAWCLIPBOARD message
    private IntPtr _clipboardViewerNext;                // Our variable that will hold the value to identify the next window in the clipboard viewer chain

    private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
    {
        ChangeClipboardChain(this.Handle, _clipboardViewerNext);        // Removes our from the chain of clipboard viewers when the form closes.
    }

    List<Image> img = new List<Image>();
    int ImgCount = 0;
    int ImgIndex = -1;
    Image tmp;

    public FormMain()
    {
        InitializeComponent();

        _clipboardViewerNext = SetClipboardViewer(this.Handle);      // Adds our form to the chain of clipboard viewers.

        //set listbox/picturebox to whatever already on clipboard
        if (Clipboard.ContainsImage())
        {
            tmp = Clipboard.GetImage();
            pictureBox1.Image = tmp;
            img.Add(tmp);
            ImgCount++;
            ImgIndex++;
            btnSlctImg.Enabled = true;
            label3.Text = "Image 1 / 1";
        }
        else if (Clipboard.ContainsText())
        {
            listBox1.Items.Add(Clipboard.GetText());
        }
    }

    // clears everything from the form and the clipboard
    private void btnClear_Click(object sender, EventArgs e)
    {
        Clipboard.Clear();
        listBox1.Items.Clear();
        img.Clear();
        pictureBox1.Image = null;
        ImgCount = 0;
        ImgIndex = -1;
        btnSlctImg.Enabled = false;
    }

    private void btnUpdate_Click(object sender, EventArgs e)
    {
        /*if (Clipboard.ContainsImage())
            {
                tmp = Clipboard.GetImage();
                pictureBox1.Image = tmp;
                img.Add(tmp);
                ImgCount++;
                ImgIndex = ImgCount - 1;  

            }
            else if (Clipboard.ContainsText())
            {
                listBox1.Items.Add(Clipboard.GetText());
                listBox1.TopIndex = listBox1.Items.Count - 1;
            }*/
    }



    private void btnUp_Click(object sender, EventArgs e)
    {
        if(ImgIndex == -1)
        {
            MessageBox.Show("No image.");
        }
        else if (ImgIndex < ImgCount - 1)
        {
            ImgIndex++;
            pictureBox1.Image = img[ImgIndex];
            label3.Text = "Image " + (ImgIndex + 1).ToString() + " / " + ImgCount.ToString() ;
        }
        else
        {
            MessageBox.Show("This is the last image.");
        }
    }

    private void btnDown_Click(object sender, EventArgs e)
    {
        if(ImgIndex == -1)
        {
            MessageBox.Show("No image.");
        }
        else if (ImgIndex > 0)
        {
            ImgIndex--;
            pictureBox1.Image = img[ImgIndex];
            label3.Text = "Image " + (ImgIndex + 1).ToString() + " / " + ImgCount.ToString();
        }
        else
        {
            MessageBox.Show("This is the first image.");
        }
    }

    private void btnDeselect_Click(object sender, EventArgs e)
    {
        listBox1.SelectedIndex = -1;
    }

    //sets clipboard to selected txt from listbox
    private void btnSlct_Click(object sender, EventArgs e)
    {
        string slctTxt = listBox1.SelectedItem.ToString();
        if (slctTxt != null || slctTxt != "")
        {
            Clipboard.SetText(slctTxt);
        }
    }

    //sets clipboard to selected image
    private void btnSlctImg_Click(object sender, EventArgs e)
    {
        Image slctImg = pictureBox1.Image;
        if (slctImg != null)
        {
            Clipboard.SetImage(slctImg); 
        }

    }

    private void listBox1_SelectedIndexChanged_1(object sender, EventArgs e)
    {
        if (listBox1.SelectedIndex != -1)
        {
            btnSlctTxt.Enabled = true;
        }
        else
        {
            btnSlctTxt.Enabled = false;
        }
    }

    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);    // Process the message 

        if (m.Msg == WM_DRAWCLIPBOARD)
        {
            //btnUpdate.PerformClick();

            IDataObject iData = Clipboard.GetDataObject();      // Clipboard's data

            if (iData.GetDataPresent(DataFormats.Text))
            {
                string text = (string)iData.GetData(DataFormats.Text);      // Clipboard text
                listBox1.Items.Add(text);
                listBox1.TopIndex = listBox1.Items.Count - 1;
            }
            else if (iData.GetDataPresent(DataFormats.Bitmap))
            {
                tmp = (Bitmap)iData.GetData(DataFormats.Bitmap);   // Clipboard image
                pictureBox1.Image = tmp;
                img.Add(tmp);
                ImgCount++;
                ImgIndex = ImgCount - 1;
                label3.Text = "Image " + ImgCount.ToString() + " / " + ImgCount.ToString();
                btnSlctImg.Enabled = true;  
            }
        }
    }

}
}

Update: It seems the problem is whenever I call the Clipboard.SetImage(...) or Clipboard.SetText(...) - it does it twice. Still don't understand why though.

TaW
  • 53,122
  • 8
  • 69
  • 111
Maverick Meerkat
  • 5,737
  • 3
  • 47
  • 66
  • Well, there are 2/3 lines with `img.Add(tmp);`. Do you log them? – TaW Mar 04 '17 at 17:06
  • @TaW img is a list of images. I only add to it (a) when the program starts, if the clipboard has an image, I already displays it and add it to the list; and (b) when a new image is copied to the clipboard. I don't see why it should copy it twice when I use the checkmark button to go to a previous item. – Maverick Meerkat Mar 04 '17 at 19:26

2 Answers2

1

You have defined a WndProc to catch changes to the clipboard and add the contents to lists.

In your btnSlctImg_Click to do just that:

if (slctImg != null)  { Clipboard.SetImage(slctImg);  }

So, of course the clipboard is changed, the WndProc is triggered and the currently selected image is added once again to the list you have..

To avoid that you may need to test the lists to see if the image or the text are already in the list. For text this is trivial but for images this is anything but simple. You may have to create and store fingerprints to decide if an image is already in the list.

Here is a post that has examples of creating an MD5 hash for an image.

A simpler trick would be a flag you set in the btnSlctImg_Click right before the Clipboard.SetImage and test and clear in the WndProc. You could still get duplicates, but only if the same data are copied by the user outside of the program..

Community
  • 1
  • 1
TaW
  • 53,122
  • 8
  • 69
  • 111
  • 1
    I think I'll go for the flag workaround for now. Don't want this project to take too much of my time now... lol. Thanks! I'll try tonight, and if it works I'll accept your answer. – Maverick Meerkat Mar 05 '17 at 08:32
  • I tried flagging as a workaround, but it didn't work. It seems no matter what - executing 'Clipboard.Set...' will create double. Maybe because it first clears the clipboard and then sets it to whatever chosen. For now I have a workaround to just delete the last item after I choose it. Seems to work – Maverick Meerkat Mar 05 '17 at 21:18
-1

I wrote a Clipboard utility some time ago and posted it on CodeProject ClipSpy+

I think it will help you with what you are doing!