|
|
#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; }
|