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.

432 lines
15 KiB

  1. /*
  2. * CHNGSRC.CPP
  3. *
  4. * Implements the OleUIChangeSource function which invokes the complete
  5. * Change Source 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. OLEDBGDATA
  13. // Internally used structure
  14. typedef struct tagCHANGESOURCE
  15. {
  16. // Keep this item first as the Standard* functions depend on it here.
  17. LPOLEUICHANGESOURCE lpOCS; //Original structure passed.
  18. UINT nIDD; // IDD of dialog (used for help info)
  19. /*
  20. * What we store extra in this structure besides the original caller's
  21. * pointer are those fields that we need to modify during the life of
  22. * the dialog but that we don't want to change in the original structure
  23. * until the user presses OK.
  24. */
  25. } CHANGESOURCE, *PCHANGESOURCE, FAR* LPCHANGESOURCE;
  26. // Internal function prototypes
  27. // CHNGSRC.CPP
  28. UINT_PTR CALLBACK ChangeSourceHookProc(HWND, UINT, WPARAM, LPARAM);
  29. BOOL FChangeSourceInit(HWND hDlg, WPARAM, LPARAM);
  30. STDAPI_(BOOL) IsValidInterface(void FAR* ppv);
  31. /*
  32. * OleUIChangeSource
  33. *
  34. * Purpose:
  35. * Invokes the standard OLE Change Source dialog box allowing the user
  36. * to change the source of a link. The link source is not actually
  37. * changed by this dialog. It is up to the caller to actually change
  38. * the link source itself.
  39. *
  40. * Parameters:
  41. * lpCS LPOLEUIChangeSource pointing to the in-out structure
  42. * for this dialog.
  43. *
  44. * Return Value:
  45. * UINT One of the following codes, indicating success or error:
  46. * OLEUI_SUCCESS Success
  47. * OLEUI_ERR_STRUCTSIZE The dwStructSize value is wrong
  48. */
  49. STDAPI_(UINT) OleUIChangeSource(LPOLEUICHANGESOURCE lpCS)
  50. {
  51. HGLOBAL hMemDlg = NULL;
  52. UINT uRet = UStandardValidation((LPOLEUISTANDARD)lpCS,
  53. sizeof(OLEUICHANGESOURCE), &hMemDlg);
  54. if (OLEUI_SUCCESS != uRet)
  55. return uRet;
  56. HCURSOR hCurSave = NULL;
  57. // validate contents of lpCS
  58. if (lpCS->lpOleUILinkContainer == NULL)
  59. {
  60. uRet = OLEUI_CSERR_LINKCNTRNULL;
  61. goto Error;
  62. }
  63. if (!IsValidInterface(lpCS->lpOleUILinkContainer))
  64. {
  65. uRet = OLEUI_CSERR_LINKCNTRINVALID;
  66. goto Error;
  67. }
  68. // lpszFrom and lpszTo must be NULL (they are out only)
  69. if (lpCS->lpszFrom != NULL)
  70. {
  71. uRet = OLEUI_CSERR_FROMNOTNULL;
  72. goto Error;
  73. }
  74. if (lpCS->lpszTo != NULL)
  75. {
  76. uRet = OLEUI_CSERR_TONOTNULL;
  77. goto Error;
  78. }
  79. // lpszDisplayName must be valid or NULL
  80. if (lpCS->lpszDisplayName != NULL &&
  81. IsBadStringPtr(lpCS->lpszDisplayName, (UINT)-1))
  82. {
  83. uRet = OLEUI_CSERR_SOURCEINVALID;
  84. goto Error;
  85. }
  86. hCurSave = HourGlassOn();
  87. // attempt to retrieve link source if not provided
  88. if (lpCS->lpszDisplayName == NULL)
  89. {
  90. if (NOERROR != lpCS->lpOleUILinkContainer->GetLinkSource(
  91. lpCS->dwLink, &lpCS->lpszDisplayName, &lpCS->nFileLength,
  92. NULL, NULL, NULL, NULL))
  93. {
  94. uRet = OLEUI_CSERR_SOURCEINVALID;
  95. goto Error;
  96. }
  97. }
  98. // verify that nFileLength is valid
  99. if ((UINT)lstrlen(lpCS->lpszDisplayName) < lpCS->nFileLength)
  100. {
  101. uRet = OLEUI_CSERR_SOURCEINVALID;
  102. goto Error;
  103. }
  104. // allocate file buffer and split directory and file name
  105. UINT nFileLength; nFileLength = lpCS->nFileLength;
  106. UINT nFileBuf; nFileBuf = max(nFileLength+1, MAX_PATH);
  107. LPTSTR lpszFileBuf;
  108. LPTSTR lpszDirBuf; lpszDirBuf = (LPTSTR)OleStdMalloc(nFileBuf * sizeof(TCHAR));
  109. if (lpszDirBuf == NULL)
  110. {
  111. uRet = OLEUI_ERR_OLEMEMALLOC;
  112. goto Error;
  113. }
  114. lstrcpyn(lpszDirBuf, lpCS->lpszDisplayName, nFileLength+1);
  115. UINT nFileLen; nFileLen = GetFileName(lpszDirBuf, NULL, 0);
  116. lpszFileBuf = (LPTSTR)OleStdMalloc(nFileBuf * sizeof(TCHAR));
  117. if (lpszFileBuf == NULL)
  118. {
  119. uRet = OLEUI_ERR_OLEMEMALLOC;
  120. goto ErrorFreeDirBuf;
  121. }
  122. memmove(lpszFileBuf, lpszDirBuf+nFileLength-nFileLen+1,
  123. (nFileLen+1)*sizeof(TCHAR));
  124. lpszDirBuf[nFileLength-(nFileLen - 1)] = 0;
  125. // start filling the OPENFILENAME struct
  126. OPENFILENAME ofn; memset(&ofn, 0, sizeof(ofn));
  127. ofn.lpstrFile = lpszFileBuf;
  128. ofn.nMaxFile = nFileBuf;
  129. ofn.lpstrInitialDir = lpszDirBuf;
  130. // load filter strings
  131. TCHAR szFilters[MAX_PATH];
  132. if (!LoadString(_g_hOleStdResInst, IDS_FILTERS, szFilters, MAX_PATH))
  133. szFilters[0] = 0;
  134. else
  135. ReplaceCharWithNull(szFilters, szFilters[lstrlen(szFilters)-1]);
  136. ofn.lpstrFilter = szFilters;
  137. ofn.nFilterIndex = 1;
  138. TCHAR szTitle[MAX_PATH];
  139. // set the caption
  140. if (NULL!=lpCS->lpszCaption)
  141. ofn.lpstrTitle = lpCS->lpszCaption;
  142. else
  143. {
  144. LoadString(_g_hOleStdResInst, IDS_CHANGESOURCE, szTitle, MAX_PATH);
  145. ofn.lpstrTitle = szTitle;
  146. }
  147. // fill in rest of OPENFILENAME struct
  148. ofn.hwndOwner = lpCS->hWndOwner;
  149. ofn.lStructSize = sizeof(ofn);
  150. ofn.Flags = OFN_HIDEREADONLY | OFN_ENABLEHOOK;
  151. if (bWin4 && ((NULL == lpCS->hInstance && NULL == lpCS->hResource)
  152. || 0 != (lpCS->dwFlags & CSF_EXPLORER)))
  153. ofn.Flags |= OFN_EXPLORER;
  154. if (lpCS->dwFlags & CSF_SHOWHELP)
  155. ofn.Flags |= OFN_SHOWHELP;
  156. ofn.lCustData = (LPARAM)lpCS;
  157. ofn.lpfnHook = ChangeSourceHookProc;
  158. ofn.lCustData = (LPARAM)lpCS;
  159. lpCS->lpOFN = &ofn; // needed sometimes in hook proc
  160. // allow hooking of the dialog resource
  161. if (lpCS->hResource != NULL)
  162. {
  163. ofn.hInstance = (HINSTANCE)lpCS->hResource;
  164. ofn.lpTemplateName = (LPCTSTR)lpCS->hResource;
  165. ofn.Flags |= OFN_ENABLETEMPLATEHANDLE;
  166. }
  167. else
  168. {
  169. if (lpCS->hInstance == NULL)
  170. {
  171. ofn.hInstance = _g_hOleStdResInst;
  172. ofn.lpTemplateName = bWin4 ?
  173. MAKEINTRESOURCE(IDD_CHANGESOURCE4) : MAKEINTRESOURCE(IDD_CHANGESOURCE);
  174. ofn.Flags |= OFN_ENABLETEMPLATE;
  175. }
  176. else
  177. {
  178. ofn.hInstance = lpCS->hInstance;
  179. ofn.lpTemplateName = lpCS->lpszTemplate;
  180. ofn.Flags |= OFN_ENABLETEMPLATE;
  181. }
  182. }
  183. if (lpCS->hWndOwner != NULL)
  184. {
  185. // allow hooking of the OFN struct
  186. SendMessage(lpCS->hWndOwner, uMsgBrowseOFN, ID_BROWSE_CHANGESOURCE, (LPARAM)&ofn);
  187. }
  188. // call up the dialog
  189. BOOL bResult;
  190. bResult = StandardGetOpenFileName(&ofn);
  191. // cleanup
  192. OleStdFree(lpszDirBuf);
  193. OleStdFree(lpszFileBuf);
  194. HourGlassOff(hCurSave);
  195. // map return value to OLEUI_ standard returns
  196. return bResult ? OLEUI_OK : OLEUI_CANCEL;
  197. // handle most error returns here
  198. ErrorFreeDirBuf:
  199. OleStdFree(lpszDirBuf);
  200. Error:
  201. if (hCurSave != NULL)
  202. HourGlassOff(hCurSave);
  203. return uRet;
  204. }
  205. /*
  206. * ChangeSourceHookProc
  207. *
  208. * Purpose:
  209. * Implements the OLE Change Source dialog as invoked through the
  210. * OleUIChangeSource function. This is a standard COMMDLG hook function
  211. * as opposed to a dialog proc.
  212. *
  213. * Parameters:
  214. * Standard
  215. *
  216. * Return Value:
  217. * Standard
  218. */
  219. UINT_PTR CALLBACK ChangeSourceHookProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
  220. {
  221. // Declare Win16/Win32 compatible WM_COMMAND parameters.
  222. COMMANDPARAMS(wID, wCode, hWndMsg);
  223. // This will fail under WM_INITDIALOG, where we allocate it.
  224. UINT uHook = 0;
  225. LPCHANGESOURCE lpCS = (LPCHANGESOURCE)LpvStandardEntry(hDlg, iMsg, wParam, lParam, &uHook);
  226. LPOLEUICHANGESOURCE lpOCS = NULL;
  227. if (lpCS != NULL)
  228. lpOCS = lpCS->lpOCS;
  229. // If the hook processed the message, we're done.
  230. if (0 != uHook)
  231. return uHook;
  232. // Process help message
  233. if ((iMsg == uMsgHelp) && NULL != lpOCS)
  234. {
  235. PostMessage(lpOCS->hWndOwner, uMsgHelp,
  236. (WPARAM)hDlg, MAKELPARAM(IDD_CHANGESOURCE, 0));
  237. }
  238. // Process the temination message
  239. if (iMsg == uMsgEndDialog)
  240. {
  241. // Free any specific allocations before calling StandardCleanup
  242. StandardCleanup((PVOID)lpCS, hDlg);
  243. EndDialog(hDlg, wParam);
  244. return TRUE;
  245. }
  246. // handle validation of the file name (when user hits OK)
  247. if ((iMsg == uMsgFileOKString) && (lpOCS != NULL))
  248. {
  249. // always use fully qualified name
  250. LPOPENFILENAME lpOFN = lpOCS->lpOFN;
  251. LPCTSTR lpsz = lpOFN->lpstrFile;
  252. LPTSTR lpszFile;
  253. TCHAR szPath[MAX_PATH];
  254. if (!GetFullPathName(lpsz, MAX_PATH, szPath, &lpszFile))
  255. lstrcpyn(szPath, lpsz, MAX_PATH);
  256. UINT nLenFile = lstrlen(szPath);
  257. TCHAR szItemName[MAX_PATH];
  258. GetDlgItemText(hDlg, edt2, szItemName, MAX_PATH);
  259. // combine them into szDisplayName (which is now large enough)
  260. TCHAR szDisplayName[MAX_PATH+MAX_PATH];
  261. lstrcpy(szDisplayName, szPath);
  262. if (szItemName[0] != '\0')
  263. {
  264. lstrcat(szDisplayName, TEXT("\\"));
  265. lstrcat(szDisplayName, szItemName);
  266. }
  267. if (!(lpOCS->dwFlags & CSF_ONLYGETSOURCE))
  268. {
  269. // verify the source by calling into the link container
  270. LPOLEUILINKCONTAINER lpOleUILinkCntr = lpOCS->lpOleUILinkContainer;
  271. ULONG chEaten;
  272. if (lpOleUILinkCntr->SetLinkSource(lpOCS->dwLink, szDisplayName, nLenFile,
  273. &chEaten, TRUE) != NOERROR)
  274. {
  275. // link not verified ok
  276. lpOCS->dwFlags &= ~CSF_VALIDSOURCE;
  277. UINT uRet = PopupMessage(hDlg, IDS_CHANGESOURCE, IDS_INVALIDSOURCE,
  278. MB_ICONQUESTION | MB_YESNO);
  279. if (uRet == IDYES)
  280. {
  281. SetWindowLong(hDlg, DWLP_MSGRESULT, 1);
  282. return 1; // do not close dialog
  283. }
  284. // user doesn't care if the link is valid or not
  285. lpOleUILinkCntr->SetLinkSource(lpOCS->dwLink, szDisplayName, nLenFile,
  286. &chEaten, FALSE);
  287. }
  288. else
  289. {
  290. // link was verified ok
  291. lpOCS->dwFlags |= CSF_VALIDSOURCE;
  292. }
  293. }
  294. // calculate lpszFrom and lpszTo for batch changes to links
  295. DiffPrefix(lpOCS->lpszDisplayName, szDisplayName, &lpOCS->lpszFrom, &lpOCS->lpszTo);
  296. // only keep them if the file name portion is the only part that changed
  297. if (lstrcmpi(lpOCS->lpszTo, lpOCS->lpszFrom) == 0 ||
  298. (UINT)lstrlen(lpOCS->lpszFrom) > lpOCS->nFileLength)
  299. {
  300. OleStdFree(lpOCS->lpszFrom);
  301. lpOCS->lpszFrom = NULL;
  302. OleStdFree(lpOCS->lpszTo);
  303. lpOCS->lpszTo = NULL;
  304. }
  305. // store new source in lpOCS->lpszDisplayName
  306. OleStdFree(lpOCS->lpszDisplayName);
  307. lpOCS->lpszDisplayName = OleStdCopyString(szDisplayName);
  308. lpOCS->nFileLength = nLenFile;
  309. return 0;
  310. }
  311. switch (iMsg)
  312. {
  313. case WM_NOTIFY:
  314. if (((NMHDR*)lParam)->code == CDN_HELP)
  315. {
  316. goto POSTHELP;
  317. }
  318. break;
  319. case WM_COMMAND:
  320. if (wID == pshHelp)
  321. {
  322. POSTHELP:
  323. PostMessage(lpCS->lpOCS->hWndOwner, uMsgHelp,
  324. (WPARAM)hDlg, MAKELPARAM(IDD_CHANGESOURCE, 0));
  325. }
  326. break;
  327. case WM_INITDIALOG:
  328. return FChangeSourceInit(hDlg, wParam, lParam);
  329. }
  330. return 0;
  331. }
  332. /*
  333. * FChangeSourceInit
  334. *
  335. * Purpose:
  336. * WM_INITIDIALOG handler for the Change Source dialog box.
  337. *
  338. * Parameters:
  339. * hDlg HWND of the dialog
  340. * wParam WPARAM of the message
  341. * lParam LPARAM of the message
  342. *
  343. * Return Value:
  344. * BOOL Value to return for WM_INITDIALOG.
  345. */
  346. BOOL FChangeSourceInit(HWND hDlg, WPARAM wParam, LPARAM lParam)
  347. {
  348. // Copy the structure at lParam into our instance memory.
  349. LPCHANGESOURCE lpCS = (LPCHANGESOURCE)LpvStandardInit(hDlg, sizeof(CHANGESOURCE), NULL);
  350. // PvStandardInit send a termination to us already.
  351. if (NULL == lpCS)
  352. return FALSE;
  353. LPOLEUICHANGESOURCE lpOCS=
  354. (LPOLEUICHANGESOURCE)((LPOPENFILENAME)lParam)->lCustData;
  355. lpCS->lpOCS = lpOCS;
  356. lpCS->nIDD = IDD_CHANGESOURCE;
  357. // Setup Item text box with item part of lpszDisplayName
  358. LPTSTR lpszItemName = lpOCS->lpszDisplayName + lpOCS->nFileLength;
  359. if (*lpszItemName != '\0')
  360. SetDlgItemText(hDlg, edt2, lpszItemName+1);
  361. SendDlgItemMessage(hDlg, edt2, EM_LIMITTEXT, MAX_PATH, 0L);
  362. // Change the caption
  363. if (NULL!=lpOCS->lpszCaption)
  364. SetWindowText(hDlg, lpOCS->lpszCaption);
  365. // Call the hook with lCustData in lParam
  366. UStandardHook((PVOID)lpCS, hDlg, WM_INITDIALOG, wParam, lpOCS->lCustData);
  367. #ifdef CHICO
  368. TCHAR szTemp[MAX_PATH];
  369. LoadString(_g_hOleStdResInst, IDS_CHNGSRCOKBUTTON , szTemp, MAX_PATH);
  370. CommDlg_OpenSave_SetControlText(GetParent(hDlg), IDOK, szTemp);
  371. #endif
  372. return TRUE;
  373. }
  374. /////////////////////////////////////////////////////////////////////////////