3

CreateFile 関数を利用してディレクトリ情報にアクセスしようとしています。しかし、win32 エラー コード 5 を受け取りました。これは、アクセスが拒否されたことを意味します。お知らせ下さい。

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 を使用することによってのみ実現できます。

4

2 に答える 2

5

まず、アプリケーションにマニフェストを含めて、管理者権限で実行されるようにする必要があります。次に、APISE_BACKUP_NAMEを使用して特権を有効にする必要があります。AdjustTokenPrivileges次にFILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE、フラグを として使用することをお勧めしますsharedModeCreateFileこれで、 を使用してディレクトリ ハンドルを開き、 を使用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ステートメントを参照)。「UAC実行レベル」として使用する必要がある前にすでに述べたようにrequireAdministrator(リンカー設定の「マニフェストファイル」部分を参照)。上記のコードはテスト済みで、私で動作します。C# で同じコードを再現できます。

于 2012-04-18T00:18:29.570 に答える