Самый простой способ - это 2 процесса. Один из них - обычный пользователь, и он запускает процесс с повышенными правами / admin. Затем процесс администрирования может использовать IPC, чтобы попросить обычный пользовательский процесс сделать что-то.
Переход от невыполненного процесса к высокому процессу прост. Вы можете запустить процесс с правами на повышение , передав глагол runas ShellExecute или ShellExecuteEx.
Идти по другому пути сложнее. Во-первых, действительно трудно взломать ваш токен, чтобы правильно удалить природу возвышения. И с другой стороны, даже если бы вы могли это сделать, это не правильно, потому что пользователь без прав доступа может отличаться от пользователя с повышенными правами.
Решение здесь - вернуться в Explorer и попросить Explorer запустить программу для вас. Поскольку Explorer работает как исходный пользователь без прав, программа (в данном случае веб-браузер) будет работать как Bob. Это также важно в том случае, если обработчик файла, который вы хотите открыть, работает как расширение внутри процесса, а не как отдельный процесс, так как в этом случае попытка разрыхления была бы бессмысленной, поскольку в нем не было создано никакого нового процесса. первое место. (И если обработчик файла пытается связаться с существующей неизмененной копией самого себя, из-за UIPI все может закончиться неудачей.)
Хорошо, я знаю, что Маленькие Программы не должны иметь мотивацию, но я не мог с собой поделать. Хватит болтовни. Давайте напишем код. (Помните, что Маленькие Программы мало или совсем не проверяют ошибки, потому что так они и работают.)
#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. Необязательные параметры - это параметры выполняемой вещи, текущий используемый каталог, выполняемая операция и способ открытия окна.
Откройте командную строку с повышенными привилегиями, а затем запустите эту программу различными способами.
- царапина http://www.msn.com/
Откройте неровную веб-страницу в веб-браузере пользователя по умолчанию.
- scratch cmd.exe "" C: \ Users "" 3
Откройте неограниченную командную строку в C: \ Users, развернуто.
- scratch C: \ Path \ To \ Image.bmp "" "" edit
Отредактируйте растровое изображение в редакторе неровных изображений.