Tuesday, November 07, 2006

Scott Leonard asks: I am trying to transfer some binary data (byte array) through the clipboard in VS2005 C# without any success. Essentially what I want to do is take a binary file (e.g. dll, exe, jpg, etc.) as a byte array and put it on the clipboard. Then I want to go into a programmer's editor (VSlick, Ultra, VC6, HexEdit etc.), paste the clipboard into an empty doc and save it. I have tried
SetText and SetData and scoured MSDN and the web to no avail. I am not trying to create a custom clipboard type to pass into another app I am writing, I just want to pass binary data and paste it into a standard editor. I found a little tool called CFList from www.ciansoft.com which will show you what format the data in your clipboard is in, and I was trying to see how VSlick and VC6 did it, but it doesn't give very detailed info. MSDN mentions using a memorystream if you want to pass data around unaltered, but I had no success with that either. Here is a simple example of a couple things I tried:

//byte[] byTag = new byte[5] { 0x05, 0x03, 0x09, 0x00, 0x01 }; //doesn't
matter where we get this...
// MemoryStream ms = new MemoryStream(byTag);
// Clipboard.SetData(/*DataFormats.GetFormat(*/"BinaryData"/*)*/,
byTag/*ms*/);




William Answers:

There are two rules for moving data onto the clipboard.
  1. It must be done from the primary thread of a windows form (the thread that created the form), and
  2. You typically need to Clear the clipboard before sending data to it.
Obviously when getting data from the clipboard you don't need to clear it first, but it still needs to occur on a form thread.

To get the function to invoke on the thread which created the form, you'll need to encapsulate your code in a function which checks to see if an Invoke is needed, and if it is, to invoke itself.

Here's a form that I tested out that demonstrates the technique:


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace WindowsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
Thread T = new Thread(new ThreadStart(SetTest));
T.Start();
}

public void SetTest()
{
byte[] byTag = new byte[5] { 0x05, 0x03, 0x09, 0x00, 0x01 };
SetClipboard(this, byTag);
}

public delegate void d_SetClipboard(Form Parent, byte[] Data);
public void SetClipboard(Form Target, byte[] Data)
{
if (Target.InvokeRequired)
Target.Invoke(new d_SetClipboard(SetClipboard), new object[] { Target, Data });
else
{
Clipboard.Clear();
Clipboard.SetDataObject(System.Text.ASCIIEncoding.ASCII.GetString(Data), true);
}
}

public delegate byte[] d_GetClipboard(Form Parent);
public byte[] GetClipboard(Form Target)
{
if (Target.InvokeRequired)
return (byte[])Target.Invoke(new d_GetClipboard(GetClipboard), new object[] { Target });
else
{
IDataObject ido = Clipboard.GetDataObject();
string data = (string) ido.GetData(typeof(string));
return ASCIIEncoding.ASCII.GetBytes(data);
}
}

private void button2_Click(object sender, EventArgs e)
{
Thread T = new Thread(new ThreadStart(GetTest));
T.Start();
}

public void GetTest()
{
if (this.InvokeRequired)
Invoke(new MethodInvoker(GetTest));
else
{
byte[] x = GetClipboard(this);
textBox1.Text = x.Length.ToString();
}
}
}
}



Click button1 to set the clipboard to the contents of the array, then click button 2. The text box will be set to 5, which is the length of the byte array on the clipboard. Notice I translated the byte array into/from a string to make it easy to paste into other applications. It may not be necessary to do this if you want the content as an actual byte array instead of as an ASCII string.

0 Comments:

Post a Comment

<< Home