Запустите мою программу от имени пользователя

2

Windows 7, Vista, Server 2008, UAC активирован

Для выполнения некоторых действий по установке необходимо указать права администратора. После этого я хочу, чтобы моя программа продолжала работать с правами, отличными от admin.

Как перезапустить его с правами администратора?


P.S.

Моя программа переустанавливается. Я не хочу распространять для него дополнительные программы. Итак, мои шаги:

  • Загрузите новую версию в temp dir
  • Перезапустить себя под правами администратора
  • Переименуйте старый exe файл и скопируйте новый exe файл из temp dir
  • Перезагрузите себя под правами, отличными от admin.
Теги:
process
uac

4 ответа

4
Лучший ответ

Thanx to Кейт Грегори для справки.

В Delphi есть рабочий код:

function RunAsUser(CommandLine, WorkDirectory: string; Wait: Boolean): Boolean;
const
  TOKEN_ADJUST_SESSIONID = $0100;
  dwTokenRights = TOKEN_QUERY or TOKEN_ASSIGN_PRIMARY or TOKEN_DUPLICATE or TOKEN_ADJUST_DEFAULT or TOKEN_ADJUST_SESSIONID;
var
  WExe, WCmdLine, wCurrDir: WideString;
  hProcessToken, dwLastErr, retLength, hwnd, dwPID, hShellProcess, hShellProcessToken, hPrimaryToken: Cardinal;
  tkp: TOKEN_PRIVILEGES;
  PI: TProcessInformation;
  SI: TStartupInfoW;
begin
  Result:= False;

  hShellProcessToken:= 0;
  hPrimaryToken:= 0;
  hShellProcess:= 0;

  if WorkDirectory = '' then WorkDirectory:= GetCurrentDir;
  Wexe:= SeparateText(CommandLine, ' ');
  WCmdLine:= CommandLine;
  wCurrDir:= WorkDirectory;

    // Enable SeIncreaseQuotaPrivilege in this process.  (This won't work if current process is not elevated.)
    if not OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, hProcessToken) then Exit;

  tkp.PrivilegeCount:= 1;
  LookupPrivilegeValueW(nil, SE_INCREASE_QUOTA_NAME, tkp.Privileges[0].Luid);
  tkp.Privileges[0].Attributes:= SE_PRIVILEGE_ENABLED;
  AdjustTokenPrivileges(hProcessToken, FALSE, tkp, 0, nil, retLength);
  dwLastErr:= GetLastError();
  CloseHandle(hProcessToken);
  if (dwLastErr <> ERROR_SUCCESS) then Exit;

    // Get an HWND representing the desktop shell.
    // CAVEATS:  This will fail if the shell is not running (crashed or terminated), or the default shell has been
    // replaced with a custom shell.  This also won't return what you probably want if Explorer has been terminated and
    // restarted elevated.

    hwnd:= GetShellWindow();
  if hwnd = 0 then Exit;

  // Get the PID of the desktop shell process.
  GetWindowThreadProcessId(hwnd, dwPID);
  if dwPID = 0 then Exit;

  // Open the desktop shell process in order to query it (get the token)
  hShellProcess:= OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwPID);
  if hShellProcess = 0 then Exit;

  // From this point down, we have handles to close, so make sure to clean up.
  try
    // Get the process token of the desktop shell.
    if not OpenProcessToken(hShellProcess, TOKEN_DUPLICATE, hShellProcessToken) then Exit;

    // Duplicate the shell process token to get a primary token.
    // Based on experimentation, this is the minimal set of rights required for CreateProcessWithTokenW (contrary to current documentation).
    if not DuplicateTokenEx(hShellProcessToken, dwTokenRights, nil, SecurityImpersonation, TokenPrimary, hPrimaryToken) then Exit;

    SI.cb:= SizeOf(SI);
    FillChar(SI, SI.cb, 0);
    SI.wShowWindow:= SW_SHOWNORMAL;
    SI.dwFlags:= STARTF_USESHOWWINDOW;

    // Start the target process with the new token.
    Result:= CreateProcessWithTokenW(
      hPrimaryToken,
      0,
      PWideChar(WExe),
      PWideChar(wCmdLine),
      0,
      nil,
      PWideChar(wCurrDir),
      @si,
      @pi);

    if not Result then Exit;

    if Wait then
      while MsgWaitForMultipleObjects(1, PI.hProcess, False, INFINITE, QS_ALLINPUT) <> WAIT_OBJECT_0 do
        ProcessMessages;

    CloseHandle(PI.hProcess);
  finally
    // Clean up resources
    CloseHandle(hShellProcessToken);
      CloseHandle(hPrimaryToken);
    CloseHandle(hShellProcess);
  end;
end;
4

В UAC выполнение чего-либо "при первом запуске" теперь сильно обескуражено. Кроме того, программы, которые обновляют себя, используя технику "roll-your-own", усложнят работу. Вы говорите, что не хотите распространять дополнительные программы, но в UAC у вас действительно мало выбора. Либо все ваше приложение запускается каждый раз при повышении (раздражает пользователя) в случае, если вам нужно сделать что-то административное, или вы разделите его на две части, и запустите один повышающийся время от времени, а другой - не повышающийся все время.

Один из способов разделить его - написать установщик, который поднимает, и обычное приложение, а это не так. Это работает для людей, которые устанавливают один раз, делают некоторые вещи при первом запуске (вы переносите эти вещи в установщик), а затем выполняются. Вы говорите, что ваше приложение обновляется. Поэтому вам нужно переместить этот код в отдельный exe и поместить манифест на этот exe, у которого есть requireAdministrator. Затем ваше основное приложение запустит (используя ShellExecute) обновление exe, когда появится новое обновление.

  • 0
    Я знаю, как решить мою проблему, используя две программы. Но мне было интересно сделать это таким образом. И я просто хочу знать, могу ли я запустить в процессе администратора другой процесс с правами не администратора. Если это невозможно - просто подтвердите это.
  • 3
    Запуск не повышенного процесса из повышенного может быть сделано. Ссылки на gregcons.com/KateBlog/…
Показать ещё 1 комментарий
1

Я думаю, что вы ошибетесь в этом. На мой взгляд, вы должны сделать одно из следующих действий:

  • Выполняйте действия по установке во время установки программного обеспечения и требуйте, чтобы установка имела права администратора.

или

  • Начать как не-администратор и запрашивать возвышение, когда вам нужно выполнить некоторые действия. Таким образом, вам не нужно перезапускать программу.

Изменить: Таким образом, шаги:

  • Проверить наличие новой версии и загрузить при необходимости
  • Оповестить пользователя о наличии новой версии и запросить возвышение
  • Переименование/копирование действий
  • Обычно перезагружается

Для запроса высоты нет необходимости перезапуска. Возможно, вы захотите использовать этот способ при работе в средах до Vista.

  • 0
    Моя программа переустанавливает себя. Я не хочу распространять какие-либо дополнительные программы для этого. Итак, мои шаги: 1. Скачать новую версию в temp dir. 2. Перезагрузите себя с правами администратора. 3. Переименуйте старый exe-файл и скопируйте новый exe-файл из временного каталога. 4. Перезагрузите себя без прав администратора
  • 0
    Смотрите мое редактирование с предложениями.
Показать ещё 2 комментария
0

Здесь используется простой метод перезапуска;

procedure Restart(RunAs: Boolean);
var
  i: Integer;
  Params: string;
begin
// Close handle to Mutex or any such thing if only one inst. is allowed

// Prepare to re-pass parameters if the application uses them
  Params := '';
  for i := 1 to ParamCount do
    Params := Params + ' "' + ParamStr(i) + '"';

  Application.MainForm.Close;
  Application.ProcessMessages;
  if RunAs then
    ShellExecute(0, 'runas', PChar(ParamStr(0)), PChar(Params), '', SW_SHOW)
  else
    ShellExecute(0, 'open', PChar(ParamStr(0)), PChar(Params), '', SW_SHOW);
end;
  • 0
    Я уже пробовал этот метод, но ShellExecute (0, 'open', PChar (ParamStr (0)), PChar (Params), '', SW_SHOW) не работают должным образом: в процессе, запущенном с правами администратора, эта команда запускает процесс также с правами администратора.
  • 0
    @LionSoft - действительно.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню