为什么CreateFile会修改我的ShareMode参数?

huangapple go评论60阅读模式
英文:

Why does CreateFile modify my ShareMode parameter?

问题

在Windows中,我正在使用CreateFile打开一个文件。我想以较高的权限打开文件(在dwDesiredAccess参数中)并仅共享其中的一部分(在dwShareMode参数中)。

#include <iostream>
#include <Windows.h>

int main()
{
    const WCHAR* wszFile = LR"(D:\temp\myfile.txt)";
    HANDLE hFile1 = CreateFileW(wszFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
    if(hFile1 == INVALID_HANDLE_VALUE)
        std::cout << "File 1 opening failed with error code " << GetLastError() << std::endl;
    else
        std::cout << "File 1 opening succeeded." << std::endl;

    HANDLE hFile2 = CreateFileW(wszFile, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
    if(hFile2 == INVALID_HANDLE_VALUE)
        std::cout << "File 2 opening failed with error code " << GetLastError() << std::endl;
    else
        std::cout << "File 2 opening succeeded." << std::endl;

    HANDLE hFile3 = CreateFileW(wszFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
    if(hFile3 == INVALID_HANDLE_VALUE)
        std::cout << "File 3 opening failed with error code " << GetLastError() << std::endl;
    else
        std::cout << "File 3 opening succeeded." << std::endl;

    CloseHandle(hFile1);
    CloseHandle(hFile2);
    CloseHandle(hFile3);

    return 0;
}

我期望第一次和第二次调用成功,而第三次调用失败,但实际上第一次和第三次调用成功,而第二次调用失败。这意味着CreateFile修改了我的dwShareMode参数标志。

为什么会发生这种情况?

英文:

In Windows I am opening a file with CreateFile. I want to open the file with much privileges (in dwDesiredAccess parameter) and share only a subset of them (in dwShareMode parameter).

#include &lt;iostream&gt;
#include &lt;Windows.h&gt;

int main()
{
	const WCHAR* wszFile = LR&quot;(D:\temp\myfile.txt)&quot;;
	HANDLE hFile1 = CreateFileW(wszFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
	if(hFile1 == INVALID_HANDLE_VALUE)
		std::cout &lt;&lt; &quot;File 1 opening failed with error code &quot; &lt;&lt; GetLastError() &lt;&lt; std::endl;
	else
		std::cout &lt;&lt; &quot;File 1 opening succeeded.&quot; &lt;&lt; std::endl;

	HANDLE hFile2 = CreateFileW(wszFile, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
	if(hFile2 == INVALID_HANDLE_VALUE)
		std::cout &lt;&lt; &quot;File 2 opening failed with error code &quot; &lt;&lt; GetLastError() &lt;&lt; std::endl;
	else
		std::cout &lt;&lt; &quot;File 2 opening succeeded.&quot; &lt;&lt; std::endl;

	HANDLE hFile3 = CreateFileW(wszFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
	if(hFile3 == INVALID_HANDLE_VALUE)
    	std::cout &lt;&lt; &quot;File 3 opening failed with error code &quot; &lt;&lt; GetLastError() &lt;&lt; std::endl;
	else
    	std::cout &lt;&lt; &quot;File 3 opening succeeded.&quot; &lt;&lt; std::endl;

	CloseHandle(hFile1);
	CloseHandle(hFile2);
	CloseHandle(hFile3);

	return 0;
}

I would expect that the first two calls succeed and the third call fails, but instead the first and the third call succeed and the second call fails.
This means that CreateFile did modify my dwShareMode parameter flags.

Why does this happen?

答案1

得分: -1

第四次调用也失败了。这证明了ShareMode参数并没有被CreateFile修改。第五次调用成功了,尽管它授予了一个额外的共享模式(FILE_SHARE_DELETE),但由于之前的调用,这个共享模式实际上是不可用的。

我的问题在于,ShareMode参数的含义取决于文件是第一次打开还是后续打开:

  • 在第一次打开时,您为所有后续的文件访问指定了共享模式。随后的CreateFile调用不能在其dwDesiredAccess参数中指定比这个更多的权限。
  • 从第二次打开开始,您必须指定与第一次调用中给定的共享模式相同的共享模式,以及允许前面调用的dwDesiredAccess参数的共享模式。但是您可以分享更多(只要其他句柄仍然打开…?)。

我的问题在于,我期望dwShareMode只需要知道先前调用的dwShareMode参数,而不需要知道先前dwDesiredAccess参数的所需访问权限。

不幸的是,在MSDN中并没有清晰地描述这一点。我已经阅读了以下文章,其中提到:

https://learn.microsoft.com/en-us/windows/win32/fileio/creating-and-opening-files

应用程序还使用CreateFile指定是否要共享文件以进行读取、写入、两者兼而有之或两者都不要。这称为共享模式。不共享的打开文件(dwShareMode设置为零)无法再次被打开,无论是由打开它的应用程序还是其他应用程序,直到它的句柄被关闭。这也被称为独占访问。

当进程使用CreateFile尝试打开已经以共享模式(dwShareMode设置为有效的非零值)打开的文件时,系统会将请求的访问和共享模式与文件在打开时指定的模式进行比较。如果您指定了与先前调用中指定的模式冲突的访问或共享模式,CreateFile将失败。

dwShareMode的行为是合理的,但在那里并没有完全描述。

英文:

I tried some more times and found an explaination. I extended my previous code by two more calls.

#include &lt;iostream&gt;
#include &lt;Windows.h&gt;

int main()
{
	const WCHAR* wszFile = LR&quot;(D:\temp\myfile.txt)&quot;;
	HANDLE hFile1 = CreateFileW(wszFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
	if(hFile1 == INVALID_HANDLE_VALUE)
		std::cout &lt;&lt; &quot;File 1 opening failed with error code &quot; &lt;&lt; GetLastError() &lt;&lt; std::endl;
	else
		std::cout &lt;&lt; &quot;File 1 opening succeeded.&quot; &lt;&lt; std::endl;

	HANDLE hFile2 = CreateFileW(wszFile, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
	if(hFile2 == INVALID_HANDLE_VALUE)
		std::cout &lt;&lt; &quot;File 2 opening failed with error code &quot; &lt;&lt; GetLastError() &lt;&lt; std::endl;
	else
		std::cout &lt;&lt; &quot;File 2 opening succeeded.&quot; &lt;&lt; std::endl;

	HANDLE hFile3 = CreateFileW(wszFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
	if(hFile3 == INVALID_HANDLE_VALUE)
		std::cout &lt;&lt; &quot;File 3 opening failed with error code &quot; &lt;&lt; GetLastError() &lt;&lt; std::endl;
	else
		std::cout &lt;&lt; &quot;File 3 opening succeeded.&quot; &lt;&lt; std::endl;

	HANDLE hFile4 = CreateFileW(wszFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
	if(hFile4 == INVALID_HANDLE_VALUE)
		std::cout &lt;&lt; &quot;File 4 opening failed with error code &quot; &lt;&lt; GetLastError() &lt;&lt; std::endl;
	else
		std::cout &lt;&lt; &quot;File 4 opening succeeded.&quot; &lt;&lt; std::endl;

	HANDLE hFile5 = CreateFileW(wszFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
	if(hFile5 == INVALID_HANDLE_VALUE)
		std::cout &lt;&lt; &quot;File 5 opening failed with error code &quot; &lt;&lt; GetLastError() &lt;&lt; std::endl;
	else
		std::cout &lt;&lt; &quot;File 5 opening succeeded.&quot; &lt;&lt; std::endl;

	CloseHandle(hFile1);
	CloseHandle(hFile2);
	CloseHandle(hFile3);
	CloseHandle(hFile4);
	CloseHandle(hFile5);

	return 0;
}

The fourth call also fails. So there is the proof that the ShareMode parameter hasn't been modified by CreateFile.
The fifth call succeeds, although it grants an additional share mode (FILE_SHARE_DELETE) which is not available due to previous calls.
My problem is that the meaning of ShareMode is ambiguous depending on whether the file is opened for the first time or for subsequent times:

  • In the first time you specify the share mode for all subsequent file access. The following CreateFile calls may not specify more privileges than this in their dwDesiredAccess parameter.
  • Starting with the second time you must specify the same share mode given in the first call plus the share mode required to allow the dwDesiredAccess parameter of the previous calls. But you are allowed to share more (although there will not be shared more (as long as the other handles are open...?)).

My problem was that I expected that dwShareMode only needs to know the dwShareMode parameter of the previous calls and not that it must also know the required access rights for previous dwDesiredAccess parameters.

Unfortunately this isn't clearly described in the MSDN. I had already read the following article, which says:

https://learn.microsoft.com/en-us/windows/win32/fileio/creating-and-opening-files

> An application also uses CreateFile to specify whether it wants to share the file for reading, writing, both, or neither. This is known as the sharing mode. An open file that is not shared (dwShareMode set to zero) cannot be opened again, either by the application that opened it or by another application, until its handle has been closed. This is also referred to as exclusive access.
>
> When a process uses CreateFile to attempt to open a file that has already been opened in a sharing mode (dwShareMode set to a valid nonzero value), the system compares the requested access and sharing modes to those specified when the file was opened. If you specify an access or sharing mode that conflicts with the modes specified in the previous call, CreateFile fails.

The behavior of dwShareMode makes sence, but isn't fully described there.

huangapple
  • 本文由 发表于 2023年3月15日 19:39:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/75744196.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定