Michael Marcel
Michael Marcel

Reputation: 37

Get ProcessId that is using a file

IMPORTANT: we use DELPHI 7.

I have a problem to get the ProcessId that is using a file.

Just to let you know, in our software we need to show to the user what Process is using the file that we need.

To do that, I used NtQuerySystemInformation to get the Process list and Handle list.

After that, I used OpenProcess on those Process Ids with Handles that are files (ObjectType = 28)

And then I used DuplicateHandle to get the File Handle.

Let's see the code:

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;

So, I created GetFileNameByHandle

This function receives a File Handle from the previous code and tries to get its File Name using NtQueryInformationFile and NtQueryObject.

But, every call of NtQueryInformationFile returns STATUS_OBJECT_TYPE_MISMATCH. How can I get its File Name?

Let me show you the code of this function:

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;

After that, I compare Filenames in GetProcessIdUsingFile function to return the PID.

I used this code as a base, and tried some modifications, but nothing work:

Delphi - finding the process that is accessing a file from my program

If you guys need more information, please LMK.

Upvotes: 0

Views: 264

Answers (0)

Related Questions