- BORLAND/: Borland C++ 4.52 (chosen over 4.5 by byte-match: CODE/RP/CW32.LIB
is identical to 4.52's install lib). BCC32/TLINK32/TLIB/MAKE run natively on
Win11; CODE/BT/OPT.MAK is the shipped BTL4OPT.EXE's exact flag recipe
(extender = Borland PowerPack DPMI32, not Phar Lap TNT).
- restoration/source410/: the literal 1995-form reconstruction of the missing
BT game source (never mixed into CODE/). Round 1-3 state:
* 6 of 10 surviving original TUs COMPILE CLEAN under the period toolchain
(BTMSSN, BTCNSL, BTSCNRL, BTTEAM, BTL4MODE, BTL4ARND) - first builds
since 1996.
* BT_L4/BTL4APP.CPP pilot reconstruction: 12/12 functions, Fail() lands on
its binary-recorded line 400 exactly.
* BT/BTCNSL.HPP: console wire IDs recovered from the binary's ctors
(Killed=9, Damaged=10, ScoreUpdate=13, DeathWithoutHonor=15 [T1];
TeamScore=12 flagged [T4]).
* MUNGA/: 8 engine-header backfills back-dated from the BT412 WinTesla tree
(VDATA numbering decomp-verified; AUDREND's OpenAL-era virtual removed -
the period compiler is the drift detector).
* Tooling: backdate.py (WinTesla->1995 header transform), compile410.sh
(per-TU verification sweep under authentic OPT.MAK flags).
* README: corrected roadmap - MECH.HPP is the capstone grown with the mech
TU reconstructions; BTREG.CPP green = the header-family milestone.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1269 lines
36 KiB
C++
1269 lines
36 KiB
C++
//
|
|
//**************************************************************************
|
|
//
|
|
// BOleDoc.cpp -- Implements the Bolero half of the document-level
|
|
// object. Provides plumbing for activation of OLE2 objects
|
|
// as document windows become active. Also the main drag/drop
|
|
// and clipboard implementation.
|
|
//
|
|
// Copyright (c) 1993,94 by Borland International, Inc. All rights reserved
|
|
//
|
|
//**************************************************************************
|
|
|
|
#include "BOleDoc.h"
|
|
#include "BOleSvc.h"
|
|
#include "BOlePart.h"
|
|
|
|
#include <olestd.h>
|
|
|
|
//**************************************************************************
|
|
//
|
|
// Initialize static/global data
|
|
//
|
|
//**************************************************************************
|
|
|
|
// IOleUILinkContainer is only used here
|
|
|
|
#include "initguid.h"
|
|
DEFINE_GUID(IID_IOleUILinkContainer, 0x000004FF, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
|
|
PREDECLARE_INTERFACE(IOleUILinkContainer)
|
|
DEFINE_INLINE_QI(IOleUILinkContainer, IUnknown)
|
|
|
|
// CLIPFORMAT is a WORD while RegisterClipboardFormat returns a UINT
|
|
|
|
#ifdef ANSI
|
|
CLIPFORMAT BOleDocument::oleEmbdObjClipFmt = RegisterClipboardFormatA("Embedded Object");
|
|
CLIPFORMAT BOleDocument::oleEmbSrcClipFmt = RegisterClipboardFormatA("Embed Source");
|
|
CLIPFORMAT BOleDocument::oleLinkSrcClipFmt = RegisterClipboardFormatA("Link Source");
|
|
CLIPFORMAT BOleDocument::oleLinkSrcDescFmt = RegisterClipboardFormatA("Link Source Descriptor");
|
|
|
|
CLIPFORMAT BOleDocument::oleLinkClipFmt = RegisterClipboardFormatA("ObjectLink");
|
|
CLIPFORMAT BOleDocument::oleNativeClipFmt = RegisterClipboardFormatA("Native");
|
|
CLIPFORMAT BOleDocument::oleOwnerLinkClipFmt = RegisterClipboardFormatA("OwnerLink");
|
|
CLIPFORMAT BOleDocument::oleObjectDescFmt = RegisterClipboardFormatA("Object Descriptor");
|
|
|
|
UINT BOleDocument::dragScrollInset = GetProfileIntA ("windows", "DragScrollInset", DD_DEFSCROLLINSET);
|
|
UINT BOleDocument::dragScrollDelay = GetProfileIntA ("windows", "DragScrollDelay", DD_DEFSCROLLDELAY);
|
|
UINT BOleDocument::dragScrollInterval = GetProfileIntA ("windows", "DragScrollInterval", DD_DEFSCROLLINTERVAL);
|
|
#else
|
|
CLIPFORMAT BOleDocument::oleEmbdObjClipFmt = RegisterClipboardFormat (OLESTR("Embedded Object"));
|
|
CLIPFORMAT BOleDocument::oleEmbSrcClipFmt = RegisterClipboardFormat (OLESTR("Embed Source"));
|
|
CLIPFORMAT BOleDocument::oleLinkSrcClipFmt = RegisterClipboardFormat (OLESTR("Link Source"));
|
|
CLIPFORMAT BOleDocument::oleLinkSrcDescFmt = RegisterClipboardFormat (OLESTR("Link Source Descriptor"));
|
|
|
|
CLIPFORMAT BOleDocument::oleLinkClipFmt = RegisterClipboardFormat (OLESTR("ObjectLink"));
|
|
CLIPFORMAT BOleDocument::oleNativeClipFmt = RegisterClipboardFormat (OLESTR("Native"));
|
|
CLIPFORMAT BOleDocument::oleOwnerLinkClipFmt = RegisterClipboardFormat (OLESTR("OwnerLink"));
|
|
CLIPFORMAT BOleDocument::oleObjectDescFmt = RegisterClipboardFormat (OLESTR("Object Descriptor"));
|
|
|
|
UINT BOleDocument::dragScrollInset = GetProfileInt (OLESTR("windows"), OLESTR("DragScrollInset"), DD_DEFSCROLLINSET);
|
|
UINT BOleDocument::dragScrollDelay = GetProfileInt (OLESTR("windows"), OLESTR("DragScrollDelay"), DD_DEFSCROLLDELAY);
|
|
UINT BOleDocument::dragScrollInterval = GetProfileInt (OLESTR("windows"), OLESTR("DragScrollInterval"), DD_DEFSCROLLINTERVAL);
|
|
#endif
|
|
|
|
#ifdef OLEDBG
|
|
OLEDBGDATA;
|
|
#endif
|
|
|
|
//**************************************************************************
|
|
//
|
|
// BOleDocument implementation
|
|
//
|
|
//**************************************************************************
|
|
|
|
HRESULT _IFUNC BOleDocument::QueryInterfaceMain(REFIID iid, LPVOID FAR *ppv)
|
|
{
|
|
HRESULT hr = ResultFromScode(E_NOINTERFACE);
|
|
*ppv = NULL;
|
|
|
|
// self
|
|
|
|
if (iid == IID_BOleDocument) {
|
|
(BOleDocument*) *ppv = this;
|
|
AddRef ();
|
|
return NOERROR;
|
|
}
|
|
|
|
// interfaces
|
|
|
|
SUCCEEDED(hr = IOleInPlaceUIWindow_QueryInterface(this, iid, ppv))
|
|
|| SUCCEEDED(hr = IDropTarget_QueryInterface(this, iid, ppv))
|
|
|| SUCCEEDED(hr = IBDocument_QueryInterface(this, iid, ppv))
|
|
|| SUCCEEDED(hr = IOleUILinkContainer_QueryInterface(this, iid, ppv))
|
|
|| SUCCEEDED(hr = IOleInPlaceFrame_QueryInterface(this, iid, ppv))
|
|
|| SUCCEEDED(hr = IBOverrideBrowseLinks_QueryInterface(this, iid, ppv))
|
|
|
|
// base classes
|
|
|
|
|| SUCCEEDED(hr = BOleComponent::QueryInterfaceMain(iid, ppv))
|
|
|
|
// helpers
|
|
;
|
|
|
|
return hr;
|
|
}
|
|
|
|
BOleDocument::BOleDocument (BOleClassManager *pF, IBUnknownMain * pObj, BOleService * pOS) :
|
|
BOleComponent(pF, pObj), pService (pOS), fInBrowseLinks(FALSE),
|
|
pActivePart (NULLP), pFirstPart(NULLP), fRegistered(FALSE)
|
|
{
|
|
pContainer = NULLP;
|
|
pApplication = NULLP;
|
|
|
|
#ifdef OLEDBG
|
|
DebugMode = 0;
|
|
#endif
|
|
|
|
WIN::SetRect (&rcScrollTop,0,0,0,0);
|
|
WIN::SetRect (&rcScrollBottom,0,0,0,0);
|
|
WIN::SetRect (&rcScrollLeft,0,0,0,0);
|
|
WIN::SetRect (&rcScrollRight,0,0,0,0);
|
|
scrollEnterTime = 0;
|
|
scrollLastTime = 0;
|
|
fScrollDelay = FALSE;
|
|
|
|
dndObjPos.left = dndObjPos.top = dndObjPos.right = dndObjPos.bottom = 0;
|
|
dndLastPos.x = dndLastPos.y = -1;
|
|
dndSize.cx = dndSize.cy = 0;
|
|
dndOffset.x = dndOffset.y = 0;
|
|
dndInfoAvailable = FALSE;
|
|
|
|
dndFormatCount = 0;
|
|
dndFormatList = NULL;
|
|
fDrawn = FALSE;
|
|
}
|
|
|
|
BOleDocument::~BOleDocument ()
|
|
{
|
|
if (pService->GetActiveDoc() == this)
|
|
pService->SetActiveDoc (NULL);
|
|
|
|
if (pActivePart) {
|
|
pActivePart->Release ();
|
|
pActivePart = NULL;
|
|
}
|
|
}
|
|
|
|
//**************************************************************************
|
|
//
|
|
// IBDocument implementation
|
|
//
|
|
//**************************************************************************
|
|
|
|
HRESULT _IFUNC BOleDocument::Init( IBContainer *pBack)
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT hRes = NOERROR;
|
|
|
|
pContainer = pBack;
|
|
pApplication = pService->GetApplication();
|
|
|
|
HWND hwnd = pContainer->GetWindow();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!fRegistered) {
|
|
|
|
// Register the document window as a Drag & Drop target. This
|
|
// means that we can't drag onto the frame window, but that
|
|
// doesn't seem like an oppressive restriction
|
|
//
|
|
if (hwnd) {
|
|
|
|
CoLockObjectExternal (AsPIUnknown(pObjOuter), TRUE, TRUE);
|
|
hRes = OLE::RegisterDragDrop(hwnd, this);
|
|
fRegistered = SUCCEEDED(hRes);
|
|
}
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
// Call when the container window in the client app was resized
|
|
//
|
|
void _IFUNC BOleDocument::OnResize ()
|
|
{
|
|
if (pContainer) {
|
|
RECT r;
|
|
pContainer->GetWindowRect (&r);
|
|
if (pActivePart) {
|
|
|
|
// You would think that telling the object that its container has
|
|
// resized would renegotiate the clip rect, but it doesn't seem to
|
|
//
|
|
pActivePart->ResizeBorder (&r, this, FALSE);
|
|
|
|
// We renegotiate the clipping rect for them here
|
|
//
|
|
BOlePart *pWalk = pFirstPart;
|
|
while (pWalk) {
|
|
if (pWalk->IsInPlace()) {
|
|
pWalk->ResetObjectRects();
|
|
pWalk = NULL;
|
|
}
|
|
else
|
|
pWalk = pWalk->GetNextPart();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void _IFUNC BOleDocument::OnActivate (BOOL fActivate)
|
|
{
|
|
// Remember the active document state
|
|
//
|
|
if (fActivate)
|
|
pService->SetActiveDoc (this);
|
|
else
|
|
if (pService->GetActiveDoc() == this)
|
|
pService->SetActiveDoc (NULL);
|
|
|
|
// Make the OLE2 call to remove the inplace active object's
|
|
// user interface
|
|
//
|
|
BOOL fMDI = (GetScode(pService->GetApplication()->IsMDI()) == S_OK);
|
|
|
|
if (fMDI && pActivePart) {
|
|
pActivePart->OnDocWindowActivate (fActivate);
|
|
|
|
// Strangely, no OLE2 traffic is generated by deactivating the
|
|
// document window of an inplace active object. I would expect
|
|
// them to call SetBorderSpace(NULL), but the docs specifically
|
|
// instruct *not* to do that. I suppose straight OLE2 apps can
|
|
// just put back their UI in addition to calling OnDocWindowActivate,
|
|
// but Bolero will notify clients to do it.
|
|
//
|
|
if (!fActivate)
|
|
pService->GetApplication()->RestoreUI ();
|
|
}
|
|
}
|
|
|
|
// Call just before the container window is destroyed
|
|
//
|
|
void _IFUNC BOleDocument::OnClose ()
|
|
{
|
|
if (fRegistered) {
|
|
HWND hwnd = pContainer->GetWindow();
|
|
HRESULT hRes = OLE::RevokeDragDrop(hwnd);
|
|
|
|
// If we can't unregister the window, it isn't registered and can't
|
|
// be unlocked. In particular, CoLockObjectExternal can recursively
|
|
// call OnClose, and calling CoLockObjectExternal recursively will
|
|
// be a big mess
|
|
//
|
|
if (hRes == NOERROR) {
|
|
CoLockObjectExternal (AsPIUnknown(pObjOuter), FALSE, TRUE);
|
|
fRegistered = FALSE;
|
|
}
|
|
else
|
|
fRegistered = TRUE;
|
|
}
|
|
}
|
|
|
|
HRESULT _IFUNC BOleDocument::OnSetFocus(BOOL bSet)
|
|
{
|
|
// The policy is that inplace active object always gets first shot at
|
|
// keystrokes, but the practicality is that the user can set focus to
|
|
// any old window by clicking on it. So, if some other window does
|
|
// succeed in getting focus, it should give it immediately back to
|
|
// the inplace server object.
|
|
//
|
|
if(bSet && pActivePart) {
|
|
HWND w = NULL;
|
|
HRESULT h = pActivePart->GetWindow(&w);
|
|
if (SUCCEEDED(h)) {
|
|
::SetFocus (w);
|
|
return ResultFromScode (S_FALSE);
|
|
}
|
|
}
|
|
|
|
// The Bolero container app gets to keep focus since there was no
|
|
// a inplace active server object
|
|
//
|
|
return ResultFromScode (S_OK);
|
|
}
|
|
|
|
HRESULT _IFUNC BOleDocument::EnumLinks (PIBLinkInfo FAR*)
|
|
{
|
|
return ResultFromScode (E_NOTIMPL);
|
|
}
|
|
|
|
// UpdateLinks -- This function packages up some functionality of IBLinkInfo
|
|
// and IBDocument::EnumLinks. The goal is to provide a
|
|
// one-stop way for client apps to update the links in their
|
|
// document. They are responsible for the dialog box, if any.
|
|
//
|
|
HRESULT _IFUNC BOleDocument::UpdateLinks ()
|
|
{
|
|
BOlePart FAR *pWalk = pFirstPart->GetNextLink (TRUE);
|
|
HRESULT hr = NOERROR;
|
|
|
|
while (pWalk) {
|
|
hr = pWalk->UpdateNow();
|
|
pWalk = pWalk->GetNextLink (FALSE);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT _IFUNC BOleDocument::BrowseLinks ()
|
|
{
|
|
if( fInBrowseLinks )
|
|
// Cannot nest link browser for the same document
|
|
return ResultFromScode (E_FAIL);
|
|
fInBrowseLinks++;
|
|
|
|
OLEUIEDITLINKS el;
|
|
_fmemset((LPOLEUIEDITLINKS)&el,0,sizeof(el));
|
|
el.cbStruct = sizeof (OLEUIEDITLINKS);
|
|
el.hWndOwner = ::GetActiveWindow(); // pContainer->GetWindow ();
|
|
el.lpOleUILinkContainer = this;
|
|
el.dwIBApplication = (DWORD) pApplication;
|
|
if (pService->ShowHelpButton(BOLE_HELP_BROWSELINKS))
|
|
el.dwFlags = ELF_SHOWHELP;
|
|
|
|
pService->EnterBOleDialog (TRUE, el.hHook, el.hTask);
|
|
UINT r = OleUIEditLinks (&el);
|
|
pService->EnterBOleDialog (FALSE, el.hHook, el.hTask);
|
|
|
|
fInBrowseLinks--;
|
|
|
|
if (r == 1)
|
|
return ResultFromScode (S_OK); //
|
|
return ResultFromScode (S_FALSE);
|
|
}
|
|
|
|
// This guy is private implementation called by BOleService because the
|
|
// document knows if any parts are links
|
|
//
|
|
BOOL _IFUNC BOleDocument::EnableBrowseLinks ()
|
|
{
|
|
return pFirstPart && pFirstPart->GetNextLink (TRUE) != NULLP;
|
|
}
|
|
|
|
//**************************************************************************
|
|
//
|
|
// IOleWindow implementation
|
|
//
|
|
//**************************************************************************
|
|
|
|
HRESULT _IFUNC BOleDocument::GetWindow (HWND FAR *phwnd)
|
|
{
|
|
*phwnd = pContainer->GetWindow();
|
|
OLERET(S_OK);
|
|
}
|
|
|
|
HRESULT _IFUNC BOleDocument::ContextSensitiveHelp (BOOL fEnterMode)
|
|
{
|
|
pService->SetHelpMode (fEnterMode);
|
|
OLERET(S_OK);
|
|
}
|
|
|
|
//**************************************************************************
|
|
//
|
|
// IOleInPlaceUIWindow implementation
|
|
//
|
|
//**************************************************************************
|
|
|
|
HRESULT _IFUNC BOleDocument::GetBorder (LPRECT prectBorder)
|
|
{
|
|
OLERET (SUCCEEDED(pContainer->GetWindowRect(prectBorder))
|
|
? S_OK : INPLACE_E_NOTOOLSPACE);
|
|
}
|
|
|
|
HRESULT _IFUNC BOleDocument::RequestBorderSpace (LPCRECT prectWidths)
|
|
{
|
|
OLERET (SUCCEEDED(pContainer->RequestBorderSpace(prectWidths))
|
|
? S_OK : INPLACE_E_NOTOOLSPACE);
|
|
}
|
|
|
|
HRESULT _IFUNC BOleDocument::SetBorderSpace (LPCBORDERWIDTHS prectWidths)
|
|
{
|
|
|
|
|
|
|
|
OLERET(SUCCEEDED(pContainer->SetBorderSpace(prectWidths))
|
|
? S_OK : OLE_E_INVALIDRECT);
|
|
}
|
|
|
|
HRESULT _IFUNC BOleDocument::SetActiveObject (IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName)
|
|
{
|
|
// 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 (pActivePart)
|
|
pActivePart->Release ();
|
|
pActivePart = pActiveObject;
|
|
if (pActivePart)
|
|
pActivePart->AddRef ();
|
|
|
|
// Although it seems a little strange, we're supposed to put the
|
|
// name of the object in our caption bar in the client.
|
|
//
|
|
if (pszObjName)
|
|
pContainer->AppendWindowTitle (pszObjName);
|
|
else
|
|
// Null name means object is deactivating.
|
|
pContainer->RestoreUI();
|
|
|
|
OLERET (S_OK);
|
|
}
|
|
|
|
//**************************************************************************
|
|
//
|
|
// IDropTarget implementation (and some helper functions)
|
|
//
|
|
//**************************************************************************
|
|
|
|
// Helper function called by IDropTarget functions to make sure the object the
|
|
// user is trying to drop is acceptable to the application
|
|
//
|
|
short _IFUNC BOleDocument::ValidateDrag(DWORD keyState, POINTL *where, DWORD *effect, IDataObject *dataObj)
|
|
{
|
|
// No container formats -- no legal drop available
|
|
//
|
|
if (!dndFormatCount) {
|
|
*effect = DROPEFFECT_NONE;
|
|
dndFormat = 0;
|
|
return -1;
|
|
}
|
|
|
|
IBApplication*pIA = pService->GetApplication();
|
|
|
|
// Find out what the user wants to do by looking at the modifier keys
|
|
if (keyState & MK_CONTROL)
|
|
*effect = (keyState & MK_SHIFT ? DROPEFFECT_LINK : DROPEFFECT_COPY);
|
|
else
|
|
// !(MK_SHIFT) is the "default" case for no modifier keys. In this case
|
|
// the default has the same effect as shift, but it isn't required to
|
|
//
|
|
*effect = (keyState & MK_SHIFT ? DROPEFFECT_MOVE : DROPEFFECT_MOVE);
|
|
|
|
// if the key state doesn't match with the server capabilities, fail
|
|
// ie. don't allow user to press control shift if server doesn't allow link
|
|
if (*effect == DROPEFFECT_LINK) {
|
|
if (fCantLink) {
|
|
*effect = DROPEFFECT_NONE;
|
|
return -1;
|
|
}
|
|
}
|
|
// dndFormat explanation: The reason dndFormat is in member data is that
|
|
// for DragOver messages, we don't have a data object to negotiate with.
|
|
// But we still want to give the format to the container window, so
|
|
// dndFormat remembers what the last agreed format was and we can still
|
|
// pass it back.
|
|
//
|
|
// Also, dndFormat is an actual clipboard format and agreedFormat is a
|
|
// list index.
|
|
|
|
// Now make sure the application supports what the user wants to do
|
|
//
|
|
BOOL canLink = (GetScode (pIA->CanLink()) == S_OK);
|
|
BOOL canEmbed = (GetScode(pIA->CanEmbed()) == S_OK);
|
|
if ((*effect & DROPEFFECT_LINK && !canLink) ||
|
|
((*effect & DROPEFFECT_COPY || *effect & DROPEFFECT_MOVE) && !canEmbed)) {
|
|
*effect = DROPEFFECT_NONE;
|
|
dndFormat = 0;
|
|
return -1;
|
|
}
|
|
|
|
// Find the best data format the server and client can agree upon and
|
|
// see if that format can be dropped at the current mouse location
|
|
//
|
|
// If we didn't get an IDataObject (it isn't passed to DragOver) we can't
|
|
// validate the clipboard format, which is fine with us because it's pretty slow
|
|
//
|
|
if (dataObj) {
|
|
short agreedFormat = -1;
|
|
agreedFormat = pService->MatchPriorityClipFormat(dataObj,
|
|
dndFormatList, dndFormatCount);
|
|
if (agreedFormat == -1) {
|
|
*effect = DROPEFFECT_NONE;
|
|
dndFormat = 0; // to 0 to know we don't agree during DragOver
|
|
return -1;
|
|
}
|
|
else {
|
|
dndFormat = dndFormatList[agreedFormat].fmtetc.cfFormat;
|
|
return agreedFormat;
|
|
}
|
|
}
|
|
else
|
|
// No data object -- no format to negotiate (don't touch dndFormat)
|
|
//
|
|
if (dndFormat == 0) // in case we couldn't agree in DragEnter
|
|
return -1;
|
|
else
|
|
return 1;
|
|
|
|
}
|
|
|
|
// In OLE2, the container (IDropTarget) may decide to scroll if certain
|
|
// conditions are met:
|
|
// 1. The mouse must be within 11 pixels of the edge of the target
|
|
// 2. The mouse must remain within 11 pixels for 50 millisecs ("delay")
|
|
// before any scrolling takes place
|
|
// 3. The rate of scrolling ("interval") must be no more than once
|
|
// every 50 millisecs.
|
|
// These values are pulled from WIN.INI when the Bolero DLL is loaded.
|
|
//
|
|
// Bolero clients will receive an IContainer::Scroll message whenever
|
|
// it's appropriate to scroll. The BOleScroll bitfield may specify
|
|
// two-directional scrolling (e.g. up and to the left). The client may
|
|
// scroll or not, and should return TRUE if it does in order to tell
|
|
// the server to change the cursor shape to the scrolling version.
|
|
//
|
|
BOleScroll _IFUNC BOleDocument::DragScrollReqd (POINTL *where)
|
|
{
|
|
// Check to see if the point is in any of our cached scrolling rects
|
|
//
|
|
BOleScroll ret = (BOleScroll) 0;
|
|
POINT shortWhere = {where->x, where->y};
|
|
HWND w = pContainer->GetWindow(); //
|
|
WIN::ScreenToClient (w, &shortWhere);
|
|
if (::PtInRect (&rcScrollLeft, shortWhere))
|
|
ret = ret | BOLE_SCROLL_RIGHT;
|
|
if (::PtInRect (&rcScrollRight, shortWhere))
|
|
ret = ret | BOLE_SCROLL_LEFT;
|
|
if (::PtInRect (&rcScrollTop, shortWhere))
|
|
ret = ret| BOLE_SCROLL_DOWN;
|
|
if (::PtInRect (&rcScrollBottom, shortWhere))
|
|
ret = ret | BOLE_SCROLL_UP;
|
|
|
|
// If not in any scroll rects, reset the times and leave
|
|
//
|
|
if (!ret) {
|
|
scrollEnterTime = 0;
|
|
scrollLastTime = 0;
|
|
return (BOleScroll) ret;
|
|
}
|
|
|
|
DWORD now = WIN::GetCurrentTime ();
|
|
|
|
// If this is the first time we've noticed the mouse in the scroll
|
|
// area, make a note of the time and start waiting for the
|
|
// initial delay latency
|
|
//
|
|
if (!scrollEnterTime) {
|
|
scrollEnterTime = now;
|
|
fScrollDelay = TRUE;
|
|
return (BOleScroll) 0;
|
|
}
|
|
|
|
// If we're waiting for the initial delay to pass, check 'now' against
|
|
// the initial delay latency instead of the interval latency. These
|
|
// are probably the same, but we're good citizens. If the delay has
|
|
// expired, we can return the scrolling direction to indicate the
|
|
// beginning of a scroll operation.
|
|
//
|
|
if (fScrollDelay)
|
|
if (now > scrollEnterTime + dragScrollDelay) {
|
|
fScrollDelay = FALSE;
|
|
scrollLastTime = now;
|
|
return (BOleScroll) ret;
|
|
}
|
|
else
|
|
return (BOleScroll) 0;
|
|
|
|
// If we've gotten this far, we must be in the middle of a scrolling
|
|
// operation. Check 'now' against the interval latency and return
|
|
// the scrolling direction, or 0 if the latency has not expired.
|
|
//
|
|
if (now > scrollLastTime + dragScrollInterval) {
|
|
scrollLastTime = now;
|
|
return (BOleScroll) ret;
|
|
}
|
|
else
|
|
return (BOleScroll) 0;
|
|
}
|
|
|
|
// CalculateDndObjPos is a helper function which sets up a rectangle which
|
|
// represents the position of the object being dragged RELATIVE TO ITS
|
|
// ORIGINAL HIT POINT.
|
|
//
|
|
// I know I'm not passing any parameters, but this stuff is all in member
|
|
// data anyway, so it seems silly to pass it on the stack too.
|
|
//
|
|
void _IFUNC BOleDocument::CalculateDndObjPos ()
|
|
{
|
|
::SetRect (&dndObjPos,
|
|
dndLastPos.x - dndOffset.x,
|
|
dndLastPos.y - dndOffset.y,
|
|
dndLastPos.x - dndOffset.x + dndSize.cx,
|
|
dndLastPos.y - dndOffset.y + dndSize.cy);
|
|
}
|
|
|
|
HRESULT _IFUNC BOleDocument::DragEnter (IDataObject *dataObj,
|
|
DWORD keyState, POINTL where, LPDWORD effect)
|
|
{
|
|
POINT shortPoint;
|
|
shortPoint.x = LOWORD(where.x);
|
|
shortPoint.y = LOWORD(where.y);
|
|
|
|
HRESULT hr = pContainer->FindDropDest (&shortPoint, &pDropDest);
|
|
if (!SUCCEEDED(hr)) {
|
|
*effect = DROPEFFECT_NONE;
|
|
return ResultFromScode (E_FAIL);
|
|
}
|
|
|
|
// cache this for use in ValidateDrag during drag-over
|
|
fCantLink = S_OK != GetScode(OleQueryLinkFromData (dataObj));
|
|
|
|
// same dropdest/document pair
|
|
//
|
|
RECT r;
|
|
if (SUCCEEDED(pDropDest->GetScrollRect (&r)))
|
|
CacheDragRects (&r);
|
|
|
|
// Find out how many formats the client can accept. If they can't
|
|
// accept any, return an error so no drop can take place
|
|
//
|
|
dndFormatCount = pDropDest->CountFormats ();
|
|
if (!dndFormatCount) {
|
|
*effect = DROPEFFECT_NONE;
|
|
return ResultFromScode (E_FAIL);
|
|
}
|
|
|
|
// Hold the container's legal data formats in an array
|
|
//
|
|
dndFormatList = new OLEUIPASTEENTRY [dndFormatCount];
|
|
BOleFormat f;
|
|
for (short i = 0; i < dndFormatCount; i++) {
|
|
pDropDest->GetFormat (i, &f);
|
|
|
|
dndFormatList[i].fmtetc.cfFormat = f.fmtId;
|
|
dndFormatList[i].fmtetc.ptd = NULL;
|
|
dndFormatList[i].fmtetc.dwAspect = DVASPECT_CONTENT;
|
|
dndFormatList[i].fmtetc.tymed = f.fmtMedium & ~BOLE_MED_STATIC;
|
|
dndFormatList[i].fmtetc.lindex = -1;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
dndFormatList[i].lpstrFormatName =
|
|
(f.fmtName[0] ? f.fmtName : TEXT("%s"));
|
|
dndFormatList[i].lpstrResultText =
|
|
(f.fmtResultName[0] ? f.fmtResultName : TEXT("%s"));
|
|
|
|
if (f.fmtId == BOleDocument::oleEmbdObjClipFmt ||
|
|
f.fmtId == BOleDocument::oleLinkSrcClipFmt ||
|
|
f.fmtId == BOleDocument::oleEmbSrcClipFmt)
|
|
|
|
// PASTEONLY and ENABLEICON are mutually exclusive
|
|
//
|
|
dndFormatList[i].dwFlags = OLEUIPASTE_PASTE | OLEUIPASTE_ENABLEICON;
|
|
else
|
|
dndFormatList[i].dwFlags = OLEUIPASTE_PASTEONLY;
|
|
|
|
}
|
|
|
|
dndFormat = -1; // prime with "no agreed format"
|
|
|
|
|
|
// Ask the data object for its object descriptor
|
|
//
|
|
FORMATETC fmtetc;
|
|
STGMEDIUM tymed;
|
|
fmtetc.cfFormat = BOleDocument::oleObjectDescFmt;
|
|
fmtetc.ptd = 0;
|
|
fmtetc.dwAspect = DVASPECT_CONTENT;
|
|
fmtetc.lindex = -1;
|
|
fmtetc.tymed = TYMED_HGLOBAL;
|
|
|
|
hr = dataObj->GetData (&fmtetc, &tymed);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
// Keep this around since not all servers give out object
|
|
// descriptor data, and we wouldn't want to send a bogus
|
|
// size back to the client
|
|
//
|
|
dndInfoAvailable = TRUE;
|
|
|
|
// Ask the object descriptor how much screen size it needs
|
|
//
|
|
OBJECTDESCRIPTOR *pOD = (OBJECTDESCRIPTOR*) ::GlobalLock(tymed.hGlobal);
|
|
|
|
// MSGraph5 fix: object descriptor is garbage
|
|
//
|
|
if (!IsBadReadPtr (pOD, sizeof (OBJECTDESCRIPTOR))) {
|
|
|
|
// These coordinate transformations produce a rectangle, in
|
|
// client pixel coordinates, which represents the position of
|
|
// the dragged object RELATIVE TO THE HIT POSITION in the
|
|
// original server object.
|
|
//
|
|
dndSize.cx = MAP_LOGHIM_TO_PIX (pOD->sizel.cx, BOleService::pixPerIn.x);
|
|
dndSize.cy = MAP_LOGHIM_TO_PIX (pOD->sizel.cy, BOleService::pixPerIn.y);
|
|
|
|
dndOffset.x = MAP_LOGHIM_TO_PIX (pOD->pointl.x, BOleService::pixPerIn.x);
|
|
dndOffset.y = MAP_LOGHIM_TO_PIX (pOD->pointl.y, BOleService::pixPerIn.y);
|
|
}
|
|
else
|
|
SetRect (&dndObjPos, -1, -1, -1, -1);
|
|
|
|
WIN::GlobalUnlock (tymed.hGlobal);
|
|
OLE::ReleaseStgMedium (&tymed);
|
|
pOD = NULL;
|
|
}
|
|
else {
|
|
SetRect (&dndObjPos, -1, -1, -1, -1);
|
|
}
|
|
|
|
// Make sure the action implied by 'keyState' is supported
|
|
//
|
|
if (ValidateDrag(keyState, &where, effect, dataObj) >= 0) {
|
|
|
|
// Find out if the user has dragged over the scroll zone
|
|
//
|
|
BOleScroll scrollDirection = (BOleScroll) 0;
|
|
scrollEnterTime = 0;
|
|
scrollLastTime = 0;
|
|
scrollDirection = DragScrollReqd(&where);
|
|
if (scrollDirection) {
|
|
if (GetScode (pDropDest->Scroll (scrollDirection)) == S_OK)
|
|
|
|
// If the app did scroll, tell the server so it can
|
|
// make the cursor into the drag-scroll bitmap
|
|
//
|
|
*effect |= DROPEFFECT_SCROLL;
|
|
|
|
}
|
|
|
|
// Get the drag position in container window's client coords
|
|
//
|
|
dndLastPos.x = where.x;
|
|
dndLastPos.y = where.y;
|
|
HWND w = pContainer->GetWindow();
|
|
::ScreenToClient (w, &dndLastPos);
|
|
|
|
// Ask the container to give appropriate feedback. This first time
|
|
// through draws the feedback so we're ready for the erase-redraw
|
|
// sequence in DragOver
|
|
//
|
|
CalculateDndObjPos ();
|
|
|
|
HRESULT hr = NOERROR;
|
|
pDropDest->DragFeedback (&dndLastPos, &dndObjPos, BOLE_MOUSEENTER, dndFormat, hr);
|
|
fDrawn = TRUE;
|
|
if (hr != NOERROR) {
|
|
dndLastFeedbackFailed = TRUE;
|
|
*effect = DROPEFFECT_NONE;
|
|
return hr;
|
|
}
|
|
else
|
|
dndLastFeedbackFailed = FALSE;
|
|
|
|
// We can return 'ok' as long as ValidateDrag succeeded.
|
|
// It isn't important whether the IContainer accepted Scroll
|
|
//
|
|
OLERET(S_OK);
|
|
}
|
|
|
|
OLERET(E_FAIL);
|
|
}
|
|
|
|
HRESULT _IFUNC BOleDocument::DragOver (DWORD keyState, POINTL where, LPDWORD effect)
|
|
{
|
|
// *effect = NULL;
|
|
// return ResultFromScode (E_FAIL);
|
|
|
|
// Make sure the action implied by 'keyState' is supported
|
|
//
|
|
BOOL fValid = ValidateDrag(keyState, &where, effect) >= 0;
|
|
|
|
if (fValid) {
|
|
// Find out if the user has dragged over the scroll zone
|
|
//
|
|
BOleScroll scrollDirection = (BOleScroll) 0;
|
|
scrollDirection = DragScrollReqd(&where);
|
|
if (scrollDirection) {
|
|
if (GetScode (pDropDest->Scroll (scrollDirection)) == S_OK)
|
|
|
|
// If the app did scroll, tell the server so it can
|
|
// make the cursor into the drag-scroll bitmap
|
|
//
|
|
*effect |= DROPEFFECT_SCROLL;
|
|
|
|
}
|
|
}
|
|
|
|
// Do drop-target feedback
|
|
//
|
|
|
|
HWND w = pContainer->GetWindow();
|
|
POINT newPos;
|
|
newPos.x = where.x;
|
|
newPos.y = where.y;
|
|
::ScreenToClient (w, &newPos);
|
|
|
|
if ((dndLastPos.x != newPos.x) || (dndLastPos.y != newPos.y)) {
|
|
if (fDrawn) {
|
|
// Once to erase in the old position
|
|
//
|
|
if (dndInfoAvailable)
|
|
CalculateDndObjPos ();
|
|
else
|
|
SetRect (&dndObjPos, -1, -1, -1, -1);
|
|
|
|
HRESULT hr = NOERROR;
|
|
pDropDest->DragFeedback (&dndLastPos, &dndObjPos, BOLE_MOUSECONTAINED, dndFormat, hr);
|
|
fDrawn = FALSE;
|
|
if (hr != NOERROR) {
|
|
dndLastFeedbackFailed = TRUE;
|
|
*effect = DROPEFFECT_NONE;
|
|
return hr;
|
|
}
|
|
else
|
|
dndLastFeedbackFailed = FALSE;
|
|
|
|
}
|
|
|
|
if (fValid) { // Once to draw in the new position
|
|
//
|
|
dndLastPos = newPos;
|
|
if (dndInfoAvailable)
|
|
CalculateDndObjPos ();
|
|
else
|
|
SetRect (&dndObjPos, -1, -1, -1, -1);
|
|
|
|
HRESULT hr = NOERROR;
|
|
pDropDest->DragFeedback (&dndLastPos, &dndObjPos, BOLE_MOUSECONTAINED, dndFormat, hr);
|
|
fDrawn = TRUE;
|
|
if (hr != NOERROR) {
|
|
dndLastFeedbackFailed = TRUE;
|
|
*effect = DROPEFFECT_NONE;
|
|
return hr;
|
|
}
|
|
else
|
|
dndLastFeedbackFailed = FALSE;
|
|
}
|
|
}
|
|
else {
|
|
if (dndLastFeedbackFailed) {
|
|
*effect = DROPEFFECT_NONE;
|
|
return ResultFromScode (E_FAIL);
|
|
}
|
|
}
|
|
if (fValid) {
|
|
// We can return 'ok' as long as ValidateDrag succeeded.
|
|
// It isn't important whether the IContainer accepted Scroll
|
|
//
|
|
OLERET (S_OK);
|
|
}
|
|
else {
|
|
*effect = DROPEFFECT_NONE;
|
|
OLERET (E_FAIL);
|
|
}
|
|
|
|
}
|
|
|
|
HRESULT _IFUNC BOleDocument::DragLeave ()
|
|
{
|
|
HRESULT hr = NOERROR;
|
|
|
|
// Erase feedback at last position
|
|
//
|
|
if (!dndInfoAvailable)
|
|
SetRect (&dndObjPos, -1, -1, -1, -1);
|
|
|
|
if (fDrawn) {
|
|
pDropDest->DragFeedback (&dndLastPos, &dndObjPos, BOLE_MOUSEEXIT, dndFormat, hr);
|
|
fDrawn = FALSE;
|
|
// dndLastFeedbackFailed shouldn't matter here
|
|
}
|
|
|
|
// This info is invalid after the DnD transaction
|
|
//
|
|
dndSize.cx = dndSize.cy = 0;
|
|
dndLastPos.x = dndLastPos.y = -1;
|
|
dndInfoAvailable = FALSE;
|
|
if (dndFormatList)
|
|
delete [] dndFormatList;
|
|
dndFormatList = NULL;
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT _IFUNC BOleDocument::Drop (IDataObject *dataObj, DWORD keyState,
|
|
POINTL where, LPDWORD effect)
|
|
{
|
|
short agreedFormat = ValidateDrag(keyState, &where, effect, dataObj);
|
|
|
|
if (agreedFormat >= 0) {
|
|
|
|
// Find out if the format we agreed on can support static objects.
|
|
// This would be a little more convenient if dndFormatList contained
|
|
// BOleFormats rather than FORMATETCs, but this works out.
|
|
//
|
|
BOOL fStaticOK = FALSE;
|
|
BOleFormat f;
|
|
if (SUCCEEDED(pDropDest->GetFormat(agreedFormat, &f)))
|
|
fStaticOK = f.fmtMedium & BOLE_MED_STATIC;
|
|
|
|
// Fill in BOleInitInfo fields dependent on the format
|
|
//
|
|
BOleInitInfo bii;
|
|
bii.pContainer = NULL;
|
|
UINT cf = dndFormatList[agreedFormat].fmtetc.cfFormat;
|
|
if (cf == oleEmbdObjClipFmt || cf == oleEmbSrcClipFmt) {
|
|
bii.Where = BOLE_DATAOBJECT;
|
|
bii.pStorage = NULLP;
|
|
bii.whereData.pData = dataObj;
|
|
}
|
|
else if (cf == oleLinkSrcClipFmt) {
|
|
bii.Where = BOLE_DATAOBJECT;
|
|
bii.pStorage = NULLP;
|
|
bii.whereData.pData = dataObj;
|
|
}
|
|
else if (fStaticOK) {
|
|
bii.How = (cf == CF_METAFILEPICT) ?
|
|
BOLE_EMBED_ASMETAFILE : BOLE_EMBED_ASBITMAP;
|
|
bii.Where = BOLE_DATAOBJECT;
|
|
bii.whereData.pData = dataObj;
|
|
}
|
|
else {
|
|
STGMEDIUM medium;
|
|
bii.Where = BOLE_HANDLE;
|
|
bii.whereHandle.dataFormat = cf;
|
|
bii.whereHandle.data = pService->GetDataFromDataObject (
|
|
dataObj, cf, NULL, DVASPECT_CONTENT, &medium);
|
|
|
|
bii.pStorage = NULL;
|
|
}
|
|
|
|
// Fields the same for all dropped objects
|
|
//
|
|
bii.hIcon = NULL;
|
|
if (*effect & DROPEFFECT_COPY || *effect & DROPEFFECT_MOVE)
|
|
bii.How = BOLE_EMBED;
|
|
else
|
|
if (*effect & DROPEFFECT_LINK)
|
|
bii.How = BOLE_LINK;
|
|
|
|
// Erase feedback at last position
|
|
//
|
|
if (dndInfoAvailable)
|
|
CalculateDndObjPos ();
|
|
else
|
|
SetRect (&dndObjPos, -1, -1, -1, -1);
|
|
|
|
HRESULT hr = NOERROR;
|
|
if (fDrawn) {
|
|
pDropDest->DragFeedback (&dndLastPos, &dndObjPos, BOLE_MOUSECONTAINED, dndFormat, hr);
|
|
fDrawn = FALSE;
|
|
if (hr != NOERROR) {
|
|
// dndLastFeedbackFailed shouldn't matter here
|
|
*effect = DROPEFFECT_NONE;
|
|
}
|
|
}
|
|
|
|
if (hr == NOERROR)
|
|
hr = pDropDest->Drop (&bii, &dndLastPos, &dndObjPos);
|
|
|
|
// This info is invalid after the DnD transaction
|
|
//
|
|
dndInfoAvailable = FALSE;
|
|
dndSize.cx = dndSize.cy = 0;
|
|
dndLastPos.x = dndLastPos.y = -1;
|
|
if (dndFormatList)
|
|
delete [] dndFormatList;
|
|
dndFormatList = NULL;
|
|
|
|
SCODE sc = GetScode (hr);
|
|
if (sc == S_OK || sc == DRAGDROP_S_DROP)
|
|
pContainer->BringToFront();
|
|
else
|
|
*effect = DROPEFFECT_NONE;
|
|
|
|
return hr;
|
|
}
|
|
|
|
*effect = DROPEFFECT_NONE;
|
|
OLERET (E_FAIL);
|
|
}
|
|
|
|
/**************************************************************************
|
|
|
|
IOleUILinkContainer implementation
|
|
|
|
This interface isn't part of OLE2 proper -- it's part of OLE2UI, and
|
|
is implemented here to allow clients to use the default Links dialog
|
|
box without building their own. If all the clients do build their own,
|
|
we could take this implementation out and also remove the BrowseLinks
|
|
member function of IDocument.
|
|
|
|
The DWORD dwLink parameter to these functions seems to be a magic
|
|
cookie that the OLE2UI Links dialog passes around to refer to an
|
|
individual link object. We use a BOlePart* and downcast as necessary.
|
|
|
|
The role of these functions is to translate the OLE2UI IOleUILinkContainer
|
|
calls into Bolero ILinkInfo calls and delegate them to BOlePart.
|
|
|
|
*/
|
|
|
|
DWORD _IFUNC BOleDocument::GetNextLink (DWORD dwLink)
|
|
{
|
|
BOlePart *pPart = (BOlePart*) dwLink;
|
|
if (!pPart)
|
|
|
|
// Start looking at the beginning, rather than relative to another part
|
|
//
|
|
if (pFirstPart)
|
|
|
|
// Find the next linked part *including* pFirstPart
|
|
//
|
|
return (DWORD) pFirstPart->GetNextLink (TRUE);
|
|
else
|
|
|
|
// We don't have any parts, linked or otherwise
|
|
//
|
|
return 0;
|
|
|
|
// Find the next linked part *after* pPart
|
|
//
|
|
return (DWORD) pPart->GetNextLink (FALSE);
|
|
}
|
|
|
|
HRESULT _IFUNC BOleDocument::SetLinkUpdateOptions
|
|
(
|
|
DWORD dwLink,
|
|
DWORD dwUpdateOpt
|
|
)
|
|
{
|
|
BOlePart *pPart = (BOlePart*) dwLink;
|
|
return pPart->UpdateSet ((BOleLinkUpdate)dwUpdateOpt);
|
|
}
|
|
|
|
HRESULT _IFUNC BOleDocument::GetLinkUpdateOptions
|
|
(
|
|
DWORD dwLink,
|
|
DWORD FAR* lpdwUpdateOpt
|
|
)
|
|
{
|
|
BOlePart *pPart = (BOlePart*) dwLink;
|
|
BOleLinkUpdate blu;
|
|
HRESULT hr = pPart->UpdateGet (&blu);
|
|
*lpdwUpdateOpt = blu;
|
|
return hr;
|
|
}
|
|
|
|
HRESULT _IFUNC BOleDocument::SetLinkSource
|
|
(
|
|
DWORD dwLink,
|
|
LPOLESTR lpszDisplayName,
|
|
ULONG lenFileName,
|
|
ULONG FAR* pchEaten,
|
|
BOOL fValidateSource
|
|
)
|
|
{
|
|
BOlePart *pPart = (BOlePart*) dwLink;
|
|
return pPart->SourceSet( lpszDisplayName );
|
|
}
|
|
|
|
HRESULT _IFUNC BOleDocument::GetLinkSource
|
|
(
|
|
DWORD dwLink,
|
|
LPOLESTR FAR* lplpszDisplayName,
|
|
ULONG FAR* lplenFileName,
|
|
LPOLESTR FAR* lplpszFullLinkType,
|
|
LPOLESTR FAR* lplpszShortLinkType,
|
|
BOOL FAR* lpfSourceAvailable,
|
|
BOOL FAR* lpfIsSelected
|
|
)
|
|
{
|
|
BOlePart *pPart = (BOlePart*) dwLink;
|
|
|
|
*lplpszDisplayName = NULL;
|
|
*lplpszFullLinkType = NULL;
|
|
*lplpszShortLinkType = NULL;
|
|
*lplenFileName = NULL;
|
|
*lpfSourceAvailable = pPart->GetLinkAvailability();
|
|
if (lpfIsSelected)
|
|
*lpfIsSelected = pPart == pFirstPart ? TRUE : FALSE;
|
|
|
|
BOOL ok = pPart->SourceGet (lplpszDisplayName, lplpszFullLinkType,
|
|
lplpszShortLinkType, lplenFileName);
|
|
|
|
OLERET(ok ? S_OK : E_FAIL);
|
|
}
|
|
|
|
HRESULT _IFUNC BOleDocument::OpenLinkSource (DWORD dwLink)
|
|
{
|
|
BOlePart *pPart = (BOlePart*) dwLink;
|
|
return pPart->Activate(TRUE);
|
|
}
|
|
|
|
HRESULT _IFUNC BOleDocument::UpdateLink
|
|
(
|
|
DWORD dwLink,
|
|
BOOL fErrorMessage,
|
|
BOOL fErrorAction
|
|
)
|
|
{
|
|
BOlePart *pPart = (BOlePart*) dwLink;
|
|
return pPart->UpdateNow ();
|
|
}
|
|
|
|
HRESULT _IFUNC BOleDocument::CancelLink (DWORD dwLink)
|
|
{
|
|
BOlePart *pPart = (BOlePart*) dwLink;
|
|
return pPart->SourceBreak();
|
|
}
|
|
|
|
//**************************************************************************
|
|
//
|
|
// Support functions for other Bolero objects
|
|
//
|
|
//**************************************************************************
|
|
|
|
// This OnModalDialog is not part of any Bolero interface.
|
|
// It's called by BOleService because the service doesn't know
|
|
// who the active object is, so the service just routes the call
|
|
// to the active doc to let us figure it out
|
|
//
|
|
HRESULT BOleDocument::OnModalDialog (BOOL fDialogComingActive)
|
|
{
|
|
if (pActivePart)
|
|
return pActivePart->EnableModeless (!fDialogComingActive);
|
|
return NOERROR;
|
|
}
|
|
|
|
// This TranslateAccel is not part of any Bolero interface.
|
|
// It's called by BOleService because the service doesn't know
|
|
// who the active object is, so the service just routes the call
|
|
// to the active doc to let us figure it out
|
|
//
|
|
HRESULT BOleDocument::TranslateAccel (LPMSG pMsg)
|
|
{
|
|
HRESULT hRes = ResultFromScode( S_FALSE );
|
|
if (pActivePart) {
|
|
hRes = pActivePart->TranslateAccelerator(pMsg);
|
|
}
|
|
return hRes;
|
|
}
|
|
|
|
// CacheDragRects is called to precompute the 11-pixel zones
|
|
// around the perimeter of the drop target. Normally, this
|
|
// wouldn't be a big deal to compute on the fly, but the traffic
|
|
// already generated during a drag-and-drop is so time consuming
|
|
// it seems worthwhile to give up a few bytes of instance data
|
|
//
|
|
void _IFUNC BOleDocument::CacheDragRects (LPRECT pR)
|
|
{
|
|
RECT r = *pR;
|
|
WIN::SetRect (&rcScrollTop, r.left, r.top, r.right, r.top + 11);
|
|
WIN::SetRect (&rcScrollTop, r.left, r.top, r.right, r.top + 11);
|
|
WIN::SetRect (&rcScrollLeft, r.left, r.top, r.left + 11, r.bottom);
|
|
WIN::SetRect (&rcScrollRight, r.right - 11, r.top, r.right, r.bottom);
|
|
WIN::SetRect (&rcScrollBottom, r.left, r.bottom - 11, r.right, r.bottom);
|
|
}
|
|
|
|
// Accessor function used by BOlePart::RemoveFromList to make sure
|
|
// the head of the list (maintained by BOleDocument) is up-to-date
|
|
//
|
|
void BOleDocument::OnRemovePart (BOlePart *pPart)
|
|
{
|
|
if (pFirstPart == pPart)
|
|
pFirstPart = pFirstPart->GetNextPart();
|
|
}
|
|
|
|
|
|
//*************************************************************************
|
|
//
|
|
// IOleInPlaceFrame implementation
|
|
//
|
|
//*************************************************************************
|
|
|
|
HRESULT _IFUNC BOleDocument::InsertMenus (HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths)
|
|
{
|
|
OLERET (SUCCEEDED(pContainer->InsertContainerMenus (hmenuShared, (BOleMenuWidths*) lpMenuWidths)) ?
|
|
S_OK : E_FAIL);
|
|
}
|
|
|
|
HRESULT _IFUNC BOleDocument::SetMenu (HMENU hmenuShared, HOLEMENU holeMenu, HWND hwndActiveObject)
|
|
{
|
|
HRESULT hr = NOERROR;
|
|
|
|
// hmenuShared will be null when the call to BOleDocument::SetMenu is
|
|
// initiated from BOlePart::OnUIDeactivate. hmenuShared will be valid
|
|
// when the SetMenu call comes from the real server object
|
|
//
|
|
if (hmenuShared)
|
|
hr = pContainer->SetFrameMenu (hmenuShared);
|
|
|
|
// holemenu will be null when the call to BOleDocument::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, pContainer->GetWindow(),
|
|
hwndActiveObject, NULL, NULL);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT _IFUNC BOleDocument::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 BOleDocument::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.
|
|
//
|
|
pContainer->SetStatusText(statusText);
|
|
OLERET(S_OK);
|
|
}
|
|
|
|
HRESULT _IFUNC BOleDocument::EnableModeless (BOOL fEnable)
|
|
{
|
|
return pApplication->OnModalDialog (!fEnable);
|
|
}
|
|
|
|
HRESULT _IFUNC BOleDocument::TranslateAccelerator (MSG FAR* msg, WORD wID)
|
|
{
|
|
HWND oldhwnd = msg->hwnd;
|
|
msg->hwnd = pContainer->GetWindow ();
|
|
HRESULT hr = pContainer->Accelerator(msg);
|
|
msg->hwnd = oldhwnd;
|
|
return hr;
|
|
}
|
|
|
|
|