PageRenderTime 44ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/Samples/Extra/DragDrop/list_clipboard/main.d

http://github.com/AndrejMitrovic/DWinProgramming
D | 456 lines | 346 code | 87 blank | 23 comment | 26 complexity | 6a39c5f7033d1198811cf4e00d4252ad MD5 | raw file
  1. module list_clipboard.main;
  2. /**
  3. The project queries the OS clipboard using COM functions,
  4. and then prints out all the content types in the clipboard.
  5. */
  6. import core.runtime;
  7. import std.c.process;
  8. import std.algorithm;
  9. import std.conv;
  10. import std.exception;
  11. import std.range;
  12. import std.stdio;
  13. import std.string;
  14. import std.utf;
  15. pragma(lib, "comctl32.lib");
  16. pragma(lib, "ole32.lib");
  17. import core.sys.windows.commctrl;
  18. import core.sys.windows.objidl;
  19. import core.sys.windows.ole2;
  20. import core.sys.windows.winbase;
  21. import core.sys.windows.windef;
  22. import core.sys.windows.winuser;
  23. import core.sys.windows.wtypes;
  24. import list_clipboard.resource;
  25. import utils.com;
  26. alias toCharz = toUTFz!(char*);
  27. struct STRLOOKUP
  28. {
  29. UINT cfFormat;
  30. string name;
  31. }
  32. // note: missing in WinAPI
  33. enum CF_DIBV5 = 17;
  34. enum CF_MAX = 18;
  35. STRLOOKUP[] cliplook =
  36. [
  37. STRLOOKUP(CF_BITMAP, "CF_BITMAP"),
  38. STRLOOKUP(CF_DIB, "CF_DIB"),
  39. STRLOOKUP(CF_DIBV5, "CF_DIBV5"),
  40. STRLOOKUP(CF_DIF, "CF_DIF"),
  41. STRLOOKUP(CF_DSPBITMAP, "CF_DSPBITMAP"),
  42. STRLOOKUP(CF_DSPENHMETAFILE, "CF_DSPENHMETAFILE"),
  43. STRLOOKUP(CF_DSPMETAFILEPICT, "CF_DSPMETAFILEPICT"),
  44. STRLOOKUP(CF_DSPTEXT, "CF_DSPTEXT"),
  45. STRLOOKUP(CF_ENHMETAFILE, "CF_ENHMETAFILE"),
  46. STRLOOKUP(CF_GDIOBJFIRST, "CF_GDIOBJFIRST"),
  47. STRLOOKUP(CF_HDROP, "CF_HDROP"),
  48. STRLOOKUP(CF_LOCALE, "CF_LOCALE"),
  49. STRLOOKUP(CF_METAFILEPICT, "CF_METAFILEPICT"),
  50. STRLOOKUP(CF_OEMTEXT, "CF_OEMTEXT"),
  51. STRLOOKUP(CF_OWNERDISPLAY, "CF_OWNERDISPLAY"),
  52. STRLOOKUP(CF_PALETTE, "CF_PALETTE"),
  53. STRLOOKUP(CF_PENDATA, "CF_PENDATA"),
  54. STRLOOKUP(CF_PRIVATEFIRST, "CF_PRIVATEFIRST"),
  55. STRLOOKUP(CF_RIFF, "CF_RIFF"),
  56. STRLOOKUP(CF_SYLK, "CF_SYLK"),
  57. STRLOOKUP(CF_TEXT, "CF_TEXT"),
  58. STRLOOKUP(CF_WAVE, "CF_WAVE"),
  59. STRLOOKUP(CF_TIFF, "CF_TIFF"),
  60. STRLOOKUP(CF_UNICODETEXT, "CF_UNICODETEXT"),
  61. STRLOOKUP(0, null),
  62. ];
  63. STRLOOKUP[] aspectlook =
  64. [
  65. STRLOOKUP(DVASPECT.DVASPECT_CONTENT, "Content "),
  66. STRLOOKUP(DVASPECT.DVASPECT_THUMBNAIL, "Thumbnail"),
  67. STRLOOKUP(DVASPECT.DVASPECT_ICON, "Icon "),
  68. STRLOOKUP(DVASPECT.DVASPECT_DOCPRINT, "DocPrint "),
  69. STRLOOKUP(0, null),
  70. ];
  71. STRLOOKUP[] tymedlook =
  72. [
  73. STRLOOKUP(TYMED.TYMED_HGLOBAL, "hGlobal"),
  74. STRLOOKUP(TYMED.TYMED_FILE, "File"),
  75. STRLOOKUP(TYMED.TYMED_ISTREAM, "IStream"),
  76. STRLOOKUP(TYMED.TYMED_ISTORAGE, "IStorage"),
  77. STRLOOKUP(TYMED.TYMED_GDI, "GDI"),
  78. STRLOOKUP(TYMED.TYMED_MFPICT, "MFPict"),
  79. STRLOOKUP(TYMED.TYMED_ENHMF, "ENHMF"),
  80. STRLOOKUP(TYMED.TYMED_NULL, "Null"),
  81. STRLOOKUP(0, null),
  82. ];
  83. enum APPNAME = "IDataObject Viewer";
  84. HWND hwndMain;
  85. HWND hwndList;
  86. HINSTANCE hInstance;
  87. /** Display the enumerated format of the clipboard. */
  88. void AddFormatListView(HWND hwndList, FORMATETC* pfmtetc)
  89. {
  90. // Get textual name of format
  91. string name;
  92. char[64] namebuf = 0;
  93. if (GetClipboardFormatName(pfmtetc.cfFormat, namebuf.ptr, 64) == 0)
  94. {
  95. auto fmt = cliplook.find!(a => a.cfFormat == pfmtetc.cfFormat);
  96. if (fmt.empty)
  97. name = "Unknown Format";
  98. else
  99. name = fmt.front.name;
  100. }
  101. else
  102. {
  103. name = to!string(namebuf.ptr);
  104. }
  105. DWORD nIndex = ListView_GetItemCount(hwndList);
  106. LVITEM lvitem;
  107. lvitem.mask = LVIF_TEXT;
  108. lvitem.iSubItem = 0;
  109. lvitem.iItem = nIndex;
  110. lvitem.pszText = name.toCharz;
  111. // add new row, and set format name (cfFormat)
  112. ListView_InsertItem(hwndList, &lvitem);
  113. // Add TARGETDEVICE pointer
  114. string ptd;
  115. if (pfmtetc.ptd !is null)
  116. ptd = format("%08x", pfmtetc.ptd);
  117. // set the subitem
  118. ListView_SetItemText(hwndList, nIndex, 1, ptd.toCharz);
  119. // Add DVASPECT_xxx constant
  120. string aspect;
  121. auto aspectRng = aspectlook.find!(a => a.cfFormat == pfmtetc.dwAspect);
  122. if (aspectRng.empty)
  123. aspect = "Unknown ";
  124. else
  125. aspect = aspectRng.front.name;
  126. ListView_SetItemText(hwndList, nIndex, 2, aspect.toCharz);
  127. // Add lindex value
  128. ListView_SetItemText(hwndList, nIndex, 3, pfmtetc.lindex.to!string.toCharz);
  129. // Add TYMED value(s)
  130. string[] tymedArr;
  131. // now add all supported data mediums
  132. for (int i = 1; i <= 64; i <<= 2)
  133. {
  134. if (pfmtetc.tymed & i)
  135. {
  136. string tymed;
  137. auto tymedRng = tymedlook.find!(a => a.cfFormat == i);
  138. if (tymedRng.empty)
  139. tymed = "Unknown";
  140. else
  141. tymed = tymedRng.front.name;
  142. tymedArr ~= tymed;
  143. }
  144. }
  145. ListView_SetItemText(hwndList, nIndex, 4, tymedArr.join(", ").toCharz);
  146. }
  147. /** Create the list view and the columns. */
  148. HWND CreateListView(HWND hwndParent)
  149. {
  150. LVCOLUMN lvcol;
  151. int width = 512;
  152. hwndList = CreateWindowEx(WS_EX_CLIENTEDGE, "SysListView32", "",
  153. WS_CHILD|WS_VISIBLE|LVS_REPORT, 0, 0, 0, 0, hwndParent, null,
  154. hInstance, null);
  155. width -= GetSystemMetrics(SM_CXVSCROLL);
  156. lvcol.pszText = "cfFormat".toCharz;
  157. lvcol.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
  158. lvcol.cx = 164;
  159. lvcol.iSubItem = 0;
  160. ListView_InsertColumn(hwndList, 0, &lvcol);
  161. width -= lvcol.cx;
  162. lvcol.pszText = "ptd".toCharz;
  163. lvcol.cx = 54;
  164. ListView_InsertColumn(hwndList, 1, &lvcol);
  165. width -= lvcol.cx;
  166. lvcol.pszText = "dwAspect".toCharz;
  167. lvcol.cx = 90;
  168. ListView_InsertColumn(hwndList, 2, &lvcol);
  169. width -= lvcol.cx;
  170. lvcol.pszText = "lindex".toCharz;
  171. lvcol.cx = 68;
  172. ListView_InsertColumn(hwndList, 3, &lvcol);
  173. width -= lvcol.cx;
  174. lvcol.pszText = "tymed".toCharz;
  175. lvcol.cx = max(120, width + 1);
  176. ListView_InsertColumn(hwndList, 4, &lvcol);
  177. width -= lvcol.cx;
  178. return hwndList;
  179. }
  180. extern (Windows) LRESULT WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  181. {
  182. HICON hIcon;
  183. switch (msg)
  184. {
  185. case WM_CREATE:
  186. hwndList = CreateListView(hwnd);
  187. // set small icon for window
  188. hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));
  189. SendMessage(hwnd, WM_SETICON, ICON_BIG, cast(LPARAM)hIcon);
  190. RegisterDropWindow(hwnd);
  191. return TRUE;
  192. case WM_ERASEBKGND:
  193. // stop background flicker!
  194. return 1;
  195. case WM_COMMAND:
  196. switch (LOWORD(wParam))
  197. {
  198. case IDM_FILE_EXIT:
  199. CloseWindow(hwnd);
  200. return 0;
  201. case IDM_FILE_ABOUT:
  202. MessageBox(hwnd, "IDataObject Viewer\r\n\r\n"
  203. "Copyright(c) 2003 by Catch22 Productions\t\r\n"
  204. "Written by J Brown.\r\n\r\n"
  205. "Homepage at www.catch22.net", APPNAME, MB_ICONINFORMATION);
  206. return 0;
  207. case IDM_FILE_CLIP:
  208. enumClipboardData(hwnd);
  209. return 0;
  210. default:
  211. }
  212. break;
  213. case WM_CLOSE:
  214. // shut program down
  215. UnregisterDropWindow(hwnd);
  216. DestroyWindow(hwnd);
  217. PostQuitMessage(0);
  218. return 0;
  219. case WM_SIZE:
  220. // resize listbox to fit in main window
  221. MoveWindow(hwndList, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
  222. return 0;
  223. default:
  224. }
  225. return DefWindowProc(hwnd, msg, wParam, lParam);
  226. }
  227. extern (Windows)
  228. int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow)
  229. {
  230. int result;
  231. try
  232. {
  233. Runtime.initialize();
  234. result = myWinMain(hInstance, hPrevInstance, lpCmdLine, iCmdShow);
  235. Runtime.terminate();
  236. }
  237. catch (Throwable o)
  238. {
  239. MessageBox(null, o.toString().toStringz, "Error", MB_OK | MB_ICONEXCLAMATION);
  240. result = 0;
  241. }
  242. return result;
  243. }
  244. int myWinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmdLine, int nShowCmd)
  245. {
  246. enforce(OleInitialize(null) == S_OK);
  247. scope (exit) OleUninitialize();
  248. MSG msg;
  249. hInstance = hInst;
  250. InitCommonControls();
  251. InitMainWnd();
  252. CreateMainWnd();
  253. while (GetMessage(&msg, null, 0, 0))
  254. {
  255. TranslateMessage(&msg);
  256. DispatchMessage(&msg);
  257. }
  258. return 0;
  259. }
  260. void InitMainWnd()
  261. {
  262. WNDCLASSEX wc;
  263. wc.lpfnWndProc = &WndProc;
  264. wc.lpszClassName = APPNAME;
  265. wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
  266. wc.hInstance = hInstance;
  267. RegisterClassEx(&wc);
  268. }
  269. void CreateMainWnd()
  270. {
  271. hwndMain = CreateWindowEx(0, APPNAME, APPNAME,
  272. WS_VISIBLE | WS_OVERLAPPEDWINDOW,
  273. CW_USEDEFAULT, CW_USEDEFAULT, 512, 200, null, null,
  274. hInstance, null);
  275. }
  276. class CDropTarget : ComObject, IDropTarget
  277. {
  278. this(HWND hwnd)
  279. {
  280. _hwnd = hwnd;
  281. }
  282. extern(Windows)
  283. override HRESULT QueryInterface (IID* riid, void ** ppv)
  284. {
  285. if (*riid == IID_IDropTarget)
  286. {
  287. AddRef();
  288. *ppv = cast(void*)cast(IUnknown)this;
  289. return S_OK;
  290. }
  291. return super.QueryInterface(riid, ppv);
  292. }
  293. extern(Windows)
  294. DWORD DropEffect(DWORD dwAllowed)
  295. {
  296. DWORD dwEffect = dwAllowed & DROPEFFECT.DROPEFFECT_COPY;
  297. if (dwEffect == 0)
  298. dwEffect = dwAllowed;
  299. return dwEffect;
  300. }
  301. extern(Windows)
  302. HRESULT DragEnter(IDataObject dataObject, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect)
  303. {
  304. *pdwEffect = DropEffect(*pdwEffect);
  305. return S_OK;
  306. }
  307. extern(Windows)
  308. HRESULT DragOver(DWORD grfKeyState, POINTL pt, DWORD * pdwEffect)
  309. {
  310. *pdwEffect = DropEffect(*pdwEffect);
  311. return S_OK;
  312. }
  313. extern(Windows)
  314. HRESULT DragLeave()
  315. {
  316. return S_OK;
  317. }
  318. extern(Windows)
  319. HRESULT Drop(IDataObject dataObject, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect)
  320. {
  321. enumData(_hwnd, dataObject);
  322. *pdwEffect = DROPEFFECT.DROPEFFECT_NONE;
  323. return S_OK;
  324. }
  325. private:
  326. HWND _hwnd;
  327. }
  328. void RegisterDropWindow(HWND hwnd)
  329. {
  330. CDropTarget pDropTarget = newCom!CDropTarget(hwnd);
  331. auto res = RegisterDragDrop(hwnd, pDropTarget);
  332. enforce(res == S_OK || res == DRAGDROP_E_ALREADYREGISTERED,
  333. format("Could not register handle '%s'. Error code: %s", hwnd, res));
  334. }
  335. void UnregisterDropWindow(HWND hwnd)
  336. {
  337. RevokeDragDrop(hwnd);
  338. }
  339. /** Enumerate all data in the data object and fill it in the list view. */
  340. void enumData(HWND hwnd, IDataObject dataObject)
  341. {
  342. FORMATETC fmtetc;
  343. HWND hwndList;
  344. ULONG num;
  345. hwndList = GetWindow(hwnd, GW_CHILD);
  346. ListView_DeleteAllItems(hwndList);
  347. // Get the COM interface for format enumeration
  348. IEnumFORMATETC enumFormats;
  349. enforce(dataObject.EnumFormatEtc(DATADIR.DATADIR_GET, &enumFormats) == S_OK);
  350. // Enumerate each type of data supported by this IDataObject, one-by-one
  351. while (enumFormats.Next(1, &fmtetc, &num) == S_OK)
  352. {
  353. AddFormatListView(hwndList, &fmtetc);
  354. }
  355. enumFormats.Release();
  356. }
  357. /** Get the data object of the clipboard and enumerate its data. */
  358. void enumClipboardData(HWND hwnd)
  359. {
  360. IDataObject dataObject = getClipboardDataObject();
  361. enumData(hwnd, dataObject);
  362. dataObject.Release();
  363. }
  364. IDataObject getClipboardDataObject()
  365. {
  366. IDataObject dataObject;
  367. enforce(OleGetClipboard(&dataObject) == S_OK);
  368. return dataObject;
  369. }