【问题标题】:Open Directory Using CreateFile使用 CreateFile 打开目录
【发布时间】:2012-04-17 20:13:51
【问题描述】:

我正在尝试利用 CreateFile 函数来访问目录信息。但是,我收到一个 5 的 win32 错误代码,这意味着访问被拒绝。请指教。

CreateFile(path, GENERIC_READ, FILE_SHARE_READ, IntPtr.Zero, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, IntPtr.Zero);

这是正在进行的调用,如文档中所述,正在使用“FILE_FLAG_BACKUP_SEMANTICS”。 DLL 导入似乎工作正常,如下所示:

[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr CreateFile(string filename,
                                    uint desiredAccess,
                                    uint sharedMode,
                                    IntPtr securityAttributes,
                                    uint creationDisposition,
                                    uint flagsAndAttributes,
                                    IntPtr templateFile);

更新:我需要获取目录的句柄,这样我才能使用 GetFileInformationByHandle() 并提取唯一 ID。此方法目前适用于文件,目前不适用于目录。

更新:这个问题的 X 是我需要一个目录的唯一标识符,该标识符不是其绝对路径。即使目录被移动或重命名,它也需要保持不变。 .NET没有提供刚才提到的任何唯一标识符,只能通过win32来实现

【问题讨论】:

  • 这看起来确实是一个 XY 问题。为什么使用 API 而不是内置功能? meta.stackexchange.com/a/66378/171858
  • 我需要 C# 文件 API 未提供的信息,它需要使用 Win32 调用
  • 您需要什么信息?
  • 我需要获取目录的句柄,这样我才能使用 GetFileInformationByHandle() 并提取唯一 ID。此方法目前适用于文件,目前不适用于目录。
  • 广告,也许?我猜它是权限问题,直截了当。

标签: c# winapi directory createfile


【解决方案1】:

首先,您应该在应用程序中包含清单,以确保它在管理员权限下运行。然后您应该使用AdjustTokenPrivileges API 启用SE_BACKUP_NAME 权限。那么我建议你使用FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE 标志作为sharedMode。现在您应该可以使用CreateFile 打开目录句柄并使用GetFileInformationByHandle 获取BY_HANDLE_FILE_INFORMATION

已更新:或许以下简单的演示程序可以帮助您

#include <windows.h>
#include <tchar.h>

int _tmain()
{
    HANDLE hAccessToken = NULL;
    HANDLE hFile = INVALID_HANDLE_VALUE;

    __try {
        LUID luidPrivilege;
        DWORD dwErrorCode;
        BY_HANDLE_FILE_INFORMATION fiFileInfo;

        // -----------------------------------------------------
        // first of all we need anable SE_BACKUP_NAME privilege
        // -----------------------------------------------------
        if (!OpenProcessToken (GetCurrentProcess(),
                               TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
                               &hAccessToken))
            __leave;

        if (LookupPrivilegeValue (NULL, SE_BACKUP_NAME, &luidPrivilege)) {
            TOKEN_PRIVILEGES tpPrivileges;
            tpPrivileges.PrivilegeCount = 1;
            tpPrivileges.Privileges[0].Luid = luidPrivilege;
            tpPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
            AdjustTokenPrivileges (hAccessToken, FALSE, &tpPrivileges, 
                                   0, NULL, NULL);
            if ((dwErrorCode = GetLastError ()) != ERROR_SUCCESS)
                __leave;
        }
        else
            __leave;

        // -----------------------------------------------------
        // now one can open directory and get 
        // -----------------------------------------------------
        hFile = CreateFile (TEXT("C:\\"),
                            0, //GENERIC_READ, 
                            0, //FILE_SHARE_READ, //FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
                            NULL,
                            OPEN_EXISTING, 
                            FILE_FLAG_BACKUP_SEMANTICS,
                            NULL);
        if (hFile == INVALID_HANDLE_VALUE)
            __leave;
        if (!GetFileInformationByHandle (hFile, &fiFileInfo))
            __leave;

        _tprintf(TEXT("VolumeSerialNumber: 0x%08X\n"), fiFileInfo.dwVolumeSerialNumber);
        _tprintf(TEXT("FileIndex: 0x%08X%08X\n"), fiFileInfo.nFileIndexHigh, fiFileInfo.nFileIndexLow);
    }
    __finally {
        if (hFile != INVALID_HANDLE_VALUE)
            CloseHandle (hFile);
        if (hAccessToken != NULL)
            CloseHandle (hAccessToken);
    }

    return 0;
}

程序打开C:\ 目录并显示卷序列号和文件索引,它们标识了NTFS 上的目录。为了使程序更短,我删除了所有错误消息(请参阅__leave 语句)。就像我之前已经提到的那样,您应该使用 requireAdministrator 作为“UAC 执行级别”(请参阅​​链接器设置的“清单文件”部分)。上面的代码已经过测试,它对我有用。您可以在 C# 中重现相同的代码。

【讨论】:

    【解决方案2】:

    更新:也许以下简单的演示程序可以帮助您...

    我尝试了 SetFileTime() 但它是错误的。我已经修改了:

    hFile = CreateFile(  TEXT("C:\\MyDirectory"),
    // 0, //GENERIC_READ,
    GENERIC_READ | GENERIC_WRITE,
    // 0, //FILE_SHARE_READ, //FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
    FILE_SHARE_READ | FILE_SHARE_WRITE,
    NULL,
    OPEN_EXISTING,
    FILE_FLAG_BACKUP_SEMANTICS,
    NULL);
    

    没关系。谢谢。安德烈。

    【讨论】:

    猜你喜欢
    • 2019-06-14
    • 2010-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-03
    • 1970-01-01
    相关资源
    最近更新 更多