2010-07-21 7 views
2

Windows 7, Vista, Server 2008, UAC активируетсяЗапуск моей программы asUser

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

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


P.S.

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

  1. Скачать новую версию в каталог для временных файлов
  2. Restart себя под правами администратора
  3. Переименовать старый EXE-файл и скопировать новый EXE-файл из температуры дир
  4. Перезагрузите себя по неправедным правам

ответ

4

Thanx к Кейт Грегори за помощь.

Существует рабочий код на 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's 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; 
1

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

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

или

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

Edit: Так шаги будут:

  1. Проверить наличие новой версии и скачать при необходимости
  2. пользователя оповещения о том, что новая версия доступна и высота запроса
  3. Rename/копировать действия
  4. Restart обычно

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

+0

Моя программа заново себя. Я не хочу распространять для него дополнительные программы. Итак, мои шаги: 1. Загрузите новую версию в каталоге temp. 2. Перезапустите себя под правами администратора 3. Переименуйте старый exe-файл и скопируйте новый exe-файл из каталога temp. 4. Перезагрузите себя под правами не-администратора – LionSoft

+0

См. Мои изменения с предложениями. –

+0

> «..request elevation, когда вам нужно ...» - Как вы это делаете? –

4

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

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

+0

Я знаю, как решить мою проблему, используя две программы. Но мне было интересно сделать так. И я просто хочу знать, могу ли я запустить административный процесс другого процесса с правами, отличными от admin. Если это невозможно - просто подтвердите это. – LionSoft

+3

Запуск не поднятого процесса с повышенного уровня может быть выполнен. Ссылки на http://www.gregcons.com/KateBlog/NonElevatedFromElevatedManagedThisTime.aspx –

+0

Да !!!! Это действительно работает !!! Большое спасибо U. – LionSoft

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) не работают: в процессе, запущенном с admin, эта команда запускает процесс также с правами администратора. – LionSoft

+0

@ LionSoft - действительно. –

+0

«действительно» - Это был вопрос или одобрение? :) – LionSoft

Смежные вопросы