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.

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