Re: Fixing incorrect clip box on multi-monitor machines
I'm using Visual Studio 6.0 (newest SP) on XP SP2.
You seem to be right: Both MFC and direct API calls show the same behaviour.
But it's not quite as simple as that - I've tried a few more things, and the
results confuse me quite a little:
TextOut called directly within the OnPaint event handler will render to the
3rd monitor (both the MFC and API variant). LineTo and DrawClipRect will not
do so.
When calling a function from OnPaint (handing over the dc), even TextOut
will no longer render to the 3rd monitor.
When I restrict my form to use only the middle and right monitors, I can
suddenly draw on the rightmost monitor (but of course, then I can't draw on
the lestmost monitor).
I also have no problems drawing on my leftmost (=negative coordinate)
monitor. I seem to run into trouble only when my client coordinates exceed
the maximum screen coordinate. However, within other applications this seems
to work, so I don't really suspect the graphics drivers.
BTW it's a single graphics card which can manager up to four display
monitors. Each monitor is seen by Windows as a single display (when you go
to display properties / settings).
The application I have is already very trivial. At times it basically only
had an OnPaint handler with the lines and TextOut drawn (and the latter one
only for test purposes).
I can post the current code here...(warning: I haven't worked with C / C++ /
MFC for years, the code might look a bit awkward...)
// clsBackgroundForm.cpp : implementation file
//
#include "stdafx.h"
#include "winuser.h"
#include "WR_MFC_Functions.h"
#include "clsBackgroundForm.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
////////////////////////////////////////////////////////////////////////////
/
// clsBackgroundForm dialog
clsBackgroundForm::clsBackgroundForm(CWnd* pParent /*=NULL*/)
: CDialog(clsBackgroundForm::IDD, pParent)
{
//{{AFX_DATA_INIT(clsBackgroundForm)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
}
void clsBackgroundForm::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(clsBackgroundForm)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(clsBackgroundForm, CDialog)
//{{AFX_MSG_MAP(clsBackgroundForm)
ON_WM_RBUTTONUP()
ON_WM_PAINT()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
////////////////////////////////////////////////////////////////////////////
/
// clsBackgroundForm message handlers
HDC hMemDC;
HBITMAP hBmp;
HBITMAP hOldBmp;
int x,y,w,h;
int isButtonDown;
CPoint ptStart, ptEnd, ptPrevEnd, ptPrevStart;
CPen myPen;
int isLassoDrawn;
int forceFullRedraw;
void clsBackgroundForm::PaintLines(CPaintDC* dc, CPoint ptFrom, CPoint ptTo)
{
CRect r;
if (ptStart == ptTo)
{
return;
}
dc->SelectObject(myPen);
int hOldRasterMode = dc->SetROP2(R2_NOT);
// Only test
dc->TextOut(2500, 72, "Hello MFC!");
::TextOut(*dc,2500,372,"Hello API!",10);
dc->MoveTo(ptStart.x,ptStart.y);
dc->LineTo(ptTo.x,ptStart.y);
dc->LineTo(ptTo.x,ptTo.y);
dc->LineTo(ptStart.x,ptTo.y);
dc->LineTo(ptStart.x,ptStart.y);
isLassoDrawn = !isLassoDrawn;
}
void clsBackgroundForm::OnRButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CDialog::EndDialog(0);
CDialog::OnRButtonUp(nFlags, point);
}
BOOL clsBackgroundForm::OnInitDialog()
{
CDialog::OnInitDialog();
HDC hScreenDC = ::GetDC(NULL);
x = GetSystemMetrics(SM_XVIRTUALSCREEN);
y = GetSystemMetrics(SM_YVIRTUALSCREEN);
w = GetSystemMetrics(SM_CXVIRTUALSCREEN);
h = GetSystemMetrics(SM_CYVIRTUALSCREEN);
/*
// When I do this, I can draw on the rightmost monitor, but no longer on
the leftmost
x = 0;
w = 2560;
*/
CDialog::MoveWindow(x,y,w,h);
myPen.CreatePen(PS_SOLID | PS_GEOMETRIC,1,RGB(255,0,0));
hMemDC = CreateCompatibleDC(hScreenDC);
hBmp = CreateCompatibleBitmap(hScreenDC,w,h);
static_cast<HBITMAP>(SelectObject(hMemDC,hBmp));
// Capture the screen
BitBlt(hMemDC,0,0,w,h,hScreenDC,x,y,SRCCOPY);
::ReleaseDC(NULL,hScreenDC);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
void clsBackgroundForm::OnPaint()
{
CRect r,rPrev;
CRgn rgn;
CPaintDC dc(this); // device context for painting
if ((forceFullRedraw) || (!isButtonDown))
{
// Paste my screen capture on my window
StretchBlt(dc,0,0,w,h,hMemDC,0,0,w,h,SRCCOPY);
isLassoDrawn=0;
}
// Only test
dc.TextOut(2500, 572, "Hello MFC!");
::TextOut(dc,2500,772,"Hello API!",10);
if (isLassoDrawn)
{
PaintLines(&dc, ptPrevStart, ptPrevEnd);
}
ptPrevEnd = ptEnd;
ptPrevStart = ptStart;
PaintLines(&dc, ptStart, ptEnd);
forceFullRedraw=0;
}
BOOL clsBackgroundForm::DestroyWindow()
{
myPen.DeleteObject();
DeleteObject(SelectObject(hMemDC,hOldBmp));
DeleteDC(hMemDC);
return CDialog::DestroyWindow();
}
void clsBackgroundForm::OnLButtonDown(UINT nFlags, CPoint point)
{
CRect r;
GetWindowRect(&r);
InvalidateRect(&r,0);
ptStart = point;
ptEnd = ptStart;
isButtonDown=1;
forceFullRedraw=1;
CDialog::OnLButtonDown(nFlags, point);
}
void clsBackgroundForm::OnLButtonUp(UINT nFlags, CPoint point)
{
ptEnd = point;
isButtonDown=0;
ptStart.x += x;
ptStart.y += y;
ptEnd.x += x;
ptEnd.y += y;
CDialog::OnLButtonUp(nFlags, point);
m_strRange.Format ("%d;%d;%d;%d",ptStart.x, ptStart.y, ptEnd.x, ptEnd.y);
}
void clsBackgroundForm::OnMouseMove(UINT nFlags, CPoint point)
{
if (isButtonDown)
{
ptEnd = point;
CRect r;
GetWindowRect(&r);
InvalidateRect(&r,0);
}
CDialog::OnMouseMove(nFlags, point);
}
"Joseph M. Newcomer" <newcomer@flounder.com> wrote in message
news:kt1vc2p07erjjdcio9av6hgtoufeohhio1@4ax.com...
Which version of MFC are you using? And what platform are you using,
e.g., are you using
XP SP2, Server 2003, or something else?
Note that this is most likely *not* MFC that is doing it, because MFC
doesn't create the
clip box; this comes from the operating system. Have you tried creating a
trivial example
application that demonstrates this?
Just an observation that I've successfully used these techniques to draw
on my left-hand
monitor, which has negative coordinates. This sounds like it could also be
a bug in the
device driver for your display screens; you might want to report this to
the vendor of
your video card(s). Also, make sure you have the latest drivers. If you
have a single
card that does all three monitors, it is a different question than if you
have two cards
from either the same or two different vendors. It could be drivers Not
Playing Well With
Others.
joe
On Tue, 1 Aug 2006 17:04:22 +0200, "Robert" <noone@nowhere.com> wrote:
Hello all,
I have a CDialog, which I set to span the whole virtual screen. The
machine
has 3 monitors with 1280x1024 each, and the virtual screen ranges from
(-1280 / 0) to (2560 / 1024) (yes, the first monitor has negative
X-coordinates).
The MFC drawing routines don't seem to like that. I was absolutely unable
to
draw anything on the third (=rightmost) monitor (TextOut, LineTo).
So I took a look at the ClipBox within OnPaint, and sure enought, it said
(0/0) - (2560/1024), where it SHOULD've read (0/0) - (3840/1024), because
that's the size of my window. (Interestingly, 2560 is the maximum
X-Coordinate in screen coordinates, but NOT in client coordinates!).
Then I tried overriding the clipping region using CreateRectRgn and
SelectClipRgn, but MFC either ignores the call, or overrides the values I
set.
What can I do? Any ideas?
Thanks for any input!
Robert
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm