以用户身份运行我的程序

Windows 7,Vista,Server 2008,UAC已激活

程序必须用pipe理员权限进行说明才能进行一些安装操作。 之后,我希望我的程序继续使用非pipe理员权限。

我怎样才能重新启动它没有pipe理权限?


PS

我的程序重新安装。 我不想分发任何额外的程序。 所以我的步骤是:

  1. 在临时目录中下载新版本
  2. 在pipe理员权限下重新启动
  3. 重命名旧的exe文件,并从临时目录复制新的exe文件
  4. 在非pipe理员权限下重新启动

Solutions Collecting From Web of "以用户身份运行我的程序"

在UAC之下,现在强烈建议不要“做第一次”做任何事情。 此外,使用自己的技术更新自己的程序会发现更加困难。 你说你不想分发额外的程序,但在UAC下,你真的没有多少选择。 要么你的整个应用程序每次都运行(恼人的用户),以防万一它需要做一些管理工作,或者你把它分成两部分,偶尔运行一个提升,另一个不提升。

一种方法来分裂它是写一个安装程序,它提升,而普通的应用程序,而不是。 这适用于安装一次的用户,在首次运行时执行一些操作(将这些内容移至安装程序),然后完成。 你说你的应用程序更新自己。 所以你需要将这个代码移动到一个单独的exe文件,并在需要管理员的那个exe文件上放置一个清单。 然后,当有新的更新可用时,您的主应用程序将启动(使用ShellExecute)更新exe。

感谢凯特格雷戈里的帮助。

德尔福有一个工作代码:

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. 检查新版本并在必要时下载
  2. 提醒用户有新版本可用并请求提升
  3. 重命名/复制操作
  4. 正常重启

请求提升不需要重新启动。 在Vista之前的环境中工作时,您可能仍然要使用这种方式。

这是一个简单的重启方法。

 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;