Log On
Embarcadero Home
Watch, Follow, &
Connect with Us
Share This
QualityCentral
Communities
Articles
Blogs
Resources
Downloads
Help
QualityCentral
3rdRail
Blackfish SQL
C#Builder
C++BuilderX
CodeCentral
Conference
DBArtisan
Delphi for PHP
Delphi Prism
Delphi-BCB
EDN
InterBase
JBuilder
JBuilder 2007
Kylix
Optimizeit
QualityCentral
Test project
You are not logged in.
Help
Print
Public Report
Report From:
[ Add a report in this area ]
Report #:
60698
Status:
Closed
Get/SetWindowLong prototypes bugged; they don't take LONG_PTRs
Project:
Build #:
11.0.2902.10471
Version:
11.2
Submitted By:
Jordan Russell
Report Type:
Basic functionality failure
Date Reported:
4/9/2008 3:24:44 PM
Severity:
Serious / Highly visible problem
Last Updated:
3/20/2012 2:24:39 AM
Platform:
All versions
Internal Tracking #:
259068
Resolution:
Deferred to Next Rel
(Resolution Comments)
Resolved in Build:
:
Duplicate of:
None
Voting and Rating
Overall Rating:
No Ratings Yet
0.00 out of 5
Total Votes:
None
Description
In Delphi.NET 2007's Windows unit, GetWindowLong and SetWindowLong were changed to take/return LONG_PTRs in an attempt to give them support for 64-bit values on 64-bit Windows.
This, however, wasn't the correct approach at all.
In 64-bit Windows, Microsoft actually did not make any alterations to the prototypes of GetWindowLong and SetWindowLong. They still take/return 32-bit LONGs (Longints) exactly as on 32-bit Windows. (Refer to WinUser.h and the Platform SDK docs.)
Rather than update the existing functions, Microsoft instead opted to introduce two new functions -- GetWindowLongPtr and SetWindowLongPtr -- that applications are to use when 64 bits are required.
It is these functions that Delphi.NET should be calling on 64-bit Windows.
Presently, by trying to pass 64-bit arguments (LONG_PTRs) to functions designed to accept only 32-bit arguments (LONGs), and by treating 32-bit results as if they were 64-bit results, it is relying on implementation details on the Windows side which could change at any moment.
For example: In the case of GetWindowLong, by declaring the result type as a LONG_PTR (64-bit), the assumption is being made that the function correctly initializes all 64 bits of RAX. Since GetWindowLong actually returns a LONG (32-bit), Windows could legally set only the lower 32 bits of RAX, leaving the upper 32 bits zero or garbage.
====== FIX ======
To eliminate this problem, while still retaining compatibility with existing code, GetWindowLong* and SetWindowLong* should be replaced with wrapper functions that call the proper Ptr versions when running on 64-bit Windows. (This is exactly what Microsoft has done in Windows Forms.)
The code is too long to paste here, so I've attached it. See WindowLongFix.pas.
Steps to Reproduce:
At very least, this breaks SetWindowLongA and SetWindowLongW, causing them to clip their arguments to 32 bits. (*All* of the Get/SetWindowLong prototypes are incorrect, though.)
Steps to reproduce (on Windows XP x64 Edition SP2):
1. Create a new Delphi.NET VCL Forms Application.
2. Go to Project Options, Compiler, and set Target Platform to "x64".
3. Drop a TMemo on the form, and set its Align property to alClient.
4. Create an OnCreate handler on the form, and paste the following code:
procedure TForm1.FormCreate(Sender: TObject);
const
NewValue = $1122334455667788;
var
ActualValue: LONG_PTR;
begin
Assert(IntPtr.Size = 8); // This test must be run on a 64-bit build!
SetWindowLong(Handle, GWL_USERDATA, NewValue);
ActualValue := GetWindowLong(Handle, GWL_USERDATA);
Memo1.Lines.Add(Format('SetWindowLong($%.16x) -- GetWindowLong() = $%.16x',
[NewValue, ActualValue]));
SetWindowLongA(Handle, GWL_USERDATA, NewValue);
ActualValue := GetWindowLongA(Handle, GWL_USERDATA);
Memo1.Lines.Add(Format('SetWindowLongA($%.16x) -- GetWindowLongA() = $%.16x',
[NewValue, ActualValue]));
SetWindowLongW(Handle, GWL_USERDATA, NewValue);
ActualValue := GetWindowLongW(Handle, GWL_USERDATA);
Memo1.Lines.Add(Format('SetWindowLongW($%.16x) -- GetWindowLongW() = $%.16x',
[NewValue, ActualValue]));
end;
Actual results:
SetWindowLong($1122334455667788) -- GetWindowLong() = $1122334455667788
SetWindowLongA($1122334455667788) -- GetWindowLongA() = $0000000055667788 <-- upper 32 bits were zeroed!
SetWindowLongW($1122334455667788) -- GetWindowLongW() = $0000000055667788 <-- upper 32 bits were zeroed!
Expected results:
SetWindowLong($1122334455667788) -- GetWindowLong() = $1122334455667788
SetWindowLongA($1122334455667788) -- GetWindowLongA() = $1122334455667788
SetWindowLongW($1122334455667788) -- GetWindowLongW() = $1122334455667788
(The Get/SetWindowLong versions in WindowLongFix.pas (see attachment) produce the expected results.)
Workarounds
None
Attachment
WindowLongFix.zip
Comments
None
View Your Reports
Search
Server Response from: ETNACODE01
Developer Tools
Blackfish SQL
C++Builder
Delphi
FireMonkey
Prism
InterBase
JBuilder
J Optimizer
HTML5 Builder
3rdRail & TurboRuby
Database Tools
Change Manager
DBArtisan
DB Optimizer
ER/Studio
Performance Center
Rapid SQL
Technical Articles
Tutorials
White Papers
Press Releases
Newsletters
Add Content (GetPublished)
Audio
Audio & Video
Video
Bugs & Suggestions (QualityCentral)
Discussion Forums
Examples (CodeCentral)
Tags
Technology Partners
Downloads
Free Trials
Registered User Downloads
Beta Programs
Add Content (GetPublished)
Articles
Blogs
Bugs & Suggestions (QualityCentral)
Discussion Forums
Examples (CodeCentral)
Member Services
About
Connect with Us