568 lines
16 KiB
C++
568 lines
16 KiB
C++
// GsPreviewCtrl.cpp : implementation file
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
#include "resource.h"
|
|
#include "GsPreviewCtrl.h"
|
|
#include "acgsmanager.h"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
extern TARCH_IMPEXP double g_nWalkDistStep, g_nWalkAngleStep;
|
|
#define RXASSERT ASSERT
|
|
|
|
double GetLatitude(XPoint ptCam, XPoint ptTar) //-PI/2 ~ PI/2
|
|
{
|
|
double nDist=ptTar.Distance(ptCam);
|
|
if(nDist<_DIST_SNAP)
|
|
return 0.0;
|
|
if(ptTar.Distance2d(ptCam)<_DIST_SNAP) {
|
|
return ((ptTar.z > ptCam.z)? PI/2 : -PI/2);
|
|
}
|
|
return asin((ptTar.z-ptCam.z)/nDist);
|
|
}
|
|
|
|
|
|
double GetLongitude(XPoint ptCam, XPoint ptTar) // 0 ~ 2*PI
|
|
{
|
|
if(ptTar.Distance2d(ptCam)<_DIST_SNAP)
|
|
return 0.0;
|
|
return ads_angle(ptCam, ptTar);
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CGsPreviewCtrl
|
|
IMPLEMENT_DYNAMIC(CGsPreviewCtrl, CStatic)
|
|
|
|
CGsPreviewCtrl::CGsPreviewCtrl(int nOrbitFlag) : CStatic(), mOrbitFlag(nOrbitFlag),
|
|
mpManager(NULL), mpFactory(NULL), mpDevice(NULL), mpView(NULL),
|
|
mpModel(NULL),mbModelCreated(false),mbPanning(false),mbOrbiting(false),
|
|
mDistStep(g_nWalkDistStep), mAngStep(g_nWalkAngleStep)
|
|
{
|
|
|
|
}
|
|
|
|
BOOL CGsPreviewCtrl::DestroyWindow()
|
|
{
|
|
clearAll();
|
|
return CStatic::DestroyWindow();
|
|
}
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(CGsPreviewCtrl, CStatic)
|
|
//{{AFX_MSG_MAP(CGsPreviewCtrl)
|
|
ON_WM_PAINT()
|
|
ON_WM_SIZE()
|
|
ON_WM_MOUSEWHEEL()
|
|
ON_WM_LBUTTONDOWN()
|
|
ON_WM_MBUTTONDOWN()
|
|
ON_WM_MBUTTONUP()
|
|
ON_WM_MOUSEMOVE()
|
|
ON_WM_NCHITTEST()
|
|
ON_WM_SETFOCUS()
|
|
ON_WM_LBUTTONUP()
|
|
ON_WM_KEYDOWN()
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CGsPreviewCtrl message handlers
|
|
|
|
void CGsPreviewCtrl::OnPaint()
|
|
{
|
|
CPaintDC dc(this);
|
|
//update the gs view
|
|
if(mpView) {
|
|
mpView->invalidate();
|
|
mpView->update();
|
|
}
|
|
}
|
|
|
|
// Erase view and delete model
|
|
void CGsPreviewCtrl::erasePreview()
|
|
{
|
|
if (mpView)
|
|
mpView->eraseAll();
|
|
if (mpManager && mpModel) {
|
|
mpManager->destroyAutoCADModel (mpModel);
|
|
mpModel = NULL;
|
|
}
|
|
}
|
|
|
|
void CGsPreviewCtrl::setModel(AcGsModel* pModel)
|
|
{
|
|
erasePreview();
|
|
mpModel = pModel;
|
|
mbModelCreated =false;
|
|
}
|
|
|
|
void CGsPreviewCtrl::clearAll()
|
|
{
|
|
if (mpView) {
|
|
mpView->eraseAll();
|
|
}
|
|
if (mpDevice) {
|
|
bool b = mpDevice->erase(mpView);
|
|
RXASSERT(b);
|
|
}
|
|
|
|
if (mpFactory) {
|
|
if (mpView) {
|
|
mpFactory->deleteView(mpView);
|
|
mpView = NULL;
|
|
}
|
|
if (mpGhostModel) {
|
|
mpFactory->deleteModel(mpGhostModel);
|
|
mpGhostModel = NULL;
|
|
}
|
|
mpFactory = NULL;
|
|
}
|
|
|
|
if (mpManager) {
|
|
if (mpModel) {
|
|
if (mbModelCreated)
|
|
mpManager->destroyAutoCADModel(mpModel);
|
|
mpModel = NULL;
|
|
}
|
|
|
|
if (mpDevice) {
|
|
mpManager->destroyAutoCADDevice(mpDevice);
|
|
mpDevice = NULL;
|
|
}
|
|
mpManager = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
void CGsPreviewCtrl::init(bool bCreateModel)
|
|
{
|
|
//Load our special cursors
|
|
{
|
|
CTemporaryResourceOverride vTemp;
|
|
CWinApp *pApp=AfxGetApp();
|
|
mhPanCursor=pApp->LoadCursor(IDI_PAN);
|
|
mhCrossCursor=pApp->LoadCursor(IDI_CROSS);
|
|
mhOrbitCursor=pApp->LoadCursor(IDI_ORBIT);
|
|
}
|
|
|
|
//Instantiate view, a device and a model object
|
|
CRect rect;
|
|
if (!mpManager) {
|
|
mpManager = acgsGetGsManager();
|
|
RXASSERT(mpManager);
|
|
#if (ADS >= 20)
|
|
AcGsKernelDescriptor desc;
|
|
desc.addRequirement(AcGsKernelDescriptor::k3DDrawing);
|
|
mpFactory = AcGsManager::acquireGraphicsKernel(desc);
|
|
if (!mpFactory) return;
|
|
#else
|
|
mpFactory = mpManager->getGSClassFactory();
|
|
#endif
|
|
RXASSERT(mpFactory);
|
|
//a device with standard autocad color palette
|
|
|
|
#if (ADS >= 20)
|
|
//mpDevice = mpFactory->createOffScreenDevice();
|
|
mpDevice = mpManager->createAutoCADDevice(*mpFactory, m_hWnd);
|
|
#else
|
|
mpDevice = mpManager->createAutoCADDevice(m_hWnd);
|
|
#endif
|
|
|
|
RXASSERT(mpDevice);
|
|
|
|
GetClientRect( &rect);
|
|
mpDevice->onSize(rect.Width(), rect.Height());
|
|
//a simple view
|
|
mpView = mpFactory->createView();
|
|
RXASSERT(mpView);
|
|
if (bCreateModel)
|
|
{
|
|
RXASSERT(mpModel==NULL);
|
|
//a model with open/close protocol
|
|
#if (ADS >= 20)
|
|
mpModel = mpManager->createAutoCADModel(*mpFactory);
|
|
#else
|
|
mpModel = mpManager->createAutoCADModel();
|
|
#endif
|
|
RXASSERT(mpModel);
|
|
mbModelCreated = true;
|
|
}
|
|
//another model without open/close for the orbit gadget
|
|
mpGhostModel = mpFactory->createModel(AcGsModel::kDirect,0,0,0);
|
|
if(mOrbitFlag) {
|
|
/*
|
|
mpView->add(&mOrbitGadget,mpGhostModel);
|
|
mOrbitGadget.setGsView(mpView);
|
|
*/
|
|
}
|
|
mpDevice->add(mpView);
|
|
mpView->setView(AcGePoint3d(0.0, 0.0, 1.0),
|
|
AcGePoint3d(0.0, 0.0, 0.0),
|
|
AcGeVector3d(0.0, 1.0, 0.0),
|
|
1.0, 1.0);
|
|
}
|
|
}
|
|
|
|
|
|
void CGsPreviewCtrl::OnSize(UINT nType, int cx, int cy)
|
|
{
|
|
CRect rect;
|
|
if (mpDevice) {
|
|
GetClientRect( &rect);
|
|
mpDevice->onSize(rect.Width(), rect.Height());
|
|
}
|
|
}
|
|
|
|
BOOL CGsPreviewCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
|
|
{
|
|
if(!(mOrbitFlag&OBF_ZOOM))
|
|
return CStatic::OnMouseWheel(nFlags, zDelta, pt);
|
|
if (mpView) {
|
|
|
|
if(mpView->isPerspective()) {
|
|
AcGePoint3d ptTar=mpView->target();
|
|
AcGePoint3d ptCam=mpView->position();
|
|
AcGeVector3d vtView=ptTar-ptCam;
|
|
vtView.normalize();
|
|
double nScale=mDistStep;
|
|
if(zDelta<0)
|
|
nScale=-nScale;
|
|
vtView *= nScale;
|
|
ptCam += vtView;
|
|
ptTar += vtView;
|
|
|
|
mpView->setView(ptCam, ptTar, AcGeVector3d(0,0,1), mpView->fieldWidth(),
|
|
mpView->fieldHeight(), AcGsView::kPerspective);
|
|
//mpView->setTarget(ptTar);
|
|
//mpView->setCamera(ptCam);
|
|
} else {
|
|
if (zDelta<0)
|
|
mpView->zoom(0.9);
|
|
else
|
|
mpView->zoom(1.1);
|
|
}
|
|
|
|
|
|
Invalidate();
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void CGsPreviewCtrl::OnLButtonDown(UINT nFlags, CPoint point)
|
|
{
|
|
SetFocus();
|
|
|
|
if(!(mOrbitFlag&OBF_ORBIT)) {
|
|
CStatic::OnLButtonDown(nFlags, point);
|
|
return;
|
|
}
|
|
|
|
//start orbit
|
|
mbOrbiting = true;
|
|
SetCapture();
|
|
//set up the proper cursor
|
|
//::SetClassLong(m_hWnd,GCL_HCURSOR,NULL);
|
|
::SetCursor(mhOrbitCursor);
|
|
//store the start point
|
|
mStartPt = point;
|
|
}
|
|
|
|
void CGsPreviewCtrl::OnLButtonUp(UINT nFlags, CPoint point)
|
|
{
|
|
if(!(mOrbitFlag&OBF_ORBIT)) {
|
|
CStatic::OnLButtonUp(nFlags, point);
|
|
return;
|
|
}
|
|
|
|
//end orbit
|
|
mbOrbiting = false;
|
|
//::SetClassLong(m_hWnd,GCL_HCURSOR,(long)mhCrossCursor);
|
|
::SetCursor(mhCrossCursor);
|
|
ReleaseCapture();
|
|
}
|
|
|
|
void CGsPreviewCtrl::OnMButtonDown(UINT nFlags, CPoint point)
|
|
{
|
|
if(!(mOrbitFlag&OBF_PAN)) {
|
|
CStatic::OnMButtonDown(nFlags, point);
|
|
return;
|
|
}
|
|
|
|
//start pan
|
|
mbPanning = true;
|
|
SetCapture();
|
|
//set up the proper cursor
|
|
//::SetClassLong(m_hWnd,GCL_HCURSOR,NULL);
|
|
::SetCursor(mhPanCursor);
|
|
//store the start point
|
|
mStartPt = point;
|
|
|
|
|
|
}
|
|
|
|
void CGsPreviewCtrl::OnMButtonUp(UINT nFlags, CPoint point)
|
|
{
|
|
if(!(mOrbitFlag&OBF_PAN)) {
|
|
CStatic::OnMButtonUp(nFlags, point);
|
|
return;
|
|
}
|
|
|
|
//end pan
|
|
ReleaseCapture();
|
|
mbPanning = false;
|
|
//::SetClassLong(m_hWnd,GCL_HCURSOR,(long)mhCrossCursor);
|
|
::SetCursor(mhCrossCursor);
|
|
}
|
|
void CGsPreviewCtrl::Invalidate(BOOL bErase)
|
|
{
|
|
if(g_nAcadVer<17.05)//2008以下
|
|
CStatic::Invalidate(bErase);
|
|
else
|
|
{
|
|
CWnd*pParent=GetParent();
|
|
if(pParent!=NULL)//2008+vista发现刷新问题,暂用此方法解决
|
|
{
|
|
CRect rect;
|
|
GetWindowRect(rect);
|
|
pParent->ScreenToClient(rect);
|
|
pParent->InvalidateRect(rect,bErase);
|
|
}
|
|
else
|
|
CStatic::Invalidate(bErase);
|
|
}
|
|
}
|
|
void CGsPreviewCtrl::OnMouseMove(UINT nFlags, CPoint point)
|
|
{
|
|
if (mpView && mbPanning && (mOrbitFlag&OBF_PAN) ) {
|
|
//transform the point from device coordinates to
|
|
//world coordinates
|
|
AcGeVector3d pan_vec(-(point.x-mStartPt.x),point.y-mStartPt.y,0);
|
|
pan_vec.transformBy(mpView->viewingMatrix() * mpView->worldToDeviceMatrix().inverse());
|
|
mpView->dolly(pan_vec);
|
|
Invalidate();
|
|
mStartPt = point;
|
|
} else if (mpView && mbOrbiting && (mOrbitFlag&OBF_ORBIT)) {
|
|
AcGeVector3d vtMov(mStartPt.x-point.x, point.y-mStartPt.y, 0.0);
|
|
//AcGeVector3d vtOff(point.x-m_ptLast.x, point.y-m_ptLast.y, 0.0);
|
|
//if(max(fabs(vtOff[0]), fabs(vtOff[1]))<10)
|
|
// return;
|
|
AcGePoint3d ptCam=mpView->position();
|
|
AcGePoint3d ptTar=mpView->target();
|
|
AcGeVector3d vtUp=mpView->upVector();
|
|
vtUp=AcGeVector3d(0,0,1);
|
|
CRect rect;
|
|
GetClientRect(rect);
|
|
|
|
//Modify bu xlc on 111222 Y向反向,解决预览图里拖动方向与实际方向相反的问题
|
|
//double nRotX = -vtMov.y/rect.Height()*PI/2;
|
|
//double nRotY = -vtMov.x/rect.Width()*PI/2;
|
|
double nRotX = vtMov.y/rect.Height()*PI/2;
|
|
double nRotY = vtMov.x/rect.Width()*PI/2;
|
|
|
|
AcGeVector3d vtZ=ptCam-ptTar;
|
|
AcGePlane plan(ptCam, vtZ);
|
|
AcGePoint3d ptUp=ptCam + vtUp*10000.0;
|
|
AcGePoint3d ptUp1=ptUp.orthoProject(plan);
|
|
if(ptCam.distanceTo(ptUp1)<0.1)
|
|
return;
|
|
AcGeVector3d vtY=ptUp1-ptCam;
|
|
|
|
//Modify bu xlc on 111222 Y向反向,解决预览图里拖动方向与实际方向相反的问题
|
|
vtY.negate();
|
|
|
|
AcGeVector3d vtX=vtY.crossProduct(vtZ);
|
|
vtX.normalize();
|
|
vtY.normalize();
|
|
vtZ.normalize();
|
|
|
|
AcGeVector3d vtView=ptTar-ptCam;
|
|
//if(fabs(vtMov.y)>fabs(vtMov.x)) {
|
|
//m_vtUp.rotateBy(nRotX, vtX);
|
|
vtView.rotateBy(nRotX, vtX);
|
|
//} else {
|
|
vtY.rotateBy(nRotX, vtX);
|
|
//m_vtUp.rotateBy(nRotY, vtY);
|
|
vtView.rotateBy(nRotY, vtY);
|
|
//}
|
|
ptTar = ptCam + vtView;
|
|
mpView->setView(ptCam, ptTar, vtUp, mpView->fieldWidth(), mpView->fieldHeight(),
|
|
mpView->isPerspective()? AcGsView::kPerspective : AcGsView::kParallel);
|
|
|
|
Invalidate();
|
|
//m_ptLast = point;
|
|
mStartPt=point;
|
|
|
|
/* 原来的代码
|
|
const double Half_Pi = 1.570796326795;
|
|
|
|
AcGsDCRect view_rect;
|
|
mpView->getViewport (view_rect);
|
|
|
|
int nViewportX = (view_rect.m_max.x - view_rect.m_min.x) + 1;
|
|
int nViewportY = (view_rect.m_max.y - view_rect.m_min.y) + 1;
|
|
|
|
int centerX = AS_INT(nViewportX / 2.0f + view_rect.m_min.x);
|
|
int centerY = AS_INT(nViewportY / 2.0f + view_rect.m_min.y);
|
|
|
|
const double radius = min (nViewportX, nViewportY) * 0.4f;
|
|
|
|
// compute two vectors from last and new cursor positions:
|
|
|
|
AcGeVector3d last_vector ((mStartPt.x - centerX) / radius,
|
|
-(mStartPt.y - centerY) / radius,
|
|
0.0);
|
|
|
|
if (last_vector.lengthSqrd () > 1.0) // outside the radius
|
|
last_vector.normalize ();
|
|
else
|
|
last_vector.z = sqrt (1.0 - last_vector.x * last_vector.x - last_vector.y * last_vector.y);
|
|
|
|
AcGeVector3d new_vector((point.x - centerX) / radius,
|
|
-(point.y - centerY) / radius,
|
|
0.0);
|
|
|
|
if (new_vector.lengthSqrd () > 1.0) // outside the radius
|
|
new_vector.normalize ();
|
|
else
|
|
new_vector.z = sqrt (1.0 - new_vector.x * new_vector.x - new_vector.y * new_vector.y);
|
|
|
|
// determine angles for proper sequence of camera manipulations:
|
|
|
|
AcGeVector3d rotation_vector (last_vector);
|
|
rotation_vector = rotation_vector.crossProduct (new_vector); // rotation_vector = last_vector x new_vector
|
|
|
|
AcGeVector3d work_vector (rotation_vector);
|
|
work_vector.z = 0.0f; // projection of rotation_vector onto xy plane
|
|
|
|
double roll_angle = atan2 (work_vector.x,
|
|
work_vector.y); // assuming that the camera's up vector is "up",
|
|
// this computes the angle between the up vector
|
|
// and the work vector, which is the roll required
|
|
// to make the up vector coincident with the rotation_vector
|
|
|
|
double length = rotation_vector.length ();
|
|
double orbit_y_angle = (length != 0.0) ? acos (rotation_vector.z / length) + Half_Pi : Half_Pi; // represents inverse cosine of the dot product of the
|
|
if (length > 1.0f) // rotation_vector and the up_vector divided by the
|
|
length = 1.0f; // magnitude of both vectors. We add pi/2 because we
|
|
// are making the up-vector parallel to the the rotation
|
|
double rotation_angle = asin (length); // vector ... up-vector is perpin. to the eye-vector.
|
|
|
|
// perform view manipulations
|
|
|
|
mpView->roll( roll_angle); // 1: roll camera to make up vector coincident with rotation vector
|
|
mpView->orbit( 0.0f, orbit_y_angle); // 2: orbit along y to make up vector parallel with rotation vector
|
|
mpView->orbit( rotation_angle, 0.0f); // 3: orbit along x by rotation angle
|
|
mpView->orbit( 0.0f, -orbit_y_angle); // 4: orbit along y by the negation of 2
|
|
mpView->roll(-roll_angle); // 5: roll camera by the negation of 1
|
|
Invalidate();
|
|
mStartPt = point;
|
|
*/
|
|
} else {
|
|
CStatic::OnMouseMove(nFlags, point);
|
|
}
|
|
|
|
}
|
|
|
|
#if ADS<17
|
|
UINT CGsPreviewCtrl::OnNcHitTest(CPoint point)
|
|
#else
|
|
LRESULT CGsPreviewCtrl::OnNcHitTest(CPoint point)
|
|
#endif
|
|
{
|
|
return HTCLIENT;
|
|
}
|
|
|
|
|
|
void CGsPreviewCtrl::OnSetFocus(CWnd* pOldWnd)
|
|
{
|
|
if(mOrbitFlag && mhCrossCursor) {
|
|
//::SetClassLong(m_hWnd,GCL_HCURSOR,(long)mhCrossCursor);
|
|
::SetCursor(mhCrossCursor);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void CGsPreviewCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
|
|
{
|
|
BOOL bShift = IsKeyPressed(VK_SHIFT);
|
|
BOOL bCtrl = IsKeyPressed(VK_CONTROL);
|
|
|
|
XPoint ptCam=mpView->position();
|
|
XPoint ptTar=mpView->target();
|
|
XVector3D vtView=ptTar-ptCam;
|
|
vtView.Normalize();
|
|
XVector3D vtUp(0,0,1);
|
|
if(nChar==VK_LEFT || nChar==VK_RIGHT) {
|
|
double nFactor=1.0;
|
|
if(nChar==VK_RIGHT)
|
|
nFactor=-1.0;
|
|
if(!bShift && !bCtrl){ //左右移
|
|
double nStepLen=mDistStep*nRepCnt;
|
|
double longitude=GetLongitude(ptCam, ptTar);
|
|
ads_matrix mat;
|
|
XPoint().GetMoveMatrix(XPoint(nStepLen*cos(longitude + PI/2.0*nFactor),
|
|
nStepLen*sin(longitude + PI/2.0*nFactor)), mat);
|
|
ptCam.TransformBy(mat);
|
|
ptTar.TransformBy(mat);
|
|
} else if(bCtrl){ //左右转 PI/2
|
|
double val=GetLongitude(ptCam, ptTar) + PI / 2.0 * nFactor;
|
|
double nElev=ptTar.z;
|
|
ads_polar(ptCam, val, ptCam.Distance2d(ptTar), ptTar);
|
|
ptTar.z=nElev;
|
|
} else if(bShift) { //左右转
|
|
double val = GetLongitude(ptCam, ptTar) + mAngStep*nRepCnt*nFactor;
|
|
double nElev=ptTar.z;
|
|
ads_polar(ptCam, val, ptCam.Distance2d(ptTar), ptTar);
|
|
ptTar.z=nElev;
|
|
}
|
|
} else if(nChar==VK_UP || nChar==VK_DOWN) {
|
|
double nFactor=1.0;
|
|
if(nChar==VK_DOWN)
|
|
nFactor=-1.0;
|
|
if(!bShift && !bCtrl){ //前进或后退
|
|
ads_matrix mat;
|
|
double nStepLen=mDistStep*nRepCnt*nFactor;
|
|
double longitude = GetLongitude(ptCam, ptTar);
|
|
XPoint().GetMoveMatrix(XPoint(nStepLen*cos(longitude), nStepLen*sin(longitude)), mat);
|
|
ptCam.TransformBy(mat);
|
|
ptTar.TransformBy(mat);
|
|
} else if(bCtrl){ //上下移动
|
|
ptCam.z += mDistStep*nRepCnt*nFactor;
|
|
ptTar.z += mDistStep*nRepCnt*nFactor;
|
|
} else if(bShift) { //上下转动
|
|
double val = GetLatitude(ptCam, ptTar) + mAngStep*nRepCnt*nFactor;
|
|
double nElevDiff=ptCam.Distance2d(ptTar)*tan(val);
|
|
ptTar.z = ptCam.z + nElevDiff;
|
|
}
|
|
} else {
|
|
CStatic::OnKeyDown(nChar, nRepCnt, nFlags);
|
|
return;
|
|
}
|
|
mpView->setView(ptCam, ptTar, vtUp, mpView->fieldWidth(), mpView->fieldHeight(),
|
|
mpView->isPerspective()? AcGsView::kPerspective : AcGsView::kParallel);
|
|
Invalidate();
|
|
}
|
|
|
|
|
|
|
|
BOOL CGsPreviewCtrl::PreTranslateMessage(MSG* pMsg)
|
|
{
|
|
// TODO: Add your specialized code here and/or call the base class
|
|
if(pMsg->message==WM_KEYDOWN) {
|
|
int vk=pMsg->wParam;
|
|
if(vk==VK_LEFT || vk==VK_RIGHT || vk==VK_DOWN || vk==VK_UP) {
|
|
int nRepCnt=LOWORD(pMsg->lParam);
|
|
OnKeyDown(vk, nRepCnt, 0);
|
|
return TRUE;
|
|
}
|
|
}
|
|
return CStatic::PreTranslateMessage(pMsg);
|
|
}
|
|
|