People may think that BOOL and Boolean are the same types in Delphi since they can just contain true and false. Right? Yes and No. They seem to be the same, however there is a little difference how these types are handled in an assignment. To see the difference we have to open up the CPU window and dig into assembler code. Don’t stop reading since it is really easy to understand.
You can also pack a boolean value into an integer. In fact the Windows Headers define it that way so we going to look at it as well.
The following assembler lines were read from the Delphi 7 CPU window:
Integer
value := Integer(True); mov [value],$00000001
value := true; mov [value],$ffffffff
value := true; mov byte ptr [value],$01
Why is it so important to understand these differences? Well, some Win32API functions check for the incoming value and may return with an error 87 (invalid paramater) or behave strangely in the worst case. As you could see, every time a BOOL type value is set to true, Delphi internally sets it to -1. If a Win32API function casts this value into a simple integer it obtains -1 ($ffffffff) and fails because the function may only accept one and zero.
The journey just starts here…. The whole JEDI API uses BOOL as a type that resolves into Delphi’s LongBool which – as we’ve already seen – defines the value “-1″ as true. In most cases Win32API functions don’t thoroughly check it and we are fine. They just check for a zero (false) and otherwise recognize it as true. Because I do not want to change such a big once made decision, so I decided to leave BOOL alone in the JEDI API. Furthermore changing BOOL to Integer means that you can’t assign true and false without excplicitly casting a boolean value to BOOL (or Integer).
In the ending it is just about compability and convenience. However the other side of the story is that you should remember that the Delphi type BOOL may be the source of a 87 (invalid parameter) error.
Summary:
| X | BOOL in Delphi | BOOL in C | Boolean in Delphi |
| original Type | LongBool | int | compiler magic |
| size in bytes | 4 | 4 | 1 |
| false = ? | 0 | 0 | 0 |
| true = ? | -1 ($FFFFFFFF) | 1 | 1 |
The following list contains functions that may collide with the different declaration because they check the value. Send me function names that behave strange with a BOOL type.
| # | Name | original header | note |
| 1. | QueryServiceConfig2(W/A) | JwaWinSVC.pas | Happened with struct TServiceDelayedAutoStartInfo (VISTA) |
Solutions you may find in JEDI API.
You may find different solutions for this problem in the JEDI source code. This reason is that the code was written by many persons with different knowledge during a long period of time. So if you find an struct that as a BOOL declaration like SERVICE_DELAYED_AUTO_START_INFO you should make sure that the function which uses this struct behaves correctly.
And here are two possible solution…you’d think.
The first declaration seems to be correct, however as you know it isn’t for the reasons described in the beginning. The second one may work, but it does only work by accident. Be aware that BOOL in C has 4 bytes (=sizeof(int)) and that type Boolean consists only of one byte. Actually we map one byte into four bytes without caring about the other three bytes. So the target function (here: ChangeServiceConfig2) “thinks” that the record member fDelayedAutoStart consists of four bytes (sizeof(int)) and also uses the three bytes behind our declaration. Since we don’t know the values of them (don’t care) they may be filled with random values. The result is a new number that isn’t just zero or one. Since ChangeServiceConfig2 may only succeed for one or zero values, we get the error 87 (invalid parameter).
So there are two real solutions:
I prefer the second solution and you should too! Why? If you hadn’t read the article above you would have thought that the first solution is quite handy because you just could have assigned true or false to it – like C programmers. However as I already mentioned the Pad variable has to be initialized first. So it is obvious to use something like this:
But it won’t work! Why? Again the solution is simple. Many Delphi programmers find their solution in real C sources. They just convert the C syntax to Delphi without knowing the details. As a matter of fact you won’t find a ZeroMemory call in such a C source! The C programmer just sets fDelayedAutoStart to TRUE and nothing more. So don’t you agree that solution numer 2 is the right one?
That’s the reason why you’ll find only the following record in the recent JED API version:
The compiler will fail if you assign true to the record member. However this is the best case I can think of.
So there is nothing better than working code…
4 Responses
GunSmoker
26|Sep|2008 1I don’t get it.
BOOL/LongBool
value := true;
mov [value],$ffffffff
And in Summary you say that “BOOL in Delphi” is “LongBool” and True is “1″.
First you say True is -1 and then you say True is 1.
Is this some kind of mistake or I just don’t understand something?
Christian Wimmer
26|Sep|2008 2No, you’re right. It should be -1. I fixed that issue. Thanks. Originally I wanted to add the Boolean type at first, then I forgot it. Now I readded and fixed it.
GunSmoker
15|Mar|2009 3BTW, do you aware of this issue:
http://sourceforge.net/tracker/index.php?func=detail&aid=2675572&group_id=121894&atid=694029 ?
Christian Wimmer
15|Mar|2009 4A long time ago the CreateMutex issue was fixed by Marcel. See JwaWinBase::CreateMutexA/W
But I tried it again in Delphi 7 and you know: I had the same problem. It seems that at the times Marcel created the patch, LongBool was the correct way to solve this problem (Maybe < D5). However I changed the declaration of the wrapper function from LongBool to DWORD (to remain the size of the boolean parameter (4)). And now it works.
The fix was applied to trunk revision 760.
Leave a reply
Search
Paypal donation (EUR)
Categories
Archives
Tags
Recent Posts
Recent Comments
Blogroll
JEDI Sites
Pages