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");
| Вернуться в корень Архива |