使用NTQuerySystemInformation/NtQueryInformationFile/NtQueryObject获取进程使用的Unicode文件名

hik*_*ari 3 delphi delphi-xe3

我稍微调整了这里的代码:

Delphi - 查找从我的程序访问文件的进程

要按给定的pID返回句柄名称列表,我将每个条目添加到TStringList.问题是名称中包含垃圾"?" 在包含unicode字符的文件名中,例如"xxx★5"出现为"xxx?5"

代码有什么问题?

Dav*_*nan 8

查看任何非ASCII字符的问号是尝试从Unicode转换为ANSI的标志.

问题出在这个函数中:

function GetFileNameHandleThr(Data: Pointer): DWORD; stdcall;
var
  dwReturn: DWORD;
  FileNameInfo: FILE_NAME_INFORMATION;
  ObjectNameInfo: TOBJECT_NAME_INFORMATION;
  IoStatusBlock: IO_STATUS_BLOCK;
  pThreadParam: TGetFileNameThreadParam;
begin
  ZeroMemory(@FileNameInfo, SizeOf(FILE_NAME_INFORMATION));
  pThreadParam := PGetFileNameThreadParam(Data)^;
  Result := NtQueryInformationFile(pThreadParam.hFile, @IoStatusBlock,  @FileNameInfo, MAX_PATH * 2, FileNameInformation);
  if Result = STATUS_SUCCESS then
  begin
    Result := NtQueryObject(pThreadParam.hFile, ObjectNameInformation,  @ObjectNameInfo, MAX_PATH * 2, @dwReturn);
    if Result = STATUS_SUCCESS then
    begin
      pThreadParam.Result := Result;
      WideCharToMultiByte(CP_ACP, 0, @ObjectNameInfo.Name.Buffer[ObjectNameInfo.Name.MaximumLength - ObjectNameInfo.Name.Length], ObjectNameInfo.Name.Length, @pThreadParam.FileName[0], MAX_PATH, nil, nil);
    end
    else
    begin
      pThreadParam.Result := STATUS_SUCCESS;
      Result := STATUS_SUCCESS;
      WideCharToMultiByte(CP_ACP, 0, @FileNameInfo.FileName[0], IoStatusBlock.Information, @pThreadParam.FileName[0], MAX_PATH, nil, nil);
    end;
  end;
  PGetFileNameThreadParam(Data)^ := pThreadParam;
  ExitThread(Result);
end;
Run Code Online (Sandbox Code Playgroud)

这在调用中从Unicode转换为ANSI WideCharToMultiByte.您只需删除该部分代码即可.

您需要修改此记录

TGetFileNameThreadParam = packed record
  hFile    : THandle;
  Result   : NT_STATUS;
  FileName : array [0..MAX_PATH - 1] of AnsiChar;
end;
Run Code Online (Sandbox Code Playgroud)

所以这FileName是一个数组WideChar.

TGetFileNameThreadParam = packed record
  hFile    : THandle;
  Result   : NT_STATUS;
  FileName : array [0..MAX_PATH - 1] of WideChar;
end;
Run Code Online (Sandbox Code Playgroud)

然后GetFileNameHandleThr相应地进行调整.我没有详细研究它,但我希望你需要这样的东西:

function GetFileNameHandleThr(Data: Pointer): DWORD; stdcall;
var
  dwReturn: DWORD;
  FileNameInfo: FILE_NAME_INFORMATION;
  ObjectNameInfo: TOBJECT_NAME_INFORMATION;
  IoStatusBlock: IO_STATUS_BLOCK;
  pThreadParam: TGetFileNameThreadParam;
begin
  ZeroMemory(@FileNameInfo, SizeOf(FILE_NAME_INFORMATION));
  pThreadParam := PGetFileNameThreadParam(Data)^;
  Result := NtQueryInformationFile(pThreadParam.hFile, @IoStatusBlock,  @FileNameInfo, MAX_PATH * 2, FileNameInformation);
  if Result = STATUS_SUCCESS then
  begin
    Result := NtQueryObject(pThreadParam.hFile, ObjectNameInformation,  @ObjectNameInfo, MAX_PATH * 2, @dwReturn);
    if Result = STATUS_SUCCESS then
    begin
      pThreadParam.Result := Result;
      Move(ObjectNameInfo.Name.Buffer[ObjectNameInfo.Name.MaximumLength - ObjectNameInfo.Name.Length], pThreadParam.FileName[0], Min(ObjectNameInfo.Name.Length, MAX_PATH)*SizeOf(WideChar));
      //WideCharToMultiByte(CP_ACP, 0, @ObjectNameInfo.Name.Buffer[ObjectNameInfo.Name.MaximumLength - ObjectNameInfo.Name.Length], ObjectNameInfo.Name.Length, @pThreadParam.FileName[0], MAX_PATH, nil, nil);
    end
    else
    begin
      pThreadParam.Result := STATUS_SUCCESS;
      Result := STATUS_SUCCESS;
      Move(FileNameInfo.FileName[0], pThreadParam.FileName[0], Min(IoStatusBlock.Information, MAX_PATH)*SizeOf(WideChar));
      //WideCharToMultiByte(CP_ACP, 0, @FileNameInfo.FileName[0], IoStatusBlock.Information, @pThreadParam.FileName[0], MAX_PATH, nil, nil);
    end;
  end;
  PGetFileNameThreadParam(Data)^ := pThreadParam;
  ExitThread(Result);
end;
Run Code Online (Sandbox Code Playgroud)

我没有运行此代码,因此您可能需要进一步处理它.但是,问题显然是转换为ANSI.

我现在运行此代码并且运行良好.

  • 我希望那是因为你未能做出所有改变.你可能没有改变`TGetFileNameThreadParam`来使用`WideChar`缓冲区.重要的是,您不要将此视为黑盒子并完全理解代码的工作原理. (3认同)