Why is it that if I compile an FPC program with range checking turned on, opening any HTML file in ie immediately causes "Error 201" from my FPC program?
---
L D Blake

Mailing lists / fpc-pascal / 2003-08
27 messages · 8 people · –
Reply by email Subscribe to this list Your subscription
Read-only archive. Use j and k to move between messages.
Why is it that if I compile an FPC program with range checking turned on, opening any HTML file in ie immediately causes "Error 201" from my FPC program?
---
L D Blake
L D Blake wroteWhy is it that if I compile an FPC program with range checking turned on, opening any HTML file in ie immediately causes "Error 201" from my FPC program?
Ahem.
A litlle bit more information may be in order here ? What kind of program is this ? What units does it use ? What function does it perform ? Is this a GUI program or a console app ?
Michael.
In reply to your message of August 28, 2003
Okey dokey... I gave quite a bit of information in my other message about these problems... XP1800/win2k/sp4/256mbram/tnt64 video, all stable on other software... so, to add the new info..
It's a Gui app. No OOP, just plain pascal. Basically it's media player with some special functions, such as a text editor for transcribing lyrics. From FPC, it uses only mmsystem and windows, and of course it has it's own private units. I'm compiling with delphi and gui support enabled at the top of each unit and in the main program.
To restate what's going on... If I compile without range checking it will play songs perfectly, and the text editor behaves normally so long as I don't open any other window over it or let it fall into the screen saver. If it goes into the background I sometimes (often, but not every time) lose the title bars from the windows and re-draws occur at random locations on the screen making the program appear to break in to pieces, this happens with any window or dialog the program opens, including those built into windows. If I guess where the buttons should be I can click them, even if I can't see them and the images scattered on the screen have the menu context numbers on them instead of the button text. Sometimes it will also grab bits of other windows and displace them as well. If I compile it with range checking it errors off (code 201 at random addresses) every time I try to open a html file in IE. The IE window will not open until I exit the application. It also errors off unexpectedly (but not very often) giving Error 201 at seemingly random addresses while running in background. All though this, it will continue playing music very nicely...
Also, keep in mind that so long as it's in the foreqround, none of these errors occur. I've tortured it horribly and it runs error free so long as it never gets covered by anything else.
I've been all over my own code with a fine tooth comb. I've tried declaring my variables with win-api names (eg. dword instead of longword) and I've tried using the native pascal type declarations and this seems to have little effect on it. I've tried re-doing the windows dispatcher and the 4 winproc routines (one for each main window) in several different ways, but this does not change the errors. I've also tried commenting out blocks of code to see if the error vanishes along with the function and, unless I render it unworkable, the errors persist.
The FP IDE will not point me to a source code line when the errors occur because, weirdly enough, I don't get the errors in debug mode.
I'm slowly becoming convinced that it's an error someplace in FP, perhaps in the "Windows" unit ... perhaps a type declaration that doesn't match the C equivalent or some other more fundimental problem. I've experimented with lots of differing combinations of compiler switches (in fpc.cfg) and tried several different compiler directives in the source code itself. All to no avail. Depending on the use of range checking, I either get a scrambled display or randomly occuring "Error 201" popups sometimes listing 20 or more errors.
So far, I've been resisting tampering with the FPC distribution, because frankly I would have no idea where to start looking for these kinds of problems in all that source code.
I was a professional programmer some years back, worked with TP extensively and liked it just fine on the DOS platform, but FP and windows has been a real hassle. I've never yet had a problem I can't find and fix... until now.
Needless to say, I'm rather frustrated and very near scrapping FP...
-----
L D Blake
Do you catch the 'focus lost' event ? Do you have any assembler ? Windows expects some registers to be saved.
Are the winproc routines declared as stdcall ?
Did you go over all the WinAPI calls that you use ? I know this is a tedious job, but it is one which needs to be done in such cases. We've had other cases where the declaration was wrong.
So far, I've been resisting tampering with the FPC distribution, because frankly I would have no idea where to start looking for these kinds of problems in all that source code.
The fact that huge projects as Lazarus work fine, make me believe that the error is win32 specific, and this points to the Windows unit or some special routines uses in mmsystem or whatever.
This is understandable. Did you try compiling using Delphi ? If you want, you can send me the sources in private, and I will give it a try with Delphi.
Michael.
In reply to your message of August 29, 2003
Do you catch the 'focus lost' event ? Do you have any assembler ? Windows expects some registers to be saved.
No and no. But come to think of it that's about when the problem is occuring.
Are the winproc routines declared as stdcall ?
Yes.
Did you go over all the WinAPI calls that you use ?
Twice now. But will do it again.
I know this is a tedious job, but it is one which needs to be done in such cases. We've had other cases where the declaration was wrong.
I've followed the SDK very closely, but mistakes do happen...
The fact that huge projects as Lazarus work fine, make me believe that the error is win32 specific, and this points to the Windows unit or some special routines uses in mmsystem or whatever.
Yep, I took a look at the windows unit last night, found the bulk of type declarations were in BASE.INC and noticed, almost right away, that "Handle" a 32 bit unsigned value is declared as a longint. Shouldn't it be a LongWord? A longint has only half as many positive values as a longword and a high-numbered handle could be causing the range checking error.
I also found a lot of places in Base.inc where longint has been substituted for other variable types (byte, word, longword, etc) often complete with the necessary wrangling to get the byte or word back out of the longint inside the procedures. A quick text search found over 1000 lines with references to "longint" in the windows unit, some lines have multiple references ... all of which are now suspect.
I wasn't able to get a test compile out of the unit last night (it bombs out at line 255 of Base.inc, in the "enumeratons" section) and there's no point swimming through all that code until I do.
If anyone knows the correct setup for re-compiling the windows and mmsystem units could you please let me know... Thanks.
-----
L D Blake
It could be the handle which is passed on the lost focus event.
That, in combination with 'focus lost' may be worth looking at?
Yes. I have had to fix them on several occasions myself.
Unfortunately, the Windows unit is very basic. Short of the system unit, almost all other RTL units are based on it. You have no choice but to compile the RTL, using make...
Michael.
In reply to your message of August 29, 2003 No and no. But come to think of it that's…
Yep, I took a look at the windows unit last night, found the bulk of type declarations were in BASE.INC and noticed, almost right away, that
"Handle" a
32 bit unsigned value is declared as a longint. Shouldn't it be a
LongWord? A
longint has only half as many positive values as a longword and a high-numbered handle could be causing the range checking error.
THandle = DWORD = LondWord = Cardinal in 32bit ObjectPascal
Integer is completely wrong.
Matt
In the development branch THandle is a Cardinal. In the stable 1.0.x branch we left it an Longint. In the past there were some issues in the with Cardinal. At that moment it was decided to leave it has been already a longint for 5 years. When it was really a problem then it would have been noticed much earlier.
Peter
Peter, longint is simply wrong. whist is may work in most circumstances, if you are on a system with a lot of handles being allocated, you will get to the realms on 32bit unsigned values. As the normal test for a handle allocation is :
h := AllocateSomeHandle;
if (h > 0) then Success
else Recover;you are simply asking for trouble. A negative handle value is not acceptable. I'm guessing the problems have been got around by the shear luck of a silent cast when passing an longint to a function expecting a longword. However it's possible that L D Blake has stumbled accross somewhere where this is not possible.
It's not actually a Cardinal, it's a DWORD that is the normal Win32 type. DWORD is mapped to LongWord in Delphi and therefore Cardinal.
Matt
I am looking foward into the development of a potentially large project using FPC, but this project will require the development and dynamic linking of shared libraries, when looking the site docs, I saw it was not recommended to make shared libraries with FPC, although the Programmer´s Manual treat the subject as if it was quite straightfoward... so I got pretty confused.... any thoughts?
I will need to both create the libraries and link to them at runtime without knowing them at design time, like the win32 LoadLibrary(filename) function, but I would need a multiplatform solution...
Any ideas would be welcome.
Renato Borges A. Prado
Peter, longint is simply wrong. whist is may work in most circumstances, if you are on a…
Is it? FPC 1.0.x is at D2..D4 level, and some of those versions don't have proper unsigned 32-bit types IIRC.
Moreover, I agree with Peter, HWND's are used really a lot. Inside FPC, ICS, Lazarus etc etc.
It would have been detected.
I am looking foward into the development of a potentially large project using FPC, but…
Shared libraries are currently only support on win32. The Unix shared libraries require Position Independent Code (PIC) support which is not available yet. Before we can start adding PIC support we need to have the new register allocator (currently in development) fully working.
Peter
It could be the handle which is passed on the lost focus event. That, in combination with…
In reply to your message of August 29, 2003
It could be the handle which is passed on the lost focus event.
That's what I'm thinking... a handle passed in LParam, which is defined as a longint in the windows unit and thus in my code, causing a range checking error.
I've been looking further at that unit... So far I've caught about 115 references to longint that should be either Byte, Word or Longword values. I'm still only and I really dread the thought that it might be through all the hundreds of function and record and type declarations in the other files.
For example:
HANDLE = longint; { or should it be cardinal ?? PM }
HACCEL = HANDLE;
HBITMAP = HANDLE;
HBRUSH = HANDLE;
HCOLORSPACE = HANDLE;
HCONV = HANDLE;
HCONVLIST = HANDLE;
HCURSOR = HANDLE;
HDBC = HANDLE;
HDC = HANDLE;
HDDEDATA = HANDLE;
HDESK = HANDLE;
HDROP = HANDLE;
HDWP = HANDLE;
HENHMETAFILE = HANDLE;
HENV = HANDLE;
HFILE = HANDLE;
HFONT = HANDLE;
HGDIOBJ = HANDLE;
HGLOBAL = HANDLE;
HGLRC = HANDLE;
HHOOK = HANDLE;
HICON = HANDLE;
HIMAGELIST = HANDLE;
HINST = HANDLE; { Not HINSTANCE, else it has problems with the var HInstance }
HKEY = CARDINAL;
HKL = HANDLE;
HLOCAL = HANDLE;
HMENU = HANDLE;
HMETAFILE = HANDLE;
HMODULE = HANDLE;
HPALETTE = HANDLE;
HPEN = HANDLE;
HRASCONN = HANDLE;
HRESULT = HANDLE;
HRGN = HANDLE;
HRSRC = HANDLE;
HSTMT = HANDLE;
HSZ = HANDLE;
HWINSTA = HANDLE;
HWND = HANDLE;
HTASK = HANDLE;
LANGID = word;
LCID = DWORD;
LCTYPE = DWORD;
LPARAM = longint;Which occupies lines 85 to 132 of the file. In another file, THandle is defines as "Type THandle : handle;" Granted, there's only half a dozen changes needed to fix this part... but look at the potential for chaos. Also, note the comment made by the unit Author...
I also found functions defined with longints that, according to the SDK should be Bytes, others that should be Words and others that should be longwords.
For example, further down in the same file:
{ was #define dname(params) def_expr }
{ argument types are unknown }
function GetBValue(rgb : longint) : BYTE; { was #define dname(params) def_expr }
{ argument types are unknown }
function GetGValue(rgb : longint) : BYTE;
{ was #define dname(params) def_expr }
{ argument types are unknown }
function GetRValue(rgb : longint) : BYTE;According to the SDK these should be:
Function GetBValue(RGB : LongWord) : Byte;
Function GetGValue(RGB : LongWord) : Byte;
Function GetRValue(RGB : LongWord) : Byte;
{ was #define dname(params) def_expr }
{ argument types are unknown }
function RGB(r,g,b : longint) : DWORD;And according to the SDK this should be:
Function RGB(R,G,B : Byte) : LongWord;These examples are all from one file... BASE.INC. Lord only knows how many *hundreds* of these mistakes there are in the other files!
OK... not having done such an extensive job in FP before, I would really appreciate some step by step instructions. I tried recompiling last night and it just kept bombing out on this:
ACL_INFORMATION_CLASS = (AclRevisionInformation := 1,AclSizeInformation);
(BASE.INC Line: 259)So... how do I get this to work???
1) Move the following directories and files to a separate location...
2) ... ???
I don't mind putting in the time and effort to go though this and correct the problems (at least the ones I can find), and I have no reservation about sharing the result with everyone... but I sure could use a little help with the correct compiling process to follow.
<G> It's not worth a darn if I can't compile it... (Thanks in advance)
-----
L D Blake
In the development branch THandle is a Cardinal. In the stable 1.0.x branch we left it an…
In reply to your message of August 29, 2003
OR ... it was such a problem that nobody is using FP for Windows developement anymore.
I do have to say I'm leaning that way... Bad typedefs all over the place, units that won't compile by themselves, sourcecode that takes hours of searching to find anyting... It can all be very discouraging.
-----
L D Blake
Peter, longint is simply wrong. whist is may work in most circumstances, if you are on a…
In reply to your message of August 29, 2003
Peter, longint is simply wrong. whist is may work in most circumstances, if you are on a system with a lot of handles being allocated, you will get to the realms on 32bit unsigned values. As the normal test for a handle allocation is :
There's a chance nobody has run into this before...
The SDK says that in 9x versions of windows Handles use only the 16 lsb of the 32 bit value (max 65535 open handles) and this would not cause a range check error unless the program was run on a true 32 bit system like NT/2k/XP. In the latter versions, the full 32 bit value is allocated... and I'm on win2k.
Yep... using the 32bit compiler on a true 32bit operating system with actual WinApi calls.
(Sorry for the sarcasm, but I'm sitting her watching a month and a half's work go right down the drain...)
It's not actually a Cardinal, it's a DWORD that is the normal Win32 type. DWORD is mapped to LongWord in Delphi and therefore Cardinal.
Actually the closest match in the FP system unit is LongWord.
FP defines "Cardinal" to be a dynamically sized possibility of Byte, Word or Longword... which I also doubt windows is going to handle very well.
-----
L D Blake
Is it? FPC 1.0.x is at D2..D4 level, and some of those versions don't have proper…
In reply to your message of August 29, 2003
> Peter, longint is simply wrong. Is it?
Yeah totally wrong... A negative handle??? Think about it...
Moreover, I agree with Peter, HWND's are used really a lot. Inside FPC, ICS, Lazarus etc etc.
Yep, well here's the rub... I took an older system I have laying about and set it up witn win98 and ran my project... it doesn't do it there! According to the SDK that's because 9x versions don't assign handles above 65,535 ... i.e. only the low word of the 32 bit handle is used, which won't cause a range check error.
It would have been detected.
Not if...
A) nobody is using direct winapi calls on nt/2k/xp or B) nobody bothered to report it.
One has to ask how many people tried this, ran into trouble and just moved on to some other compiler without ever bothering to report it...
Matt is right... Longint is absolutely the wrong declaration for a window handle.
-----
L D Blake
Yes I think about it. Typed negative on this side (the pascal side). On 2-complements it is the same binary layout, only the interpretation is different. The win32 API sees no difference, since it puts its own typing over it.
So signed<->unsigned isn't really a problem as long as you don't move between types with various sizes.
Wrong sizes are a problem, but ....
I've played with Active Directory, services and some other win2000 feats, in total 2 years,
and have been porting ICS (1 or 2 MB TCP/IP code, multithreading, heavily messaging) for two weeks now on XP.
However that was mostly with 1.1.
Unless you do arithmetic with it, it shouldn't matter.
In reply to your message of August 29, 2003
Yes I think about it. Typed negative on this side (the pascal side). On 2-complements it is the same binary layout, only the interpretation is different. The win32 API sees no difference, since it puts its own typing over it.
Turn on Pascal's range checking and watch what happens...
I counted the errors and counted the HWNDs in my application... one error for each window handle.
Also... as I reported, it garbles the display. I'm thinking the window handle is *changed* by the mismatch, giving rise to the possibility of duplicate handles.
(My app is highly visual... most everything occurs on the screen.)
-----
L D Blake
Yes I think about it. Typed negative on this side (the pascal side). On 2-complements it…
In reply to your message of August 29, 2003
Yes I think about it. Typed negative on this side (the pascal side). On 2-complements it is the same binary layout, only the interpretation is different. The win32 API sees no difference, since it puts its own typing over it.
Not to be sarcastic or anything... then what is causing this?
-----
L D Blake
In the development branch THandle is a Cardinal. In the stable 1.0.x branch we left it an…
In reply to your message of August 29, 2003
And it has been already a longint for 5 years.
Which pre-dates all of NT4, win2000, XP, 2003 ... Which are true 32 bit operating systems.
I can't help wondering if the handle is somehow being changed by the type mismatch giving rise to duplicate handles... which is bound to do strange things.
-----
L D Blake
In reply to your message of August 29, 2003 Turn on Pascal's range checking and watch…
We can discuss principles for hours of course, but that doesn't help you. Did you try to change the HWND type from longint to DWORD or Cardinal (which is the same) in the windows unit ? If so, does it help ?
Did you turn off range checking ? If so, what is the effect ?
At work I run NT 4, at home Windows 2000. I repeat my offer: If you want to send me your code, I can perform the necessary tests.
Michael.
In reply to your message of August 29, 2003 Not to be sarcastic or anything... then what…
Something else. But I think you are on the wrong track with HWND.
What you could do is increase the granularity of windows API checking.
I'm no Windows hero, but the WinAPI must have some checking (return values, a function like GetLastWinError or something), and try to check that after _each_ winapi call.
(or first scatter them roughly, and then increase the granularity only on the place where you expect errors).
This is an approach that works both when you are wrong about HWND, (and it is something else) but also if I'm wrong and it is HWND.
If somewhere something corrupted is delivered to the winapi, there is a fair chance the winapi will give some errorcode back, sooner or later.
In reply to your message of August 29, 2003 Which pre-dates all of NT4, win2000, XP, 2003…
NT4 is older, I run 2000 and before that its beta's on my work space for 24 hours/a week since early 2000.
I can't help wondering if the handle is somehow being changed by the type mismatch giving rise to duplicate handles... which is bound to do strange things.
A corrupt handle will be detected, since the object on the kernel side won't be valid. (a handle is kind of an index/pointer into an object list on the kernel side, the object itself has probably some corruption detection measures)
To me, it sounds more like an alignment or typing error in some record structure you use to pass a record to the kernel than a rotten handle.
But first we must pinpoint the exact call. Increase the granularity of your error detection (getlasterror or so) should do that.
Does somebody know something more about Winapi errorhandling? Please step forward :_)
We can discuss principles for hours of course, but that doesn't help you. Did you try to…
In reply to your message of August 30, 2003
We can discuss principles for hours of course, but that doesn't help you. Did you try to change the HWND type from longint to DWORD or Cardinal (which is the same) in the windows unit ? If so, does it help ?
I re-declared Hwind to be a longword in my own software, which should overide the declaration in the windows unit... the program runs now, but I still get an error each time I launch an HTML file in IE... it's only HTML and only in IE... Baffling.
Did you turn off range checking ? If so, what is the effect ?
IF I turn off range checking the program runs perfectly, but if I open windows on top of it (as you would with almost any media player) the display gets messed up... bits of the window open in the wrong places, the title bars are lost, etc. (FWIW, I consider it bad practice to turn off range checking since that prevents error detection and can lead to, well, this...)
At work I run NT 4, at home Windows 2000. I repeat my offer: If you want to send me your code, I can perform the necessary tests.
Ummm... I'll give it one more pass here if the problem persists I just might take you up on that.
I've been thinking about timelines... "What else happened about the same time this showed up?"... and the day before this all started I installed service pack 4 (now there's a scary thought) and just before that I test-ran Resource Hacker while looking for guidance on building resource files... I doubt there's a connection since it's only the FP code that's giving me any trouble... but I'm gonna spend a couple of days and nuke my system then reinstall everything just to play it safe (thank <insert deity of choice> for Backups!)
If I can't get this cleared up, the only remaining alternative is to ditch FP and find something else to program in... but I really don't want to do that. Despite this bit of strangeness and despite issues with string handling and now with the windows unit's declarations, I've actually been enjoying it. This "el-different" media player was a learning project... Pascal wise I'm pretty sure I've made no serious mistakes but these problems are giving me fits (at least in the figurative sense).
-----
Laura
Something else. But I think you are on the wrong track with HWND. What you could do is…
In reply to your message of August 30, 2003
Something else. But I think you are on the wrong track with HWND.
This is a possibility I've considered. It might be something else entirely... but it is definately something related to my program...
Another possibility, and one I've tested for, is that there are problems with my proggy picking up window messages it's not supposed to... but commenting out the suspect code did nothing to improve the situation.
What you could do is increase the granularity of windows API checking. I'm no Windows hero, but the WinAPI must have some checking (return values, a function like GetLastWinError or something), and try to check that after _each_ winapi call.
Every winapi call has a return value, which can indicate error states. I check every single one of them and produce message boxes for them all. The one thing I did learn from my earlier programming experience is that ignoring errors is how you get yourself into trouble...
Here's a code fragment showing what I mean:
//register the main window
With MDRClass do
begin
Style := cs_hRedraw or cs_vRedraw; // Set styles
lpfnWndProc := @MainProc; // point to main procedure
cbClsExtra := 0; // no extra class space
cbWndExtra := 0; // no extra window space
hInstance := MDRProg; // main program handle
hIcon := loadicon(MDRprog,'AppIcon');// title bar icon
hCursor := 0; // use standard cursor
hbrBackground := 1 + COLOR_BTNFACE; // background colour
lpszMenuName := nil; // no predefined menus
lpszClassName := 'mdrplay'; // text name of class
end;
if RegisterClass(MDRClass) < 1 then
begin
MessageBox(0, 'Main window registration failed',
'Fatal', mb_Ok or mb_iconstop);
Halt(0);
end;Every Api call is done like this... But I'm not getting my descriptive little message boxes... all I get is either Range Check errors (201 followed by dozens of references) or the screen scattering effect I've already described.
All my programs are compiled with range, stack and overflow checking enabled... that's how I found the bad declarations in the windows unit.
This is an approach that works both when you are wrong about HWND, (and it is something else) but also if I'm wrong and it is HWND.
Yep... it certainly should. This is what's leading me to believe the problem is someplace beyond the reach of any error trapping I might personally enact... someplace far more intimate to FP than my code.
If somewhere something corrupted is delivered to the winapi, there is a fair chance the winapi will give some errorcode back, sooner or later.
In a weird way it does... when things go strange, it mangles my desktop scattering bits of the program all over the place... The window frame will draw in the top left corner, the "menu context" numbers will appear on the button faces, the title bars disappear, etc. But only on this one program, which is written in FP. The program itself continues running and will still do most things if I estimate button locations... it's only the visual aspect of it that gets mangled... which is how I first concluded it was a redraw problem involving handles.
-----
L D Blake
Marco van de Voort wrote:
...
Does somebody know something more about Winapi errorhandling?
...
It works the same way as under libc but instead checking ErrNo you check GetLastError.
Expressing it as clearly as I can: For each WinPAI call you should check the WinAPI documentation (as with everything..); usually it states something like this : "this call returs <something> on success and <something, usually 0 = NULL = LongBool(false)> on failure. If this special failure-value is returned you should call GetLastError to obtain specific error code."
Some notes: some WinAPI functions clear the value returned from GetLastError on success, that is after successfull call to that function GetLastError is guaranteed to return NO_ERROR (NO_ERROR = ERROR_SUCCESS = 0, these are defined in errors.inc included in Windows unit). But this is unusual case and most WinAPI functions don't clear GetLastError on success. So the most reliable way to check for errors is to call GetLastError RIGHT AFTER each WinAPI call, i.e. every WinAPI call should be wrapped with a code like this: if WinAPIFunctionCall(...) = <failure-value> than
ReportError(GetLastError);Where ReportError(ErrorCode:DWORD) should do something like this: raise EWin32Error.Create(SysErrorMesage(ErrorCode)) (SysErrorMessage is defined in SysUtils).
In Delphi's SysUtils there are some functions that can be helpful here : RaiseLastWin32Error and Win32Check. There can be implemented like this (_like_ this, there are some details missing here):
procedure RaiseLastWin32Error;
begin
raise EWin32Error.Create(SysErrorMesage(GetLastError));
end;
function Win32Check(RetVal: BOOL): BOOL;
begin
if not RetVal then RaiseLastWin32Error;
Result := RetVal;
end;Notes:
- With these functions, the typical situation when you have a WinAPI call that returns BOOL (=LongBool) indicating success or failure can be written simply: Win32Check( WinAPICall(...) )
If function returns something different than BOOL you can use the code
if WinAPICall(...) = <failure-value> then
RaiseLastWin32Error;
or
Win32Check( WinAPICall(...) <failure-value> );- as you can see, value returned by Win32Check is not very useful. Actually, it would be more elegant for Win32Check to be a procedure.
- In newer Delphi's you should use RaiseLastOSError (that is implemented under Linux too, simply by replacing "GetLastError" with "ErrNo") and the exception name is EOSError. Function named OSCheck (instead Win32Check) would be sensible too but they didn't implemented it in Delphi. (but if someone here is now thinking about adding these functions to FPC's SysUtils, adding function named OSCheck would be really sensible - let's not stick to Delphi's limitations, besides adding this function would not break compatibility with Delphi)
- EWin32Error/EOSError exception has a field ErrorCode, so when you raise it you should not only create the message using "SysErrorMesage(GetLastError)" but you should also set ErrorCode field to GetLastError - it is a useful field in case you want later to inspect Windows error code that caused this exception. So RaiseLastWin32Error (and/or RaiseLastOSError) should be _actually_ implemented like this:
procedure RaiseLastOSError;
var E:EOSError;
LastError:DWORD;
begin
LastError:=GetLastError; { ErrNo for UNIX/Linux }
E:=EOSError.Create(SysErrorMessage(LastError));
E.LastError:=LastError;
end;You can make things even more elegant and implement new constructor for EOSError, one that takes as parameter ErrorCode:DWORD, sets his ErrorCode field and calls "inherited Create(SysErrorMessage(ErrorCode));". OK, if anyone here is interested more in some details he can always take a look at Delphi's source code.
Getting back to the subject, there are some more notes: Some WinAPI calls indicate as error things that are usually not really errorneous (that is, sometimes you want to check GetLastError and for some error codes ignore the error (don't raise exception); you can extend any of the functions RaiseLastWin32Error/RaiseLastOSError/Win32Check to handle these cases). Fortunately, these cases are very rare. But you should always check WinAPI docs.
GetLastError returns thread-specific error code, that is it keeps track of the last error for each thread separately. So using threads does not cause the problem.
So basically making a WinAPI program reliable is simple: you must wrap calls to almost all functions in code like Win32Check( WinAPICall(..) )
or
Win32Check( WinAPICall(..) <error-value> )
Hope this helps someone to simplify error handling in WinAPI programs.
In reply to your message of August 29, 2003 Which pre-dates all of NT4, win2000, XP, 2003…
From: L D Blake
Organization: Secret society to end secret societies To: Peter Vreman
Subject: Re: [fpc-pascal]More strangeness... Send reply to:
Date sent: Fri, 29 Aug 2003 19:12:04 -0400
> And it has been already a longint for 5 years. Which pre-dates all of NT4, win2000, XP, 2003 ... Which are true 32 bit operating systems.
.
.
NT4 is available since around, IIRC.
Tomas