Introduction
Through the years. Access to the Clipboard object has become easier and easier. You might find it strange to have an entire article dedicated to the Clipboard object but the sad fact of the matter is it’s obvious properties and methods got lost in translation. Better said, people still do not know what the Clipboard object is, how to differentiate between copied information, and how to use it. I hope with this article I will demonstrate its proper use, and eliminate confusion.
Logic
With the advent of .NET, accessing the Clipboard from text fields has become so easy. Many a programmer does not realize this, especially if they come from a VB 6 background. The Textboxes come with built in Clipboard methods (Copy, Cut, Paste ) built in. We will make use of these methods, as well as make use of the Clipboard object to do the text manipulation.
With Pictureboxes we will make use of the Clipboard methods, as well as the BitBlt API. The reason for this is so that you can see which one of these two methods are better. The BitBlt API is much more capable of handling various picture types, as well as transparancy.
Design
Fire up Visual Studio 2012 and create a Windows Forms project with either VB.NET or C#. Give your form an appropriate name, or use mine, and add the following controls to it:
Control | Property | Setting |
Form1 | Name | frmEasyClipBoard |
Size | 474, 311 | |
Text | Copying Cutting & Pasting | |
TextBox | Name | txtSource |
Location | 0, 0 | |
TextBox | Name | txtDest |
Location | 0, 58 | |
Button | Name | btnCopyTXT |
Location | 126, 0 | |
Text | Copy With Textbox | |
Button | Name | btnCutTXT |
Location | 126, 29 | |
Text | Cut With Textbox | |
Button | Name | btnPasteTXT |
Location | 126, 58 | |
Text | Paste With TextBox | |
Button | Name | btnClear |
Location | 244, 29 | |
Text | Clear | |
Button | Name | btnClipCopy |
Location | 304, 0 | |
Text | Clipboard Copy | |
Button | Name | btnClipCut |
Location | 304, 29 | |
Text | Clipboard Cut | |
Button | Name | btnClipPaste |
Location | 304, 58 | |
Text | Clipboard Paste | |
PictureBox | Name | picSource |
Image | Any picture, or use mine which is supplied in the download | |
Location | 34, 107 | |
PictureBox | Name | picDest |
Location | 226, 87 | |
Button | Name | btnClipCopyPic |
Location | 12, 242 | |
Text | Clipboard Copy | |
Button | Name | btnClipPastePic |
Location | 120, 242 | |
Text | Clipboard Paste | |
Button | Name | btnBBCopy |
Location | 235, 242 | |
Text | BitBlt Copy | |
Button | Name | btnBBPaste |
Location | 316, 242 | |
Text | BitBlt Paste |
Coding
Text
As usual, let us start with the Modular declarations.
VB.NET
Private strSelectedText As String 'Selected text
C#
This will keep the Selected text inside the textbox(es) that we want to copy. Now, let us Copy, Cut and Paste via the TextBoxes’ built-in methods. Add the following code.
VB.NET
Private Sub btnCopyTXT_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCopyTXT.Click If txtSource.Text <> "" Then 'If something typed in box If txtSource.SelectionLength > 0 Then 'if something selected strSelectedText = txtSource.SelectedText 'store selection txtSource.Copy() 'copy Else txtSource.SelectAll() 'nothing selected, take everything txtSource.Copy() 'copy End If End If End Sub Private Sub btnCutTXT_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCutTXT.Click If txtSource.Text <> "" Then If txtSource.SelectionLength > 0 Then strSelectedText = txtSource.SelectedText txtSource.Cut() Else txtSource.SelectAll() txtSource.Cut() End If End If End Sub Private Sub btnPasteTXT_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPasteTXT.Click Dim OldText As String 'previous text in textbox OldText = txtDest.Text 'store previous text txtDest.SelectionStart = OldText.Length ' set cursor at end to paste at back of text txtDest.Paste() 'paste End Sub
C#
private void btnCopyTXT_Click(object sender, EventArgs e) { //If something typed in box if (!string.IsNullOrEmpty(txtSource.Text)) { //if something selected if (txtSource.SelectionLength > 0) { strSelectedText = txtSource.SelectedText; //store selection txtSource.Copy(); //copy } else { txtSource.SelectAll(); //nothing selected, take everything txtSource.Copy(); //copy } } } private void btnCutTXT_Click(object sender, EventArgs e) { if (!string.IsNullOrEmpty(txtSource.Text)) { if (txtSource.SelectionLength > 0) { strSelectedText = txtSource.SelectedText; txtSource.Cut(); } else { txtSource.SelectAll(); txtSource.Cut(); } } } private void btnPasteTXT_Click(object sender, EventArgs e) { string OldText = null; //previous text in textbox OldText = txtDest.Text; //store previous text txtDest.SelectionStart = OldText.Length; // set cursor at end to paste at back of text //paste txtDest.Paste(); }
This is quite straightforward, as you probably expected. See how simple it is to use the TextBox properties for copy and paste operations?
Now, let us have a look at how it is done through the Clipboard object alone. Add the next code.
VB.NET
Private Sub btnClipCopy_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnClipCopy.Click If txtSource.Text <> "" Then If txtSource.SelectionLength > 0 Then strSelectedText = txtSource.SelectedText Clipboard.SetText(strSelectedText) 'put selection on clipboard Else txtSource.SelectAll() Clipboard.SetText(txtSource.Text) 'put all text on clipboard End If End If End Sub Private Sub btnClipCut_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnClipCut.Click If txtSource.Text <> "" Then If txtSource.SelectionLength > 0 Then strSelectedText = txtSource.SelectedText Clipboard.SetText(strSelectedText) txtSource.SelectedText = "" 'clear text, for cutting - otherwise it's same as copy Else txtSource.SelectAll() Clipboard.SetText(txtSource.Text) txtSource.Text = "" End If End If End Sub Private Sub btnClipPaste_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnClipPaste.Click Dim ClipText As String 'store text from clipboard Dim OldText As String 'previous text in textbox OldText = txtDest.Text 'store previous text ClipText = Clipboard.GetText 'get the clipboard contents txtDest.Text = OldText & ClipText 'to paste at back of text, otherwise just say textbox2.text = cliptext End Sub
C#
private void btnClipCopy_Click(object sender, EventArgs e) { if (!string.IsNullOrEmpty(txtSource.Text)) { if (txtSource.SelectionLength > 0) { strSelectedText = txtSource.SelectedText; Clipboard.SetText(strSelectedText); //put selection on clipboard } else { txtSource.SelectAll(); Clipboard.SetText(txtSource.Text); //put all text on clipboard } } } private void btnClipCut_Click(object sender, EventArgs e) { if (!string.IsNullOrEmpty(txtSource.Text)) { if (txtSource.SelectionLength > 0) { strSelectedText = txtSource.SelectedText; Clipboard.SetText(strSelectedText); txtSource.SelectedText = ""; //clear text, for cutting - otherwise it's same as copy } else { txtSource.SelectAll(); Clipboard.SetText(txtSource.Text); txtSource.Text = ""; } } } private void btnClipPaste_Click(object sender, EventArgs e) { string ClipText = null; //store text from clipboard string OldText = null; //previous text in textbox OldText = txtDest.Text; //store previous text ClipText = Clipboard.GetText(); //get the clipboard contents //to paste at back of text, otherwise just say textbox2.text = cliptext txtDest.Text = OldText + ClipText; }
As you can see, using only the Clipboard to copy and paste items is a bit more code, but the gist of the logic remains the same.
Now, for the fun part.
Pictures
Copying pictures is also quite straightforward. The Pictureboxes do not have clipboard methods built in, but we still have two options for copying and pasting. Option 1 is to use the Clipboard object, and option 2 is to use the BitBlt API. Let us have a look at how the Clipboard handles Image content.
VB.NET
Private Sub btnClipCopyPic_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnClipCopyPic.Click Clipboard.SetImage(picSource.Image) 'copy picture onto clipboard End Sub Private Sub btnClipPastePic_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnClipPastePic.Click picDest.Image = Clipboard.GetImage() 'paste the image End Sub
C#:
private void btnClipCopyPic_Click(object sender, EventArgs e) { //copy picture onto clipboard Clipboard.SetImage(picSource.Image); } private void btnClipCutPic_Click(object sender, EventArgs e) { picDest.Image = Clipboard.GetImage(); //paste the image }
As easy easy as that! You might have noticed after pasting the picture (if you have used my picture that I have supplied – snake.gif ) that there was some sort of greyish area surrounding our picture. That area is actually transparent, so there should be no shading whatsoever. How do we fix this? The answer is BitBlt.
BitBlt
Bit Block Image Transfer copies pixels from a source rectangle to a destination rectangle object based on the Raster Operation Code.
Whoa! That is a mouthful! What it does in laymans terms is to copy a whole picture or a part of a picture to a destination. This destination can be an empty picturebox, or a picturebox with an image. The sky is the limit. We need to add this functionality to our program.
Add a new class to your project and name it EC_BitBlt.
Add the following namespace to the EC_BitBlt class to handle API calls.
VB.NET
Imports System.Runtime.InteropServices
C#
using System.Runtime.InteropServices;
Add the BitBlt API :
VB.NET
<DllImport("gdi32.dll", EntryPoint:="BitBlt", SetLastError:=True, CharSet:=CharSet.Auto)> _ Private Shared Function BitBlt( _ ByVal hdcDest As IntPtr, _ ByVal nXDest As Integer, _ ByVal nYDest As Integer, _ ByVal nWidth As Integer, _ ByVal nHeight As Integer, _ ByVal hdcSrc As IntPtr, _ ByVal nXSrc As Integer, _ ByVal nYSrc As Integer, _ ByVal dwRop As Int32) As Boolean End Function
C#
[DllImport("gdi32.dll", EntryPoint = "BitBlt", SetLastError = true, CharSet = CharSet.Auto)] private static extern bool BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, Int32 dwRop);
Add the following fields to the class.
VB.NET
Private grpMem As Graphics 'Memory Graphic Private iptMem As IntPtr 'Pointer Handle Private szLastSize As Size 'get previous size Private blnCopied As Boolean 'copied? Const SRCCOPY As Integer = &HCC0020 'to copy, also get SRCINVERT to invert the colours as well
C#
//Memory Graphic private Graphics grpMem; //Pointer Handle private IntPtr iptMem; //get previous size private Size szLastSize; //copied? private bool blnCopied; //to copy, also get SRCINVERT to invert the colours as well const int SRCCOPY = 0xcc0020;
Add the next code to copy the picture into memory.
VB.NET
Public Sub EC_Copy(ByVal grpSource As Graphics, ByVal szSize As Size) szLastSize = szSize 'Store size 'Copied already? If blnCopied Then DisposeObjects() 'Dispose old objects 'Create temp Bitmap to create objects from Dim srcBmp As New Bitmap(szSize.Width, szSize.Height, grpSource) grpMem = Graphics.FromImage(srcBmp) 'Create Graphics object iptMem = grpMem.GetHdc 'Get Device Context 'Get the picture DoBitBlt(grpSource, iptMem, szSize.Width, szSize.Height) 'Dispose srcBmp.Dispose() blnCopied = True 'We have copied End Sub
C#
public void EC_Copy(Graphics grpSource, Size szSize) { szLastSize = szSize; //Store size if (blnCopied) DisposeObjects(); //Dispose old objects Bitmap srcBmp = new Bitmap(szSize.Width, szSize.Height, grpSource); //Create temp Bitmap to create objects from grpMem = Graphics.FromImage(srcBmp); //Create Graphics object iptMem = grpMem.GetHdc(); //Get Device Context DoBitBlt(grpSource, iptMem, szSize.Width, szSize.Height); //Get the picture srcBmp.Dispose(); //Dispose blnCopied = true; //We have copied }
Add the code to paste the picture(s).
VB.NET
Public Sub EC_Paste(ByVal grpDest As Graphics, ByVal intX As Integer, ByVal intY As Integer) Dim TargetHdc As IntPtr = grpDest.GetHdc 'Get target object DoBitBlt(iptMem, TargetHdc, szLastSize.Width, szLastSize.Height, intX, intY) 'Source, Dest, Width, Height, X, Y grpDest.ReleaseHdc(TargetHdc) 'Release memory reference End Sub
C#
public void EC_Paste(Graphics grpDest, int intX, int intY) { IntPtr TargetHdc = grpDest.GetHdc(); //Get target object DoBitBlt(iptMem, TargetHdc, szLastSize.Width, szLastSize.Height, intX, intY); //Source, Dest, Width, Height, X, Y grpDest.ReleaseHdc(TargetHdc); //Release memory reference }
You will have noticed that we made reference to the DoBitBlt functions inside both copy and paste. Why? Well, we first have to copy the source into memory, then copy the memory graphic into the picturebox. The two steps are necessary because we might want to do other manipulation to the in-memory graphic before pasting. Let us add the DoBitBlt functions. One is for copying the image into memory, and the other one is for copying the picture from memory into a destination.
VB.NET
Private Sub DoBitBlt(ByVal grpSource As Graphics, ByVal iptDest As IntPtr, ByVal intWidth As Integer, ByVal intHeight As Integer) 'Create DeviceContext to capture from Dim SourceHDC As IntPtr = grpSource.GetHdc ' Blit (Copy) the data BitBlt(iptDest, 0, 0, intWidth, intHeight, SourceHDC, 0, 0, SRCCOPY) ' Release Device context grpSource.ReleaseHdc(SourceHDC) End Sub Private Sub DoBitBlt(ByVal iptSource As IntPtr, ByVal iptDest As IntPtr, ByVal intWidth As Integer, ByVal intHeight As Integer, ByVal intXPos As Integer, ByVal intYPos As Integer) ' Copy data to a specific position on target Device Context BitBlt(iptDest, intXPos, intYPos, intWidth, intHeight, iptSource, 0, 0, SRCCOPY) End Sub
C#
private void DoBitBlt(Graphics grpSource, IntPtr iptDest, int intWidth, int intHeight) { //Create DeviceContext to capture from IntPtr SourceHDC = grpSource.GetHdc(); // Blit (Copy) the data BitBlt(iptDest, 0, 0, intWidth, intHeight, SourceHDC, 0, 0, SRCCOPY); // Release Device context grpSource.ReleaseHdc(SourceHDC); } private void DoBitBlt(IntPtr iptSource, IntPtr iptDest, int intWidth, int intHeight, int intXPos, int intYPos) { // Copy data to a specific position on target Device Context BitBlt(iptDest, intXPos, intYPos, intWidth, intHeight, iptSource, 0, 0, SRCCOPY); }
All we need to do now is to make sure all objects have been Disposed properly out of memory. Add the next procedures.
VB.NET
Protected Overrides Sub Finalize() DisposeObjects() 'make sure all memory is released MyBase.Finalize() End Sub Private Sub DisposeObjects() grpMem.ReleaseHdc(iptMem) ' Release Device Context grpMem.Dispose() ' Disposing of Graphics object End Sub
C#
private void DisposeObjects() { grpMem.ReleaseHdc(iptMem); // Release Device Context grpMem.Dispose(); // Disposing of Graphics object }
Add the next code to your frmEasyClipboard class to access the EC_BitBlt class’ methods
VB.NET
Private Sub btnBBCopy_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnBBCopy.Click ' Create a Graphics object to work with Dim SourceGrp As Graphics = picSource.CreateGraphics ' Copy the surface BBBlits.EC_Copy(SourceGrp, New Size(picSource.Width, picSource.Height)) ' Dispose of the Graphics object SourceGrp.Dispose() End Sub Private Sub btnBBPaste_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnBBPaste.Click 'Create a Graphics object to paste to Dim targetGrp As Graphics = picDest.CreateGraphics ' BitBlt BBBlits.EC_Paste(targetGrp, 0, 0) targetGrp.Dispose() End Sub
C#
private void btnBBCopy_Click(object sender, EventArgs e) { Graphics SourceGrp = picSource.CreateGraphics(); // Copy the surface BBBlits.EC_Copy(SourceGrp, new Size(picSource.Width, picSource.Height)); // Dispose of the Graphics object SourceGrp.Dispose(); } private void btnBBPaste_Click(object sender, EventArgs e) { Graphics targetGrp = picDest.CreateGraphics(); // BitBlt BBBlits.EC_Paste(targetGrp, 0, 0); targetGrp.Dispose(); } }
Not too complicated now is it?
The source files are included with this article, so in case you have missed a step or two, you could have a look in there.
Conclusion
I hope you have enjoyed this article and that you have benefited from it. Until next time! Cheers!