Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1258 lines
44 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 2000.
  5. //
  6. // File: ConfirmationUI.cpp
  7. //
  8. // Contents: Confirmation UI for storage based copy engine
  9. //
  10. // History: 20-Mar-2000 ToddB
  11. //
  12. //--------------------------------------------------------------------------
  13. #include "shellprv.h"
  14. #pragma hdrstop
  15. #include "ConfirmationUI.h"
  16. #include "resource.h"
  17. #include "ntquery.h"
  18. #include "ids.h"
  19. #include <initguid.h>
  20. #define TF_DLGDISPLAY 0x00010000 // messages related to display of the confirmation dialog
  21. #define TF_DLGSTORAGE 0x00020000 // messages related to using the legacy IStorage to get dialog info
  22. #define TF_DLGISF 0x00040000 // messages related to using IShellFolder to get dialog info
  23. #define RECT_WIDTH(rc) ((rc).right - (rc).left)
  24. #define RECT_HEIGHT(rc) ((rc).bottom - (rc).top)
  25. GUID guidStorage = PSGUID_STORAGE;
  26. // prototype some functions that are local to this file:
  27. void ShiftDialogItem(HWND hDlg, int id, int cx, int cy);
  28. BOOL CALLBACK ShiftLeftProc(HWND hwnd, LPARAM lParam);
  29. STDAPI CTransferConfirmation_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
  30. {
  31. if (!ppv)
  32. return E_POINTER;
  33. CComObject<CTransferConfirmation> *pObj = NULL;
  34. // created with ref count of 0
  35. if (SUCCEEDED(CComObject<CTransferConfirmation>::CreateInstance(&pObj)))
  36. {
  37. // QueryInterface ups the refcount to 1
  38. if (SUCCEEDED(pObj->QueryInterface(riid, ppv)))
  39. {
  40. return S_OK;
  41. }
  42. // failed to get the right interface, delete the object.
  43. delete pObj;
  44. }
  45. *ppv = NULL;
  46. return E_FAIL;
  47. }
  48. CTransferConfirmation::CTransferConfirmation() :
  49. m_fSingle(TRUE)
  50. {
  51. ASSERT(NULL == m_pszDescription);
  52. ASSERT(NULL == m_pszTitle);
  53. ASSERT(NULL == m_hIcon);
  54. ASSERT(NULL == m_pPropUI);
  55. ASSERT(NULL == m_cItems);
  56. }
  57. CTransferConfirmation::~CTransferConfirmation()
  58. {
  59. if (m_pPropUI)
  60. m_pPropUI->Release();
  61. }
  62. BOOL CTransferConfirmation::_IsCopyOperation(STGOP stgop)
  63. {
  64. return (stgop == STGOP_COPY) || (stgop == STGOP_COPY_PREFERHARDLINK);
  65. }
  66. // TODO: Get better icons for "Nuke File" and "Nuke Folder" from design.
  67. // TODO: Get better icons for "Move File" and "Move Folder" from design.
  68. // TODO: Get better icons for "Secondary Attribute loss" from design (stream loss, encrypt loss, ACL loss, etc)
  69. HRESULT CTransferConfirmation::_GetDialogSettings()
  70. {
  71. _FreeDialogSettings();
  72. ASSERT(NULL == m_pszDescription);
  73. ASSERT(NULL == m_pszTitle);
  74. ASSERT(NULL == m_hIcon);
  75. ASSERT(NULL == m_cItems);
  76. m_fSingle = (m_cop.cRemaining<=1);
  77. // Set the default values of m_crResult so that if the dialog is killed or
  78. // some error occurs we give a valid default response.
  79. m_crResult = CONFRES_CANCEL;
  80. if (m_cop.pcc)
  81. {
  82. // we already have the strings to use
  83. switch (m_cop.pcc->dwButtons)
  84. {
  85. case CCB_YES_SKIP_CANCEL:
  86. m_idDialog = IDD_CONFIRM_YESSKIPCANCEL;
  87. break;
  88. case CCB_RENAME_SKIP_CANCEL:
  89. m_idDialog = IDD_CONFIRM_RENAMESKIPCANCEL;
  90. break;
  91. case CCB_YES_SKIP_RENAME_CANCEL:
  92. m_idDialog = IDD_CONFIRM_YESSKIPRENAMECANCEL;
  93. break;
  94. case CCB_RETRY_SKIP_CANCEL:
  95. m_idDialog = IDD_CONFIRM_RETRYSKIPCANCEL;
  96. break;
  97. case CCB_OK:
  98. m_idDialog = IDD_CONFIRM_OK;
  99. break;
  100. default:
  101. return E_INVALIDARG; // REVIEW: should we define more specific error codes like STG_E_INVALIDBUTTONOPTIONS?
  102. }
  103. if (m_cop.pcc->dwFlags & CCF_SHOW_SOURCE_INFO)
  104. {
  105. _AddItem(m_cop.psiItem);
  106. }
  107. if (m_cop.pcc->dwFlags & CCF_SHOW_DESTINATION_INFO)
  108. {
  109. _AddItem(m_cop.psiDest);
  110. }
  111. }
  112. else
  113. {
  114. TCHAR szBuf[2048];
  115. int idTitle = 0;
  116. int idIcon = 0;
  117. int idDescription = 0;
  118. ////////////////////////////////////////////////////////////////////////////////
  119. // These are "confirmations", i.e. conditions the user can choose to ignore.
  120. // You can typically answer "Yes", "Skip", or "Cancel"
  121. ////////////////////////////////////////////////////////////////////////////////
  122. if (IsEqualIID(m_cop.stc, STCONFIRM_DELETE_STREAM))
  123. {
  124. idTitle = IDS_CONFIRM_FILE_DELETE;
  125. idIcon = IDI_DELETE_FILE;
  126. idDescription = IDS_DELETE_FILE;
  127. m_idDialog = IDD_CONFIRM_YESSKIPCANCEL;
  128. _AddItem(m_cop.psiItem);
  129. }
  130. else if (IsEqualIID(m_cop.stc, STCONFIRM_DELETE_STORAGE))
  131. {
  132. idTitle = IDS_CONFIRM_FOLDER_DELETE;
  133. idIcon = IDI_DELETE_FOLDER;
  134. idDescription = IDS_DELETE_FOLDER;
  135. m_idDialog = IDD_CONFIRM_YESSKIPCANCEL;
  136. _AddItem(m_cop.psiItem);
  137. }
  138. else if (IsEqualIID(m_cop.stc, STCONFIRM_DELETE_READONLY_STREAM))
  139. {
  140. idTitle = IDS_CONFIRM_FILE_DELETE;
  141. idIcon = IDI_DELETE_FILE;
  142. idDescription = IDS_DELETE_READONLY_FILE;
  143. m_idDialog = IDD_CONFIRM_YESSKIPCANCEL;
  144. _AddItem(m_cop.psiItem);
  145. }
  146. else if (IsEqualIID(m_cop.stc, STCONFIRM_DELETE_READONLY_STORAGE))
  147. {
  148. idTitle = IDS_CONFIRM_FOLDER_DELETE;
  149. idIcon = IDI_DELETE_FOLDER;
  150. idDescription = IDS_DELETE_READONLY_FOLDER;
  151. m_idDialog = IDD_CONFIRM_YESSKIPCANCEL;
  152. _AddItem(m_cop.psiItem);
  153. }
  154. else if (IsEqualIID(m_cop.stc, STCONFIRM_DELETE_SYSTEM_STREAM))
  155. {
  156. idTitle = IDS_CONFIRM_FILE_DELETE;
  157. idIcon = IDI_DELETE_FILE;
  158. idDescription = IDS_DELETE_SYSTEM_FILE;
  159. m_idDialog = IDD_CONFIRM_YESSKIPCANCEL;
  160. _AddItem(m_cop.psiItem);
  161. }
  162. else if (IsEqualIID(m_cop.stc, STCONFIRM_DELETE_SYSTEM_STORAGE))
  163. {
  164. idTitle = IDS_CONFIRM_FOLDER_DELETE;
  165. idIcon = IDI_DELETE_FOLDER;
  166. idDescription = IDS_DELETE_SYSTEM_FOLDER;
  167. m_idDialog = IDD_CONFIRM_YESSKIPCANCEL;
  168. _AddItem(m_cop.psiItem);
  169. }
  170. else if (IsEqualIID(m_cop.stc, STCONFIRM_DELETE_TOOLARGE_STREAM))
  171. {
  172. idTitle = IDS_CONFIRM_FILE_DELETE;
  173. idIcon = IDI_NUKE_FILE;
  174. idDescription = IDS_DELETE_TOOBIG_FILE;
  175. m_idDialog = IDD_CONFIRM_YESSKIPCANCEL;
  176. _AddItem(m_cop.psiItem);
  177. }
  178. else if (IsEqualIID(m_cop.stc, STCONFIRM_DELETE_TOOLARGE_STORAGE))
  179. {
  180. idTitle = IDS_CONFIRM_FOLDER_DELETE;
  181. idIcon = IDI_NUKE_FOLDER;
  182. idDescription = IDS_DELETE_TOOBIG_FOLDER;
  183. m_idDialog = IDD_CONFIRM_YESSKIPCANCEL;
  184. _AddItem(m_cop.psiItem);
  185. }
  186. else if (IsEqualIID(m_cop.stc, STCONFIRM_DELETE_WONT_RECYCLE_STREAM))
  187. {
  188. idTitle = IDS_CONFIRM_FILE_DELETE;
  189. idIcon = IDI_NUKE_FILE;
  190. idDescription = IDS_NUKE_FILE;
  191. m_idDialog = IDD_CONFIRM_YESSKIPCANCEL;
  192. _AddItem(m_cop.psiItem);
  193. }
  194. else if (IsEqualIID(m_cop.stc, STCONFIRM_DELETE_WONT_RECYCLE_STORAGE))
  195. {
  196. idTitle = IDS_CONFIRM_FOLDER_DELETE;
  197. idIcon = IDI_NUKE_FOLDER;
  198. idDescription = IDS_NUKE_FOLDER;
  199. m_idDialog = IDD_CONFIRM_YESSKIPCANCEL;
  200. _AddItem(m_cop.psiItem);
  201. }
  202. else if (IsEqualIID(m_cop.stc, STCONFIRM_DELETE_PROGRAM_STREAM))
  203. {
  204. idTitle = IDS_CONFIRM_FILE_DELETE;
  205. idIcon = IDI_DELETE_FILE;
  206. idDescription = IDS_DELETE_PROGRAM_FILE;
  207. m_fShowARPLink = TRUE; // TODO)) implement ShowARPLink
  208. m_idDialog = IDD_CONFIRM_YESSKIPCANCEL;
  209. _AddItem(m_cop.psiItem);
  210. }
  211. else if (IsEqualIID(m_cop.stc, STCONFIRM_MOVE_SYSTEM_STREAM))
  212. {
  213. idTitle = IDS_CONFIRM_FILE_MOVE;
  214. idIcon = IDI_MOVE;
  215. idDescription = IDS_MOVE_SYSTEM_FILE;
  216. m_idDialog = IDD_CONFIRM_YESSKIPCANCEL;
  217. _AddItem(m_cop.psiItem);
  218. }
  219. else if (IsEqualIID(m_cop.stc, STCONFIRM_MOVE_SYSTEM_STORAGE))
  220. {
  221. idTitle = IDS_CONFIRM_FOLDER_MOVE;
  222. idIcon = IDI_MOVE;
  223. idDescription = IDS_MOVE_SYSTEM_FOLDER;
  224. m_idDialog = IDD_CONFIRM_YESSKIPCANCEL;
  225. _AddItem(m_cop.psiItem);
  226. }
  227. else if (IsEqualIID(m_cop.stc, STCONFIRM_RENAME_SYSTEM_STREAM))
  228. {
  229. idTitle = IDS_CONFIRM_FILE_RENAME;
  230. idIcon = IDI_RENAME;
  231. idDescription = IDS_RENAME_SYSTEM_FILE; // Two Arg
  232. m_idDialog = IDD_CONFIRM_YESSKIPCANCEL;
  233. _AddItem(m_cop.psiItem);
  234. }
  235. else if (IsEqualIID(m_cop.stc, STCONFIRM_RENAME_SYSTEM_STORAGE))
  236. {
  237. idTitle = IDS_CONFIRM_FOLDER_RENAME;
  238. idIcon = IDI_RENAME;
  239. idDescription = IDS_RENAME_SYSTEM_FOLDER; // Two Arg
  240. m_idDialog = IDD_CONFIRM_YESSKIPCANCEL;
  241. _AddItem(m_cop.psiItem);
  242. }
  243. else if (IsEqualIID(m_cop.stc, STCONFIRM_STREAM_LOSS_STREAM))
  244. {
  245. idTitle = IDS_CONFIRM_STREAM_LOSS;
  246. idIcon = IDI_NUKE;
  247. idDescription = _IsCopyOperation(m_cop.dwOperation) ? IDS_STREAM_LOSS_COPY_FILE : IDS_STREAM_LOSS_MOVE_FILE;
  248. m_idDialog = IDD_CONFIRM_YESSKIPCANCEL;
  249. _AddItem(m_cop.psiItem);
  250. }
  251. else if (IsEqualIID(m_cop.stc, STCONFIRM_STREAM_LOSS_STORAGE))
  252. {
  253. idTitle = IDS_CONFIRM_STREAM_LOSS;
  254. idIcon = IDI_NUKE;
  255. idDescription = _IsCopyOperation(m_cop.dwOperation) ? IDS_STREAM_LOSS_COPY_FOLDER : IDS_STREAM_LOSS_MOVE_FOLDER;
  256. m_idDialog = IDD_CONFIRM_YESSKIPCANCEL;
  257. _AddItem(m_cop.psiItem);
  258. }
  259. else if (IsEqualIID(m_cop.stc, STCONFIRM_METADATA_LOSS_STREAM))
  260. {
  261. idTitle = IDS_CONFIRM_METADATA_LOSS;
  262. idIcon = IDI_NUKE;
  263. idDescription = _IsCopyOperation(m_cop.dwOperation) ? IDS_METADATA_LOSS_COPY_FILE : IDS_METADATA_LOSS_MOVE_FILE;
  264. m_idDialog = IDD_CONFIRM_YESSKIPCANCEL;
  265. _AddItem(m_cop.psiItem);
  266. }
  267. else if (IsEqualIID(m_cop.stc, STCONFIRM_METADATA_LOSS_STORAGE))
  268. {
  269. idTitle = IDS_CONFIRM_METADATA_LOSS;
  270. idIcon = IDI_NUKE;
  271. idDescription = _IsCopyOperation(m_cop.dwOperation) ? IDS_METADATA_LOSS_COPY_FOLDER : IDS_METADATA_LOSS_MOVE_FOLDER;
  272. m_idDialog = IDD_CONFIRM_YESSKIPCANCEL;
  273. _AddItem(m_cop.psiItem);
  274. }
  275. else if (IsEqualIID(m_cop.stc, STCONFIRM_COMPRESSION_LOSS_STREAM))
  276. {
  277. idTitle = IDS_CONFIRM_COMPRESSION_LOSS;
  278. idIcon = IDI_ATTRIBS_FILE;
  279. idDescription = _IsCopyOperation(m_cop.dwOperation) ? IDS_COMPRESSION_LOSS_COPY_FILE : IDS_COMPRESSION_LOSS_MOVE_FILE;
  280. m_idDialog = IDD_CONFIRM_YESSKIPCANCEL;
  281. _AddItem(m_cop.psiItem);
  282. }
  283. else if (IsEqualIID(m_cop.stc, STCONFIRM_COMPRESSION_LOSS_STORAGE))
  284. {
  285. idTitle = IDS_CONFIRM_COMPRESSION_LOSS;
  286. idIcon = IDI_ATTRIBS_FOLDER;
  287. idDescription = _IsCopyOperation(m_cop.dwOperation) ? IDS_COMPRESSION_LOSS_COPY_FOLDER : IDS_COMPRESSION_LOSS_MOVE_FOLDER;
  288. m_idDialog = IDD_CONFIRM_YESSKIPCANCEL;
  289. _AddItem(m_cop.psiItem);
  290. }
  291. else if (IsEqualIID(m_cop.stc, STCONFIRM_SPARSEDATA_LOSS_STREAM))
  292. {
  293. idTitle = IDS_CONFIRM_COMPRESSION_LOSS;
  294. idIcon = IDI_ATTRIBS_FILE;
  295. idDescription = _IsCopyOperation(m_cop.dwOperation) ? IDS_SPARSE_LOSS_COPY_FILE : IDS_SPARSE_LOSS_MOVE_FILE;
  296. m_idDialog = IDD_CONFIRM_YESSKIPCANCEL;
  297. _AddItem(m_cop.psiItem);
  298. }
  299. else if (IsEqualIID(m_cop.stc, STCONFIRM_ENCRYPTION_LOSS_STREAM))
  300. {
  301. idTitle = IDS_CONFIRM_ENCRYPTION_LOSS;
  302. idIcon = IDI_ATTRIBS_FILE;
  303. idDescription = _IsCopyOperation(m_cop.dwOperation) ? IDS_ENCRYPTION_LOSS_COPY_FILE : IDS_ENCRYPTION_LOSS_MOVE_FILE;
  304. m_idDialog = IDD_CONFIRM_YESSKIPCANCEL;
  305. // is it on purpose that we are not adding item here
  306. }
  307. else if (IsEqualIID(m_cop.stc, STCONFIRM_ENCRYPTION_LOSS_STORAGE))
  308. {
  309. idTitle = IDS_CONFIRM_ENCRYPTION_LOSS;
  310. idIcon = IDI_ATTRIBS_FOLDER;
  311. idDescription = _IsCopyOperation(m_cop.dwOperation) ? IDS_ENCRYPTION_LOSS_COPY_FOLDER : IDS_ENCRYPTION_LOSS_MOVE_FOLDER;
  312. m_idDialog = IDD_CONFIRM_YESSKIPCANCEL;
  313. _AddItem(m_cop.psiItem);
  314. }
  315. else if (IsEqualIID(m_cop.stc, STCONFIRM_ACCESSCONTROL_LOSS_STREAM))
  316. {
  317. idTitle = IDS_CONFIRM_ACL_LOSS;
  318. idIcon = IDI_ATTRIBS_FILE;
  319. m_idDialog = IDD_CONFIRM_YESSKIPCANCEL;
  320. _AddItem(m_cop.psiItem);
  321. }
  322. else if (IsEqualIID(m_cop.stc, STCONFIRM_ACCESSCONTROL_LOSS_STORAGE))
  323. {
  324. idTitle = IDS_CONFIRM_ACL_LOSS;
  325. idIcon = IDI_ATTRIBS_FOLDER;
  326. m_idDialog = IDD_CONFIRM_YESSKIPCANCEL;
  327. _AddItem(m_cop.psiItem);
  328. }
  329. else if (IsEqualIID(m_cop.stc, STCONFIRM_LFNTOFAT_STREAM))
  330. {
  331. idTitle = IDS_SELECT_FILE_NAME;
  332. idIcon = IDI_RENAME;
  333. m_idDialog = IDD_CONFIRM_RENAMESKIPCANCEL;
  334. _AddItem(m_cop.psiItem);
  335. }
  336. else if (IsEqualIID(m_cop.stc, STCONFIRM_LFNTOFAT_STORAGE))
  337. {
  338. idTitle = IDS_SELECT_FOLDER_NAME;
  339. idIcon = IDI_RENAME;
  340. m_idDialog = IDD_CONFIRM_RENAMESKIPCANCEL;
  341. _AddItem(m_cop.psiItem);
  342. }
  343. ////////////////////////////////////////////////////////////////////////////////
  344. // These are the "do you want to replace something" cases, they are special in
  345. // that you can answer "Yes", "Skip", "Rename", or "Cancel"
  346. ////////////////////////////////////////////////////////////////////////////////
  347. else if (IsEqualIID(m_cop.stc, STCONFIRM_REPLACE_STREAM))
  348. {
  349. idTitle = IDS_CONFIRM_FILE_REPLACE;
  350. idIcon = IDI_REPLACE_FILE;
  351. idDescription = IDS_REPLACE_FILE;
  352. m_idDialog = IDD_CONFIRM_YESSKIPRENAMECANCEL;
  353. _AddItem(m_cop.psiDest, IDS_REPLACEEXISTING_FILE);
  354. _AddItem(m_cop.psiItem, IDS_WITHTHIS);
  355. }
  356. else if (IsEqualIID(m_cop.stc, STCONFIRM_REPLACE_STORAGE))
  357. {
  358. idTitle = IDS_CONFIRM_FOLDER_REPLACE;
  359. idIcon = IDI_REPLACE_FOLDER;
  360. idDescription = IDS_REPLACE_FOLDER;
  361. m_idDialog = IDD_CONFIRM_YESSKIPRENAMECANCEL;
  362. _AddItem(m_cop.psiDest, IDS_REPLACEEXISTING_FOLDER);
  363. _AddItem(m_cop.psiItem, IDS_INTOTHIS);
  364. }
  365. ////////////////////////////////////////////////////////////////////////////////
  366. // This group is "error messages", you can typically reply with "Skip",
  367. // "Retry", or "Cancel"
  368. ////////////////////////////////////////////////////////////////////////////////
  369. else
  370. {
  371. // See if the guid is one of our phony guids that's really just an HRESULT and a bunch of zeros.
  372. // To do this we treat the guid like an array of 4 DWORDS and check the last 3 DWORDs against 0.
  373. AssertMsg(sizeof(m_cop.stc) == 4*sizeof(DWORD), TEXT("Size of STGTRANSCONFIRMATION is not 128 bytes!"));
  374. DWORD *pdw = (DWORD*)&m_cop.stc;
  375. if (pdw[1] == 0 && pdw[2] == 0 && pdw[3] == 0)
  376. {
  377. HRESULT hrErr = pdw[0];
  378. switch (hrErr)
  379. {
  380. case STG_E_FILENOTFOUND:
  381. case STG_E_PATHNOTFOUND:
  382. case STG_E_ACCESSDENIED:
  383. case STG_E_INUSE:
  384. case STG_E_SHAREVIOLATION:
  385. case STG_E_LOCKVIOLATION:
  386. case STG_E_DOCFILETOOLARGE:
  387. case STG_E_MEDIUMFULL:
  388. case STG_E_INSUFFICIENTMEMORY:
  389. case STG_E_DISKISWRITEPROTECTED:
  390. case STG_E_FILEALREADYEXISTS:
  391. case STG_E_INVALIDNAME:
  392. case STG_E_REVERTED:
  393. case STG_E_DOCFILECORRUPT:
  394. // these are expected errors for which we should have custom friendly strings:
  395. // TODO: Get friendly messages for these errors from UA
  396. idTitle = IDS_DEFAULTTITLE;
  397. idIcon = IDI_DEFAULTICON;
  398. idDescription = IDS_DEFAULTDESC;
  399. m_idDialog = IDD_CONFIRM_RETRYSKIPCANCEL;
  400. break;
  401. // these are errors I don't think we should ever see, so I'm asserting but then falling through to the
  402. // default case anyway. In most cases I simply don't know what these mean.
  403. case E_PENDING:
  404. case STG_E_CANTSAVE:
  405. case STG_E_SHAREREQUIRED:
  406. case STG_E_NOTCURRENT:
  407. case STG_E_WRITEFAULT:
  408. case STG_E_READFAULT:
  409. case STG_E_SEEKERROR:
  410. case STG_E_NOTFILEBASEDSTORAGE:
  411. case STG_E_NOTSIMPLEFORMAT:
  412. case STG_E_INCOMPLETE:
  413. case STG_E_TERMINATED:
  414. case STG_E_BADBASEADDRESS:
  415. case STG_E_EXTANTMARSHALLINGS:
  416. case STG_E_OLDFORMAT:
  417. case STG_E_OLDDLL:
  418. case STG_E_UNKNOWN:
  419. case STG_E_UNIMPLEMENTEDFUNCTION:
  420. case STG_E_INVALIDFLAG:
  421. case STG_E_PROPSETMISMATCHED:
  422. case STG_E_ABNORMALAPIEXIT:
  423. case STG_E_INVALIDHEADER:
  424. case STG_E_INVALIDPARAMETER:
  425. case STG_E_INVALIDFUNCTION:
  426. case STG_E_TOOMANYOPENFILES:
  427. case STG_E_INVALIDHANDLE:
  428. case STG_E_INVALIDPOINTER:
  429. case STG_E_NOMOREFILES:
  430. TraceMsg(TF_ERROR, "We should never be asked to confirm this error (%08x)", hrErr);
  431. // fall through...
  432. default:
  433. // Use FormatMessage to get the default description for this error message. Sure that's totally
  434. // useless to the end user, but its more useful that nothing which is the altnerative.
  435. idTitle = IDS_DEFAULTTITLE;
  436. idIcon = IDI_DEFAULTICON;
  437. if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, hrErr, 0, szBuf, ARRAYSIZE(szBuf), NULL))
  438. {
  439. m_pszDescription = StrDup(szBuf);
  440. }
  441. else
  442. {
  443. idDescription = IDS_DEFAULTDESC;
  444. }
  445. m_idDialog = IDD_CONFIRM_RETRYSKIPCANCEL;
  446. break;
  447. }
  448. }
  449. else
  450. {
  451. // for the default case we show an "unknown error" message and offer
  452. // "skip", "retry", and "cancel". We should never get to this code path.
  453. TraceMsg(TF_ERROR, "An unknown non-custom error is being display in CTransferConfirmation!");
  454. idTitle = IDS_DEFAULTTITLE;
  455. idIcon = IDI_DEFAULTICON;
  456. idDescription = IDS_DEFAULTDESC;
  457. m_idDialog = IDD_CONFIRM_RETRYSKIPCANCEL;
  458. }
  459. }
  460. if (idTitle && LoadString(_Module.GetResourceInstance(), idTitle, szBuf, ARRAYSIZE(szBuf)))
  461. {
  462. m_pszTitle = StrDup(szBuf);
  463. }
  464. if (idIcon)
  465. {
  466. m_hIcon = (HICON)LoadImage(_Module.GetResourceInstance(), MAKEINTRESOURCE(idIcon), IMAGE_ICON, 0,0, LR_DEFAULTSIZE);
  467. }
  468. if (idDescription && LoadString(_Module.GetResourceInstance(), idDescription, szBuf, ARRAYSIZE(szBuf)))
  469. {
  470. m_pszDescription = StrDup(szBuf);
  471. }
  472. }
  473. if (m_fSingle)
  474. {
  475. // we don't show the "skip" button if only a single item is being moved.
  476. switch(m_idDialog)
  477. {
  478. case IDD_CONFIRM_RETRYSKIPCANCEL:
  479. m_idDialog = IDD_CONFIRM_RETRYCANCEL;
  480. break;
  481. case IDD_CONFIRM_YESSKIPCANCEL:
  482. m_idDialog = IDD_CONFIRM_YESCANCEL;
  483. break;
  484. case IDD_CONFIRM_RENAMESKIPCANCEL:
  485. m_idDialog = IDD_CONFIRM_RENAMECANCEL;
  486. break;
  487. case IDD_CONFIRM_YESSKIPRENAMECANCEL:
  488. m_idDialog = IDD_CONFIRM_YESRENAMECANCEL;
  489. break;
  490. default:
  491. break; // unknown dialog
  492. }
  493. }
  494. // rename - not really implemented yet
  495. switch(m_idDialog)
  496. {
  497. case IDD_CONFIRM_RENAMESKIPCANCEL:
  498. m_idDialog = IDD_CONFIRM_SKIPCANCEL;
  499. break;
  500. case IDD_CONFIRM_RENAMECANCEL:
  501. m_idDialog = IDD_CONFIRM_CANCEL;
  502. break;
  503. case IDD_CONFIRM_YESSKIPRENAMECANCEL:
  504. m_idDialog = IDD_CONFIRM_YESSKIPCANCEL;
  505. break;
  506. case IDD_CONFIRM_YESRENAMECANCEL:
  507. m_idDialog = IDD_CONFIRM_YESCANCEL;
  508. break;
  509. default:
  510. break; // Non-rename dialog
  511. }
  512. return S_OK;
  513. }
  514. // free everything loaded or allocated in _GetDialogSetttings.
  515. HRESULT CTransferConfirmation::_FreeDialogSettings()
  516. {
  517. if (m_pszTitle)
  518. {
  519. LocalFree(m_pszTitle);
  520. m_pszTitle = NULL;
  521. }
  522. if (m_hIcon)
  523. {
  524. DestroyIcon(m_hIcon);
  525. m_hIcon = NULL;
  526. }
  527. if (m_pszDescription)
  528. {
  529. LocalFree(m_pszDescription);
  530. m_pszDescription = NULL;
  531. }
  532. // This array is zeroed before usage, anything that's no longer zero needs to
  533. // be freed in the appropriate mannor.
  534. for (int i=0; i<ARRAYSIZE(m_rgItemInfo); i++)
  535. {
  536. if (m_rgItemInfo[i].pwszIntro)
  537. {
  538. delete [] m_rgItemInfo[i].pwszIntro;
  539. m_rgItemInfo[i].pwszIntro = NULL;
  540. }
  541. if (m_rgItemInfo[i].pwszDisplayName)
  542. {
  543. CoTaskMemFree(m_rgItemInfo[i].pwszDisplayName);
  544. m_rgItemInfo[i].pwszDisplayName = NULL;
  545. }
  546. if (m_rgItemInfo[i].pwszAttribs)
  547. {
  548. SHFree(m_rgItemInfo[i].pwszAttribs);
  549. m_rgItemInfo[i].pwszAttribs = NULL;
  550. }
  551. if (m_rgItemInfo[i].hBitmap)
  552. {
  553. DeleteObject(m_rgItemInfo[i].hBitmap);
  554. m_rgItemInfo[i].hBitmap = NULL;
  555. }
  556. if (m_rgItemInfo[i].hIcon)
  557. {
  558. DestroyIcon(m_rgItemInfo[i].hIcon);
  559. m_rgItemInfo[i].hIcon = NULL;
  560. }
  561. }
  562. m_cItems = 0;
  563. return S_OK;
  564. }
  565. HRESULT CTransferConfirmation::_ClearSettings()
  566. {
  567. m_idDialog = IDD_CONFIRM_RETRYSKIPCANCEL;
  568. m_fShowARPLink = 0;
  569. m_fApplyToAll = 0;
  570. m_cItems = 0;
  571. m_hfont = 0;
  572. ZeroMemory(m_rgItemInfo, sizeof(m_rgItemInfo));
  573. return S_OK;
  574. }
  575. HRESULT CTransferConfirmation::_Init()
  576. {
  577. HRESULT hr = S_OK;
  578. ASSERT(m_pszTitle == NULL);
  579. ASSERT(m_hIcon == NULL);
  580. ASSERT(m_pszDescription == NULL);
  581. _ClearSettings();
  582. if (!m_pPropUI)
  583. {
  584. hr = CoCreateInstance(CLSID_PropertiesUI, NULL, CLSCTX_INPROC_SERVER,
  585. IID_PPV_ARG(IPropertyUI, &m_pPropUI));
  586. }
  587. return hr;
  588. }
  589. STDMETHODIMP CTransferConfirmation::Confirm(CONFIRMOP *pcop, LPCONFIRMATIONRESPONSE pcr, BOOL *pbAll)
  590. {
  591. HRESULT hr = E_INVALIDARG;
  592. if (pcop && pcr)
  593. {
  594. hr = _Init();
  595. if (SUCCEEDED(hr))
  596. {
  597. m_cop = *pcop;
  598. hr = _GetDialogSettings();
  599. if (SUCCEEDED(hr))
  600. {
  601. HWND hwnd;
  602. IUnknown_GetWindow(pcop->punkSite, &hwnd);
  603. int res = (int)DialogBoxParam(_Module.GetResourceInstance(), MAKEINTRESOURCE(m_idDialog), hwnd, s_ConfirmDialogProc, (LPARAM)this);
  604. if (pbAll)
  605. *pbAll = m_fApplyToAll;
  606. *pcr = m_crResult;
  607. }
  608. _FreeDialogSettings();
  609. }
  610. }
  611. return hr;
  612. }
  613. INT_PTR CALLBACK CTransferConfirmation::s_ConfirmDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  614. {
  615. CTransferConfirmation *pThis;
  616. if (WM_INITDIALOG == uMsg)
  617. {
  618. SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
  619. pThis = (CTransferConfirmation *)lParam;
  620. }
  621. else
  622. {
  623. pThis = (CTransferConfirmation *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
  624. }
  625. if (!pThis)
  626. return 0;
  627. return pThis->ConfirmDialogProc(hwndDlg, uMsg, wParam, lParam);
  628. }
  629. BOOL CTransferConfirmation::ConfirmDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  630. {
  631. switch (uMsg)
  632. {
  633. case WM_INITDIALOG:
  634. return OnInitDialog(hwndDlg, wParam, lParam);
  635. case WM_COMMAND:
  636. return OnCommand(hwndDlg, LOWORD(wParam), (HWND)lParam);
  637. // TODO: In WM_DESTROY I need to free the icon in IDD_ICON
  638. }
  639. return 0;
  640. }
  641. BOOL CTransferConfirmation::OnInitDialog(HWND hwndDlg, WPARAM wParam, LPARAM lParam)
  642. {
  643. TCHAR szBuf[1024];
  644. _CalculateMetrics(hwndDlg);
  645. int cxShift = 0;
  646. int cyShift = 0;
  647. int i;
  648. GetWindowRect(hwndDlg, &m_rcDlg);
  649. // We have one or more items that are part of this confirmation, we must get more
  650. // information about these items. For example, we want to use full path names instead
  651. // of just the file name, we need to know file size, modifided data, and if possible
  652. // the two "most important" attributes of the file.
  653. // set the title
  654. if (m_cop.pcc)
  655. {
  656. SetWindowTextW(hwndDlg, m_cop.pcc->pwszTitle);
  657. }
  658. else if (m_pszTitle)
  659. {
  660. SetWindowText(hwndDlg, m_pszTitle);
  661. }
  662. // set the icon
  663. HICON hicon = NULL;
  664. if (m_cop.pcc)
  665. {
  666. hicon = m_cop.pcc->hicon;
  667. }
  668. else
  669. {
  670. hicon = m_hIcon;
  671. }
  672. if (hicon)
  673. {
  674. SendDlgItemMessage(hwndDlg, IDD_ICON, STM_SETICON, (LPARAM)hicon, 0);
  675. }
  676. else
  677. {
  678. HWND hwnd = GetDlgItem(hwndDlg, IDD_ICON);
  679. RECT rc;
  680. GetClientRect(hwnd, &rc);
  681. ShowWindow(hwnd, SW_HIDE);
  682. cxShift -= rc.right + m_cxControlPadding;
  683. }
  684. // Set the description text. We need to remember the size and position of this window
  685. // so that we can position other controls under this text
  686. HWND hwndDesc = GetDlgItem(hwndDlg, ID_CONDITION_TEXT);
  687. RECT rcDesc;
  688. GetClientRect(hwndDesc, &rcDesc);
  689. USES_CONVERSION;
  690. szBuf[0] = NULL;
  691. if (m_cop.pcc)
  692. {
  693. StrCpyN(szBuf, m_cop.pcc->pwszDescription, ARRAYSIZE(szBuf));
  694. }
  695. else if (m_pszDescription)
  696. {
  697. DWORD_PTR rg[2];
  698. rg[0] = (DWORD_PTR)m_rgItemInfo[0].pwszDisplayName;
  699. rg[1] = (DWORD_PTR)m_rgItemInfo[1].pwszDisplayName;
  700. FormatMessage(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
  701. m_pszDescription, 0, 0, szBuf, ARRAYSIZE(szBuf),
  702. (va_list*)rg);
  703. }
  704. if (szBuf[0])
  705. {
  706. int cyWndHeight = _WindowHeightFromString(hwndDesc, RECT_WIDTH(rcDesc), szBuf);
  707. cyShift += (cyWndHeight - rcDesc.bottom);
  708. SetWindowPos(hwndDesc, NULL, 0,0, RECT_WIDTH(rcDesc), cyWndHeight, SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
  709. SetWindowText(hwndDesc, szBuf);
  710. }
  711. // We need to convert from the client coordinates of hwndDesc to the client coordinates of hwndDlg.
  712. // We do this converstion after adjusting the size of hwndDesc to fit the description text.
  713. MapWindowPoints(hwndDesc, hwndDlg, (LPPOINT)&rcDesc, 2);
  714. // Create the folder item(s). The first one starts at cyShift+2*cyControlPadding
  715. // The begining insertion point is one spaceing below the description text
  716. rcDesc.bottom += cyShift + m_cyControlPadding;
  717. AssertMsg(m_cItems<=2, TEXT("Illegal m_cItems value (%d) should never be larger than 2."), m_cItems);
  718. for (i=0; i<m_cItems; i++)
  719. {
  720. int cyHeightOtItem = _DisplayItem(i, hwndDlg, rcDesc.left, rcDesc.bottom);
  721. cyShift += cyHeightOtItem;
  722. rcDesc.bottom += cyHeightOtItem;
  723. TraceMsg(TF_DLGDISPLAY, "_DisplayItem returned a height of: %d", cyHeightOtItem);
  724. }
  725. if (m_cop.pcc && m_cop.pcc->pwszAdvancedDetails)
  726. {
  727. // TODO: if there is "advanced text" create a read-only edit control and put the text in it.
  728. }
  729. if (m_fSingle)
  730. {
  731. HWND hwnd = GetDlgItem(hwndDlg, IDD_REPEAT);
  732. if (hwnd)
  733. {
  734. RECT rc;
  735. GetClientRect(hwnd, &rc);
  736. ShowWindow(hwnd, SW_HIDE);
  737. m_rcDlg.bottom -= rc.bottom + m_cyControlPadding;
  738. }
  739. }
  740. if (cxShift)
  741. {
  742. // shift all child windows by cxShift pixels
  743. EnumChildWindows(hwndDlg, ShiftLeftProc, cxShift);
  744. // don't ask! SetWindowPos in ShiftLeftProc, for some reason, does not do anything on mirrored builds
  745. if (!(GetWindowLong(hwndDlg, GWL_EXSTYLE) & WS_EX_LAYOUTRTL))
  746. m_rcDlg.right += cxShift;
  747. }
  748. if (cyShift)
  749. {
  750. ShiftDialogItem(hwndDlg, IDCANCEL, 0, cyShift);
  751. ShiftDialogItem(hwndDlg, IDYES, 0, cyShift);
  752. ShiftDialogItem(hwndDlg, IDNO, 0, cyShift);
  753. ShiftDialogItem(hwndDlg, IDRETRY, 0, cyShift);
  754. ShiftDialogItem(hwndDlg, IDOK, 0, cyShift);
  755. if (!m_fSingle)
  756. ShiftDialogItem(hwndDlg, IDD_REPEAT, 0, cyShift);
  757. m_rcDlg.bottom += cyShift;
  758. }
  759. // now adjust the dialog size to account for all the things we've added and position it properly
  760. int x = 0;
  761. int y = 0;
  762. UINT uFlags = SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOMOVE;
  763. HMONITOR hMonitor = MonitorFromWindow(GetParent(hwndDlg), MONITOR_DEFAULTTONEAREST);
  764. if (hMonitor)
  765. {
  766. MONITORINFO mi;
  767. mi.cbSize = sizeof(mi);
  768. if (GetMonitorInfo(hMonitor, &mi))
  769. {
  770. RECT rcMonitor = mi.rcMonitor;
  771. x = max((RECT_WIDTH(rcMonitor)-RECT_WIDTH(m_rcDlg))/2, 0);
  772. y = max((RECT_HEIGHT(rcMonitor)-RECT_HEIGHT(m_rcDlg))/2, 0);
  773. uFlags &= ~SWP_NOMOVE;
  774. }
  775. }
  776. TraceMsg(TF_DLGDISPLAY, "Setting dialog size to %dx%d", RECT_WIDTH(m_rcDlg), RECT_HEIGHT(m_rcDlg));
  777. SetWindowPos(hwndDlg, NULL, x, y, RECT_WIDTH(m_rcDlg), RECT_HEIGHT(m_rcDlg), uFlags);
  778. return 1;
  779. }
  780. BOOL CTransferConfirmation::OnCommand(HWND hwndDlg, int wID, HWND hwndCtl)
  781. {
  782. BOOL fFinish = TRUE;
  783. switch (wID)
  784. {
  785. case IDD_REPEAT:
  786. fFinish = FALSE;
  787. break;
  788. case IDRETRY: // "Retry"
  789. m_crResult = CONFRES_RETRY;
  790. break;
  791. case IDOK:
  792. case IDYES: // "Yes"
  793. m_crResult = CONFRES_CONTINUE;
  794. break;
  795. case IDNO: // "Skip"
  796. m_crResult = CONFRES_SKIP;
  797. break;
  798. case IDCANCEL: // "Cancel"
  799. m_crResult = CONFRES_CANCEL;
  800. break;
  801. default:
  802. // if we get to here, then the command ID was not one of our buttons, and since the
  803. // only command IDs we have our the buttons this should not happen.
  804. AssertMsg(0, TEXT("Invalid command recieved in CTransferConfirmation::OnCommand."));
  805. fFinish = FALSE;
  806. break;
  807. }
  808. if (fFinish)
  809. {
  810. // ignore apply to all for retry case or we can have infinite loop
  811. m_fApplyToAll = (m_crResult != CONFRES_RETRY && BST_CHECKED == SendDlgItemMessage(hwndDlg, IDD_REPEAT, BM_GETCHECK, 0, 0));
  812. EndDialog(hwndDlg, wID);
  813. return 1;
  814. }
  815. return 0;
  816. }
  817. HRESULT CTransferConfirmation::_AddItem(IShellItem *psi, int idIntro)
  818. {
  819. if (idIntro)
  820. {
  821. TCHAR szBuf[1024];
  822. if (LoadString(_Module.GetResourceInstance(), idIntro, szBuf, ARRAYSIZE(szBuf)))
  823. {
  824. m_rgItemInfo[m_cItems].pwszIntro = StrDup(szBuf);
  825. }
  826. }
  827. HRESULT hr = psi->GetDisplayName(SIGDN_NORMALDISPLAY, &m_rgItemInfo[m_cItems].pwszDisplayName);
  828. if (SUCCEEDED(hr))
  829. {
  830. IQueryInfo *pqi;
  831. hr = psi->BindToHandler(NULL, BHID_SFUIObject, IID_PPV_ARG(IQueryInfo, &pqi));
  832. if (SUCCEEDED(hr))
  833. {
  834. hr = pqi->GetInfoTip(0, &m_rgItemInfo[m_cItems].pwszAttribs);
  835. pqi->Release();
  836. }
  837. IExtractImage *pImg;
  838. hr = psi->BindToHandler(NULL, BHID_SFUIObject, IID_PPV_ARG(IExtractImage, &pImg));
  839. if (SUCCEEDED(hr))
  840. {
  841. WCHAR szImage[MAX_PATH];
  842. SIZE sz = {120, 120};
  843. DWORD dwFlags = 0;
  844. hr = pImg->GetLocation(szImage, ARRAYSIZE(szImage), NULL, &sz, 24, &dwFlags);
  845. if (SUCCEEDED(hr))
  846. {
  847. hr = pImg->Extract(&m_rgItemInfo[m_cItems].hBitmap);
  848. }
  849. pImg->Release();
  850. }
  851. if (FAILED(hr))
  852. {
  853. IExtractIcon *pIcon;
  854. hr = psi->BindToHandler(NULL, BHID_SFUIObject, IID_PPV_ARG(IExtractIcon, &pIcon));
  855. if (SUCCEEDED(hr))
  856. {
  857. TCHAR szIconName[MAX_PATH];
  858. int iIconIndex = 0;
  859. UINT dwFlags = 0;
  860. hr = pIcon->GetIconLocation(0, szIconName, ARRAYSIZE(szIconName), &iIconIndex, &dwFlags);
  861. if (SUCCEEDED(hr))
  862. {
  863. hr = pIcon->Extract(szIconName, iIconIndex, &m_rgItemInfo[m_cItems].hIcon, NULL, GetSystemMetrics(SM_CXICON));
  864. }
  865. pIcon->Release();
  866. }
  867. }
  868. if (FAILED(hr))
  869. {
  870. IQueryAssociations *pAssoc;
  871. hr = CoCreateInstance(CLSID_QueryAssociations, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IQueryAssociations, &pAssoc));
  872. if (SUCCEEDED(hr))
  873. {
  874. WCHAR wszAssocInit[MAX_PATH];
  875. DWORD dwFlags = 0;
  876. SFGAOF flags = SFGAO_STREAM;
  877. if (SUCCEEDED(psi->GetAttributes(flags, &flags)) && (flags & SFGAO_STREAM))
  878. {
  879. dwFlags = ASSOCF_INIT_DEFAULTTOSTAR;
  880. StrCpyNW(wszAssocInit, PathFindExtensionW(m_rgItemInfo[m_cItems].pwszDisplayName), ARRAYSIZE(wszAssocInit));
  881. }
  882. else
  883. {
  884. dwFlags = ASSOCF_INIT_DEFAULTTOFOLDER;
  885. StrCpyNW(wszAssocInit, L"Directory", ARRAYSIZE(wszAssocInit)); // NB: "Directory is a cannonical name and should not be localized
  886. }
  887. hr = pAssoc->Init(dwFlags, wszAssocInit, NULL,NULL);
  888. if (SUCCEEDED(hr))
  889. {
  890. WCHAR wszIconPath[MAX_PATH];
  891. DWORD dwSize = ARRAYSIZE(wszIconPath);
  892. hr = pAssoc->GetString(0, ASSOCSTR_DEFAULTICON, NULL, wszIconPath, &dwSize);
  893. if (SUCCEEDED(hr))
  894. {
  895. int iIndex = 0;
  896. LPWSTR pszArg = StrChrW(wszIconPath, L',');
  897. if (pszArg)
  898. {
  899. *pszArg = NULL;
  900. pszArg++;
  901. iIndex = StrToIntW(pszArg);
  902. }
  903. ExtractIconEx(wszIconPath, iIndex, &m_rgItemInfo[m_cItems].hIcon, NULL, 1);
  904. if (!m_rgItemInfo[m_cItems].hIcon)
  905. {
  906. TraceMsg(TF_WARNING, "LoadImage(%S) failed", wszIconPath);
  907. }
  908. }
  909. else
  910. {
  911. TraceMsg(TF_WARNING, "pAssoc->GetString() failed");
  912. }
  913. }
  914. else
  915. {
  916. TraceMsg(TF_WARNING, "pAssoc->Init(%S) failed", wszAssocInit);
  917. }
  918. pAssoc->Release();
  919. }
  920. }
  921. // if we fail to extract an image then we show the remaining info anyway:
  922. if (FAILED(hr))
  923. hr = S_FALSE;
  924. }
  925. if (SUCCEEDED(hr))
  926. {
  927. m_cItems++;
  928. }
  929. return hr;
  930. }
  931. BOOL CTransferConfirmation::_CalculateMetrics(HWND hwndDlg)
  932. {
  933. // We space the controls 6 dialog units apart, convert that to pixels
  934. // REVIEW: Is it valid to hardcode this, or does the height in dialog units need to be localized?
  935. RECT rc = {CX_DIALOG_PADDING, CY_DIALOG_PADDING, 0, CY_STATIC_TEXT_HEIGHT};
  936. BOOL bRes = MapDialogRect(hwndDlg, &rc);
  937. m_cxControlPadding = rc.left;
  938. m_cyControlPadding = rc.top;
  939. m_cyText = rc.bottom;
  940. m_hfont = (HFONT)SendMessage(hwndDlg, WM_GETFONT, 0,0);
  941. return bRes;
  942. }
  943. DWORD CTransferConfirmation::_DisplayItem(int iItem, HWND hwndDlg, int x, int y)
  944. {
  945. // We are told what X coordinate to place our left edge, we calculate from that how much room
  946. // we have available for our controls.
  947. int cxAvailable = RECT_WIDTH(m_rcDlg) - x - 2 * m_cxControlPadding;
  948. int yOrig = y;
  949. USES_CONVERSION;
  950. HWND hwnd;
  951. TraceMsg(TF_DLGDISPLAY, "_DisplayItem %d at location (%d,%d) in dialog %08x", iItem, x, y, hwndDlg);
  952. if (m_rgItemInfo[iItem].pwszIntro)
  953. {
  954. TraceMsg(TF_DLGDISPLAY, "CreateWindowEx(0, TEXT(\"STATIC\"), %s, WS_CHILD|WS_VISIBLE, %d,%d, %d,%d, %08x, NULL, %08x, 0);",
  955. m_rgItemInfo[iItem].pwszIntro,
  956. x,y,cxAvailable,m_cyText, hwndDlg, _Module.GetModuleInstance());
  957. hwnd = CreateWindowEx(0, TEXT("STATIC"), m_rgItemInfo[iItem].pwszIntro,
  958. WS_CHILD|WS_VISIBLE,
  959. x,y, cxAvailable,m_cyText,
  960. hwndDlg, NULL,
  961. _Module.GetModuleInstance(), 0);
  962. if (hwnd)
  963. {
  964. // we successfully added the title string for the item
  965. SendMessage(hwnd, WM_SETFONT, (WPARAM)m_hfont, 0);
  966. x += m_cxControlPadding;
  967. y += m_cyText+m_cyControlPadding;
  968. }
  969. }
  970. RECT rcImg = {0};
  971. if (m_rgItemInfo[iItem].hBitmap)
  972. {
  973. TraceMsg(TF_DLGDISPLAY, "CreateWindowEx(0, TEXT(\"STATIC\"), %s, WS_CHILD|WS_VISIBLE, %d,%d, %d,%d, %08x, NULL, %08x, 0);",
  974. "_Icon Window_",
  975. x,y,cxAvailable,m_cyText, hwndDlg, _Module.GetModuleInstance());
  976. hwnd = CreateWindowEx(0, TEXT("STATIC"), NULL,
  977. WS_CHILD|WS_VISIBLE|SS_BITMAP,
  978. x,y,
  979. 120,120,
  980. hwndDlg, NULL,
  981. _Module.GetModuleInstance(), 0);
  982. if (hwnd)
  983. {
  984. SendMessage(hwnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)m_rgItemInfo[iItem].hBitmap);
  985. GetClientRect(hwnd, &rcImg);
  986. x += rcImg.right + m_cxControlPadding;
  987. cxAvailable -= rcImg.right + m_cxControlPadding;
  988. rcImg.bottom += y;
  989. }
  990. }
  991. else if (m_rgItemInfo[iItem].hIcon)
  992. {
  993. TraceMsg(TF_DLGDISPLAY, "CreateWindowEx(0, TEXT(\"STATIC\"), %s, WS_CHILD|WS_VISIBLE, %d,%d, %d,%d, %08x, NULL, %08x, 0);",
  994. "_Icon Window_",
  995. x,y,cxAvailable,m_cyText, hwndDlg, _Module.GetModuleInstance());
  996. hwnd = CreateWindowEx(0, TEXT("STATIC"), NULL,
  997. WS_CHILD|WS_VISIBLE|SS_ICON,
  998. x,y,
  999. GetSystemMetrics(SM_CXICON),GetSystemMetrics(SM_CYICON),
  1000. hwndDlg, NULL,
  1001. _Module.GetModuleInstance(), 0);
  1002. if (hwnd)
  1003. {
  1004. SendMessage(hwnd, STM_SETICON, (WPARAM)m_rgItemInfo[iItem].hIcon, NULL);
  1005. GetClientRect(hwnd, &rcImg);
  1006. x += rcImg.right + m_cxControlPadding;
  1007. cxAvailable -= rcImg.right + m_cxControlPadding;
  1008. rcImg.bottom += y;
  1009. }
  1010. }
  1011. else
  1012. {
  1013. TraceMsg(TF_DLGDISPLAY, "Not using an image for item %d.", iItem);
  1014. }
  1015. TraceMsg(TF_DLGDISPLAY, "CreateWindowEx(0, TEXT(\"STATIC\"), %s, WS_CHILD|WS_VISIBLE, %d,%d, %d,%d, %08x, NULL, %08x, 0);",
  1016. m_rgItemInfo[iItem].pwszDisplayName,
  1017. x,y,cxAvailable,m_cyText, hwndDlg, _Module.GetModuleInstance());
  1018. int cyWnd = _WindowHeightFromString(hwndDlg, cxAvailable, m_rgItemInfo[iItem].pwszDisplayName);
  1019. hwnd = CreateWindowEx(0, TEXT("STATIC"), m_rgItemInfo[iItem].pwszDisplayName,
  1020. WS_CHILD|WS_VISIBLE,
  1021. x,y, cxAvailable,cyWnd,
  1022. hwndDlg, NULL,
  1023. _Module.GetModuleInstance(), 0);
  1024. if (hwnd)
  1025. {
  1026. SendMessage(hwnd, WM_SETFONT, (WPARAM)m_hfont, 0);
  1027. y += cyWnd;
  1028. }
  1029. else
  1030. {
  1031. TraceMsg(TF_DLGDISPLAY, "CreateWindowEx for display name failed.");
  1032. }
  1033. TraceMsg(TF_DLGDISPLAY, "CreateWindowEx(0, TEXT(\"STATIC\"), %s, WS_CHILD|WS_VISIBLE, %d,%d, %d,%d, %08x, NULL, %08x, 0);",
  1034. m_rgItemInfo[iItem].pwszAttribs,
  1035. x,y,cxAvailable,m_cyText, hwndDlg, _Module.GetModuleInstance());
  1036. cyWnd = _WindowHeightFromString(hwndDlg, cxAvailable, m_rgItemInfo[iItem].pwszAttribs);
  1037. hwnd = CreateWindowEx(0, TEXT("STATIC"), m_rgItemInfo[iItem].pwszAttribs,
  1038. WS_CHILD|WS_VISIBLE|SS_LEFT,
  1039. x,y, cxAvailable,cyWnd,
  1040. hwndDlg, NULL,
  1041. _Module.GetModuleInstance(), 0);
  1042. if (hwnd)
  1043. {
  1044. SendMessage(hwnd, WM_SETFONT, (WPARAM)m_hfont, 0);
  1045. y += cyWnd;
  1046. }
  1047. else
  1048. {
  1049. TraceMsg(TF_DLGDISPLAY, "CreateWindowEx for attribs failed.");
  1050. }
  1051. if (rcImg.bottom > y)
  1052. y = rcImg.bottom;
  1053. return (y-yOrig) + m_cyControlPadding;
  1054. }
  1055. int CTransferConfirmation::_WindowHeightFromString(HWND hwnd, int cx, LPTSTR psz)
  1056. {
  1057. RECT rc = {0,0, cx,0 };
  1058. HDC hdc = GetDC(hwnd);
  1059. HFONT hfontOld = NULL;
  1060. DWORD dtFlags = DT_CALCRECT|DT_WORDBREAK;
  1061. if (m_hfont)
  1062. {
  1063. // We need to select the font that the dialog will use so that we calculate the correct size
  1064. hfontOld = (HFONT)SelectObject(hdc, m_hfont);
  1065. }
  1066. else
  1067. {
  1068. // a NULL m_hfont means we are using the system font, using DT_INTERNAL should do the
  1069. // calculation based on the system font.
  1070. dtFlags |= DT_INTERNAL;
  1071. }
  1072. DrawText(hdc, psz, -1, &rc, dtFlags);
  1073. if (hfontOld)
  1074. SelectObject(hdc, hfontOld);
  1075. ReleaseDC(hwnd, hdc);
  1076. return rc.bottom;
  1077. }
  1078. void ShiftWindow(HWND hwnd, int cx, int cy)
  1079. {
  1080. RECT rc;
  1081. // rect in screen coordinates
  1082. GetWindowRect(hwnd, &rc);
  1083. // shift it over
  1084. if (GetWindowLong(GetParent(hwnd), GWL_EXSTYLE) & WS_EX_LAYOUTRTL)
  1085. rc.left -= cx;
  1086. else
  1087. rc.left += cx;
  1088. rc.top += cy;
  1089. // convert to parent windows coords
  1090. MapWindowPoints(NULL, GetParent(hwnd), (LPPOINT)&rc, 2);
  1091. // and move the window
  1092. SetWindowPos(hwnd, NULL, rc.left, rc.top, 0,0, SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE);
  1093. }
  1094. void ShiftDialogItem(HWND hDlg, int id, int cx, int cy)
  1095. {
  1096. HWND hwnd;
  1097. hwnd = GetDlgItem(hDlg, id);
  1098. if (NULL != hwnd)
  1099. {
  1100. ShiftWindow(hwnd, cx, cy);
  1101. }
  1102. }
  1103. BOOL CALLBACK ShiftLeftProc(HWND hwnd, LPARAM lParam)
  1104. {
  1105. ShiftWindow(hwnd, (int)(INT_PTR)lParam, 0);
  1106. return TRUE;
  1107. }