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.

911 lines
33 KiB

  1. #include "privcpp.h"
  2. #include <initguid.h>
  3. #include "packguid.h"
  4. HWND g_hTaskWnd;
  5. BOOL CALLBACK GetTaskWndProc(HWND hwnd, DWORD lParam);
  6. DWORD CALLBACK MainWaitOnChildThreadProc(void *lpv);
  7. BOOL IsProgIDInList(LPCTSTR pszProgID, LPCTSTR pszExt, const LPCTSTR *arszList, UINT nExt);
  8. typedef struct
  9. {
  10. IStream * pIStreamIOleCommandTarget; // an interface we can marshal
  11. HANDLE h;
  12. } MAINWAITONCHILD;
  13. //
  14. HRESULT CPackage::SetClientSite(LPOLECLIENTSITE pClientSite)
  15. {
  16. DebugMsg(DM_TRACE, "pack oo - SetClientSite() called.");
  17. if (_pIOleClientSite)
  18. _pIOleClientSite->Release();
  19. _pIOleClientSite = pClientSite;
  20. if (_pIOleClientSite)
  21. _pIOleClientSite->AddRef();
  22. return S_OK;
  23. }
  24. HRESULT CPackage::GetClientSite(LPOLECLIENTSITE *ppClientSite)
  25. {
  26. DebugMsg(DM_TRACE, "pack oo - GetClientSite() called.");
  27. if (ppClientSite == NULL)
  28. return E_INVALIDARG;
  29. // Be sure to AddRef the pointer we're giving away.
  30. *ppClientSite = _pIOleClientSite;
  31. _pIOleClientSite->AddRef();
  32. return S_OK;
  33. }
  34. HRESULT CPackage::SetHostNames(LPCOLESTR szContainerApp, LPCOLESTR szContainerObj)
  35. {
  36. DebugMsg(DM_TRACE, "pack oo - SetHostNames() called.");
  37. delete [] _lpszContainerApp;
  38. DWORD cch = lstrlenW(szContainerApp) + 1;
  39. if (NULL != (_lpszContainerApp = new OLECHAR[cch]))
  40. {
  41. StringCchCopy(_lpszContainerApp, cch, szContainerApp);
  42. }
  43. delete [] _lpszContainerObj;
  44. cch = lstrlenW(szContainerObj) + 1;
  45. if (NULL != (_lpszContainerObj = new OLECHAR[cch]))
  46. {
  47. StringCchCopy(_lpszContainerObj,cch, szContainerObj);
  48. }
  49. switch(_panetype) {
  50. case PEMBED:
  51. if (_pEmbed->poo)
  52. _pEmbed->poo->SetHostNames(szContainerApp,szContainerObj);
  53. break;
  54. case CMDLINK:
  55. // nothing to do...we're a link to a file, so we don't ever get
  56. // opened and need to be edited or some such thing.
  57. break;
  58. }
  59. return S_OK;
  60. }
  61. HRESULT CPackage::Close(DWORD dwSaveOption)
  62. {
  63. DebugMsg(DM_TRACE, "pack oo - Close() called.");
  64. switch (_panetype) {
  65. case PEMBED:
  66. if (_pEmbed == NULL)
  67. return S_OK;
  68. // tell the server to close, and release our pointer to it
  69. if (_pEmbed->poo)
  70. {
  71. _pEmbed->poo->Close(dwSaveOption); // Unadvise/release done in OnClose
  72. }
  73. break;
  74. case CMDLINK:
  75. // again, nothing to do...we shouldn't be getting close
  76. // messages since we're never activated through OLE.
  77. break;
  78. }
  79. if ((dwSaveOption != OLECLOSE_NOSAVE) && (_fIsDirty))
  80. {
  81. _pIOleClientSite->SaveObject();
  82. if (_pIOleAdviseHolder)
  83. _pIOleAdviseHolder->SendOnSave();
  84. }
  85. return S_OK;
  86. }
  87. HRESULT CPackage::SetMoniker(DWORD dwWhichMoniker, LPMONIKER pmk)
  88. {
  89. DebugMsg(DM_TRACE, "pack oo - SetMoniker() called.");
  90. // NOTE: Uninteresting for embeddings only.
  91. return (E_NOTIMPL);
  92. }
  93. HRESULT CPackage::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker,
  94. LPMONIKER *ppmk)
  95. {
  96. DebugMsg(DM_TRACE, "pack oo - GetMoniker() called.");
  97. // NOTE: Unintersting for embeddings only.
  98. return (E_NOTIMPL);
  99. }
  100. HRESULT CPackage::InitFromData(LPDATAOBJECT pDataObject, BOOL fCreation,
  101. DWORD dwReserved)
  102. {
  103. DebugMsg(DM_TRACE, "pack oo - InitFromData() called.");
  104. // NOTE: This isn't supported at this time
  105. return (E_NOTIMPL);
  106. }
  107. HRESULT CPackage::GetClipboardData(DWORD dwReserved, LPDATAOBJECT *ppDataObject)
  108. {
  109. DebugMsg(DM_TRACE, "pack oo - GetClipboardData() called.");
  110. if (ppDataObject == NULL)
  111. return E_INVALIDARG;
  112. *ppDataObject = this; // ->_pIDataObject;
  113. AddRef();
  114. return S_OK;
  115. }
  116. HRESULT CPackage::DoVerb(LONG iVerb, LPMSG lpmsg, LPOLECLIENTSITE pActiveSite,
  117. LONG lindex, HWND hwndParent, LPCRECT lprcPosRect)
  118. {
  119. void *lpFileData = NULL;
  120. BOOL fError = TRUE;
  121. SHELLEXECUTEINFO sheinf = {sizeof(SHELLEXECUTEINFO)};
  122. HRESULT hr ;
  123. DebugMsg(DM_TRACE, "pack oo - DoVerb() called.");
  124. DebugMsg(DM_TRACE, " iVerb==%d",iVerb);
  125. // We allow show, primary verb, edit, and context menu verbs on our packages...
  126. //
  127. if (iVerb < OLEIVERB_SHOW)
  128. return E_NOTIMPL;
  129. // Some applications (WordPerfect 10 for one) give us incorrect verb numbers
  130. // In that case they are giving us OLEIVERB_SHOW for activation
  131. if(OLEIVERB_SHOW == iVerb)
  132. {
  133. if(_pEmbed && _pEmbed->fd.cFileName)
  134. iVerb = OLEIVERB_PRIMARY;
  135. }
  136. else if(2 == iVerb)
  137. {
  138. // And they give us a 2 (menu item position) for "Properties
  139. iVerb = _iPropertiesMenuItem;
  140. }
  141. /////////////////////////////////////////////////////////////////
  142. // SHOW VERB
  143. /////////////////////////////////////////////////////////////////
  144. //
  145. if (iVerb == OLEIVERB_SHOW) {
  146. PACKAGER_INFO packInfo = {0};
  147. // Run the Wizard...
  148. #ifdef USE_RESOURCE_DLL
  149. HINSTANCE hInstRes = LoadLibraryEx(L"sp1res.dll", NULL, LOAD_LIBRARY_AS_DATAFILE);
  150. if(!hInstRes)
  151. return E_FAIL;
  152. g_hinstResDLL = hInstRes;
  153. #endif
  154. PackWiz_CreateWizard(hwndParent, &packInfo);
  155. if(0 == lstrlen(packInfo.szFilename))
  156. {
  157. return S_OK;
  158. }
  159. HRESULT hr = InitFromPackInfo(&packInfo);
  160. #ifdef USE_RESOURCE_DLL
  161. FreeLibrary(hInstRes);
  162. #endif
  163. return hr;
  164. }
  165. /////////////////////////////////////////////////////////////////
  166. // EDIT PACKAGE VERB
  167. /////////////////////////////////////////////////////////////////
  168. //
  169. else if (iVerb == OLEIVERB_EDITPACKAGE)
  170. {
  171. // Call the edit package dialog. Which dialog is ultimately called will
  172. // depend on whether we're a cmdline package or an embedded file
  173. // package.
  174. int idDlg;
  175. PACKAGER_INFO packInfo;
  176. ZeroMemory(&packInfo, sizeof(PACKAGER_INFO));
  177. int ret;
  178. StringCchCopy(packInfo.szLabel, ARRAYSIZE(packInfo.szLabel), _lpic->szIconText);
  179. StringCchCopy(packInfo.szIconPath, ARRAYSIZE(packInfo.szIconPath), _lpic->szIconPath);
  180. packInfo.iIcon = _lpic->iDlgIcon;
  181. switch(_panetype)
  182. {
  183. case PEMBED:
  184. if(!PathFileExists(_pEmbed->fd.cFileName))
  185. {
  186. #ifdef USE_RESOURCE_DLL
  187. HINSTANCE hInstRes = LoadLibraryEx(L"sp1res.dll", NULL, LOAD_LIBRARY_AS_DATAFILE);
  188. if(!hInstRes)
  189. return E_FAIL;
  190. #endif
  191. ShellMessageBox(hInstRes,
  192. NULL,
  193. MAKEINTRESOURCE(IDS_CANNOT_EDIT_PACKAGE),
  194. MAKEINTRESOURCE(IDS_APP_TITLE),
  195. MB_ICONERROR | MB_TASKMODAL | MB_OK);
  196. #ifdef USE_RESOURCE_DLL
  197. FreeLibrary(hInstRes);
  198. #endif
  199. return S_OK;
  200. }
  201. StringCchCopy(packInfo.szFilename, ARRAYSIZE(packInfo.szFilename), _pEmbed->fd.cFileName);
  202. idDlg = IDD_EDITEMBEDPACKAGE;
  203. break;
  204. case CMDLINK:
  205. StringCchCopy(packInfo.szFilename, ARRAYSIZE(packInfo.szFilename), _pCml->szCommandLine);
  206. idDlg = IDD_EDITCMDPACKAGE;
  207. break;
  208. }
  209. #ifdef USE_RESOURCE_DLL
  210. HINSTANCE hInstRes = LoadLibraryEx(L"sp1res.dll", NULL, LOAD_LIBRARY_AS_DATAFILE);
  211. if(!hInstRes)
  212. return E_FAIL;
  213. g_hinstResDLL = hInstRes;
  214. #endif
  215. ret = PackWiz_EditPackage(hwndParent, idDlg, &packInfo);
  216. #ifdef USE_RESOURCE_DLL
  217. FreeLibrary(hInstRes);
  218. #endif
  219. // If User cancels the edit package...just return.
  220. if (ret == -1)
  221. return S_OK;
  222. switch(_panetype)
  223. {
  224. case PEMBED:
  225. if (_pEmbed->pszTempName)
  226. {
  227. // It's possible that the file name was changed, so our temp file name could be out of date
  228. DeleteFile(_pEmbed->pszTempName);
  229. delete [] _pEmbed->pszTempName;
  230. _pEmbed->pszTempName = NULL;
  231. _fLoaded = FALSE;
  232. ReleaseContextMenu();
  233. }
  234. InitFromPackInfo(&packInfo);
  235. break;
  236. case CMDLINK:
  237. InitFromPackInfo(&packInfo);
  238. break;
  239. }
  240. return S_OK;
  241. }
  242. else if (iVerb == OLEIVERB_PRIMARY)
  243. {
  244. /////////////////////////////////////////////////////////////////
  245. // ACTIVATE CONTENTS VERB
  246. /////////////////////////////////////////////////////////////////
  247. // NOTE: This is kind of crazy looking code, partially because we have
  248. // to worry about two ways of launching things--ShellExecuteEx and
  249. // calling through OLE.
  250. //
  251. switch(_panetype)
  252. {
  253. case PEMBED:
  254. {
  255. // ok, we now have a file name. If necessary give a warning message to the user before
  256. // proceeding.
  257. if(IDCANCEL == _GiveWarningMsg())
  258. return S_OK;
  259. // if this is an OLE file then, activate through OLE
  260. // Note that the only way to know is if this fails. We start out all files as OLE the first time
  261. if (_pEmbed->fIsOleFile)
  262. {
  263. // If we've activated the server, then we can just pass this
  264. // call along to it.
  265. _bClosed = FALSE;
  266. if (_pEmbed->poo)
  267. {
  268. return _pEmbed->poo->DoVerb(iVerb,lpmsg, pActiveSite,lindex, hwndParent, lprcPosRect);
  269. }
  270. // We don't want to use OleCreateFromFile since that can turn around and create a packaged object...
  271. CLSID clsid;
  272. hr = GetClassFile(_pEmbed->pszTempName, &clsid);
  273. if (SUCCEEDED(hr))
  274. {
  275. IOleObject* poo;
  276. hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, IID_IOleObject, (void **)&poo);
  277. if (SUCCEEDED(hr))
  278. {
  279. hr = poo->Advise(this, &_dwCookie);
  280. if (SUCCEEDED(hr))
  281. {
  282. // NOTE: apparently we have to call
  283. // OleRun before we can get IPersistFile from some apps, namely
  284. // Word and Excel. If we don't call OleRun, they fail our QI
  285. // for IPersistfile.
  286. OleRun(poo);
  287. IPersistFile* ppf;
  288. hr = poo->QueryInterface(IID_IPersistFile, (void **)&ppf);
  289. if (SUCCEEDED(hr))
  290. {
  291. hr = ppf->Load(_pEmbed->pszTempName, STGM_READWRITE | STGM_SHARE_DENY_WRITE);
  292. if (SUCCEEDED(hr))
  293. {
  294. hr = poo->DoVerb(iVerb, lpmsg, pActiveSite, lindex, hwndParent, lprcPosRect);
  295. if (SUCCEEDED(hr))
  296. {
  297. // By passing NULL for the container object, this forces apps such
  298. // as Office to save to our temp file rather than something like
  299. // "Document in Outer.doc".
  300. poo->SetHostNames(_lpszContainerApp, NULL); // _lpszContainerObj
  301. if (!_fNoIOleClientSiteCalls)
  302. {
  303. _pIOleClientSite->ShowObject();
  304. _pIOleClientSite->OnShowWindow(TRUE);
  305. }
  306. _pEmbed->poo = poo; // save this so when we get a
  307. poo = NULL;
  308. }
  309. }
  310. ppf->Release();
  311. }
  312. if (FAILED(hr))
  313. poo->Unadvise(_dwCookie);
  314. }
  315. if (FAILED(hr))
  316. poo->Release();
  317. }
  318. }
  319. // This flag gets set in the our IExternalConnection ReleaseConnection method.
  320. // Some applications (MSPaint for one) give us a final release before we get here
  321. // so we can safely assume that we're done and can close.
  322. if(_bCloseIt)
  323. {
  324. OnClose();
  325. }
  326. if (SUCCEEDED(hr))
  327. return hr;
  328. // We weren't an OLE file after all, change our state to reflect this,
  329. // and fall through to try the ShellExecuteEx
  330. _pEmbed->fIsOleFile = FALSE;
  331. _fIsDirty = TRUE;
  332. }
  333. // Try to execute the file
  334. _pEmbed->hTask = NULL;
  335. sheinf.fMask = SEE_MASK_NOCLOSEPROCESS;
  336. sheinf.lpFile = _pEmbed->pszTempName;
  337. sheinf.nShow = SW_SHOWNORMAL;
  338. if (ShellExecuteEx(&sheinf))
  339. {
  340. // if we get a valid process handle, we want to create a thread
  341. // to wait for the process to exit so we know when we can load
  342. // the tempfile back into memory.
  343. //
  344. if (sheinf.hProcess)
  345. {
  346. _pEmbed->hTask = sheinf.hProcess;
  347. MAINWAITONCHILD *pmwoc = new MAINWAITONCHILD;
  348. if(!pmwoc)
  349. {
  350. CloseHandle(sheinf.hProcess);
  351. return E_OUTOFMEMORY;
  352. }
  353. HRESULT hr;
  354. hr = CoMarshalInterThreadInterfaceInStream(IID_IOleCommandTarget, (IUnknown*)static_cast<IDataObject*>(this), &pmwoc->pIStreamIOleCommandTarget);
  355. if(FAILED(hr))
  356. {
  357. CloseHandle(sheinf.hProcess);
  358. delete pmwoc;
  359. return hr;
  360. }
  361. if (pmwoc)
  362. {
  363. pmwoc->h = sheinf.hProcess;
  364. if(SHCreateThread(MainWaitOnChildThreadProc, pmwoc, CTF_COINIT , NULL))
  365. fError = FALSE;
  366. else
  367. {
  368. CloseHandle(sheinf.hProcess);
  369. return E_FAIL;
  370. }
  371. }
  372. }
  373. // NOTE: there's not much we can do if the ShellExecute
  374. // succeeds and we don't get a valid handle back. we'll just
  375. // load from the temp file when we're asked to save and hope
  376. // for the best.
  377. // According to ShellExecuteEx, if hInstApp > 32 then we succeeded. This is a DDE launch
  378. // rather than a CreateProcess. However, since we don't have the hProcess, we have nothing
  379. // to wait for.
  380. if(!sheinf.hProcess && reinterpret_cast<INT_PTR>(sheinf.hInstApp) > 32)
  381. {
  382. _fIsDirty = TRUE;
  383. return S_OK;
  384. }
  385. }
  386. else // ShellExecuteEx failed!
  387. {
  388. return E_FAIL;
  389. }
  390. // show that the object is now active
  391. if (!fError && !_fNoIOleClientSiteCalls)
  392. {
  393. _pIOleClientSite->ShowObject();
  394. _pIOleClientSite->OnShowWindow(TRUE);
  395. }
  396. return fError ? E_FAIL : S_OK;
  397. }
  398. case CMDLINK:
  399. if(gCmdLineOK)
  400. {
  401. TCHAR szPath[MAX_PATH];
  402. TCHAR szArgs[CBCMDLINKMAX-MAX_PATH];
  403. StringCchCopy(szPath, ARRAYSIZE(szPath), _pCml->szCommandLine);
  404. PathSeparateArgs(szPath, szArgs, ARRAYSIZE(szPath));
  405. sheinf.fMask = SEE_MASK_NOCLOSEPROCESS;
  406. sheinf.lpFile = szPath;
  407. sheinf.lpParameters = szArgs;
  408. sheinf.nShow = SW_SHOWNORMAL;
  409. // NOTE: This code is much nicer than ShellExec-ing an embedded
  410. // file. Here, we just need to ShellExec the command line and
  411. // the we're done. We don't need to know when that process
  412. // finishes or anything else.
  413. return ShellExecuteEx(&sheinf)? S_OK:E_FAIL;
  414. }
  415. else
  416. {
  417. #ifdef USE_RESOURCE_DLL
  418. HINSTANCE hInstRes = LoadLibraryEx(L"sp1res.dll", NULL, LOAD_LIBRARY_AS_DATAFILE);
  419. if(!hInstRes)
  420. return E_FAIL;
  421. #endif
  422. ShellMessageBox(hInstRes,
  423. NULL,
  424. MAKEINTRESOURCE(IDS_COMMAND_LINE_NOT_ALLOWED),
  425. MAKEINTRESOURCE(IDS_APP_TITLE),
  426. MB_ICONERROR | MB_TASKMODAL | MB_OK);
  427. #ifdef USE_RESOURCE_DLL
  428. FreeLibrary(hInstRes);
  429. #endif
  430. }
  431. break;
  432. case PACKAGE:
  433. {
  434. PACKAGER_INFO packInfo = {0};
  435. ASSERT(_pCml);
  436. StringCchCopy(packInfo.szFilename, ARRAYSIZE(packInfo.szFilename), _pCml->szCommandLine);
  437. // Run the Wizard...
  438. #ifdef USE_RESOURCE_DLL
  439. HINSTANCE hInstRes = LoadLibraryEx(L"sp1res.dll", NULL, LOAD_LIBRARY_AS_DATAFILE);
  440. if(!hInstRes)
  441. return E_FAIL;
  442. g_hinstResDLL = hInstRes;
  443. #endif
  444. PackWiz_CreateWizard(hwndParent, &packInfo);
  445. HRESULT hr = InitFromPackInfo(&packInfo);
  446. #ifdef USE_RESOURCE_DLL
  447. FreeLibrary(hInstRes);
  448. #endif
  449. return hr;
  450. }
  451. break;
  452. }
  453. }
  454. else
  455. {
  456. // Let's see if it is a context menu verb:
  457. HRESULT hr;
  458. IContextMenu* pcm;
  459. if (SUCCEEDED(hr = GetContextMenu(&pcm)))
  460. {
  461. HMENU hmenu = CreatePopupMenu();
  462. if (NULL != hmenu)
  463. {
  464. if (SUCCEEDED(hr = pcm->QueryContextMenu(hmenu,
  465. 0,
  466. OLEIVERB_FIRST_CONTEXT,
  467. OLEIVERB_LAST_CONTEXT,
  468. CMF_NORMAL)))
  469. {
  470. MENUITEMINFO mii;
  471. mii.cbSize = sizeof(mii);
  472. mii.fMask = MIIM_ID;
  473. if (GetMenuItemInfo(hmenu, (UINT) (iVerb - OLEIVERB_FIRST_CONTEXT), TRUE, &mii))
  474. {
  475. if (PEMBED == _panetype)
  476. {
  477. // If we have an embedding, we have to make sure that
  478. // the temp file is created before we execute a command:
  479. hr =CreateTempFile();
  480. }
  481. if (SUCCEEDED(hr))
  482. {
  483. CMINVOKECOMMANDINFO ici;
  484. ici.cbSize = sizeof(ici);
  485. ici.fMask = 0;
  486. ici.hwnd = NULL;
  487. ici.lpVerb = (LPCSTR) IntToPtr(mii.wID - OLEIVERB_FIRST_CONTEXT);
  488. ici.lpParameters = NULL;
  489. ici.lpDirectory = NULL;
  490. ici.nShow = SW_SHOWNORMAL;
  491. // REVIEW: should we return OLEOBJ_S_CANNOT_DOVERB_NOW if this fails?
  492. hr = pcm->InvokeCommand(&ici);
  493. }
  494. }
  495. else
  496. {
  497. hr = OLEOBJ_S_CANNOT_DOVERB_NOW;
  498. }
  499. }
  500. DestroyMenu(hmenu);
  501. }
  502. else
  503. {
  504. hr = E_OUTOFMEMORY;
  505. }
  506. pcm->Release();
  507. }
  508. return hr;
  509. }
  510. return E_FAIL;
  511. }
  512. HRESULT CPackage::EnumVerbs(LPENUMOLEVERB *ppEnumOleVerb)
  513. {
  514. DebugMsg(DM_TRACE, "pack oo - EnumVerbs() called.");
  515. HRESULT hr;
  516. IContextMenu* pcm;
  517. // tell the package to release the cached context menu:
  518. ReleaseContextMenu();
  519. if (SUCCEEDED(hr = GetContextMenu(&pcm)))
  520. {
  521. HMENU hmenu = CreatePopupMenu();
  522. if (NULL != hmenu)
  523. {
  524. if (SUCCEEDED(hr = pcm->QueryContextMenu(hmenu,
  525. 0,
  526. OLEIVERB_FIRST_CONTEXT,
  527. OLEIVERB_LAST_CONTEXT,
  528. CMF_NORMAL)))
  529. {
  530. // FEATURE: remove problematic items by canonical names
  531. int nItems = GetMenuItemCount(hmenu);
  532. if (nItems > 0)
  533. {
  534. const DWORD cdwNumVerbs = 3; // (3) change if the number of registry verbs changes
  535. OLEVERB* pVerbs = new OLEVERB[nItems + cdwNumVerbs];
  536. if(!pVerbs)
  537. return E_OUTOFMEMORY;
  538. // NOTE: we allocate nItems, but we may not use all of them
  539. // First, get the registry based verbs
  540. IEnumOLEVERB * pIVerbEnum;
  541. UINT cRegFetched = 0;
  542. if(SUCCEEDED(OleRegEnumVerbs(CLSID_CPackage, &pIVerbEnum)))
  543. {
  544. // There are currently only two, but ask for cdwNumVerbs to double check
  545. pIVerbEnum->Next(cdwNumVerbs, pVerbs, (ULONG *) &cRegFetched);
  546. ASSERT(cRegFetched < cdwNumVerbs);
  547. if(cRegFetched)
  548. {
  549. for(UINT i = 0; i < (ULONG) cRegFetched; i++)
  550. {
  551. InsertMenu(hmenu, i, MF_BYPOSITION, i, pVerbs[i].lpszVerbName);
  552. }
  553. }
  554. pIVerbEnum->Release();
  555. }
  556. if (NULL != pVerbs)
  557. {
  558. MENUITEMINFO mii;
  559. TCHAR szMenuName[MAX_PATH];
  560. mii.cbSize = sizeof(mii);
  561. mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_STATE | MIIM_ID;
  562. int cOleVerbs = cRegFetched;
  563. for (ULONG i = cRegFetched; i < nItems + cRegFetched; i++)
  564. {
  565. mii.dwTypeData = szMenuName;
  566. mii.cch = ARRAYSIZE(szMenuName);
  567. // NOTE: use GetMenuState() to avoid converting flags:
  568. DWORD dwState = GetMenuState(hmenu, i, MF_BYPOSITION);
  569. if (0 == (dwState & (MF_BITMAP | MF_OWNERDRAW | MF_POPUP)))
  570. {
  571. if (GetMenuItemInfo(hmenu, i, TRUE, &mii) && (MFT_STRING == mii.fType))
  572. {
  573. TCHAR szVerb[MAX_PATH];
  574. if (FAILED(pcm->GetCommandString(mii.wID - OLEIVERB_FIRST_CONTEXT,
  575. GCS_VERB,
  576. NULL,
  577. (LPSTR) szVerb,
  578. ARRAYSIZE(szVerb))))
  579. {
  580. // Some commands don't have canonical names - just
  581. // set the verb string to empty
  582. szVerb[0] = TEXT('\0');
  583. }
  584. // hardcode the verbs we want to add. We expect this list to be quite
  585. // limited. For now, just properties
  586. if (0 == lstrcmp(szVerb, TEXT("properties")))
  587. {
  588. // In the first design, the context menu ID was used as
  589. // the lVerb - however MFC apps only give us a range of
  590. // 16 ID's and context menu ID's are often over 100
  591. // (they aren't contiguous)
  592. // Instead, we use the menu position plus the verb offset
  593. pVerbs[cOleVerbs].lVerb = (LONG) i;
  594. _iPropertiesMenuItem = i;
  595. int cchMenu = lstrlen(mii.dwTypeData) + 1;
  596. if (NULL != (pVerbs[cOleVerbs].lpszVerbName = new WCHAR[cchMenu]))
  597. {
  598. SHTCharToUnicode(mii.dwTypeData, pVerbs[cOleVerbs].lpszVerbName, cchMenu);
  599. }
  600. pVerbs[cOleVerbs].fuFlags = dwState;
  601. pVerbs[cOleVerbs].grfAttribs = OLEVERBATTRIB_ONCONTAINERMENU;
  602. DebugMsg(DM_TRACE, " Adding verb: id==%d,name=%s,verb=%s",mii.wID,mii.dwTypeData,szVerb);
  603. cOleVerbs++;
  604. }
  605. }
  606. }
  607. }
  608. if (SUCCEEDED(hr = InitVerbEnum(pVerbs, cOleVerbs)))
  609. {
  610. hr = QueryInterface(IID_IEnumOLEVERB, (void**) ppEnumOleVerb);
  611. }
  612. else
  613. {
  614. delete [] pVerbs;
  615. }
  616. }
  617. else
  618. {
  619. hr = E_OUTOFMEMORY;
  620. }
  621. }
  622. else
  623. {
  624. hr = OLEOBJ_E_NOVERBS;
  625. }
  626. }
  627. DestroyMenu(hmenu);
  628. }
  629. else
  630. {
  631. hr = E_OUTOFMEMORY;
  632. }
  633. pcm->Release();
  634. }
  635. return hr; // OleRegEnumVerbs(CLSID_CPackage, ppEnumOleVerb);
  636. }
  637. HRESULT CPackage::Update(void)
  638. {
  639. DebugMsg(DM_TRACE, "pack - Update called");
  640. return S_OK;
  641. }
  642. HRESULT CPackage::IsUpToDate(void)
  643. {
  644. DebugMsg(DM_TRACE, "pack - IsUpToDate called");
  645. return S_OK;
  646. }
  647. HRESULT CPackage::GetUserClassID(LPCLSID pClsid)
  648. {
  649. DebugMsg(DM_TRACE, "pack - GetUserClassID called");
  650. *pClsid = CLSID_CPackage; // CLSID_OldPackage;
  651. return S_OK;
  652. }
  653. HRESULT CPackage::GetUserType(DWORD dwFromOfType, LPOLESTR *pszUserType)
  654. {
  655. DebugMsg(DM_TRACE, "pack - GetUserType called");
  656. return OleRegGetUserType(CLSID_CPackage, dwFromOfType, pszUserType);
  657. }
  658. HRESULT CPackage::SetExtent(DWORD dwDrawAspect, SIZEL *psizel)
  659. {
  660. DebugMsg(DM_TRACE, "pack - SetExtent called");
  661. return E_FAIL;
  662. }
  663. HRESULT CPackage::GetExtent(DWORD dwDrawAspect, SIZEL *psizel)
  664. {
  665. DebugMsg(DM_TRACE, "pack - GetExtent called");
  666. return GetExtent(dwDrawAspect, -1, NULL,psizel);
  667. }
  668. HRESULT CPackage::Advise(IAdviseSink *pAdvSink, DWORD *pdwConnection)
  669. {
  670. HRESULT hr = S_OK;
  671. DebugMsg(DM_TRACE, "pack - Advise called");
  672. if (NULL == _pIOleAdviseHolder)
  673. {
  674. hr = CreateOleAdviseHolder(&_pIOleAdviseHolder);
  675. }
  676. if(SUCCEEDED(hr))
  677. {
  678. hr = _pIOleAdviseHolder->Advise(pAdvSink, pdwConnection);
  679. }
  680. return hr;
  681. }
  682. HRESULT CPackage::Unadvise(DWORD dwConnection)
  683. {
  684. HRESULT hr = E_FAIL;
  685. DebugMsg(DM_TRACE, "pack oo - Unadvise() called.");
  686. if (NULL != _pIOleAdviseHolder)
  687. hr = _pIOleAdviseHolder->Unadvise(dwConnection);
  688. return hr;
  689. }
  690. HRESULT CPackage::EnumAdvise(LPENUMSTATDATA *ppenumAdvise)
  691. {
  692. HRESULT hr = E_FAIL;
  693. DebugMsg(DM_TRACE, "pack oo - EnumAdvise() called.");
  694. if (NULL != _pIOleAdviseHolder)
  695. hr = _pIOleAdviseHolder->EnumAdvise(ppenumAdvise);
  696. return hr;
  697. }
  698. HRESULT CPackage::GetMiscStatus(DWORD dwAspect, LPDWORD pdwStatus)
  699. {
  700. DebugMsg(DM_TRACE, "pack - GetMiscStatus called");
  701. return OleRegGetMiscStatus(CLSID_CPackage, dwAspect, pdwStatus);
  702. }
  703. HRESULT CPackage::SetColorScheme(LPLOGPALETTE pLogpal)
  704. {
  705. DebugMsg(DM_TRACE, "pack - SetColorScheme called");
  706. return E_NOTIMPL;
  707. }
  708. DEFINE_GUID(SID_targetGUID, 0xc7b318a8, 0xfc2c, 0x47e6, 0x8b, 0x2, 0x46, 0xa9, 0xc, 0xc9, 0x1b, 0x43);
  709. // Wait for the spawned application to exit,then call back to the main thread to do some notifications
  710. DWORD CALLBACK MainWaitOnChildThreadProc(void *lpv)
  711. {
  712. DebugMsg(DM_TRACE, "pack oo - MainWaitOnChildThreadProc() called.");
  713. HRESULT hr;
  714. MAINWAITONCHILD *pmwoc = (MAINWAITONCHILD *)lpv;
  715. IOleCommandTarget * pIOleCommandTarget;
  716. // Unmarshal the IOleCommandTarget interface that we need to call back into the main thread interfaces
  717. hr = CoGetInterfaceAndReleaseStream(pmwoc->pIStreamIOleCommandTarget, IID_PPV_ARG(IOleCommandTarget, &pIOleCommandTarget));
  718. if(SUCCEEDED(hr))
  719. {
  720. DWORD ret = WaitForSingleObject(pmwoc->h, INFINITE);
  721. DebugMsg(DM_TRACE,"WaitForSingObject exits...ret==%d",ret);
  722. if(WAIT_OBJECT_0 == ret)
  723. {
  724. // Use the IOleCommandTarget interface to execute on the main thread. Can't marshal _pIOleAdviseHolder
  725. pIOleCommandTarget->Exec(&SID_targetGUID, 0, 0, NULL, NULL);
  726. pIOleCommandTarget->Release();
  727. }
  728. }
  729. CloseHandle(pmwoc->h);
  730. delete pmwoc;
  731. DebugMsg(DM_TRACE, " MainWaitOnChildThreadProc exiting.");
  732. return 0;
  733. }
  734. BOOL CALLBACK GetTaskWndProc(HWND hwnd, DWORD lParam)
  735. {
  736. BOOL result = TRUE;
  737. DebugMsg(DM_TRACE, "pack oo - GetTaskWndProc() called.");
  738. if (IsWindowVisible(hwnd))
  739. {
  740. g_hTaskWnd = hwnd;
  741. result = FALSE;
  742. }
  743. return result;
  744. }
  745. // We need an IOLECache Interface to Keep Office97 happy.
  746. HRESULT CPackage::Cache(FORMATETC * pFormatetc, DWORD advf, DWORD * pdwConnection)
  747. {
  748. DebugMsg(DM_TRACE, "Cache called");
  749. return S_OK;
  750. }
  751. HRESULT CPackage::Uncache(DWORD dwConnection)
  752. {
  753. DebugMsg(DM_TRACE, "Uncache called");
  754. return S_OK;
  755. }
  756. HRESULT CPackage::EnumCache(IEnumSTATDATA ** ppenumSTATDATA)
  757. {
  758. DebugMsg(DM_TRACE, "EnumCache called - returning failure");
  759. return E_NOTIMPL;
  760. }
  761. HRESULT CPackage::InitCache(IDataObject *pDataObject)
  762. {
  763. DebugMsg(DM_TRACE, "InitCache called");
  764. return S_OK;
  765. }