742 lines
26 KiB
C++
742 lines
26 KiB
C++
|
#include "privcpp.h"
|
||
|
|
||
|
HWND g_hTaskWnd;
|
||
|
BOOL CALLBACK GetTaskWndProc(HWND hwnd, DWORD lParam);
|
||
|
DWORD CALLBACK MainWaitOnChildThreadProc(void *lpv);
|
||
|
|
||
|
typedef struct {
|
||
|
CPackage_IOleObject *pObj;
|
||
|
HANDLE h;
|
||
|
} MAINWAITONCHILD;
|
||
|
|
||
|
CPackage_IOleObject::CPackage_IOleObject(CPackage *pPackage) :
|
||
|
_pPackage(pPackage)
|
||
|
{
|
||
|
ASSERT(_cRef == 0);
|
||
|
}
|
||
|
|
||
|
CPackage_IOleObject::~CPackage_IOleObject()
|
||
|
{
|
||
|
DebugMsg(DM_TRACE,"CPackage_IOleObject destroyed with ref count %d",_cRef);
|
||
|
}
|
||
|
|
||
|
|
||
|
//////////////////////////////////
|
||
|
//
|
||
|
// IUnknown Methods...
|
||
|
//
|
||
|
HRESULT CPackage_IOleObject::QueryInterface(REFIID iid, void ** ppv)
|
||
|
{
|
||
|
return _pPackage->QueryInterface(iid,ppv);
|
||
|
}
|
||
|
|
||
|
ULONG CPackage_IOleObject::AddRef(void)
|
||
|
{
|
||
|
_cRef++; // interface ref count for debugging
|
||
|
return _pPackage->AddRef();
|
||
|
}
|
||
|
|
||
|
ULONG CPackage_IOleObject::Release(void)
|
||
|
{
|
||
|
_cRef--; // interface ref count for debugging
|
||
|
return _pPackage->Release();
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////
|
||
|
//
|
||
|
// IOleObject Methods...
|
||
|
//
|
||
|
HRESULT CPackage_IOleObject::SetClientSite(LPOLECLIENTSITE pClientSite)
|
||
|
{
|
||
|
DebugMsg(DM_TRACE, "pack oo - SetClientSite() called.");
|
||
|
|
||
|
if (!pClientSite)
|
||
|
return E_POINTER;
|
||
|
|
||
|
if (_pPackage->_pIOleClientSite != NULL)
|
||
|
_pPackage->_pIOleClientSite->Release();
|
||
|
|
||
|
_pPackage->_pIOleClientSite = pClientSite;
|
||
|
_pPackage->_pIOleClientSite->AddRef();
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT CPackage_IOleObject::GetClientSite(LPOLECLIENTSITE *ppClientSite)
|
||
|
{
|
||
|
DebugMsg(DM_TRACE, "pack oo - GetClientSite() called.");
|
||
|
|
||
|
if (ppClientSite == NULL)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
// Be sure to AddRef the pointer we're giving away.
|
||
|
*ppClientSite = _pPackage->_pIOleClientSite;
|
||
|
_pPackage->_pIOleClientSite->AddRef();
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT CPackage_IOleObject::SetHostNames(LPCOLESTR szContainerApp, LPCOLESTR szContainerObj)
|
||
|
{
|
||
|
DebugMsg(DM_TRACE, "pack oo - SetHostNames() called.");
|
||
|
|
||
|
delete _pPackage->_lpszContainerApp;
|
||
|
|
||
|
if (NULL != (_pPackage->_lpszContainerApp = new OLECHAR[lstrlenW(szContainerApp) + 1]))
|
||
|
{
|
||
|
lstrcpyW(_pPackage->_lpszContainerApp,szContainerApp);
|
||
|
}
|
||
|
|
||
|
delete _pPackage->_lpszContainerObj;
|
||
|
|
||
|
if (NULL != (_pPackage->_lpszContainerObj = new OLECHAR[lstrlenW(szContainerObj) + 1]))
|
||
|
{
|
||
|
lstrcpyW(_pPackage->_lpszContainerObj,szContainerObj);
|
||
|
}
|
||
|
|
||
|
switch(_pPackage->_panetype) {
|
||
|
case PEMBED:
|
||
|
if (_pPackage->_pEmbed->poo)
|
||
|
_pPackage->_pEmbed->poo->SetHostNames(szContainerApp,szContainerObj);
|
||
|
break;
|
||
|
case CMDLINK:
|
||
|
// nothing to do...we're a link to a file, so we don't ever get
|
||
|
// opened and need to be edited or some such thing.
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT CPackage_IOleObject::Close(DWORD dwSaveOption)
|
||
|
{
|
||
|
DebugMsg(DM_TRACE, "pack oo - Close() called.");
|
||
|
|
||
|
switch (_pPackage->_panetype) {
|
||
|
case PEMBED:
|
||
|
if (_pPackage->_pEmbed == NULL)
|
||
|
return S_OK;
|
||
|
|
||
|
// tell the server to close, and release our pointer to it
|
||
|
if (_pPackage->_pEmbed->poo) {
|
||
|
_pPackage->_pEmbed->poo->Close(dwSaveOption);
|
||
|
_pPackage->_pEmbed->poo->Unadvise(_pPackage->_dwCookie);
|
||
|
_pPackage->_pEmbed->poo->Release();
|
||
|
_pPackage->_pEmbed->poo = NULL;
|
||
|
}
|
||
|
break;
|
||
|
case CMDLINK:
|
||
|
// again, nothing to do...we shouldn't be getting close
|
||
|
// messages since we're never activated through OLE.
|
||
|
break;
|
||
|
}
|
||
|
if ((dwSaveOption != OLECLOSE_NOSAVE) && (_pPackage->_fIsDirty))
|
||
|
{
|
||
|
_pPackage->_pIOleClientSite->SaveObject();
|
||
|
if (_pPackage->_pIOleAdviseHolder)
|
||
|
_pPackage->_pIOleAdviseHolder->SendOnSave();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT CPackage_IOleObject::SetMoniker(DWORD dwWhichMoniker, LPMONIKER pmk)
|
||
|
{
|
||
|
DebugMsg(DM_TRACE, "pack oo - SetMoniker() called.");
|
||
|
|
||
|
// NOTE: Uninteresting for embeddings only.
|
||
|
return (E_NOTIMPL);
|
||
|
}
|
||
|
|
||
|
HRESULT CPackage_IOleObject::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker,
|
||
|
LPMONIKER *ppmk)
|
||
|
{
|
||
|
DebugMsg(DM_TRACE, "pack oo - GetMoniker() called.");
|
||
|
|
||
|
// NOTE: Unintersting for embeddings only.
|
||
|
return (E_NOTIMPL);
|
||
|
}
|
||
|
|
||
|
HRESULT CPackage_IOleObject::InitFromData(LPDATAOBJECT pDataObject, BOOL fCreation,
|
||
|
DWORD dwReserved)
|
||
|
{
|
||
|
DebugMsg(DM_TRACE, "pack oo - InitFromData() called.");
|
||
|
|
||
|
// NOTE: This isn't supported at this time
|
||
|
return (E_NOTIMPL);
|
||
|
}
|
||
|
|
||
|
HRESULT CPackage_IOleObject::GetClipboardData(DWORD dwReserved, LPDATAOBJECT *ppDataObject)
|
||
|
{
|
||
|
DebugMsg(DM_TRACE, "pack oo - GetClipboardData() called.");
|
||
|
|
||
|
if (ppDataObject == NULL)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
*ppDataObject = _pPackage->_pIDataObject;
|
||
|
AddRef();
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT CPackage_IOleObject::DoVerb(LONG iVerb, LPMSG lpmsg, LPOLECLIENTSITE pActiveSite,
|
||
|
LONG lindex, HWND hwndParent, LPCRECT lprcPosRect)
|
||
|
{
|
||
|
void *lpFileData = NULL;
|
||
|
BOOL fError = TRUE;
|
||
|
DWORD id;
|
||
|
SHELLEXECUTEINFO sheinf = {sizeof(SHELLEXECUTEINFO)};
|
||
|
|
||
|
DebugMsg(DM_TRACE, "pack oo - DoVerb() called.");
|
||
|
DebugMsg(DM_TRACE, " iVerb==%d",iVerb);
|
||
|
|
||
|
// We allow show, primary verb, edit, and context menu verbs on our packages...
|
||
|
//
|
||
|
if (iVerb < OLEIVERB_SHOW)
|
||
|
return E_NOTIMPL;
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////
|
||
|
// SHOW VERB
|
||
|
/////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
if (iVerb == OLEIVERB_SHOW) {
|
||
|
PACKAGER_INFO packInfo = {0};
|
||
|
|
||
|
// Run the Wizard...
|
||
|
PackWiz_CreateWizard(hwndParent, &packInfo);
|
||
|
|
||
|
return _pPackage->InitFromPackInfo(&packInfo);
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////
|
||
|
// EDIT PACKAGE VERB
|
||
|
/////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
else if (iVerb == OLEIVERB_EDITPACKAGE) {
|
||
|
// Call the edit package dialog. Which dialog is ultimately called will
|
||
|
// depend on whether we're a cmdline package or an embedded file
|
||
|
// package.
|
||
|
int idDlg;
|
||
|
PACKAGER_INFO packInfo;
|
||
|
int ret;
|
||
|
|
||
|
lstrcpy(packInfo.szLabel,_pPackage->_lpic->szIconText);
|
||
|
lstrcpy(packInfo.szIconPath,_pPackage->_lpic->szIconPath);
|
||
|
packInfo.iIcon = _pPackage->_lpic->iDlgIcon;
|
||
|
|
||
|
switch(_pPackage->_panetype) {
|
||
|
case PEMBED:
|
||
|
lstrcpy(packInfo.szFilename, _pPackage->_pEmbed->fd.cFileName);
|
||
|
idDlg = IDD_EDITEMBEDPACKAGE;
|
||
|
break;
|
||
|
case CMDLINK:
|
||
|
lstrcpy(packInfo.szFilename, _pPackage->_pCml->szCommandLine);
|
||
|
idDlg = IDD_EDITCMDPACKAGE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
ret = PackWiz_EditPackage(hwndParent,idDlg, &packInfo);
|
||
|
|
||
|
// If User cancells the edit package...just return.
|
||
|
if (ret == -1)
|
||
|
return S_OK;
|
||
|
|
||
|
switch(_pPackage->_panetype) {
|
||
|
case PEMBED:
|
||
|
// if we have a tempfile, we'll want to delete it
|
||
|
if (_pPackage->_pEmbed->pszTempName) {
|
||
|
DeleteFile(_pPackage->_pEmbed->pszTempName);
|
||
|
delete _pPackage->_pEmbed->pszTempName;
|
||
|
_pPackage->_pEmbed->pszTempName = NULL;
|
||
|
_pPackage->ReleaseContextMenu();
|
||
|
}
|
||
|
// fall through
|
||
|
|
||
|
case CMDLINK:
|
||
|
_pPackage->InitFromPackInfo(&packInfo);
|
||
|
break;
|
||
|
}
|
||
|
return S_OK;
|
||
|
}
|
||
|
else if (iVerb == OLEIVERB_PRIMARY)
|
||
|
{
|
||
|
/////////////////////////////////////////////////////////////////
|
||
|
// ACTIVATE CONTENTS VERB
|
||
|
/////////////////////////////////////////////////////////////////
|
||
|
// NOTE: This is kind of crazy looking code, partially because we have
|
||
|
// to worry about two ways of launching things--ShellExecuteEx and
|
||
|
// calling through OLE.
|
||
|
//
|
||
|
|
||
|
switch(_pPackage->_panetype)
|
||
|
{
|
||
|
case PEMBED:
|
||
|
if (FAILED(_pPackage->CreateTempFile())) // will just return S_OK
|
||
|
return E_FAIL; // if we have a temp file
|
||
|
|
||
|
// if this is an OLE file then, activate through OLE
|
||
|
//
|
||
|
if (_pPackage->_pEmbed->fIsOleFile)
|
||
|
{
|
||
|
// If we've activated the server, then we can just pass this
|
||
|
// call along to it.
|
||
|
if (_pPackage->_pEmbed->poo)
|
||
|
{
|
||
|
return _pPackage->_pEmbed->poo->DoVerb(iVerb,lpmsg,
|
||
|
pActiveSite,lindex, hwndParent, lprcPosRect);
|
||
|
}
|
||
|
|
||
|
// We don't want to use OleCreateFromFile since that can turn around and create a packaged object...
|
||
|
CLSID clsid;
|
||
|
HRESULT hr = GetClassFile(_pPackage->_pEmbed->pszTempName, &clsid);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
IOleObject* poo;
|
||
|
hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, IID_IOleObject, (void **)&poo);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = poo->Advise(_pPackage->_pIAdviseSink, &_pPackage->_dwCookie);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// NOTE: apparently we have to call
|
||
|
// OleRun before we can get IPersistFile from some apps, namely
|
||
|
// Word and Excel. If we don't call OleRun, they fail our QI
|
||
|
// for IPersistfile.
|
||
|
OleRun(poo);
|
||
|
|
||
|
IPersistFile* ppf;
|
||
|
hr = poo->QueryInterface(IID_IPersistFile, (void **)&ppf);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = ppf->Load(_pPackage->_pEmbed->pszTempName, STGM_READWRITE | STGM_SHARE_DENY_WRITE);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = poo->DoVerb(iVerb, lpmsg, pActiveSite, lindex, hwndParent, lprcPosRect);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
poo->SetHostNames(_pPackage->_lpszContainerApp, _pPackage->_lpszContainerObj);
|
||
|
if (!_pPackage->_fNoIOleClientSiteCalls)
|
||
|
{
|
||
|
_pPackage->_pIOleClientSite->ShowObject();
|
||
|
_pPackage->_pIOleClientSite->OnShowWindow(TRUE);
|
||
|
}
|
||
|
_pPackage->_pEmbed->poo = poo; // save this so when we get a
|
||
|
poo = NULL;
|
||
|
}
|
||
|
}
|
||
|
ppf->Release();
|
||
|
}
|
||
|
if (FAILED(hr))
|
||
|
poo->Unadvise(_pPackage->_dwCookie);
|
||
|
}
|
||
|
if (FAILED(hr))
|
||
|
poo->Release();
|
||
|
}
|
||
|
}
|
||
|
if (SUCCEEDED(hr))
|
||
|
return hr;
|
||
|
|
||
|
// We weren't an OLE file after all, change our state to reflect this
|
||
|
_pPackage->_pEmbed->fIsOleFile = FALSE;
|
||
|
_pPackage->_fIsDirty = TRUE;
|
||
|
}
|
||
|
|
||
|
// Try to execute the file
|
||
|
_pPackage->_pEmbed->hTask = NULL;
|
||
|
|
||
|
sheinf.fMask = SEE_MASK_NOCLOSEPROCESS;
|
||
|
sheinf.lpFile = _pPackage->_pEmbed->pszTempName;
|
||
|
sheinf.nShow = SW_SHOWNORMAL;
|
||
|
|
||
|
if (ShellExecuteEx(&sheinf))
|
||
|
{
|
||
|
// if we get a valid process handle, we want to create a thread
|
||
|
// to wait for the process to exit so we know when we can load
|
||
|
// the tempfile back into memory.
|
||
|
//
|
||
|
if (sheinf.hProcess)
|
||
|
{
|
||
|
_pPackage->_pEmbed->hTask = sheinf.hProcess;
|
||
|
MAINWAITONCHILD *pmwoc = new MAINWAITONCHILD;
|
||
|
if (pmwoc)
|
||
|
{
|
||
|
pmwoc->pObj = this;
|
||
|
pmwoc->h = sheinf.hProcess;
|
||
|
|
||
|
if (CreateThread(NULL, 0, MainWaitOnChildThreadProc, pmwoc, 0, &id))
|
||
|
fError = FALSE;
|
||
|
else
|
||
|
{
|
||
|
CloseHandle(sheinf.hProcess);
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// NOTE: there's not much we can do if the ShellExecute
|
||
|
// succeeds and we don't get a valid handle back. we'll just
|
||
|
// load from the temp file when we're asked to save and hope
|
||
|
// for the best.
|
||
|
}
|
||
|
else // ShellExecuteEx failed!
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
// show that the object is now active
|
||
|
if (!fError && !_pPackage->_fNoIOleClientSiteCalls)
|
||
|
{
|
||
|
_pPackage->_pIOleClientSite->ShowObject();
|
||
|
_pPackage->_pIOleClientSite->OnShowWindow(TRUE);
|
||
|
}
|
||
|
return fError ? E_FAIL : S_OK;
|
||
|
|
||
|
case CMDLINK:
|
||
|
{
|
||
|
TCHAR szPath[MAX_PATH];
|
||
|
TCHAR szArgs[CBCMDLINKMAX-MAX_PATH];
|
||
|
|
||
|
lstrcpy(szPath, _pPackage->_pCml->szCommandLine);
|
||
|
PathSeparateArgs(szPath, szArgs);
|
||
|
|
||
|
sheinf.fMask = SEE_MASK_NOCLOSEPROCESS;
|
||
|
sheinf.lpFile = szPath;
|
||
|
sheinf.lpParameters = szArgs;
|
||
|
sheinf.nShow = SW_SHOWNORMAL;
|
||
|
|
||
|
// NOTE: This code is much nicer than ShellExec-ing an embedded
|
||
|
// file. Here, we just need to ShellExec the command line and
|
||
|
// the we're done. We don't need to know when that process
|
||
|
// finishes or anything else.
|
||
|
|
||
|
return ShellExecuteEx(&sheinf)? S_OK:E_FAIL;
|
||
|
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case PACKAGE:
|
||
|
{
|
||
|
PACKAGER_INFO packInfo = {0};
|
||
|
|
||
|
ASSERT(_pPackage->_pCml);
|
||
|
lstrcpyn(packInfo.szFilename, _pPackage->_pCml->szCommandLine, ARRAYSIZE(packInfo.szFilename));
|
||
|
|
||
|
// Run the Wizard...
|
||
|
PackWiz_CreateWizard(hwndParent, &packInfo);
|
||
|
|
||
|
return _pPackage->InitFromPackInfo(&packInfo);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Let's see if it is a context menu verb:
|
||
|
HRESULT hr;
|
||
|
IContextMenu* pcm;
|
||
|
if (SUCCEEDED(hr = _pPackage->GetContextMenu(&pcm)))
|
||
|
{
|
||
|
HMENU hmenu = CreatePopupMenu();
|
||
|
if (NULL != hmenu)
|
||
|
{
|
||
|
if (SUCCEEDED(hr = pcm->QueryContextMenu(hmenu,
|
||
|
0,
|
||
|
OLEIVERB_FIRST_CONTEXT,
|
||
|
OLEIVERB_LAST_CONTEXT,
|
||
|
CMF_NORMAL)))
|
||
|
{
|
||
|
MENUITEMINFO mii;
|
||
|
mii.cbSize = sizeof(mii);
|
||
|
mii.fMask = MIIM_ID;
|
||
|
if (GetMenuItemInfo(hmenu, (UINT) (iVerb - OLEIVERB_FIRST_CONTEXT), TRUE, &mii))
|
||
|
{
|
||
|
if (PEMBED == _pPackage->_panetype)
|
||
|
{
|
||
|
// If we have an embedding, we have to make sure that
|
||
|
// the temp file is created before we execute a command:
|
||
|
hr =_pPackage->CreateTempFile();
|
||
|
}
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
CMINVOKECOMMANDINFO ici;
|
||
|
ici.cbSize = sizeof(ici);
|
||
|
ici.fMask = 0;
|
||
|
ici.hwnd = NULL;
|
||
|
ici.lpVerb = (LPCSTR) IntToPtr(mii.wID - OLEIVERB_FIRST_CONTEXT);
|
||
|
ici.lpParameters = NULL;
|
||
|
ici.lpDirectory = NULL;
|
||
|
ici.nShow = SW_SHOWNORMAL;
|
||
|
// REVIEW: should we return OLEOBJ_S_CANNOT_DOVERB_NOW if this fails?
|
||
|
hr = pcm->InvokeCommand(&ici);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = OLEOBJ_S_CANNOT_DOVERB_NOW;
|
||
|
}
|
||
|
}
|
||
|
DestroyMenu(hmenu);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
pcm->Release();
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
HRESULT CPackage_IOleObject::EnumVerbs(LPENUMOLEVERB *ppEnumOleVerb)
|
||
|
{
|
||
|
DebugMsg(DM_TRACE, "pack oo - EnumVerbs() called.");
|
||
|
HRESULT hr;
|
||
|
|
||
|
IContextMenu* pcm;
|
||
|
// tell the package to release the cached context menu:
|
||
|
_pPackage->ReleaseContextMenu();
|
||
|
if (SUCCEEDED(hr = _pPackage->GetContextMenu(&pcm)))
|
||
|
{
|
||
|
HMENU hmenu = CreatePopupMenu();
|
||
|
if (NULL != hmenu)
|
||
|
{
|
||
|
if (SUCCEEDED(hr = pcm->QueryContextMenu(hmenu,
|
||
|
0,
|
||
|
OLEIVERB_FIRST_CONTEXT,
|
||
|
OLEIVERB_LAST_CONTEXT,
|
||
|
CMF_NORMAL)))
|
||
|
{
|
||
|
// FEATURE: remove problematic items by canonical names
|
||
|
int nItems = GetMenuItemCount(hmenu);
|
||
|
int cOleVerbs = 0;
|
||
|
if (nItems > 0)
|
||
|
{
|
||
|
// NOTE: we allocate nItems, but we may not use all of them
|
||
|
// FEATURE: add in menu items from the registry: "activate" & "edit"
|
||
|
OLEVERB* pVerbs = new OLEVERB[nItems];
|
||
|
if (NULL != pVerbs)
|
||
|
{
|
||
|
MENUITEMINFO mii;
|
||
|
TCHAR szMenuName[MAX_PATH];
|
||
|
mii.cbSize = sizeof(mii);
|
||
|
mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_STATE | MIIM_ID;
|
||
|
for (int i = 0; i < nItems; i++)
|
||
|
{
|
||
|
mii.dwTypeData = szMenuName;
|
||
|
mii.cch = ARRAYSIZE(szMenuName);
|
||
|
// NOTE: use GetMenuState() to avoid converting flags:
|
||
|
DWORD dwState = GetMenuState(hmenu, i, MF_BYPOSITION);
|
||
|
if (0 == (dwState & (MF_BITMAP | MF_OWNERDRAW | MF_POPUP)))
|
||
|
{
|
||
|
if (GetMenuItemInfo(hmenu, i, TRUE, &mii) && (MFT_STRING == mii.fType))
|
||
|
{
|
||
|
TCHAR szVerb[MAX_PATH];
|
||
|
if (FAILED(pcm->GetCommandString(mii.wID - OLEIVERB_FIRST_CONTEXT,
|
||
|
GCS_VERB,
|
||
|
NULL,
|
||
|
(LPSTR) szVerb,
|
||
|
ARRAYSIZE(szVerb))))
|
||
|
{
|
||
|
// Some commands don't have canonical names - just
|
||
|
// set the verb string to empty
|
||
|
szVerb[0] = TEXT('\0');
|
||
|
}
|
||
|
if ((0 != lstrcmp(szVerb, TEXT("cut"))) &&
|
||
|
(0 != lstrcmp(szVerb, TEXT("delete"))))
|
||
|
{
|
||
|
// In the first design, the context menu ID was used as
|
||
|
// the lVerb - however MFC apps only give us a range of
|
||
|
// 16 ID's and context menu ID's are often over 100
|
||
|
// (they aren't contiguous)
|
||
|
// Instead, we use the menu position plus the verb offset
|
||
|
pVerbs[cOleVerbs].lVerb = (LONG) OLEIVERB_FIRST_CONTEXT + i;
|
||
|
int cchMenu = lstrlen(mii.dwTypeData) + 1;
|
||
|
if (NULL != (pVerbs[cOleVerbs].lpszVerbName = new WCHAR[cchMenu]))
|
||
|
{
|
||
|
SHTCharToUnicode(mii.dwTypeData, pVerbs[cOleVerbs].lpszVerbName, cchMenu);
|
||
|
}
|
||
|
pVerbs[cOleVerbs].fuFlags = dwState;
|
||
|
pVerbs[cOleVerbs].grfAttribs = OLEVERBATTRIB_ONCONTAINERMENU;
|
||
|
DebugMsg(DM_TRACE, " Adding verb: id==%d,name=%s,verb=%s",mii.wID,mii.dwTypeData,szVerb);
|
||
|
cOleVerbs++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (SUCCEEDED(hr = _pPackage->InitVerbEnum(pVerbs, cOleVerbs)))
|
||
|
{
|
||
|
hr = _pPackage->QueryInterface(IID_IEnumOLEVERB, (void**) ppEnumOleVerb);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
delete pVerbs;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = OLEOBJ_E_NOVERBS;
|
||
|
}
|
||
|
}
|
||
|
DestroyMenu(hmenu);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
pcm->Release();
|
||
|
}
|
||
|
|
||
|
return hr; // OleRegEnumVerbs(CLSID_CPackage, ppEnumOleVerb);
|
||
|
}
|
||
|
|
||
|
HRESULT CPackage_IOleObject::Update(void)
|
||
|
{
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CPackage_IOleObject::IsUpToDate(void)
|
||
|
{
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CPackage_IOleObject::GetUserClassID(LPCLSID pClsid)
|
||
|
{
|
||
|
*pClsid = CLSID_CPackage;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CPackage_IOleObject::GetUserType(DWORD dwFromOfType, LPOLESTR *pszUserType)
|
||
|
{
|
||
|
return OleRegGetUserType(CLSID_CPackage, dwFromOfType, pszUserType);
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CPackage_IOleObject::SetExtent(DWORD dwDrawAspect, SIZEL *psizel)
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CPackage_IOleObject::GetExtent(DWORD dwDrawAspect, SIZEL *psizel)
|
||
|
{
|
||
|
return _pPackage->_pIViewObject2->GetExtent(dwDrawAspect,-1,NULL,psizel);
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CPackage_IOleObject::Advise(IAdviseSink *pAdvSink, DWORD *pdwConnection)
|
||
|
{
|
||
|
if (_pPackage->_pIOleAdviseHolder == NULL)
|
||
|
{
|
||
|
HRESULT hr = CreateOleAdviseHolder(&_pPackage->_pIOleAdviseHolder);
|
||
|
if (FAILED(hr))
|
||
|
return hr;
|
||
|
}
|
||
|
return _pPackage->_pIOleAdviseHolder->Advise(pAdvSink, pdwConnection);
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CPackage_IOleObject::Unadvise(DWORD dwConnection)
|
||
|
{
|
||
|
DebugMsg(DM_TRACE, "pack oo - Unadvise() called.");
|
||
|
|
||
|
if (_pPackage->_pIOleAdviseHolder != NULL)
|
||
|
return _pPackage->_pIOleAdviseHolder->Unadvise(dwConnection);
|
||
|
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CPackage_IOleObject::EnumAdvise(LPENUMSTATDATA *ppenumAdvise)
|
||
|
{
|
||
|
DebugMsg(DM_TRACE, "pack oo - EnumAdvise() called.");
|
||
|
|
||
|
if (_pPackage->_pIOleAdviseHolder != NULL)
|
||
|
return _pPackage->_pIOleAdviseHolder->EnumAdvise(ppenumAdvise);
|
||
|
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CPackage_IOleObject::GetMiscStatus(DWORD dwAspect, LPDWORD pdwStatus)
|
||
|
{
|
||
|
return OleRegGetMiscStatus(CLSID_CPackage, dwAspect, pdwStatus);
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CPackage_IOleObject::SetColorScheme(LPLOGPALETTE pLogpal)
|
||
|
{
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD CALLBACK MainWaitOnChildThreadProc(void *lpv)
|
||
|
{
|
||
|
INT ret;
|
||
|
MAINWAITONCHILD *pmwoc = (MAINWAITONCHILD *)lpv;
|
||
|
CPackage *pPack = pmwoc->pObj->_pPackage;
|
||
|
|
||
|
DebugMsg(DM_TRACE, "pack oo - MainWaitOnChildThreadProc() called.");
|
||
|
DebugMsg(DM_TRACE, " handle = %d",(DWORD_PTR)lpv);
|
||
|
|
||
|
ret = WaitForSingleObject(pmwoc->h, INFINITE);
|
||
|
DebugMsg(DM_TRACE,"WaitForSingObject exits...ret==%d",ret);
|
||
|
|
||
|
if (ret == -1)
|
||
|
DebugMsg(DM_TRACE,"GetLastError==%d",GetLastError());
|
||
|
|
||
|
CloseHandle(pmwoc->h);
|
||
|
|
||
|
// BUGBUG: NONE OF THE BELOW CALLS ARE THREAD-SAFE!!!
|
||
|
|
||
|
// this will set our dirty flag...
|
||
|
if (FAILED(pPack->EmbedInitFromFile(pPack->_pEmbed->pszTempName,FALSE)))
|
||
|
{
|
||
|
ShellMessageBox(g_hinst,
|
||
|
NULL,
|
||
|
MAKEINTRESOURCE(IDS_UPDATE_ERROR),
|
||
|
MAKEINTRESOURCE(IDS_APP_TITLE),
|
||
|
MB_ICONERROR | MB_TASKMODAL | MB_OK);
|
||
|
}
|
||
|
|
||
|
pPack->_pIOleClientSite->SaveObject();
|
||
|
|
||
|
if (pPack->_pIOleAdviseHolder)
|
||
|
{
|
||
|
pPack->_pIOleAdviseHolder->SendOnSave();
|
||
|
pPack->_pIOleAdviseHolder->SendOnClose();
|
||
|
}
|
||
|
|
||
|
if (pPack->_pIOleClientSite && !pPack->_fNoIOleClientSiteCalls)
|
||
|
pPack->_pIOleClientSite->OnShowWindow(FALSE);
|
||
|
|
||
|
pPack->_pEmbed->hTask = NULL;
|
||
|
|
||
|
// NOTE: we should probably pop up some sort of message box here if we
|
||
|
// can't reinit from the temp file.
|
||
|
DebugMsg(DM_TRACE, " MainWaitOnChildThreadProc exiting.");
|
||
|
|
||
|
delete pmwoc;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
BOOL CALLBACK GetTaskWndProc(HWND hwnd, DWORD lParam)
|
||
|
{
|
||
|
DebugMsg(DM_TRACE, "pack oo - GetTaskWndProc() called.");
|
||
|
|
||
|
if (IsWindowVisible(hwnd))
|
||
|
{
|
||
|
g_hTaskWnd = hwnd;
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|