And
and or
are bitwise operators. That means they apply to each bit of their operands independently. When learning about bitwise operations, it helps to picture the operands in binary rather than decimal. (Once you're familiar with how they work, decimal still isn't the ideal format; most people prefer hexadecimal instead, or, to a lesser extent, octal.)
For and
, the result bit is set if and only if the bits of both operands are set; otherwise, the result is cleared. For or
, the result is set if either one of the operand bits is set. It's also set when both are set, so it's known as inclusive or. (There's also exclusive or, where the result is set only when exactly one of the two operands is set. Delphi uses the xor
operator for that.)
To compute a result for operands that are larger than one bit, the bits are computed in parallel, so the first bit of the result is computed from the first bits of the operands, the second bit from the second bits, and so on.
When combining flags, you use or
to indicate that you want both flags set. For example:
// Indicate we want both a simple progress bar *and* a lack of confirmation.
OpStruc.fFlags := fof_NoConfirmation or fof_SimpleProgress;
The first flag's value in binary is 00010000. The second's is 000100000000. That makes the result 000100010000.
You won't frequently use and
when setting flags. Rather, that's usually used when you want to check whether a flag is set. For example:
// Check whether the no-confirmation flag is set:
var FlagSet: Boolean;
FlagSet := (OpStruc.FFlags and fof_NoConfirmation) = fof_NoConfirmation;
Since the input was 000100010000, the result of the and
with the flag value is 000000010000. That's equal to the flag value, so the value of FlagSet
will be true.
It's sometimes enough to check whether the result of the and
operation is non-zero, rather than to check that it's exactly equal to the flag you were testing. When the flag consists of multiple set bits, you want to check that all of them were present, though. If only one were present, the result of the and
operation would still be non-zero.
To remove flags, you use not
to invert the bits of the flag you want to remove (clearing all the set bits and vice versa), and then use and
to clear those bits. For example:
OpStruc.FFlags := OpStruc.FFlags and not fof_SimpleProgress;
The inverse of fof_SimpleProgress
is 111011111111. The value of FFlags
so far is 000100010000. Combining those with and
will yield 000000010000, which equals fof_NoConfirmation
, just as we'd expect by removing fof_SimpleProgress
.
Now that you understand how individual flag values get combined, you're equipped indicate which flags you want to pass to the particular API function you're having trouble with. Read the documentation for each flag and decide whether it's one you want to use. If it is, include it in your list of flags.
You can combine flags with or
in any order. If you know you always want certain flags, and you conditionally want others, you can start with your list of common flags and then add others later. For example:
OpStruc.FFlags := fof_NoConfirmation or fof_SimpleProgress;
if BigFiles then
OpStruct.FFlags := OpStruc.FFlags or fof_Silent;
It will frequently work to use addition to combine flags. Obviously, the result of fof_NoConfirmation or fof_SimpleProgress
is equal to fof_NoConfirmation + fof_SimpleProgress
. However, that only works when the bit values of each flag are distinct, and when no flag is included more than once. The result of fof_Silent or fof_Silent
is equal to fof_Silent
, whereas the result of fof_Silent + fof_Silent
is fof_RenameOnCollision
, which is an entirely unrelated flag. Always use and
and or
when working with flags, never +
and -
.