📄 page.cpp
字号:
* we leave xOff and yOff the same to account for scrolling.
*/
if (fPrinter)
{
xOff=LOMETRIC_BORDER+m_pPG->m_xMarginLeft;
yOff=-LOMETRIC_BORDER-m_pPG->m_yMarginTop;
/*
* Get device information. If this fails, ptd is
* NULL which is acceptable.
*/
if (m_pPG->DevReadConfig(&pcd, &hIC))
ptd=&(pcd->td);
}
for (i=(int)m_cTenants-1; i >=0; i--)
{
if (TenantGet(i, &pTenant, FALSE))
{
RECT rc, rcWin;
RECTL rcl;
//Paint this tenant only if visible.
pTenant->RectGet(&rcl, TRUE);
RECTFROMRECTL(rc, rcl);
OffsetRect(&rc, -(int)m_pPG->m_xPos
, -(int)m_pPG->m_yPos);
GetClientRect(m_hWnd, &rcWin);
if (IntersectRect(&rc, &rc, &rcWin))
{
pTenant->Draw(hDC, ptd, hIC, xOff, yOff
, fNoColor, fPrinter);
}
}
}
//Free whatever CPages::DevReadConfig returned.
if (NULL!=pcd)
{
LPMALLOC pIMalloc;
if (SUCCEEDED(CoGetMalloc(MEMCTX_TASK, &pIMalloc)))
{
pIMalloc->Free(pcd);
pIMalloc->Release();
}
}
if (NULL!=hIC)
DeleteDC(hIC);
return;
}
/*
* CPage::TenantCreate
*
* Purpose:
* Creates a new tenant of a specific type.
*
* Parameters:
* tType TENANTTYPE to create.
* pv LPVOID providing information for the new
* object creation.
* pFE LPFORMATETC describing how we want this
* rendered.
* ppo PPATRONOBJECT with placement data.
* dwData DWORD extra data to pass to the tenant.
*
* Return Value:
* None
*/
BOOL CPage::TenantCreate(TENANTTYPE tType, LPVOID pv
, LPFORMATETC pFE, PPATRONOBJECT ppo, DWORD dwData)
{
PCTenant pTenant;
UINT uRet;
int x, y;
int h, v;
POINTL ptl;
SIZEL szl;
RECTL rcl;
RECT rc;
//New tenants go at top of the pile; zero index to TenantAdd.
if (!TenantAdd(0, m_dwIDNext, &pTenant))
return FALSE;
uRet=pTenant->Create(tType, pv, pFE, &ptl, &szl, m_pIStorage
, ppo, dwData);
if (CREATE_FAILED==uRet)
{
//Reverse Create AND TenantAdd
SendMessage(m_hWndTenantList, LB_DELETESTRING, 0, 0L);
pTenant->Destroy(m_pIStorage);
pTenant->Release();
return FALSE;
}
m_dwIDNext++;
m_cTenants++;
if (NULL!=m_pTenantCur)
m_pTenantCur->Select(FALSE, TRUE);
m_iTenantCur=0; //First one in the list now.
m_pTenantCur=pTenant;
//Tell the tenant where it lives, default is (0,0) in print area
x=LOMETRIC_BORDER+m_pPG->m_xMarginLeft;
y=-LOMETRIC_BORDER-m_pPG->m_yMarginTop;
h=x;
v=y;
if (CREATE_PLACEDOBJECT==uRet)
{
SetRect(&rc, 3*CXYHANDLE, 3*CXYHANDLE, 0, 0);
RectConvertMappings(&rc, NULL, FALSE);
//Make sure place point is on page, otherwise go to (0,0)
if (((int)ptl.x > x)
&& ((int)ptl.x < x+(int)m_pPG->m_cx-rc.left))
x=(int)ptl.x;
//m_pPG->m_cy is absolute
if (((int)ptl.y < y)
&& ((int)ptl.y > y-(int)m_pPG->m_cy-rc.top))
y=(int)ptl.y;
}
//Bounds check size of the object and fit to page as necessary.
if (x+(int)szl.cx > (int)(h+m_pPG->m_cx))
szl.cx=h+m_pPG->m_cx-x;
//Remember that szl we get from Create is absolute
if (y-(int)szl.cy < (int)(v-m_pPG->m_cy))
szl.cy=-(int)(v-m_pPG->m_cy-y);
SETRECTL(rcl, x, y, x+szl.cx, y-szl.cy);
m_pTenantCur->RectSet(&rcl, FALSE, TRUE);
//Force a repaint on this new guy
m_pTenantCur->Invalidate();
UpdateWindow(m_hWnd);
m_pTenantCur->Select(TRUE, TRUE);
//Make sure this new tenant knows about showing it's type.
m_pTenantCur->ShowObjectType(m_pPG->m_fShowTypes);
//New tenants must know the available monikers
if (NULL!=m_pmkFile)
{
LPBC pbc;
LPMONIKER pmkPage;
TCHAR szTemp[32];
LPTSTR pszFile;
#ifdef WIN32ANSI
OLECHAR szW[32];
GetStorageName(szW);
WideCharToMultiByte(CP_ACP, 0, szW, -1, szTemp, 32
, NULL, NULL);
#else
GetStorageName(szTemp);
#endif
CreateItemMoniker(TEXT("!"), szTemp, &pmkPage);
//We can get the filename from our file moniker
CreateBindCtx(0, &pbc);
#ifdef WIN32ANSI
LPOLESTR pszTemp;
m_pmkFile->GetDisplayName(pbc, NULL, &pszTemp);
pszFile=(LPTSTR)CoTaskMemAlloc(512);
WideCharToMultiByte(CP_ACP, 0, pszTemp, -1, pszFile
, 512, NULL, NULL);
CoTaskMemFree((void *)pszTemp);
#else
m_pmkFile->GetDisplayName(pbc, NULL, &pszFile);
#endif
pbc->Release();
pTenant->NotifyOfRename(pszFile, m_pmkFile, pmkPage);
pmkPage->Release();
CoTaskMemFree((void *)pszFile);
}
//Activate new objects immediately and force a save on them
if (TENANTTYPE_EMBEDDEDOBJECT==tType)
{
//CHAPTER24MOD
DWORD dwFlags;
/*
* A control, by virtue of being a control, will already
* be in-place active except in design mode. In any case,
* the only thing a control can do is draw on our page,
* so there's little point in activating a control here.
*/
dwFlags=m_pTenantCur->GetControlFlags();
if (!(TENANTSTATE_CONTROL & dwFlags))
{
m_pTenantCur->Activate(OLEIVERB_SHOW, NULL);
m_pTenantCur->Update();
}
//End CHAPTER24MOD
}
return TRUE;
}
/*
* CPage::TenantDestroy
*
* Purpose:
* Destroys the currently selected tenant on this page.
*
* Parameters:
* None
*
* Return Value:
* None
*/
BOOL CPage::TenantDestroy(void)
{
if (NULL==m_pTenantCur)
{
MessageBeep(0);
return FALSE;
}
SendMessage(m_hWndTenantList, LB_DELETESTRING
, m_iTenantCur, 0L);
m_pTenantCur->Invalidate();
m_pTenantCur->Destroy(m_pIStorage);
m_pTenantCur->Release();
m_pTenantCur=NULL;
//Update counts, etc., and select the next tenant in the list.
if (m_iTenantCur==m_cTenants-1)
m_iTenantCur--;
if (0==--m_cTenants)
m_pTenantCur=NULL;
else
{
TenantGet(m_iTenantCur, &m_pTenantCur, TRUE);
m_pTenantCur->Select(TRUE, TRUE);
}
UpdateWindow(m_hWnd);
return TRUE;
}
/*
* CPage::TenantClip
*
* Purpose:
* Copies or cuts the currently selected tenant to the clipoard.
*
* Parameters:
* fCut BOOL TRUE to cut the object, FALSE to copy.
*
* Return Value:
* BOOL TRUE if successful, FALSE otherwise.
*/
BOOL CPage::TenantClip(BOOL fCut)
{
LPDATAOBJECT pIDataObject;
BOOL fRet=FALSE;
if (NULL==m_pTenantCur)
return FALSE;
/*
* To perform a data transfer operation, we need to create a
* data object with the selected object's data inside. To do
* this we CoCreateInstance on CLSID_DataTransferObject
* (Also implemented in this chapter), retrieve data from the
* object we have, stuff that data into the transfer object,
* then stick that object on the clipboard.
*
* Since we'll want an identical object at other times, like for
* drag-drop, we use a private function to actually create it.
*/
pIDataObject=TransferObjectCreate(NULL);
if (NULL!=pIDataObject)
{
if (SUCCEEDED(OleSetClipboard(pIDataObject)))
{
if (fCut)
TenantDestroy();
fRet=TRUE;
}
pIDataObject->Release();
}
return fRet;
}
/*
* CPage::FQueryObjectSelected
*
* Purpose:
* Returns whether or not there is an object selected on this
* page for Cut, Copy, Delete functions.
*
* Parameters:
* hMenu HMENU of the Edit menu.
*
* Return Value:
* BOOL TRUE if we have an object, FALSE otherwise.
*/
BOOL CPage::FQueryObjectSelected(HMENU hMenu)
{
HMENU hMenuTemp;
/*
* This will only be called on WM_INITMENUPOPUP, we'll also
* use this function to create the Verb menu for this object.
*/
if (NULL!=m_pTenantCur)
{
m_pTenantCur->AddVerbMenu(hMenu, MENUPOS_OBJECT);
return TRUE;
}
OleUIAddVerbMenu(NULL, NULL, hMenu, MENUPOS_OBJECT
, IDM_VERBMIN, IDM_VERBMAX, FALSE, 0, &hMenuTemp);
return FALSE;
}
/*
* CPage::ActivateObject
*
* Purpose:
* Executes a verb on the currently selected object.
*
* Parameters:
* iVerb LONG of the selected verb.
* pMSG LPMSG that caused the invocation of the verb.
*
* Return Value:
* None
*/
void CPage::ActivateObject(LONG iVerb, LPMSG pMSG)
{
if (NULL==m_pTenantCur)
return;
m_pTenantCur->Activate(iVerb, pMSG);
return;
}
/*
* CPage::ShowObjectTypes
*
* Purpose:
* Loops through all the tenants and tells each one to turn on or
* off the Show Objects features.
*
* Parameters:
* fShow BOOL indicating to show the type or not.
*
* Return Value:
* None
*/
void CPage::ShowObjectTypes(BOOL fShow)
{
PCTenant pTenant;
UINT i;
for (i=0; i < m_cTenants; i++)
{
if (TenantGet(i, &pTenant, FALSE))
pTenant->ShowObjectType(fShow);
}
return;
}
/*
* CPage::NotifyTenantsOfRename
*
* Purpose:
* Loops through all the tenants and informs each of the new
* document name.
*
* Parameters:
* pszFile LPTSTR of the new filename.
* pmk LPMONKIER for the new filename.
*
* Return Value:
* None
*/
void CPage::NotifyTenantsOfRename(LPTSTR pszFile, LPMONIKER pmk)
{
PCTenant pTenant;
UINT i;
LPMONIKER pmkPage;
LPMONIKER pmkAll;
TCHAR szTemp[32];
//Save the file moniker
ReleaseInterface(m_pmkFile);
m_pmkFile=pmk;
m_pmkFile->AddRef();
//Create a page moniker to send to the tenants.
#ifdef WIN32ANSI
OLECHAR szW[32];
GetStorageName(szW);
WideCharToMultiByte(CP_ACP, 0, szW, -1, szTemp, 32
, NULL, NULL);
#else
GetStorageName(szTemp);
#endif
CreateItemMoniker(TEXT("!"), szTemp, &pmkPage);
for (i=0; i < m_cTenants; i++)
{
if (TenantGet(i, &pTenant, FALSE))
pTenant->NotifyOfRename(pszFile, pmk, pmkPage);
}
/*
* Register a File!Page!"\" wildcard moniker as well.
* Note that the page is already marked as running
* with the document's wildcard moniker.
*/
CreateItemMoniker(TEXT("!"), TEXT("\\"), &pmkAll);
if (NULL!=pmkAll)
{
LPMONIKER pmkWild=NULL;
LPMONIKER pmkTemp=NULL;
INOLE_RevokeAsRunning(&m_dwRegROTWild);
pmk->ComposeWith(pmkPage, FALSE, &pmkTemp);
if (NULL!=pmkTemp)
{
pmkTemp->ComposeWith(pmkAll, FALSE, &pmkWild);
pmkTemp->Release();
}
if (NULL!=pmkWild)
{
INOLE_RegisterAsRunning(this, pmk, 0
, &m_dwRegROTWild);
pmkWild->Release();
}
pmkAll->Release();
}
//If anything held onto this, they AddRef'd
pmkPage->Release();
return;
}
/*
* CPage::ConvertObject
*
* Purpose:
* Invokes and handles the results of the Convert dialog
*
* Parameters:
* hWndFrame HWND to use as the parent of the dialog.
* fNoServer BOOL indicating if this was called because
* ActivateObject failed.
*
* Return Value:
* None
*/
BOOL CPage::ConvertObject(HWND hWndFrame, BOOL fNoServer)
{
HRESULT hr;
OLEUICONVERT ct;
TENANTTYPE tType;
TENANTINFO ti;
UINT uRet;
HCURSOR hCur;
BOOL fActivate=fNoServer;
SIZEL szl;
if (NULL==m_pTenantCur)
return FALSE;
tType=m_pTenantCur->TypeGet();
if (TENANTTYPE_STATIC==tType)
{
MessageBeep(0);
return FALSE;
}
//Get object information we may want.
m_pTenantCur->GetInfo(&ti);
//Fill the structure.
memset(&ct, 0, sizeof(ct));
ct.cbStruct=sizeof(OLEUICONVERT);
ct.hWndOwner=hWndFrame;
ct.fIsLinkedObject=(TENANTTYPE_LINKEDOBJECT==tType);
ct.dvAspect=ti.fe.dwAspect;
m_pTenantCur->ObjectClassFormatAndIcon(&ct.clsid, &ct.wFormat
, &ct.lpszUserType, &ct.hMetaPict, &ct.lpszDefLabel);
uRet=OleUIConvert(&ct);
if (OLEUI_OK==uRet)
{
//Potentially a long operation.
hCur=SetCursor(LoadCursor(NULL, IDC_WAIT));
//Prevent multiple repaints.
m_pTenantCur->EnableRepaint(FALSE);
//First, let's bother with the iconic aspect switch.
if ((DVASPECT_ICON==ct.dvAspect && ct.fObjectsIconChanged)
|| ct.dvAspect!=ti.fe.dwAspect)
{
HGLOBAL hMem=NULL;
//Only pass non-NULL handle for icon aspects.
if (DVASPECT_ICON==ct.dvAspect)
hMem=ct.hMetaPict;
m_pPG->m_fDirty=m_pTenantCur->SwitchOrUpdateAspect(hMem
, FALSE);
}
//Now change types around.
if ((CF_SELECTCONVERTTO & ct.dwFlags)
&& ct.clsid!=ct.clsidNew)
{
LPSTORAGE pIStorage;
/*
* User selected convert, so:
* 1. Unload the object (back to passive state)
* 2. Call INOLE_DoConvert, which calls WriteClassStg,
* WriteFmtUserTypeStg, and SetConvertStg.
* 3. Reload the object and force an update.
*/
//This should be the only close necessary.
m_pTenantCur->StorageGet(&pIStorage);
m_pTenantCur->Close(TRUE);
hr=INOLE_DoConvert(pIStorage, ct.clsidNew);
//Need to commit the new type and format
pIStorage->Commit(STGC_DEFAULT);
pIStorage->Release();
if (SUCCEEDED(hr))
{
LPUNKNOWN pObj;
LPOLEOBJECT pIOleObject;
//Reload and update.
m_pTenantCur->Load(m_pIStorage, &ti);
m_pTenantCur->ObjectGet(&pObj);
pObj->QueryInterface(IID_IOleObject
, (PPVOID)&pIOleObject);
pIOleObject->Update();
pIOleObject->Release();
pObj->Release();
}
m_pPG->m_fDirty=TRUE;
}
if (CF_SELECTACTIVATEAS & ct.dwFlags)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -