Delphi - get what files are opened by an application

How can I get the list of opened files by an application, using Delphi? For example what files are opened by winword.exe


Using the Native API function NtQuerySystemInformation you can list all open handles from all processes.

try this example

program ListAllHandles;

{$APPTYPE CONSOLE}

uses
  PSApi,
  Windows,
  SysUtils;

const
SystemHandleInformation       = $10;
STATUS_SUCCESS               = $00000000;
STATUS_BUFFER_OVERFLOW        = $80000005;
STATUS_INFO_LENGTH_MISMATCH   = $C0000004;
DefaulBUFFERSIZE              = $100000;


type
 OBJECT_INFORMATION_CLASS = (ObjectBasicInformation,ObjectNameInformation,ObjectTypeInformation,ObjectAllTypesInformation,ObjectHandleInformation );

 SYSTEM_HANDLE=packed record
 uIdProcess:ULONG;
 ObjectType:UCHAR;
 Flags     :UCHAR;
 Handle    :Word;
 pObject   :Pointer;
 GrantedAccess:ACCESS_MASK;
 end;

 PSYSTEM_HANDLE      = ^SYSTEM_HANDLE;
 SYSTEM_HANDLE_ARRAY = Array[0..0] of SYSTEM_HANDLE;
 PSYSTEM_HANDLE_ARRAY= ^SYSTEM_HANDLE_ARRAY;

  SYSTEM_HANDLE_INFORMATION=packed record
 uCount:ULONG;
 Handles:SYSTEM_HANDLE_ARRAY;
 end;
 PSYSTEM_HANDLE_INFORMATION=^SYSTEM_HANDLE_INFORMATION;

 TNtQuerySystemInformation=function (SystemInformationClass:DWORD; SystemInformation:pointer; SystemInformationLength:DWORD;  ReturnLength:PDWORD):THandle; stdcall;
 TNtQueryObject           =function (ObjectHandle:cardinal; ObjectInformationClass:OBJECT_INFORMATION_CLASS; ObjectInformation:pointer; Length:ULONG;ResultLength:PDWORD):THandle;stdcall;

 UNICODE_STRING=packed record
    Length       :Word;
    MaximumLength:Word;
    Buffer       :PWideChar;
 end;

 OBJECT_NAME_INFORMATION=UNICODE_STRING;
 POBJECT_NAME_INFORMATION=^OBJECT_NAME_INFORMATION;

Var
 NTQueryObject           :TNtQueryObject;
 NTQuerySystemInformation:TNTQuerySystemInformation;


function GetObjectInfo(hObject:cardinal; objInfoClass:OBJECT_INFORMATION_CLASS):LPWSTR;
var
 pObjectInfo:POBJECT_NAME_INFORMATION;
 HDummy     :THandle;
 dwSize     :DWORD;
begin
  Result:=nil;
  dwSize      := sizeof(OBJECT_NAME_INFORMATION);
  pObjectInfo := AllocMem(dwSize);
  HDummy      := NTQueryObject(hObject, objInfoClass, pObjectInfo,dwSize, @dwSize);

  if((HDummy = STATUS_BUFFER_OVERFLOW) or (HDummy = STATUS_INFO_LENGTH_MISMATCH)) then
    begin
   FreeMem(pObjectInfo);
   pObjectInfo := AllocMem(dwSize);
   HDummy      := NTQueryObject(hObject, objInfoClass, pObjectInfo,dwSize, @dwSize);
  end;

  if((HDummy >= STATUS_SUCCESS) and (pObjectInfo.Buffer <> nil)) then
  begin
   Result := AllocMem(pObjectInfo.Length + sizeof(WCHAR));
   CopyMemory(result, pObjectInfo.Buffer, pObjectInfo.Length);
  end;
  FreeMem(pObjectInfo);
end;

Procedure EnumerateOpenFiles();
var
 sDummy      : string;
 hProcess    : THandle;
 hObject     : THandle;
 ResultLength: DWORD;
 aBufferSize : DWORD;
 aIndex      : Integer;
 pHandleInfo : PSYSTEM_HANDLE_INFORMATION;
 HDummy      : THandle;
 lpwsName    : PWideChar;
 lpwsType    : PWideChar;
 lpszProcess : PAnsiChar;
begin
    AbufferSize      := DefaulBUFFERSIZE;
  pHandleInfo      := AllocMem(AbufferSize);
  HDummy           := NTQuerySystemInformation(DWORD(SystemHandleInformation), pHandleInfo,AbufferSize, @ResultLength);  //Get the list of handles

  if(HDummy = STATUS_SUCCESS) then  //If no error continue
    begin

      for aIndex:=0 to pHandleInfo^.uCount-1 do   //iterate the list
      begin
    hProcess := OpenProcess(PROCESS_DUP_HANDLE or PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, FALSE, pHandleInfo.Handles[aIndex].uIdProcess);  //open the process to get aditional info
    if(hProcess <> INVALID_HANDLE_VALUE) then  //Check valid handle
        begin
     hObject := 0;
     if DuplicateHandle(hProcess, pHandleInfo.Handles[aIndex].Handle,GetCurrentProcess(), @hObject, STANDARD_RIGHTS_REQUIRED,FALSE, 0) then  //Get  a copy of the original handle
          begin
      lpwsName := GetObjectInfo(hObject, ObjectNameInformation); //Get the filename linked to the handle
      if (lpwsName <> nil)  then
            begin
       lpwsType    := GetObjectInfo(hObject, ObjectTypeInformation);
       lpszProcess := AllocMem(MAX_PATH);

       if GetModuleFileNameEx(hProcess, 0,lpszProcess, MAX_PATH)<>0 then  //get the name of the process
               sDummy:=ExtractFileName(lpszProcess)
              else
               sDummy:= 'System Process';

              Writeln('PID      ',pHandleInfo.Handles[aIndex].uIdProcess);
              Writeln('Handle   ',pHandleInfo.Handles[aIndex].Handle);
              Writeln('Process  ',sDummy);
              Writeln('FileName ',string(lpwsName));
              Writeln;

              FreeMem(lpwsName);
              FreeMem(lpwsType);
              FreeMem(lpszProcess);
      end;
      CloseHandle(hObject);
     end;
     CloseHandle(hProcess);
    end;
   end;
  end;
  FreeMem(pHandleInfo);

end;

begin
  try
    NTQueryObject            := GetProcAddress(GetModuleHandle('NTDLL.DLL'), 'NtQueryObject');
    NTQuerySystemInformation := GetProcAddress(GetModuleHandle('NTDLL.DLL'), 'NtQuerySystemInformation');
   if (@NTQuerySystemInformation<>nil) and (@NTQuerySystemInformation<>nil) then
    EnumerateOpenFiles();
    Readln;
  except
    on E:Exception do
      Writeln(E.Classname, ': ', E.Message);
  end;
end.

You could port walkobjects.cpp or run a command line process that does it for you and parse it's output.


I've looked at the MSDN page... it said NtQuerySystemInformation() is an OS internal proc, and that we're not recommended to use it:

The NtQuerySystemInformation function and the structures that it returns are internal to the operating system and subject to change from one release of Windows to another. To maintain the compatibility of your application, it is better to use the alternate functions previously mentioned instead.