Greetings Community of experts, I am trying to synchronize the movement and zoom in two windows of AutoCAD models, that is, in two different planes open .dwg divided into two windows one active and the other inactive synchronize the zoom (scroll + or -) or the movement (PAN) from the active window to the inactive one (In model with two open planes in AutoCAD M3D -> SYSWINDOWS :: tile Vertical), I was researching and I found this code that does what I want but only with one plane, the problem is that I can not make it work in VS2019 c ++, I get an error in the lines with "WinCallBack" indicating that BOOL cannot become a constant, I appreciate your help in advance.
#include "StdAfx.h"
#include "resource.h"
#pragma warning( disable : 4278 )
#include <windows.h>
#include <stdio.h>
#include "acedCmdNF.h"
#include "AcMyEditorReactor.h"
#include "AcMyInputContextReactor.h"
// Viewchanged notification is not received during a pan or zoom using mouse wheel.
// So identify those using WM messages.
BOOL WinCallBack(MSG *pMsg)
{
if( pMsg->message == WM_VSCROLL ||
pMsg->message == WM_HSCROLL ||
pMsg->message == WM_MOUSEWHEEL ||
pMsg->message == WM_MBUTTONUP)
{
// Sync the modelspace viewports
acDocManager->sendStringToExecute(acDocManager->mdiActiveDocument(), ACRX_T("SyncVTR "), false, true, false);
}
return FALSE;
}
class CMyTest1App : public AcRxArxApp
{
private:
AcMyEditorReactor *pEditorReactor;
AcMyInputContextReactor *pInputContextReactor;
public:
CMyTest1App () : AcRxArxApp ()
{
}
virtual AcRx::AppRetCode On_kInitAppMsg (void *pkt)
{
AcRx::AppRetCode retCode =AcRxArxApp::On_kInitAppMsg (pkt) ;
// Editor reactor to receive to ViewChanged notification
pEditorReactor = new AcMyEditorReactor(true);
// InputContext reactor to receive quiescent state change notification
pInputContextReactor = new AcMyInputContextReactor();
// Viewchanged notification is not received during a pan or zoom using mouse wheel.
// So identify those using WM messages.
acedRegisterFilterWinMsg(WinCallBack);
return (retCode);
}
virtual AcRx::AppRetCode On_kUnloadAppMsg (void *pkt)
{
AcRx::AppRetCode retCode =AcRxArxApp::On_kUnloadAppMsg (pkt) ;
// cleanup
if(pEditorReactor)
{
delete pEditorReactor;
pEditorReactor = NULL;
}
if(pInputContextReactor)
{
delete pInputContextReactor;
pInputContextReactor = NULL;
}
acedRemoveFilterWinMsg(WinCallBack);
return (retCode);
}
virtual AcRx::AppRetCode On_kLoadDwgMsg (void *pkt)
{
AcRx::AppRetCode retCode =AcRxArxApp::On_kLoadDwgMsg (pkt) ;
return (retCode) ;
}
virtual void RegisterServerComponents ()
{
}
// Command to sync the model space viewport parameters
static void AdskMyTestSyncVTR()
{
// Get the VTR updated
acedVports2VportTableRecords();
// We will update the other VTR only if view parameters change
Adesk::Boolean updateNeeded = Adesk::kFalse;
Acad::ErrorStatus es;
AcDbDatabase *pDb = acdbHostApplicationServices()->workingDatabase();
AcApDocument *pDoc = acDocManager->document(pDb);
if( pDoc == NULL )
return;
es = acDocManager->lockDocument(pDoc);
// This code at present can only deal with 2 Modelspace viewports split vertically in half
if(pDb->tilemode() == Adesk::kFalse)
{
struct resbuf rb;
if(ads_getvar(_T("cvport"), &rb) != RTNORM)
{
acutPrintf(_T("\nError using ads_getvar().\n"));
return;
}
if(rb.resval.rint == 1)
{
return; // Can only work with model space viewports.
}
}
AcDbViewportTable *pVT = NULL;
pDb->getViewportTable(pVT,AcDb::kForRead);
// Identify the left and right modelspace viewports
AcDbViewportTableRecord *pLeftVTR = NULL;
AcDbViewportTableRecord *pRightVTR = NULL;
AcDbViewportTableIterator *pIter = NULL;
es = pVT->newIterator(pIter);
if(es == Acad::eOk)
{
for (;!pIter->done();pIter->step())
{
AcDbViewportTableRecord *pVTR = NULL;
es = pIter->getRecord(pVTR, AcDb::kForRead);
if(es == Acad::eOk)
{
AcGePoint2d ll = pVTR->lowerLeftCorner();
AcGePoint2d ur = pVTR->upperRightCorner();
if(ll.isEqualTo(AcGePoint2d(0, 0)))
{// Left modelspace viewport
pLeftVTR = pVTR;
}
else if(ur.isEqualTo(AcGePoint2d(1.0, 1.0)))
{// Right modelspace viewport
pRightVTR = pVTR;
}
else
pVTR->close();
}
}
// If for some reason, we did not have two modelspace viewports,
// lets stop here.
if(pLeftVTR == NULL)
{
if(pRightVTR != NULL)
pRightVTR->close();
return;
}
if(pRightVTR == NULL)
{
if(pLeftVTR != NULL)
pLeftVTR->close();
return;
}
// Ensure that the two viewports are split vertically in half.
// If not, the view parameters when applied from one to another
// may not apply directly using this code.
// If the viewports were resized manually, set them right.
AcGePoint2d ll1 = pLeftVTR->lowerLeftCorner();
AcGePoint2d ur1 = pLeftVTR->upperRightCorner();
AcGePoint2d ll2 = pRightVTR->lowerLeftCorner();
AcGePoint2d ur2 = pRightVTR->upperRightCorner();
if(ll1.isEqualTo(AcGePoint2d(0.0, 0.0)) == false)
{
if(! pLeftVTR->isWriteEnabled())
pLeftVTR->upgradeOpen();
pLeftVTR->setLowerLeftCorner(AcGePoint2d(0.0, 0.0));
}
if(ur1.isEqualTo(AcGePoint2d(0.5, 1.0)) == false)
{
if(! pLeftVTR->isWriteEnabled())
pLeftVTR->upgradeOpen();
pLeftVTR->setUpperRightCorner(AcGePoint2d(0.5, 1.0));
}
if(ll2.isEqualTo(AcGePoint2d(0.5, 0.0)) == false)
{
if(! pRightVTR->isWriteEnabled())
pRightVTR->upgradeOpen();
pRightVTR->setLowerLeftCorner(AcGePoint2d(0.5, 0.0));
}
if(ur2.isEqualTo(AcGePoint2d(1.0, 1.0)) == false)
{
if(! pRightVTR->isWriteEnabled())
pRightVTR->upgradeOpen();
pRightVTR->setUpperRightCorner(AcGePoint2d(1.0, 1.0));
}
// Get the active model space viewport
struct resbuf res;
acedGetVar(L"CVPORT", &res);
short vpnumber = res.resval.rint;
// Identify the model space viewports from/to which settings will be copied
// The active modelspace viewport is the viewport from which settings will be copied
AcDbViewportTableRecord *pFromVTR = NULL;
AcDbViewportTableRecord *pToVTR = NULL;
if(pLeftVTR->number() == vpnumber)
{
pFromVTR = pLeftVTR;
pToVTR = pRightVTR;
}
if(pRightVTR->number() == vpnumber)
{
pFromVTR = pRightVTR;
pToVTR = pLeftVTR;
}
// Sorry, we did not identify the active viewport
// from which settings need to be copied.
if(pFromVTR == NULL || pToVTR == NULL)
return;
// Copy the VTR settings from one modelspace viewport to another
// only if they are different. We will use a tolerance to ensure
// very small differences do not get us in a soup. I meant loop :)
AcGeTol newTol;
newTol.setEqualPoint (0.00001);
newTol.setEqualVector(0.00001);
// ViewDirection
AcGeVector3d fromViewDir = pFromVTR->viewDirection();
AcGeVector3d toViewDir = pToVTR->viewDirection();
if(pFromVTR->viewDirection().isEqualTo(pToVTR->viewDirection(), newTol) == false)
{
if(! pToVTR->isWriteEnabled())
pToVTR->upgradeOpen();
pToVTR->setViewDirection(pFromVTR->viewDirection());
updateNeeded = Adesk::kTrue;
}
// ViewTwist
if(abs(pFromVTR->viewTwist() - pToVTR->viewTwist()) > 0.01)
{
if(! pToVTR->isWriteEnabled())
pToVTR->upgradeOpen();
pToVTR->setViewTwist(pFromVTR->viewTwist());
updateNeeded = Adesk::kTrue;
}
// Target
if(pFromVTR->target().isEqualTo(pToVTR->target(), newTol) == false)
{
if(! pToVTR->isWriteEnabled())
pToVTR->upgradeOpen();
pToVTR->setTarget(pFromVTR->target());
updateNeeded = Adesk::kTrue;
}
// BackClipEnabled
if(pFromVTR->backClipEnabled() != pToVTR->backClipEnabled())
{
if(! pToVTR->isWriteEnabled())
pToVTR->upgradeOpen();
pToVTR->setBackClipEnabled(pFromVTR->backClipEnabled());
updateNeeded = Adesk::kTrue;
}
// BackClipDistance
if(abs(pFromVTR->backClipDistance() - pToVTR->backClipDistance()) > 0.01)
{
if(! pToVTR->isWriteEnabled())
pToVTR->upgradeOpen();
pToVTR->setBackClipDistance(pFromVTR->backClipDistance());
updateNeeded = Adesk::kTrue;
}
// FrontClipEnabled
if(pFromVTR->frontClipEnabled() != pToVTR->frontClipEnabled())
{
if(! pToVTR->isWriteEnabled())
pToVTR->upgradeOpen();
pToVTR->setFrontClipEnabled(pFromVTR->frontClipEnabled());
updateNeeded = Adesk::kTrue;
}
// FrontClipDistance
if(abs(pFromVTR->frontClipDistance() - pToVTR->frontClipDistance()) > 0.01)
{
if(! pToVTR->isWriteEnabled())
pToVTR->upgradeOpen();
pToVTR->setFrontClipDistance(pFromVTR->frontClipDistance());
updateNeeded = Adesk::kTrue;
}
// Elevation
if(abs(pFromVTR->elevation() - pToVTR->elevation()) > 0.01)
{
if(! pToVTR->isWriteEnabled())
pToVTR->upgradeOpen();
pToVTR->setElevation(pFromVTR->elevation());
updateNeeded = Adesk::kTrue;
}
// centerPoint
if(pFromVTR->centerPoint().isEqualTo(pToVTR->centerPoint(), newTol) == false)
{
if(! pToVTR->isWriteEnabled())
pToVTR->upgradeOpen();
pToVTR->setCenterPoint(pFromVTR->centerPoint());
updateNeeded = Adesk::kTrue;
}
// Height
if(abs(pFromVTR->height() - pToVTR->height()) > 0.01)
{
if(! pToVTR->isWriteEnabled())
pToVTR->upgradeOpen();
pToVTR->setHeight(pFromVTR->height());
updateNeeded = Adesk::kTrue;
}
// Width
if(abs(pFromVTR->width() - pToVTR->width()) > 0.01)
{
if(! pToVTR->isWriteEnabled())
pToVTR->upgradeOpen();
pToVTR->setWidth(pFromVTR->width());
updateNeeded = Adesk::kTrue;
}
// Done with the VTR
pLeftVTR->close();
pRightVTR->close();
delete pIter;
}
es = pVT->close();
es = acDocManager->unlockDocument(pDoc);
// Update the Vports if we did change any of the VTR parameters
if(updateNeeded)
{
acedVportTableRecords2Vports();
}
}
};
//-----------------------------------------------------------------------------
IMPLEMENT_ARX_ENTRYPOINT(CMyTest1App)
ACED_ARXCOMMAND_ENTRY_AUTO(CMyTest1App, AdskMyTest, SyncVTR, SyncVTR, ACRX_CMD_MODAL, NULL)
https://adndevblog.typepad.com/autocad/2014/07/synchronizing-model-space-viewports.html