15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту


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");






| Вернуться в корень Архива |