2010-01-12 162 views
4

我希望一個進程始終在用戶級別運行。無論是由安裝程序(自定義,而不是msi)啓動(運行於管理員級別),還是用戶登錄時。環顧四周,我不確定這是可能的。如何在較高級別啓動用戶級別的exe

回答

1

每個人都一直在尋找轉向另一種方式。 Anyhoo,這個code project應該有所幫助。

1

有很多哈克的方式來做到這一點(使用的TaskScheduler,注入到explorer.exe的等)

,以獲得正確的用戶(即UAC提升之前就開始你的程序的一個(只有這樣,這可能不是與shell /「login」/「會話所有者」是相同的用戶))是讓安裝程序運行它自己的兩個實例,一個沒有提升的「外部」實例,它大多隻是啓動另一個實例,帶有runas動詞的ShellExecute [Ex]。當啓動中/低級進程時,由某種形式的IPC提升的實例會告訴外部實例啓動新進程。

這是一個痛苦的脖子實施,我會建議只是有一個運行復選框在您的安裝程序的末尾。

+0

這很好,但不是「唯一」(正確)的方式。您可以在不注入的情況下調用IShellDispatch2 :: ShellExecute。 – Alex 2015-01-06 08:17:54

+0

@Alexander:IShellDispatch2將以與Explorer.exe相同的用戶身份執行,該用戶可能不是「正確的」用戶,並且在cmd.exe外殼的服務器核心上根本無法工作... – Anders 2015-01-06 20:24:08

0

類似於Bill所說的,你也可以使用CreateProcessAsUser()API來做到這一點。

  1. 首先使用LogonUser()並獲取進程需要運行的用戶的訪問令牌。這裏如果用戶屬於管理員組(那麼如果您將LOGON_FLAG作爲LOGON32_LOGON_INTERACTIVE傳遞,您將獲得拆分令牌)。因此,如果您需要提升的管理員令牌,請將該標誌作爲LOGON32_LOGON_BATCH傳遞。
  2. 使用上面獲得的令牌,可以調用CreateProcessAsUser()傳遞命令行和參數。
1

最簡單的方法是有2個進程。一個是普通用戶,它啓動升級/管理進程。然後管理進程可以使用IPC來請求正常的用戶進程執行任務。

如果沒有正常的用戶進程,然後Raymond Chen文件:

從unelevated過程要提升的過程很簡單。您可以通過passing the runas verb向ShellExecute或ShellExecuteEx運行具有高程的進程。

另一種方式更棘手。一方面,要讓你的標記正確移除標高屬性真的很難。另一方面,即使你能做到,也不是正確的做法,因爲未升級的用戶可能與升級的用戶不同。

這裏的解決方案是回到資源管理器並要求資源管理器爲您啓動程序。由於資源管理器以原始未升級的用戶身份運行,程序(在本例中爲Web瀏覽器)將以Bob身份運行。這對於您要打開的文件的處理程序作爲進程內擴展而不是作爲單獨的進程運行也很重要,因爲在這種情況下,嘗試進行非篩選將毫無意義,因爲沒有創建新進程第一個地方。 (如果文件的處理程序試圖與其自身的未發佈副本進行通信,則由於UIPI,事情可能會失敗。)

好的,我知道小程序不應該有動力,但我忍不住自己。足夠的jabber。我們來編寫代碼吧。 (請記住,小程序很少或沒有錯誤檢查,因爲這是他們推出的方式。)

#define STRICT 
#include <windows.h> 
#include <shldisp.h> 
#include <shlobj.h> 
#include <exdisp.h> 
#include <atlbase.h> 
#include <stdlib.h> 

void FindDesktopFolderView(REFIID riid, void **ppv) 
{ 
CComPtr<IShellWindows> spShellWindows; 
spShellWindows.CoCreateInstance(CLSID_ShellWindows); 

CComVariant vtLoc(CSIDL_DESKTOP); 
CComVariant vtEmpty; 
long lhwnd; 
CComPtr<IDispatch> spdisp; 
spShellWindows->FindWindowSW(
    &vtLoc, &vtEmpty, 
    SWC_DESKTOP, &lhwnd, SWFO_NEEDDISPATCH, &spdisp); 

CComPtr<IShellBrowser> spBrowser; 
CComQIPtr<IServiceProvider>(spdisp)-> 
    QueryService(SID_STopLevelBrowser, 
        IID_PPV_ARGS(&spBrowser)); 

CComPtr<IShellView> spView; 
spBrowser->QueryActiveShellView(&spView); 

spView->QueryInterface(riid, ppv); 
}  

void GetDesktopAutomationObject(REFIID riid, void **ppv) 
{ 
CComPtr<IShellView> spsv; 
FindDesktopFolderView(IID_PPV_ARGS(&spsv)); 
CComPtr<IDispatch> spdispView; 
spsv->GetItemObject(SVGIO_BACKGROUND, IID_PPV_ARGS(&spdispView)); 
spdispView->QueryInterface(riid, ppv); 
} 

的GetDesktopAutomationObject功能定位桌面文件夾視圖,然後詢問視圖的派遣對象。然後,我們以調用者請求的形式返回該調度對象。這個dispatch對象是一個ShellFolderView,而它的C++接口是IShellFolderViewDual,所以大多數callres都會要求這個接口,但是如果你是一個受虐狂者,你可以跳過雙接口並直接與IDispatch對話。

void ShellExecuteFromExplorer(
    PCWSTR pszFile, 
    PCWSTR pszParameters = nullptr, 
    PCWSTR pszDirectory = nullptr, 
    PCWSTR pszOperation = nullptr, 
    int nShowCmd   = SW_SHOWNORMAL) 
{ 
CComPtr<IShellFolderViewDual> spFolderView; 
GetDesktopAutomationObject(IID_PPV_ARGS(&spFolderView)); 
CComPtr<IDispatch> spdispShell; 
spFolderView->get_Application(&spdispShell); 

CComQIPtr<IShellDispatch2>(spdispShell) 
    ->ShellExecute(CComBSTR(pszFile), 
        CComVariant(pszParameters ? pszParameters : L""), 
        CComVariant(pszDirectory ? pszDirectory : L""), 
        CComVariant(pszOperation ? pszOperation : L""), 
        CComVariant(nShowCmd)); 
} 

ShellExecuteFromExplorer函數首先獲取桌面文件夾自動化對象。我們使用桌面不是因爲它特別有意義,而是因爲我們知道它總是會在那裏。

與桌面文件夾視圖一樣,ShellFolderView對象本身對我們來說並不感興趣。這對我們很有趣,因爲對象駐留在託管桌面視圖的過程中(這是主瀏覽器進程)。在ShellFolderView中,我們要求Application屬性,以便我們可以訪問主Shell.Application對象,該對象具有IShellDispatch接口(及其擴展IShellDispatch2到IShellDispatch6)作爲其C++接口。這是我們真正想要的IShellDispatch2 :: ShellExecute方法。

我們用適當的參數調用IShellDispatch2 :: ShellExecute。請注意,IShellDispatch2 :: ShellExecute的參數與ShellExecute的參數順序不同!

好的,讓我們把它放在一個小程序中。

int __cdecl wmain(int argc, wchar_t **argv) 
{ 
if (argc < 2) return 0; 

CCoInitialize init; 
ShellExecuteFromExplorer(
    argv[1], 
    argc >= 3 ? argv[2] : L"", 
    argc >= 4 ? argv[3] : L"", 
    argc >= 5 ? argv[4] : L"", 
    argc >= 6 ? _wtoi(argv[5]) : SW_SHOWNORMAL); 

return 0; 
} 

該程序採用必須執行的命令行參數,它是一個程序或文檔或URL。可選參數是正在執行的參數,要使用的當前目錄,要執行的操作以及應該如何打開窗口的參數。

打開提升的命令提示符,然後以各種方式運行該程序。

  • 劃傷http://www.msn.com/
    打開用戶的默認Web瀏覽器的unelevated網頁。
  • scratch cmd.exe「」C:\ Users「」3
    在C:\ Users處打開未升級的命令提示符,最大化。
  • 從頭開始C:\ Path \ To \ Image.bmp「」「」編輯
    在未放置的圖像編輯器中編輯位圖。
+0

非常有幫助。謝謝。它很好地工作。不幸的是,你必須小心不要過早地調用FindWindowSW。如果在桌面啓動之前調用它,它將返回S_FALSE和NULL指針。在Windows 10計算機上安裝新用戶時,我們會看到很多。我們的代碼在完成之前觸發。 – tdemay 2017-04-19 22:35:29