我正在尝试在Windows中使用和卷ID启动.exe
文件。该卷没有字母。这是我尝试过的。
当我使用卷ID调用ShellExecute
时,Windows的资源管理器会打开正确的目录。如果我尝试打开卷内的文件夹,也是一样的。但是,如果我尝试打开exe文件,则不会发生任何事情。
这就是我调用ShellExecute的方式,它是windows.h
的一部分:
char path[MAX_PATH] = R"(\\?\Volume{0dc7f9cc-d3ea-11e4-824b-806e6f6e6963}\App.exe)";
LONG_PTR returnValue = (LONG_PTR) ShellExecute(GetDesktopWindow(),NULL, path,NULL,NULL,SW_SHOW);
返回的错误代码是2:
系统找不到指定的文件。
在发表评论之后,我现在正在使用。我的新代码如下所示:
char path[MAX_PATH] = R"(\\?\Volume{0dc7f9cc-d3ea-11e4-824b-806e6f6e6963}\launcher.exe)";
STARTUPINFO info = {sizeof(info)};
PROCESS_INFORMATION processInfo;
if (CreateProcessW(path, NULL, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &info, &processInfo))
{
WaitForSingleObject(processInfo.hProcess, INFINITE);
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
}
else {
DWORD dw = GetLastError();
printf("ERROR CODE: %d", dw);
}
但它仍然无效。错误是相同的(2)。
从"\\?\Volume{ID}"
到"\\.\Volume{ID}"
。
奇怪的是,我可以列出驱动器的文件或启动控制台进程,但我无法启动任何GUI EXE文件。错误代码仍为2。
我在这里想念的是什么?欢迎任何帮助。谢谢。
我对评论感到困惑,使用"\\.\Volume{ID}\myApp.exe"
如果与CreateProcess一起使用效果很好,而不是CreateProcessW。
有完整功能的代码(别忘了包含windows.h
)。
char path[MAX_PATH] = R"(\\.\Volume{0dc7f9cc-d3ea-11e4-824b-806e6f6e6963}\App.exe)";
STARTUPINFO info = {sizeof(info)};
PROCESS_INFORMATION processInfo;
if (CreateProcess(path, NULL, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &info, &processInfo))
{
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
}
else
{
DWORD dw = GetLastError();
printf("ERROR CODE WHILE STARTING: %d", dw);
}
答案 0 :(得分:1)
问题 - 它不使用native NT Paths的native,而是Win32 Paths,它在传递给内核之前首先必须转换为NT Paths。
某些功能,例如ShellExecuteEx
或CreateProcessW
,不接受任何有效 win32路径,但只接受限制子集 - 所谓的驱动器信件表单。如果表单\\?\Volume{guid}\*
- ShellExecuteEx
和CreateProcessW
中的传递路径始终因此路径(所谓的卷路径)失败,即使路径正确(CreateFileW
打开此路径)。有趣的是CreateProcessW
将使用路径\\.\Volume{guid}\*
(如果在?
位置将.
替换为[2]
),但ShellExecuteEx
无法使用此路径太。
此处只有一个可靠的解决方案 - 将此卷表单路径转换为 Drive Letter 表单。这可以通过帮助IOCTL_MOUNTMGR_QUERY_POINTS
完成 - 需要获取系统中所有MOUNTMGR_MOUNT_POINT
的列表,并按此列表执行2个循环 - 首先通过现有卷符号链接找到设备名称。然后在循环#2中 - 通过已知的设备名称找到 - dos-device name并获得驱动器号
#include <mountmgr.h>
ULONG NtVolumePathToDosPath(PUNICODE_STRING VolumePath)
{
if (!MOUNTMGR_IS_NT_VOLUME_NAME(VolumePath))
{
return ERROR_PATH_NOT_FOUND;
}
static volatile UCHAR guz;
PVOID stack = alloca(guz);
ULONG cb = 0, rcb = 0x400;
union {
PVOID buf;
PMOUNTMGR_MOUNT_POINTS pmmp;
};
HANDLE hFile = CreateFile(MOUNTMGR_DOS_DEVICE_NAME, FILE_GENERIC_READ, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hFile == INVALID_HANDLE_VALUE)
{
return GetLastError();
}
static MOUNTMGR_MOUNT_POINT mmp;
ULONG dwError = NOERROR;
do
{
if (cb < rcb) cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
if (!DeviceIoControl(hFile, IOCTL_MOUNTMGR_QUERY_POINTS, &mmp, sizeof(mmp), buf, cb, &rcb, 0))
{
dwError = GetLastError();
rcb = pmmp->Size;
continue;
}
dwError = ERROR_PATH_NOT_FOUND;
if (ULONG NumberOfMountPoints = pmmp->NumberOfMountPoints)
{
PMOUNTMGR_MOUNT_POINT MountPoints = pmmp->MountPoints;
//loop #1: search for DeviceName linked to VolumePath
do
{
UNICODE_STRING SymbolicLinkName = {
MountPoints->SymbolicLinkNameLength,
SymbolicLinkName.Length,
(PWSTR)RtlOffsetToPointer(pmmp, MountPoints->SymbolicLinkNameOffset)
};
if (MOUNTMGR_IS_VOLUME_NAME(&SymbolicLinkName))
{
if (RtlEqualUnicodeString(&SymbolicLinkName, VolumePath, TRUE))
{
// found DeviceName
UNICODE_STRING _DeviceName = {
MountPoints->DeviceNameLength,
_DeviceName.Length,
(PWSTR)RtlOffsetToPointer(pmmp, MountPoints->DeviceNameOffset)
};
NumberOfMountPoints = pmmp->NumberOfMountPoints;
MountPoints = pmmp->MountPoints;
// loop #2: search for "drive letter" linked to DeviceName
do
{
UNICODE_STRING DeviceName = {
MountPoints->DeviceNameLength,
DeviceName.Length,
(PWSTR)RtlOffsetToPointer(pmmp, MountPoints->DeviceNameOffset)
};
if (RtlEqualUnicodeString(&_DeviceName, &DeviceName, FALSE))
{
SymbolicLinkName.MaximumLength = SymbolicLinkName.Length = MountPoints->SymbolicLinkNameLength;
SymbolicLinkName.Buffer = (PWSTR)RtlOffsetToPointer(pmmp, MountPoints->SymbolicLinkNameOffset);
if (MOUNTMGR_IS_DRIVE_LETTER(&SymbolicLinkName))
{
PWSTR szVolumePath = VolumePath->Buffer + 48;
*--szVolumePath = ':';
*--szVolumePath = SymbolicLinkName.Buffer[12];
*--szVolumePath = '\\';
*--szVolumePath = '?';
*--szVolumePath = '\\';
*--szVolumePath = '\\';
VolumePath->Buffer = szVolumePath;
dwError = NOERROR;
break;
}
}
} while (MountPoints++, --NumberOfMountPoints);
break;
}
}
} while (MountPoints++, --NumberOfMountPoints);
}
break;
} while (dwError == ERROR_MORE_DATA);
CloseHandle(hFile);
return dwError;
}
ULONG TestExecByVolumePath(PCWSTR szVolumePath)
{
size_t size = wcslen(szVolumePath) * sizeof(WCHAR);
if (size >= MAXUSHORT || size < 98)
{
return ERROR_PATH_NOT_FOUND;
}
UNICODE_STRING VolumePath;
VolumePath.Length = 96;
VolumePath.MaximumLength = (USHORT)size + sizeof(WCHAR);
memcpy(VolumePath.Buffer = (PWSTR)alloca(VolumePath.MaximumLength), szVolumePath, VolumePath.MaximumLength);
if (!MOUNTMGR_IS_DOS_VOLUME_NAME(&VolumePath))
{
return ERROR_PATH_NOT_FOUND;
}
VolumePath.Buffer[1] = '?';
ULONG dwErr = NtVolumePathToDosPath(&VolumePath);
if (dwErr == NOERROR)
{
SHELLEXECUTEINFOW sei = {sizeof(sei), 0, 0, L"open", VolumePath.Buffer, 0, 0, SW_SHOWDEFAULT };
if (!ShellExecuteExW(&sei))
{
dwErr = GetLastError();
}
}
return dwErr;
}
TestExecByVolumePath(L"\\\\?\\Volume{***}\\Windows\\System32\\notepad.exe");