Has SetWindowPos behaviour changed between VC2.2 and VC4.0?
johnr@virtuality.com
Thursday, January 18, 1996
I am porting an application from VC2.2 to VC4.0 and have a problem. I
have written "tooltrays", i.e. subsidiary toolbars which drop down
when a button in a main toolbar is clicked (similar to the way in
which menus drop down when the main menubar is clicked). They worked
great with VC2.2, but with VC4.0 they appear in the wrong place. It
would appear that the function SetWindowPos, which used to take
co-ordinates relative to the screen, now takes co-ordinates relative
to the main window of the application. It seems incredible that
Microsoft would change this so that our applications would still
compile perfectly but no longer work! Any answers?
John Rowland
Virtuality Limited
Brad Wilson -- bradw@netnet.net
Friday, January 19, 1996
[Mini-digest: 6 responses, including one doozy!]
>> It
>> would appear that the function SetWindowPos, which used to take
>> co-ordinates relative to the screen, now takes co-ordinates relative
>> to the main window of the application.
SetWindowPos() has always taken coordinates relative to the parent
window. To move a main window, SetWindowPos() would take coordinates
relative to the screen; to move a child window, SetWindowPos() would
take coordinates relative to (0,0) in the parent's client area.
The Remarks section from the SetWindowPos() function states: "All
coordinates for child windows are client coordinates (relative to
the upper-left corner of the parent window's client area)".
That's always the way it worked for me ...
Brad
--
class CBradWilson : public CWorldWatchProgrammingTeam {
public:
void GetInetAddr ( CString& s ) { s = "bradw@exptech.com"; }
void GetInetURL ( CString& s ) { s = "http://www.exptech.com"; }
void GetE164Addr ( CString& s ) { s = "+1 (810) 620-9803"; }
void GetDisclaimer( CString& s ) { s = "All I say is fact :-p"; }
};
// QOTW: "In the world of the blind, the one eyed man is king."
-----From: "David W. Gillett"
I can't believe that this is where the problem really is.
SetWindowPos should always have taken coordinates relative to the
parent of the window being positioned -- the screen only if this is a
top-level window.
The Win32 "4.0" API involves some modified semantics for
GetSystemMetrics, however, and it may be that your calculation of the
position of the window is relying on the old semantics. Marking your
app "subsystem 4.0" tells Windows that you want the new semantics,
and have coded accordingly -- if you haven't, you may see odd
results, including calculated window positions that aren't quite
where you expected them to be.
Dave
-----From: "Rick Esterling"
In the help file under SetWindowPos() you'll find:
All coordinates for child windows are client coordinates (relative to the
upper-left corner of the parent window's client area).
This has been the case for as long as I can remember.
Sorry I can't help you with the problem you're having, but it hasn't been
caused by a difference in the way SetWindowPos works. Perhaps your
toolbar button has a difference parent now than it used to and that's what
is throwing the calculation off?
Good luck,
-------------------------------------------------------------
Rick Esterling The Wollongong Group, Inc.
Senior Software Engineer McLean, VA
http://widget.eco.twg.com:1080 http://www.twg.com
-----From: "Mike Blaszczak"
Here's a level-headed reply:
The position parameters you pass to SetWindowPos() are relative to the screen
if the window being moved is a top-level window, while they're relative to
the parent if the window being moved is a child window. It sounds like in one
version of your code, the window is (or isn't) a parent, while in the other
version of the code, the window isn't (or is) a parent.
.B ekiM
-----From: Marty Fried
I haven't noticed a change from any version since 1, and I'm pretty sure I
use the function. In reading the online docs, I see that child windows use
their parent's client area coordinates, and others use screen coordinates;
or perhaps it's the desktop window's client coordinates. Anyway, I'm not
sure, but the tooltray may be a child of the toolbar.
If something seems too incredible to believe, don't assume it's true.
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Marty Fried (mfried@linex.com)
Marin County, California
-----From: "Mike Blaszczak"
I'm going to go a little postal in this reply, so watch the heck out.
> which menus drop down when the man menubar is clicked). They worked
> great with VC2.2, but with VC4.0 they appear in the wrong place.
It sounds like you have a bug in your code.
> It would appear
Not everything is as it appears. Have you ever seen the sun come up in the
morning? It turns out that the sun _isn't_ coming up; it's actually standing
still, and it's the _Earth_ that is rotating which causes this illusion.
Believe it or not, there was a time when you'd be thrown out of The Church for
entertaining such conjecture!
> that the function SetWindowPos, which used to take
> co-ordinates relative to the screen, now takes co-ordinates relative
> to the main window of the application.
It's hard to tell if you're talking about the Windows API ::SetWindowPos() or
the MFC function CWnd::SetWindowPos().
If you're talking about the API, you should realize that the vesion of VC++
you're using has _nothing_ to do with the way the API works. APIs are
implemented by Windows, not by the development platform. The code that really
_is_ ::SetWindowPos() lives in some system file in your WINDOWS\SYSTEM
directory. The only possible way for that code to change is for you to run
off and install a new version of Windows. Since you say that you're using
VC++ 2.2 and VC++ 4.0, I don't think you're using a new version of
Windows--though maybe you're comparing results of running under Win95 to
running under Windows NT.
At any rate, either version of Windows takes coordinates that are relative to
the parent window if the window being moved is a child window. If the window
being moved is a top-level window, the coordinates are relative to the screen
origin. This is a well-documented fact. If you'd bother to look at the
documentation, you can figure these kind of things out. If you _don't_ read
the documentation, you'll be likely to grasp for an excuse like "Microsoft
must have changed the API!" It seems you'd be unlikely to do any reasoning:
"Jeez, if Microsoft changed the way a fundamental API like ::SetWindowPos()
worked between Windows Version This and Windows Version That, then _no_
application would be able to call ::SetWindowPos() without knowing what
version of Windows it was using. That just seems unreasonable, so maybe the
problem is really mine."
If you're talking about the MFC implemnetation of CWnd::SetWindowPos(), your
question seems a little silly because you could have looked at the actual
implementation of the function before posting your question. Since you didn't
do it for some reason, I'll assume you can't and do it for you. Here's the MFC
4.0 version of the function. You could have found it yourself by using the
"Find in Files" command in the IDE to search the MFC source code on your VC++
4.0 CD or on your hard drive, if you installed the source code. This code is
around line 289 of WINOCC.CPP:
BOOL CWnd::SetWindowPos(const CWnd* pWndInsertAfter, int x, int y, int cx,
int cy, UINT nFlags)
{
ASSERT(::IsWindow(m_hWnd));
if (m_pCtrlSite == NULL)
return ::SetWindowPos(m_hWnd, pWndInsertAfter->GetSafeHwnd(),
x, y, cx, cy, nFlags);
else
return m_pCtrlSite->SetWindowPos(pWndInsertAfter,
x, y, cx, cy, nFlags);
}
(I've reformatted the code so it looks nice in mail.)
As you can see, the code ASSERTs that the window referenced by this CWnd
object actually exists. Then, it checks to see if the window is managing an
OLE Control-- if it isn't, it simply falls through to a call to the Windows
::SetWindowPos() API. It doesn't dink with the parameters, or call any APIs
which would explain the behaviour you've said you're seeing.
For comparison, here's the MFC 2.2 version of the function. You could have
found it yourself by using the "Find in Files" command in the IDE to search
the MFC source code on your VC++ 2.2 CD or on your hard drive, if you bothered
to install the source code. This code is around line 72 of the file
AFXWIN2.INL:
_AFXWIN_INLINE BOOL CWnd::SetWindowPos(const CWnd* pWndInsertAfter,
int x, int y, int cx, int cy, UINT nFlags)
{ ASSERT(::IsWindow(m_hWnd));
return ::SetWindowPos(m_hWnd, pWndInsertAfter->GetSafeHwnd(),
x, y, cx, cy, nFlags); }
(I've reformatted the code so it looks nice in mail.)
As you can see, MFC 2.2 does an assertion to see if the referenced window is
really a window. It then hands the parameters over to the Windows
::SetWindowPos() API. Since MFC 2.2 doesn't support OLE controls like MFC 4.0
does, the check of m_pCtrlSite isn't necessary.
As you can see, with a few minutes of investigation, you could have proven to
yourself that MFC isn't an issue in the problem you think you're experiencing.
And you probably could have spent a few minutes reading documentation to find
out that the API isn't at all a likely candidate for the behaviour you're
observing.
I guess it's also possible that you're talking about the SetWindowPos()
function implemented by the Macintosh Portability Layer, but I can't say much
about that since I've never used it.
So, the answer is that, somehow, the window you're calling SetWindowPos() on
back in your VC++ 2.2 build has the opposite WS_CHILD style bit than the
window you're moving in VC++ 4.0. You can convert from and to screen and
child-window coordinates using well-documneted APIs. Maybe it's possible that
the style bits of the base-class window you're using have changed, or maybe it
turns out that some wiredness between the way the two versions of your program
are compiled causes the styles you're setting or requesting to not be set or
granted, and then that causes the positioning problem you notice. Maybe you
just have a plain old bug; like, maybe you're calling a function like
GetActiveWindow() to figure out which window to move, or which window to make
a parent of your tool window, and that's breaking your code.
Since you didn't read the documentation, I doubt you read this far in my
answer. But, if you care, here's the reason why I went nuts: your conjecture
that this change was even made drips of the "Microsoft is responsible for all
my problems" bunk which sometimes seems to be very prevalent on the 'net.
Microsoft software sometimes has bugs, but 999 times of 1000, in my
experience, it's really the user's problem. (And I'm not saying I'm not a
user--certainly, before QA sees my code, there's lots of peoblems in it.) You
didn't lift a finger to figure out what was going on. Instead, you just came
running to the list to spread your "Microsoft is evil" conjecture.
You know, you can apply lots of rules of science to computers. You can figure
out if variables are chanigng and limit their changes, or observe their
changes experimentally to make guesses. Then, you could do other experiments
to make your guesses a little more sold, or even prove them beyond a shadow of
a doubt.
I'd really like to see more people exercise some scientific method before they
cry wolf. _Especially_ when the wolf they've called ends up chewing on the
reputation of a company or the specific work of other people.
.B ekiM
TCHAR szDisc[] = _T("These words are my own; I do not speak for Microsoft");
| Вернуться в корень Архива
|