为什么CreateFileMapping返回“文件已存在”?

8

我有一个应用程序,使用CreateFileMapping定义了一个共享内存区域,我正在尝试从另一个应用程序中读取该内存。

我尝试了以下方法:

handle := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE,
             0,$3200, pchar('FileMappingZone'));

但是我得到了:

当该文件已经存在时,无法创建文件

可能的问题是什么?


2
你的winapi调用包装器是否在每次调用后无条件检查GetLastError?预期CreateFileMapping返回有效句柄并且以下GetLastError返回ERROR_ALREADY_EXISTS(如果这是您期望的结果,则实际上不是错误)。 - Anton Kovalenko
如果在CreateFileMapping调用后关闭了创建文件映射的应用程序,我会立即调用GetLastError,以确保操作已成功完成。 - opc0de
@opc0de 不要这样做。只有在文档中建议这样做时才调用 GetLastError。而且只有当 CreateFileMapping 返回 NULL 时才需要这样做。 - David Heffernan
@DavidHeffernan GetLastError 有时候应该在非错误情况下进行检查,不像 errno。但是重要的是不要将其值解释为错误。 - Anton Kovalenko
1个回答

17

GetLastError()返回非成功值并不代表一定发生了错误。重要的是先通过函数的返回值区分错误,然后再检查GetLastError()以获取有关所发生错误类型的更多信息。

对于已经存在的映射,文档中记录 CreateFileMapping 返回一个有效句柄并且GetLastError()设为ERROR_ALREADY_EXISTS。在这种情况下,错误值是信息性的:如果您想知道打开它之前是否存在映射,则可以检查它,但它不是错误。通过测试返回值是否为空来检测失败。否则,只需继续使用句柄。

P.S. 如果您希望确保在打开之前部分存在,则可以使用OpenFileMapping,它将针对不存在的部分而不是创建新部分而失败。


1
在这种情况下,共享应用程序将调用CreateFileMapping()来共享数据,而阅读应用程序应该使用OpenFileMapping()来读取共享的数据,而不是CreateFileMapping()。如果OpenFileMapping()失败,那么共享应用程序就没有共享任何数据(除非发生其他错误,比如阅读应用程序没有权限访问共享应用程序的映射)。我不会让一个读取应用程序创建映射,除非它打算共享自己的数据。 - Remy Lebeau
如果我希望阅读应用程序能够以任意顺序启动(而不必等待/重试可能发生的竞争),那么我将创建映射。有时这十分重要。原帖中提供了文件映射的大小,因此他显然足够熟悉其他应用程序,可以做出决策。 - Anton Kovalenko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接