【问题标题】:Why does CreateFileMapping return "file already exists"?为什么 CreateFileMapping 返回“文件已存在”?
【发布时间】:2013-01-22 22:00:14
【问题描述】:

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

我试过了:

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

但我明白了:

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

可能是什么问题?

【问题讨论】:

  • 您的 winapi 调用包装器是否在每次调用后无条件检查GetLastErrorCreateFileMapping 应该返回一个有效的句柄,下面的 GetLastError 会返回 ERROR_ALREADY_EXISTS(如果它是你所期望的,这实际上不是一个错误)。
  • 我在调用 CreateFileMapping 之后调用 GetLastError,如果我在它说:操作成功完成之前关闭了已创建文件映射的应用程序
  • @opc0de 不要那样做。仅当文档要求这样做时才调用GetLastError。那是CreateFileMapping返回NULL的时候。
  • @DavidHeffernan GetLastError 有时应该在非错误情况下进行检查,这与errno 不同。但重要的是将其值解释为错误。

标签: delphi winapi shared-memory


【解决方案1】:

并非所有将GetLastError() 值设置为不成功的东西都是错误的。首先通过函数的返回值区分错误很重要,然后检查GetLastError()以获取有关发生的错误类型的更多信息。

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

附:如果您想在打开之前确保该部分存在,您可以使用OpenFileMapping,这将导致不存在的部分失败,而不是创建一个新部分。

【讨论】:

  • 在这种情况下,共享应用会调用CreateFileMapping()来共享数据,而阅读应用应该使用OpenFileMapping()而不是CreateFileMapping()来读取共享数据。如果OpenFileMapping() 失败,则共享应用程序不会共享任何数据(除非发生另一个错误,例如阅读应用程序无权访问共享应用程序的映射)。如果它不存在,我不会让阅读应用程序创建映射,除非它打算共享自己的数据。
  • 如果我希望阅读应用程序能够以任何顺序开始(而不是等待/重试可能的比赛),我会让阅读应用程序创建映射,这有时很重要。 OP 的示例提供了文件映射的大小,因此他显然知道其他应用程序足以做出决定。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-03-20
  • 2017-06-19
  • 2022-01-25
  • 1970-01-01
  • 2016-07-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多