Ошибка ShellExecuteEx на USB-накопителе с защитой от записи?
Я пытаюсь протестировать приложение на USB-накопителе с защитой от записи, я хочу использовать API-интерфейс ShellExecuteEx (мне нужно использовать этот вызов API, потому что мне нужен вызов lpVerb:= "runas") для выполнения второй программы, но я продолжайте получать "Ошибка защиты от записи" с вызовом ShellExecuteEx. Я не могу понять, что пытается записать на диск, у меня нет кода, который пишет на диск, и я даже использовал последнюю версию Microsoft Standard User Analyzer и Application Verifier, чтобы попытаться проверить, что пытается записать на диск. ехать без успеха. Вот ошибка, которую я продолжаю получать:
[Ошибка защиты от записи]
Ничто в следующем коде не пытается записать на этот диск, API ShellExecuteEx вызывает неправильный способ сделать то, что я пытаюсь сделать? Если нет, как я могу получить эту ошибку при появлении. Любая помощь будет принята с благодарностью.
[WP-ON.reg]
REGEDIT4
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\StorageDevicePolicies]
"WriteProtect"=dword:00000001
[WP-OFF.reg]
REGEDIT4
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\StorageDevicePolicies]
"WriteProtect"=dword:00000000
ПРИМЕЧАНИЕ. Вы должны извлекать и повторно вставлять устройство каждый раз при обновлении реестра.
[project1.dpr]
program project1;
{.$APPTYPE CONSOLE}
uses
Windows, SysUtils;
begin
Windows.MessageBox(Windows.GetActiveWindow(),
PChar('Hello World!'), PChar('project1'), MB_OK);
end.
[launch.manifest]
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity processorArchitecture="x86" version="2.0.1.0" name="eyeClaxton.asInvoker.Launch" type="win32" />
<description>asInvoker Launch</description>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" publicKeyToken="6595b64144ccf1df" language="*" processorArchitecture="x86" />
</dependentAssembly>
</dependency>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
</assembly>
[launch.dpr]
program launch;
uses
Windows, ShellAPI;
{$R 'MANIFEST.RES'}
procedure ShellEx(const theFilename, theParams: string);
function RunAsAdmin(): Boolean;
var
OSVerInfo: TOSVersionInfo;
begin
OSVerInfo.dwOSVersionInfoSize := System.SizeOf(OSVerInfo);
Result := (Windows.GetVersionEx(OSVerInfo)) and (OSVerInfo.dwMajorVersion > 5);
end;
var
ShellExInfo: TShellExecuteInfo;
Directory: array[0..MAX_PATH] of Char;
begin
Windows.ZeroMemory(@ShellExInfo, System.SizeOf(ShellExInfo));
ShellExInfo.cbSize := System.SizeOf(TShellExecuteInfo);
ShellExInfo.Wnd := Windows.GetActiveWindow();
ShellExInfo.nShow := SW_SHOWNORMAL;
ShellExInfo.fMask := SEE_MASK_FLAG_NO_UI;
if (RunAsAdmin()) then // If OS is greater than Windows XP
ShellExInfo.lpVerb := PChar('runas');
Windows.ZeroMemory(@Directory, System.SizeOf(Directory));
Windows.GetCurrentDirectory(SizeOf(Directory), Directory);
ShellExInfo.lpDirectory := PChar(string(Directory));
ShellExInfo.lpFile := PChar('"' + string(Directory) + '\' + theFilename + '"');
ShellExInfo.lpParameters := PChar('"' + theParams + '"');
//
// ShellExecuteEx causes a "Write Protect" error to popup.
//
if (not ShellAPI.ShellExecuteEx(@ShellExInfo)) then
Windows.MessageBox(Windows.GetActiveWindow(),
PChar('File ' + ShellExInfo.lpFile + ' not found!'),
PChar('asInvoker Launch'), MB_OK or MB_ICONERROR);
end;
begin
ShellEx('project1.exe', System.ParamStr(1));
end.
1 ответ
Проблема заключается в том, ShellExecuteEx
это довольно сложный процесс, начиная новый фоновый поток, затем вызывая много COM-вещей. По соображениям безопасности запись должна быть включена где-то.
Вы можете попытаться отключить UAC. Но не хорошее решение.
Когда вы посмотрите на соответствующие решения для повышения прав процесса программно (проводной манифест - еще один статический способ повышения прав), вы можете найти только два, указанных в этом ответе SO:
- Используйте ShellExecuteEx с
runas
параметр; - Создайте COM-объект с повышенными правами с волшебным префиксом "Elevation:Administrator! New:".
Стоит прочитать всю статью "Vista UAC: полное руководство", чтобы понять, как работает ShellExecuteEx.
Итак, вот мой ответ: поскольку вам нужно запустить процесс с повышенными правами, а API-интерфейс CreateProcessElevated не существует, а имеется только хороший большой ShellExecute, проще всего использовать файл манифеста для второго исполняемого файла.
Если вы хотите, чтобы файл project1.exe запускался с правами "AsInvoker", но только с правами администратора, у вас есть две возможности:
- Используйте внешний
.manifest
файл, и не вставляйте файл в исполняемый файл как ресурс - затем замените.manifest
контент с одной версией с параметром "AsInvoker" или "requireAdministrator" - но трудный для чтения только на носителе, не так ли:; - Используйте внешний 3-й исполняемый файл (назовем его
Elevate.exe
), содержащий манифест с уровнем "requireAdministrator", который запустит второй исполняемый файл. Вы можете предоставить exe и командную строку в качестве параметра для этогоElevate.exe
программа.