1568 lines
44 KiB
C++
1568 lines
44 KiB
C++
|
#include "privcpp.h"
|
||
|
|
||
|
#define CPP_FUNCTIONS
|
||
|
// #include <crtfree.h>
|
||
|
|
||
|
UINT g_cfFileContents;
|
||
|
UINT g_cfFileDescriptor;
|
||
|
UINT g_cfObjectDescriptor;
|
||
|
UINT g_cfEmbedSource;
|
||
|
UINT g_cfFileNameW;
|
||
|
|
||
|
INT g_cxIcon;
|
||
|
INT g_cyIcon;
|
||
|
INT g_cxArrange;
|
||
|
INT g_cyArrange;
|
||
|
HFONT g_hfontTitle;
|
||
|
|
||
|
static TCHAR szUserType[] = TEXT("Package");
|
||
|
static TCHAR szDefTempFile[] = TEXT("PKG");
|
||
|
|
||
|
CPackage::CPackage() :
|
||
|
_cRef(1)
|
||
|
{
|
||
|
DebugMsg(DM_TRACE, "pack - CPackage() called.");
|
||
|
g_cRefThisDll++;
|
||
|
|
||
|
// Excel v.5 - v2000 has a hosting bug when they host an object as a link.
|
||
|
// They always remove their hpmbed->hpobj object, yet all their methods
|
||
|
// on the IOleClientSite interface they give us dereference this and fault.
|
||
|
//
|
||
|
TCHAR szProcess[MAX_PATH];
|
||
|
if (GetModuleFileName(NULL, szProcess, ARRAYSIZE(szProcess)) &&
|
||
|
!lstrcmp(TEXT("EXCEL.EXE"), PathFindFileName(szProcess)))
|
||
|
_fNoIOleClientSiteCalls = TRUE;
|
||
|
|
||
|
ASSERT(_cf == 0);
|
||
|
ASSERT(_panetype == NOTHING);
|
||
|
ASSERT(_pEmbed == NULL);
|
||
|
ASSERT(_pCml == NULL);
|
||
|
ASSERT(_fLoaded == FALSE);
|
||
|
|
||
|
ASSERT(_lpszContainerApp == NULL);
|
||
|
ASSERT(_lpszContainerObj == NULL);
|
||
|
|
||
|
ASSERT(_fIsDirty == FALSE);
|
||
|
|
||
|
ASSERT(_pIStorage == NULL);
|
||
|
ASSERT(_pstmFileContents == NULL);
|
||
|
ASSERT(_pstm == NULL);
|
||
|
|
||
|
ASSERT(_pIPersistStorage == NULL);
|
||
|
ASSERT(_pIDataObject == NULL);
|
||
|
ASSERT(_pIOleObject == NULL);
|
||
|
ASSERT(_pIViewObject2 == NULL);
|
||
|
ASSERT(_pIAdviseSink == NULL);
|
||
|
ASSERT(_pIRunnableObject == NULL);
|
||
|
|
||
|
ASSERT(_pIDataAdviseHolder == NULL);
|
||
|
ASSERT(_pIOleAdviseHolder == NULL);
|
||
|
ASSERT(_pIOleClientSite == NULL);
|
||
|
|
||
|
ASSERT(_pViewSink == NULL);
|
||
|
ASSERT(_dwViewAspects == 0);
|
||
|
ASSERT(_dwViewAdvf == 0);
|
||
|
|
||
|
ASSERT(_cVerbs == 0);
|
||
|
ASSERT(_nCurVerb == 0);
|
||
|
ASSERT(_pVerbs == NULL);
|
||
|
ASSERT(_pcm == NULL);
|
||
|
}
|
||
|
|
||
|
|
||
|
CPackage::~CPackage()
|
||
|
{
|
||
|
DebugMsg(DM_TRACE, "pack - ~CPackage() called.");
|
||
|
|
||
|
// We should never be destroyed unless our ref count is zero.
|
||
|
ASSERT(_cRef == 0);
|
||
|
|
||
|
g_cRefThisDll--;
|
||
|
|
||
|
// Destroy our interfaces...
|
||
|
//
|
||
|
delete _pIOleObject;
|
||
|
delete _pIViewObject2;
|
||
|
delete _pIDataObject;
|
||
|
delete _pIPersistStorage;
|
||
|
delete _pIAdviseSink;
|
||
|
delete _pIRunnableObject;
|
||
|
|
||
|
// Destroy the packaged file structure...
|
||
|
//
|
||
|
DestroyIC();
|
||
|
|
||
|
// we destroy depending on which type of object we had packaged
|
||
|
switch(_panetype)
|
||
|
{
|
||
|
case PEMBED:
|
||
|
if (_pEmbed->pszTempName) {
|
||
|
DeleteFile(_pEmbed->pszTempName);
|
||
|
delete _pEmbed->pszTempName;
|
||
|
}
|
||
|
delete _pEmbed;
|
||
|
break;
|
||
|
|
||
|
case CMDLINK:
|
||
|
delete _pCml;
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
// Release Advise pointers...
|
||
|
//
|
||
|
if (_pIDataAdviseHolder)
|
||
|
_pIDataAdviseHolder->Release();
|
||
|
if (_pIOleAdviseHolder)
|
||
|
_pIOleAdviseHolder->Release();
|
||
|
if (_pIOleClientSite)
|
||
|
_pIOleClientSite->Release();
|
||
|
|
||
|
|
||
|
// Release Storage pointers...
|
||
|
//
|
||
|
if (_pIStorage)
|
||
|
_pIStorage->Release();
|
||
|
if (_pstmFileContents)
|
||
|
_pstmFileContents->Release();
|
||
|
if (_pstm)
|
||
|
_pstm->Release();
|
||
|
|
||
|
delete _lpszContainerApp;
|
||
|
delete _lpszContainerObj;
|
||
|
|
||
|
ReleaseContextMenu();
|
||
|
if (NULL != _pVerbs)
|
||
|
{
|
||
|
for (ULONG i = 0; i < _cVerbs; i++)
|
||
|
{
|
||
|
delete _pVerbs[i].lpszVerbName;
|
||
|
}
|
||
|
delete _pVerbs;
|
||
|
}
|
||
|
|
||
|
DebugMsg(DM_TRACE,"CPackage being destroyed. _cRef == %d",_cRef);
|
||
|
}
|
||
|
|
||
|
HRESULT CPackage::Init()
|
||
|
{
|
||
|
//
|
||
|
// initializes parts of a package object that have a potential to fail
|
||
|
// return: S_OK -- everything initialized
|
||
|
// E_FAIL -- error in initialzation
|
||
|
// E_OUTOFMEMORY -- out of memory
|
||
|
//
|
||
|
|
||
|
DebugMsg(DM_TRACE, "pack - Init() called.");
|
||
|
|
||
|
// Initialize all the interfaces...
|
||
|
//
|
||
|
if (!(_pIOleObject = new CPackage_IOleObject(this)))
|
||
|
return E_OUTOFMEMORY;
|
||
|
if (!(_pIViewObject2 = new CPackage_IViewObject2(this)))
|
||
|
return E_OUTOFMEMORY;
|
||
|
if (!(_pIDataObject = new CPackage_IDataObject(this)))
|
||
|
return E_OUTOFMEMORY;
|
||
|
if (!(_pIPersistStorage = new CPackage_IPersistStorage(this)))
|
||
|
return E_OUTOFMEMORY;
|
||
|
if (!(_pIPersistFile = new CPackage_IPersistFile(this)))
|
||
|
return E_OUTOFMEMORY;
|
||
|
if (!(_pIAdviseSink = new CPackage_IAdviseSink(this)))
|
||
|
return E_OUTOFMEMORY;
|
||
|
if (!(_pIRunnableObject = new CPackage_IRunnableObject(this)))
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
// Get some system metrics that we'll need later...
|
||
|
//
|
||
|
LOGFONT lf;
|
||
|
SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, FALSE);
|
||
|
SystemParametersInfo(SPI_ICONHORIZONTALSPACING, 0, &g_cxArrange, FALSE);
|
||
|
SystemParametersInfo(SPI_ICONVERTICALSPACING, 0, &g_cyArrange, FALSE);
|
||
|
g_cxIcon = GetSystemMetrics(SM_CXICON);
|
||
|
g_cyIcon = GetSystemMetrics(SM_CYICON);
|
||
|
g_hfontTitle = CreateFontIndirect(&lf);
|
||
|
|
||
|
// register some clipboard formats that we support...
|
||
|
//
|
||
|
g_cfFileContents = RegisterClipboardFormat(CFSTR_FILECONTENTS);
|
||
|
g_cfFileDescriptor = RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR);
|
||
|
g_cfObjectDescriptor= RegisterClipboardFormat(CFSTR_OBJECTDESCRIPTOR);
|
||
|
g_cfEmbedSource = RegisterClipboardFormat(CFSTR_EMBEDSOURCE);
|
||
|
g_cfFileNameW = RegisterClipboardFormat(TEXT("FileNameW"));
|
||
|
|
||
|
// Initialize a generic icon
|
||
|
_lpic = IconCreate();
|
||
|
IconRefresh();
|
||
|
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// IUnknown Methods...
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
HRESULT CPackage::QueryInterface(REFIID iid, void ** ppvObj)
|
||
|
{
|
||
|
DebugMsg(DM_TRACE, "pack - QueryInterface() called.");
|
||
|
|
||
|
if (iid == IID_IUnknown) {
|
||
|
DebugMsg(DM_TRACE, " getting IID_IUnknown");
|
||
|
*ppvObj = (void *)this;
|
||
|
}
|
||
|
else if (iid == IID_IOleObject) {
|
||
|
DebugMsg(DM_TRACE, " getting IID_IOleObject");
|
||
|
*ppvObj = (void *)_pIOleObject;
|
||
|
}
|
||
|
else if ((iid == IID_IViewObject2) || (iid == IID_IViewObject)) {
|
||
|
DebugMsg(DM_TRACE, " getting IID_IViewObject");
|
||
|
*ppvObj = (void *)_pIViewObject2;
|
||
|
}
|
||
|
else if (iid == IID_IDataObject) {
|
||
|
DebugMsg(DM_TRACE, " getting IID_IDataObject");
|
||
|
*ppvObj = (void *)_pIDataObject;
|
||
|
}
|
||
|
else if ((iid == IID_IPersistStorage) || (iid == IID_IPersist)) {
|
||
|
DebugMsg(DM_TRACE, " getting IID_IPersistStorage");
|
||
|
*ppvObj = (void *)_pIPersistStorage;
|
||
|
}
|
||
|
else if (iid == IID_IPersistFile) {
|
||
|
DebugMsg(DM_TRACE, " getting IID_IPersistFile");
|
||
|
*ppvObj = (void *)_pIPersistFile;
|
||
|
}
|
||
|
else if (iid == IID_IAdviseSink) {
|
||
|
DebugMsg(DM_TRACE, " getting IID_IAdviseSink");
|
||
|
*ppvObj = (void *)_pIAdviseSink;
|
||
|
}
|
||
|
else if (iid == IID_IRunnableObject) {
|
||
|
DebugMsg(DM_TRACE, " getting IID_IRunnableObject");
|
||
|
*ppvObj = (void *)_pIRunnableObject;
|
||
|
}
|
||
|
else if (iid == IID_IEnumOLEVERB)
|
||
|
{
|
||
|
DebugMsg(DM_TRACE, " getting IID_IEnumOLEVERB");
|
||
|
*ppvObj = (IEnumOLEVERB*) this;
|
||
|
}
|
||
|
else {
|
||
|
*ppvObj = NULL;
|
||
|
return E_NOINTERFACE;
|
||
|
}
|
||
|
|
||
|
((LPUNKNOWN)*ppvObj)->AddRef();
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
ULONG CPackage::AddRef()
|
||
|
{
|
||
|
_cRef++;
|
||
|
return _cRef;
|
||
|
}
|
||
|
|
||
|
ULONG CPackage::Release()
|
||
|
{
|
||
|
_cRef--;
|
||
|
if (_cRef > 0)
|
||
|
return _cRef;
|
||
|
|
||
|
delete this;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
HRESULT CPackage_CreateInstnace(LPUNKNOWN * ppunk)
|
||
|
{
|
||
|
DebugMsg(DM_TRACE, "pack - CreateInstance called");
|
||
|
|
||
|
*ppunk = NULL; // null the out param
|
||
|
|
||
|
CPackage* pPack = new CPackage;
|
||
|
if (!pPack)
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
if (FAILED(pPack->Init())) {
|
||
|
delete pPack;
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
*ppunk = pPack;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CPackage::Next(ULONG celt, OLEVERB* rgVerbs, ULONG* pceltFetched)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
if (NULL != rgVerbs)
|
||
|
{
|
||
|
if (1 == celt)
|
||
|
{
|
||
|
if (_nCurVerb < _cVerbs)
|
||
|
{
|
||
|
ASSERT(NULL != _pVerbs);
|
||
|
*rgVerbs = _pVerbs[_nCurVerb];
|
||
|
if ((NULL != _pVerbs[_nCurVerb].lpszVerbName) &&
|
||
|
(NULL != (rgVerbs->lpszVerbName = (LPWSTR) CoTaskMemAlloc(
|
||
|
(lstrlenW(_pVerbs[_nCurVerb].lpszVerbName) + 1) * SIZEOF(WCHAR)))))
|
||
|
{
|
||
|
StrCpyW(rgVerbs->lpszVerbName, _pVerbs[_nCurVerb].lpszVerbName);
|
||
|
}
|
||
|
_nCurVerb++;
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = S_FALSE;
|
||
|
}
|
||
|
if (NULL != pceltFetched)
|
||
|
{
|
||
|
*pceltFetched = (S_OK == hr) ? 1 : 0;
|
||
|
}
|
||
|
}
|
||
|
else if (NULL != pceltFetched)
|
||
|
{
|
||
|
int cVerbsToCopy = min(celt, _cVerbs - _nCurVerb);
|
||
|
if (cVerbsToCopy > 0)
|
||
|
{
|
||
|
ASSERT(NULL != _pVerbs);
|
||
|
CopyMemory(rgVerbs, &(_pVerbs[_nCurVerb]), cVerbsToCopy * sizeof(OLEVERB));
|
||
|
for (int i = 0; i < cVerbsToCopy; i++)
|
||
|
{
|
||
|
if ((NULL != _pVerbs[_nCurVerb + i].lpszVerbName) &&
|
||
|
(NULL != (rgVerbs[i].lpszVerbName = (LPWSTR) CoTaskMemAlloc(
|
||
|
(lstrlenW(_pVerbs[_nCurVerb + i].lpszVerbName) + 1) * SIZEOF(WCHAR)))))
|
||
|
{
|
||
|
StrCpyW(rgVerbs[i].lpszVerbName, _pVerbs[_nCurVerb + i].lpszVerbName);
|
||
|
}
|
||
|
}
|
||
|
_nCurVerb += cVerbsToCopy;
|
||
|
}
|
||
|
*pceltFetched = (ULONG) cVerbsToCopy;
|
||
|
hr = (celt == (ULONG) cVerbsToCopy) ? S_OK : S_FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_INVALIDARG;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_INVALIDARG;
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CPackage::Skip(ULONG celt)
|
||
|
{
|
||
|
if (_nCurVerb + celt > _cVerbs)
|
||
|
{
|
||
|
// there aren't enough elements, go to the end and return S_FALSE
|
||
|
_nCurVerb = _cVerbs;
|
||
|
return S_FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_nCurVerb += celt;
|
||
|
return S_OK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CPackage::Reset()
|
||
|
{
|
||
|
_nCurVerb = 0;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CPackage::Clone(IEnumOLEVERB** ppEnum)
|
||
|
{
|
||
|
if (NULL != ppEnum)
|
||
|
{
|
||
|
*ppEnum = NULL;
|
||
|
}
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Package helper functions
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////
|
||
|
|
||
|
HRESULT CPackage::EmbedInitFromFile(LPCTSTR lpFileName, BOOL fInitFile)
|
||
|
{
|
||
|
//
|
||
|
// get's the file size of the packaged file and set's the name
|
||
|
// of the packaged file if fInitFile == TRUE.
|
||
|
// return: S_OK -- initialized ok
|
||
|
// E_FAIL -- error initializing file
|
||
|
//
|
||
|
|
||
|
DWORD dwSize;
|
||
|
|
||
|
|
||
|
// if this is the first time we've been called, then we need to allocate
|
||
|
// memory for the _pEmbed structure
|
||
|
if (_pEmbed == NULL)
|
||
|
{
|
||
|
_pEmbed = new EMBED;
|
||
|
if (_pEmbed)
|
||
|
{
|
||
|
_pEmbed->pszTempName = NULL;
|
||
|
_pEmbed->hTask = NULL;
|
||
|
_pEmbed->poo = NULL;
|
||
|
_pEmbed->fIsOleFile = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (_pEmbed == NULL)
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
|
||
|
// open the file to package...
|
||
|
//
|
||
|
HANDLE fh = CreateFile(lpFileName, GENERIC_READ, FILE_SHARE_READWRITE,
|
||
|
NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
||
|
if (fh == INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
DWORD dwError = GetLastError();
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
_panetype = PEMBED;
|
||
|
|
||
|
// Get the size of the file
|
||
|
_pEmbed->fd.nFileSizeLow = GetFileSize(fh, &dwSize);
|
||
|
if (_pEmbed->fd.nFileSizeLow == 0xFFFFFFFF)
|
||
|
{
|
||
|
DWORD dwError = GetLastError();
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
ASSERT(dwSize == 0);
|
||
|
_pEmbed->fd.nFileSizeHigh = 0L;
|
||
|
_pEmbed->fd.dwFlags = FD_FILESIZE;
|
||
|
|
||
|
// We only want to set the filename if this is the file to be packaged.
|
||
|
// If it's only a temp file that we're reloading (fInitFile == FALSE) then
|
||
|
// don't bother setting the filename.
|
||
|
//
|
||
|
if (fInitFile)
|
||
|
{
|
||
|
lstrcpy(_pEmbed->fd.cFileName,lpFileName);
|
||
|
DestroyIC();
|
||
|
_lpic = IconCreateFromFile(lpFileName);
|
||
|
if (_pIDataAdviseHolder)
|
||
|
_pIDataAdviseHolder->SendOnDataChange(_pIDataObject,0, NULL);
|
||
|
if (_pViewSink)
|
||
|
_pViewSink->OnViewChange(_dwViewAspects,_dwViewAdvf);
|
||
|
}
|
||
|
|
||
|
_fIsDirty = TRUE;
|
||
|
CloseHandle(fh);
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT CPackage::CmlInitFromFile(LPTSTR lpFileName, BOOL fUpdateIcon, PANETYPE paneType)
|
||
|
{
|
||
|
// if this is the first time we've been called, then we need to allocate
|
||
|
// memory for the _pCml structure
|
||
|
if (_pCml == NULL)
|
||
|
{
|
||
|
_pCml = new CML;
|
||
|
if (_pCml)
|
||
|
{
|
||
|
// we don't use this, but an old packager accessing us might.
|
||
|
_pCml->fCmdIsLink = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (_pCml == NULL)
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
_panetype = paneType;
|
||
|
lstrcpy(_pCml->szCommandLine,lpFileName);
|
||
|
_fIsDirty = TRUE;
|
||
|
|
||
|
if (fUpdateIcon)
|
||
|
{
|
||
|
DestroyIC();
|
||
|
_lpic = IconCreateFromFile(lpFileName);
|
||
|
|
||
|
if (_pIDataAdviseHolder)
|
||
|
_pIDataAdviseHolder->SendOnDataChange(_pIDataObject,0, NULL);
|
||
|
|
||
|
if (_pViewSink)
|
||
|
_pViewSink->OnViewChange(_dwViewAspects,_dwViewAdvf);
|
||
|
}
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CPackage::InitFromPackInfo(LPPACKAGER_INFO lppi)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
DWORD dwFileAttributes = GetFileAttributes(lppi->szFilename);
|
||
|
|
||
|
// Ok, we need to test whether the user tried to package a folder
|
||
|
// instead of a file. If s/he did, then we'll just create a link
|
||
|
// to that folder instead of an embedded file.
|
||
|
//
|
||
|
|
||
|
if (-1 == dwFileAttributes)
|
||
|
{
|
||
|
hr = CmlInitFromFile(lppi->szFilename, FALSE, PACKAGE);
|
||
|
}
|
||
|
else if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||
|
{
|
||
|
hr = CmlInitFromFile(lppi->szFilename, FALSE, CMDLINK);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// we pass FALSE here, because we don't want to write the icon
|
||
|
// information.
|
||
|
//
|
||
|
hr = EmbedInitFromFile(lppi->szFilename, FALSE);
|
||
|
lstrcpy(_pEmbed->fd.cFileName,lppi->szFilename);
|
||
|
_panetype = PEMBED;
|
||
|
}
|
||
|
|
||
|
// set the icon information
|
||
|
if (PathFileExists(lppi->szFilename))
|
||
|
lstrcpy(_lpic->szIconPath, *lppi->szIconPath? lppi->szIconPath : lppi->szFilename);
|
||
|
|
||
|
_lpic->iDlgIcon = lppi->iIcon;
|
||
|
lstrcpy(_lpic->szIconText,lppi->szLabel);
|
||
|
|
||
|
IconRefresh();
|
||
|
|
||
|
// we need to tell the client we want to be saved...it should be smart
|
||
|
// enough to do it anyway, but we can't take any chances.
|
||
|
if (_pIOleClientSite)
|
||
|
_pIOleClientSite->SaveObject();
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT CPackage::CreateTempFileName()
|
||
|
{
|
||
|
ASSERT(NULL != _pEmbed);
|
||
|
TCHAR szDefPath[MAX_PATH];
|
||
|
if (_pEmbed->pszTempName)
|
||
|
{
|
||
|
return S_OK;
|
||
|
}
|
||
|
else if (GetTempPath(ARRAYSIZE(szDefPath), szDefPath))
|
||
|
{
|
||
|
LPTSTR pszFile;
|
||
|
if ((NULL != _lpic) && (TEXT('\0') != _lpic->szIconText[0]))
|
||
|
{
|
||
|
pszFile = _lpic->szIconText;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pszFile = PathFindFileName(_pEmbed->fd.cFileName);
|
||
|
}
|
||
|
PathAppend(szDefPath, pszFile);
|
||
|
if (PathFileExists(szDefPath))
|
||
|
{
|
||
|
TCHAR szOriginal[MAX_PATH];
|
||
|
lstrcpy(szOriginal, szDefPath);
|
||
|
PathYetAnotherMakeUniqueName(szDefPath, szOriginal, NULL, NULL);
|
||
|
}
|
||
|
|
||
|
_pEmbed->pszTempName = new TCHAR[lstrlen(szDefPath) + 1];
|
||
|
if (!_pEmbed->pszTempName)
|
||
|
{
|
||
|
DebugMsg(DM_TRACE," couldn't alloc memory for pszTempName!!");
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
lstrcpy(_pEmbed->pszTempName, szDefPath);
|
||
|
return S_OK;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DebugMsg(DM_TRACE," couldn't get temp path!!");
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HRESULT CPackage::CreateTempFile()
|
||
|
{
|
||
|
//
|
||
|
// used to create a temporary file that holds the file contents of the
|
||
|
// packaged file. the old packager used to keep the packaged file in
|
||
|
// memory which is just a total waste. so, being as we're much more
|
||
|
// efficient, we create a temp file whenever someone wants to do something
|
||
|
// with our contents. we initialze the temp file from the original file
|
||
|
// to package or our persistent storage depending on whether we are a new
|
||
|
// package or a loaded package
|
||
|
// return: S_OK -- temp file created
|
||
|
// E_FAIL -- error creating temp file
|
||
|
//
|
||
|
|
||
|
DebugMsg(DM_TRACE," CreateTempFile() called.");
|
||
|
|
||
|
HRESULT hr = CreateTempFileName();
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
if (PathFileExists(_pEmbed->pszTempName))
|
||
|
{
|
||
|
DebugMsg(DM_TRACE," already have a temp file!!");
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
// if we weren't loaded from a storage then we're in the process of
|
||
|
// creating a package, and should be able to copy the packaged file
|
||
|
// to create a temp file
|
||
|
//
|
||
|
if (!_fLoaded)
|
||
|
{
|
||
|
if (!(CopyFile(_pEmbed->fd.cFileName, _pEmbed->pszTempName, FALSE)))
|
||
|
{
|
||
|
DebugMsg(DM_TRACE," couldn't copy file!!");
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TCHAR szTempFile[MAX_PATH];
|
||
|
// copy the file name because _pEmbed may get re-created below,
|
||
|
// but we want to hold on to this filename:
|
||
|
lstrcpy(szTempFile, _pEmbed->pszTempName);
|
||
|
|
||
|
// if we have a valid stream, but not a file contents stream,
|
||
|
// it's because we went hands off and didn't know where to put
|
||
|
// the seek pointer to init the filecontents stream. so, we
|
||
|
// call PackageReadFromStream to create the FileContents stream
|
||
|
//
|
||
|
if (_pstm && !_pstmFileContents)
|
||
|
{
|
||
|
if (FAILED(PackageReadFromStream(_pstm)))
|
||
|
{
|
||
|
DebugMsg(DM_TRACE," couldn't read from stream!!");
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
IStream* pstm;
|
||
|
_pstmFileContents->Clone(&pstm); // we don't want to move the seek
|
||
|
// pointer on our FileContents stream
|
||
|
|
||
|
if (FAILED(CopyStreamToFile(pstm, szTempFile)))
|
||
|
{
|
||
|
DebugMsg(DM_TRACE," couldn't copy from stream!!");
|
||
|
pstm->Release();
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ASSERT(_pEmbed);
|
||
|
delete _pEmbed->pszTempName;
|
||
|
if (NULL != (_pEmbed->pszTempName = new TCHAR[lstrlen(szTempFile) + 1]))
|
||
|
{
|
||
|
lstrcpy(_pEmbed->pszTempName, szTempFile);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
}
|
||
|
pstm->Release();
|
||
|
}
|
||
|
|
||
|
|
||
|
// whenever we create a tempfile we are activating the contents which
|
||
|
// means we are dirty until we get a save message
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Data Transfer Functions
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
HRESULT CPackage::GetFileDescriptor(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
|
||
|
{
|
||
|
FILEGROUPDESCRIPTOR *pfgd;
|
||
|
|
||
|
|
||
|
DebugMsg(DM_TRACE," Getting File Descriptor");
|
||
|
|
||
|
// we only support HGLOBAL at this time
|
||
|
//
|
||
|
if (!(pFE->tymed & TYMED_HGLOBAL)) {
|
||
|
DebugMsg(DM_TRACE," does not support HGLOBAL!");
|
||
|
return DATA_E_FORMATETC;
|
||
|
}
|
||
|
|
||
|
//// Copy file descriptor to HGLOBAL ///////////////////////////
|
||
|
//
|
||
|
pSTM->tymed = TYMED_HGLOBAL;
|
||
|
|
||
|
// render the file descriptor
|
||
|
if (!(pfgd = (FILEGROUPDESCRIPTOR *)GlobalAlloc(GPTR,
|
||
|
sizeof(FILEGROUPDESCRIPTOR))))
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
pSTM->hGlobal = pfgd;
|
||
|
|
||
|
pfgd->cItems = 1;
|
||
|
|
||
|
switch(_panetype)
|
||
|
{
|
||
|
case PEMBED:
|
||
|
pfgd->fgd[0] = _pEmbed->fd;
|
||
|
GetDisplayName(pfgd->fgd[0].cFileName, _pEmbed->fd.cFileName);
|
||
|
break;
|
||
|
|
||
|
case CMDLINK:
|
||
|
// the label for the package will serve as the filename for the
|
||
|
// shortcut we're going to create.
|
||
|
lstrcpy(pfgd->fgd[0].cFileName, _lpic->szIconText);
|
||
|
// harcoded use of .lnk extension!!
|
||
|
lstrcat(pfgd->fgd[0].cFileName, TEXT(".lnk"));
|
||
|
|
||
|
// we want to add the little arrow to the shortcut.
|
||
|
pfgd->fgd[0].dwFlags = FD_LINKUI;
|
||
|
break;
|
||
|
}
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT CPackage::GetFileContents(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
|
||
|
{
|
||
|
void * lpvDest = NULL;
|
||
|
DWORD dwSize;
|
||
|
HANDLE hFile = NULL;
|
||
|
DWORD cb;
|
||
|
HRESULT hr = E_FAIL;
|
||
|
|
||
|
DebugMsg(DM_TRACE," Getting File Contents");
|
||
|
|
||
|
//// Copy file contents to ISTREAM ///////////////////////////
|
||
|
//
|
||
|
// NOTE: Hopefully, everyone using our object supports TYMED_ISTREAM,
|
||
|
// otherwise we could get some really slow behavior. We might later
|
||
|
// want to implement TYMED_ISTORAGE as well and shove our file contents
|
||
|
// into a single stream named CONTENTS.
|
||
|
//
|
||
|
if (pFE->tymed & TYMED_ISTREAM) {
|
||
|
DebugMsg(DM_TRACE," using TYMED_ISTREAM");
|
||
|
pSTM->tymed = TYMED_ISTREAM;
|
||
|
|
||
|
switch (_panetype) {
|
||
|
case PEMBED:
|
||
|
if (_pstmFileContents)
|
||
|
hr = _pstmFileContents->Clone(&pSTM->pstm);
|
||
|
else
|
||
|
return E_FAIL;
|
||
|
break;
|
||
|
|
||
|
case CMDLINK:
|
||
|
hr = CreateStreamOnHGlobal(NULL, TRUE, &pSTM->pstm);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = CreateShortcutOnStream(pSTM->pstm);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
pSTM->pstm->Release();
|
||
|
pSTM->pstm = NULL;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//// Copy file contents to HGLOBAL ///////////////////////////
|
||
|
//
|
||
|
// NOTE: This is really icky and could potentially be very slow if
|
||
|
// somebody decides to package really large files. Hopefully,
|
||
|
// everyone should be able to get the info it wants through TYMED_ISTREAM,
|
||
|
// but this is here as a common denominator
|
||
|
//
|
||
|
if (pFE->tymed & TYMED_HGLOBAL) {
|
||
|
DebugMsg(DM_TRACE," using TYMED_HGLOBAL");
|
||
|
pSTM->tymed = TYMED_HGLOBAL;
|
||
|
|
||
|
if (_panetype == CMDLINK) {
|
||
|
DebugMsg(DM_TRACE,
|
||
|
" H_GLOBAL not supported for CMDLINK");
|
||
|
return DATA_E_FORMATETC;
|
||
|
}
|
||
|
|
||
|
dwSize = _pEmbed->fd.nFileSizeLow;
|
||
|
|
||
|
// caller is responsible for freeing this memory, even if we fail.
|
||
|
if (!(lpvDest = GlobalAlloc(GPTR, dwSize))) {
|
||
|
DebugMsg(DM_TRACE," out o memory!!");
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
pSTM->hGlobal = lpvDest;
|
||
|
|
||
|
// This will reinitialize our FileContents stream if we had to get
|
||
|
// rid of it. For instance, we have to get rid of all our storage
|
||
|
// pointers in HandsOffStorage, but there's no need to reinit our
|
||
|
// FileContents stream unless we need it again.
|
||
|
//
|
||
|
if (_pstm && !_pstmFileContents)
|
||
|
PackageReadFromStream(_pstm);
|
||
|
|
||
|
if (_pstmFileContents) {
|
||
|
IStream* pstm;
|
||
|
hr = _pstmFileContents->Clone(&pstm);
|
||
|
if (FAILED(hr))
|
||
|
return hr;
|
||
|
hr = pstm->Read(lpvDest, dwSize, &cb);
|
||
|
pstm->Release();
|
||
|
if (FAILED(hr))
|
||
|
return hr;
|
||
|
}
|
||
|
else
|
||
|
return E_FAIL;
|
||
|
|
||
|
if (FAILED(hr) || cb != dwSize) {
|
||
|
DebugMsg(DM_TRACE," error reading from stream!!");
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
return DATA_E_FORMATETC;
|
||
|
}
|
||
|
|
||
|
void DrawIconToDC(HDC hdcMF, LPIC lpic)
|
||
|
{
|
||
|
RECT rcTemp;
|
||
|
HFONT hfont = NULL;
|
||
|
|
||
|
// Initializae the metafile
|
||
|
SetWindowOrgEx(hdcMF, 0, 0, NULL);
|
||
|
SetWindowExtEx(hdcMF, lpic->rc.right - 1, lpic->rc.bottom - 1, NULL);
|
||
|
|
||
|
SetRect(&rcTemp, 0, 0, lpic->rc.right,lpic->rc.bottom);
|
||
|
hfont = SelectFont(hdcMF, g_hfontTitle);
|
||
|
|
||
|
// Center the icon
|
||
|
DrawIcon(hdcMF, (rcTemp.right - g_cxIcon) / 2, 0, lpic->hDlgIcon);
|
||
|
|
||
|
// Center the text below the icon
|
||
|
SetBkMode(hdcMF, TRANSPARENT);
|
||
|
SetTextAlign(hdcMF, TA_CENTER);
|
||
|
TextOut(hdcMF, rcTemp.right / 2, g_cxIcon + 1, lpic->szIconText,
|
||
|
lstrlen(lpic->szIconText));
|
||
|
|
||
|
if (hfont)
|
||
|
SelectObject(hdcMF, hfont);
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CPackage::GetMetafilePict(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
|
||
|
{
|
||
|
LPMETAFILEPICT lpmfpict;
|
||
|
RECT rcTemp;
|
||
|
LPIC lpic = _lpic;
|
||
|
HDC hdcMF = NULL;
|
||
|
|
||
|
|
||
|
DebugMsg(DM_TRACE," Getting MetafilePict");
|
||
|
|
||
|
if (!(pFE->tymed & TYMED_MFPICT)) {
|
||
|
DebugMsg(DM_TRACE," does not support MFPICT!");
|
||
|
return DATA_E_FORMATETC;
|
||
|
}
|
||
|
pSTM->tymed = TYMED_MFPICT;
|
||
|
|
||
|
// Allocate memory for the metafilepict and get a pointer to it
|
||
|
// NOTE: the caller is responsible for freeing this memory, even on fail
|
||
|
//
|
||
|
if (!(pSTM->hMetaFilePict = GlobalAlloc(GPTR, sizeof(METAFILEPICT))))
|
||
|
return E_OUTOFMEMORY;
|
||
|
lpmfpict = (LPMETAFILEPICT)pSTM->hMetaFilePict;
|
||
|
|
||
|
// Create the metafile
|
||
|
if (!(hdcMF = CreateMetaFile(NULL)))
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
DrawIconToDC(hdcMF, lpic);
|
||
|
|
||
|
// Map to device independent coordinates
|
||
|
SetRect(&rcTemp, 0, 0, lpic->rc.right,lpic->rc.bottom);
|
||
|
rcTemp.right =
|
||
|
MulDiv((rcTemp.right - rcTemp.left), HIMETRIC_PER_INCH, DEF_LOGPIXELSX);
|
||
|
rcTemp.bottom =
|
||
|
MulDiv((rcTemp.bottom - rcTemp.top), HIMETRIC_PER_INCH, DEF_LOGPIXELSY);
|
||
|
|
||
|
// Finish filling in the metafile header
|
||
|
lpmfpict->mm = MM_ANISOTROPIC;
|
||
|
lpmfpict->xExt = rcTemp.right;
|
||
|
lpmfpict->yExt = rcTemp.bottom;
|
||
|
lpmfpict->hMF = CloseMetaFile(hdcMF);
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT CPackage::GetEnhMetafile(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
|
||
|
{
|
||
|
DebugMsg(DM_TRACE," Getting EnhancedMetafile");
|
||
|
|
||
|
if (!(pFE->tymed & TYMED_ENHMF)) {
|
||
|
DebugMsg(DM_TRACE," does not support ENHMF!");
|
||
|
return DATA_E_FORMATETC;
|
||
|
}
|
||
|
|
||
|
// Map to device independent coordinates
|
||
|
RECT rcTemp;
|
||
|
SetRect(&rcTemp, 0, 0, _lpic->rc.right,_lpic->rc.bottom);
|
||
|
rcTemp.right =
|
||
|
MulDiv((rcTemp.right - rcTemp.left), HIMETRIC_PER_INCH, DEF_LOGPIXELSX);
|
||
|
rcTemp.bottom =
|
||
|
MulDiv((rcTemp.bottom - rcTemp.top), HIMETRIC_PER_INCH, DEF_LOGPIXELSY);
|
||
|
|
||
|
HDC hdc = CreateEnhMetaFile(NULL, NULL, &rcTemp, NULL);
|
||
|
if (hdc)
|
||
|
{
|
||
|
DrawIconToDC(hdc, _lpic);
|
||
|
|
||
|
pSTM->tymed = TYMED_ENHMF;
|
||
|
pSTM->hEnhMetaFile = CloseEnhMetaFile(hdc);
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pSTM->tymed = TYMED_NULL;
|
||
|
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HRESULT CPackage::GetObjectDescriptor(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
|
||
|
{
|
||
|
LPOBJECTDESCRIPTOR lpobj;
|
||
|
DWORD dwFullUserTypeNameLen;
|
||
|
|
||
|
DebugMsg(DM_TRACE," Getting Object Descriptor");
|
||
|
|
||
|
// we only support HGLOBAL at this time
|
||
|
//
|
||
|
if (!(pFE->tymed & TYMED_HGLOBAL)) {
|
||
|
DebugMsg(DM_TRACE," does not support HGLOBAL!");
|
||
|
return DATA_E_FORMATETC;
|
||
|
}
|
||
|
|
||
|
//// Copy file descriptor to HGLOBAL ///////////////////////////
|
||
|
|
||
|
dwFullUserTypeNameLen = 0; //lstrlen(szUserType) + 1;
|
||
|
pSTM->tymed = TYMED_HGLOBAL;
|
||
|
|
||
|
if (!(lpobj = (OBJECTDESCRIPTOR *)GlobalAlloc(GPTR,
|
||
|
sizeof(OBJECTDESCRIPTOR)+dwFullUserTypeNameLen)))
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
pSTM->hGlobal = lpobj;
|
||
|
|
||
|
lpobj->cbSize = sizeof(OBJECTDESCRIPTOR)+dwFullUserTypeNameLen;
|
||
|
lpobj->clsid = CLSID_CPackage;
|
||
|
lpobj->dwDrawAspect = DVASPECT_CONTENT|DVASPECT_ICON;
|
||
|
_pIOleObject->GetMiscStatus(DVASPECT_CONTENT|DVASPECT_ICON,&(lpobj->dwStatus));
|
||
|
lpobj->dwFullUserTypeName = 0L; //sizeof(OBJECTDESCRIPTOR);
|
||
|
lpobj->dwSrcOfCopy = 0L;
|
||
|
|
||
|
// lstrcpy((LPTSTR)lpobj+lpobj->dwFullUserTypeName, szUserType);
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Stream I/O Functions
|
||
|
//
|
||
|
/////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
HRESULT CPackage::PackageReadFromStream(IStream* pstm)
|
||
|
{
|
||
|
//
|
||
|
// initialize the package object from a stream
|
||
|
// return: s_OK - package properly initialized
|
||
|
// E_FAIL - error initializing package
|
||
|
//
|
||
|
|
||
|
WORD w;
|
||
|
DWORD dw;
|
||
|
|
||
|
DebugMsg(DM_TRACE, "pack - PackageReadFromStream called.");
|
||
|
|
||
|
// read in the package size, which we don't really need, but the old
|
||
|
// packager puts it there.
|
||
|
if (FAILED(pstm->Read(&dw, sizeof(dw), NULL)))
|
||
|
return E_FAIL;
|
||
|
|
||
|
// NOTE: Ok, this is really dumb. The old packager allowed the user
|
||
|
// to create packages without giving them icons or labels, which
|
||
|
// in my opinion is just dumb, it should have at least created a default
|
||
|
// icon and shoved it in the persistent storage...oh well...
|
||
|
// So if the appearance type comes back as NOTHING ( == 0)
|
||
|
// then we just won't read any icon information.
|
||
|
|
||
|
// read in the appearance type
|
||
|
pstm->Read(&w, sizeof(w), NULL);
|
||
|
|
||
|
// read in the icon information
|
||
|
if (w == (WORD)ICON)
|
||
|
{
|
||
|
if (FAILED(IconReadFromStream(pstm)))
|
||
|
{
|
||
|
DebugMsg(DM_TRACE," error reading icon info!!");
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
}
|
||
|
else if (w == (WORD)PICTURE)
|
||
|
{
|
||
|
DebugMsg(DM_TRACE, " old Packager Appearance, not supported!!");
|
||
|
// NOTE: Ideally, we could just ignore the appearance and continue, but to
|
||
|
// do so, we'll need to know how much information to skip over before continuing
|
||
|
// to read from the stream
|
||
|
ShellMessageBox(g_hinst,
|
||
|
NULL,
|
||
|
MAKEINTRESOURCE(IDS_OLD_FORMAT_ERROR),
|
||
|
MAKEINTRESOURCE(IDS_APP_TITLE),
|
||
|
MB_OK | MB_ICONERROR | MB_TASKMODAL);
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
// read in the contents type
|
||
|
pstm->Read(&w, sizeof(w), NULL);
|
||
|
|
||
|
_panetype = (PANETYPE)w;
|
||
|
|
||
|
switch((PANETYPE)w)
|
||
|
{
|
||
|
case PEMBED:
|
||
|
// read in the contents information
|
||
|
return EmbedReadFromStream(pstm);
|
||
|
|
||
|
case CMDLINK:
|
||
|
// read in the contents information
|
||
|
return CmlReadFromStream(pstm);
|
||
|
|
||
|
default:
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// read the icon info from a stream
|
||
|
// return: S_OK -- icon read correctly
|
||
|
// E_FAIL -- error reading icon
|
||
|
//
|
||
|
HRESULT CPackage::IconReadFromStream(IStream* pstm)
|
||
|
{
|
||
|
LPIC lpic = IconCreate();
|
||
|
if (lpic)
|
||
|
{
|
||
|
CHAR szTemp[MAX_PATH];
|
||
|
StringReadFromStream(pstm, szTemp, ARRAYSIZE(szTemp));
|
||
|
SHAnsiToTChar(szTemp, lpic->szIconText, ARRAYSIZE(lpic->szIconText));
|
||
|
|
||
|
StringReadFromStream(pstm, szTemp, ARRAYSIZE(szTemp));
|
||
|
SHAnsiToTChar(szTemp, lpic->szIconPath, ARRAYSIZE(lpic->szIconPath));
|
||
|
|
||
|
WORD wDlgIcon;
|
||
|
pstm->Read(&wDlgIcon, sizeof(wDlgIcon), NULL);
|
||
|
lpic->iDlgIcon = (INT) wDlgIcon;
|
||
|
GetCurrentIcon(lpic);
|
||
|
IconCalcSize(lpic);
|
||
|
}
|
||
|
|
||
|
DestroyIC();
|
||
|
_lpic = lpic;
|
||
|
|
||
|
return lpic ? S_OK : E_FAIL;
|
||
|
}
|
||
|
|
||
|
HRESULT CPackage::EmbedReadFromStream(IStream* pstm)
|
||
|
{
|
||
|
//
|
||
|
// reads embedded file contents from a stream
|
||
|
// return: S_OK - contents read succesfully
|
||
|
// E_FAIL - error reading contents
|
||
|
//
|
||
|
|
||
|
DWORD dwSize;
|
||
|
CHAR szFileName[MAX_PATH];
|
||
|
|
||
|
DebugMsg(DM_TRACE, "pack - EmbedReadFromStream called.");
|
||
|
|
||
|
pstm->Read(&dwSize, sizeof(dwSize), NULL); // get string size
|
||
|
pstm->Read(szFileName, dwSize, NULL); // get string
|
||
|
pstm->Read(&dwSize, sizeof(dwSize), NULL); // get file size
|
||
|
|
||
|
// we don't do anything with the file contents here, because anything
|
||
|
// we do could be a potentially expensive operation. so, we just clone
|
||
|
// the stream and hold onto it for future use.
|
||
|
|
||
|
if (_pstmFileContents)
|
||
|
_pstmFileContents->Release();
|
||
|
|
||
|
if (FAILED(pstm->Clone(&_pstmFileContents)))
|
||
|
return E_FAIL;
|
||
|
|
||
|
if (_pEmbed) {
|
||
|
if (_pEmbed->pszTempName) {
|
||
|
DeleteFile(_pEmbed->pszTempName);
|
||
|
delete _pEmbed->pszTempName;
|
||
|
}
|
||
|
delete _pEmbed;
|
||
|
}
|
||
|
|
||
|
_pEmbed = new EMBED;
|
||
|
if (NULL != _pEmbed)
|
||
|
{
|
||
|
_pEmbed->fd.dwFlags = FD_FILESIZE;
|
||
|
_pEmbed->fd.nFileSizeLow = dwSize;
|
||
|
_pEmbed->fd.nFileSizeHigh = 0;
|
||
|
SHAnsiToTChar(szFileName, _pEmbed->fd.cFileName, ARRAYSIZE(_pEmbed->fd.cFileName));
|
||
|
DebugMsg(DM_TRACE," %s\n\r %d",_pEmbed->fd.cFileName,_pEmbed->fd.nFileSizeLow);
|
||
|
return S_OK;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CPackage::CmlReadFromStream(IStream* pstm)
|
||
|
{
|
||
|
//
|
||
|
// reads command line contents from a stream
|
||
|
// return: S_OK - contents read succesfully
|
||
|
// E_FAIL - error reading contents
|
||
|
//
|
||
|
|
||
|
WORD w;
|
||
|
CHAR szCmdLink[CBCMDLINKMAX];
|
||
|
|
||
|
DebugMsg(DM_TRACE, "pack - CmlReadFromStream called.");
|
||
|
|
||
|
// read in the fCmdIsLink and the command line string
|
||
|
if (FAILED(pstm->Read(&w, sizeof(w), NULL)))
|
||
|
return E_FAIL;
|
||
|
StringReadFromStream(pstm, szCmdLink, ARRAYSIZE(szCmdLink));
|
||
|
|
||
|
if (_pCml != NULL)
|
||
|
delete _pCml;
|
||
|
|
||
|
_pCml = new CML;
|
||
|
SHAnsiToTChar(szCmdLink, _pCml->szCommandLine, ARRAYSIZE(_pCml->szCommandLine));
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CPackage::PackageWriteToStream(IStream* pstm)
|
||
|
{
|
||
|
//
|
||
|
// write the package object to a stream
|
||
|
// return: s_OK - package properly written
|
||
|
// E_FAIL - error writing package
|
||
|
//
|
||
|
|
||
|
WORD w;
|
||
|
DWORD cb = 0L;
|
||
|
DWORD dwSize;
|
||
|
|
||
|
DebugMsg(DM_TRACE, "pack - PackageWriteToStream called.");
|
||
|
|
||
|
// write out a DWORD where the package size will go
|
||
|
if (FAILED(pstm->Write(&cb, sizeof(DWORD), NULL)))
|
||
|
return E_FAIL;
|
||
|
|
||
|
// write out the appearance type
|
||
|
w = (WORD)ICON;
|
||
|
if (FAILED(pstm->Write(&w, sizeof(WORD), NULL)))
|
||
|
return E_FAIL;
|
||
|
cb += 2*sizeof(WORD); // for appearance type and contents type
|
||
|
|
||
|
// write out the icon information
|
||
|
if (FAILED(IconWriteToStream(pstm,&dwSize)))
|
||
|
{
|
||
|
DebugMsg(DM_TRACE," error writing icon info!!");
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
cb += dwSize;
|
||
|
|
||
|
// write out the contents type
|
||
|
w = (WORD)_panetype;
|
||
|
if (FAILED(pstm->Write(&_panetype, sizeof(WORD), NULL)))
|
||
|
return E_FAIL;
|
||
|
|
||
|
switch(_panetype)
|
||
|
{
|
||
|
case PEMBED:
|
||
|
|
||
|
// write out the contents information
|
||
|
if (FAILED(EmbedWriteToStream(pstm,&dwSize)))
|
||
|
{
|
||
|
DebugMsg(DM_TRACE," error writing embed info!!");
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
cb += dwSize;
|
||
|
break;
|
||
|
|
||
|
case CMDLINK:
|
||
|
// write out the contents information
|
||
|
if (FAILED(CmlWriteToStream(pstm,&dwSize))) {
|
||
|
DebugMsg(DM_TRACE," error writing cml info!!");
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
cb += dwSize;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
LARGE_INTEGER li = {0, 0};
|
||
|
if (FAILED(pstm->Seek(li, STREAM_SEEK_SET, NULL)))
|
||
|
return E_FAIL;
|
||
|
if (FAILED(pstm->Write(&cb, sizeof(DWORD), NULL)))
|
||
|
return E_FAIL;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// write the icon to a stream
|
||
|
// return: s_OK - icon properly written
|
||
|
// E_FAIL - error writing icon
|
||
|
//
|
||
|
HRESULT CPackage::IconWriteToStream(IStream* pstm, DWORD *pdw)
|
||
|
{
|
||
|
DWORD cb = 0;
|
||
|
CHAR szTemp[MAX_PATH];
|
||
|
SHTCharToAnsi(_lpic->szIconText, szTemp, ARRAYSIZE(szTemp));
|
||
|
HRESULT hr = StringWriteToStream(pstm, szTemp, &cb);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
SHTCharToAnsi(_lpic->szIconPath, szTemp, ARRAYSIZE(szTemp));
|
||
|
hr = StringWriteToStream(pstm, szTemp, &cb);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
DWORD dwWrite;
|
||
|
WORD wDlgIcon = (WORD) _lpic->iDlgIcon;
|
||
|
hr = pstm->Write(&wDlgIcon, sizeof(wDlgIcon), &dwWrite);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
cb += dwWrite;
|
||
|
if (pdw)
|
||
|
*pdw = cb;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// write embedded file contents to a stream
|
||
|
// return: S_OK - contents written succesfully
|
||
|
// E_FAIL - error writing contents
|
||
|
//
|
||
|
HRESULT CPackage::EmbedWriteToStream(IStream* pstm, DWORD *pdw)
|
||
|
{
|
||
|
DWORD cb = 0;
|
||
|
CHAR szTemp[MAX_PATH];
|
||
|
SHTCharToAnsi(_pEmbed->fd.cFileName, szTemp, ARRAYSIZE(szTemp));
|
||
|
DWORD dwSize = lstrlenA(szTemp) + 1;
|
||
|
HRESULT hr = pstm->Write(&dwSize, sizeof(dwSize), &cb);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
DWORD dwWrite = 0;
|
||
|
hr = StringWriteToStream(pstm, szTemp, &dwWrite);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
cb += dwWrite;
|
||
|
hr = pstm->Write(&_pEmbed->fd.nFileSizeLow, sizeof(_pEmbed->fd.nFileSizeLow), &dwWrite);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
cb += dwWrite;
|
||
|
|
||
|
// we want to make sure our file contents stream always points to latest
|
||
|
// saved file contents
|
||
|
//
|
||
|
// NOTE: If we're not saving to our loaded stream, we shouldn't keep a
|
||
|
// pointer to it, because we're in a SaveAs situation, and we don't want
|
||
|
// to be hanging onto pointers to other peoples streams.
|
||
|
//
|
||
|
if (_pstmFileContents && _pstm == pstm)
|
||
|
{
|
||
|
_pstmFileContents->Release();
|
||
|
pstm->Clone(&_pstmFileContents);
|
||
|
}
|
||
|
|
||
|
// This is for screwy apps, like MSWorks that ask us to save ourselves
|
||
|
// before they've even told us to initialize ourselves.
|
||
|
//
|
||
|
if (_pEmbed->fd.cFileName[0])
|
||
|
{
|
||
|
hr = CopyFileToStream(_pEmbed->pszTempName, pstm);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
cb += _pEmbed->fd.nFileSizeLow;
|
||
|
}
|
||
|
}
|
||
|
if (pdw)
|
||
|
*pdw = cb;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// write embedded file contents to a stream
|
||
|
// return: S_OK - contents written succesfully
|
||
|
// E_FAIL - error writing contents
|
||
|
//
|
||
|
HRESULT CPackage::CmlWriteToStream(IStream* pstm, DWORD *pdw)
|
||
|
{
|
||
|
DWORD cb = 0;
|
||
|
WORD w = (WORD)_pCml->fCmdIsLink;
|
||
|
|
||
|
DebugMsg(DM_TRACE, "pack - CmlWriteToStream called.");
|
||
|
|
||
|
if (FAILED(pstm->Write(&w, sizeof(w), NULL)))
|
||
|
return E_FAIL; // write fCmdIsLink
|
||
|
cb += sizeof(w); // for fCmdIsLink
|
||
|
|
||
|
CHAR szTemp[MAX_PATH];
|
||
|
SHTCharToAnsi(_pCml->szCommandLine, szTemp, ARRAYSIZE(szTemp));
|
||
|
HRESULT hres = StringWriteToStream(pstm, szTemp, &cb);
|
||
|
if (FAILED(hres))
|
||
|
return hres; // write command link
|
||
|
|
||
|
// return the number of bytes written in the outparam
|
||
|
if (pdw)
|
||
|
*pdw = cb;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CPackage::CreateShortcutOnStream(IStream* pstm)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
IShellLink *psl;
|
||
|
TCHAR szArgs[CBCMDLINKMAX - MAX_PATH];
|
||
|
TCHAR szPath[MAX_PATH];
|
||
|
|
||
|
hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
|
||
|
IID_IShellLink, (void **)&psl);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
IPersistStream *pps;
|
||
|
|
||
|
lstrcpy(szPath,_pCml->szCommandLine);
|
||
|
PathSeparateArgs(szPath, szArgs);
|
||
|
|
||
|
psl->SetPath(szPath);
|
||
|
psl->SetIconLocation(_lpic->szIconPath, _lpic->iDlgIcon);
|
||
|
psl->SetShowCmd(SW_SHOW);
|
||
|
psl->SetArguments(szArgs);
|
||
|
|
||
|
hr = psl->QueryInterface(IID_IPersistStream, (void **)&pps);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = pps->Save(pstm,TRUE);
|
||
|
pps->Release();
|
||
|
}
|
||
|
psl->Release();
|
||
|
}
|
||
|
|
||
|
LARGE_INTEGER li = {0,0};
|
||
|
pstm->Seek(li,STREAM_SEEK_SET,NULL);
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT CPackage::InitVerbEnum(OLEVERB* pVerbs, ULONG cVerbs)
|
||
|
{
|
||
|
if (NULL != _pVerbs)
|
||
|
{
|
||
|
for (ULONG i = 0; i < _cVerbs; i++)
|
||
|
{
|
||
|
delete _pVerbs[i].lpszVerbName;
|
||
|
}
|
||
|
delete _pVerbs;
|
||
|
}
|
||
|
_pVerbs = pVerbs;
|
||
|
_cVerbs = cVerbs;
|
||
|
_nCurVerb = 0;
|
||
|
return (NULL != pVerbs) ? S_OK : E_FAIL;
|
||
|
}
|
||
|
|
||
|
VOID CPackage::ReleaseContextMenu()
|
||
|
{
|
||
|
if (NULL != _pcm)
|
||
|
{
|
||
|
_pcm->Release();
|
||
|
_pcm = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HRESULT CPackage::GetContextMenu(IContextMenu** ppcm)
|
||
|
{
|
||
|
HRESULT hr = E_FAIL;
|
||
|
ASSERT(NULL != ppcm);
|
||
|
if (NULL != _pcm)
|
||
|
{
|
||
|
_pcm->AddRef();
|
||
|
*ppcm = _pcm;
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
else if ((PEMBED == _panetype) || (CMDLINK == _panetype))
|
||
|
{
|
||
|
if (PEMBED == _panetype)
|
||
|
{
|
||
|
hr = CreateTempFileName();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
LPITEMIDLIST pidl = SHSimpleIDListFromPath((PEMBED == _panetype) ?
|
||
|
_pEmbed->pszTempName :
|
||
|
_pCml->szCommandLine);
|
||
|
if (NULL != pidl)
|
||
|
{
|
||
|
IShellFolder* psf;
|
||
|
LPCITEMIDLIST pidlChild;
|
||
|
if (SUCCEEDED(hr = SHBindToIDListParent(pidl, IID_IShellFolder, (void **)&psf, &pidlChild)))
|
||
|
{
|
||
|
hr = psf->GetUIObjectOf(NULL, 1, &pidlChild, IID_IContextMenu, NULL, (void**) &_pcm);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
_pcm->AddRef();
|
||
|
*ppcm = _pcm;
|
||
|
}
|
||
|
psf->Release();
|
||
|
}
|
||
|
ILFree(pidl);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT CPackage::IconRefresh()
|
||
|
{
|
||
|
// we refresh the icon. typically, this will be called the first time
|
||
|
// the package is created to load the new icon and calculate how big
|
||
|
// it should be. this will also be called after we edit the package,
|
||
|
// since the user might have changed the icon.
|
||
|
|
||
|
// First, load the appropriate icon. We'll load the icon specified by
|
||
|
// lpic->szIconPath and lpic->iDlgIcon if possible, otherwise we'll just
|
||
|
// use the generic packager icon.
|
||
|
//
|
||
|
GetCurrentIcon(_lpic);
|
||
|
|
||
|
// Next, we need to have the icon recalculate its size, since it's text
|
||
|
// might have changed, causing it to get bigger or smaller.
|
||
|
//
|
||
|
IconCalcSize(_lpic);
|
||
|
|
||
|
// Next, notify our containers that our view has changed.
|
||
|
if (_pIDataAdviseHolder)
|
||
|
_pIDataAdviseHolder->SendOnDataChange(_pIDataObject,0, NULL);
|
||
|
if (_pViewSink)
|
||
|
_pViewSink->OnViewChange(_dwViewAspects,_dwViewAdvf);
|
||
|
|
||
|
// Set our dirty flag
|
||
|
_fIsDirty = TRUE;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
int CPackage::RunWizard()
|
||
|
{
|
||
|
PACKAGER_INFO packInfo;
|
||
|
HRESULT hr;
|
||
|
|
||
|
PackWiz_CreateWizard(NULL, &packInfo);
|
||
|
|
||
|
InitFromPackInfo(&packInfo);
|
||
|
|
||
|
hr = OleSetClipboard(_pIDataObject);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
ShellMessageBox(g_hinst,
|
||
|
NULL,
|
||
|
MAKEINTRESOURCE(IDS_COPY_ERROR),
|
||
|
MAKEINTRESOURCE(IDS_APP_TITLE),
|
||
|
MB_ICONERROR | MB_TASKMODAL | MB_OK);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
// we need to do this. our OleUninitialze call at the end, free the
|
||
|
// libarary and our dataobject on the clipboard unless we flush
|
||
|
// the clipboard.
|
||
|
|
||
|
hr = OleFlushClipboard();
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
ShellMessageBox(g_hinst,
|
||
|
NULL,
|
||
|
MAKEINTRESOURCE(IDS_COPY_ERROR),
|
||
|
MAKEINTRESOURCE(IDS_APP_TITLE),
|
||
|
MB_ICONERROR | MB_TASKMODAL | MB_OK);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
ShellMessageBox(g_hinst,
|
||
|
NULL,
|
||
|
MAKEINTRESOURCE(IDS_COPY_COMPLETE),
|
||
|
MAKEINTRESOURCE(IDS_APP_TITLE),
|
||
|
MB_ICONINFORMATION | MB_TASKMODAL | MB_OK);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void CPackage::DestroyIC()
|
||
|
{
|
||
|
if (_lpic)
|
||
|
{
|
||
|
if (_lpic->hDlgIcon)
|
||
|
DestroyIcon(_lpic->hDlgIcon);
|
||
|
|
||
|
GlobalFree(_lpic);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
STDAPI_(BOOL) PackWizRunFromExe()
|
||
|
{
|
||
|
OleInitialize(NULL);
|
||
|
|
||
|
CPackage *pPackage = new CPackage;
|
||
|
if (pPackage)
|
||
|
{
|
||
|
pPackage->Init();
|
||
|
pPackage->RunWizard();
|
||
|
pPackage->Release();
|
||
|
}
|
||
|
|
||
|
OleUninitialize();
|
||
|
return 0;
|
||
|
}
|