The flag CF_OPEN_FILE_FLAG_FOREGROUND
is not documented in either the documentation for CF_OPEN_FILE_FLAGS nor in the documentation for CfOpenFileWithOplock.
What is this flag's meaning?
The following information was supplied via a Microsoft Case:
CF_OPEN_FILE_FLAG_FOREGROUND
is not documented, probably it was added at a later stage.Based on the code, it seems that If a caller doesn’t want to use Oplocks, they should use this flag when calling
CfOpenFileWithOplock
. It implies thatFILE_OPEN_REQUIRING_OPLOCK
wouldn’t be set when the API callsCreateFile()
underneath.By default, the
FOREGROUND
flag is not specified, so the default behavior ofCfOpenFileWithOplock
is to request an oplock. That would make it consistent with defaulting to background behavior.In this context “foreground” seems to mean that the caller is acting as a foreground application. I.e., they don’t care whether the file handle created by this API causes sharing violations for other callers, and they don’t care about breaking any oplocks that may already be on the file, so they open the handle without requesting an oplock. The default “background” behavior requests an oplock when opening the file handle so that their call fails if there’s already an oplock, and they can be told to close their handle if they need to get out of the way to avoid causing a sharing violation later.
Side note: unless the caller specifies
CF_OPEN_FILE_FLAG_EXCLUSIVE
toCfOpenFileWithOplock
, the oplock they get will be onlyOPLOCK_LEVEL_CACHE_READ
, not (OPLOCK_LEVEL_CACHE_READ | OPLOCK_LEVEL_CACHE_HANDLE
), so there won’t be the sharing violation protection a background app might normally want.
Note: Microsoft has (since this case) has now documented this flag.
Further information was provided in this case, and is shared here as it is relevant in general to this API:
A background application typically wants to operate transparently on files. In particular, they want to avoid causing sharing violations to other (foreground) openers. To do that, they take a
CACHE_READ | CACHE_HANDLE
oplock, such as would be granted by usingCF_OPEN_FILE_FLAG_EXCLUSIVE
withCfOpenFileWithOplock
. Then, if some other opener comes along whose requested share/access modes conflict with the background app’s, the background app’s oplock breaks. This prompts the background app to close their file handle (for aCf
handle, that causes it to become invalid – the real underlying handle has been closed). Once the background app closes their handle, the other opener’s open proceeds without hitting the sharing violation. That all works because of theCACHE_HANDLE
part of the oplock. WithoutCF_OPEN_FILE_FLAG_EXCLUSIVE
, the oplock only hasCACHE_READ
protection, so that sharing violation protection I described doesn’t happen.
If
CF_OPEN_FILE_FLAG_EXCLUSIVE
is specified, the open is “share none” and it gets aCACHE_READ | CACHE_HANDLE
oplock.
a. A normalCreateFile
call that opens for any ofFILE_EXECUTE | FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA | DELETE
(or either/both ofGENERIC_READ | GENERIC_WRITE
) will break the oplock due to the sharing conflict, as described above. The oplock owner will get to finish and acknowledge.If
CF_OPEN_FILE_FLAG_EXCLUSIVE
is not specified, the open is “share all” and it gets aCACHE_READ
oplock.a. A normal
CreateFile
call will not break the oplock.b. If the normal
CreateFile
specifies a sharing mode that conflicts with theCf
handle’s access (for instance, if the normalCreateFile
does not specifyFILE_SHARE_READ
), the normalCreateFile
will fail withERROR_SHARING_VIOLATION
.c. The oplock doesn’t break until the other caller issues a conflicting I/O, such as a write. When that happens the oplock break is advisory only.
The way the Cf APIs use oplocks, the “exclusive” oplock is the only one that breaks the way you’re expecting.
(i.e. a break that is not just advisory)