I need to copy the contents of a handle returned by GetClipboardData from winuser.h, but can't seem to find anything about how to do this.
My program needs to be able to retrieve the contents of the clipboard (regardless of format), set clipboard contents, then return the clipboard contents to the original value, unfortunately since I have to call emptyClipboard() before setClipboardData(), this invalidates the handle returned by GetClipboardData(). I can't seem to find a way to get the length of whatever the handle points to to copy it myself, and the DuplicateHandle function doesn't seem to allow copying of clipboard handles if I understand the docs correctly.
Anyone have any ideas of what I can do here?
rough outline of what I'm trying to do for clarity:
HANDLE clipboardContents;
HANDLE copyMe = WhatIWantOnClipboard();
for (int i = 0; i < 26; i++) {
if ((clipboardContents = GetClipboardData(dataFormats[i])) != NULL) {
formatType = dataFormats[i];
break;
}
else if (i == 25) {
//nothing in clipboard
clipboardContents = -1;
}
}
EmptyClipboard();
SetClipboardData(FORMAT, copyMe);
DoSomethingWithClipboard();
EmptyClipboard();
SetClipboardData(formatType, clipboardContents);
//above will fail with error code 5: Access is denied. As I have emptied the clipboard, which I have to to set the data, from what I understand.
I've tried all different permutations of when I can call functions to no avail, I've attempted to memcopy the contents of the clipboard, but since I can't get the length of what is at the handle, I can't do this.
Here is some code from my own library mixed with your code :
#include <Windows.h>
#include <iostream>
struct ClipboardData {
void* handle;
int size;
unsigned int format;
};
unsigned int dataFormats[26]{ /* ... */ };
class Clipboard {
public:
static void open() {
OpenClipboard(0);
}
static void close() {
CloseClipboard();
}
static void empty() {
EmptyClipboard();
}
static ClipboardData getData() {
ClipboardData data;
for (unsigned int i = 0; i < 26; ++i) {
data.handle = GetClipboardData(dataFormats[i]); // free the memory later.
if (data.handle) {
data.size = GlobalSize(data.handle);
data.format = dataFormats[i];
break;
}
else if (i == 25) {
data.handle = reinterpret_cast<void*>(-1);
}
}
return data;
}
static void setData(void* dataHandle, unsigned int format) {
SetClipboardData(format, dataHandle);
}
};
int main() {
Clipboard::open();
ClipboardData data{ Clipboard::getData() };
char* str{ "Hello world!" };
char* mem{ reinterpret_cast<char*>(HeapAlloc(GetProcessHeap(), 0, 13)) };
for (int i = 0; i < 13; ++i) {
mem[i] = str[i];
}
Clipboard::empty();
Clipboard::setData(mem, CF_TEXT); // set clipboard data to text.
// ...
Clipboard::empty();
Clipboard::setData(data.handle, data.format); // set clipboard data back to as before - doesn't crash.
HeapFree(GetProcessHeap(), 0, mem);
GlobalFree(data.handle); // free memory returned by GetClipboardData.
Clipboard::close();
system("pause");
return 0;
}
I have defined a Clipboard class to encapsulate the system functions.
The first three functions and the last are self-explanatory. The getData function will loop through the defined data formats. When calling the GetClipboardData function, it will return a handle to a memory block. This handle can then be used in the GlobalSize function to get the size of the data. I don't know why your program crashed, but this code works just fine for me.
Hope this helps :)