Skip to content

Instantly share code, notes, and snippets.

@zumoshi
Created January 14, 2019 09:07
Show Gist options
  • Select an option

  • Save zumoshi/81da40bfd2ae965e1f6a9b7dfb97ceea to your computer and use it in GitHub Desktop.

Select an option

Save zumoshi/81da40bfd2ae965e1f6a9b7dfb97ceea to your computer and use it in GitHub Desktop.
companion code for `Playing around with window's clipboard` article
#include <iostream>
#include <string>
#include <sstream>
#include <windows.h>
#include <Winuser.h>
using namespace std;
string clipboardFormat(UINT type) {
switch (type) {
// standard types, since GetClipboardFormatName doesn't return their name
case 1: return "CF_TEXT";
case 2: return "CF_BITMAP";
case 3: return "CF_METAFILEPICT";
case 4: return "CF_SYLK";
case 5: return "CF_DIF";
case 6: return "CF_TIFF";
case 7: return "CF_OEMTEXT";
case 8: return "CF_DIB";
case 9: return "CF_PALETTE";
case 10: return "CF_PENDATA";
case 11: return "CF_RIFF";
case 12: return "CF_WAVE";
case 13: return "CF_UNICODETEXT";
case 14: return "CF_ENHMETAFILE";
case 15: return "CF_HDROP";
case 16: return "CF_LOCALE";
case 17: return "CF_DIBV5";
case 0x0080: return "CF_OWNERDISPLAY";
case 0x0081: return "CF_DSPTEXT";
case 0x0082: return "CF_DSPBITMAP";
case 0x0083: return "CF_DSPMETAFILEPICT";
case 0x008E: return "CF_DSPENHMETAFILE";
case 0x0200: return "CF_PRIVATEFIRST";
case 0x02FF: return "CF_PRIVATELAST";
case 0x0300: return "CF_GDIOBJFIRST";
case 0x03FF: return "CF_GDIOBJLAST";
default: {
// for registered types
LPSTR formatName = new CHAR[256];
return string(formatName, GetClipboardFormatNameA(type, formatName, 256));
}
}
}
string wideToString(LPWSTR buf, int maxLen) {
LPSTR narrow = new CHAR[maxLen];
return string(narrow, WideCharToMultiByte(CP_UTF8, 0, buf, wcsnlen_s(buf, maxLen), narrow, maxLen, NULL, NULL));
}
string clipboardOwner() {
DWORD dwProcId = 0;
GetWindowThreadProcessId(GetClipboardOwner(), &dwProcId);
LPWSTR ownerImageName = new TCHAR[MAX_PATH];
HANDLE hProc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, dwProcId);
DWORD maxPath = MAX_PATH;
QueryFullProcessImageName(hProc, 0, ownerImageName, &maxPath);
CloseHandle(hProc);
return wideToString(ownerImageName, MAX_PATH);
}
int clipboardSize(UINT type) {
auto hData = GetClipboardData(type);
return hData ? GlobalSize(hData) : -1;
}
string readable_fs(int size) {
if (size < 0)
return "N/A";
const char* units[] = { "B", "kB", "MB", "GB", "TB" };
int i = 0; for (; size > 1024; size /= 1024, i++);
return to_string(size) + units[i];
}
int main()
{
OpenClipboard(NULL);
cout << clipboardOwner() << "\n";
UINT currentFormat = 0;
while (currentFormat = EnumClipboardFormats(currentFormat))
cout << currentFormat << " (" << clipboardFormat(currentFormat) << ")" << " [" << readable_fs(clipboardSize(currentFormat)) << "]" << "\n";
if (IsClipboardFormatAvailable(CF_HDROP)) {
cout << "\n\nList of copied files:\n";
HGLOBAL hGlobal = (HGLOBAL)GetClipboardData(CF_HDROP);
HDROP hDrop = (HDROP)GlobalLock(hGlobal);
LPWSTR fileName = new TCHAR[MAX_PATH];
int fc = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, MAX_PATH);
for (int i = 0; fc > 0; fc--, i++) {
DragQueryFile(hDrop, i, fileName, MAX_PATH);
cout << wideToString(fileName, wcsnlen_s(fileName, MAX_PATH)) << "\n";
}
GlobalUnlock(hGlobal);
}
CloseClipboard();
return 0;
}
#include <string>
#include <sstream>
#include <windows.h>
#include <Winuser.h>
using namespace std;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_CLIPBOARDUPDATE: {
OpenClipboard(hWnd);
// check if a file is copied
if (IsClipboardFormatAvailable(CF_HDROP) &&
// make sure we haven't already done this
// or in case the program already supplied text don't overwrite it
!IsClipboardFormatAvailable(CF_TEXT)) {
// stringStream to create the list (in case of multiple files)
wstringstream fileListStream;
// get Clipboard data
HGLOBAL hGlobal = (HGLOBAL)GetClipboardData(CF_HDROP);
// check if succeeded
if (hGlobal) {
// lock the clipboard so other programs can't modify it while we're reading it
HDROP hDrop = (HDROP)GlobalLock(hGlobal);
if (hDrop) {
// buffer for file names
LPWSTR filePathW = new TCHAR[MAX_PATH];
// calling DragQueryFile with 0xFFFFFFFF will return count of files
int fc = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, MAX_PATH);
for (int i = 0; fc > 0; fc--, i++) {
// get i'th fileName
DragQueryFile(hDrop, i, filePathW, MAX_PATH);
// DragQueryFile returns file with full path, but we only want name.ext
WCHAR filename[_MAX_FNAME], ext[_MAX_EXT];
_wsplitpath_s(filePathW, NULL, NULL, NULL, NULL, filename, _MAX_FNAME, ext, _MAX_EXT);
fileListStream << filename << ext << L"\n";
}
}
GlobalUnlock(hGlobal);
}
// get fileList's data to a string
wstring filelist = fileListStream.str();
// ignore it if empty (either an error or no files were copied)
if (filelist.size() > 0) {
// if it wasn't empty we will put it in clipboard
// note the lack of EmptyClipboard method before SetClipboardData
// create a buffer and globally allocate it
HGLOBAL clipbuffer;
WCHAR * buffer;
clipbuffer = GlobalAlloc(GMEM_DDESHARE, filelist.size() * sizeof(wchar_t) + 1);
buffer = (WCHAR*)GlobalLock(clipbuffer);
// copy the generated list into the buffer
wcscpy_s(buffer, filelist.size() + 1, filelist.c_str());
GlobalUnlock(clipbuffer);
// put it in clipboard
SetClipboardData(CF_UNICODETEXT, clipbuffer);
}
}
CloseClipboard();
break;
}
case WM_CREATE:
AddClipboardFormatListener(hWnd);
break;
case WM_DESTROY:
RemoveClipboardFormatListener(hWnd);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
int CALLBACK WinMain(_In_ HINSTANCE hInstance, _In_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow) {
WNDCLASS wc = { 0 };
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.lpszClassName = L"clip";
RegisterClass(&wc);
HWND hWnd = CreateWindow(wc.lpszClassName, L"x", NULL, 0, 0, 0, 0, HWND_MESSAGE, NULL, hInstance, NULL);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment