windows - 为什么我的 Delphi 应用程序说存在一个不存在的文件?

标签 windows delphi

我有以下 32 位 Delphi 项目源代码:

program TestApp;

uses
  SysUtils, Dialogs, Windows;

var
  filename: String = 'C:\Program Files (x86)\Some Application\foo.txt';
  fd: TWIN32FindData;
  h: THandle;

begin
  FillChar(fd, SizeOf(fd), 0);
  h := FindFirstFile(PChar(filename), fd);
  if h = INVALID_HANDLE_VALUE then
    ShowMessage('FindFirstFile=false')
  else
  begin
    ShowMessage('FindFirstFile=true');
    FindClose(h);
  end;

  if FileExists(filename) then
    ShowMessage('FileExists=true')
  else
    ShowMessage('FileExists=false');
end.

当我运行它时,Windows API FindFirst 调用和 FileExists 调用都返回 True,即使该目录中不存在该文件。

为什么它声称文件存在而实际上不存在?

最佳答案

该文件存在于 VirtualStore 目录中

C:\Users\{username}\AppData\Local\VirtualStore\Program Files (x86)

这是一项称为UAC 虚拟化的功能,首次在Windows Vista 中引入。它允许应用程序写入它们无权访问的受限目录。当启用了 UAC 虚拟化的 32 位应用程序写入真实目录并收到访问拒绝结果时,Windows 会在 VirtualStore 中创建该文件的副本。

当此应用程序或另一个启用了 UAC 虚拟化的 32 位应用程序尝试读取该文件时,它将首先检查该文件的 VirtualStore。通过在任务管理器中添加此列,您可以看到 UAC 虚拟化已启用。

当您删除 {$R *.res} 时,Delphi 程序中会发生这种情况指示。如果更改项目源以添加 {$R *.res}指令返回

program TestApp;

uses
  SysUtils, Dialogs, Windows;

{$R *.res}

var
  filename: String = 'C:\Program Files (x86)\Some Application\foo.txt';
  fd: TWIN32FindData;
  h: THandle;

begin
  FillChar(fd, SizeOf(fd), 0);
  h := FindFirstFile(PChar(filename), fd);
  if h = INVALID_HANDLE_VALUE then
    ShowMessage('FindFirstFile=false')
  else
  begin
    ShowMessage('FindFirstFile=true');
    FindClose(h);
  end;

  if FileExists(filename) then
    ShowMessage('FileExists=true')
  else
    ShowMessage('FileExists=false');
end.

它将识别您的应用程序已禁用 UAC 虚拟化(这是大多数应用程序的标准)。您可以在任务管理器中看到,文件查找操作的结果将是您所期望的。

省略 .RES 文件会导致此问题的原因是它包含 list 。此 list 中的以下行禁用 UAC 虚拟化:

<requestedExecutionLevel level="asInvoker" uiAccess="false"/>

当省略 level 时,UAC 虚拟化已启用。

关于windows - 为什么我的 Delphi 应用程序说存在一个不存在的文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53508928/

相关文章:

windows - Groovy:如何将 .groovy 脚本作为 Windows 服务

windows - 在 Windows 上从 Electron 应用程序安装 VirtualBox 的正确方法

delphi如何设置tcpserver接收字符串数据

c++ - 检测 Windows 10 版本

windows - SPI_SETDISABLEOVERLAPPEDCONTENT

javascript - 使用 JavaScript 在窗口/选项卡之间进行通信

delphi - 如何使用Delphi XE的TEncoding将西里尔文或ShiftJis文本保存到文件?

delphi - 如何检测 TListView 中复选框的点击

delphi - "Library path"应该指向包的源文件吗?

delphi - 从 Delphi REST 服务器返回图像并将其显示在浏览器中