You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1612 lines
46 KiB
1612 lines
46 KiB
#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;
|
|
|
|
BOOL gCmdLineOK = FALSE; // this global flag will (eventually) be set by security policy in packager constructor
|
|
static TCHAR szUserType[] = TEXT("Package");
|
|
static TCHAR szDefTempFile[] = TEXT("PKG");
|
|
|
|
DEFINE_GUID(SID_targetGUID, 0xc7b318a8, 0xfc2c, 0x47e6, 0x8b, 0x2, 0x46, 0xa9, 0xc, 0xc9, 0x1b, 0x43);
|
|
|
|
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.
|
|
//
|
|
_fNoIOleClientSiteCalls = FALSE;
|
|
TCHAR szProcess[MAX_PATH];
|
|
if (GetModuleFileName(NULL, szProcess, ARRAYSIZE(szProcess)) &&
|
|
!lstrcmp(TEXT("EXCEL.EXE"), PathFindFileName(szProcess)))
|
|
{
|
|
DWORD dwVersionSize = GetFileVersionInfoSize(szProcess, 0);
|
|
char * pVersionBuffer = new char[dwVersionSize];
|
|
GetFileVersionInfo(szProcess, 0, ARRAYSIZE(szProcess), pVersionBuffer);
|
|
VS_FIXEDFILEINFO * pVersionInfo;
|
|
UINT dwVerLen;
|
|
BOOL result = VerQueryValue(pVersionBuffer, L"\\", (LPVOID *) &pVersionInfo, &dwVerLen);
|
|
if(result)
|
|
{
|
|
if(pVersionInfo->dwFileVersionLS < 0x0a0000)
|
|
_fNoIOleClientSiteCalls = TRUE;
|
|
else
|
|
_fNoIOleClientSiteCalls = FALSE; // Except that they fixed it in version 10.
|
|
}
|
|
else
|
|
{
|
|
_fNoIOleClientSiteCalls = TRUE;
|
|
}
|
|
|
|
delete [] pVersionBuffer;
|
|
}
|
|
|
|
ASSERT(_cf == 0);
|
|
ASSERT(_panetype == NOTHING);
|
|
}
|
|
|
|
|
|
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 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();
|
|
|
|
|
|
|
|
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.");
|
|
|
|
// 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"));
|
|
|
|
// Get the value of the group policy (if it exists) for the "Software\Policies\Microsoft\Packager -- AllowCommandLinePackages key
|
|
DWORD dwAllowCL = 0;
|
|
DWORD dwDataType;
|
|
DWORD dwcb = sizeof(DWORD);
|
|
|
|
if(ERROR_SUCCESS == SHGetValue(
|
|
HKEY_CURRENT_USER,
|
|
L"Software\\Policies\\Microsoft\\Packager",
|
|
L"AllowCommandLinePackages",
|
|
&dwDataType,
|
|
&dwAllowCL,
|
|
&dwcb))
|
|
{
|
|
if(REG_DWORD == dwDataType && dwAllowCL)
|
|
{
|
|
gCmdLineOK = TRUE;
|
|
}
|
|
}
|
|
|
|
// Initialize a generic icon
|
|
_lpic = IconCreate();
|
|
_IconRefresh();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// IUnknown Methods...
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT CPackage::QueryInterface(REFIID riid, void ** ppv)
|
|
{
|
|
|
|
DebugMsg(DM_TRACE, "pack - QueryInterface() called.");
|
|
static const QITAB qit[] =
|
|
{
|
|
QITABENT(CPackage, IOleObject),
|
|
QITABENT(CPackage, IViewObject),
|
|
QITABENT(CPackage, IViewObject2),
|
|
QITABENT(CPackage, IDataObject),
|
|
QITABENT(CPackage, IPersistStorage),
|
|
QITABENT(CPackage, IPersistFile),
|
|
QITABENT(CPackage, IAdviseSink),
|
|
QITABENT(CPackage, IRunnableObject),
|
|
QITABENT(CPackage, IEnumOLEVERB),
|
|
QITABENT(CPackage, IOleCommandTarget),
|
|
QITABENT(CPackage, IOleCache),
|
|
QITABENT(CPackage, IExternalConnection),
|
|
{ 0 },
|
|
};
|
|
|
|
HRESULT hr = QISearch(this, qit, riid, ppv);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
DebugMsg(DM_TRACE, "pack - QueryInterface() failed! .");
|
|
}
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
ULONG CPackage::AddRef()
|
|
{
|
|
_cRef++;
|
|
return _cRef;
|
|
}
|
|
|
|
ULONG CPackage::Release()
|
|
{
|
|
DebugMsg(DM_TRACE, "pack - Release() called.");
|
|
ULONG cRef = InterlockedDecrement( &_cRef );
|
|
if ( 0 == cRef )
|
|
{
|
|
delete this;
|
|
}
|
|
return cRef;
|
|
}
|
|
|
|
HRESULT CPackage_CreateInstance(LPUNKNOWN * ppunk)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DebugMsg(DM_TRACE, "pack - CreateInstance called");
|
|
|
|
*ppunk = NULL; // null the out param
|
|
|
|
CPackage* pPack = new CPackage;
|
|
if (!pPack)
|
|
hr = E_OUTOFMEMORY;
|
|
else
|
|
{
|
|
if (FAILED(pPack->Init())) {
|
|
delete pPack;
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
hr = pPack->QueryInterface(IID_IUnknown, (void **) ppunk);
|
|
pPack->Release();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CPackage::Next(ULONG celt, OLEVERB* rgVerbs, ULONG* pceltFetched)
|
|
{
|
|
DebugMsg(DM_TRACE, "Next called");
|
|
HRESULT hr;
|
|
if (NULL != rgVerbs)
|
|
{
|
|
if (1 == celt)
|
|
{
|
|
if (_nCurVerb < _cVerbs)
|
|
{
|
|
ASSERT(NULL != _pVerbs);
|
|
*rgVerbs = _pVerbs[_nCurVerb];
|
|
if ((NULL != _pVerbs[_nCurVerb].lpszVerbName))
|
|
{
|
|
DWORD cch = lstrlenW(_pVerbs[_nCurVerb].lpszVerbName) + 1;
|
|
if(NULL != (rgVerbs->lpszVerbName = (LPWSTR) CoTaskMemAlloc(cch * SIZEOF(WCHAR))))
|
|
{
|
|
StringCchCopy(rgVerbs->lpszVerbName, cch, _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))
|
|
{
|
|
DWORD cch = lstrlenW(_pVerbs[_nCurVerb + i].lpszVerbName) + 1;
|
|
if(NULL != (rgVerbs[i].lpszVerbName = (LPWSTR) CoTaskMemAlloc(cch * SIZEOF(WCHAR))))
|
|
{
|
|
StringCchCopy(rgVerbs[i].lpszVerbName, cch, _pVerbs[_nCurVerb + i].lpszVerbName);
|
|
}
|
|
else
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
_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)
|
|
{
|
|
DebugMsg(DM_TRACE, "Skip called");
|
|
HRESULT hr = S_OK;
|
|
|
|
if (_nCurVerb + celt > _cVerbs)
|
|
{
|
|
// there aren't enough elements, go to the end and return S_FALSE
|
|
_nCurVerb = _cVerbs;
|
|
hr = S_FALSE;
|
|
}
|
|
else
|
|
{
|
|
_nCurVerb += celt;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CPackage::Reset()
|
|
{
|
|
DebugMsg(DM_TRACE, "pack - Reset() called.");
|
|
_nCurVerb = 0;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CPackage::Clone(IEnumOLEVERB** ppEnum)
|
|
{
|
|
DebugMsg(DM_TRACE, "pack - Clone() called.");
|
|
|
|
if (NULL != ppEnum)
|
|
{
|
|
*ppEnum = NULL;
|
|
}
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Package helper functions
|
|
//
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT CPackage::EmbedInitFromFile(LPCTSTR lpFileName, BOOL fInitFile)
|
|
{
|
|
DebugMsg(DM_TRACE, "pack - EmbedInitFromFile() called.");
|
|
|
|
//
|
|
// 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)
|
|
{
|
|
StringCchCopy(_pEmbed->fd.cFileName, ARRAYSIZE(_pEmbed->fd.cFileName), lpFileName);
|
|
_DestroyIC();
|
|
_lpic = _IconCreateFromFile(lpFileName);
|
|
if (_pIDataAdviseHolder)
|
|
_pIDataAdviseHolder->SendOnDataChange(this,0, NULL);
|
|
if (_pViewSink)
|
|
_pViewSink->OnViewChange(_dwViewAspects,_dwViewAdvf);
|
|
}
|
|
|
|
_fIsDirty = TRUE;
|
|
CloseHandle(fh);
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT CPackage::CmlInitFromFile(LPTSTR lpFileName, BOOL fUpdateIcon, PANETYPE paneType)
|
|
{
|
|
DebugMsg(DM_TRACE, "pack - CmlINitFromFile() called.");
|
|
|
|
// 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;
|
|
StringCchCopy(_pCml->szCommandLine, ARRAYSIZE(_pCml->szCommandLine), lpFileName);
|
|
_fIsDirty = TRUE;
|
|
|
|
if (fUpdateIcon)
|
|
{
|
|
_DestroyIC();
|
|
_lpic = _IconCreateFromFile(lpFileName);
|
|
|
|
if (_pIDataAdviseHolder)
|
|
_pIDataAdviseHolder->SendOnDataChange(this, 0, NULL);
|
|
|
|
if (_pViewSink)
|
|
_pViewSink->OnViewChange(_dwViewAspects, _dwViewAdvf);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT CPackage::InitFromPackInfo(LPPACKAGER_INFO lppi)
|
|
{
|
|
DebugMsg(DM_TRACE, "pack - InitFromPackInfo() called.");
|
|
|
|
HRESULT hr = E_FAIL;
|
|
|
|
// 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 (lppi->bUseCommandLine)
|
|
{
|
|
hr = CmlInitFromFile(lppi->szFilename, FALSE, CMDLINK);
|
|
}
|
|
else
|
|
{
|
|
// we pass FALSE here, because we don't want to write the icon
|
|
hr = EmbedInitFromFile(lppi->szFilename, FALSE);
|
|
StringCchCopy(_pEmbed->fd.cFileName, ARRAYSIZE(_pEmbed->fd.cFileName), lppi->szFilename);
|
|
_panetype = PEMBED;
|
|
}
|
|
|
|
if(!SUCCEEDED(hr))
|
|
return hr;
|
|
|
|
// set the icon information
|
|
if (PathFileExists(lppi->szFilename))
|
|
{
|
|
StringCchCopy(_lpic->szIconPath, ARRAYSIZE(_lpic->szIconPath), *lppi->szIconPath? lppi->szIconPath : lppi->szFilename);
|
|
}
|
|
|
|
_lpic->iDlgIcon = lppi->iIcon;
|
|
|
|
StringCchCopy(_lpic->szIconText, ARRAYSIZE(_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;
|
|
pszFile = PathFindFileName(_pEmbed->fd.cFileName);
|
|
if(!PathAppend(szDefPath, pszFile))
|
|
return E_FAIL;
|
|
|
|
HRESULT hr;
|
|
if (PathFileExists(szDefPath))
|
|
{
|
|
TCHAR szOriginal[MAX_PATH];
|
|
StringCchCopy(szOriginal, ARRAYSIZE(szOriginal), szDefPath);
|
|
hr = PathYetAnotherMakeUniqueName(szDefPath, szOriginal, NULL, NULL)
|
|
? S_OK
|
|
: E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
DWORD cch = lstrlen(szDefPath) + 1;
|
|
_pEmbed->pszTempName = new TCHAR[cch];
|
|
if (!_pEmbed->pszTempName)
|
|
{
|
|
DebugMsg(DM_TRACE," couldn't alloc memory for pszTempName!!");
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
StringCchCopy(_pEmbed->pszTempName, cch, szDefPath);
|
|
}
|
|
return hr;
|
|
}
|
|
else
|
|
{
|
|
DebugMsg(DM_TRACE," couldn't get temp path!!");
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
HRESULT CPackage::CreateTempFile(bool deleteExisting)
|
|
{
|
|
//
|
|
// 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 (_pEmbed->pszTempName && PathFileExists(_pEmbed->pszTempName))
|
|
{
|
|
DebugMsg(DM_TRACE," already have a temp file!!");
|
|
if(!deleteExisting)
|
|
return S_OK;
|
|
else
|
|
{
|
|
DeleteFile(_pEmbed->pszTempName);
|
|
}
|
|
}
|
|
|
|
// 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
|
|
{
|
|
// nothing to do, we've already loaded it. temp file must exist
|
|
ASSERT(_pEmbed);
|
|
ASSERT(_pEmbed->pszTempName);
|
|
}
|
|
|
|
// 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)
|
|
{
|
|
DebugMsg(DM_TRACE, "pack - GetFileDescriptor called");
|
|
FILEGROUPDESCRIPTOR *pfgd;
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
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); // This is packagers, not the shell (for now)
|
|
break;
|
|
|
|
case CMDLINK:
|
|
// the label for the package will serve as the filename for the
|
|
// shortcut we're going to create.
|
|
hr = StringCchCopy(pfgd->fgd[0].cFileName, ARRAYSIZE(pfgd->fgd[0].cFileName), _lpic->szIconText);
|
|
// harcoded use of .lnk extension!!
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
hr = StringCchCat(pfgd->fgd[0].cFileName, ARRAYSIZE(pfgd->fgd[0].cFileName), TEXT(".lnk"));
|
|
}
|
|
|
|
// we want to add the little arrow to the shortcut.
|
|
pfgd->fgd[0].dwFlags = FD_LINKUI;
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CPackage::GetFileContents(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
|
|
{
|
|
void * lpvDest = NULL;
|
|
DWORD dwSize;
|
|
HANDLE hFile = NULL;
|
|
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)
|
|
{
|
|
DWORD dwFileLength;
|
|
DebugMsg(DM_TRACE," using TYMED_ISTREAM");
|
|
pSTM->tymed = TYMED_ISTREAM;
|
|
|
|
hr = CreateStreamOnHGlobal(NULL, TRUE, &pSTM->pstm);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
switch (_panetype)
|
|
{
|
|
case PEMBED:
|
|
hr = CopyFileToStream(_pEmbed->pszTempName, pSTM->pstm, &dwFileLength);
|
|
break;
|
|
|
|
case CMDLINK:
|
|
hr = CreateShortcutOnStream(pSTM->pstm);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
pSTM->pstm->Release();
|
|
pSTM->pstm = NULL;
|
|
}
|
|
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;
|
|
|
|
// open file to copy to stream
|
|
hFile = CreateFile(_pEmbed->pszTempName, GENERIC_READ,
|
|
FILE_SHARE_READWRITE, NULL,
|
|
OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
DebugMsg(DM_TRACE, " couldn't open file!!");
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
goto ErrRet;
|
|
}
|
|
|
|
DWORD dwSizeLow;
|
|
DWORD dwSizeHigh;
|
|
|
|
// Figure out how much to copy...
|
|
dwSizeLow = GetFileSize(hFile, &dwSizeHigh);
|
|
ASSERT(dwSizeHigh == 0);
|
|
|
|
SetFilePointer(hFile, 0L, NULL, FILE_BEGIN);
|
|
|
|
// read in the file
|
|
DWORD cbRead;
|
|
if (ReadFile(hFile, lpvDest, dwSize, &cbRead, NULL))
|
|
{
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
ErrRet:
|
|
CloseHandle(hFile);
|
|
GlobalFree(pSTM->hGlobal);
|
|
pSTM->hGlobal = NULL;
|
|
return hr;
|
|
}
|
|
|
|
return DATA_E_FORMATETC;
|
|
}
|
|
|
|
|
|
|
|
void CPackage::_DrawIconToDC(HDC hdcMF, LPIC lpic, bool stripAlpha, LPCTSTR pszActualFileName)
|
|
{
|
|
RECT rcTemp;
|
|
HFONT hfont = NULL;
|
|
|
|
// Initializae the metafile
|
|
_IconCalcSize(lpic);
|
|
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
|
|
if(stripAlpha)
|
|
AlphaStripRenderIcon(hdcMF, (rcTemp.right - g_cxIcon) / 2, 0, lpic->hDlgIcon, NULL);
|
|
else
|
|
DrawIcon(hdcMF, (rcTemp.right - g_cxIcon) / 2, 0, lpic->hDlgIcon);
|
|
|
|
// Center the text below the icon
|
|
SetBkMode(hdcMF, TRANSPARENT);
|
|
SetTextAlign(hdcMF, TA_CENTER);
|
|
|
|
|
|
// Set's the icon text for MF ie Word display's it from here.
|
|
WCHAR szLabel[MAX_PATH];
|
|
_CreateSaferIconTitle(szLabel, lpic->szIconText);
|
|
|
|
TextOut(hdcMF, rcTemp.right / 2, g_cxIcon + 1, szLabel, lstrlen(szLabel));
|
|
|
|
if (hfont)
|
|
SelectObject(hdcMF, hfont);
|
|
}
|
|
|
|
|
|
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, false, _pEmbed->fd.cFileName);
|
|
pSTM->tymed = TYMED_ENHMF;
|
|
pSTM->hEnhMetaFile = CloseEnhMetaFile(hdc);
|
|
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
pSTM->tymed = TYMED_NULL;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
|
|
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, true, _pEmbed->fd.cFileName);
|
|
|
|
// 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::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;
|
|
GetMiscStatus(DVASPECT_CONTENT|DVASPECT_ICON,&(lpobj->dwStatus));
|
|
lpobj->dwFullUserTypeName = 0L; //sizeof(OBJECTDESCRIPTOR);
|
|
lpobj->dwSrcOfCopy = 0L;
|
|
|
|
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
|
|
#ifdef USE_RESOURCE_DLL
|
|
HINSTANCE hInstRes = LoadLibraryEx(L"sp1res.dll", NULL, LOAD_LIBRARY_AS_DATAFILE);
|
|
if(!hInstRes)
|
|
return E_FAIL;
|
|
#endif
|
|
|
|
ShellMessageBox(hInstRes,
|
|
NULL,
|
|
MAKEINTRESOURCE(IDS_OLD_FORMAT_ERROR),
|
|
MAKEINTRESOURCE(IDS_APP_TITLE),
|
|
MB_OK | MB_ICONERROR | MB_TASKMODAL);
|
|
#ifdef USE_RESOURCE_DLL
|
|
FreeLibrary(hInstRes);
|
|
#endif
|
|
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)
|
|
{
|
|
UINT cb;
|
|
DebugMsg(DM_TRACE, "pack - IconReadFromStream() called.");
|
|
|
|
LPIC lpic = IconCreate();
|
|
if (lpic)
|
|
{
|
|
CHAR szTemp[MAX_PATH];
|
|
cb = (UINT) StringReadFromStream(pstm, szTemp, ARRAYSIZE(szTemp));
|
|
SHAnsiToTChar(szTemp, lpic->szIconText, ARRAYSIZE(lpic->szIconText));
|
|
|
|
cb = (UINT) 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;
|
|
DWORD cb;
|
|
CHAR szFileName[MAX_PATH];
|
|
|
|
DebugMsg(DM_TRACE, "pack - EmbedReadFromStream called.");
|
|
|
|
pstm->Read(&dwSize, sizeof(dwSize), &cb); // get string size
|
|
if(dwSize < MAX_PATH)
|
|
{
|
|
pstm->Read(szFileName, dwSize, &cb); // get string
|
|
}
|
|
else
|
|
return E_FAIL;
|
|
|
|
pstm->Read(&dwSize, sizeof(dwSize), &cb); // get file size
|
|
|
|
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;
|
|
_pEmbed->fIsOleFile = TRUE; // Give it a chance to do ole style launch
|
|
SHAnsiToTChar(szFileName, _pEmbed->fd.cFileName, ARRAYSIZE(_pEmbed->fd.cFileName));
|
|
|
|
DebugMsg(DM_TRACE," %s\n\r %d",_pEmbed->fd.cFileName,_pEmbed->fd.nFileSizeLow);
|
|
|
|
HRESULT hr = CreateTempFileName();
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
if (FAILED(CopyStreamToFile(pstm, _pEmbed->pszTempName, _pEmbed->fd.nFileSizeLow)))
|
|
{
|
|
DebugMsg(DM_TRACE," couldn't copy from stream!!");
|
|
return E_FAIL;
|
|
}
|
|
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
|
|
//
|
|
DebugMsg(DM_TRACE, "pack - CmlReadFromStream() called.");
|
|
|
|
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;
|
|
|
|
cb = 0;
|
|
|
|
// write out the appearance type
|
|
w = (WORD)ICON;
|
|
if (FAILED(pstm->Write(&w, sizeof(WORD), NULL)))
|
|
return E_FAIL;
|
|
cb += sizeof(WORD);
|
|
|
|
// 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;
|
|
cb += sizeof(WORD);
|
|
|
|
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)
|
|
{
|
|
ASSERT(pdw);
|
|
DebugMsg(DM_TRACE, "pack - IconWriteToStream() called.");
|
|
|
|
CHAR szTemp[MAX_PATH];
|
|
SHTCharToAnsi(_lpic->szIconText, szTemp, ARRAYSIZE(szTemp));
|
|
*pdw = 0;
|
|
HRESULT hr = StringWriteToStream(pstm, szTemp, pdw);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
SHTCharToAnsi(_lpic->szIconPath, szTemp, ARRAYSIZE(szTemp));
|
|
hr = StringWriteToStream(pstm, szTemp, pdw);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
DWORD dwWrite;
|
|
WORD wDlgIcon = (WORD) _lpic->iDlgIcon;
|
|
hr = pstm->Write(&wDlgIcon, sizeof(wDlgIcon), &dwWrite);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*pdw += dwWrite;
|
|
}
|
|
}
|
|
}
|
|
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)
|
|
{
|
|
DebugMsg(DM_TRACE, "pack - EmbedWriteToStream() called.");
|
|
|
|
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;
|
|
|
|
// This is for screwy apps, like MSWorks that ask us to save ourselves
|
|
// before they've even told us to initialize ourselves.
|
|
//
|
|
if (_pEmbed->pszTempName && _pEmbed->pszTempName[0])
|
|
{
|
|
DWORD dwFileSize;
|
|
hr = CopyFileToStream(_pEmbed->pszTempName, pstm, &dwFileSize);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
cb += dwFileSize;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASSERT(0);
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
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)
|
|
{
|
|
DebugMsg(DM_TRACE, "pack - CreateShortcutOnStream() called.");
|
|
|
|
HRESULT hr;
|
|
IShellLink *psl;
|
|
TCHAR szArgs[CBCMDLINKMAX];
|
|
TCHAR szPath[CBCMDLINKMAX];
|
|
|
|
hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IShellLink, (void **)&psl);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IPersistStream *pps;
|
|
|
|
StringCchCopy(szPath, ARRAYSIZE(szPath), _pCml->szCommandLine);
|
|
PathSeparateArgs(szPath, szArgs, ARRAYSIZE(szPath));
|
|
|
|
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)
|
|
{
|
|
DebugMsg(DM_TRACE, "pack - InitVerbEnum called");
|
|
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)
|
|
{
|
|
DebugMsg(DM_TRACE, "pack - GetContextMenu called");
|
|
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()
|
|
{
|
|
DebugMsg(DM_TRACE, "pack - IconRefresh() called.");
|
|
|
|
// 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(this,0, NULL);
|
|
if (_pViewSink)
|
|
_pViewSink->OnViewChange(_dwViewAspects,_dwViewAdvf);
|
|
|
|
// Set our dirty flag
|
|
_fIsDirty = TRUE;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
void CPackage::_DestroyIC()
|
|
{
|
|
if (_lpic)
|
|
{
|
|
if (_lpic->hDlgIcon)
|
|
DestroyIcon(_lpic->hDlgIcon);
|
|
|
|
GlobalFree(_lpic);
|
|
}
|
|
}
|
|
|
|
|
|
// This is an IOleCommandTarget method that we use because we cannot marshal the pIOleAdviseHolder.
|
|
// While we're at it, we use the _pIOleClientSite methods too.
|
|
|
|
HRESULT CPackage::Exec(const GUID* pguidCmdGroup, DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG* pvaIn, VARIANTARG* pvaOut)
|
|
{
|
|
DebugMsg(DM_TRACE, "pack Exec called");
|
|
HRESULT hr = OLECMDERR_E_UNKNOWNGROUP;
|
|
|
|
if (*pguidCmdGroup != SID_targetGUID)
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
if(nCmdID == 0) // for future expansion
|
|
{
|
|
// this will set our dirty flag...
|
|
if (FAILED(EmbedInitFromFile(_pEmbed->pszTempName,FALSE)))
|
|
{
|
|
#ifdef USE_RESOURCE_DLL
|
|
HINSTANCE hInstRes = LoadLibraryEx(L"sp1res.dll", NULL, LOAD_LIBRARY_AS_DATAFILE);
|
|
if(!hInstRes)
|
|
return E_FAIL;
|
|
#endif
|
|
|
|
ShellMessageBox(hInstRes,
|
|
NULL,
|
|
MAKEINTRESOURCE(IDS_UPDATE_ERROR),
|
|
MAKEINTRESOURCE(IDS_APP_TITLE),
|
|
MB_ICONERROR | MB_TASKMODAL | MB_OK);
|
|
#ifdef USE_RESOURCE_DLL
|
|
FreeLibrary(hInstRes);
|
|
#endif
|
|
|
|
}
|
|
|
|
// The SendOnDataChange is necessary for Word to save any changes
|
|
if(_pIDataAdviseHolder)
|
|
{
|
|
// if it fails, no harm, no foul?
|
|
_pIDataAdviseHolder->SendOnDataChange(this, 0, 0);
|
|
}
|
|
|
|
if(_pIOleClientSite)
|
|
_pIOleClientSite->SaveObject();
|
|
|
|
hr = _pIOleAdviseHolder->SendOnSave();
|
|
if(FAILED(hr))
|
|
return hr;
|
|
|
|
hr = _pIOleAdviseHolder->SendOnClose();
|
|
_pEmbed->hTask = NULL;
|
|
if(FAILED(hr))
|
|
return hr;
|
|
|
|
|
|
if (_pIOleClientSite && !_fNoIOleClientSiteCalls)
|
|
hr = _pIOleClientSite->OnShowWindow(FALSE);
|
|
|
|
_pEmbed->hTask = NULL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
// This is a required IOleCommandTarget method that should never be called
|
|
|
|
HRESULT CPackage::QueryStatus(const GUID* pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT* pCmdText)
|
|
{
|
|
DebugMsg(DM_TRACE, "pack - QueryStatus called");
|
|
return OLECMDERR_E_UNKNOWNGROUP;
|
|
}
|