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.

1567 lines
44 KiB

  1. #include "privcpp.h"
  2. #define CPP_FUNCTIONS
  3. // #include <crtfree.h>
  4. UINT g_cfFileContents;
  5. UINT g_cfFileDescriptor;
  6. UINT g_cfObjectDescriptor;
  7. UINT g_cfEmbedSource;
  8. UINT g_cfFileNameW;
  9. INT g_cxIcon;
  10. INT g_cyIcon;
  11. INT g_cxArrange;
  12. INT g_cyArrange;
  13. HFONT g_hfontTitle;
  14. static TCHAR szUserType[] = TEXT("Package");
  15. static TCHAR szDefTempFile[] = TEXT("PKG");
  16. CPackage::CPackage() :
  17. _cRef(1)
  18. {
  19. DebugMsg(DM_TRACE, "pack - CPackage() called.");
  20. g_cRefThisDll++;
  21. // Excel v.5 - v2000 has a hosting bug when they host an object as a link.
  22. // They always remove their hpmbed->hpobj object, yet all their methods
  23. // on the IOleClientSite interface they give us dereference this and fault.
  24. //
  25. TCHAR szProcess[MAX_PATH];
  26. if (GetModuleFileName(NULL, szProcess, ARRAYSIZE(szProcess)) &&
  27. !lstrcmp(TEXT("EXCEL.EXE"), PathFindFileName(szProcess)))
  28. _fNoIOleClientSiteCalls = TRUE;
  29. ASSERT(_cf == 0);
  30. ASSERT(_panetype == NOTHING);
  31. ASSERT(_pEmbed == NULL);
  32. ASSERT(_pCml == NULL);
  33. ASSERT(_fLoaded == FALSE);
  34. ASSERT(_lpszContainerApp == NULL);
  35. ASSERT(_lpszContainerObj == NULL);
  36. ASSERT(_fIsDirty == FALSE);
  37. ASSERT(_pIStorage == NULL);
  38. ASSERT(_pstmFileContents == NULL);
  39. ASSERT(_pstm == NULL);
  40. ASSERT(_pIPersistStorage == NULL);
  41. ASSERT(_pIDataObject == NULL);
  42. ASSERT(_pIOleObject == NULL);
  43. ASSERT(_pIViewObject2 == NULL);
  44. ASSERT(_pIAdviseSink == NULL);
  45. ASSERT(_pIRunnableObject == NULL);
  46. ASSERT(_pIDataAdviseHolder == NULL);
  47. ASSERT(_pIOleAdviseHolder == NULL);
  48. ASSERT(_pIOleClientSite == NULL);
  49. ASSERT(_pViewSink == NULL);
  50. ASSERT(_dwViewAspects == 0);
  51. ASSERT(_dwViewAdvf == 0);
  52. ASSERT(_cVerbs == 0);
  53. ASSERT(_nCurVerb == 0);
  54. ASSERT(_pVerbs == NULL);
  55. ASSERT(_pcm == NULL);
  56. }
  57. CPackage::~CPackage()
  58. {
  59. DebugMsg(DM_TRACE, "pack - ~CPackage() called.");
  60. // We should never be destroyed unless our ref count is zero.
  61. ASSERT(_cRef == 0);
  62. g_cRefThisDll--;
  63. // Destroy our interfaces...
  64. //
  65. delete _pIOleObject;
  66. delete _pIViewObject2;
  67. delete _pIDataObject;
  68. delete _pIPersistStorage;
  69. delete _pIAdviseSink;
  70. delete _pIRunnableObject;
  71. // Destroy the packaged file structure...
  72. //
  73. DestroyIC();
  74. // we destroy depending on which type of object we had packaged
  75. switch(_panetype)
  76. {
  77. case PEMBED:
  78. if (_pEmbed->pszTempName) {
  79. DeleteFile(_pEmbed->pszTempName);
  80. delete _pEmbed->pszTempName;
  81. }
  82. delete _pEmbed;
  83. break;
  84. case CMDLINK:
  85. delete _pCml;
  86. break;
  87. }
  88. // Release Advise pointers...
  89. //
  90. if (_pIDataAdviseHolder)
  91. _pIDataAdviseHolder->Release();
  92. if (_pIOleAdviseHolder)
  93. _pIOleAdviseHolder->Release();
  94. if (_pIOleClientSite)
  95. _pIOleClientSite->Release();
  96. // Release Storage pointers...
  97. //
  98. if (_pIStorage)
  99. _pIStorage->Release();
  100. if (_pstmFileContents)
  101. _pstmFileContents->Release();
  102. if (_pstm)
  103. _pstm->Release();
  104. delete _lpszContainerApp;
  105. delete _lpszContainerObj;
  106. ReleaseContextMenu();
  107. if (NULL != _pVerbs)
  108. {
  109. for (ULONG i = 0; i < _cVerbs; i++)
  110. {
  111. delete _pVerbs[i].lpszVerbName;
  112. }
  113. delete _pVerbs;
  114. }
  115. DebugMsg(DM_TRACE,"CPackage being destroyed. _cRef == %d",_cRef);
  116. }
  117. HRESULT CPackage::Init()
  118. {
  119. //
  120. // initializes parts of a package object that have a potential to fail
  121. // return: S_OK -- everything initialized
  122. // E_FAIL -- error in initialzation
  123. // E_OUTOFMEMORY -- out of memory
  124. //
  125. DebugMsg(DM_TRACE, "pack - Init() called.");
  126. // Initialize all the interfaces...
  127. //
  128. if (!(_pIOleObject = new CPackage_IOleObject(this)))
  129. return E_OUTOFMEMORY;
  130. if (!(_pIViewObject2 = new CPackage_IViewObject2(this)))
  131. return E_OUTOFMEMORY;
  132. if (!(_pIDataObject = new CPackage_IDataObject(this)))
  133. return E_OUTOFMEMORY;
  134. if (!(_pIPersistStorage = new CPackage_IPersistStorage(this)))
  135. return E_OUTOFMEMORY;
  136. if (!(_pIPersistFile = new CPackage_IPersistFile(this)))
  137. return E_OUTOFMEMORY;
  138. if (!(_pIAdviseSink = new CPackage_IAdviseSink(this)))
  139. return E_OUTOFMEMORY;
  140. if (!(_pIRunnableObject = new CPackage_IRunnableObject(this)))
  141. return E_OUTOFMEMORY;
  142. // Get some system metrics that we'll need later...
  143. //
  144. LOGFONT lf;
  145. SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, FALSE);
  146. SystemParametersInfo(SPI_ICONHORIZONTALSPACING, 0, &g_cxArrange, FALSE);
  147. SystemParametersInfo(SPI_ICONVERTICALSPACING, 0, &g_cyArrange, FALSE);
  148. g_cxIcon = GetSystemMetrics(SM_CXICON);
  149. g_cyIcon = GetSystemMetrics(SM_CYICON);
  150. g_hfontTitle = CreateFontIndirect(&lf);
  151. // register some clipboard formats that we support...
  152. //
  153. g_cfFileContents = RegisterClipboardFormat(CFSTR_FILECONTENTS);
  154. g_cfFileDescriptor = RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR);
  155. g_cfObjectDescriptor= RegisterClipboardFormat(CFSTR_OBJECTDESCRIPTOR);
  156. g_cfEmbedSource = RegisterClipboardFormat(CFSTR_EMBEDSOURCE);
  157. g_cfFileNameW = RegisterClipboardFormat(TEXT("FileNameW"));
  158. // Initialize a generic icon
  159. _lpic = IconCreate();
  160. IconRefresh();
  161. return S_OK;
  162. }
  163. ////////////////////////////////////////////////////////////////////////
  164. //
  165. // IUnknown Methods...
  166. //
  167. ////////////////////////////////////////////////////////////////////////
  168. HRESULT CPackage::QueryInterface(REFIID iid, void ** ppvObj)
  169. {
  170. DebugMsg(DM_TRACE, "pack - QueryInterface() called.");
  171. if (iid == IID_IUnknown) {
  172. DebugMsg(DM_TRACE, " getting IID_IUnknown");
  173. *ppvObj = (void *)this;
  174. }
  175. else if (iid == IID_IOleObject) {
  176. DebugMsg(DM_TRACE, " getting IID_IOleObject");
  177. *ppvObj = (void *)_pIOleObject;
  178. }
  179. else if ((iid == IID_IViewObject2) || (iid == IID_IViewObject)) {
  180. DebugMsg(DM_TRACE, " getting IID_IViewObject");
  181. *ppvObj = (void *)_pIViewObject2;
  182. }
  183. else if (iid == IID_IDataObject) {
  184. DebugMsg(DM_TRACE, " getting IID_IDataObject");
  185. *ppvObj = (void *)_pIDataObject;
  186. }
  187. else if ((iid == IID_IPersistStorage) || (iid == IID_IPersist)) {
  188. DebugMsg(DM_TRACE, " getting IID_IPersistStorage");
  189. *ppvObj = (void *)_pIPersistStorage;
  190. }
  191. else if (iid == IID_IPersistFile) {
  192. DebugMsg(DM_TRACE, " getting IID_IPersistFile");
  193. *ppvObj = (void *)_pIPersistFile;
  194. }
  195. else if (iid == IID_IAdviseSink) {
  196. DebugMsg(DM_TRACE, " getting IID_IAdviseSink");
  197. *ppvObj = (void *)_pIAdviseSink;
  198. }
  199. else if (iid == IID_IRunnableObject) {
  200. DebugMsg(DM_TRACE, " getting IID_IRunnableObject");
  201. *ppvObj = (void *)_pIRunnableObject;
  202. }
  203. else if (iid == IID_IEnumOLEVERB)
  204. {
  205. DebugMsg(DM_TRACE, " getting IID_IEnumOLEVERB");
  206. *ppvObj = (IEnumOLEVERB*) this;
  207. }
  208. else {
  209. *ppvObj = NULL;
  210. return E_NOINTERFACE;
  211. }
  212. ((LPUNKNOWN)*ppvObj)->AddRef();
  213. return S_OK;
  214. }
  215. ULONG CPackage::AddRef()
  216. {
  217. _cRef++;
  218. return _cRef;
  219. }
  220. ULONG CPackage::Release()
  221. {
  222. _cRef--;
  223. if (_cRef > 0)
  224. return _cRef;
  225. delete this;
  226. return 0;
  227. }
  228. HRESULT CPackage_CreateInstnace(LPUNKNOWN * ppunk)
  229. {
  230. DebugMsg(DM_TRACE, "pack - CreateInstance called");
  231. *ppunk = NULL; // null the out param
  232. CPackage* pPack = new CPackage;
  233. if (!pPack)
  234. return E_OUTOFMEMORY;
  235. if (FAILED(pPack->Init())) {
  236. delete pPack;
  237. return E_OUTOFMEMORY;
  238. }
  239. *ppunk = pPack;
  240. return S_OK;
  241. }
  242. STDMETHODIMP CPackage::Next(ULONG celt, OLEVERB* rgVerbs, ULONG* pceltFetched)
  243. {
  244. HRESULT hr;
  245. if (NULL != rgVerbs)
  246. {
  247. if (1 == celt)
  248. {
  249. if (_nCurVerb < _cVerbs)
  250. {
  251. ASSERT(NULL != _pVerbs);
  252. *rgVerbs = _pVerbs[_nCurVerb];
  253. if ((NULL != _pVerbs[_nCurVerb].lpszVerbName) &&
  254. (NULL != (rgVerbs->lpszVerbName = (LPWSTR) CoTaskMemAlloc(
  255. (lstrlenW(_pVerbs[_nCurVerb].lpszVerbName) + 1) * SIZEOF(WCHAR)))))
  256. {
  257. StrCpyW(rgVerbs->lpszVerbName, _pVerbs[_nCurVerb].lpszVerbName);
  258. }
  259. _nCurVerb++;
  260. hr = S_OK;
  261. }
  262. else
  263. {
  264. hr = S_FALSE;
  265. }
  266. if (NULL != pceltFetched)
  267. {
  268. *pceltFetched = (S_OK == hr) ? 1 : 0;
  269. }
  270. }
  271. else if (NULL != pceltFetched)
  272. {
  273. int cVerbsToCopy = min(celt, _cVerbs - _nCurVerb);
  274. if (cVerbsToCopy > 0)
  275. {
  276. ASSERT(NULL != _pVerbs);
  277. CopyMemory(rgVerbs, &(_pVerbs[_nCurVerb]), cVerbsToCopy * sizeof(OLEVERB));
  278. for (int i = 0; i < cVerbsToCopy; i++)
  279. {
  280. if ((NULL != _pVerbs[_nCurVerb + i].lpszVerbName) &&
  281. (NULL != (rgVerbs[i].lpszVerbName = (LPWSTR) CoTaskMemAlloc(
  282. (lstrlenW(_pVerbs[_nCurVerb + i].lpszVerbName) + 1) * SIZEOF(WCHAR)))))
  283. {
  284. StrCpyW(rgVerbs[i].lpszVerbName, _pVerbs[_nCurVerb + i].lpszVerbName);
  285. }
  286. }
  287. _nCurVerb += cVerbsToCopy;
  288. }
  289. *pceltFetched = (ULONG) cVerbsToCopy;
  290. hr = (celt == (ULONG) cVerbsToCopy) ? S_OK : S_FALSE;
  291. }
  292. else
  293. {
  294. hr = E_INVALIDARG;
  295. }
  296. }
  297. else
  298. {
  299. hr = E_INVALIDARG;
  300. }
  301. return hr;
  302. }
  303. STDMETHODIMP CPackage::Skip(ULONG celt)
  304. {
  305. if (_nCurVerb + celt > _cVerbs)
  306. {
  307. // there aren't enough elements, go to the end and return S_FALSE
  308. _nCurVerb = _cVerbs;
  309. return S_FALSE;
  310. }
  311. else
  312. {
  313. _nCurVerb += celt;
  314. return S_OK;
  315. }
  316. }
  317. STDMETHODIMP CPackage::Reset()
  318. {
  319. _nCurVerb = 0;
  320. return S_OK;
  321. }
  322. STDMETHODIMP CPackage::Clone(IEnumOLEVERB** ppEnum)
  323. {
  324. if (NULL != ppEnum)
  325. {
  326. *ppEnum = NULL;
  327. }
  328. return E_NOTIMPL;
  329. }
  330. ///////////////////////////////////////////////////////////////////
  331. //
  332. // Package helper functions
  333. //
  334. ///////////////////////////////////////////////////////////////////
  335. HRESULT CPackage::EmbedInitFromFile(LPCTSTR lpFileName, BOOL fInitFile)
  336. {
  337. //
  338. // get's the file size of the packaged file and set's the name
  339. // of the packaged file if fInitFile == TRUE.
  340. // return: S_OK -- initialized ok
  341. // E_FAIL -- error initializing file
  342. //
  343. DWORD dwSize;
  344. // if this is the first time we've been called, then we need to allocate
  345. // memory for the _pEmbed structure
  346. if (_pEmbed == NULL)
  347. {
  348. _pEmbed = new EMBED;
  349. if (_pEmbed)
  350. {
  351. _pEmbed->pszTempName = NULL;
  352. _pEmbed->hTask = NULL;
  353. _pEmbed->poo = NULL;
  354. _pEmbed->fIsOleFile = TRUE;
  355. }
  356. }
  357. if (_pEmbed == NULL)
  358. return E_OUTOFMEMORY;
  359. // open the file to package...
  360. //
  361. HANDLE fh = CreateFile(lpFileName, GENERIC_READ, FILE_SHARE_READWRITE,
  362. NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
  363. if (fh == INVALID_HANDLE_VALUE)
  364. {
  365. DWORD dwError = GetLastError();
  366. return E_FAIL;
  367. }
  368. _panetype = PEMBED;
  369. // Get the size of the file
  370. _pEmbed->fd.nFileSizeLow = GetFileSize(fh, &dwSize);
  371. if (_pEmbed->fd.nFileSizeLow == 0xFFFFFFFF)
  372. {
  373. DWORD dwError = GetLastError();
  374. return E_FAIL;
  375. }
  376. ASSERT(dwSize == 0);
  377. _pEmbed->fd.nFileSizeHigh = 0L;
  378. _pEmbed->fd.dwFlags = FD_FILESIZE;
  379. // We only want to set the filename if this is the file to be packaged.
  380. // If it's only a temp file that we're reloading (fInitFile == FALSE) then
  381. // don't bother setting the filename.
  382. //
  383. if (fInitFile)
  384. {
  385. lstrcpy(_pEmbed->fd.cFileName,lpFileName);
  386. DestroyIC();
  387. _lpic = IconCreateFromFile(lpFileName);
  388. if (_pIDataAdviseHolder)
  389. _pIDataAdviseHolder->SendOnDataChange(_pIDataObject,0, NULL);
  390. if (_pViewSink)
  391. _pViewSink->OnViewChange(_dwViewAspects,_dwViewAdvf);
  392. }
  393. _fIsDirty = TRUE;
  394. CloseHandle(fh);
  395. return S_OK;
  396. }
  397. HRESULT CPackage::CmlInitFromFile(LPTSTR lpFileName, BOOL fUpdateIcon, PANETYPE paneType)
  398. {
  399. // if this is the first time we've been called, then we need to allocate
  400. // memory for the _pCml structure
  401. if (_pCml == NULL)
  402. {
  403. _pCml = new CML;
  404. if (_pCml)
  405. {
  406. // we don't use this, but an old packager accessing us might.
  407. _pCml->fCmdIsLink = FALSE;
  408. }
  409. }
  410. if (_pCml == NULL)
  411. return E_OUTOFMEMORY;
  412. _panetype = paneType;
  413. lstrcpy(_pCml->szCommandLine,lpFileName);
  414. _fIsDirty = TRUE;
  415. if (fUpdateIcon)
  416. {
  417. DestroyIC();
  418. _lpic = IconCreateFromFile(lpFileName);
  419. if (_pIDataAdviseHolder)
  420. _pIDataAdviseHolder->SendOnDataChange(_pIDataObject,0, NULL);
  421. if (_pViewSink)
  422. _pViewSink->OnViewChange(_dwViewAspects,_dwViewAdvf);
  423. }
  424. return S_OK;
  425. }
  426. HRESULT CPackage::InitFromPackInfo(LPPACKAGER_INFO lppi)
  427. {
  428. HRESULT hr;
  429. DWORD dwFileAttributes = GetFileAttributes(lppi->szFilename);
  430. // Ok, we need to test whether the user tried to package a folder
  431. // instead of a file. If s/he did, then we'll just create a link
  432. // to that folder instead of an embedded file.
  433. //
  434. if (-1 == dwFileAttributes)
  435. {
  436. hr = CmlInitFromFile(lppi->szFilename, FALSE, PACKAGE);
  437. }
  438. else if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  439. {
  440. hr = CmlInitFromFile(lppi->szFilename, FALSE, CMDLINK);
  441. }
  442. else
  443. {
  444. // we pass FALSE here, because we don't want to write the icon
  445. // information.
  446. //
  447. hr = EmbedInitFromFile(lppi->szFilename, FALSE);
  448. lstrcpy(_pEmbed->fd.cFileName,lppi->szFilename);
  449. _panetype = PEMBED;
  450. }
  451. // set the icon information
  452. if (PathFileExists(lppi->szFilename))
  453. lstrcpy(_lpic->szIconPath, *lppi->szIconPath? lppi->szIconPath : lppi->szFilename);
  454. _lpic->iDlgIcon = lppi->iIcon;
  455. lstrcpy(_lpic->szIconText,lppi->szLabel);
  456. IconRefresh();
  457. // we need to tell the client we want to be saved...it should be smart
  458. // enough to do it anyway, but we can't take any chances.
  459. if (_pIOleClientSite)
  460. _pIOleClientSite->SaveObject();
  461. return hr;
  462. }
  463. HRESULT CPackage::CreateTempFileName()
  464. {
  465. ASSERT(NULL != _pEmbed);
  466. TCHAR szDefPath[MAX_PATH];
  467. if (_pEmbed->pszTempName)
  468. {
  469. return S_OK;
  470. }
  471. else if (GetTempPath(ARRAYSIZE(szDefPath), szDefPath))
  472. {
  473. LPTSTR pszFile;
  474. if ((NULL != _lpic) && (TEXT('\0') != _lpic->szIconText[0]))
  475. {
  476. pszFile = _lpic->szIconText;
  477. }
  478. else
  479. {
  480. pszFile = PathFindFileName(_pEmbed->fd.cFileName);
  481. }
  482. PathAppend(szDefPath, pszFile);
  483. if (PathFileExists(szDefPath))
  484. {
  485. TCHAR szOriginal[MAX_PATH];
  486. lstrcpy(szOriginal, szDefPath);
  487. PathYetAnotherMakeUniqueName(szDefPath, szOriginal, NULL, NULL);
  488. }
  489. _pEmbed->pszTempName = new TCHAR[lstrlen(szDefPath) + 1];
  490. if (!_pEmbed->pszTempName)
  491. {
  492. DebugMsg(DM_TRACE," couldn't alloc memory for pszTempName!!");
  493. return E_OUTOFMEMORY;
  494. }
  495. lstrcpy(_pEmbed->pszTempName, szDefPath);
  496. return S_OK;
  497. }
  498. else
  499. {
  500. DebugMsg(DM_TRACE," couldn't get temp path!!");
  501. return E_FAIL;
  502. }
  503. }
  504. HRESULT CPackage::CreateTempFile()
  505. {
  506. //
  507. // used to create a temporary file that holds the file contents of the
  508. // packaged file. the old packager used to keep the packaged file in
  509. // memory which is just a total waste. so, being as we're much more
  510. // efficient, we create a temp file whenever someone wants to do something
  511. // with our contents. we initialze the temp file from the original file
  512. // to package or our persistent storage depending on whether we are a new
  513. // package or a loaded package
  514. // return: S_OK -- temp file created
  515. // E_FAIL -- error creating temp file
  516. //
  517. DebugMsg(DM_TRACE," CreateTempFile() called.");
  518. HRESULT hr = CreateTempFileName();
  519. if (FAILED(hr))
  520. {
  521. return hr;
  522. }
  523. if (PathFileExists(_pEmbed->pszTempName))
  524. {
  525. DebugMsg(DM_TRACE," already have a temp file!!");
  526. return S_OK;
  527. }
  528. // if we weren't loaded from a storage then we're in the process of
  529. // creating a package, and should be able to copy the packaged file
  530. // to create a temp file
  531. //
  532. if (!_fLoaded)
  533. {
  534. if (!(CopyFile(_pEmbed->fd.cFileName, _pEmbed->pszTempName, FALSE)))
  535. {
  536. DebugMsg(DM_TRACE," couldn't copy file!!");
  537. return E_FAIL;
  538. }
  539. }
  540. else
  541. {
  542. TCHAR szTempFile[MAX_PATH];
  543. // copy the file name because _pEmbed may get re-created below,
  544. // but we want to hold on to this filename:
  545. lstrcpy(szTempFile, _pEmbed->pszTempName);
  546. // if we have a valid stream, but not a file contents stream,
  547. // it's because we went hands off and didn't know where to put
  548. // the seek pointer to init the filecontents stream. so, we
  549. // call PackageReadFromStream to create the FileContents stream
  550. //
  551. if (_pstm && !_pstmFileContents)
  552. {
  553. if (FAILED(PackageReadFromStream(_pstm)))
  554. {
  555. DebugMsg(DM_TRACE," couldn't read from stream!!");
  556. return E_FAIL;
  557. }
  558. }
  559. IStream* pstm;
  560. _pstmFileContents->Clone(&pstm); // we don't want to move the seek
  561. // pointer on our FileContents stream
  562. if (FAILED(CopyStreamToFile(pstm, szTempFile)))
  563. {
  564. DebugMsg(DM_TRACE," couldn't copy from stream!!");
  565. pstm->Release();
  566. return E_FAIL;
  567. }
  568. else
  569. {
  570. ASSERT(_pEmbed);
  571. delete _pEmbed->pszTempName;
  572. if (NULL != (_pEmbed->pszTempName = new TCHAR[lstrlen(szTempFile) + 1]))
  573. {
  574. lstrcpy(_pEmbed->pszTempName, szTempFile);
  575. }
  576. else
  577. {
  578. return E_OUTOFMEMORY;
  579. }
  580. }
  581. pstm->Release();
  582. }
  583. // whenever we create a tempfile we are activating the contents which
  584. // means we are dirty until we get a save message
  585. return S_OK;
  586. }
  587. ///////////////////////////////////////////////////////////////////////
  588. //
  589. // Data Transfer Functions
  590. //
  591. ///////////////////////////////////////////////////////////////////////
  592. HRESULT CPackage::GetFileDescriptor(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
  593. {
  594. FILEGROUPDESCRIPTOR *pfgd;
  595. DebugMsg(DM_TRACE," Getting File Descriptor");
  596. // we only support HGLOBAL at this time
  597. //
  598. if (!(pFE->tymed & TYMED_HGLOBAL)) {
  599. DebugMsg(DM_TRACE," does not support HGLOBAL!");
  600. return DATA_E_FORMATETC;
  601. }
  602. //// Copy file descriptor to HGLOBAL ///////////////////////////
  603. //
  604. pSTM->tymed = TYMED_HGLOBAL;
  605. // render the file descriptor
  606. if (!(pfgd = (FILEGROUPDESCRIPTOR *)GlobalAlloc(GPTR,
  607. sizeof(FILEGROUPDESCRIPTOR))))
  608. return E_OUTOFMEMORY;
  609. pSTM->hGlobal = pfgd;
  610. pfgd->cItems = 1;
  611. switch(_panetype)
  612. {
  613. case PEMBED:
  614. pfgd->fgd[0] = _pEmbed->fd;
  615. GetDisplayName(pfgd->fgd[0].cFileName, _pEmbed->fd.cFileName);
  616. break;
  617. case CMDLINK:
  618. // the label for the package will serve as the filename for the
  619. // shortcut we're going to create.
  620. lstrcpy(pfgd->fgd[0].cFileName, _lpic->szIconText);
  621. // harcoded use of .lnk extension!!
  622. lstrcat(pfgd->fgd[0].cFileName, TEXT(".lnk"));
  623. // we want to add the little arrow to the shortcut.
  624. pfgd->fgd[0].dwFlags = FD_LINKUI;
  625. break;
  626. }
  627. return S_OK;
  628. }
  629. HRESULT CPackage::GetFileContents(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
  630. {
  631. void * lpvDest = NULL;
  632. DWORD dwSize;
  633. HANDLE hFile = NULL;
  634. DWORD cb;
  635. HRESULT hr = E_FAIL;
  636. DebugMsg(DM_TRACE," Getting File Contents");
  637. //// Copy file contents to ISTREAM ///////////////////////////
  638. //
  639. // NOTE: Hopefully, everyone using our object supports TYMED_ISTREAM,
  640. // otherwise we could get some really slow behavior. We might later
  641. // want to implement TYMED_ISTORAGE as well and shove our file contents
  642. // into a single stream named CONTENTS.
  643. //
  644. if (pFE->tymed & TYMED_ISTREAM) {
  645. DebugMsg(DM_TRACE," using TYMED_ISTREAM");
  646. pSTM->tymed = TYMED_ISTREAM;
  647. switch (_panetype) {
  648. case PEMBED:
  649. if (_pstmFileContents)
  650. hr = _pstmFileContents->Clone(&pSTM->pstm);
  651. else
  652. return E_FAIL;
  653. break;
  654. case CMDLINK:
  655. hr = CreateStreamOnHGlobal(NULL, TRUE, &pSTM->pstm);
  656. if (SUCCEEDED(hr))
  657. {
  658. hr = CreateShortcutOnStream(pSTM->pstm);
  659. if (FAILED(hr))
  660. {
  661. pSTM->pstm->Release();
  662. pSTM->pstm = NULL;
  663. }
  664. }
  665. break;
  666. }
  667. return hr;
  668. }
  669. //// Copy file contents to HGLOBAL ///////////////////////////
  670. //
  671. // NOTE: This is really icky and could potentially be very slow if
  672. // somebody decides to package really large files. Hopefully,
  673. // everyone should be able to get the info it wants through TYMED_ISTREAM,
  674. // but this is here as a common denominator
  675. //
  676. if (pFE->tymed & TYMED_HGLOBAL) {
  677. DebugMsg(DM_TRACE," using TYMED_HGLOBAL");
  678. pSTM->tymed = TYMED_HGLOBAL;
  679. if (_panetype == CMDLINK) {
  680. DebugMsg(DM_TRACE,
  681. " H_GLOBAL not supported for CMDLINK");
  682. return DATA_E_FORMATETC;
  683. }
  684. dwSize = _pEmbed->fd.nFileSizeLow;
  685. // caller is responsible for freeing this memory, even if we fail.
  686. if (!(lpvDest = GlobalAlloc(GPTR, dwSize))) {
  687. DebugMsg(DM_TRACE," out o memory!!");
  688. return E_OUTOFMEMORY;
  689. }
  690. pSTM->hGlobal = lpvDest;
  691. // This will reinitialize our FileContents stream if we had to get
  692. // rid of it. For instance, we have to get rid of all our storage
  693. // pointers in HandsOffStorage, but there's no need to reinit our
  694. // FileContents stream unless we need it again.
  695. //
  696. if (_pstm && !_pstmFileContents)
  697. PackageReadFromStream(_pstm);
  698. if (_pstmFileContents) {
  699. IStream* pstm;
  700. hr = _pstmFileContents->Clone(&pstm);
  701. if (FAILED(hr))
  702. return hr;
  703. hr = pstm->Read(lpvDest, dwSize, &cb);
  704. pstm->Release();
  705. if (FAILED(hr))
  706. return hr;
  707. }
  708. else
  709. return E_FAIL;
  710. if (FAILED(hr) || cb != dwSize) {
  711. DebugMsg(DM_TRACE," error reading from stream!!");
  712. return E_FAIL;
  713. }
  714. return hr;
  715. }
  716. return DATA_E_FORMATETC;
  717. }
  718. void DrawIconToDC(HDC hdcMF, LPIC lpic)
  719. {
  720. RECT rcTemp;
  721. HFONT hfont = NULL;
  722. // Initializae the metafile
  723. SetWindowOrgEx(hdcMF, 0, 0, NULL);
  724. SetWindowExtEx(hdcMF, lpic->rc.right - 1, lpic->rc.bottom - 1, NULL);
  725. SetRect(&rcTemp, 0, 0, lpic->rc.right,lpic->rc.bottom);
  726. hfont = SelectFont(hdcMF, g_hfontTitle);
  727. // Center the icon
  728. DrawIcon(hdcMF, (rcTemp.right - g_cxIcon) / 2, 0, lpic->hDlgIcon);
  729. // Center the text below the icon
  730. SetBkMode(hdcMF, TRANSPARENT);
  731. SetTextAlign(hdcMF, TA_CENTER);
  732. TextOut(hdcMF, rcTemp.right / 2, g_cxIcon + 1, lpic->szIconText,
  733. lstrlen(lpic->szIconText));
  734. if (hfont)
  735. SelectObject(hdcMF, hfont);
  736. }
  737. HRESULT CPackage::GetMetafilePict(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
  738. {
  739. LPMETAFILEPICT lpmfpict;
  740. RECT rcTemp;
  741. LPIC lpic = _lpic;
  742. HDC hdcMF = NULL;
  743. DebugMsg(DM_TRACE," Getting MetafilePict");
  744. if (!(pFE->tymed & TYMED_MFPICT)) {
  745. DebugMsg(DM_TRACE," does not support MFPICT!");
  746. return DATA_E_FORMATETC;
  747. }
  748. pSTM->tymed = TYMED_MFPICT;
  749. // Allocate memory for the metafilepict and get a pointer to it
  750. // NOTE: the caller is responsible for freeing this memory, even on fail
  751. //
  752. if (!(pSTM->hMetaFilePict = GlobalAlloc(GPTR, sizeof(METAFILEPICT))))
  753. return E_OUTOFMEMORY;
  754. lpmfpict = (LPMETAFILEPICT)pSTM->hMetaFilePict;
  755. // Create the metafile
  756. if (!(hdcMF = CreateMetaFile(NULL)))
  757. return E_OUTOFMEMORY;
  758. DrawIconToDC(hdcMF, lpic);
  759. // Map to device independent coordinates
  760. SetRect(&rcTemp, 0, 0, lpic->rc.right,lpic->rc.bottom);
  761. rcTemp.right =
  762. MulDiv((rcTemp.right - rcTemp.left), HIMETRIC_PER_INCH, DEF_LOGPIXELSX);
  763. rcTemp.bottom =
  764. MulDiv((rcTemp.bottom - rcTemp.top), HIMETRIC_PER_INCH, DEF_LOGPIXELSY);
  765. // Finish filling in the metafile header
  766. lpmfpict->mm = MM_ANISOTROPIC;
  767. lpmfpict->xExt = rcTemp.right;
  768. lpmfpict->yExt = rcTemp.bottom;
  769. lpmfpict->hMF = CloseMetaFile(hdcMF);
  770. return S_OK;
  771. }
  772. HRESULT CPackage::GetEnhMetafile(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
  773. {
  774. DebugMsg(DM_TRACE," Getting EnhancedMetafile");
  775. if (!(pFE->tymed & TYMED_ENHMF)) {
  776. DebugMsg(DM_TRACE," does not support ENHMF!");
  777. return DATA_E_FORMATETC;
  778. }
  779. // Map to device independent coordinates
  780. RECT rcTemp;
  781. SetRect(&rcTemp, 0, 0, _lpic->rc.right,_lpic->rc.bottom);
  782. rcTemp.right =
  783. MulDiv((rcTemp.right - rcTemp.left), HIMETRIC_PER_INCH, DEF_LOGPIXELSX);
  784. rcTemp.bottom =
  785. MulDiv((rcTemp.bottom - rcTemp.top), HIMETRIC_PER_INCH, DEF_LOGPIXELSY);
  786. HDC hdc = CreateEnhMetaFile(NULL, NULL, &rcTemp, NULL);
  787. if (hdc)
  788. {
  789. DrawIconToDC(hdc, _lpic);
  790. pSTM->tymed = TYMED_ENHMF;
  791. pSTM->hEnhMetaFile = CloseEnhMetaFile(hdc);
  792. return S_OK;
  793. }
  794. else
  795. {
  796. pSTM->tymed = TYMED_NULL;
  797. return E_OUTOFMEMORY;
  798. }
  799. }
  800. HRESULT CPackage::GetObjectDescriptor(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
  801. {
  802. LPOBJECTDESCRIPTOR lpobj;
  803. DWORD dwFullUserTypeNameLen;
  804. DebugMsg(DM_TRACE," Getting Object Descriptor");
  805. // we only support HGLOBAL at this time
  806. //
  807. if (!(pFE->tymed & TYMED_HGLOBAL)) {
  808. DebugMsg(DM_TRACE," does not support HGLOBAL!");
  809. return DATA_E_FORMATETC;
  810. }
  811. //// Copy file descriptor to HGLOBAL ///////////////////////////
  812. dwFullUserTypeNameLen = 0; //lstrlen(szUserType) + 1;
  813. pSTM->tymed = TYMED_HGLOBAL;
  814. if (!(lpobj = (OBJECTDESCRIPTOR *)GlobalAlloc(GPTR,
  815. sizeof(OBJECTDESCRIPTOR)+dwFullUserTypeNameLen)))
  816. return E_OUTOFMEMORY;
  817. pSTM->hGlobal = lpobj;
  818. lpobj->cbSize = sizeof(OBJECTDESCRIPTOR)+dwFullUserTypeNameLen;
  819. lpobj->clsid = CLSID_CPackage;
  820. lpobj->dwDrawAspect = DVASPECT_CONTENT|DVASPECT_ICON;
  821. _pIOleObject->GetMiscStatus(DVASPECT_CONTENT|DVASPECT_ICON,&(lpobj->dwStatus));
  822. lpobj->dwFullUserTypeName = 0L; //sizeof(OBJECTDESCRIPTOR);
  823. lpobj->dwSrcOfCopy = 0L;
  824. // lstrcpy((LPTSTR)lpobj+lpobj->dwFullUserTypeName, szUserType);
  825. return S_OK;
  826. }
  827. /////////////////////////////////////////////////////////////////////////
  828. //
  829. // Stream I/O Functions
  830. //
  831. /////////////////////////////////////////////////////////////////////////
  832. HRESULT CPackage::PackageReadFromStream(IStream* pstm)
  833. {
  834. //
  835. // initialize the package object from a stream
  836. // return: s_OK - package properly initialized
  837. // E_FAIL - error initializing package
  838. //
  839. WORD w;
  840. DWORD dw;
  841. DebugMsg(DM_TRACE, "pack - PackageReadFromStream called.");
  842. // read in the package size, which we don't really need, but the old
  843. // packager puts it there.
  844. if (FAILED(pstm->Read(&dw, sizeof(dw), NULL)))
  845. return E_FAIL;
  846. // NOTE: Ok, this is really dumb. The old packager allowed the user
  847. // to create packages without giving them icons or labels, which
  848. // in my opinion is just dumb, it should have at least created a default
  849. // icon and shoved it in the persistent storage...oh well...
  850. // So if the appearance type comes back as NOTHING ( == 0)
  851. // then we just won't read any icon information.
  852. // read in the appearance type
  853. pstm->Read(&w, sizeof(w), NULL);
  854. // read in the icon information
  855. if (w == (WORD)ICON)
  856. {
  857. if (FAILED(IconReadFromStream(pstm)))
  858. {
  859. DebugMsg(DM_TRACE," error reading icon info!!");
  860. return E_FAIL;
  861. }
  862. }
  863. else if (w == (WORD)PICTURE)
  864. {
  865. DebugMsg(DM_TRACE, " old Packager Appearance, not supported!!");
  866. // NOTE: Ideally, we could just ignore the appearance and continue, but to
  867. // do so, we'll need to know how much information to skip over before continuing
  868. // to read from the stream
  869. ShellMessageBox(g_hinst,
  870. NULL,
  871. MAKEINTRESOURCE(IDS_OLD_FORMAT_ERROR),
  872. MAKEINTRESOURCE(IDS_APP_TITLE),
  873. MB_OK | MB_ICONERROR | MB_TASKMODAL);
  874. return E_FAIL;
  875. }
  876. // read in the contents type
  877. pstm->Read(&w, sizeof(w), NULL);
  878. _panetype = (PANETYPE)w;
  879. switch((PANETYPE)w)
  880. {
  881. case PEMBED:
  882. // read in the contents information
  883. return EmbedReadFromStream(pstm);
  884. case CMDLINK:
  885. // read in the contents information
  886. return CmlReadFromStream(pstm);
  887. default:
  888. return E_FAIL;
  889. }
  890. }
  891. //
  892. // read the icon info from a stream
  893. // return: S_OK -- icon read correctly
  894. // E_FAIL -- error reading icon
  895. //
  896. HRESULT CPackage::IconReadFromStream(IStream* pstm)
  897. {
  898. LPIC lpic = IconCreate();
  899. if (lpic)
  900. {
  901. CHAR szTemp[MAX_PATH];
  902. StringReadFromStream(pstm, szTemp, ARRAYSIZE(szTemp));
  903. SHAnsiToTChar(szTemp, lpic->szIconText, ARRAYSIZE(lpic->szIconText));
  904. StringReadFromStream(pstm, szTemp, ARRAYSIZE(szTemp));
  905. SHAnsiToTChar(szTemp, lpic->szIconPath, ARRAYSIZE(lpic->szIconPath));
  906. WORD wDlgIcon;
  907. pstm->Read(&wDlgIcon, sizeof(wDlgIcon), NULL);
  908. lpic->iDlgIcon = (INT) wDlgIcon;
  909. GetCurrentIcon(lpic);
  910. IconCalcSize(lpic);
  911. }
  912. DestroyIC();
  913. _lpic = lpic;
  914. return lpic ? S_OK : E_FAIL;
  915. }
  916. HRESULT CPackage::EmbedReadFromStream(IStream* pstm)
  917. {
  918. //
  919. // reads embedded file contents from a stream
  920. // return: S_OK - contents read succesfully
  921. // E_FAIL - error reading contents
  922. //
  923. DWORD dwSize;
  924. CHAR szFileName[MAX_PATH];
  925. DebugMsg(DM_TRACE, "pack - EmbedReadFromStream called.");
  926. pstm->Read(&dwSize, sizeof(dwSize), NULL); // get string size
  927. pstm->Read(szFileName, dwSize, NULL); // get string
  928. pstm->Read(&dwSize, sizeof(dwSize), NULL); // get file size
  929. // we don't do anything with the file contents here, because anything
  930. // we do could be a potentially expensive operation. so, we just clone
  931. // the stream and hold onto it for future use.
  932. if (_pstmFileContents)
  933. _pstmFileContents->Release();
  934. if (FAILED(pstm->Clone(&_pstmFileContents)))
  935. return E_FAIL;
  936. if (_pEmbed) {
  937. if (_pEmbed->pszTempName) {
  938. DeleteFile(_pEmbed->pszTempName);
  939. delete _pEmbed->pszTempName;
  940. }
  941. delete _pEmbed;
  942. }
  943. _pEmbed = new EMBED;
  944. if (NULL != _pEmbed)
  945. {
  946. _pEmbed->fd.dwFlags = FD_FILESIZE;
  947. _pEmbed->fd.nFileSizeLow = dwSize;
  948. _pEmbed->fd.nFileSizeHigh = 0;
  949. SHAnsiToTChar(szFileName, _pEmbed->fd.cFileName, ARRAYSIZE(_pEmbed->fd.cFileName));
  950. DebugMsg(DM_TRACE," %s\n\r %d",_pEmbed->fd.cFileName,_pEmbed->fd.nFileSizeLow);
  951. return S_OK;
  952. }
  953. else
  954. {
  955. return E_OUTOFMEMORY;
  956. }
  957. }
  958. HRESULT CPackage::CmlReadFromStream(IStream* pstm)
  959. {
  960. //
  961. // reads command line contents from a stream
  962. // return: S_OK - contents read succesfully
  963. // E_FAIL - error reading contents
  964. //
  965. WORD w;
  966. CHAR szCmdLink[CBCMDLINKMAX];
  967. DebugMsg(DM_TRACE, "pack - CmlReadFromStream called.");
  968. // read in the fCmdIsLink and the command line string
  969. if (FAILED(pstm->Read(&w, sizeof(w), NULL)))
  970. return E_FAIL;
  971. StringReadFromStream(pstm, szCmdLink, ARRAYSIZE(szCmdLink));
  972. if (_pCml != NULL)
  973. delete _pCml;
  974. _pCml = new CML;
  975. SHAnsiToTChar(szCmdLink, _pCml->szCommandLine, ARRAYSIZE(_pCml->szCommandLine));
  976. return S_OK;
  977. }
  978. HRESULT CPackage::PackageWriteToStream(IStream* pstm)
  979. {
  980. //
  981. // write the package object to a stream
  982. // return: s_OK - package properly written
  983. // E_FAIL - error writing package
  984. //
  985. WORD w;
  986. DWORD cb = 0L;
  987. DWORD dwSize;
  988. DebugMsg(DM_TRACE, "pack - PackageWriteToStream called.");
  989. // write out a DWORD where the package size will go
  990. if (FAILED(pstm->Write(&cb, sizeof(DWORD), NULL)))
  991. return E_FAIL;
  992. // write out the appearance type
  993. w = (WORD)ICON;
  994. if (FAILED(pstm->Write(&w, sizeof(WORD), NULL)))
  995. return E_FAIL;
  996. cb += 2*sizeof(WORD); // for appearance type and contents type
  997. // write out the icon information
  998. if (FAILED(IconWriteToStream(pstm,&dwSize)))
  999. {
  1000. DebugMsg(DM_TRACE," error writing icon info!!");
  1001. return E_FAIL;
  1002. }
  1003. cb += dwSize;
  1004. // write out the contents type
  1005. w = (WORD)_panetype;
  1006. if (FAILED(pstm->Write(&_panetype, sizeof(WORD), NULL)))
  1007. return E_FAIL;
  1008. switch(_panetype)
  1009. {
  1010. case PEMBED:
  1011. // write out the contents information
  1012. if (FAILED(EmbedWriteToStream(pstm,&dwSize)))
  1013. {
  1014. DebugMsg(DM_TRACE," error writing embed info!!");
  1015. return E_FAIL;
  1016. }
  1017. cb += dwSize;
  1018. break;
  1019. case CMDLINK:
  1020. // write out the contents information
  1021. if (FAILED(CmlWriteToStream(pstm,&dwSize))) {
  1022. DebugMsg(DM_TRACE," error writing cml info!!");
  1023. return E_FAIL;
  1024. }
  1025. cb += dwSize;
  1026. break;
  1027. }
  1028. LARGE_INTEGER li = {0, 0};
  1029. if (FAILED(pstm->Seek(li, STREAM_SEEK_SET, NULL)))
  1030. return E_FAIL;
  1031. if (FAILED(pstm->Write(&cb, sizeof(DWORD), NULL)))
  1032. return E_FAIL;
  1033. return S_OK;
  1034. }
  1035. //
  1036. // write the icon to a stream
  1037. // return: s_OK - icon properly written
  1038. // E_FAIL - error writing icon
  1039. //
  1040. HRESULT CPackage::IconWriteToStream(IStream* pstm, DWORD *pdw)
  1041. {
  1042. DWORD cb = 0;
  1043. CHAR szTemp[MAX_PATH];
  1044. SHTCharToAnsi(_lpic->szIconText, szTemp, ARRAYSIZE(szTemp));
  1045. HRESULT hr = StringWriteToStream(pstm, szTemp, &cb);
  1046. if (SUCCEEDED(hr))
  1047. {
  1048. SHTCharToAnsi(_lpic->szIconPath, szTemp, ARRAYSIZE(szTemp));
  1049. hr = StringWriteToStream(pstm, szTemp, &cb);
  1050. if (SUCCEEDED(hr))
  1051. {
  1052. DWORD dwWrite;
  1053. WORD wDlgIcon = (WORD) _lpic->iDlgIcon;
  1054. hr = pstm->Write(&wDlgIcon, sizeof(wDlgIcon), &dwWrite);
  1055. if (SUCCEEDED(hr))
  1056. {
  1057. cb += dwWrite;
  1058. if (pdw)
  1059. *pdw = cb;
  1060. }
  1061. }
  1062. }
  1063. return hr;
  1064. }
  1065. //
  1066. // write embedded file contents to a stream
  1067. // return: S_OK - contents written succesfully
  1068. // E_FAIL - error writing contents
  1069. //
  1070. HRESULT CPackage::EmbedWriteToStream(IStream* pstm, DWORD *pdw)
  1071. {
  1072. DWORD cb = 0;
  1073. CHAR szTemp[MAX_PATH];
  1074. SHTCharToAnsi(_pEmbed->fd.cFileName, szTemp, ARRAYSIZE(szTemp));
  1075. DWORD dwSize = lstrlenA(szTemp) + 1;
  1076. HRESULT hr = pstm->Write(&dwSize, sizeof(dwSize), &cb);
  1077. if (SUCCEEDED(hr))
  1078. {
  1079. DWORD dwWrite = 0;
  1080. hr = StringWriteToStream(pstm, szTemp, &dwWrite);
  1081. if (SUCCEEDED(hr))
  1082. {
  1083. cb += dwWrite;
  1084. hr = pstm->Write(&_pEmbed->fd.nFileSizeLow, sizeof(_pEmbed->fd.nFileSizeLow), &dwWrite);
  1085. if (SUCCEEDED(hr))
  1086. {
  1087. cb += dwWrite;
  1088. // we want to make sure our file contents stream always points to latest
  1089. // saved file contents
  1090. //
  1091. // NOTE: If we're not saving to our loaded stream, we shouldn't keep a
  1092. // pointer to it, because we're in a SaveAs situation, and we don't want
  1093. // to be hanging onto pointers to other peoples streams.
  1094. //
  1095. if (_pstmFileContents && _pstm == pstm)
  1096. {
  1097. _pstmFileContents->Release();
  1098. pstm->Clone(&_pstmFileContents);
  1099. }
  1100. // This is for screwy apps, like MSWorks that ask us to save ourselves
  1101. // before they've even told us to initialize ourselves.
  1102. //
  1103. if (_pEmbed->fd.cFileName[0])
  1104. {
  1105. hr = CopyFileToStream(_pEmbed->pszTempName, pstm);
  1106. if (SUCCEEDED(hr))
  1107. {
  1108. cb += _pEmbed->fd.nFileSizeLow;
  1109. }
  1110. }
  1111. if (pdw)
  1112. *pdw = cb;
  1113. }
  1114. }
  1115. }
  1116. return hr;
  1117. }
  1118. //
  1119. // write embedded file contents to a stream
  1120. // return: S_OK - contents written succesfully
  1121. // E_FAIL - error writing contents
  1122. //
  1123. HRESULT CPackage::CmlWriteToStream(IStream* pstm, DWORD *pdw)
  1124. {
  1125. DWORD cb = 0;
  1126. WORD w = (WORD)_pCml->fCmdIsLink;
  1127. DebugMsg(DM_TRACE, "pack - CmlWriteToStream called.");
  1128. if (FAILED(pstm->Write(&w, sizeof(w), NULL)))
  1129. return E_FAIL; // write fCmdIsLink
  1130. cb += sizeof(w); // for fCmdIsLink
  1131. CHAR szTemp[MAX_PATH];
  1132. SHTCharToAnsi(_pCml->szCommandLine, szTemp, ARRAYSIZE(szTemp));
  1133. HRESULT hres = StringWriteToStream(pstm, szTemp, &cb);
  1134. if (FAILED(hres))
  1135. return hres; // write command link
  1136. // return the number of bytes written in the outparam
  1137. if (pdw)
  1138. *pdw = cb;
  1139. return S_OK;
  1140. }
  1141. HRESULT CPackage::CreateShortcutOnStream(IStream* pstm)
  1142. {
  1143. HRESULT hr;
  1144. IShellLink *psl;
  1145. TCHAR szArgs[CBCMDLINKMAX - MAX_PATH];
  1146. TCHAR szPath[MAX_PATH];
  1147. hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
  1148. IID_IShellLink, (void **)&psl);
  1149. if (SUCCEEDED(hr))
  1150. {
  1151. IPersistStream *pps;
  1152. lstrcpy(szPath,_pCml->szCommandLine);
  1153. PathSeparateArgs(szPath, szArgs);
  1154. psl->SetPath(szPath);
  1155. psl->SetIconLocation(_lpic->szIconPath, _lpic->iDlgIcon);
  1156. psl->SetShowCmd(SW_SHOW);
  1157. psl->SetArguments(szArgs);
  1158. hr = psl->QueryInterface(IID_IPersistStream, (void **)&pps);
  1159. if (SUCCEEDED(hr))
  1160. {
  1161. hr = pps->Save(pstm,TRUE);
  1162. pps->Release();
  1163. }
  1164. psl->Release();
  1165. }
  1166. LARGE_INTEGER li = {0,0};
  1167. pstm->Seek(li,STREAM_SEEK_SET,NULL);
  1168. return hr;
  1169. }
  1170. HRESULT CPackage::InitVerbEnum(OLEVERB* pVerbs, ULONG cVerbs)
  1171. {
  1172. if (NULL != _pVerbs)
  1173. {
  1174. for (ULONG i = 0; i < _cVerbs; i++)
  1175. {
  1176. delete _pVerbs[i].lpszVerbName;
  1177. }
  1178. delete _pVerbs;
  1179. }
  1180. _pVerbs = pVerbs;
  1181. _cVerbs = cVerbs;
  1182. _nCurVerb = 0;
  1183. return (NULL != pVerbs) ? S_OK : E_FAIL;
  1184. }
  1185. VOID CPackage::ReleaseContextMenu()
  1186. {
  1187. if (NULL != _pcm)
  1188. {
  1189. _pcm->Release();
  1190. _pcm = NULL;
  1191. }
  1192. }
  1193. HRESULT CPackage::GetContextMenu(IContextMenu** ppcm)
  1194. {
  1195. HRESULT hr = E_FAIL;
  1196. ASSERT(NULL != ppcm);
  1197. if (NULL != _pcm)
  1198. {
  1199. _pcm->AddRef();
  1200. *ppcm = _pcm;
  1201. hr = S_OK;
  1202. }
  1203. else if ((PEMBED == _panetype) || (CMDLINK == _panetype))
  1204. {
  1205. if (PEMBED == _panetype)
  1206. {
  1207. hr = CreateTempFileName();
  1208. }
  1209. else
  1210. {
  1211. hr = S_OK;
  1212. }
  1213. if (SUCCEEDED(hr))
  1214. {
  1215. LPITEMIDLIST pidl = SHSimpleIDListFromPath((PEMBED == _panetype) ?
  1216. _pEmbed->pszTempName :
  1217. _pCml->szCommandLine);
  1218. if (NULL != pidl)
  1219. {
  1220. IShellFolder* psf;
  1221. LPCITEMIDLIST pidlChild;
  1222. if (SUCCEEDED(hr = SHBindToIDListParent(pidl, IID_IShellFolder, (void **)&psf, &pidlChild)))
  1223. {
  1224. hr = psf->GetUIObjectOf(NULL, 1, &pidlChild, IID_IContextMenu, NULL, (void**) &_pcm);
  1225. if (SUCCEEDED(hr))
  1226. {
  1227. _pcm->AddRef();
  1228. *ppcm = _pcm;
  1229. }
  1230. psf->Release();
  1231. }
  1232. ILFree(pidl);
  1233. }
  1234. else
  1235. {
  1236. hr = E_OUTOFMEMORY;
  1237. }
  1238. }
  1239. }
  1240. return hr;
  1241. }
  1242. HRESULT CPackage::IconRefresh()
  1243. {
  1244. // we refresh the icon. typically, this will be called the first time
  1245. // the package is created to load the new icon and calculate how big
  1246. // it should be. this will also be called after we edit the package,
  1247. // since the user might have changed the icon.
  1248. // First, load the appropriate icon. We'll load the icon specified by
  1249. // lpic->szIconPath and lpic->iDlgIcon if possible, otherwise we'll just
  1250. // use the generic packager icon.
  1251. //
  1252. GetCurrentIcon(_lpic);
  1253. // Next, we need to have the icon recalculate its size, since it's text
  1254. // might have changed, causing it to get bigger or smaller.
  1255. //
  1256. IconCalcSize(_lpic);
  1257. // Next, notify our containers that our view has changed.
  1258. if (_pIDataAdviseHolder)
  1259. _pIDataAdviseHolder->SendOnDataChange(_pIDataObject,0, NULL);
  1260. if (_pViewSink)
  1261. _pViewSink->OnViewChange(_dwViewAspects,_dwViewAdvf);
  1262. // Set our dirty flag
  1263. _fIsDirty = TRUE;
  1264. return S_OK;
  1265. }
  1266. int CPackage::RunWizard()
  1267. {
  1268. PACKAGER_INFO packInfo;
  1269. HRESULT hr;
  1270. PackWiz_CreateWizard(NULL, &packInfo);
  1271. InitFromPackInfo(&packInfo);
  1272. hr = OleSetClipboard(_pIDataObject);
  1273. if (FAILED(hr))
  1274. {
  1275. ShellMessageBox(g_hinst,
  1276. NULL,
  1277. MAKEINTRESOURCE(IDS_COPY_ERROR),
  1278. MAKEINTRESOURCE(IDS_APP_TITLE),
  1279. MB_ICONERROR | MB_TASKMODAL | MB_OK);
  1280. return -1;
  1281. }
  1282. // we need to do this. our OleUninitialze call at the end, free the
  1283. // libarary and our dataobject on the clipboard unless we flush
  1284. // the clipboard.
  1285. hr = OleFlushClipboard();
  1286. if (FAILED(hr))
  1287. {
  1288. ShellMessageBox(g_hinst,
  1289. NULL,
  1290. MAKEINTRESOURCE(IDS_COPY_ERROR),
  1291. MAKEINTRESOURCE(IDS_APP_TITLE),
  1292. MB_ICONERROR | MB_TASKMODAL | MB_OK);
  1293. return -1;
  1294. }
  1295. ShellMessageBox(g_hinst,
  1296. NULL,
  1297. MAKEINTRESOURCE(IDS_COPY_COMPLETE),
  1298. MAKEINTRESOURCE(IDS_APP_TITLE),
  1299. MB_ICONINFORMATION | MB_TASKMODAL | MB_OK);
  1300. return 0;
  1301. }
  1302. void CPackage::DestroyIC()
  1303. {
  1304. if (_lpic)
  1305. {
  1306. if (_lpic->hDlgIcon)
  1307. DestroyIcon(_lpic->hDlgIcon);
  1308. GlobalFree(_lpic);
  1309. }
  1310. }
  1311. STDAPI_(BOOL) PackWizRunFromExe()
  1312. {
  1313. OleInitialize(NULL);
  1314. CPackage *pPackage = new CPackage;
  1315. if (pPackage)
  1316. {
  1317. pPackage->Init();
  1318. pPackage->RunWizard();
  1319. pPackage->Release();
  1320. }
  1321. OleUninitialize();
  1322. return 0;
  1323. }