获取使用文件的 ProcessId

Get ProcessId that is using a file

提问人:Michael Marcel 提问时间:8/8/2023 最后编辑:marc_sMichael Marcel 更新时间:8/21/2023 访问量:176

问:

重要提示:我们使用 DELPHI 7。

我有一个问题来获取正在使用的文件。ProcessId

只是为了让您知道,在我们的软件中,我们需要向用户显示哪个进程正在使用我们需要的文件。

为此,我曾经获取过“进程”列表和“句柄”列表。NtQuerySystemInformation

之后,我使用了那些带有文件句柄的进程 ID (ObjectType = 28)OpenProcess

然后我曾经得到文件句柄。DuplicateHandle

让我们看看代码:

function GetProcessIdUsingFile(const TargetFileName:string): DWORD;
var
 hProcess    : THandle;
 hFile       : THandle;
 SystemInformationLength : DWORD;
 Index       : Integer;
 pHandleInfo : PSYSTEM_HANDLE_INFORMATION;
 hQuery      : THandle;
 FileName    : String;
 ReturnInformation : LongBool;
 FileInfo : _BY_HANDLE_FILE_INFORMATION;

 //Novo
 cbRet : DWORD;
 cbSize : DWORD;
begin
  Result:= 0;
  cbSize := $5000;
  GetMem(pHandleInfo, cbSize);
  repeat
    cbSize := cbSize * 2;
    ReallocMem(pHandleInfo, cbSize);
    hQuery := NtQuerySystemInformation(SystemHandleInformation, pHandleInfo, cbSize, @cbRet);
  until hQuery <> STATUS_INFO_LENGTH_MISMATCH;

  try
    if(hQuery = STATUS_SUCCESS) then
    begin
      for Index:=0 to pHandleInfo^.uCount-1 do
        if pHandleInfo^.Handles[Index].ObjectType=28 then
          begin
            hProcess := OpenProcess(PROCESS_DUP_HANDLE, FALSE, pHandleInfo^.Handles[Index].uIdProcess);
            if(hProcess <> INVALID_HANDLE_VALUE) then
            begin
              try
                if not DuplicateHandle(hProcess, pHandleInfo^.Handles[Index].Handle,GetCurrentProcess(), @hFile,  0 ,FALSE, DUPLICATE_SAME_ACCESS) then
                   hFile := INVALID_HANDLE_VALUE;

                if (hFile<>INVALID_HANDLE_VALUE) then
                  begin
                    try
                      FileName := GetFileNameByHandle(hFile);
                    finally
                      CloseHandle(hFile);
                    end;
                  end
                else
                   FileName := '';
              finally
                CloseHandle(hProcess);
              end;

               if CompareText(ExtractFileName(FileName), TargetFileName)=0 then
                  Result := pHandleInfo^.Handles[Index].uIdProcess;
            end;
          end;
    end;
  finally
   if pHandleInfo<>nil then
     FreeMem(pHandleInfo);
  end;
end;

所以,我创造了GetFileNameByHandle

此函数从前面的代码中接收文件句柄,并尝试使用 和 获取其文件名。NtQueryInformationFileNtQueryObject

但是,每一次回电.如何获取其文件名?NtQueryInformationFileSTATUS_OBJECT_TYPE_MISMATCH

让我向你展示这个函数的代码:

function GetFileNameByHandle(hFile: THandle): String;
var
  dwReturn: DWORD;
  FileNameInfoRecord: FILE_NAME_INFORMATION;
  ObjectNameInfo: TOBJECT_NAME_INFORMATION;
  IoStatusBlock: IO_STATUS_BLOCK;
  ntSTATUS : DWORD;
  FileName : array [0..MAX_PATH - 1] of WCHAR;
begin
  FillChar(FileName, SizeOf(FileName), 0);
  FillChar(FileNameInfoRecord.FileName, SizeOf(FileNameInfoRecord.FileName), 0);
  FileNameInfoRecord.FileNameLength := 0;
  ntSTATUS := NtQueryInformationFile(hFile, @IoStatusBlock,  @FileNameInfoRecord, SizeOf(FILE_NAME_INFORMATION) * 2 + 1, FileNameInformation);
  if ntSTATUS = STATUS_SUCCESS then
    begin
       // NEVER ENTER HERE... WHY?
       ntSTATUS := NtQueryObject(hFile, ObjectNameInformation,  @ObjectNameInfo, MAX_PATH * 2, @dwReturn);
       if ntSTATUS = STATUS_SUCCESS then
       begin
         WideCharToMultiByte(CP_ACP, 0, @ObjectNameInfo.Name.Buffer[ObjectNameInfo.Name.MaximumLength - ObjectNameInfo.Name.Length], ObjectNameInfo.Name.Length, @FileName[0], MAX_PATH, nil, nil);
       end
       else
       begin
         ntSTATUS := STATUS_SUCCESS;
         WideCharToMultiByte(CP_ACP, 0, @FileNameInfoRecord.FileName[1], IoStatusBlock.Information, @FileName[0], MAX_PATH, nil, nil);
       end;
     end;
  Result := WideCharToString(@FileName);
end;

之后,我比较函数中的文件名以返回 PID。GetProcessIdUsingFile

我使用此代码作为基础,并尝试了一些修改,但没有任何效果:

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

如果你们需要更多信息,请LMK。

Delphi-7 PID 处理文件

评论

1赞 Remy Lebeau 8/8/2023
若要从句柄获取文件名,可以使用 GetFileInformationByHandleEx() 而不是 +。NtQueryInformationFileNtQueryObject
0赞 Michael Marcel 8/8/2023
@RemyLebeau我尝试使用,但它也总是返回 False。GetFileInformationByHandleEx
1赞 Remy Lebeau 8/8/2023
两者都告诉您文件句柄无效。您需要调试代码以找出原因。NtQueryInformationFileGetFileInformationByHandleEx
1赞 Ken Bourassa 8/9/2023
我似乎在德尔福的文件中找不到声明。如果你的声明与 Microsoft 定义的声明完全相同,则返回 6。因此,您会告诉您有一个 13 字节的缓冲区(这实际上不是真的),并且有缓冲区溢出的风险(在这种情况下很可能是这样)。即使您有不同的声明,也没有声明不会使您面临缓冲区溢出的风险,除非您声明它比需要的要大得多......FILE_NAME_INFORMATIONSizeOf(FILE_NAME_INFORMATION)NtQueryInformationFileFILE_NAME_INFORMATIONSizeOf(FILE_NAME_INFORMATION) * 2 + 1
1赞 Ken Bourassa 8/9/2023
但是,如果 GetFileInformationByHandleEx 无论如何都返回您ERROR_INVALID_HANDLE,那么这一切可能只是一个红鲱鱼。

答: 暂无答案