FAQ VCL
Windows

:: Меню ::
:: На главную ::
:: FAQ ::
:: Заметки ::
:: Практика ::
:: Win API ::
:: Проекты ::
:: Скачать ::
:: Секреты ::
:: Ссылки ::

:: Сервис ::
:: Написать ::

:: MVP ::

:: RSS ::

Яндекс.Метрика

Как получить имя файла оболочки?

uses
  Winapi.TlHelp32, System.Win.Registry;

procedure TForm1.Button1Click(Sender: TObject);

 function ShellWindow: HWND;
 type
   TGetShellWindow = function(): HWND; stdcall;
 var
   hUser32: THandle;
   GetShellWindow: TGetShellWindow;
 begin
    Result := 0;
    hUser32 := GetModuleHandle('user32.dll');
    if (hUser32 > 0) then
    begin
       @GetShellWindow := GetProcAddress(hUser32, 'GetShellWindow');
       if Assigned(GetShellWindow) then
          Result := GetShellWindow;
    end;
 end;

 function ReadFromRegistry: string;
 const
   szReg = 'SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon';
   szKey = 'Shell';
 var
   Reg: TRegistry;
 begin
    Result := '';

    Reg := TRegistry.Create;
    try
       // Сначала ищем в HKEY_CURRENT_USER
       Reg.RootKey := HKEY_CURRENT_USER;
       if Reg.OpenKeyReadOnly(szReg) then
          Result := Reg.ReadString(szKey);
       if Result = '' then
       begin
          // Reg.CloseKey;
          // Посмотрим в HKEY_LOCAL_MACHINE
          Reg.RootKey := HKEY_LOCAL_MACHINE;
          if Reg.OpenKeyReadOnly(szReg) then
             Result := Reg.ReadString(szKey);
       end;
    finally
       Reg.CloseKey;
       Reg.Free;
    end;
 end;

var
  hWnd, hProc: Cardinal;
  hSnapshot: NativeUInt;
  pe32: TProcessEntry32;
begin
   // Недостаток FindWindow - ничто не мешает любому приложению создать
   // окно с классом "Progman", а при отсутствии запущенного штатного
   // шелла это гарантированно приведет к неверным результатам.
   // hWnd := FindWindow('Progman', nil);

   hWnd := ShellWindow;
   if hWnd > 0 then
   begin
      GetWindowThreadProcessId(hWnd, hProc);
      if hProc > 0 then
      begin
         hSnapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
         if (hSnapshot = -1) then
            Exit;

         pe32.dwSize := SizeOf(TProcessEntry32);
         if Process32First(hSnapshot, pe32) then
         repeat
            if pe32.th32ProcessID = hProc then
               ShowMessage(pe32.szExeFile);
         until not Process32Next(hSnapshot, pe32);

         CloseHandle (hSnapshot);
      end;
   end
   else
      // Если функция GetShellWindow вернула ошибку, то скорее всего в системе
      // используется альтернативный шелл и придется заглянуть в реестр.
      ShowMessage(ReadFromRegistry);
end;


Как получить системный разделитель целой части числа от дробной?

function GetDecimalSeparator: Char;
var
  DefaultLCID: Integer;
begin
   if IsValidLocale(GetUserDefaultLCID, LCID_INSTALLED) then
      DefaultLCID := GetUserDefaultLCID
   else
      DefaultLCID := GetThreadLocale;
   Result := GetLocaleChar(DefaultLCID, LOCALE_SDECIMAL, '.');
end;


Как отловить перезапуск Explorer'а после аварийного завершения?

type
  TForm1 = class(TForm)
  protected
    procedure ClientWndProc(var Msg: TMessage); override;
  end;

implementation

var
  WM_TASKBARCREATED: Cardinal;

procedure TForm1.ClientWndProc(var Msg: TMessage);
begin
   inherited WndProc(Msg);

   if Msg.Msg = WM_TASKBARCREATED then
      {...};
end;

initialization
  WM_TASKBARCREATED := RegisterWindowMessage('TaskbarCreated');


Как узнать об изменении региональных настроек?

type
  TForm1 = class(TForm)
  private
    procedure WMSettingChange(var Msg: TWMSettingChange); message WM_SETTINGCHANGE;
    {...}
  end;
  Form1: TForm1;

implementation

procedure TForm1.WMSettingChange(var Msg: TWMSettingChange);
const
  CM_CHANGEFORMAT = WM_USER + 101;
begin
   // Обновляем свои собственные настройки
   PostMessage(Handle, CM_CHANGEFORMAT, 0, 0);
   Msg.Result := 0;
   inherited;
   ShowMessage('Региональные настройки были изменены');
end;


Как уведомить все приложения об изменении региональных настроек?

procedure TForm1.Button1Click(Sender: TObject);
begin
   // Меняем региональные настройки...
   // ...и уведомляем об этом все приложения
   SendNotifyMessage(HWND_BROADCAST, WM_WININICHANGE, SPI_SETNONCLIENTMETRICS, 0);
   // Фцнкции SendXXX отправляют сообщение другому окну немедленно, вызывая его
   // оконную процедуру, в то время как функции PostXXX посылают сообщение другому
   // окну постановкой сообщения в очередь потока, ассоциированного с этим самым
   // окном. Однако пользоваться функцией PostMessage не рекомендуется. Если вызвать
   // ее при запущенном экземпляре Excel, приложение может подвиснуть, ожидая обработки
   // отправленного собщения. А ждать этого можно ну оооочень долго, порой проще взять
   // да и "срубить" процесс Excel. Лучше воспользоваться функцией SendNotifyMessage,
   // которая не ждет обработки сообщения и возвращает управление сразу после отправки.
end;


Как скрыть кнопки меню по Ctrl+Alt+Del в Win7/Vista?

// Скрываем кнопки:
//  • Блокировать компьютер
//  • Сменить пользователя
//  • Выйти из системы
//  • Сменить пароль...
//  • Запустить диспетчер задач
//  • Отмена
// https://msdn.microsoft.com/en-us/library/ms815238.aspx?f=255&MSPPError=-2147217396

uses
  {...,} Registry;

/// 
///   Сокрытие кнопок
/// 
procedure TForm1.Button1Click(Sender: TObject);
var
  Reg: TRegistry;
begin
   try
      Reg := TRegIniFile.Create;
      Reg.RootKey := HKEY_LOCAL_MACHINE;
      if Reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\Policies\System', True) then
      begin
         // Сменить пользователя
         Reg.WriteInteger('HideFastUserSwitching', 1);
         Reg.CloseKey;
      end;
      Reg.RootKey := HKEY_CURRENT_USER;
      if Reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\Policies\System', True) then
      begin
         // Блокировать компьютер
         Reg.WriteInteger('DisableLockWorkstation', 1);
         // Сменить пароль...
         Reg.WriteInteger('DisableChangePassword', 1);
         // Запустить диспетчер задач
         Reg.WriteInteger('DisableTaskMgr', 1);
         Reg.CloseKey;
      end;
      if Reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\Policies\Explorer', True) then
      begin
         // Выйти из системы
         Reg.WriteInteger('NoLogoff', 1);
         // Выключить компьютер
         Reg.WriteInteger('NoClose', 1);
         Reg.Free;
      end;
   except
      ShowMessage('У Вас нет прав администратора.');
   end;
end;

/// 
///   Отображение кнопок
/// 
procedure TForm1.Button2Click(Sender: TObject); //отображение кнопок
var
  Reg: TRegistry;
begin
   try
      Reg := TRegIniFile.Create;
      Reg.RootKey := HKEY_LOCAL_MACHINE;
      if Reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\Policies\System', True) then
      begin
         // Сменить пользователя
         Reg.WriteInteger('HideFastUserSwitching', 0);
         Reg.CloseKey;
      end;
      Reg.RootKey:=HKEY_CURRENT_USER;
      if Reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\Policies\System', True) then
      begin
         // Блокировать компьютер
         Reg.WriteInteger('DisableLockWorkstation', 0);
         // Сменить пароль...
         Reg.WriteInteger('DisableChangePassword', 0);
         // Запустить диспетчер задач
         Reg.WriteInteger('DisableTaskMgr', 0);
         Reg.CloseKey;
      end;
      if Reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\Policies\Explorer', True) then
      begin
         // Выйти из системы
         Reg.WriteInteger('NoLogoff', 0);
         // Выключить компьютер
         Reg.WriteInteger('NoClose', 0);
         Reg.Free;
      end;
   except
      ShowMessage('У Вас нет прав администратора.');
   end;
end;


Как получить полный путь исполняемого файла по PID процесса?

// Способ первый
uses
  {...,} PsAPI;
  
// Результат работы функции зависит от разрядности компилируемого приложения.
// В 32-bit версии получится получить пути только к 32-bit приложениям,
// выполняемым в 64-bit версии Windows.
function GetFullPathFromPID(PID: Cardinal): string;
var
  hProcess: THandle;
  ModName: array[0..MAX_PATH+1] of Char;
begin
   Result := '';

   hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, PID);
   try
      if hProcess <> 0 then
      begin
         if GetModuleFileNameEx(hProcess, 0, ModName, Sizeof(ModName)) <> 0 then
            Result := ModName;
//         else
//            ShowMessage(SysErrorMessage(GetLastError));
      end;
   finally
      CloseHandle(hProcess);
   end;
end;

// Способ второй
// Функция вернет путь в виде "C:\..."
function QueryFullProcessImageName(hProcess: THandle; dwFlags: DWORD;
  lpExeName: PChar; nSize: PDWORD): BOOL; stdcall; external kernel32
  name 'QueryFullProcessImageName' + {$IFDEF UNICODE}'W'{$ELSE}'A'{$ENDIF};

function GetProcImageName(PID: Cardinal): string;
const
  PROCESS_QUERY_LIMITED_INFORMATION = $1000;
var
  hProcess: THandle;
  MaxLen: DWORD;
begin
   Result := '';
   hProcess := OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, False, PID);
   if (hProcess <> 0) and (hProcess <> INVALID_HANDLE_VALUE) then
   try
      MaxLen := MAX_PATH;
      SetLength(Result, MaxLen);

      if not QueryFullProcessImageName(hProcess, 0, PChar(Result), @MaxLen) then
         Result := '';
   finally
      CloseHandle(hProcess);
   end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
   ShowMessage(GetProcImageName(4864));
end;

// Способ третий
// Функция вернет путь в виде "\Device\HarddiskVolume1\..."
function GetProcessImageFileName(hProcess: THandle; lpImageFileName: PChar;
  nSize: DWORD): BOOL; stdcall; external 'psapi.dll'
  name 'GetProcessImageFileName' + {$IFDEF UNICODE}'W'{$ELSE}'A'{$ENDIF};

function GetProcImageFileName(PID: Cardinal): string;
const
  PROCESS_QUERY_LIMITED_INFORMATION = $1000;
var
  hProcess: THandle;
  MaxLen: DWORD;
begin
   Result := '';
   hProcess := OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, False, PID);
   if (hProcess <> 0) and (hProcess <> INVALID_HANDLE_VALUE) then
   try
      MaxLen := MAX_PATH;
      SetLength(Result, MaxLen);

      if not GetProcessImageFileName(hProcess, PChar(Result), MaxLen) then
         Result := '';
   finally
      CloseHandle(hProcess);
   end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
   ShowMessage(GetProcImageFileName(4864));
end;

// Способ четвертый
// Функция вернет путь в виде "C:\..."
function GetModuleFileNameEx(hProcess: THandle; hModule: THandle;
  lpFileName: PChar; nSize: PDWORD): BOOL; stdcall; external kernel32
  name 'QueryFullProcessImageName' + {$IFDEF UNICODE}'W'{$ELSE}'A'{$ENDIF};

// Если hModule равен 0, функция возвращает путь к исполняемому файлу процесса,
// указанного в hProcess, иначе возвращает путь к загруженному модулю.
function GetProcImageName(PID, hModule: Cardinal): string;
const
  PROCESS_QUERY_LIMITED_INFORMATION = $1000;
var
  hProcess: THandle;
  MaxLen: DWORD;
begin
   Result := '';
   hProcess := OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, False, PID);
   if (hProcess <> 0) and (hProcess <> INVALID_HANDLE_VALUE) then
   try
      MaxLen := MAX_PATH;
      SetLength(Result, MaxLen);

      if not GetModuleFileNameEx(hProcess, 0, PChar(Result), @MaxLen) then
         Result := '';
   finally
      CloseHandle(hProcess);
   end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
   ShowMessage(GetProcImageName(4864, 0));
end;


Как получить имя исполняемого файла по PID процесса?

uses
  {...,} PsAPI;

// Результат работы функции зависит от разрядности компилируемого приложения.
// В 32-bit версии получится получить имя только для 32-bit приложений,
// выполняемых в 64-bit версии Windows.
function GetFileNameFromPID(PID: Cardinal): string;
var
  hProcess: THandle;
  ModName: array[0..MAX_PATH+1] of Char;
begin
   Result := '';

   hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, PID);
   try
      if hProcess <> 0 then
      begin
         if GetModuleBaseName(hProcess, 0, ModName, Sizeof(ModName)) <> 0 then
            Result := ModName;
//         else
//            ShowMessage(SysErrorMessage(GetLastError));
      end;
   finally
      CloseHandle(hProcess);
   end;
end;


Как получить разрядность запущенного процесса по его PID?

function DetectWow64Process(PID: Cardinal): Boolean;
const
  PROCESS_QUERY_LIMITED_INFORMATION = $1000;
var
  hProcess: THandle;
  IsWow64: LongBool;
begin
   Result := False;

   hProcess := OpenProcess(PROCESS_ALL_ACCESS, False, PID);
   if hProcess = 0 then
      hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ or
                              PROCESS_VM_OPERATION, False, PID);

   if hProcess = 0 then
      hProcess := OpenProcess(PROCESS_QUERY_INFORMATION, False, PID);

   if hProcess = 0 then
      hProcess := OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, False, PID);

   if (hProcess <> INVALID_HANDLE_VALUE) and (hProcess <> 0) then
   try
      if IsWow64Process(hProcess, IsWow64) then
         Result := not IsWow64;
   finally
      CloseHandle(hProcess);
   end;
end;


Как получить командную строку процесса?

// Способ первый
const
  STATUS_SUCCESS = 0;

type
  NTStatus = Cardinal;
  PPPointer = ^PPointer;

  PROCESS_INFORMATION_CLASS = (
    ProcessBasicInformation,
    ProcessQuotaLimits,
    ProcessIoCounters,
    ProcessVmCounters,
    ProcessTimes,
    ProcessBasePriority,
    ProcessRaisePriority,
    ProcessDebugPort,
    ProcessExceptionPort,
    ProcessAccessToken,
    ProcessLdtInformation,
    ProcessLdtSize,
    ProcessDefaultHardErrorMode,
    ProcessIoPortHandlers,
    ProcessPooledUsageAndLimits,
    ProcessWorkingSetWatch,
    ProcessUserModeIOPL,
    ProcessEnableAlignmentFaultFixup,
    ProcessPriorityClass,
    ProcessWx86Information,
    ProcessHandleCount,
    ProcessAffinityMask,
    ProcessPriorityBoost,
    MaxProcessInfoClass);

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

  RTL_DRIVE_LETTER_CURDIR = record
    Flags:Word;
    Length:Word;
    TimeStamp:Cardinal;
    DosPath:UNICODE_STRING;
  end;

  PPEB_FREE_BLOCK=^PEB_FREE_BLOCK;
  PEB_FREE_BLOCK=record
    Next: PPEB_FREE_BLOCK;
    Size: Cardinal;
  end;

  PPEB_LDR_DATA = ^PEB_LDR_DATA;
  PEB_LDR_DATA = record
    Length: Cardinal ;
    Initialized: Boolean;
    SsHandle: Pointer;
    InLoadOrderModuleList: LIST_ENTRY;
    InMemoryOrderModuleList: LIST_ENTRY;
    InInitializationOrderModuleList: LIST_ENTRY;
    EntryInProgress: Pointer;
  end;

  PRTL_USER_PROCESS_PARAMETERS = ^RTL_USER_PROCESS_PARAMETERS;
  RTL_USER_PROCESS_PARAMETERS = record
    MaximumLength: Cardinal;
    Length: Cardinal;
    Flags: Cardinal;
    DebugFlags: Cardinal;
    ConsoleHandle: Pointer;
    ConsoleFlags: Cardinal;
    StdInputHandle: Cardinal;
    StdOutputHandle: Cardinal;
    StdErrorHandle: Cardinal;
    CurrentDirectoryPath: UNICODE_STRING;
    CurrentDirectoryHandle: Cardinal;
    DllPath: UNICODE_STRING;
    ImagePathName: UNICODE_STRING;
    CommandLine: UNICODE_STRING;
    Environment: Pointer;
    StartingPositionLeft: Cardinal;
    StartingPositionTop: Cardinal;
    Width: Cardinal;
    Height: Cardinal;
    CharWidth: Cardinal;
    CharHeight: Cardinal;
    ConsoleTextAttributes: Cardinal;
    WindowFlags: Cardinal;
    ShowWindowFlags: Cardinal;
    WindowTitle: UNICODE_STRING;
    DesktopName: UNICODE_STRING;
    ShellInfo: UNICODE_STRING;
    RuntimeData: UNICODE_STRING;
    DLCurrentDirectory: array [0..$1F] of RTL_DRIVE_LETTER_CURDIR
  end;

  PPEB = ^PEB;
  PEB = record
    InheritedAddressSpace: Boolean;
    ReadImageFileExecOptions: Boolean;
    BeingDebugged: Boolean;
    Spare: Boolean;
    Mutant: Cardinal;
    ImageBaseAddress: Pointer;
    LoaderData: PPEB_LDR_DATA;
    ProcessParameters: PRTL_USER_PROCESS_PARAMETERS;
    SubSystemData: Pointer;
    ProcessHeap: Pointer;
    FastPebLock: Pointer;
    FastPebLockRoutine: Pointer;
    FastPebUnlockRoutine: Pointer;
    EnvironmentUpdateCount: Cardinal;
    KernelCallbackTable: PPointer;
    EventLogSection: Pointer;
    EventLog: Pointer;
    FreeList: PPEB_FREE_BLOCK;
    TlsExpansionCounter: Cardinal;
    TlsBitmap: Pointer;
    TlsBitmapBits: array[0..1] of Cardinal;
    ReadOnlySharedMemoryBase: Pointer;
    ReadOnlySharedMemoryHeap: Pointer;
    ReadOnlyStaticServerData: PPointer;
    AnsiCodePageData: Pointer;
    OemCodePageData: Pointer;
    UnicodeCaseTableData: Pointer;
    NumberOfProcessors: Cardinal;
    NtGlobalFlag: Cardinal;
    Spare2: array[0..3] of byte;
    CriticalSectionTimeout: LARGE_INTEGER;
    HeapSegmentReserve: Cardinal;
    HeapSegmentCommit: Cardinal;
    HeapDeCommitTotalFreeThreshold: Cardinal;
    HeapDeCommitFreeBlockThreshold: Cardinal;
    NumberOfHeaps: Cardinal;
    MaximumNumberOfHeaps: Cardinal;
    ProcessHeaps: PPPointer;
    GdiSharedHandleTable: Pointer;
    ProcessStarterHelper: Pointer;
    GdiDCAttributeList: Pointer;
    LoaderLock: Pointer;
    OSMajorVersion: Cardinal;
    OSMinorVersion: Cardinal;
    OSBuildNumber: Cardinal;
    OSPlatformId: Cardinal;
    ImageSubSystem: Cardinal;
    ImageSubSystemMajorVersion: Cardinal;
    ImageSubSystemMinorVersion: Cardinal;
    GdiHandleBuffer: array [0..$21] of Cardinal;
    PostProcessInitRoutine: Cardinal;
    TlsExpansionBitmap: Cardinal;
    TlsExpansionBitmapBits: array [0..$7F] of byte;
    SessionId: Cardinal;
  end;

  PPROCESS_BASIC_INFORAMTION = ^PROCESS_BASIC_INFORMATION;
  PROCESS_BASIC_INFORMATION = record
    ExitStatus: NTStatus;
    PebBaseAddress: PPEB;
    AffinityMask: PCardinal;
    BasePriority: Cardinal;
    uUniqueProcessId: Cardinal;
    uInheritedFromUniqueProcessId: Cardinal;
  end;

function NtQueryInformationProcess(ProcessHandle: Cardinal;
  ProcessInformationClass: PROCESS_INFORMATION_CLASS;
  ProcessInformation: Pointer;
  ProcessInformationLength: Cardinal;
  ReturnLength: PCardinal): NTStatus; stdcall; external 'ntdll.dll';

function GetProcessCmdLine(pid: Cardinal): string;
var
  hProcess: Cardinal;
  pProcBasicInfo: PROCESS_BASIC_INFORMATION;
  ReturnLength: DWORD;
  aPeb: PEB;
  ProcessParameters: RTL_USER_PROCESS_PARAMETERS;
  cb: NativeUInt;
  ws: WideString;
begin
   Result := '';
   if pid = 0 then
      Exit;
   hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, pid);
   if hProcess <> 0 then
      if NtQueryInformationProcess(hProcess,ProcessBasicInformation, @pProcBasicInfo,
         SizeOf(PROCESS_BASIC_INFORMATION),@ReturnLength) = STATUS_SUCCESS then
      begin
         if ReadProcessMemory(hProcess, pProcBasicInfo.PebBaseAddress, @aPeb,
            SizeOf(PEB), cb) then
            if ReadProcessMemory(hProcess, aPeb.ProcessParameters,
               @ProcessParameters, SizeOf(ProcessParameters), cb) then
            begin
               SetLength(ws, ProcessParameters.CommandLine.Length div 2);
               if ReadProcessMemory(hProcess, ProcessParameters.CommandLine.Buffer,
                  PWideChar(ws), ProcessParameters.CommandLine.Length, cb) then
                  Result := ws;
            end;
      end;
   Closehandle(hProcess);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
   ShowMessage(GetProcessCmdLine(9648));
end;

// Способ второй
type
  NTSTATUS = Integer;

  PROCESS_BASIC_INFORMATION = packed record
    Reserved1: UINT64;
    PebBaseAddress: UINT64;
    Reserved2: array [0..1] of UINT64;
    UniqueProcessId: UINT64;
    Reserved3: UINT64;
  end;

  PPROCESS_BASIC_INFORMATION = ^PROCESS_BASIC_INFORMATION;

  TNtQueryInformationProcess = function(ProcessHandle: THANDLE; ProcessInformationClass:
    ULONG; ProcessInformation: Pointer; ProcessInformationLength: ULONG;
    ReturnLength: Pointer): NTSTATUS; stdcall;
  TNtReadVirtualMemory = function(ProcessHandle: THANDLE; BaseAddress: UINT64;
    Buffer: Pointer; BufferLength: UINT64; ReturnLength: Pointer): NTSTATUS; stdcall;

var
  NtQueryInformationProcess: TNtQueryInformationProcess;
  NtReadVirtualMemory: TNtReadVirtualMemory;

//function AddCurrentProcessPrivilege(PrivilegeName: WideString): Boolean;
//var
//  TokenHandle: THandle;
//  TokenPrivileges: TTokenPrivileges;
//  ReturnLength: Cardinal;
//begin
//   Result := False;
//   if OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, TokenHandle) then
//   try
//      LookupPrivilegeValueW(nil, PWideChar(PrivilegeName), TokenPrivileges.Privileges[0].Luid);
//      TokenPrivileges.PrivilegeCount := 1;
//      TokenPrivileges.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
//      if AdjustTokenPrivileges(TokenHandle, False, TokenPrivileges, 0, nil, ReturnLength) then
//         Result := True;
//   finally
//      CloseHandle(TokenHandle);
//   end;
//end;

function GetCommandLineFromPID(PID: Cardinal): string;
var
  hLibrary: HMODULE;
  ProcessHandle: THandle;
  PBI: PROCESS_BASIC_INFORMATION;
  ReturnLength: UINT64;
  Buffer: UINT64;
  Data: array [0..MAX_PATH-1] of Char;
begin
   Result := '';
//   AddCurrentProcessPrivilege('SeDebugPrivilege');

   hLibrary := LoadLibrary('ntdll.dll');
   if hLibrary <> 0 then
   begin
      @NtQueryInformationProcess := GetProcAddress(hLibrary, 'NtWow64QueryInformationProcess64');
      @NtReadVirtualMemory := GetProcAddress(hLibrary, 'NtWow64ReadVirtualMemory64');
   end;

   ProcessHandle:= OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, True, PID);

   if NtQueryInformationProcess(ProcessHandle, 0, @PBI, SizeOf(PBI), nil) = 0 then
   begin
     if NtReadVirtualMemory(ProcessHandle, PBI.PebBaseAddress + $20, @Buffer,
        SizeOf(Buffer), @ReturnLength) = 0 then
     begin
        if NtReadVirtualMemory(ProcessHandle, Buffer + $78, @Buffer, SizeOf(Buffer),
           @ReturnLength) = 0 then
        begin
           if NtReadVirtualMemory(ProcessHandle, Buffer, @Data, SizeOf(Data),
              @ReturnLength) = 0 then
              Result := String(Data);
        end;
     end;
   end;
end;

При использовании материала - ссылка на сайт обязательна