Created
January 14, 2019 09:07
-
-
Save zumoshi/81da40bfd2ae965e1f6a9b7dfb97ceea to your computer and use it in GitHub Desktop.
companion code for `Playing around with window's clipboard` article
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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