Capture the Clipboard’s Contents
The Win32::Clipboard extension makes it easy
June 11, 2006
I have hundreds of Perl scripts that I use. Many of these scripts process some kind of data, such as URLs, email addresses, or paths. Historically, I would write Perl scripts that would obtain this data from an input file or from the keyboard. For example, I would run an application, copy and paste the application's resulting data into an input file, then run a Perl script that read from the input file. One day, however, all this changed. I started using the Win32::Clipboard extension. I can't tell you why it took so long for me to realize a better way of providing input for my Perl scripts. I suppose all that copying and pasting never really bothered me enough to do something about it.
With the Win32::Clipboard extension, the way I provide input to scripts has changed. For example, I have one script that formats network packets captured by the Ethereal network tracing program. When network traffic is captured, all I need to do is copy a particular packet to the Windows Clipboard. The script continuously monitors the Clipboard for changes. When a change is detected, the script retrieves the packet of data from the Clipboard, decodes it, and formats it so that it's legible to humans. The script then writes the formatted data back to the Clipboard. Therefore, with this script, all I need to do is run Ethereal, copy a packet to the Clipboard, then paste the formatted results into an email or a report.
Using the Win32::Clipboard extension has saved me countless hours of work. If you also want to save some time by using the Win32::Clipboard extension, you need to know how the extension works and how to use it in a script.
How the Extension Works
In Windows, every time you select and copy something in a program, it's stored in the Clipboard, which is a temporary memory buffer. Any subsequent use of the Paste command attempts to transfer a copy of the Clipboard's contents into the selected application.
To access the Clipboard, Perl scripts can use the Win32::Clipboard extension, which is part of the ActivePerl standard distribution (http://www.activestate.com). Aldo Calpini, one of the unsung Win32 Perl heroes, wrote the extension.
Using the extension is very simple. Because there's only one shared Clipboard for the entire Windows OS, the Win32::Clipboard extension doesn't require you to create a Win32::Clipboard object. However, to follow common Perl practice, I encourage you to do so. Therefore, to start using the extension, a Perl script should first generate a Clipboard object. With this object, the script can perform a couple of basic tasks: determine the type of content on the Clipboard, retrieve the content on the Clipboard, and copy content to the Clipboard.
Win32::Clipboard recognizes only a few different data formats. The formats are text data, bitmap graphic data, and lists of filenames and directory paths that have been copied to the Clipboard (such as from Windows Explorer). You can determine the data format by calling the Clipboard object's IsText(), IsBitmap(), and IsFiles() methods. Each method will return a Boolean value of TRUE (which has a numeric value of 1) when the method reflects the format of the data currently on the Clipboard.
After determining the kind of data on the Clipboard, the script can use the Get() method to retrieve the data. This method returns the data as a text string when the data is in text format, as a standard binary bitmap when the data is in graphic format, or as an array of paths when the data is in filelist format. The Get() method doesn't modify or erase data from the Clipboard, so the script can call it as many times as necessary. After retrieving the data from the Clipboard, the script can process that data any way it chooses. For example, the script can save the data to a file or display the data on screen.
If the data is in text format, the script can even modify the data, then copy it back to the Clipboard for storage. (This won't work with data in the graphic or file-list format. This is a limitation of the Win32::Clipboard extension.) To copy text data back to the Clipboard, the script needs to pass the data to the Set() method. The data passed in will overwrite any existing data on the Clipboard. To erase the Clipboard's contents, the script can call the Empty() method.
There's one last Win32::Clipboard method that's worth noting: WaitForChange(). This method causes a Perl script to fall asleep until it detects a change to the Clipboard or until a specified timeout value is exceeded. When a timeout value isn't passed to the method, the script will wait forever until a Clipboard change is detected. When a timeout value (in milliseconds) is passed to the method, the script will wait until the specified time, waking up earlier if a change is detected. WaitForChange() returns a Boolean value of TRUE (1) when a change is detected. Any other value indicates that the script slept for the specified time or there was an error.
How to Use the Extension in a Script
The ClipboardMonitor.pl script, which Listing 1, shows, demonstrates how you can write scripts that interact with the Clipboard. This script uses the Win32::Clipboard extension to continuously monitor the Clipboard for changes, then performs an action when a change is detected.
As callout A in Listing 1 shows, the script starts by creating a Win32::Clipboard object ($Clip). If the creation fails, the script terminates. You can use this object for method calls by using code such as
$Clip->Get()
Alternatively, if you don't create a Clipboard object, you can use the full namespace in method calls by using code such as
Win32::Clipboard::Get()
Because there might already be content on the Clipboard, the code at callout A clears any pending change notifications by calling the WaitForChange() method. Notice that a timeout value of 100 milliseconds is passed to this method. A timeout value is included in case no change notification is pending. Otherwise, the script might wait indefinitely and never enter the main loop.
Callout A ends with the beginning of the main loop. This large while() loop uses the WaitForChange() method to wait for Clipboard changes, but this time the method isn't passed a timeout value. Therefore, the script could wait forever. However, a change will most likely be detected. When a change occurs, the main loop processes it.
The code at callout B performs two important tasks. First, the code calls the IsText() method to see whether the Clipboard contains text data. If this method returns TRUE (1), the code calls the Get() method to retrieve that data and assigns it to the $Data variable. Second, the code uses regular expressions to look for URLs, email addresses, and paths in the text that the $Data variable contains. If the code finds any of these elements, it stores them under respective keys in the %List hash.
Using a hash is a neat trick to quickly weed out duplicates. For example, if the Clipboard contains two identical URLs, they'll both be stored in a hash using the same key. This will cause the second entry to overwrite the first one, which essentially removes the duplicate entry.
The code at callout C iterates through each of the entries in the %List hash and groups them by category (i.e., URL, email addresses, and file paths). Each entry in each category is appended to the $Clipboard-Buffer variable.
It's worth noting that the script treats carriage returns () as if they don't imply linefeeds (r). Windows' file I/O routines automatically convert between and r as appropriate when retrieving data from or storing data to text files. However, Windows doesn't perform such conversions when retrieving data from or storing data to the Clipboard. Therefore, the code at callout D and callout G converts all occurrences of to r. This treatment is done solely for the sake of testing with Notepad. If Perl stores carriage returns on the Clipboard and the data is later pasted into Notepad, all the text will display on one long line. This is a limitation of Notepad and not Win32::Clipboard.
The data in the $ClipboardBuffer variable is displayed and copied back to the Clipboard. As callout D shows, the script uses the print() method to display the sorted data and the Set() method to copy the data back to the Clipboard. Anything that was previously on the Clipboard is overwritten.
Next, the script checks to see whether the Clipboard contains graphic data. The code at callout E first calls the IsBitmap() method to determine whether the Clipboard contains graphic data. If so, the code saves the graphic to a file with a unique filename. Because the graphic data is binary and must not be interpreted as text, the created file is switched from text mode to binary mode. The code then uses the Get() method to retrieve the graphic from the Clipboard and uses the print() method to write it to the file. The file's path is copied back to the Clipboard. Thus, you can paste the path from the Clipboard to an application, such as Windows Explorer.
The final part of this script processes any list of files and directories on the Clipboard. This occurs when the user selects objects on the desktop or in Windows Explorer, then selects the Copy option on the Edit menu. As callout F shows, the script calls the IsFiles() method. If paths are found on the Clipboard, the script checks each path to see whether it's a file or directory path. All file and directory paths are stored in the %List hash to remove any duplicates.
Just like the code at Callout C, the code at callout G sorts the contents of the %List hash and stores the sorted data in the $ClipboardBuffer variable. If any paths were found, the script displays and copies them to the Clipboard.
A Great Tool
Using the Clipboard isn't for everyone. For some people, writing Perl scripts that interact with the Clipboard might seem like a useless endeavor. But for me, reading from and writing to the Clipboard is part of my everyday work life. The Clipboard can be a great tool that you can leverage with minimal effort.
About the Author
You May Also Like