从卷ID

时间:2017-05-30 11:06:30

标签: c winapi shellexecute

我正在尝试在Windows中使用和卷ID启动.exe文件。该卷没有字母。这是我尝试过的。

的ShellExecute

当我使用卷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:

  

系统找不到指定的文件。

CreateProcessW

在发表评论之后,我现在正在使用。我的新代码如下所示:

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);
}

1 个答案:

答案 0 :(得分:1)

win32子系统中的

问题 - 它不使用native NT Paths的native,而是Win32 Paths,它在传递给内核之前首先必须转换为NT Paths

某些功能,例如ShellExecuteExCreateProcessW,不接受任何有效 win32路径,但只接受限制子集 - 所谓的驱动器信件表单。如果表单\\?\Volume{guid}\* - ShellExecuteExCreateProcessW中的传递路径始终因此路径(所谓的卷路径)失败,即使路径正确(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");