我希望一个进程始终在用户级别运行。安装程序启动时(自定义,而不是msi),在管理员级别运行,或者在用户登录时启动。环顾四周,我不确定这是可能的。
答案 0 :(得分:1)
每个人总是在寻找另一种方式。 Anyhoo,这code project应该有所帮助。
答案 1 :(得分:1)
假设您知道要运行哪个用户并拥有密码,CreateProcessWithLogonW Function就会这样做。
答案 2 :(得分:1)
有许多hacky方法可以做到这一点(使用taskscheduler,注入explorer.exe等)
获取正确用户的唯一方法(在UAC提升之前启动程序的用户(可能与shell /“login”/“session owner”不同的用户))是让安装程序运行两个它本身的实例,一个没有提升的“外部”实例,它主要是通过使用带有runas动词的ShellExecute [Ex]启动它来启动另一个实例。当启动中/低级别进程时,通过某种形式的IPC提升实例会告诉外部实例启动新进程。
实施起来很痛苦,我建议只需不在安装程序的末尾添加一个运行复选框。
答案 3 :(得分:1)
最简单的方法是拥有2个进程。一个是普通用户,它启动提升/管理过程。然后管理进程可以使用IPC来询问正常的用户进程。
如果您没有正常的用户流程,那么Raymond Chen文档:
从一个不高尚的流程转变为一个升级的流程很容易。您可以使用passing the runas verb高程运行ShellExecute或ShellExecuteEx。
走另一条路比较棘手。首先,很难让你的令牌正确地去除高程性质。而另一方面,即使你能做到这一点,也不是正确的事情,因为没有提升的用户可能与提升的用户不同。
此处的解决方案是返回资源管理器并请求Explorer为您启动该程序。由于Explorer作为原始的非高效用户运行,因此程序(在本例中为Web浏览器)将作为Bob运行。在您要打开的文件的处理程序作为进程内扩展而不是作为单独的进程运行的情况下,这也很重要,因为在这种情况下,由于没有创建新进程,因此无法进行的尝试将毫无意义。第一名。 (如果文件的处理程序试图与其自身的现有非高效副本进行通信,则由于UIPI,事情可能会失败。)
好的,我知道Little Programs不应该有动力,但我无法自拔。足够的jabber。我们来写代码。 (请记住,Little程序很少或根本没有错误检查,因为这是他们滚动的方式。)
#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函数找到桌面文件夹视图,然后请求视图的调度对象。然后,我们以调用者请求的形式返回该调度对象。这个调度对象是一个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对象对我们自身并不感兴趣。这对我们很有意思,因为对象驻留在托管桌面视图的进程中(这是主要的Explorer进程)。从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。可选参数是正在执行的事物的参数,要使用的当前目录,要执行的操作以及如何打开窗口。
打开提升的命令提示符,然后以各种方式运行此程序。
- scratch http://www.msn.com/
在用户的默认Web浏览器中打开未加载的Web页面。- scratch cmd.exe“”C:\ Users“”3
在C:\ Users打开一个无效的命令提示符,最大化。- scratch C:\ Path \ To \ Image.bmp“”“”编辑
在未加工的图像编辑器中编辑位图。
答案 4 :(得分:0)
类似于Bill所说的,你也可以使用CreateProcessAsUser()API来做到这一点。