【发布时间】:2014-08-20 19:31:21
【问题描述】:
我有以下代码(主要部分取自 MS SDK v7.1 示例代码,它演示了如何从提升的进程启动非提升的进程)- 提升和非提升进程将在(无监督的)服务器上启动,因此用户交互是不可行的(当然,如果需要,配置部分除外)。
问题是,通过 IShellDispatch2->ShellExecute 启动的非提升进程仍然被提升(预期是非提升的)。 这已通过使用 IsUserAnAdmin() API 得到确认。 任何想法为什么通过 ShellExecute() 创建的进程确实仍然具有提升的权限?
一些更相关的细节:在我的机器上,UAC 被禁用。 基于 VS 2013 的应用程序表现在: ) (可以使用 /MANIFEST:no linker flag 禁用清单,如果它有助于解决这个问题)。 我正在使用 VS 2013 在 Windows 7 x64 上编译它。
#include <shlwapi.h>
#include <shlobj.h>
#include <comutil.h>
#pragma comment(lib, "shlwapi.lib")
// link with (at least) OleAut32.lib shlwapi.lib comsupp.lib shell32.lib uuid.lib
// sorry for the bad formatting
int main(void)
{
std::wstring processName(L"myapp.exe"), processParams(L"-myAppParam");
LPWSTR processNamePtr = const_cast<LPWSTR>(processName.c_str());
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
if (SUCCEEDED(hr))
{
IShellView *psv;
HRESULT hr = GetShellViewForDesktop(IID_PPV_ARGS(&psv));
if (SUCCEEDED(hr))
{
IShellDispatch2 *psd;
hr = GetShellDispatchFromView(psv, IID_PPV_ARGS(&psd));
if (SUCCEEDED(hr))
{
BSTR bstrProcessName = SysAllocString(processNamePtr);
hr = bstrProcessName ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
VARIANT vtEmpty = {}; // VT_EMPTY
LPWSTR processParamsPtr = const_cast<LPWSTR>(processParams.c_str());
_bstr_t bstrProcessParams(processParamsPtr);
VARIANT varParams;
varParams.vt = VT_BSTR;
varParams.bstrVal = bstrProcessParams;
char processDir[MAX_PATH + 1];
::GetCurrentDirectory(MAX_PATH, processDir);
_bstr_t bstrProcessDir(processDir);
VARIANT varProcessDir;
varProcessDir.vt = VT_BSTR;
varProcessDir.bstrVal = bstrProcessDir;
_bstr_t bstrOperation("open");
VARIANT varOperation;
varOperation.vt = VT_BSTR;
varOperation.bstrVal = bstrOperation;
hr = psd->ShellExecute(bstrProcessName,
varParams, // reinterpret_cast<_variant_t&>(bstrProcessParams),
varProcessDir,
varOperation,
vtEmpty);
SysFreeString(bstrProcessName);
SysFreeString(bstrProcessParams);
}
psd->Release();
}
psv->Release();
}
CoUninitialize();
}
} // main()
// use the shell view for the desktop using the shell windows automation to find the
// desktop web browser and then grabs its view
//
// returns:
// IShellView, IFolderView and related interfaces
HRESULT GetShellViewForDesktop(REFIID riid, void **ppv)
{
*ppv = NULL;
IShellWindows *psw;
HRESULT hr = CoCreateInstance(CLSID_ShellWindows, NULL, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&psw));
if (SUCCEEDED(hr))
{
HWND hwnd;
IDispatch* pdisp;
VARIANT vEmpty = {}; // VT_EMPTY
if (S_OK == psw->FindWindowSW(&vEmpty, &vEmpty, SWC_DESKTOP, (long*)&hwnd, SWFO_NEEDDISPATCH, &pdisp))
{
IShellBrowser *psb;
hr = IUnknown_QueryService(pdisp, SID_STopLevelBrowser, IID_PPV_ARGS(&psb));
if (SUCCEEDED(hr))
{
IShellView *psv;
hr = psb->QueryActiveShellView(&psv);
if (SUCCEEDED(hr))
{
hr = psv->QueryInterface(riid, ppv);
psv->Release();
}
psb->Release();
}
pdisp->Release();
}
else
{
hr = E_FAIL;
}
psw->Release();
}
return hr;
} // GetShellViewForDesktop()
// From a shell view object gets its automation interface and from that gets the shell
// application object that implements IShellDispatch2 and related interfaces.
HRESULT GetShellDispatchFromView(IShellView *psv, REFIID riid, void **ppv)
{
*ppv = NULL;
IDispatch *pdispBackground;
HRESULT hr = psv->GetItemObject(SVGIO_BACKGROUND, IID_PPV_ARGS(&pdispBackground));
if (SUCCEEDED(hr))
{
IShellFolderViewDual *psfvd;
hr = pdispBackground->QueryInterface(IID_PPV_ARGS(&psfvd));
if (SUCCEEDED(hr))
{
IDispatch *pdisp;
hr = psfvd->get_Application(&pdisp);
if (SUCCEEDED(hr))
{
hr = pdisp->QueryInterface(riid, ppv);
pdisp->Release();
}
psfvd->Release();
}
pdispBackground->Release();
}
return hr;
} // GetShellDispatchFromView()
【问题讨论】: