pack2.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 44k
Category:

Windows Kernel

Development Platform:

Visual C++

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