Inspired by this bug report, I just wrote a small, quick and dirty utility to dump the current clipboard content on Windows. Windows development to me is still pretty much an uncharted territory, so even a utility as simple as this took me some time. Anyway, you can download the binary from here: clipdump.exe. Note that this is a console utility, so you need to run this from the console window.
Here is the source code.
#include <Windows.h> #include <cstdio> #include <cstdlib> #include <iostream> #include <vector> using namespace std; size_t char_per_line = 16; typedef vector<WORD> line_store_type; void dump_line(const line_store_type& line) { if (line.empty()) return; size_t fill_size = char_per_line - line.size(); line_store_type::const_iterator i = line.begin(), iend = line.end(); for (; i != iend; ++i) printf("%04X ", *i); while (fill_size--) cout << " "; cout << ' '; i = line.begin(); for (; i != iend; ++i) { WORD c = *i; if (32 <= c && c <= 126) // ASCII printable range cout << static_cast<char>(c); else // non-printable range cout << '.'; } cout << endl; } void dump_clip(HANDLE hdl) { if (!hdl) return; LPTSTR buf = static_cast<LPTSTR>(GlobalLock(hdl)); if (!buf) return; line_store_type line; line.reserve(char_per_line); for (size_t i = 0, n = GlobalSize(hdl); i < n; ++i) { line.push_back(buf[i]); if (line.size() == char_per_line) { dump_line(line); line.clear(); } } dump_line(line); GlobalUnlock(hdl); } int main() { if (!OpenClipboard(NULL)) return EXIT_FAILURE; UINT fmt = 0; for (fmt = EnumClipboardFormats(fmt); fmt; fmt = EnumClipboardFormats(fmt)) { char name[100]; int len = GetClipboardFormatName(fmt, name, 100); if (!len) continue; cout << "---" << endl; cout << "format code: " << fmt << endl; cout << "name: " << name << endl << endl; HANDLE hdl = GetClipboardData(fmt); dump_clip(hdl); } CloseClipboard(); return EXIT_SUCCESS; } |
It’s nothing sophisticated, and it could probably use more polishing and perhaps some GUI (since it’s a Windows app). But for now it serves the purpose for me.
Update:
Tor has submitted his version in the comment section. Much more sophisticated than mine (and it’s C not C++).
Here is mine… unfortunately not really much documentation, but experimenting with the options and browsing the code should be informative.
#include
#include
#include
#include
#include
#ifndef CF_DIBV5
#define CF_DIBV5 17
#endif
#define MAXDATA 1000
static int maxdata = MAXDATA;
static int interpret_newlines = 1;
typedef enum {
FORMAT_DEFAULT,
FORMAT_STRING,
FORMAT_WSTRING,
FORMAT_HEX,
FORMAT_BINARY
} output_format_type;
const char *
clipboard_format_name (UINT format)
{
static char bfr[100];
if (GetClipboardFormatName (format, bfr, sizeof (bfr)))
return bfr;
if (format >= CF_GDIOBJFIRST && format = CF_PRIVATEFIRST && format 0)
return format;
#define CASE(x) if (strcmp (string, “CF_” # x) == 0) return CF_##x
CASE (BITMAP);
CASE (DIB);
CASE (DIBV5);
CASE (DIF);
CASE (DSPBITMAP);
CASE (DSPENHMETAFILE);
CASE (DSPMETAFILEPICT);
CASE (DSPTEXT);
CASE (ENHMETAFILE);
CASE (HDROP);
CASE (LOCALE);
CASE (METAFILEPICT);
CASE (OEMTEXT);
CASE (OWNERDISPLAY);
CASE (PALETTE);
CASE (PENDATA);
CASE (RIFF);
CASE (SYLK);
CASE (TEXT);
CASE (WAVE);
CASE (TIFF);
CASE (UNICODETEXT);
#undef CASE
while ((format = EnumClipboardFormats (format)))
if (strcmp (string, clipboard_format_name (format)) == 0)
return format;
return 0;
}
static void
print_string_data (const unsigned char *data,
size_t size)
{
int i;
for (i = 0; i = maxdata)
break;
switch (*data)
{
case ‘\a’:
printf (“\\a”);
break;
case ‘\b’:
printf (“\\b”);
break;
case ‘\f’:
printf (“\\f”);
break;
case ‘\n’:
printf (“\\n”);
break;
case ‘\r’:
if (interpret_newlines && data[1] == ‘\n’)
{
printf (“\n”);
data++;
}
else
printf (“\\r”);
break;
case ‘\t’:
printf (“\\t”);
break;
case ‘\\’:
printf (“\\\\”);
break;
default:
if (*data >= ‘ ‘ && *data < 0177)
printf ("%c", *data);
else
printf ("\\%03o", (int) *data);
}
}
}
static void
print_unicode_data (const wchar_t *data,
size_t size)
{
int i;
for (i = 0; i = maxdata)
break;
switch (*data)
{
case ‘\a’:
printf (“\\a”);
break;
case ‘\b’:
printf (“\\b”);
break;
case ‘\f’:
printf (“\\f”);
break;
case ‘\n’:
printf (“\\n”);
break;
case ‘\r’:
if (interpret_newlines && data[1] == ‘\n’)
{
printf (“\n”);
data++;
}
else
printf (“\\r”);
break;
case ‘\t’:
printf (“\\t”);
break;
case ‘\\’:
printf (“\\\\”);
break;
default:
if (*data >= ‘ ‘ && *data < 0177)
printf ("%c", *data);
else
printf ("\\u%04x", *data);
}
}
}
static void
print_hex_data (const unsigned int *data,
size_t size)
{
int i;
for (i = 0; i = maxdata)
break;
printf (“%08x”, *data);
if ((i % 8) == 7)
printf (“\n”);
else
printf (” “);
}
}
static int
format_for_specific_handle (UINT format)
{
switch (format)
{
case CF_BITMAP:
case CF_ENHMETAFILE:
case CF_HDROP:
return 1;
}
return 0;
}
static char *
compression_type (DWORD compression)
{
static char buf[20];
switch (compression)
{
#define CASE(x) case BI_##x: return “BI_”#x
CASE (RGB);
CASE (RLE8);
CASE (RLE4);
CASE (BITFIELDS);
CASE (JPEG);
CASE (PNG);
#undef CASE
default:
sprintf (buf, “%#lx”, compression);
return buf;
}
}
static int
print_colors (const BITMAPINFOHEADER *bi,
const RGBQUAD *rgb)
{
if (bi->biCompression == BI_BITFIELDS &&
bi->biSize == sizeof (BITMAPINFOHEADER))
{
const DWORD *mask = (DWORD *) rgb;
printf (“{%08lx,%08lx,%08lx}”, mask[0], mask[1], mask[2]);
return 3*4;
}
if (bi->biBitCount == 1)
{
int i;
printf (“rgb[2]{“);
for (i = 0; i biBitCount == 4 || bi->biBitCount == 8)
{
int ncolors = 16;
int i;
if (bi->biClrUsed > 0)
ncolors = bi->biClrUsed;
printf (“rgb[%d]{“, ncolors);
for (i = 0; i < ncolors; i++)
{
printf ("%02x%02x%02x}",
rgb[i].rgbRed, rgb[i].rgbGreen, rgb[i].rgbBlue);
if (i bmiHeader.biSize, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, bmi->bmiHeader.biPlanes, bmi->bmiHeader.biBitCount,
compression_type (bmi->bmiHeader.biCompression),
bmi->bmiHeader.biSizeImage, bmi->bmiHeader.biXPelsPerMeter, bmi->bmiHeader.biYPelsPerMeter,
bmi->bmiHeader.biClrUsed, bmi->bmiHeader.biClrImportant);
color_table_size = print_colors (&bmi->bmiHeader, bmi->bmiColors);
image_size = ((((bmi->bmiHeader.biBitCount * bmi->bmiHeader.biWidth) / 8) + 3 ) & ~3) * bmi->bmiHeader.biHeight;
printf (“\n”
“},\n”);
print_hex_data ((const unsigned int *)((char *) data +
bmi->bmiHeader.biSize +
color_table_size),
image_size/4);
}
static void
print_dibv5 (const void *data,
SIZE_T size)
{
const BITMAPV5HEADER *bV5 = (BITMAPV5HEADER *) data;
int color_table_size;
int image_size;
printf (“bV5{\n”
” Size=%ld, Width=%ld, Height=%ld, Planes=%d, BitCount=%d,\n”
” Compression=%s, SizeImage=%ld, XPelsPerMeter=%ld, YPelsPerMeter=%ld,\n”
” ClrUsed=%ld, ClrImportant=%ld,\n”
” RedMask=%08lx, GreenMask=%08lx, BlueMask=%08lx, AlphaMask=%08lx,\n”
” CsType=%ld (%c%c%c%c)\n”
“},\n”,
bV5->bV5Size, bV5->bV5Width, bV5->bV5Height, bV5->bV5Planes, bV5->bV5BitCount,
compression_type (bV5->bV5Compression),
bV5->bV5SizeImage, bV5->bV5XPelsPerMeter, bV5->bV5YPelsPerMeter,
bV5->bV5ClrUsed, bV5->bV5ClrImportant,
bV5->bV5RedMask, bV5->bV5GreenMask, bV5->bV5BlueMask, bV5->bV5AlphaMask,
bV5->bV5CSType,
((char *)&bV5->bV5CSType)[3], ((char *)&bV5->bV5CSType)[2],
((char *)&bV5->bV5CSType)[1], ((char *)&bV5->bV5CSType)[0]);
printf (“colortable”);
color_table_size = print_colors ((BITMAPINFOHEADER *) bV5,
(RGBQUAD*) ((char *)bV5) + bV5->bV5Size);
image_size = ((((bV5->bV5BitCount * bV5->bV5Width) / 8) + 3 ) & ~3) * bV5->bV5Height;
printf (“\n”);
print_hex_data ((const unsigned int *)((char *) data +
bV5->bV5Size +
color_table_size),
image_size/4);
}
static void
print_data (output_format_type output_format,
UINT format,
const unsigned char *data,
SIZE_T size)
{
switch (output_format)
{
case FORMAT_DEFAULT:
switch (format)
{
case CF_DIB:
print_dib (data, size);
break;
case CF_DIBV5:
print_dibv5 (data, size);
break;
default:
goto _FORMAT_STRING;
}
break;
case FORMAT_STRING: _FORMAT_STRING:
print_string_data (data, size);
break;
case FORMAT_WSTRING:
print_unicode_data ((wchar_t *) data, (size+1)/2);
break;
case FORMAT_HEX:
print_hex_data ((unsigned int *) data, (size+3)/4);
break;
case FORMAT_BINARY:
_setmode (fileno (stdout), O_BINARY);
fwrite (data, size, 1, stdout);
return;
}
printf (“\n”);
}
static void
print_format_for_specific_handle (UINT format,
HANDLE handle)
{
switch (format)
{
case CF_BITMAP:
{
HANDLE handle = GetClipboardData (format);
BITMAP bm;
if (!GetObject (handle, sizeof (BITMAP), (void *) &bm))
fprintf (stderr, “GetObject failed.\n”), exit (1);
printf (“bm{\n”
” Type=%ld, Width=%ld, Height=%ld, WidthBytes=%ld,\n”
” Planes=%d, BitsPixel=%d,\n”
” bmBits=”,
bm.bmType, bm.bmWidth, bm.bmHeight, bm.bmWidthBytes,
bm.bmPlanes, bm.bmBitsPixel);
if (bm.bmBits != NULL)
print_data (FORMAT_HEX, CF_BITMAP, bm.bmBits, bm.bmHeight*bm.bmWidthBytes);
else
printf (“0”);
printf (“\n”
“}”);
}
break;
default:
printf (“%p”, handle);
}
}
static void
usage (const char *progname)
{
fprintf (stderr, “Usage: %s [-m maxdata] [-b|-h|-n|-u|-i filename|-o filename]… (-l|-g format|-p format)\n”, progname);
}
int
main (int argc,
char **argv)
{
UINT format = 0;
HANDLE handle;
int i;
output_format_type output_format = FORMAT_DEFAULT;
if (argc < 2)
usage (argv[0]), exit (1);
if (!OpenClipboard (NULL))
fprintf (stderr, "OpenClipboard failed.\n"), exit (1);
/* Traverse options twice, first set flags */
for (i = 1; i < argc; i++)
{
if (strcmp (argv[i], "-i") == 0)
{
if (i + 1 == argc)
usage (argv[0]), exit (1);
i++;
if (freopen (argv[i], "r", stdin) == NULL)
fprintf (stderr, "Could not open %s for reading.\n", argv[i]), exit (1);
}
else if (strcmp (argv[i], "-o") == 0)
{
if (i + 1 == argc)
usage (argv[0]), exit (1);
i++;
if (freopen (argv[i], "w", stdout) == NULL)
fprintf (stderr, "Could not open %s for writing.\n", argv[i]), exit (1);
}
else if (strcmp (argv[i], "-n") == 0)
{
interpret_newlines = 0;
}
else if (strcmp (argv[i], "-u") == 0)
{
output_format = FORMAT_WSTRING;
}
else if (strcmp (argv[i], "-h") == 0)
{
output_format = FORMAT_HEX;
}
else if (strcmp (argv[i], "-b") == 0)
{
output_format = FORMAT_BINARY;
}
else if (strcmp (argv[i], "-g") == 0)
{
if (i + 1 == argc)
usage (argv[0]), exit (1);
i++;
}
else if (strcmp (argv[i], "-m") == 0)
{
if (argc < 3 || (maxdata = atoi (argv[i+1])) <= 0)
usage (argv[0]), exit (1);
}
else if (strcmp (argv[i], "-p") == 0)
{
if (i + 1 == argc)
usage (argv[0]), exit (1);
}
}
/* Then interpret what to do */
for (i = 1; i 0)
{
if (nread < buffer_size – in_use && ferror (stdin))
fprintf (stderr, "Error reading after %d bytes.\n", in_use + nread), exit (1);
in_use += nread;
if (in_use == buffer_size)
{
buffer_size *= 1.5;
GlobalUnlock (handle);
if ((handle = GlobalReAlloc (handle, buffer_size, GMEM_MOVEABLE)) == NULL)
fprintf (stderr, "GlobalReAlloc(%d) failed.\n", buffer_size), exit (1);
buffer = GlobalLock (handle);
}
}
GlobalUnlock (handle);
if ((handle = GlobalReAlloc (handle, in_use, GMEM_MOVEABLE)) == NULL)
fprintf (stderr, "GlobalReAlloc(%d) failed.\n", in_use), exit (1);
if (SetClipboardData (format, handle) == NULL)
fprintf (stderr, "GetClipboardData(%d) failed.\n", format), exit (1);
GlobalUnlock (handle);
}
}
CloseClipboard ();
return 0;
}
Ah, sanely formatted: http://pastebin.com/4nieRnLa
Thanks Tor! It helps a lot. I’ve added your version to my post (so that it will stay after pastebin decides to delete it).
Actually I’ve decided to put your code here instead of putting it in my post (to keep my post from being too long).
Hi! Can you tell me the way to present C code in the post? Thank you!
Sure! I use WP-Syntax plugin for wordpress:
http://wordpress.org/extend/plugins/wp-syntax/
then you can use the pre tag (not sure if there is a separate C mode) to syntax-highlight the embedded code.
BTW this plugin seems to work in the comments too.