home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 1998 May
/
Pcwk5b98.iso
/
Borland
/
Cplus45
/
BC45
/
BOCOLE.PAK
/
BOLESVC.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1995-08-29
|
44KB
|
1,265 lines
//
//
//**************************************************************************
//
// BOleService.cpp -- Implements the Bolero half of the application-level
// object. Provides some system services such as default
// dialogs.
//
// Copyright (c) 1993,94 by Borland International, Inc. All rights reserved
//
//**************************************************************************
#include "BOle.h"
#include "BOleSvc.h"
#include "BOleIPS.h"
#include "BOlePart.h"
#include "BOleDoc.h"
#include "BHatch.h"
#include "BOleCMan.h"
#include "BOleFact.h"
#include "BOleData.h"
struct BOleFactNode {
IBClass *factory;
BOleFactNode *pNext;
BOleFactNode( IBClass *f ){ factory = f; f->AddRef(); pNext = NULL; }
~BOleFactNode(){ factory->Release(); }
};
HRESULT _IFUNC BOleService::QueryInterfaceMain(REFIID iid, LPVOID *p)
{
HRESULT hr = ResultFromScode(E_NOINTERFACE);
*p = NULL;
// interfaces
if (SUCCEEDED(hr = IOleInPlaceFrame_QueryInterface(this, iid, p))) {
}
else if SUCCEEDED(hr = IBService_QueryInterface(this, iid, p)) {
}
// base classes
else if SUCCEEDED(hr = BOleComponent:: QueryInterfaceMain(iid, p)) {
}
// helpers
return hr;
}
POINT BOleService::pixPerIn = {0,};
BOleService::BOleService (BOleClassManager *pF, IBUnknownMain *pO) : pApp(NULL),
pActiveDoc(NULL), pFocusedSite(NULL), BOleComponent(pF, pO),
helpMode (BOLE_HELP_GET), pClipboardData (NULL), pSubclassedWindow(NULL)
{
clipList = NULL;
clipCount = 0;
clipOkToLink = FALSE;
clipOkToEmbed = FALSE;
dropList = NULL;
dropCount = 0;
dropOkToLink = FALSE;
dropOkToEmbed = FALSE;
fUseDropList = FALSE;
pFirstFactNode = NULL;
}
BOleService::~BOleService ()
{
FlushClipboardData();
if (clipList) {
delete [] clipList;
clipList = NULL;
}
if (dropList) {
delete [] dropList;
dropList = NULL;
}
}
//
// Called in BOleSite::OnClose to check if the bolesite object
// is on the clipboard (BOleSite doesn't do delayed rendering.)
//
BOOL BOleService::IsOnClipboard(IDataObject *pPat)
{
BOOL ret = FALSE;
if (pClipboardData) {
if (pPat == pClipboardData) {
ret = TRUE;
}
else {
// if the shadow object is on the clipboard we need to check
// if the real data object pointer it holds is the same as
// the one passed
BOleShadowData * pShadow;
if (SUCCEEDED(pClipboardData->QueryInterface(
IID_BOleShadowData, &(LPVOID)pShadow))) {
ret = (pShadow->GetRealData() == pPat);
pShadow->Release();
}
}
}
return ret;
}
void BOleService::FlushClipboardData(BOOL bCheck)
{
if (pClipboardData) { // one of ours may've been on the clipboard
if (bCheck) {
IDataObject *pD;
if (S_OK == GetScode(OleGetClipboard(&pD))) {
if (pD == pClipboardData)
OleFlushClipboard();
pD->Release();
}
}
else
OleFlushClipboard();
pClipboardData = NULL;
}
}
void BOleService::NotifyClipboardEmptied()
{
pClipboardData = NULL;
}
HRESULT _IFUNC BOleService::Init( IBApplication *pA )
{
#ifdef _DEBUG
// to make sure client's QueryInterface is implemented correctly
//
IBApplication *dbgApp = NULL;
LPOLEINPLACEFRAME dbgIPFrame = NULL;
if ((!SUCCEEDED(pObjOuter->QueryInterfaceMain(IID_IBApplication, &(LPVOID)dbgApp)))
|| (!SUCCEEDED(pObjOuter->QueryInterfaceMain(IID_IOleInPlaceFrame,&(LPVOID)dbgIPFrame)))) {
#ifdef ANSI
MessageBoxA(NULL,"QueryInterface Aggregation isn\'t working right",
"BOleService::Init", MB_OK);
#else
MessageBox (NULL, OLESTR("QueryInterface Aggregation isn\'t working right"),
OLESTR("BOleService::Init"), MB_OK);
#endif
}
else {
dbgApp->Release();
dbgIPFrame->Release();
dbgApp = NULL;
dbgIPFrame = NULL;
}
#endif
if (!pA)
return ResultFromScode(E_INVALIDARG);
pApp = pA;
BOleHatchWindow::Register (boleInst);
// The screen is the same resolution for all windows and all processes
// so we'll just squirrel this away so we don't have to retrieve it
// every time we need to translate between himetric and pixels
//
HWND w = ::GetDesktopWindow ();
HDC dc = ::GetDC (w);
if (!w || !dc)
return ResultFromScode (E_FAIL);
pixPerIn.x = WIN::GetDeviceCaps(dc, LOGPIXELSX);
pixPerIn.y = WIN::GetDeviceCaps(dc, LOGPIXELSY);
::ReleaseDC (w, dc);
return NOERROR;
}
void _IFUNC BOleService::SetActiveDoc (BOleDocument FAR *pD)
{
pActiveDoc = pD;
}
BOleDocument FAR *_IFUNC BOleService::GetActiveDoc ()
{
return pActiveDoc;
}
// SetHelpMode is used by the other Bolero helper objects when
// one of them gets a broadcast help msg. It can come through
// any of them because help is in IOleWindow, from which they inherit.
//
void _IFUNC BOleService::SetHelpMode (BOOL fEnterMode)
{
helpMode = fEnterMode ? BOLE_HELP_ENTER : BOLE_HELP_EXIT;
}
// Maybe useful for Activate As
//
void _IFUNC BOleService::UnloadObjects (REFCLSID c)
{
}
UINT _IFUNC BOleService::ExcludeOurselves (LPCLSID FAR *ppClsid)
{
LPCLSID pClsid = *ppClsid;
UINT rCnt = 128;
UINT exclusionCount = 0;
// Allocate an array of CLSIDs to pass back to the caller (who must delete it)
//
pClsid = (LPCLSID) new CLSID [rCnt];
if (!pClsid) {
*ppClsid = NULL;
return 0;
}
for( BOleFactNode *pNode = pFirstFactNode; pNode; pNode = pNode->pNext ){
// Ask the class factory if it's willing to embed in its own container
// If it isn't willing to do this, we will exclude the CLSID for that
// factory from the list.
//
if( !pNode->factory->AllowEmbedFromSelf() ){
pNode->factory->GetClassID(&pClsid[exclusionCount]);
exclusionCount++;
}
}
*ppClsid = pClsid;
return exclusionCount;
}
// ShowHelpButton -- BOleService helper function used by Bolero to find
// out if the container app wants us to show the help
// button for the dialog boxes. If the container is
// generated by Delphi, they might not.
//
BOOL _IFUNC BOleService::ShowHelpButton (BOleDialogHelp whichDialog)
{
BOOL ret = TRUE;
PIBOverrideHelpButton pOHB = NULL;
if (SUCCEEDED(pApp->QueryInterface(IID_IBOverrideHelpButton,
&(LPVOID) pOHB))) {
if (S_OK != GetScode (pOHB->ShowHelpButton (whichDialog)))
ret = FALSE;
pOHB->Release();
}
return ret;
}
//*************************************************************************
//
// IService implementation
//
//*************************************************************************
// Convert is supported on the service because (1) the other OLE2 dialogs
// are supported on the IBService and (2) I didn't want to make another
// function on IBPart which doesn't match up on the real server object
//
HRESULT _IFUNC BOleService::ConvertUI (PIBPart pPart, BOOL b, BOleConvertInfo FAR *pInfo)
{
BOlePart FAR *pPartImpl = NULL;
pPart->QueryInterface (IID_BOlePart, &(LPVOID) pPartImpl);
HRESULT hr = pPartImpl->ConvertUI (pApp, b, pInfo);
pPartImpl->Release();
return hr;
}
HRESULT _IFUNC BOleService::ConvertGuts (PIBPart pPart, BOOL b, BOleConvertInfo FAR *pInfo)
{
BOlePart FAR *pPartImpl = NULL;
pPart->QueryInterface (IID_BOlePart, &(LPVOID) pPartImpl);
HRESULT hr = pPartImpl->ConvertGuts (b, pInfo);
pPartImpl->Release();
return hr;
}
// CreateStorageOnFile is a near-trivial helper function which creates
// an IStorage on a DOS file path. Bolero users can do this for themselves
// if they like, but this is a little protection from the OLE2 headers
//
LPSTORAGE _IFUNC BOleService::CreateStorageOnFile (LPCOLESTR pFileName, BOOL bCreate)
{
IStorage * pStorage;
if (bCreate) {
StgCreateDocfile (
pFileName,
STGM_READWRITE|STGM_DIRECT|STGM_SHARE_EXCLUSIVE|STGM_CREATE,
0,
&pStorage
);
}
else {
StgOpenStorage (
pFileName, NULL,
STGM_READWRITE|STGM_DIRECT|STGM_SHARE_EXCLUSIVE,
NULL,
0,
&pStorage
);
}
return pStorage;
}
void _IFUNC BOleService::OnResize ()
{
if (pActiveDoc && pActiveDoc->pActivePart) {
// Ask the active IOleInPlaceActiveObject to recalculate the
// dimensions of its border adornments in the window, based on
// the rectangle available in our frame
//
RECT r;
pApp->GetWindowRect (&r);
pActiveDoc->pActivePart->ResizeBorder (&r, this, TRUE);
}
}
void _IFUNC BOleService::OnActivate (BOOL fActivate)
{
if (pActiveDoc && pActiveDoc->pActivePart)
pActiveDoc->pActivePart->OnFrameWindowActivate (fActivate);
}
HRESULT _IFUNC BOleService::OnSetFocus(BOOL bSet)
{
// Just send it on to the active doc
//
if (pActiveDoc)
return pActiveDoc->OnSetFocus(bSet);
// If there's no active doc, there can't be an active object, so
// the Bolero container app gets to keep focus
//
return ResultFromScode (S_OK);
}
HRESULT _IFUNC BOleService::Browse(BOleInitInfo FAR * pInfo)
{
HRESULT ret;
// These guys are in member data so we don't have to create big objects
// on the stack, but we can still have their lifetime extend from
// IBService::Browse until IBPart::Init, like they couldn't if we
// just used a stack variable for OLEUIINSERTOBJECT
//
dynamicScopePath[0] = 0;
dynamicScopeClsid = CLSID_NULL;
OLEUIINSERTOBJECT iod;
_fmemset(&iod, 0, sizeof(iod));
iod.cbStruct = sizeof(iod);
iod.dwFlags = IOF_SELECTCREATENEW;
iod.hWndOwner= ::GetActiveWindow();
iod.lpszFile = dynamicScopePath;
iod.cchFile = OLEUI_CCHPATHMAX;
iod.dwIBApplication = (DWORD) pApp;
pInfo->pStorage = NULLP; // User must fill this in after...
iod.cClsidExclude = ExcludeOurselves (&iod.lpClsidExclude);
if (ShowHelpButton(BOLE_HELP_BROWSE))
iod.dwFlags |= IOF_SHOWHELP;
EnterBOleDialog (TRUE, iod.hHook, iod.hTask);
UINT stat = OUI::OleUIInsertObject (&iod);
EnterBOleDialog (FALSE, iod.hHook, iod.hTask);
if (stat == OLEUI_OK) {
DWORD dwFlags = iod.dwFlags;
pInfo->hIcon = (dwFlags & IOF_CHECKDISPLAYASICON) ? (HICON) iod.hMetaPict : NULL;
if (dwFlags & IOF_SELECTCREATENEW) {
pInfo->Where = BOLE_NEW;
pInfo->How = BOLE_EMBED;
dynamicScopeClsid = iod.clsid;
pInfo->whereNew.cid = (BCID) &dynamicScopeClsid;
//
}
else if (dwFlags & IOF_SELECTCREATEFROMFILE) {
pInfo->Where = BOLE_FILE;
pInfo->How = (dwFlags & IOF_CHECKLINK) ? BOLE_LINK : BOLE_EMBED;
pInfo->whereFile.pPath = new OLECHAR[strlen(iod.lpszFile) + 1];
lstrcpy ((LPOLESTR)pInfo->whereFile.pPath, iod.lpszFile);
}
ret = ResultFromScode (S_OK);
}
else
ret = ResultFromScode (S_FALSE);
if (iod.lpClsidExclude)
delete [] iod.lpClsidExclude;
if (iod.hMetaPict) {
;// OleUIMetafilePictIconFree(iod.hMetaPict); // clean up metafile
}
return ret;
}
// Dialog enabling strategy:
//
// BOleService::OnModalDialog is how Bolero containers and servers
// send dialog state to the outside world
//
// IBApplication::OnModalDialog is how Bolero containers and servers
// receive dialog state from the outside world
//
HRESULT _IFUNC BOleService::OnModalDialog (BOOL fEnable)
{
HRESULT hr = NOERROR;
// Propogate this state "down" to the active object
//
if (pActiveDoc)
hr = pActiveDoc->OnModalDialog (fEnable);
// Propogate this state "up" to the inplace frame
//
if (pFocusedSite) {
PIBApplication tmpapp = NULL;
if (SUCCEEDED(pFocusedSite->QueryInterface(
IID_IBApplication, &(LPVOID) tmpapp))) {
hr = tmpapp->OnModalDialog (fEnable);
tmpapp->Release();
}
}
// Propogate this state "back" to the application. Since Bolero
// calls OnModalDialog itself for the OLE2 dialog boxes, the app
// wouldn't otherwise know we're in a modal dialog
//
hr = pApp->OnModalDialog (fEnable);
return hr;
}
HRESULT _IFUNC BOleService::TranslateAccel (LPMSG pMsg)
{
HRESULT hR = ResultFromScode( S_FALSE );
if( pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST ){
if( pFocusedSite )
hR = pFocusedSite->Accelerator( pMsg );
else if( pActiveDoc )
hR = pActiveDoc->TranslateAccel( pMsg );
}
return hR;
}
BOleHelp _IFUNC BOleService::HelpMode (BOleHelp newMode)
{
BOleHelp oldMode = helpMode;
if (newMode != BOLE_HELP_GET)
// broadcast to all documents
if (pActiveDoc && pActiveDoc->pActivePart)
pActiveDoc->pActivePart->ContextSensitiveHelp (newMode == BOLE_HELP_ENTER);
return oldMode;
}
HRESULT _IFUNC BOleService::CanClose()
{
if (pFactory->ServerCount() == 0)
return ResultFromScode (S_OK);
else
return ResultFromScode (S_FALSE);
}
HRESULT _IFUNC BOleService::BrowseClipboard (BOleInitInfo FAR * pInfo)
{
if (TRUE == PasteHelper (pInfo, TRUE))
return ResultFromScode (S_OK);
else
return ResultFromScode (S_FALSE);
}
HRESULT _IFUNC BOleService::Paste (BOleInitInfo *pInfo)
{
if (TRUE == PasteHelper (pInfo, FALSE))
return ResultFromScode (S_OK);
else
return ResultFromScode (S_FALSE);
}
// This function is called when a moniker becomes invalid for an object
// on the clipboard
//
void _IFUNC BOleService::RemoveLinkFromClipList()
{
for (UINT i=0, from=0; i < clipCount; i++, from++) {
if ((clipList[i].cfFormat == BOleDocument::oleLinkSrcDescFmt) ||
(clipList[i].cfFormat == BOleDocument::oleLinkSrcClipFmt)) {
// skip link format
//
++from;
}
// and shift
//
if (i != from && from < clipCount)
clipList[i] = clipList[from];
}
clipCount -= (from - i);
clipOkToLink = FALSE;
}
// This is a helper function for IService::Drag and IService::Clip. Its
// purpose is to make a format list for each operation. The lists are
// independent since drag/drop shouldn't disturb the clipboard. So the
// lists are parameterized in this function.
//
BOOL _IFUNC BOleService::FormatHelper (LPFORMATETC FAR* ppList, UINT *pCount,
BOOL &fLink, BOOL &fEmbed, PIBDataProvider pProvider)
{
UINT nOffered = 0;
if (!pProvider) {
*ppList = NULL;
*pCount = 0;
fLink =FALSE;
fEmbed = FALSE;
return FALSE;
}
nOffered = pProvider->CountFormats();
if (nOffered == 0) {
*ppList = NULL;
*pCount = 0;
fLink =FALSE;
fEmbed = FALSE;
return FALSE;
}
// This will disable linking when GetMoniker fails
// eg. When the container has not been saved.
if (fLink) {
IOleObject *pOleObj;
if (SUCCEEDED(pProvider->QueryInterface(IID_IOleObject,
&(LPVOID) pOleObj))) {
IMoniker *pMon;
if (SUCCEEDED(pOleObj->GetMoniker(OLEGETMONIKER_ONLYIFTHERE,
OLEWHICHMK_OBJFULL, &pMon))) {
pMon->Release();
}
else {
fLink = FALSE;
}
pOleObj->Release();
}
else
fLink = FALSE; // forbid linking if IOleObject fails
}
if (*ppList)
delete [] *ppList;
// The part is responsible for offering all clipboard formats except
// link source descriptor and object descriptor.
//
// Note that the part won't get called in GetFormatData for embeddings
// (because getting an embedded object means calling IBDataProv::Save) or
// for CF_METAFILEPICT (because we get that in IBDataProv::Draw)
//
*ppList = new FORMATETC [nOffered + 1 + (fLink ? 1 : 0)];
// 1 for object descriptor
// 1 for link source descriptor if linkable
if (!*ppList)
return FALSE;
LPFORMATETC pNext = *ppList;
// All objects get an object descriptor
//
//
pNext->cfFormat = BOleDocument::oleObjectDescFmt;
pNext->ptd = NULL;
pNext->dwAspect = DVASPECT_CONTENT;
pNext->lindex = -1;
pNext->tymed = TYMED_HGLOBAL;
pNext++;
//
if (fLink) {
pNext->cfFormat = BOleDocument::oleLinkSrcDescFmt;
pNext->ptd = NULL;
pNext->dwAspect = DVASPECT_CONTENT;
pNext->lindex = -1;
pNext->tymed = TYMED_HGLOBAL;
pNext++;
}
// Enumerate the server's formats for this object into our list
//
BOleFormat boleFmt;
fEmbed = FALSE;
for (UINT i = 0; i < nOffered; i++) {
if (NOERROR == pProvider->GetFormat (i, &boleFmt)) {
if ((boleFmt.fmtId == BOleDocument::oleLinkSrcDescFmt) && !fLink) {
// This will disable linking when GetMoniker fails
// eg. When the container has not been saved.
continue;
}
if ((boleFmt.fmtId == BOleDocument::oleLinkSrcClipFmt) && !fLink) {
// This will disable linking when GetMoniker fails
// eg. When the container has not been saved.
continue;
}
if (boleFmt.fmtId == BOleDocument::oleEmbdObjClipFmt ||
boleFmt.fmtId == BOleDocument::oleEmbSrcClipFmt) {
// This will enable embedding if the source of the
// drag offers an embedding format
//
fEmbed = TRUE;
}
pNext->cfFormat = boleFmt.fmtId;
pNext->ptd = NULL;
pNext->dwAspect = DVASPECT_CONTENT;
pNext->lindex = -1;
pNext->tymed = boleFmt.fmtMedium & ~BOLE_MED_STATIC;
pNext++;
}
}
*pCount = pNext - *ppList;
return TRUE;
}
HRESULT _IFUNC BOleService::Clip (PIBDataProvider pClonePart, BOOL fLink,
BOOL fEmbed, BOOL fUseDataCache)
{
HRESULT hr;
// If the clone object is null, we're invalidating everything on the
// clipboard, for example if the app is shutting down or if the app
// is doing pseudo-delayed-rendering, and the clipboard doesn't reflect
// the data any more.
//
if (!pClonePart) {
OleSetClipboard (NULL); //
if (clipList) {
delete [] clipList;
clipList = NULL;
}
clipCount = 0;
clipOkToLink = FALSE;
clipOkToEmbed = FALSE;
return ResultFromScode (S_OK);
}
// Get the IPart from the part object. Need this so we can enumerate
// the formats which should be available to the data object.
//
PIBDataProvider pProvider = pClonePart;
FlushClipboardData();
// Here we have a choice of ways to get a data object to put on the
// clipboard. The first is a "snapshot" object which can be used for
// delayed rendering. The second is the original object which won't
// be protected from delayed rendering.
//
if (fUseDataCache) {
// Get the data object from the snapshot data cache implemented
// in BOleData
//
BOlePart *pBOlePart = NULL;
hr = pProvider->QueryInterface (IID_BOlePart, &(LPVOID) pBOlePart);
if (!SUCCEEDED(hr))
return hr;
hr = pBOlePart->CopyFromOriginal (NULL, &pClipboardData);
pBOlePart->Release();
if (!SUCCEEDED(hr))
return hr;
}
else {
// Get the data object from the part. Because of aggregation this
// is actually the IDataObject of the BOleSite which the part is
// associated with.
//
IDataObject *pData;
hr = pClonePart->QueryInterface(IID_IDataObject, &(LPVOID) pData);
if (!SUCCEEDED(hr))
return hr;
pClipboardData = new BOleShadowData(pFactory, pData);
pData->Release();
// Find out how many formats we need. This allows us to malloc a list
// of FORMATETCs for matching later. The user doesn't have to know
// about the OLE2 formats, so we need to add those to the count.
//
// This list is only used in BOleSite.
//
fUseDropList= FALSE;
clipOkToLink = fLink; // will be cleared by FormatHelper if format not offered
clipOkToEmbed = fEmbed;// will be cleared by FormatHelper if format not offered
if (!FormatHelper (&clipList, &clipCount, clipOkToLink, clipOkToEmbed, pProvider))
// clipOkToLink is passed by reference
hr = ResultFromScode (DV_E_FORMATETC);
}
// Use the OLE2 API to put the data object on the clipboard.
//
if (SUCCEEDED(hr)) {
hr = OleSetClipboard( pClipboardData);
if (!SUCCEEDED(hr))
Clip(NULL, FALSE, FALSE, FALSE);
}
pClipboardData->Release();
// pClipboardData is a non ref counted copy of the pointer
// that is referenced by the clipboard.
// We release our ref count now to allow BOleShadowData or BOleData
// to go away as soon as some other app copies to the clipboard. We'll set
// pClipboardData to NULL when BOleShadowData or BoleData goes away
// to avoid leaving it dangling.
return hr;
}
HRESULT _IFUNC BOleService::Drag (PIBDataProvider pPart, BOleDropAction inEffects, BOleDropAction *outEffect)
{
HRESULT hr = ResultFromScode(S_FALSE);
DWORD dwOutEffect;
IDataObject *pDataObj = NULL;
IDropSource *pDropSrc = NULL;
if (outEffect)
*outEffect = BOLE_DROP_NONE;
BOOL fUnlockRunning = FALSE;
// Get IDataObject of embedding or server being dragged
BOlePart *pBOlePart = NULL;
if (SUCCEEDED(pPart->QueryInterface(IID_IDataObject,&(LPVOID)pDataObj))) {
// Cache the data formats associated with the server object so
// when we get called in the IDataObject, we'll have something to
// compare against in BOleSite
//
fUseDropList = TRUE;
dropOkToLink = (inEffects & BOLE_DROP_LINK) != 0;
FormatHelper (&dropList, &dropCount, dropOkToLink, dropOkToEmbed, pPart);
if (!dropOkToLink) // in case link not possible
(int)inEffects &= ~BOLE_DROP_LINK;
}
else {
hr = pPart->QueryInterface (IID_BOlePart, &(LPVOID) pBOlePart);
if (!SUCCEEDED(hr))
return hr;
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
// This can be a little slow, but I think it should be better
// than running the app
//
pBOlePart->CopyFromOriginal (NULL, &pDataObj);
}
if (!pDataObj)
return hr;
if (!pDropSrc)
pPart->QueryInterface(IID_IDropSource,&(LPVOID)pDropSrc);
if (!pDropSrc) {
pDataObj->Release();
return hr;
}
// Don't lock if the objects are in another process space
//
if (!pBOlePart) {
CoLockObjectExternal (pDataObj, TRUE, FALSE);
CoLockObjectExternal (pDropSrc, TRUE, FALSE);
}
hr = OLE::DoDragDrop (pDataObj, pDropSrc, (DWORD)inEffects, &dwOutEffect);
// Fill in the out param if we got one
//
if (outEffect)
*outEffect = (BOleDropAction)dwOutEffect;
// Make up a return code. The Bolero convention here is NOERROR for
// success or an error if not. Strangely, the container can fail from
// IDropTarget::Drop and we still get DRAGDROP_S_DROP. Fortunately we
// do get the DROPEFFECT_NONE if the container set it, so use it here
// to produce an error.
//
if (GetScode(hr) == DRAGDROP_S_DROP)
if (dwOutEffect == DROPEFFECT_NONE)
hr = ResultFromScode (E_FAIL);
else
hr = ResultFromScode(S_OK);
if (!pBOlePart) {
// TRUE releases ref counts held by OLE2 if this is last unlock
// this is important if the dragging object is a clone
CoLockObjectExternal (pDataObj, FALSE, TRUE);
CoLockObjectExternal (pDropSrc, FALSE, TRUE);
}
// When we're dragging an embedding, we need to keep the object running.
// Unlock it after the drag/drop has completed.
//
if (pBOlePart) {
if (fUnlockRunning)
OleLockRunning (pBOlePart->pOleObject, FALSE, FALSE);
pBOlePart->Release();
}
pDropSrc->Release();
pDataObj->Release(); // should delete BOleData if dragging from embedding
return hr;
}
BOleMenuEnable _IFUNC BOleService::EnableEditMenu (BOleMenuEnable bmeIn,
PIBDataConsumer pConsumer)
{
BOleMenuEnable bmeOut = BOleMenuEnable( 0 );
HRESULT hr = NOERROR;
LPDATAOBJECT data = NULL;
if (bmeIn & BOLE_ENABLE_PASTELINK) {
hr = OleGetClipboard (&data);
if (S_OK == GetScode(hr)) {
hr = OleQueryLinkFromData (data);
if (data)
data->Release ();
// I didn't use SUCCEEDED here because someone returns 0x00030000
// which doesn't look like an scode at all. Go figure.
//
if (GetScode(hr) == S_OK)
( int )bmeOut |= BOLE_ENABLE_PASTELINK;
}
}
// We're borrowing the logic from the dialog which enumerates the links in
// the document. In this case, we don't so much need to enumerate them;
// it's enough to know that one exists.
//
if (bmeIn & BOLE_ENABLE_BROWSELINKS) {
if (pActiveDoc && pActiveDoc->EnableBrowseLinks())
( int )bmeOut |= BOLE_ENABLE_BROWSELINKS;
}
// The test for whether to enable these last two is really the same
// criteria: a match between what the container can accept and what the
// server offers.
//
if ((bmeIn & BOLE_ENABLE_PASTE) || (bmeIn & BOLE_ENABLE_BROWSECLIPBOARD)) {
//
//
//
//
//
LPDATAOBJECT pDataObj = NULL;
OLEUIPASTEENTRY *pOle2UIEntries = NULL;
BOleFormat *pBOleEntries = NULL;
UINT nAcceptableFormats = 0;
CLIPFORMAT i;
hr = OLE::OleGetClipboard (&pDataObj);
if (S_OK == GetScode(hr)) {
nAcceptableFormats = pConsumer->CountFormats ();
if (!nAcceptableFormats)
goto cleanup;
pOle2UIEntries = new OLEUIPASTEENTRY [nAcceptableFormats];
if (!pOle2UIEntries)
goto cleanup;
pBOleEntries = new BOleFormat[nAcceptableFormats];
if (!pBOleEntries)
goto cleanup;
for (i = 0; i < nAcceptableFormats; i++) {
//_fmemset (&pOle2UIEntries[i], 0, sizeof (OLEUIPASTEENTRY));
pConsumer->GetFormat (i, &pBOleEntries[i]);
pOle2UIEntries[i].fmtetc.cfFormat = pBOleEntries[i].fmtId;
pOle2UIEntries[i].fmtetc.ptd = NULL;
pOle2UIEntries[i].fmtetc.dwAspect = DVASPECT_CONTENT;
pOle2UIEntries[i].fmtetc.tymed = pBOleEntries[i].fmtMedium & ~BOLE_MED_STATIC;
pOle2UIEntries[i].fmtetc.lindex = -1;
pOle2UIEntries[i].lpstrFormatName =
( pBOleEntries[i].fmtName[0] ?
pBOleEntries[i].fmtName : TEXT("%s") );
pOle2UIEntries[i].lpstrResultText =
( pBOleEntries[i].fmtResultName[0] ?
pBOleEntries[i].fmtResultName : TEXT("%s") );
if (pBOleEntries[i].fmtId == BOleDocument::oleEmbdObjClipFmt ||
pBOleEntries[i].fmtId == BOleDocument::oleLinkSrcClipFmt ||
pBOleEntries[i].fmtId == BOleDocument::oleEmbSrcClipFmt)
// PASTEONLY and ENABLEICON are mutually exclusive
//
pOle2UIEntries[i].dwFlags =
OLEUIPASTE_PASTE | OLEUIPASTE_ENABLEICON;
else
pOle2UIEntries[i].dwFlags = OLEUIPASTE_PASTEONLY;
}
i = MatchPriorityClipFormat (pDataObj, pOle2UIEntries, nAcceptableFormats);
if (i != 0xFFFF) {
( int )bmeOut |= ( BOLE_ENABLE_PASTE|BOLE_ENABLE_BROWSECLIPBOARD );
}
cleanup:
// Clean up our various scratch buffers etc
//
if (pBOleEntries)
delete [] pBOleEntries;
if (pOle2UIEntries)
delete [] pOle2UIEntries;
pDataObj->Release();
}
}
return bmeOut;
}
//*************************************************************************
//
// IOleWindow implementation -- base class of OLE2 windows
//
//*************************************************************************
HRESULT _IFUNC BOleService::GetWindow (HWND FAR *phwnd)
{
*phwnd = pApp->GetWindow();
return *phwnd != NULL ? NOERROR : ResultFromScode (E_FAIL);
}
HRESULT _IFUNC BOleService::ContextSensitiveHelp (BOOL fEnterMode)
{
// The BOleService object is responsible for keeping track of Shift-F1
//
SetHelpMode (fEnterMode);
return NOERROR;
}
//*************************************************************************
//
// IOleInPlaceUIWindow implementation
//
//*************************************************************************
HRESULT _IFUNC BOleService::GetBorder (LPRECT prectBorder)
{
if (SUCCEEDED(pApp->GetWindowRect(prectBorder)))
return NOERROR;
return ResultFromScode (INPLACE_E_NOTOOLSPACE);
}
HRESULT _IFUNC BOleService::RequestBorderSpace (LPCRECT prectWidths)
{
// Ask the application if it can accept the amount of space the
// server wants on the left, top, right, and bottom of the window
//
if (SUCCEEDED(pApp->RequestBorderSpace (prectWidths)))
return NOERROR;
return ResultFromScode (INPLACE_E_NOTOOLSPACE);
}
HRESULT _IFUNC BOleService::SetBorderSpace (LPCBORDERWIDTHS prectWidths)
{
// This seems like it does the same thing as RequestBorderSpace,
// except that this time the server is really taking the space, so
// we should get our stuff out of the way.
//
//
if (SUCCEEDED(pApp->SetBorderSpace(prectWidths)))
return NOERROR;
return ResultFromScode (OLE_E_INVALIDRECT);
}
HRESULT _IFUNC BOleService::SetActiveObject (IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName)
{
// Although it seems a little strange, we're supposed to put the
// name of the object in our caption bar in the client.
//
IBWindow *pWnd;
if (pActiveDoc)
pWnd = getNegotiator(pApp, pActiveDoc->pContainer);
else
pWnd = pApp; // just in case
if (pszObjName)
pWnd->AppendWindowTitle (pszObjName);
else
// Calling SetActiveObject with a null name means the object
// is deactivating.
//
//
//
pWnd->RestoreUI();
// Decrement the ref count of the pointer we're giving up, and
// bump the ref count of the new pointer we're going to hold
//
if (pActiveDoc) {
if (pActiveDoc->pActivePart)
pActiveDoc->pActivePart->Release();
pActiveDoc->pActivePart = pActiveObject;
if (pActiveDoc->pActivePart)
pActiveDoc->pActivePart->AddRef();
}
return NOERROR;
}
//*************************************************************************
//
// IOleInPlaceFrame implementation
//
//*************************************************************************
HRESULT _IFUNC BOleService::InsertMenus (HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths)
{
if (SUCCEEDED(pApp->InsertContainerMenus (hmenuShared,
(BOleMenuWidths*) lpMenuWidths)))
return NOERROR;
return ResultFromScode (E_FAIL);
}
HRESULT _IFUNC BOleService::SetMenu (HMENU hmenuShared, HOLEMENU holeMenu, HWND hwndActiveObject)
{
HRESULT hr = NOERROR;
// hmenuShared will be null when the call to BOleService::SetMenu is
// initiated from BOlePart::OnUIDeactivate. hmenuShared will be valid
// when the SetMenu call comes from the real server object
//
// Even when hmenuShared is NULL, we have to pass the call on to the
// container because the container has to remove the menu from its
// frame window.
//
hr = pApp->SetFrameMenu (hmenuShared);
// holemenu will be null when the call to BOleService::SetMenu is
// initiated from BOlePart::OnUIDeactivate. holeMenu will be valid
// when the SetMenu call comes from the real server object
//
if (SUCCEEDED(hr))
hr = OleSetMenuDescriptor (holeMenu, pApp->GetWindow(),
hwndActiveObject, NULL, NULL);
return hr;
}
HRESULT _IFUNC BOleService::RemoveMenus (HMENU hmenuShared)
{
//
//
//
//
BOOL fNoError = TRUE;
// Remove container group menus
//
while (GetMenuItemCount(hmenuShared))
fNoError &= RemoveMenu(hmenuShared, 0, MF_BYPOSITION);
return fNoError ? NOERROR : ResultFromScode(E_FAIL);
}
HRESULT _IFUNC BOleService::SetStatusText (LPCOLESTR statusText)
{
// Servers use this function to put text in the container's status bar.
// The server is not supposed to negotiate tool space to put their own
// status bar at the bottom of the frame window.
//
pApp->SetStatusText(statusText);
return NOERROR;
}
HRESULT _IFUNC BOleService::EnableModeless (BOOL fEnable)
{
return pApp->OnModalDialog (!fEnable);
}
HRESULT _IFUNC BOleService::TranslateAccelerator (MSG FAR* msg, WORD wID)
{
HWND oldhwnd = msg->hwnd;
msg->hwnd = pApp->GetWindow ();
HRESULT hr = pApp->Accelerator(msg);
msg->hwnd = oldhwnd;
return hr;
}
/*
* Registration related.
*/
HRESULT _IFUNC BOleService::RegisterClass(LPCOLESTR szProgId, IBClassMgr * pCM, BCID rId,
BOOL fInProcExe, BOOL fSingleUse)
{
HRESULT hErr;
LPUNKNOWN pObjF;
IBClass *pClass;
pFactory->ComponentCreate(&pObjF, NULL, cidBOleFactory);
if (SUCCEEDED(hErr = pObjF->QueryInterface(IID_IBClass, &(LPVOID)pClass))) {
if (SUCCEEDED(hErr = pClass->Init(fInProcExe, szProgId, pCM, rId))) {
if (SUCCEEDED(hErr = pClass->Register(fSingleUse))) {
AddClassFactory( pClass );
}
}
pClass->Release();
}
pObjF->Release();
return hErr;
}
HRESULT _IFUNC BOleService::UnregisterClass(LPCOLESTR szProgId)
{
return RemoveClassFactory(szProgId);
}
HRESULT BOleService::AddClassFactory(IBClass *pF)
{
HRESULT hErr = NOERROR;
BOleFactNode *pNewNode = new BOleFactNode( pF );
if( !pFirstFactNode )
pFirstFactNode = pNewNode;
else {
for( BOleFactNode *pNode = pFirstFactNode; pNode->pNext; pNode = pNode->pNext );
pNode->pNext = pNewNode;
}
OLEHRES("Registered classid", hErr);
return hErr;
}
HRESULT BOleService::RemoveClassFactory( LPCOLESTR szProgId)
{
CLSID cid;
if (SUCCEEDED( CLSIDFromProgID( szProgId, &cid ) ) ){
return RemoveClassFactory( cid );
}
return ResultFromScode (E_FAIL);
}
HRESULT BOleService::RemoveClassFactory( REFCLSID cid )
{
BOleFactNode *pNode = pFirstFactNode, *pPrevNode = NULL;
while( pNode ){
IBClass *pF = pNode->factory;
if (pF->IsA(cid)) {
pF->Revoke();
// Unchain the node
if( pPrevNode )
pPrevNode->pNext = pNode->pNext;
else
pFirstFactNode = pNode->pNext;
BOleFactNode *pDel = pNode;
pNode = pNode->pNext;
delete pDel; // releases the factory
} else {
pPrevNode = pNode;
pNode = pNode->pNext;
}
}
return NOERROR;
}
HRESULT BOleService::FindClassFactory(LPCOLESTR szProgId, IBClass **pF)
{
CLSID cid;
if( SUCCEEDED( CLSIDFromProgID(szProgId, &cid ) ) ){
return FindClassFactory( cid, pF );
}
return ResultFromScode (E_FAIL);
}
HRESULT BOleService::FindClassFactory(REFCLSID cid, IBClass **ppF)
{
*ppF = NULL;
for( BOleFactNode *pNode = pFirstFactNode; pNode; pNode = pNode->pNext ){
if( pNode->factory->IsA(cid) ) {
*ppF = pNode->factory;
(*ppF)->AddRef();
break;
}
}
return (*ppF) ? NOERROR : ResultFromScode(E_FAIL);
}