Я пишу C ++ DLL для подключения к базе данных MySQL. Помимо прочего, он пытается добавить исключение в список брандмауэра Windows, чтобы он мог подключиться к удаленному серверу MySQL через TCP (порт 3306). Когда я пытаюсь добавить порт, я получаю HRESULT
из E_ACCESSDENIED
, если я не запускаю программу от имени администратора.
Я хотел бы попросить пользователя ввести пароль администратора, но только тогда, когда порт еще не находится в списке исключений. Это означает, что я не могу просто создать UAC манифест, с момента установки level="requireAdministrator"
насколько я могу судить, всегда будет запрашивать пароль администратора. Можно ли условно вызвать приглашение администратора?
По вашему запросу я делаю ответ из своего комментария.
Правильный способ сделать это — позволить пользователям вашей DLL самим справиться с ситуацией. Как разработчик API это определенно не Ваша задача беспокоиться о таких вещах, как брандмауэр: либо пользователь API и / или конечный пользователь позаботились о том, чтобы он работал, либо вы потерпели неудачу. Как уже говорили другие, существует множество причин, по которым конечный пользователь не может ответить на запрос UAC (например, на сервере без монитора), поэтому вы не должны полагаться на то, что ваша DLL используется в интерактивном контексте. Это просто не ваша ответственность.
если ты действительно Я должен продолжить с вашей первоначальной идеей (которая, я еще раз подчеркиваю, это плохая идея, ИМХО), мой лучший выбор будет разделить вашу DLL на две части:
.exe
с манифестом, требующим прав администратора, который будет запускаться вашей DLL только при необходимости.Просто сделайте это обязательным условием, чтобы оба хранились в одном и том же каталоге, чтобы вы могли легко найти ваши DLL (и, следовательно, .exe
s) каталог с GetModuleFileName
,
Другие указали runas
или же RunDll
(которые в равной степени действительны ответы IMO), но я больше похож на Unix-y, поэтому я и предложил отдельный бинарный файл. Я нахожу это намного легче поддерживать в долгосрочной перспективе.
Решение «промежуточное» будет состоять в том, что ваша DLL вообще не работает с брандмауэром (как и должно быть), но вы предоставляете совершенно отдельный инструмент (.exe
с манифестом), который помогает вашим пользователям правильно настроить брандмауэр, когда это необходимо. Это может быть лучшим решением: чистый дизайн (разделение ответственности), и все же вы предоставляете пользователям все необходимые инструменты.
Невозможно повысить привилегии приложения после его запуска. В вашем случае, одним из обходных путей является использование ShellExecuteEx
запустить небольшое внешнее приложение с повышенными привилегиями и добавить туда исключение брандмауэра. Как только исключение будет добавлено, выполните необходимую очистку и выйдите. Затем вы можете дождаться завершения приложения, прежде чем продолжить выполнение.
Много слава Коди Грей для указания почему RunDll не должен использоваться и дополнительный запись в блоге Раймонда Чена содержащий больше информации о проблемах с RunDll
Вы можете перезапустить вашу программу, используя ShellExecuteEx с глаголом «runas», когда вы получаете E_ACCESSDENIED. Что-то вроде этого
wchar_t szPath[MAX_PATH];
if (GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath)))
{`enter code here`
// Launch itself as administrator.
SHELLEXECUTEINFO sei = { sizeof(sei) };
sei.lpVerb = L"runas";
sei.lpFile = szPath;
sei.lpParameters=L"admin";
sei.nShow = SW_NORMAL;
if (!ShellExecuteEx(&sei))
{
DWORD dwError = GetLastError();
if (dwError == ERROR_CANCELLED)
{
ExitProcess(0);
}
}
else
{
ExitProcess(0);
}
}