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.

1071 lines
38 KiB

  1. /*
  2. * OLE2UI.CPP
  3. *
  4. * Contains initialization routines and miscellaneous API implementations for
  5. * the OLE 2.0 User Interface Support Library.
  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 "resimage.h"
  13. #include "iconbox.h"
  14. #include <commdlg.h>
  15. #include <stdarg.h>
  16. #include "strcache.h"
  17. OLEDBGDATA
  18. // Registered messages for use with all the dialogs, registered in LibMain
  19. UINT uMsgHelp;
  20. UINT uMsgEndDialog;
  21. UINT uMsgBrowse;
  22. UINT uMsgChangeIcon;
  23. UINT uMsgFileOKString;
  24. UINT uMsgCloseBusyDlg;
  25. UINT uMsgConvert;
  26. UINT uMsgChangeSource;
  27. UINT uMsgAddControl;
  28. UINT uMsgBrowseOFN;
  29. // local function prototypes
  30. INT_PTR CALLBACK PromptUserDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam);
  31. INT_PTR CALLBACK UpdateLinksDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam);
  32. // local definition
  33. #define WM_U_UPDATELINK (WM_USER+0x2000)
  34. #define WM_U_SHOWWINDOW (WM_USER+0x2001)
  35. // local structure definition
  36. typedef struct tagUPDATELINKS
  37. {
  38. LPOLEUILINKCONTAINER lpOleUILinkCntr; // pointer to Link Container
  39. UINT cLinks; // total number of links
  40. UINT cUpdated; // number of links updated
  41. DWORD dwLink; // pointer to link
  42. BOOL fError; // error flag
  43. LPTSTR lpszTitle; // caption for dialog box
  44. } UPDATELINKS, *PUPDATELINKS, FAR *LPUPDATELINKS;
  45. /*
  46. * OleUIInitialize
  47. *
  48. * NOTE: This function should only be called by your application IF it is
  49. * using the static-link version of this library. If the DLL version is
  50. * being used, this function is automatically called from the OLEDLG DLL's
  51. * LibMain.
  52. *
  53. * Purpose:
  54. * Initializes the OLE UI Library. Registers the OLE clipboard formats
  55. * used in the Paste Special dialog, registers private custom window
  56. * messages, and registers window classes of the "Result Image"
  57. * and "Icon Box" custom controls used in the UI dialogs.
  58. *
  59. * Parameters:
  60. *
  61. * hInstance HINSTANCE of the module where the UI library resources
  62. * and Dialog Procedures are contained. If you are calling
  63. * this function yourself, this should be the instance handle
  64. * of your application.
  65. *
  66. * hPrevInst HINSTANCE of the previous application instance.
  67. * This is the parameter passed in to your WinMain. For
  68. * the DLL version, this should always be set to zero (for
  69. * WIN16 DLLs).
  70. *
  71. * Return Value:
  72. * BOOL TRUE if initialization was successful.
  73. * FALSE otherwise.
  74. */
  75. #pragma code_seg(".text$initseg")
  76. BOOL bWin4; // TRUE if running Windows4 or greater
  77. BOOL bSharedData; // TRUE if running Win32s (it has shared data)
  78. static DWORD tlsIndex= (DWORD)-1;
  79. static TASKDATA taskData;
  80. STDAPI_(TASKDATA*) GetTaskData()
  81. {
  82. TASKDATA* pData;
  83. if (tlsIndex == (DWORD)-1)
  84. pData = &taskData;
  85. else
  86. pData = (TASKDATA*)TlsGetValue(tlsIndex);
  87. return pData;
  88. }
  89. DWORD WINAPI _AfxTlsAlloc()
  90. {
  91. DWORD dwResult = TlsAlloc();
  92. DWORD dwVersion = GetVersion();
  93. if ((dwVersion & 0x80000000) && (BYTE)dwVersion <= 3)
  94. {
  95. while (dwResult <= 2)
  96. dwResult = TlsAlloc();
  97. }
  98. return dwResult;
  99. }
  100. static int nInitCount;
  101. STDAPI_(BOOL) OleUIUnInitialize();
  102. STDAPI_(BOOL) OleUIInitialize(HINSTANCE hInstance,
  103. HINSTANCE hPrevInst)
  104. {
  105. OleDbgOut1(TEXT("OleUIInitialize called.\r\n"));
  106. // Cache information about the windows version we are running
  107. DWORD dwVersion = GetVersion();
  108. bWin4 = LOBYTE(dwVersion) >= 4;
  109. bSharedData = !bWin4 && (dwVersion & 0x80000000);
  110. if (nInitCount == 0)
  111. {
  112. if (bSharedData)
  113. {
  114. // allocate thread local storage on Win32s
  115. tlsIndex = _AfxTlsAlloc();
  116. if (tlsIndex == (DWORD)-1)
  117. return FALSE;
  118. }
  119. }
  120. ++nInitCount;
  121. // Setup process local storage if necessary
  122. if (tlsIndex != (DWORD)-1)
  123. {
  124. void* pData = LocalAlloc(LPTR, sizeof(TASKDATA));
  125. if (pData == NULL)
  126. {
  127. if (nInitCount == 0)
  128. {
  129. OleUIUnInitialize();
  130. return FALSE;
  131. }
  132. }
  133. TlsSetValue(tlsIndex, pData);
  134. }
  135. // Initialize OleStd functions
  136. OleStdInitialize(hInstance, hInstance);
  137. // Register messages we need for the dialogs.
  138. uMsgHelp = RegisterWindowMessage(SZOLEUI_MSG_HELP);
  139. uMsgEndDialog = RegisterWindowMessage(SZOLEUI_MSG_ENDDIALOG);
  140. uMsgBrowse = RegisterWindowMessage(SZOLEUI_MSG_BROWSE);
  141. uMsgChangeIcon = RegisterWindowMessage(SZOLEUI_MSG_CHANGEICON);
  142. uMsgFileOKString = RegisterWindowMessage(FILEOKSTRING);
  143. uMsgCloseBusyDlg = RegisterWindowMessage(SZOLEUI_MSG_CLOSEBUSYDIALOG);
  144. uMsgConvert = RegisterWindowMessage(SZOLEUI_MSG_CONVERT);
  145. uMsgChangeSource = RegisterWindowMessage(SZOLEUI_MSG_CHANGESOURCE);
  146. uMsgAddControl = RegisterWindowMessage(SZOLEUI_MSG_ADDCONTROL);
  147. uMsgBrowseOFN = RegisterWindowMessage(SZOLEUI_MSG_BROWSE_OFN);
  148. if (!FResultImageInitialize(hInstance, hPrevInst))
  149. {
  150. OleDbgOut1(TEXT("OleUIInitialize: FResultImageInitialize failed. Terminating.\r\n"));
  151. return 0;
  152. }
  153. if (!FIconBoxInitialize(hInstance, hPrevInst))
  154. {
  155. OleDbgOut1(TEXT("OleUIInitialize: FIconBoxInitialize failed. Terminating.\r\n"));
  156. return 0;
  157. }
  158. #if USE_STRING_CACHE==1
  159. // It is ok if this fails. InsertObject dialog can do without the cache
  160. // support. InsertObjCacheUninit will cleanup as appropriate.
  161. if (!InsertObjCacheInitialize())
  162. {
  163. OleDbgOut1(TEXT("OleUIInitiallize: InsertObjCacheInit failed."));
  164. }
  165. #endif
  166. return TRUE;
  167. }
  168. #pragma code_seg()
  169. /*
  170. * OleUIUnInitialize
  171. *
  172. * NOTE: This function should only be called by your application IF it is using
  173. * the static-link version of this library. If the DLL version is being used,
  174. * this function is automatically called from the DLL's LibMain.
  175. *
  176. * Purpose:
  177. * Uninitializes OLE UI libraries. Deletes any resources allocated by the
  178. * library.
  179. *
  180. * Return Value:
  181. * BOOL TRUE if successful, FALSE if not. Current implementation always
  182. * returns TRUE.
  183. */
  184. STDAPI_(BOOL) OleUIUnInitialize()
  185. {
  186. #if USE_STRING_CACHE==1
  187. InsertObjCacheUninitialize();
  188. #endif
  189. IconBoxUninitialize();
  190. ResultImageUninitialize();
  191. // Cleanup thread local storage
  192. if (tlsIndex != (DWORD)-1)
  193. {
  194. TASKDATA* pData = (TASKDATA*)TlsGetValue(tlsIndex);
  195. TlsSetValue(tlsIndex, NULL);
  196. if (pData != NULL)
  197. {
  198. if (pData->hInstCommCtrl != NULL)
  199. FreeLibrary(pData->hInstCommCtrl);
  200. if (pData->hInstShell != NULL)
  201. FreeLibrary(pData->hInstShell);
  202. if (pData->hInstComDlg != NULL)
  203. FreeLibrary(pData->hInstComDlg);
  204. LocalFree(pData);
  205. }
  206. }
  207. // Last chance cleanup
  208. if (nInitCount == 1)
  209. {
  210. // cleanup thread local storage
  211. if (tlsIndex != (DWORD)-1)
  212. {
  213. TlsFree(tlsIndex);
  214. tlsIndex = (DWORD)-1;
  215. }
  216. }
  217. if (nInitCount != 0)
  218. --nInitCount;
  219. return TRUE;
  220. }
  221. /*
  222. * OleUIAddVerbMenu
  223. *
  224. * Purpose:
  225. * Add the Verb menu for the specified object to the given menu. If the
  226. * object has one verb, we directly add the verb to the given menu. If
  227. * the object has multiple verbs we create a cascading sub-menu.
  228. *
  229. * Parameters:
  230. * lpObj LPOLEOBJECT pointing to the selected object. If this
  231. * is NULL, then we create a default disabled menu item.
  232. *
  233. * lpszShortType LPTSTR with short type name (AuxName==2) corresponding
  234. * to the lpOleObj. if the string is NOT known, then NULL
  235. * may be passed. if NULL is passed, then
  236. * IOleObject::GetUserType will be called to retrieve it.
  237. * if the caller has the string handy, then it is faster
  238. * to pass it in.
  239. *
  240. * hMenu HMENU in which to make modifications.
  241. *
  242. * uPos Position of the menu item
  243. *
  244. * uIDVerbMin UINT_PTR ID value at which to start the verbs.
  245. * verb_0 = wIDMVerbMin + verb_0
  246. * verb_1 = wIDMVerbMin + verb_1
  247. * verb_2 = wIDMVerbMin + verb_2
  248. * etc.
  249. * uIDVerbMax UINT_PTR maximum ID value allowed for object verbs.
  250. * if uIDVerbMax==0 then any ID value is allowed
  251. *
  252. * bAddConvert BOOL specifying whether or not to add a "Convert" item
  253. * to the bottom of the menu (with a separator).
  254. *
  255. * idConvert UINT ID value to use for the Convert menu item, if
  256. * bAddConvert is TRUE.
  257. *
  258. * lphMenu HMENU FAR * of the cascading verb menu if it's created.
  259. * If there is only one verb, this will be filled with NULL.
  260. *
  261. *
  262. * Return Value:
  263. * BOOL TRUE if lpObj was valid and we added at least one verb
  264. * to the menu. FALSE if lpObj was NULL and we created
  265. * a disabled default menu item
  266. */
  267. STDAPI_(BOOL) OleUIAddVerbMenu(LPOLEOBJECT lpOleObj,
  268. LPCTSTR lpszShortType,
  269. HMENU hMenu, UINT uPos,
  270. UINT uIDVerbMin, UINT uIDVerbMax,
  271. BOOL bAddConvert, UINT idConvert,
  272. HMENU FAR *lphMenu)
  273. {
  274. LPPERSISTSTORAGE lpPS=NULL;
  275. LPENUMOLEVERB lpEnumOleVerb = NULL;
  276. OLEVERB oleverb;
  277. LPCTSTR lpszShortTypeName = lpszShortType;
  278. LPTSTR lpszVerbName = NULL;
  279. HRESULT hrErr;
  280. BOOL fStatus;
  281. BOOL fIsLink = FALSE;
  282. BOOL fResult = TRUE;
  283. BOOL fAddConvertItem = FALSE;
  284. int cVerbs = 0;
  285. UINT uFlags = MF_BYPOSITION;
  286. static BOOL fFirstTime = TRUE;
  287. static TCHAR szBuffer[OLEUI_OBJECTMENUMAX];
  288. static TCHAR szNoObjectCmd[OLEUI_OBJECTMENUMAX];
  289. static TCHAR szObjectCmd1Verb[OLEUI_OBJECTMENUMAX];
  290. static TCHAR szLinkCmd1Verb[OLEUI_OBJECTMENUMAX];
  291. static TCHAR szObjectCmdNVerb[OLEUI_OBJECTMENUMAX];
  292. static TCHAR szLinkCmdNVerb[OLEUI_OBJECTMENUMAX];
  293. static TCHAR szUnknown[OLEUI_OBJECTMENUMAX];
  294. static TCHAR szEdit[OLEUI_OBJECTMENUMAX];
  295. static TCHAR szConvert[OLEUI_OBJECTMENUMAX];
  296. // Set fAddConvertItem flag
  297. if (bAddConvert & (idConvert != 0))
  298. fAddConvertItem = TRUE;
  299. // only need to load the strings the 1st time
  300. if (fFirstTime)
  301. {
  302. if (0 == LoadString(_g_hOleStdResInst, IDS_OLE2UIEDITNOOBJCMD,
  303. szNoObjectCmd, OLEUI_OBJECTMENUMAX))
  304. return FALSE;
  305. if (0 == LoadString(_g_hOleStdResInst, IDS_OLE2UIEDITLINKCMD_1VERB,
  306. szLinkCmd1Verb, OLEUI_OBJECTMENUMAX))
  307. return FALSE;
  308. if (0 == LoadString(_g_hOleStdResInst, IDS_OLE2UIEDITOBJECTCMD_1VERB,
  309. szObjectCmd1Verb, OLEUI_OBJECTMENUMAX))
  310. return FALSE;
  311. if (0 == LoadString(_g_hOleStdResInst, IDS_OLE2UIEDITLINKCMD_NVERB,
  312. szLinkCmdNVerb, OLEUI_OBJECTMENUMAX))
  313. return FALSE;
  314. if (0 == LoadString(_g_hOleStdResInst, IDS_OLE2UIEDITOBJECTCMD_NVERB,
  315. szObjectCmdNVerb, OLEUI_OBJECTMENUMAX))
  316. return FALSE;
  317. if (0 == LoadString(_g_hOleStdResInst, IDS_OLE2UIUNKNOWN,
  318. szUnknown, OLEUI_OBJECTMENUMAX))
  319. return FALSE;
  320. if (0 == LoadString(_g_hOleStdResInst, IDS_OLE2UIEDIT,
  321. szEdit, OLEUI_OBJECTMENUMAX))
  322. return FALSE;
  323. if (0 == LoadString(_g_hOleStdResInst, IDS_OLE2UICONVERT,
  324. szConvert, OLEUI_OBJECTMENUMAX) && fAddConvertItem)
  325. return FALSE;
  326. fFirstTime = FALSE;
  327. }
  328. // Delete whatever menu may happen to be here already.
  329. DeleteMenu(hMenu, uPos, uFlags);
  330. if (lphMenu == NULL || IsBadWritePtr(lphMenu, sizeof(HMENU)))
  331. {
  332. goto AVMError;
  333. }
  334. *lphMenu=NULL;
  335. if ((!lpOleObj) || IsBadReadPtr(lpOleObj, sizeof (IOleObject)))
  336. goto AVMError;
  337. if ((!lpszShortTypeName) || IsBadReadPtr(lpszShortTypeName, sizeof(TCHAR)))
  338. {
  339. // get the Short form of the user type name for the menu
  340. OLEDBG_BEGIN2(TEXT("IOleObject::GetUserType called\r\n"))
  341. #if defined(WIN32) && !defined(UNICODE)
  342. LPOLESTR wszShortTypeName = NULL;
  343. lpszShortTypeName = NULL;
  344. hrErr = lpOleObj->GetUserType(
  345. USERCLASSTYPE_SHORT,
  346. &wszShortTypeName);
  347. if (NULL != wszShortTypeName)
  348. {
  349. UINT uLen = WTOALEN(wszShortTypeName);
  350. lpszShortTypeName = (LPTSTR) OleStdMalloc(uLen);
  351. if (NULL != lpszShortTypeName)
  352. {
  353. WTOA((char *)lpszShortTypeName, wszShortTypeName, uLen);
  354. }
  355. OleStdFree(wszShortTypeName);
  356. }
  357. #else
  358. hrErr = lpOleObj->GetUserType(
  359. USERCLASSTYPE_SHORT,
  360. (LPTSTR FAR*)&lpszShortTypeName);
  361. #endif
  362. OLEDBG_END2
  363. if (NOERROR != hrErr) {
  364. OleDbgOutHResult(TEXT("IOleObject::GetUserType returned"), hrErr);
  365. }
  366. }
  367. // check if the object is a link
  368. fIsLink = OleStdIsOleLink((LPUNKNOWN)lpOleObj);
  369. // Get the verb enumerator from the OLE object
  370. OLEDBG_BEGIN2(TEXT("IOleObject::EnumVerbs called\r\n"))
  371. hrErr = lpOleObj->EnumVerbs(
  372. (LPENUMOLEVERB FAR*)&lpEnumOleVerb
  373. );
  374. OLEDBG_END2
  375. if (NOERROR != hrErr) {
  376. OleDbgOutHResult(TEXT("IOleObject::EnumVerbs returned"), hrErr);
  377. }
  378. if (!(*lphMenu = CreatePopupMenu()))
  379. goto AVMError;
  380. // loop through all verbs
  381. while (lpEnumOleVerb != NULL)
  382. {
  383. hrErr = lpEnumOleVerb->Next(
  384. 1,
  385. (LPOLEVERB)&oleverb,
  386. NULL
  387. );
  388. if (NOERROR != hrErr)
  389. break; // DONE! no more verbs
  390. /* OLE2NOTE: negative verb numbers and verbs that do not
  391. ** indicate ONCONTAINERMENU should NOT be put on the verb menu
  392. */
  393. if (oleverb.lVerb < 0 ||
  394. ! (oleverb.grfAttribs & OLEVERBATTRIB_ONCONTAINERMENU))
  395. {
  396. /* OLE2NOTE: we must still free the verb name string */
  397. if (oleverb.lpszVerbName)
  398. OleStdFree(oleverb.lpszVerbName);
  399. continue;
  400. }
  401. // we must free the previous verb name string
  402. if (lpszVerbName)
  403. OleStdFree(lpszVerbName);
  404. #if defined(WIN32) && !defined(UNICODE)
  405. lpszVerbName = NULL;
  406. if (NULL != oleverb.lpszVerbName)
  407. {
  408. UINT uLen = WTOALEN(oleverb.lpszVerbName);
  409. lpszVerbName = (LPTSTR) OleStdMalloc(uLen);
  410. if (NULL != lpszVerbName)
  411. {
  412. WTOA(lpszVerbName, oleverb.lpszVerbName, uLen);
  413. }
  414. OleStdFree(oleverb.lpszVerbName);
  415. }
  416. #else
  417. lpszVerbName = oleverb.lpszVerbName;
  418. #endif
  419. if ( 0 == uIDVerbMax ||
  420. (uIDVerbMax >= uIDVerbMin+(UINT)oleverb.lVerb) )
  421. {
  422. fStatus = InsertMenu(
  423. *lphMenu,
  424. (UINT)-1,
  425. MF_BYPOSITION | (UINT)oleverb.fuFlags,
  426. uIDVerbMin+(UINT)oleverb.lVerb,
  427. lpszVerbName
  428. );
  429. if (! fStatus)
  430. goto AVMError;
  431. cVerbs++;
  432. }
  433. }
  434. // Add the separator and "Convert" menu item.
  435. if (fAddConvertItem)
  436. {
  437. if (0 == cVerbs)
  438. {
  439. LPTSTR lpsz;
  440. // if object has no verbs, then use "Convert" as the obj's verb
  441. lpsz = lpszVerbName = OleStdCopyString(szConvert);
  442. uIDVerbMin = (UINT)idConvert;
  443. // remove "..." from "Convert..." string; it will be added later
  444. if (lpsz)
  445. {
  446. while(*lpsz && *lpsz != '.')
  447. lpsz = CharNext(lpsz);
  448. *lpsz = '\0';
  449. }
  450. }
  451. if (cVerbs > 0)
  452. {
  453. fStatus = InsertMenu(*lphMenu,
  454. (UINT)-1,
  455. MF_BYPOSITION | MF_SEPARATOR,
  456. (UINT)0,
  457. (LPCTSTR)NULL);
  458. if (! fStatus)
  459. goto AVMError;
  460. }
  461. /* add convert menu */
  462. fStatus = InsertMenu(*lphMenu,
  463. (UINT)-1,
  464. MF_BYPOSITION,
  465. idConvert,
  466. (LPCTSTR)szConvert);
  467. if (! fStatus)
  468. goto AVMError;
  469. cVerbs++;
  470. }
  471. /*
  472. * Build the appropriate menu based on the number of verbs found
  473. *
  474. */
  475. if (cVerbs == 0)
  476. {
  477. // there are NO verbs (not even Convert...). set the menu to be
  478. // "<short type> &Object/Link" and gray it out.
  479. wsprintf(
  480. szBuffer,
  481. (fIsLink ? szLinkCmdNVerb : szObjectCmdNVerb),
  482. (lpszShortTypeName ? lpszShortTypeName : TEXT(""))
  483. );
  484. uFlags |= MF_GRAYED;
  485. fResult = FALSE;
  486. DestroyMenu(*lphMenu);
  487. *lphMenu = NULL;
  488. }
  489. else if (cVerbs == 1)
  490. {
  491. //One verb without Convert, one item.
  492. LPTSTR lpsz = (fIsLink ? szLinkCmd1Verb : szObjectCmd1Verb);
  493. // strip ampersands from lpszVerbName to ensure that
  494. // the right character is used as the menu key
  495. LPTSTR pchIn;
  496. LPTSTR pchOut;
  497. pchIn = pchOut = lpszVerbName;
  498. while (*pchIn)
  499. {
  500. while (*pchIn && '&' == *pchIn)
  501. {
  502. pchIn++;
  503. }
  504. *pchOut = *pchIn;
  505. pchOut++;
  506. pchIn++;
  507. }
  508. *pchOut = 0;
  509. FormatString2(szBuffer, lpsz, lpszVerbName, lpszShortTypeName);
  510. // if only "verb" is "Convert..." then append the ellipses
  511. if (fAddConvertItem)
  512. lstrcat(szBuffer, TEXT("..."));
  513. DestroyMenu(*lphMenu);
  514. *lphMenu=NULL;
  515. }
  516. else
  517. {
  518. //Multiple verbs or one verb with Convert, add the cascading menu
  519. wsprintf(
  520. szBuffer,
  521. (fIsLink ? szLinkCmdNVerb: szObjectCmdNVerb),
  522. (lpszShortTypeName ? lpszShortTypeName : TEXT(""))
  523. );
  524. uFlags |= MF_ENABLED | MF_POPUP;
  525. #ifdef _WIN64
  526. //
  527. // Sundown: Checking with JerrySh for the validity of the HMENU truncation...........
  528. // If not valid, this'd require modifying the prototype of this function for
  529. // uIDVerbMin & uIDVerbMax and modifying sdk\inc\oledlg.h exposed interface.
  530. //
  531. OleDbgAssert( !(((ULONG_PTR)*lphMenu) >> 32) )
  532. #endif // _WIN64
  533. uIDVerbMin=(UINT)HandleToUlong(*lphMenu);
  534. }
  535. if (!InsertMenu(hMenu, uPos, uFlags, uIDVerbMin, szBuffer))
  536. {
  537. AVMError:
  538. InsertMenu(hMenu, uPos, MF_GRAYED | uFlags,
  539. uIDVerbMin, szNoObjectCmd);
  540. fResult = FALSE;
  541. }
  542. // Redraw the menu bar, if possible
  543. HWND hWndActive = GetActiveWindow();
  544. HMENU hMenuActive = GetMenu(hWndActive);
  545. if(hMenuActive == hMenu)
  546. {
  547. DrawMenuBar(hWndActive);
  548. }
  549. if (lpszVerbName)
  550. OleStdFree(lpszVerbName);
  551. if (!lpszShortType && lpszShortTypeName)
  552. OleStdFree((LPVOID)lpszShortTypeName);
  553. if (lpEnumOleVerb)
  554. lpEnumOleVerb->Release();
  555. return fResult;
  556. }
  557. /////////////////////////////////////////////////////////////////////////////
  558. // Support for special error prompts
  559. typedef struct tagPROMPTUSER
  560. {
  561. va_list argptr;
  562. UINT nIDD; // dialog/help ID
  563. LPTSTR szTitle;
  564. } PROMPTUSER, *PPROMPTUSER, FAR* LPPROMPTUSER;
  565. /* PromptUserDlgProc
  566. * -----------------
  567. *
  568. * Purpose:
  569. * Dialog procedure used by OleUIPromptUser(). Returns when a button is
  570. * clicked in the dialog box and the button id is return.
  571. *
  572. * Parameters:
  573. * hDlg
  574. * iMsg
  575. * wParam
  576. * lParam
  577. *
  578. * Returns:
  579. *
  580. */
  581. INT_PTR CALLBACK PromptUserDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
  582. {
  583. switch (iMsg)
  584. {
  585. case WM_INITDIALOG:
  586. {
  587. SendDlgItemMessage(hDlg, IDC_PU_ICON,
  588. STM_SETICON, (WPARAM)LoadIcon(NULL, IDI_EXCLAMATION), 0L);
  589. LPPROMPTUSER lpPU = (LPPROMPTUSER)lParam;
  590. SetProp(hDlg, STRUCTUREPROP, lpPU);
  591. SetWindowText(hDlg, lpPU->szTitle);
  592. TCHAR szFormat[256];
  593. GetDlgItemText(hDlg, IDC_PU_TEXT, szFormat,
  594. sizeof(szFormat)/sizeof(TCHAR));
  595. TCHAR szBuf[256];
  596. wvsprintf(szBuf, szFormat, lpPU->argptr);
  597. SetDlgItemText(hDlg, IDC_PU_TEXT, szBuf);
  598. }
  599. return TRUE;
  600. case WM_COMMAND:
  601. EndDialog(hDlg, wParam);
  602. return TRUE;
  603. default:
  604. return FALSE;
  605. }
  606. }
  607. //+---------------------------------------------------------------------------
  608. //
  609. // Function: OleUIPromptUserInternal
  610. //
  611. // Synopsis: internal entry point to start the PromptUser dialog
  612. // Used to support both ANSI and Unicode entrypoints
  613. //
  614. // Arguments: [nTemplate] - dialog template ID
  615. // [szTitle] - the title string
  616. // [hwndParent] - the dialog's parent window
  617. // [arglist] - variable argument list
  618. //
  619. // History: 12-01-94 stevebl Created
  620. //
  621. //----------------------------------------------------------------------------
  622. int OleUIPromptUserInternal(int nTemplate, HWND hwndParent, LPTSTR szTitle, va_list arglist)
  623. {
  624. PROMPTUSER pu;
  625. pu.szTitle = szTitle;
  626. pu.argptr = arglist;
  627. pu.nIDD = nTemplate;
  628. return ((int)DialogBoxParam(_g_hOleStdResInst, MAKEINTRESOURCE(nTemplate), hwndParent,
  629. PromptUserDlgProc, (LPARAM)&pu));
  630. }
  631. /* OleUIPromptUser
  632. * ---------------
  633. *
  634. * Purpose:
  635. * Popup a dialog box with the specified template and returned the
  636. * response (button id) from the user.
  637. *
  638. * Parameters:
  639. * nTemplate resource number of the dialog
  640. * hwndParent parent of the dialog box
  641. * ... title of the dialog box followed by argument list
  642. * for the format string in the static control
  643. * (IDC_PU_TEXT) of the dialog box.
  644. * The caller has to make sure that the correct number
  645. * and type of argument are passed in.
  646. *
  647. * Returns:
  648. * button id selected by the user (template dependent)
  649. *
  650. * Comments:
  651. * the following message dialog boxes are supported:
  652. *
  653. * IDD_LINKSOURCEUNAVAILABLE -- Link source is unavailable
  654. * VARARG Parameters:
  655. * None.
  656. * Used for the following error codes:
  657. * OLE_E_CANT_BINDTOSOURCE
  658. * STG_E_PATHNOTFOUND
  659. * (sc >= MK_E_FIRST) && (sc <= MK_E_LAST) -- any Moniker error
  660. * any unknown error if object is a link
  661. *
  662. * IDD_SERVERNOTFOUND -- server registered but NOT found
  663. * VARARG Parameters:
  664. * LPSTR lpszUserType -- user type name of object
  665. * Used for the following error codes:
  666. * CO_E_APPNOTFOUND
  667. * CO_E_APPDIDNTREG
  668. * any unknown error if object is an embedded object
  669. *
  670. * IDD_SERVERNOTREG -- server NOT registered
  671. * VARARG Parameters:
  672. * LPSTR lpszUserType -- user type name of object
  673. * Used for the following error codes:
  674. * REGDB_E_CLASSNOTREG
  675. * OLE_E_STATIC -- static object with no server registered
  676. *
  677. * IDD_LINKTYPECHANGED -- class of link source changed since last binding
  678. * VARARG Parameters:
  679. * LPSTR lpszUserType -- user type name of ole link source
  680. * Used for the following error codes:
  681. * OLE_E_CLASSDIFF
  682. *
  683. * IDD_LINKTYPECHANGED -- class of link source changed since last binding
  684. * VARARG Parameters:
  685. * LPSTR lpszUserType -- user type name of ole link source
  686. * Used for the following error codes:
  687. * OLE_E_CLASSDIFF
  688. *
  689. * IDD_OUTOFMEMORY -- out of memory
  690. * VARARG Parameters:
  691. * None.
  692. * Used for the following error codes:
  693. * E_OUTOFMEMORY
  694. *
  695. */
  696. int FAR CDECL OleUIPromptUser(int nTemplate, HWND hwndParent, ...)
  697. {
  698. va_list arglist;
  699. va_start(arglist, hwndParent);
  700. LPTSTR szTitle = va_arg(arglist, LPTSTR);
  701. int nRet = OleUIPromptUserInternal(nTemplate, hwndParent, szTitle, arglist);
  702. va_end(arglist);
  703. return nRet;
  704. }
  705. /* UpdateLinksDlgProc
  706. * ------------------
  707. *
  708. * Purpose:
  709. * Dialog procedure used by OleUIUpdateLinks(). It will enumerate all
  710. * all links in the container and updates all automatic links.
  711. * Returns when the Stop Button is clicked in the dialog box or when all
  712. * links are updated
  713. *
  714. * Parameters:
  715. * hDlg
  716. * iMsg
  717. * wParam
  718. * lParam pointer to the UPDATELINKS structure
  719. *
  720. * Returns:
  721. *
  722. */
  723. #define UPDATELINKS_STARTDELAY 2000 // delay before 1st link updates
  724. INT_PTR CALLBACK UpdateLinksDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
  725. {
  726. LPUPDATELINKS FAR* lplpUL = NULL;
  727. HANDLE gh;
  728. static BOOL fAbort = FALSE;
  729. // Process the temination message
  730. if (iMsg == uMsgEndDialog)
  731. {
  732. gh = RemoveProp(hDlg, STRUCTUREPROP);
  733. if (NULL != gh)
  734. {
  735. GlobalUnlock(gh);
  736. GlobalFree(gh);
  737. }
  738. EndDialog(hDlg, wParam);
  739. return TRUE;
  740. }
  741. switch (iMsg)
  742. {
  743. case WM_INITDIALOG:
  744. {
  745. gh = GlobalAlloc(GHND, sizeof(LPUPDATELINKS));
  746. SetProp(hDlg, STRUCTUREPROP, gh);
  747. if (NULL == gh)
  748. {
  749. PostMessage(hDlg, uMsgEndDialog, OLEUI_ERR_GLOBALMEMALLOC,0L);
  750. return FALSE;
  751. }
  752. fAbort = FALSE;
  753. lplpUL = (LPUPDATELINKS FAR*)GlobalLock(gh);
  754. if (!lplpUL)
  755. {
  756. PostMessage(hDlg, uMsgEndDialog, OLEUI_ERR_GLOBALMEMALLOC,0L);
  757. return FALSE;
  758. }
  759. if (bWin4)
  760. {
  761. if (StandardInitCommonControls() >= 0)
  762. {
  763. // get rect of the existing "progress" control
  764. RECT rect;
  765. GetWindowRect(GetDlgItem(hDlg, IDC_UL_METER), &rect);
  766. ScreenToClient(hDlg, ((POINT*)&rect)+0);
  767. ScreenToClient(hDlg, ((POINT*)&rect)+1);
  768. // create progress control in that rect
  769. HWND hProgress = CreateWindowEx(
  770. 0, PROGRESS_CLASS, NULL, WS_CHILD|WS_VISIBLE,
  771. rect.left, rect.top,
  772. rect.right-rect.left, rect.bottom-rect.top, hDlg,
  773. (HMENU)IDC_UL_PROGRESS, _g_hOleStdInst, NULL);
  774. if (hProgress != NULL)
  775. {
  776. // initialize the progress control
  777. SendMessage(hProgress, PBM_SETRANGE, 0, MAKELONG(0, 100));
  778. // hide the other "meter" control
  779. StandardShowDlgItem(hDlg, IDC_UL_METER, SW_HIDE);
  780. }
  781. }
  782. }
  783. *lplpUL = (LPUPDATELINKS)lParam;
  784. if ((*lplpUL)->lpszTitle)
  785. {
  786. SetWindowText(hDlg, (*lplpUL)->lpszTitle);
  787. }
  788. SetTimer(hDlg, 1, UPDATELINKS_STARTDELAY, NULL);
  789. return TRUE;
  790. }
  791. case WM_TIMER:
  792. KillTimer(hDlg, 1);
  793. gh = GetProp(hDlg, STRUCTUREPROP);
  794. if (NULL!=gh)
  795. {
  796. // gh was locked previously, lock and unlock to get lplpUL
  797. lplpUL = (LPUPDATELINKS*)GlobalLock(gh);
  798. GlobalUnlock(gh);
  799. }
  800. if (! fAbort && lplpUL)
  801. PostMessage(hDlg, WM_U_UPDATELINK, 0, (LPARAM)(*lplpUL));
  802. else
  803. PostMessage(hDlg,uMsgEndDialog,OLEUI_CANCEL,0L);
  804. return 0;
  805. case WM_COMMAND: // Stop button
  806. fAbort = TRUE;
  807. SendMessage(hDlg, uMsgEndDialog, OLEUI_OK, 0L);
  808. return TRUE;
  809. case WM_U_UPDATELINK:
  810. {
  811. HRESULT hErr;
  812. int nPercent;
  813. RECT rc;
  814. TCHAR szPercent[5]; // 0% to 100%
  815. HBRUSH hbr;
  816. HDC hDC;
  817. HWND hwndMeter;
  818. MSG msg;
  819. DWORD dwUpdateOpt;
  820. LPUPDATELINKS lpUL = (LPUPDATELINKS)lParam;
  821. lpUL->dwLink=lpUL->lpOleUILinkCntr->GetNextLink(lpUL->dwLink);
  822. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  823. {
  824. if (! IsDialogMessage(hDlg, &msg))
  825. {
  826. TranslateMessage(&msg);
  827. DispatchMessage(&msg);
  828. }
  829. }
  830. if (fAbort)
  831. return FALSE;
  832. if (!lpUL->dwLink)
  833. {
  834. // all links processed
  835. SendMessage(hDlg, uMsgEndDialog, OLEUI_OK, 0L);
  836. return TRUE;
  837. }
  838. hErr = lpUL->lpOleUILinkCntr->GetLinkUpdateOptions(
  839. lpUL->dwLink, (LPDWORD)&dwUpdateOpt);
  840. if ((hErr == NOERROR) && (dwUpdateOpt == OLEUPDATE_ALWAYS))
  841. {
  842. hErr = lpUL->lpOleUILinkCntr->UpdateLink(lpUL->dwLink, FALSE, FALSE);
  843. lpUL->fError |= (hErr != NOERROR);
  844. lpUL->cUpdated++;
  845. nPercent = (lpUL->cLinks > 0) ? (lpUL->cUpdated * 100 / lpUL->cLinks) : 100;
  846. if (nPercent <= 100)
  847. {
  848. // update percentage
  849. wsprintf(szPercent, TEXT("%d%%"), nPercent);
  850. SetDlgItemText(hDlg, IDC_UL_PERCENT, szPercent);
  851. HWND hProgress = GetDlgItem(hDlg, IDC_UL_PROGRESS);
  852. if (hProgress == NULL)
  853. {
  854. // update indicator
  855. hwndMeter = GetDlgItem(hDlg, IDC_UL_METER);
  856. GetClientRect(hwndMeter, (LPRECT)&rc);
  857. InflateRect((LPRECT)&rc, -1, -1);
  858. rc.right = (rc.right - rc.left) * nPercent / 100 + rc.left;
  859. hbr = CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT));
  860. if (hbr)
  861. {
  862. hDC = GetDC(hwndMeter);
  863. if (hDC)
  864. {
  865. FillRect(hDC, (LPRECT)&rc, hbr);
  866. ReleaseDC(hwndMeter, hDC);
  867. }
  868. DeleteObject(hbr);
  869. }
  870. }
  871. else
  872. {
  873. // update the progress indicator
  874. SendMessage(hProgress, PBM_SETPOS, nPercent, 0);
  875. }
  876. }
  877. }
  878. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  879. {
  880. if (! IsDialogMessage(hDlg, &msg))
  881. {
  882. TranslateMessage(&msg);
  883. DispatchMessage(&msg);
  884. }
  885. }
  886. PostMessage(hDlg, WM_U_UPDATELINK, 0, lParam);
  887. }
  888. return TRUE;
  889. case WM_U_SHOWWINDOW:
  890. ShowWindow(hDlg, SW_SHOW);
  891. return TRUE;
  892. }
  893. return FALSE;
  894. }
  895. /* OleUIUpdateLinkS
  896. * ----------------
  897. *
  898. * Purpose:
  899. * Update all links in the Link Container and popup a dialog box which
  900. * shows the progress of the updating.
  901. * The process is stopped when the user press Stop button or when all
  902. * links are processed.
  903. *
  904. * Parameters:
  905. * lpOleUILinkCntr pointer to Link Container
  906. * hwndParent parent window of the dialog
  907. * lpszTitle title of the dialog box
  908. * cLinks total number of links
  909. *
  910. * Returns:
  911. * TRUE all links updated successfully or user aborted dialog
  912. * FALSE oherwise
  913. */
  914. STDAPI_(BOOL) OleUIUpdateLinks(
  915. LPOLEUILINKCONTAINER lpOleUILinkCntr, HWND hwndParent, LPTSTR lpszTitle, int cLinks)
  916. {
  917. LPUPDATELINKS lpUL = (LPUPDATELINKS)OleStdMalloc(sizeof(UPDATELINKS));
  918. if (lpUL == NULL)
  919. return FALSE;
  920. BOOL fError = TRUE;
  921. // Validate interface.
  922. if (NULL == lpOleUILinkCntr || IsBadReadPtr(lpOleUILinkCntr, sizeof(IOleUILinkContainer)))
  923. goto Error;
  924. // Validate parent-window handle. NULL is considered valid.
  925. if (NULL != hwndParent && !IsWindow(hwndParent))
  926. goto Error;
  927. // Validate the dialog title. NULL is considered valid.
  928. if (NULL != lpszTitle && IsBadReadPtr(lpszTitle, 1))
  929. goto Error;
  930. if (cLinks < 0)
  931. goto Error;
  932. OleDbgAssert(lpOleUILinkCntr && hwndParent && lpszTitle && (cLinks>0));
  933. OleDbgAssert(lpUL);
  934. lpUL->lpOleUILinkCntr = lpOleUILinkCntr;
  935. lpUL->cLinks = cLinks;
  936. lpUL->cUpdated = 0;
  937. lpUL->dwLink = 0;
  938. lpUL->fError = FALSE;
  939. lpUL->lpszTitle = lpszTitle;
  940. DialogBoxParam(_g_hOleStdResInst, MAKEINTRESOURCE(IDD_UPDATELINKS),
  941. hwndParent, UpdateLinksDlgProc, (LPARAM)lpUL);
  942. fError = lpUL->fError;
  943. Error:
  944. OleStdFree((LPVOID)lpUL);
  945. return !fError;
  946. }