Source code of Windows XP (NT5)
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.

1318 lines
46 KiB

  1. /*
  2. * ICON.CPP
  3. *
  4. * Implements the OleUIChangeIcon function which invokes the complete
  5. * Change Icon dialog.
  6. *
  7. * Copyright (c)1992 Microsoft Corporation, All Right Reserved
  8. */
  9. #include "precomp.h"
  10. #include "common.h"
  11. #include "utility.h"
  12. #include "iconbox.h"
  13. OLEDBGDATA
  14. ULONG
  15. MyGetLongPathName(LPCTSTR pcsPath,
  16. LPTSTR pcsLongPath,
  17. ULONG cchLongPath);
  18. #define CXICONPAD (12)
  19. #define CYICONPAD (4)
  20. // Internally used structure
  21. typedef struct tagCHANGEICON
  22. {
  23. LPOLEUICHANGEICON lpOCI; //Original structure passed.
  24. UINT nIDD; // IDD of dialog (used for help info)
  25. /*
  26. * What we store extra in this structure besides the original caller's
  27. * pointer are those fields that we need to modify during the life of
  28. * the dialog but that we don't want to change in the original structure
  29. * until the user presses OK.
  30. */
  31. DWORD dwFlags;
  32. HICON hCurIcon;
  33. TCHAR szLabel[OLEUI_CCHLABELMAX+1];
  34. TCHAR szFile[MAX_PATH];
  35. UINT iIcon;
  36. HICON hDefIcon;
  37. TCHAR szDefIconFile[MAX_PATH];
  38. UINT iDefIcon;
  39. UINT nBrowseHelpID; // Help ID callback for Browse dlg
  40. } CHANGEICON, *PCHANGEICON, FAR *LPCHANGEICON;
  41. // Internal function prototypes
  42. // ICON.CPP
  43. INT_PTR CALLBACK ChangeIconDialogProc(HWND, UINT, WPARAM, LPARAM);
  44. BOOL FChangeIconInit(HWND, WPARAM, LPARAM);
  45. UINT UFillIconList(HWND, UINT, LPTSTR, BOOL);
  46. BOOL FDrawListIcon(LPDRAWITEMSTRUCT);
  47. void UpdateResultIcon(LPCHANGEICON, HWND, UINT);
  48. /*
  49. * OleUIChangeIcon
  50. *
  51. * Purpose:
  52. * Invokes the standard OLE Change Icon dialog box allowing the user
  53. * to select an icon from an icon file, executable, or DLL.
  54. *
  55. * Parameters:
  56. * lpCI LPOLEUIChangeIcon pointing to the in-out structure
  57. * for this dialog.
  58. *
  59. * Return Value:
  60. * UINT OLEUI_SUCCESS or OLEUI_OK if all is well, otherwise
  61. * an error value.
  62. */
  63. STDAPI_(UINT) OleUIChangeIcon(LPOLEUICHANGEICON lpCI)
  64. {
  65. HGLOBAL hMemDlg = NULL;
  66. UINT uRet = UStandardValidation((LPOLEUISTANDARD)lpCI, sizeof(OLEUICHANGEICON),
  67. &hMemDlg);
  68. if (OLEUI_SUCCESS != uRet)
  69. return uRet;
  70. // Check for a valid hMetaPict.
  71. if (NULL == lpCI->hMetaPict && NULL == lpCI->szIconExe && CLSID_NULL == lpCI->clsid)
  72. {
  73. return(OLEUI_CIERR_MUSTHAVECURRENTMETAFILE);
  74. }
  75. if (lpCI->hMetaPict != NULL && !IsValidMetaPict(lpCI->hMetaPict))
  76. {
  77. return(OLEUI_CIERR_MUSTHAVECURRENTMETAFILE);
  78. }
  79. // Test to be sure that the class ID matches a registered class ID
  80. // so we can return OLEUI_CIERR_MUSTHAVECLSID if necessary.
  81. HGLOBAL hTemp = OleGetIconOfClass(lpCI->clsid, NULL, TRUE);
  82. if (hTemp == NULL)
  83. {
  84. return(OLEUI_CIERR_MUSTHAVECLSID);
  85. }
  86. OleUIMetafilePictIconFree(hTemp);
  87. if (lpCI->dwFlags & CIF_USEICONEXE &&
  88. (lpCI->cchIconExe < 1 || lpCI->cchIconExe > MAX_PATH))
  89. {
  90. uRet = OLEUI_CIERR_SZICONEXEINVALID;
  91. }
  92. if (OLEUI_ERR_STANDARDMIN <= uRet)
  93. {
  94. return uRet;
  95. }
  96. // Now that we've validated everything, we can invoke the dialog.
  97. uRet = UStandardInvocation(ChangeIconDialogProc, (LPOLEUISTANDARD)lpCI,
  98. hMemDlg, MAKEINTRESOURCE(IDD_CHANGEICON));
  99. return uRet;
  100. }
  101. /*
  102. * ChangeIconDialogProc
  103. *
  104. * Purpose:
  105. * Implements the OLE Change Icon dialog as invoked through the
  106. * OleUIChangeIcon function.
  107. *
  108. * Parameters:
  109. * Standard
  110. *
  111. * Return Value:
  112. * Standard
  113. */
  114. INT_PTR CALLBACK ChangeIconDialogProc(HWND hDlg, UINT iMsg,
  115. WPARAM wParam, LPARAM lParam)
  116. {
  117. // Declare Win16/Win32 compatible WM_COMMAND parameters.
  118. COMMANDPARAMS(wID, wCode, hWndMsg);
  119. UINT uRet = 0;
  120. LPCHANGEICON lpCI = (LPCHANGEICON)LpvStandardEntry(hDlg, iMsg, wParam, lParam, &uRet);
  121. // If the hook processed the message, we're done.
  122. if (0 != uRet)
  123. return (INT_PTR)uRet;
  124. // Process the temination message
  125. if (iMsg == uMsgEndDialog)
  126. {
  127. EndDialog(hDlg, wParam);
  128. return TRUE;
  129. }
  130. TCHAR szTemp[MAX_PATH];
  131. HICON hIcon;
  132. HGLOBAL hMetaPict;
  133. switch (iMsg)
  134. {
  135. case WM_DESTROY:
  136. if (lpCI)
  137. {
  138. SendDlgItemMessage(hDlg, IDC_CI_ICONLIST, LB_RESETCONTENT, 0, 0L);
  139. StandardCleanup(lpCI, hDlg);
  140. }
  141. break;
  142. case WM_INITDIALOG:
  143. FChangeIconInit(hDlg, wParam, lParam);
  144. return TRUE;
  145. case WM_MEASUREITEM:
  146. {
  147. LPMEASUREITEMSTRUCT lpMI = (LPMEASUREITEMSTRUCT)lParam;
  148. // All icons are system metric+padding in width and height
  149. lpMI->itemWidth = GetSystemMetrics(SM_CXICON)+CXICONPAD;
  150. lpMI->itemHeight= GetSystemMetrics(SM_CYICON)+CYICONPAD;
  151. }
  152. break;
  153. case WM_DRAWITEM:
  154. return FDrawListIcon((LPDRAWITEMSTRUCT)lParam);
  155. case WM_DELETEITEM:
  156. DestroyIcon((HICON)(((LPDELETEITEMSTRUCT)lParam)->itemData));
  157. break;
  158. case WM_COMMAND:
  159. switch (wID)
  160. {
  161. case IDC_CI_CURRENT:
  162. case IDC_CI_DEFAULT:
  163. case IDC_CI_FROMFILE:
  164. if (lpCI != NULL)
  165. UpdateResultIcon(lpCI, hDlg, (UINT)-1);
  166. break;
  167. case IDC_CI_LABELEDIT:
  168. if (lpCI != NULL && EN_KILLFOCUS == wCode)
  169. UpdateResultIcon(lpCI, hDlg, (UINT)-1);
  170. break;
  171. case IDC_CI_FROMFILEEDIT:
  172. GetDlgItemText(hDlg, IDC_CI_FROMFILEEDIT, szTemp, sizeof(szTemp)/sizeof(TCHAR));
  173. if (lpCI != NULL)
  174. {
  175. if (wCode == EN_KILLFOCUS)
  176. {
  177. if (lstrcmpi(szTemp, lpCI->szFile))
  178. {
  179. lstrcpy(lpCI->szFile, szTemp);
  180. UFillIconList(hDlg, IDC_CI_ICONLIST, lpCI->szFile, FALSE);
  181. UpdateResultIcon(lpCI, hDlg, IDC_CI_FROMFILE);
  182. }
  183. }
  184. else if (wCode == EN_SETFOCUS)
  185. {
  186. UpdateResultIcon(lpCI, hDlg, IDC_CI_FROMFILE);
  187. }
  188. }
  189. break;
  190. case IDC_CI_ICONLIST:
  191. switch (wCode)
  192. {
  193. case LBN_SETFOCUS:
  194. // If we got the focus, see about updating.
  195. GetDlgItemText(hDlg, IDC_CI_FROMFILEEDIT, szTemp, sizeof(szTemp)/sizeof(TCHAR));
  196. // Check if file changed and update the list if so
  197. if (lpCI && 0 != lstrcmpi(szTemp, lpCI->szFile))
  198. {
  199. lstrcpy(lpCI->szFile, szTemp);
  200. UFillIconList(hDlg, IDC_CI_ICONLIST, lpCI->szFile, FALSE);
  201. }
  202. UpdateResultIcon(lpCI, hDlg, IDC_CI_FROMFILE);
  203. break;
  204. case LBN_SELCHANGE:
  205. UpdateResultIcon(lpCI, hDlg, IDC_CI_FROMFILE);
  206. break;
  207. case LBN_DBLCLK:
  208. SendCommand(hDlg, IDOK, BN_CLICKED, hWndMsg);
  209. break;
  210. }
  211. break;
  212. case IDC_CI_BROWSE:
  213. {
  214. lstrcpyn(szTemp, lpCI->szFile, sizeof(szTemp)/sizeof(TCHAR));
  215. uRet = UStandardHook(lpCI, hDlg, uMsgBrowse, MAX_PATH_SIZE,
  216. (LPARAM)lpCI->szFile);
  217. DWORD dwOfnFlags = OFN_FILEMUSTEXIST;
  218. if (lpCI->lpOCI->dwFlags & CIF_SHOWHELP)
  219. dwOfnFlags |= OFN_SHOWHELP;
  220. if (0 == uRet)
  221. {
  222. uRet = (BOOL)Browse(hDlg, lpCI->szFile, NULL, MAX_PATH_SIZE,
  223. IDS_ICONFILTERS, dwOfnFlags, ID_BROWSE_CHANGEICON, NULL);
  224. }
  225. if (0 != uRet && 0 != lstrcmpi(szTemp, lpCI->szFile))
  226. {
  227. SetDlgItemText(hDlg, IDC_CI_FROMFILEEDIT, lpCI->szFile);
  228. UFillIconList(hDlg, IDC_CI_ICONLIST, lpCI->szFile, TRUE);
  229. UpdateResultIcon(lpCI, hDlg, IDC_CI_FROMFILE);
  230. }
  231. }
  232. break;
  233. case IDOK:
  234. {
  235. HWND hwndCtl = GetDlgItem(hDlg, IDOK);
  236. if (hwndCtl == GetFocus())
  237. {
  238. GetDlgItemText(hDlg, IDC_CI_FROMFILEEDIT, szTemp, sizeof(szTemp)/sizeof(TCHAR));
  239. // Check if the file name is valid
  240. // if SelectFromFile radio button selected
  241. if (lpCI->dwFlags & CIF_SELECTFROMFILE)
  242. {
  243. // Check if the file changed at all.
  244. if (0 != lstrcmpi(szTemp, lpCI->szFile))
  245. {
  246. lstrcpy(lpCI->szFile, szTemp);
  247. // file changed. May need to expand the name
  248. // calling DoesFileExist will do the trick
  249. DoesFileExist(lpCI->szFile, MAX_PATH);
  250. UFillIconList(hDlg, IDC_CI_ICONLIST, lpCI->szFile, TRUE);
  251. SetDlgItemText(hDlg, IDC_CI_FROMFILEEDIT, lpCI->szFile);
  252. UpdateResultIcon(lpCI, hDlg, IDC_CI_FROMFILE);
  253. return TRUE; // eat this message to prevent focus change.
  254. }
  255. if (!DoesFileExist(lpCI->szFile, MAX_PATH))
  256. {
  257. OpenFileError(hDlg, ERROR_FILE_NOT_FOUND, lpCI->szFile);
  258. HWND hWnd = GetDlgItem(hDlg, IDC_CI_FROMFILEEDIT);
  259. SetFocus(hWnd);
  260. SendMessage(hWnd, EM_SETSEL, 0, -1);
  261. return TRUE; // eat this message
  262. }
  263. }
  264. // Get current metafile image
  265. UpdateResultIcon(lpCI, hDlg, (UINT)-1);
  266. hMetaPict = (HGLOBAL)SendDlgItemMessage(hDlg, IDC_CI_ICONDISPLAY,
  267. IBXM_IMAGEGET, 0, 0);
  268. // Clean up the current icon that we extracted.
  269. hIcon = (HICON)SendDlgItemMessage(hDlg, IDC_CI_CURRENTICON, STM_GETICON, 0, 0L);
  270. DestroyIcon(hIcon);
  271. // Clean up the default icon
  272. DestroyIcon(lpCI->hDefIcon);
  273. // Remove the prop set on our parent
  274. RemoveProp(lpCI->lpOCI->hWndOwner, PROP_HWND_CHGICONDLG);
  275. OleUIMetafilePictIconFree(lpCI->lpOCI->hMetaPict);
  276. lpCI->lpOCI->hMetaPict = hMetaPict;
  277. lpCI->lpOCI->dwFlags = lpCI->dwFlags;
  278. SendMessage(hDlg, uMsgEndDialog, OLEUI_OK, 0L);
  279. }
  280. else
  281. {
  282. SetFocus(hwndCtl);
  283. SendCommand(hDlg, IDOK, BN_CLICKED, hWndMsg);
  284. }
  285. break;
  286. }
  287. case IDCANCEL:
  288. // Free current icon display image
  289. SendDlgItemMessage(hDlg, IDC_CI_ICONDISPLAY, IBXM_IMAGEFREE, 0, 0);
  290. // Clean up the current icon that we extracted.
  291. hIcon = (HICON)SendDlgItemMessage(hDlg, IDC_CI_CURRENTICON, STM_GETICON, 0, 0L);
  292. DestroyIcon(hIcon);
  293. // Clean up the default icon
  294. DestroyIcon(lpCI->hDefIcon);
  295. // Remove the prop set on our parent
  296. RemoveProp(lpCI->lpOCI->hWndOwner, PROP_HWND_CHGICONDLG);
  297. // We leave hMetaPict intact on Cancel; caller's responsibility
  298. SendMessage(hDlg, uMsgEndDialog, OLEUI_CANCEL, 0L);
  299. break;
  300. case IDC_OLEUIHELP:
  301. PostMessage(lpCI->lpOCI->hWndOwner, uMsgHelp,
  302. (WPARAM)hDlg, MAKELPARAM(IDD_CHANGEICON, 0));
  303. break;
  304. }
  305. break;
  306. default:
  307. if (lpCI && iMsg == lpCI->nBrowseHelpID)
  308. {
  309. PostMessage(lpCI->lpOCI->hWndOwner, uMsgHelp,
  310. (WPARAM)hDlg, MAKELPARAM(IDD_CHANGEICONBROWSE, 0));
  311. }
  312. if (iMsg == uMsgBrowseOFN &&
  313. lpCI && lpCI->lpOCI && lpCI->lpOCI->hWndOwner)
  314. {
  315. SendMessage(lpCI->lpOCI->hWndOwner, uMsgBrowseOFN, wParam, lParam);
  316. }
  317. break;
  318. }
  319. return FALSE;
  320. }
  321. /*
  322. * FChangeIconInit
  323. *
  324. * Purpose:
  325. * WM_INITIDIALOG handler for the Change Icon dialog box.
  326. *
  327. * Parameters:
  328. * hDlg HWND of the dialog
  329. * wParam WPARAM of the message
  330. * lParam LPARAM of the message
  331. *
  332. * Return Value:
  333. * BOOL Value to return for WM_INITDIALOG.
  334. */
  335. BOOL FChangeIconInit(HWND hDlg, WPARAM wParam, LPARAM lParam)
  336. {
  337. // Copy the structure at lParam into our instance memory.
  338. LPCHANGEICON lpCI = (LPCHANGEICON)LpvStandardInit(hDlg, sizeof(CHANGEICON));
  339. // LpvStandardInit send a termination to us already.
  340. if (NULL == lpCI)
  341. return FALSE;
  342. // Save the original pointer and copy necessary information.
  343. LPOLEUICHANGEICON lpOCI = (LPOLEUICHANGEICON)lParam;
  344. lpCI->lpOCI = lpOCI;
  345. lpCI->nIDD = IDD_CHANGEICON;
  346. lpCI->dwFlags = lpOCI->dwFlags;
  347. // Go extract the icon source from the metafile.
  348. TCHAR szTemp[MAX_PATH];
  349. szTemp[0] = 0;
  350. OleUIMetafilePictExtractIconSource(lpOCI->hMetaPict, szTemp, &lpCI->iIcon);
  351. MyGetLongPathName(szTemp, lpCI->szFile, MAX_PATH);
  352. // Go extract the icon and the label from the metafile
  353. OleUIMetafilePictExtractLabel(lpOCI->hMetaPict, lpCI->szLabel, OLEUI_CCHLABELMAX_SIZE, NULL);
  354. lpCI->hCurIcon = OleUIMetafilePictExtractIcon(lpOCI->hMetaPict);
  355. // Show or hide the help button
  356. if (!(lpCI->dwFlags & CIF_SHOWHELP))
  357. StandardShowDlgItem(hDlg, IDC_OLEUIHELP, SW_HIDE);
  358. // Set text limits and initial control contents
  359. SendDlgItemMessage(hDlg, IDC_CI_LABELEDIT, EM_LIMITTEXT, OLEUI_CCHLABELMAX, 0L);
  360. SendDlgItemMessage(hDlg, IDC_CI_FROMFILEEDIT, EM_LIMITTEXT, MAX_PATH, 0L);
  361. SetDlgItemText(hDlg, IDC_CI_FROMFILEEDIT, lpCI->szFile);
  362. // Copy the label text into the edit and static controls.
  363. SetDlgItemText(hDlg, IDC_CI_LABELEDIT, lpCI->szLabel);
  364. lpCI->hDefIcon = NULL;
  365. if (lpCI->dwFlags & CIF_USEICONEXE)
  366. {
  367. lpCI->hDefIcon = StandardExtractIcon(_g_hOleStdInst, lpCI->lpOCI->szIconExe, 0);
  368. if (NULL != lpCI->hDefIcon)
  369. {
  370. lstrcpy(lpCI->szDefIconFile, lpCI->lpOCI->szIconExe);
  371. lpCI->iDefIcon = 0;
  372. }
  373. }
  374. if (NULL == lpCI->hDefIcon)
  375. {
  376. HGLOBAL hMetaPict;
  377. hMetaPict = OleGetIconOfClass(lpCI->lpOCI->clsid, NULL, TRUE);
  378. lpCI->hDefIcon = OleUIMetafilePictExtractIcon(hMetaPict);
  379. TCHAR szTemp[MAX_PATH];
  380. OleUIMetafilePictExtractIconSource(hMetaPict,
  381. szTemp, &lpCI->iDefIcon);
  382. MyGetLongPathName(szTemp, lpCI->szDefIconFile, MAX_PATH);
  383. OleUIMetafilePictIconFree(hMetaPict);
  384. }
  385. // Initialize all the icon displays.
  386. SendDlgItemMessage(hDlg, IDC_CI_CURRENTICON, STM_SETICON,
  387. (WPARAM)lpCI->hCurIcon, 0L);
  388. SendDlgItemMessage(hDlg, IDC_CI_DEFAULTICON, STM_SETICON,
  389. (WPARAM)lpCI->hDefIcon, 0L);
  390. /*
  391. * Since we cannot predict the size of icons on any display,
  392. * we have to resize the icon listbox to the size of an icon
  393. * (plus padding), a scrollbar, and two borders (top & bottom).
  394. */
  395. UINT cyList = GetSystemMetrics(SM_CYICON)+GetSystemMetrics(SM_CYHSCROLL)
  396. +GetSystemMetrics(SM_CYBORDER)*2+CYICONPAD;
  397. HWND hList = GetDlgItem(hDlg, IDC_CI_ICONLIST);
  398. RECT rc;
  399. GetClientRect(hList, &rc);
  400. SetWindowPos(hList, NULL, 0, 0, rc.right, cyList, SWP_NOMOVE | SWP_NOZORDER);
  401. // Set the columns in this multi-column listbox to hold one icon
  402. SendMessage(hList, LB_SETCOLUMNWIDTH,
  403. GetSystemMetrics(SM_CXICON)+CXICONPAD,0L);
  404. /*
  405. * If the listbox expanded below the group box, then size
  406. * the groupbox down, move the label static and exit controls
  407. * down, and expand the entire dialog appropriately.
  408. */
  409. GetWindowRect(hList, &rc);
  410. RECT rcG;
  411. GetWindowRect(GetDlgItem(hDlg, IDC_CI_GROUP), &rcG);
  412. if (rc.bottom > rcG.bottom)
  413. {
  414. // Calculate amount to move things down.
  415. cyList=(rcG.bottom-rcG.top)-(rc.bottom-rc.top-cyList);
  416. // Expand the group box.
  417. rcG.right -=rcG.left;
  418. rcG.bottom-=rcG.top;
  419. SetWindowPos(GetDlgItem(hDlg, IDC_CI_GROUP), NULL, 0, 0,
  420. rcG.right, rcG.bottom+cyList, SWP_NOMOVE | SWP_NOZORDER);
  421. // Expand the dialog box.
  422. GetClientRect(hDlg, &rc);
  423. SetWindowPos(hDlg, NULL, 0, 0, rc.right, rc.bottom+cyList,
  424. SWP_NOMOVE | SWP_NOZORDER);
  425. // Move the label and edit controls down.
  426. GetClientRect(GetDlgItem(hDlg, IDC_CI_LABEL), &rc);
  427. SetWindowPos(GetDlgItem(hDlg, IDC_CI_LABEL), NULL, 0, cyList,
  428. rc.right, rc.bottom, SWP_NOSIZE | SWP_NOZORDER);
  429. GetClientRect(GetDlgItem(hDlg, IDC_CI_LABELEDIT), &rc);
  430. SetWindowPos(GetDlgItem(hDlg, IDC_CI_LABELEDIT), NULL, 0, cyList,
  431. rc.right, rc.bottom, SWP_NOSIZE | SWP_NOZORDER);
  432. }
  433. /*
  434. * Select Current, Default, or From File radiobuttons appropriately.
  435. * The CheckRadioButton call sends WM_COMMANDs which handle
  436. * other actions. Note that if we check From File, which
  437. * takes an icon from the list, we better fill the list.
  438. * This will also fill the list even if default is selected.
  439. */
  440. if (0 != UFillIconList(hDlg, IDC_CI_ICONLIST, lpCI->szFile, FALSE))
  441. {
  442. // If szFile worked, then select the source icon in the listbox.
  443. SendDlgItemMessage(hDlg, IDC_CI_ICONLIST, LB_SETCURSEL, lpCI->iIcon, 0L);
  444. }
  445. if (lpCI->dwFlags & CIF_SELECTCURRENT)
  446. {
  447. CheckRadioButton(hDlg, IDC_CI_CURRENT, IDC_CI_FROMFILE, IDC_CI_CURRENT);
  448. }
  449. else
  450. {
  451. UINT uID = (lpCI->dwFlags & CIF_SELECTFROMFILE) ? IDC_CI_FROMFILE : IDC_CI_DEFAULT;
  452. CheckRadioButton(hDlg, IDC_CI_CURRENT, IDC_CI_FROMFILE, uID);
  453. }
  454. UpdateResultIcon(lpCI, hDlg, (UINT)-1);
  455. // Change the caption
  456. if (NULL!=lpOCI->lpszCaption)
  457. SetWindowText(hDlg, lpOCI->lpszCaption);
  458. /* Give our parent window access to our hDlg (via a special SetProp).
  459. * The PasteSpecial dialog may need to force our dialog down if the
  460. * clipboard contents change underneath it. if so it will send
  461. * us a IDCANCEL command.
  462. */
  463. SetProp(lpCI->lpOCI->hWndOwner, PROP_HWND_CHGICONDLG, hDlg);
  464. lpCI->nBrowseHelpID = RegisterWindowMessage(HELPMSGSTRING);
  465. // Call the hook with lCustData in lParam
  466. UStandardHook(lpCI, hDlg, WM_INITDIALOG, wParam, lpOCI->lCustData);
  467. return TRUE;
  468. }
  469. /*
  470. * UFillIconList
  471. *
  472. * Purpose:
  473. * Given a listbox and a filename, attempts to open that file and
  474. * read all the icons that exist therein, adding them to the listbox
  475. * hList as owner-draw items. If the file does not exist or has no
  476. * icons, then you get no icons and an appropriate warning message.
  477. *
  478. * Parameters:
  479. * hDlg HWND of the dialog containing the listbox.
  480. * idList UINT identifier of the listbox to fill.
  481. * pszFile LPSTR of the file from which to extract icons.
  482. *
  483. * Return Value:
  484. * UINT Number of items added to the listbox. 0 on failure.
  485. */
  486. UINT UFillIconList(HWND hDlg, UINT idList, LPTSTR pszFile, BOOL bError)
  487. {
  488. HWND hList = GetDlgItem(hDlg, idList);
  489. if (NULL == hList)
  490. return 0;
  491. // Clean out the listbox.
  492. SendMessage(hList, LB_RESETCONTENT, 0, 0L);
  493. // If we have an empty string, just exit leaving the listbox empty as well
  494. if (0 == lstrlen(pszFile))
  495. return 0;
  496. // Turn on the hourglass
  497. HCURSOR hCur = HourGlassOn();
  498. UINT nFileError = 0;
  499. // Check if the file is valid.
  500. TCHAR szPathName[MAX_PATH];
  501. LPTSTR lpszFilePart = NULL;
  502. UINT cIcons = 0;
  503. if (SearchPath(NULL, pszFile, NULL, MAX_PATH, szPathName, &lpszFilePart) != 0)
  504. {
  505. // This hack is still necessary in Win32 because even under
  506. // Win32s this ExtractIcon bug appears.
  507. #ifdef EXTRACTICONWORKS
  508. // Get the icon count for this file.
  509. cIcons = (UINT)StandardExtractIcon(_g_hOleStdInst, szPathName, (UINT)-1);
  510. #else
  511. /*
  512. * ExtractIcon in Windows 3.1 with -1 eats a selector, leaving an
  513. * extra global memory object around for this applciation. Since
  514. * changing icons may happen very often with all OLE apps in
  515. * the system, we have to work around it. So we'll say we
  516. * have lots of icons and just call ExtractIcon until it
  517. * fails. We check if there's any around by trying to get
  518. * the first one.
  519. */
  520. cIcons = 0xFFFF;
  521. HICON hIcon = StandardExtractIcon(_g_hOleStdInst, szPathName, 0);
  522. // Fake a failure with cIcons=0, or cleanup hIcon from this test.
  523. if (NULL == hIcon || 1 == HandleToUlong(hIcon))
  524. cIcons = 0;
  525. else
  526. DestroyIcon(hIcon);
  527. #endif
  528. if (0 != cIcons)
  529. {
  530. SendMessage(hList, WM_SETREDRAW, FALSE, 0L);
  531. for (UINT i = 0; i < cIcons; i++)
  532. {
  533. hIcon=StandardExtractIcon(_g_hOleStdInst, szPathName, i);
  534. if (hIcon != NULL)
  535. SendMessage(hList, LB_ADDSTRING, 0, (LPARAM)hIcon);
  536. else
  537. break;
  538. }
  539. //Force complete repaint
  540. SendMessage(hList, WM_SETREDRAW, TRUE, 0L);
  541. InvalidateRect(hList, NULL, TRUE);
  542. //Select an icon
  543. SendMessage(hList, LB_SETCURSEL, 0, 0L);
  544. }
  545. else
  546. nFileError = IDS_CINOICONSINFILE;
  547. }
  548. else
  549. nFileError = ERROR_FILE_NOT_FOUND;
  550. // show error if necessary and possible
  551. if (nFileError && bError)
  552. {
  553. ErrorWithFile(hDlg, _g_hOleStdResInst, nFileError, szPathName,
  554. MB_OK | MB_ICONEXCLAMATION);
  555. }
  556. HourGlassOff(hCur);
  557. return cIcons;
  558. }
  559. /*
  560. * FDrawListIcon
  561. *
  562. * Purpose:
  563. * Handles WM_DRAWITEM for the icon listbox.
  564. *
  565. * Parameters:
  566. * lpDI LPDRAWITEMSTRUCT from WM_DRAWITEM
  567. *
  568. * Return Value:
  569. * BOOL TRUE if we did anything, FALSE if there are no items
  570. * in the list.
  571. */
  572. BOOL FDrawListIcon(LPDRAWITEMSTRUCT lpDI)
  573. {
  574. /*
  575. * If there are no items in the list, then itemID is negative according
  576. * to the Win3.1 SDK. Unfortunately DRAWITEMSTRUCT has an unsigned int
  577. * for this field, so we need the typecast to do a signed comparison.
  578. */
  579. if ((int)lpDI->itemID < 0)
  580. return FALSE;
  581. /*
  582. * For selection or draw entire case we just draw the entire item all
  583. * over again. For focus cases, we only call DrawFocusRect.
  584. */
  585. if (lpDI->itemAction & (ODA_SELECT | ODA_DRAWENTIRE))
  586. {
  587. COLORREF cr;
  588. // Clear background and draw the icon.
  589. if (lpDI->itemState & ODS_SELECTED)
  590. cr = SetBkColor(lpDI->hDC, GetSysColor(COLOR_HIGHLIGHT));
  591. else
  592. cr = SetBkColor(lpDI->hDC, GetSysColor(COLOR_WINDOW));
  593. // Draw a cheap rectangle.
  594. ExtTextOut(lpDI->hDC, 0, 0, ETO_OPAQUE, &lpDI->rcItem, NULL, 0, NULL);
  595. DrawIcon(lpDI->hDC, lpDI->rcItem.left+(CXICONPAD/2),
  596. lpDI->rcItem.top+(CYICONPAD/2), (HICON)(lpDI->itemData));
  597. // Restore original background for DrawFocusRect
  598. SetBkColor(lpDI->hDC, cr);
  599. }
  600. // Always change focus on the focus action.
  601. if (lpDI->itemAction & ODA_FOCUS || lpDI->itemState & ODS_FOCUS)
  602. DrawFocusRect(lpDI->hDC, &lpDI->rcItem);
  603. return TRUE;
  604. }
  605. /*
  606. * UpdateResultIcon
  607. *
  608. * Purpose:
  609. * Updates the result icon using the current icon in the default display
  610. * or the icon listbox depending on fFromDefault.
  611. *
  612. * Parameters:
  613. * lpCI LPCHANGEICON containing dialog flags.
  614. * hDlg HWND of the dialog
  615. * uID UINT identifying the radiobutton selected.
  616. *
  617. * Return Value:
  618. * None
  619. */
  620. void UpdateResultIcon(LPCHANGEICON lpCI, HWND hDlg, UINT uID)
  621. {
  622. if (uID == -1)
  623. {
  624. if (SendDlgItemMessage(hDlg, IDC_CI_CURRENT, BM_GETCHECK, 0, 0))
  625. uID = IDC_CI_CURRENT;
  626. else if (SendDlgItemMessage(hDlg, IDC_CI_DEFAULT, BM_GETCHECK, 0, 0))
  627. uID = IDC_CI_DEFAULT;
  628. else if (SendDlgItemMessage(hDlg, IDC_CI_FROMFILE, BM_GETCHECK, 0, 0))
  629. uID = IDC_CI_FROMFILE;
  630. }
  631. lpCI->dwFlags &= ~(CIF_SELECTCURRENT | CIF_SELECTDEFAULT | CIF_SELECTFROMFILE);
  632. LRESULT lTemp = -1;
  633. switch (uID)
  634. {
  635. case IDC_CI_CURRENT:
  636. lTemp = SendDlgItemMessage(hDlg, IDC_CI_CURRENTICON, STM_GETICON, 0, 0L);
  637. lpCI->dwFlags |= CIF_SELECTCURRENT;
  638. break;
  639. case IDC_CI_DEFAULT:
  640. lTemp = SendDlgItemMessage(hDlg, IDC_CI_DEFAULTICON, STM_GETICON, 0, 0L);
  641. lpCI->dwFlags |= CIF_SELECTDEFAULT;
  642. break;
  643. case IDC_CI_FROMFILE:
  644. {
  645. // Get the selected icon from the list and place it in the result
  646. lpCI->dwFlags |= CIF_SELECTFROMFILE;
  647. UINT iSel = (UINT)SendDlgItemMessage(hDlg, IDC_CI_ICONLIST, LB_GETCURSEL, 0, 0L);
  648. if (LB_ERR == (int)iSel)
  649. lTemp = SendDlgItemMessage(hDlg, IDC_CI_DEFAULTICON, STM_GETICON, 0, 0L);
  650. else
  651. lTemp = SendDlgItemMessage(hDlg, IDC_CI_ICONLIST, LB_GETITEMDATA, iSel, 0);
  652. break;
  653. }
  654. default:
  655. OleDbgAssert(FALSE);
  656. break;
  657. }
  658. CheckRadioButton(hDlg, IDC_CI_CURRENT, IDC_CI_FROMFILE, uID);
  659. // set current icon display as a result of the controls
  660. LPTSTR lpszSourceFile = lpCI->szFile;
  661. if (lpCI->dwFlags & CIF_SELECTDEFAULT)
  662. {
  663. // use defaults
  664. lpszSourceFile = lpCI->szDefIconFile;
  665. lpCI->iIcon = lpCI->iDefIcon;
  666. }
  667. else if (lpCI->dwFlags & CIF_SELECTCURRENT)
  668. {
  669. TCHAR szTemp[MAX_PATH];
  670. OleUIMetafilePictExtractIconSource(lpCI->lpOCI->hMetaPict,
  671. szTemp, &lpCI->iIcon);
  672. MyGetLongPathName(szTemp, lpszSourceFile, MAX_PATH);
  673. }
  674. else if (lpCI->dwFlags & CIF_SELECTFROMFILE)
  675. {
  676. // get from file and index
  677. GetDlgItemText(hDlg, IDC_CI_FROMFILEEDIT, lpszSourceFile, MAX_PATH);
  678. lpCI->iIcon = (UINT)SendDlgItemMessage(hDlg,
  679. IDC_CI_ICONLIST, LB_GETCURSEL, 0, 0L);
  680. }
  681. // Get new hMetaPict and set result text
  682. TCHAR szTemp[MAX_PATH];
  683. GetDlgItemText(hDlg, IDC_CI_LABELEDIT, szTemp, MAX_PATH);
  684. TCHAR szShortFile[MAX_PATH];
  685. GetShortPathName(lpszSourceFile, szShortFile, MAX_PATH);
  686. #if defined(WIN32) && !defined(UNICODE)
  687. OLECHAR wszTemp[MAX_PATH];
  688. OLECHAR wszSourceFile[MAX_PATH];
  689. ATOW(wszTemp, szTemp, MAX_PATH);
  690. ATOW(wszSourceFile, szShortFile, MAX_PATH);
  691. HGLOBAL hMetaPict = OleMetafilePictFromIconAndLabel(
  692. (HICON)lTemp, wszTemp, wszSourceFile, lpCI->iIcon);
  693. #else
  694. HGLOBAL hMetaPict = OleMetafilePictFromIconAndLabel(
  695. (HICON)lTemp, szTemp, szShortFile, lpCI->iIcon);
  696. #endif
  697. SendDlgItemMessage(hDlg, IDC_CI_ICONDISPLAY, IBXM_IMAGESET, 1,
  698. (LPARAM)hMetaPict);
  699. }
  700. //+---------------------------------------------------------------------------
  701. //
  702. // Function: IsLongComponent, public
  703. //
  704. // Synopsis: Determines whether the current path component is a legal
  705. // 8.3 name or not. If not, it is considered to be a long
  706. // component.
  707. //
  708. // Arguments: [pwcsPath] - Path to check
  709. // [ppwcsEnd] - Return for end of component pointer
  710. //
  711. // Returns: BOOL
  712. //
  713. // Modifies: [ppwcsEnd]
  714. //
  715. // History: 28-Aug-94 DrewB Created
  716. // 5-04-95 stevebl Modified for use by oledlg
  717. //
  718. // Notes: An empty path is considered to be long
  719. // The following characters are not valid in file name domain:
  720. // * + , : ; < = > ? [ ] |
  721. //
  722. //----------------------------------------------------------------------------
  723. BOOL IsLongComponent(LPCTSTR pwcsPath,
  724. PTSTR *ppwcsEnd)
  725. {
  726. LPTSTR pwcEnd, pwcDot;
  727. BOOL fLongNameFound;
  728. TCHAR wc;
  729. pwcEnd = (LPTSTR)pwcsPath;
  730. fLongNameFound = FALSE;
  731. pwcDot = NULL;
  732. while (TRUE)
  733. {
  734. wc = *pwcEnd;
  735. if (wc == '\\' || wc == 0)
  736. {
  737. *ppwcsEnd = pwcEnd;
  738. // We're at a component terminator, so make the
  739. // determination of whether what we've seen is a long
  740. // name or short one
  741. // If we've aready seen illegal characters or invalid
  742. // structure for a short name, don't bother to check lengths
  743. if (pwcEnd-pwcsPath > 0 && !fLongNameFound)
  744. {
  745. // If this component fits in 8.3 then it is a short name
  746. if ((!pwcDot && (ULONG)(pwcEnd - pwcsPath) <= 8) ||
  747. (pwcDot && ((ULONG)(pwcEnd - pwcDot) <= 3 + 1 &&
  748. (ULONG)(pwcEnd - pwcsPath) <= 8 + 3 + 1)))
  749. {
  750. return FALSE;
  751. }
  752. }
  753. return TRUE;
  754. }
  755. // Handle dots
  756. if (wc == '.')
  757. {
  758. // If two or more '.' or the base name is longer than
  759. // 8 characters or no base name at all, it is an illegal dos
  760. // file name
  761. if (pwcDot != NULL ||
  762. ((ULONG)(pwcEnd - pwcsPath)) > 8 ||
  763. (pwcEnd == pwcsPath && *(pwcEnd + 1) != '\\'))
  764. {
  765. fLongNameFound = TRUE;
  766. }
  767. pwcDot = pwcEnd;
  768. }
  769. // Check for characters which aren't valid in short names
  770. else if (wc <= ' ' ||
  771. wc == '*' ||
  772. wc == '+' ||
  773. wc == ',' ||
  774. wc == ':' ||
  775. wc == ';' ||
  776. wc == '<' ||
  777. wc == '=' ||
  778. wc == '>' ||
  779. wc == '?' ||
  780. wc == '[' ||
  781. wc == ']' ||
  782. wc == '|')
  783. {
  784. fLongNameFound = TRUE;
  785. }
  786. pwcEnd++;
  787. }
  788. }
  789. //
  790. // The following code was stolen from NT's RTL in curdir.c
  791. //
  792. #define IS_PATH_SEPARATOR(wch) \
  793. ((wch) == '\\' || (wch) == '/')
  794. typedef enum
  795. {
  796. PATH_TYPE_UNKNOWN,
  797. PATH_TYPE_UNC_ABSOLUTE,
  798. PATH_TYPE_LOCAL_DEVICE,
  799. PATH_TYPE_ROOT_LOCAL_DEVICE,
  800. PATH_TYPE_DRIVE_ABSOLUTE,
  801. PATH_TYPE_DRIVE_RELATIVE,
  802. PATH_TYPE_ROOTED,
  803. PATH_TYPE_RELATIVE
  804. } PATH_TYPE;
  805. PATH_TYPE
  806. DetermineDosPathNameType(
  807. IN LPCTSTR DosFileName
  808. )
  809. /*++
  810. Routine Description:
  811. This function examines the Dos format file name and determines the
  812. type of file name (i.e. UNC, DriveAbsolute, Current Directory
  813. rooted, or Relative.
  814. Arguments:
  815. DosFileName - Supplies the Dos format file name whose type is to be
  816. determined.
  817. Return Value:
  818. PATH_TYPE_UNKNOWN - The path type can not be determined
  819. PATH_TYPE_UNC_ABSOLUTE - The path specifies a Unc absolute path
  820. in the format \\server-name\sharename\rest-of-path
  821. PATH_TYPE_LOCAL_DEVICE - The path specifies a local device in the format
  822. \\.\rest-of-path this can be used for any device where the nt and
  823. Win32 names are the same. For example mailslots.
  824. PATH_TYPE_ROOT_LOCAL_DEVICE - The path specifies the root of the local
  825. devices in the format \\.
  826. PATH_TYPE_DRIVE_ABSOLUTE - The path specifies a drive letter absolute
  827. path in the form drive:\rest-of-path
  828. PATH_TYPE_DRIVE_RELATIVE - The path specifies a drive letter relative
  829. path in the form drive:rest-of-path
  830. PATH_TYPE_ROOTED - The path is rooted relative to the current disk
  831. designator (either Unc disk, or drive). The form is \rest-of-path.
  832. PATH_TYPE_RELATIVE - The path is relative (i.e. not absolute or rooted).
  833. --*/
  834. {
  835. PATH_TYPE ReturnValue;
  836. if ( IS_PATH_SEPARATOR(*DosFileName) )
  837. {
  838. if ( IS_PATH_SEPARATOR(*(DosFileName+1)) )
  839. {
  840. if ( DosFileName[2] == '.' )
  841. {
  842. if ( IS_PATH_SEPARATOR(*(DosFileName+3)) )
  843. {
  844. ReturnValue = PATH_TYPE_LOCAL_DEVICE;
  845. }
  846. else if ( (*(DosFileName+3)) == 0 )
  847. {
  848. ReturnValue = PATH_TYPE_ROOT_LOCAL_DEVICE;
  849. }
  850. else
  851. {
  852. ReturnValue = PATH_TYPE_UNC_ABSOLUTE;
  853. }
  854. }
  855. else
  856. {
  857. ReturnValue = PATH_TYPE_UNC_ABSOLUTE;
  858. }
  859. }
  860. else
  861. {
  862. ReturnValue = PATH_TYPE_ROOTED;
  863. }
  864. }
  865. else if (*(DosFileName+1) == ':')
  866. {
  867. if (IS_PATH_SEPARATOR(*(DosFileName+2)))
  868. {
  869. ReturnValue = PATH_TYPE_DRIVE_ABSOLUTE;
  870. }
  871. else
  872. {
  873. ReturnValue = PATH_TYPE_DRIVE_RELATIVE;
  874. }
  875. }
  876. else
  877. {
  878. ReturnValue = PATH_TYPE_RELATIVE;
  879. }
  880. return ReturnValue;
  881. }
  882. //+---------------------------------------------------------------------------
  883. //
  884. // Function: MyGetLongPathName, public
  885. //
  886. // Synopsis: Expand each component of the given path into its
  887. // long form
  888. //
  889. // Arguments: [pwcsPath] - Path
  890. // [pwcsLongPath] - Long path return buffer
  891. // [cchLongPath] - Size of return buffer in characters
  892. //
  893. // Returns: 0 for errors
  894. // Number of characters needed for buffer if buffer is too small
  895. // includes NULL terminator
  896. // Length of long path, doesn't include NULL terminator
  897. //
  898. // Modifies: [pwcsLongPath]
  899. //
  900. // History: 28-Aug-94 DrewB Created
  901. // 11-Nov-94 BruceMa Modifed to use for Chicago at
  902. // FindFirstFile
  903. // 5-04-95 stevebl Modified for use by OLEDLG
  904. //
  905. // Notes: The source and destination buffers can be the same memory
  906. // Doesn't handle paths with internal . and .., although
  907. // they are handled at the beginning
  908. //
  909. //----------------------------------------------------------------------------
  910. ULONG
  911. MyGetLongPathName(LPCTSTR pcsPath,
  912. LPTSTR pwcsLongPath,
  913. ULONG cchLongPath)
  914. {
  915. PATH_TYPE pt;
  916. HANDLE h;
  917. LPTSTR pwcsLocalLongPath;
  918. ULONG cchReturn, cb, cch, cchOutput;
  919. LPTSTR pwcStart = NULL;
  920. LPTSTR pwcEnd;
  921. LPTSTR pwcLong;
  922. TCHAR wcSave;
  923. BOOL fLong;
  924. WIN32_FIND_DATA wfd;
  925. cchReturn = 0;
  926. pwcsLocalLongPath = NULL;
  927. __try
  928. {
  929. //
  930. // First, run down the string checking for tilde's. Any path
  931. // that has a short name section to it will have a tilde. If
  932. // there are no tilde's, then we already have the long path,
  933. // so we can return the string.
  934. //
  935. fLong = TRUE;
  936. for (pwcLong = (LPTSTR)pcsPath; *pwcLong != 0; pwcLong++)
  937. {
  938. if (*pwcLong == L'~')
  939. {
  940. fLong = FALSE;
  941. }
  942. }
  943. //
  944. // This derives the number of characters, including the NULL
  945. //
  946. cch = ((ULONG)(pwcLong - pcsPath)) + 1;
  947. //
  948. // If it isn't a long path already, then we are going to have
  949. // to parse it.
  950. //
  951. if (!fLong)
  952. {
  953. // Decide the path type, we want find out the position of
  954. // the first character of the first name
  955. pt = DetermineDosPathNameType(pcsPath);
  956. switch(pt)
  957. {
  958. // Form: "\\server_name\share_name\rest_of_the_path"
  959. case PATH_TYPE_UNC_ABSOLUTE:
  960. #if defined(UNICODE)
  961. if ((pwcStart = wcschr(pcsPath + 2, L'\\')) != NULL &&
  962. (pwcStart = wcschr(pwcStart + 1, L'\\')) != NULL)
  963. #else
  964. if ((pwcStart = strchr(pcsPath + 2, '\\')) != NULL &&
  965. (pwcStart = strchr(pwcStart + 1, '\\')) != NULL)
  966. #endif
  967. {
  968. pwcStart++;
  969. }
  970. else
  971. {
  972. pwcStart = NULL;
  973. }
  974. break;
  975. // Form: "\\.\rest_of_the_path"
  976. case PATH_TYPE_LOCAL_DEVICE:
  977. pwcStart = (LPTSTR)pcsPath + 4;
  978. break;
  979. // Form: "\\."
  980. case PATH_TYPE_ROOT_LOCAL_DEVICE:
  981. pwcStart = NULL;
  982. break;
  983. // Form: "D:\rest_of_the_path"
  984. case PATH_TYPE_DRIVE_ABSOLUTE:
  985. pwcStart = (LPTSTR)pcsPath + 3;
  986. break;
  987. // Form: "rest_of_the_path"
  988. case PATH_TYPE_RELATIVE:
  989. pwcStart = (LPTSTR) pcsPath;
  990. goto EatDots;
  991. // Form: "D:rest_of_the_path"
  992. case PATH_TYPE_DRIVE_RELATIVE:
  993. pwcStart = (LPTSTR)pcsPath+2;
  994. EatDots:
  995. // Handle .\ and ..\ cases
  996. while (*pwcStart != 0 && *pwcStart == L'.')
  997. {
  998. if (pwcStart[1] == L'\\')
  999. {
  1000. pwcStart += 2;
  1001. }
  1002. else if (pwcStart[1] == L'.' && pwcStart[2] == L'\\')
  1003. {
  1004. pwcStart += 3;
  1005. }
  1006. else
  1007. {
  1008. break;
  1009. }
  1010. }
  1011. break;
  1012. // Form: "\rest_of_the_path"
  1013. case PATH_TYPE_ROOTED:
  1014. pwcStart = (LPTSTR)pcsPath + 1;
  1015. break;
  1016. default:
  1017. pwcStart = NULL;
  1018. break;
  1019. }
  1020. }
  1021. // In the special case where we have no work to do, exit quickly
  1022. // This saves a lot of instructions for trivial cases
  1023. // In one case the path as given requires no processing
  1024. // The middle case, we determine there were no tilde's in the path
  1025. // In the other, the path only has one component and it is already
  1026. // long
  1027. ///
  1028. if (pwcStart == NULL ||
  1029. (fLong == TRUE) ||
  1030. ((fLong = IsLongComponent(pwcStart, &pwcEnd)) &&
  1031. *pwcEnd == 0))
  1032. {
  1033. // Nothing to convert, copy down the source string
  1034. // to the buffer if necessary
  1035. if (pwcStart != NULL)
  1036. {
  1037. cch = (ULONG)(pwcEnd - pcsPath + 1);
  1038. }
  1039. if (cchLongPath >= cch)
  1040. {
  1041. memcpy(pwcsLongPath, pcsPath, cch * sizeof(TCHAR));
  1042. cchReturn = cch - 1;
  1043. goto gsnTryExit;
  1044. }
  1045. else
  1046. {
  1047. cchReturn = cch;
  1048. goto gsnTryExit;
  1049. }
  1050. }
  1051. // Make a local buffer so that we won't overlap the
  1052. // source pathname in case the long name is longer than the
  1053. // source name.
  1054. if (cchLongPath > 0)
  1055. {
  1056. pwcsLocalLongPath = (PTCHAR)malloc(cchLongPath * sizeof(TCHAR));
  1057. if (pwcsLocalLongPath == NULL)
  1058. {
  1059. goto gsnTryExit;
  1060. }
  1061. }
  1062. // Set up pointer to copy output to
  1063. pwcLong = pwcsLocalLongPath;
  1064. cchOutput = 0;
  1065. // Copy the portions of the path that we skipped initially
  1066. cch = (ULONG)(pwcStart-pcsPath);
  1067. cchOutput += cch;
  1068. if (cchOutput <= cchLongPath)
  1069. {
  1070. memcpy(pwcLong, pcsPath, cch*sizeof(TCHAR));
  1071. pwcLong += cch;
  1072. }
  1073. for (;;)
  1074. {
  1075. // Determine whether the current component is long or short
  1076. cch = ((ULONG)(pwcEnd-pwcStart))+1;
  1077. cb = cch*sizeof(TCHAR);
  1078. if (fLong)
  1079. {
  1080. // If the component is already long, just copy it into
  1081. // the output. Copy the terminating character along with it
  1082. // so the output remains properly punctuated
  1083. cchOutput += cch;
  1084. if (cchOutput <= cchLongPath)
  1085. {
  1086. memcpy(pwcLong, pwcStart, cb);
  1087. pwcLong += cch;
  1088. }
  1089. }
  1090. else
  1091. {
  1092. TCHAR wcsTmp[MAX_PATH];
  1093. // For a short component we need to determine the
  1094. // long name, if there is one. The only way to
  1095. // do this reliably is to enumerate for the child
  1096. wcSave = *pwcEnd;
  1097. *pwcEnd = 0;
  1098. h = FindFirstFile(pcsPath, &wfd);
  1099. *pwcEnd = wcSave;
  1100. if (h == INVALID_HANDLE_VALUE)
  1101. {
  1102. goto gsnTryExit;
  1103. }
  1104. FindClose(h);
  1105. lstrcpy(wcsTmp, wfd.cFileName);
  1106. // Copy the filename returned by the query into the output
  1107. // Copy the terminator from the original component into
  1108. // the output to maintain punctuation
  1109. cch = lstrlen(wcsTmp)+1;
  1110. cchOutput += cch;
  1111. if (cchOutput <= cchLongPath)
  1112. {
  1113. memcpy(pwcLong, wcsTmp, (cch-1)*sizeof(TCHAR));
  1114. pwcLong += cch;
  1115. *(pwcLong-1) = *pwcEnd;
  1116. }
  1117. }
  1118. if (*pwcEnd == 0)
  1119. {
  1120. break;
  1121. }
  1122. // Update start pointer to next component
  1123. pwcStart = pwcEnd+1;
  1124. fLong = IsLongComponent(pwcStart, &pwcEnd);
  1125. }
  1126. // Copy local output buffer to given output buffer if necessary
  1127. if (cchLongPath >= cchOutput)
  1128. {
  1129. memcpy(pwcsLongPath, pwcsLocalLongPath, cchOutput * sizeof(TCHAR));
  1130. cchReturn = cchOutput-1;
  1131. }
  1132. else
  1133. {
  1134. cchReturn = cchOutput;
  1135. }
  1136. gsnTryExit:;
  1137. }
  1138. __finally
  1139. {
  1140. if (pwcsLocalLongPath != NULL)
  1141. {
  1142. free(pwcsLocalLongPath);
  1143. pwcsLocalLongPath = NULL;
  1144. }
  1145. }
  1146. return cchReturn;
  1147. }