James346
James346

Reputation: 197

C# Pinvoke invalid file handle

I'm having a problem with kernal32 Pinvoke functions as they keeps throwing an INVALID_FILE_HANDLE. The program reads the first sector of the current hard disk. I can't see what is wrong with the following code.

    class Program
    {
    const uint GENERIC_READ = 0x80000000;
    const uint FILE_SHARE_READ = 0x00000001;
    const uint OPEN_EXISTING = 0x00000003;
    const uint FILE_FLAG_DELETE_ON_CLOSE = 0x04000000;

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern SafeFileHandle CreateFile(string Disk, uint Access, uint ShareMode, IntPtr SecurityAttributes, uint CreationDisposition, uint Flags, IntPtr TemplateFile);
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern uint SetFilePointer([In] SafeFileHandle Handle, [In] int DistanceToMove, [Out] out int DistanceToMoveHigh, [In] int MoveMethod);
    [DllImport("kernel32.dll", SetLastError = true)]
    unsafe public static extern int ReadFile(SafeFileHandle Handle, [Out] byte[] Buffer, int NumberOfBytesToRead, out int NumberOfBytesRead, IntPtr Overlapped);



    unsafe public static void Main(string[] args)
    {
        string Drive = @"\\.\C";
        int SectorSize = 512;
        int Sector = 0;
        int BytesRead, DistanceToMoveHigh;
        byte[] Buffer = new byte[SectorSize];

        SafeFileHandle Handle = CreateFile(Drive, GENERIC_READ, FILE_SHARE_READ, IntPtr.Zero, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, IntPtr.Zero);
        SetFilePointer(Handle, Sector * SectorSize, out DistanceToMoveHigh, 0);
        ReadFile(Handle, Buffer, SectorSize, out BytesRead, IntPtr.Zero);

        Console.WriteLine(Marshal.GetLastWin32Error()); // It gives 6 which translates to an INVALID_FILE_HANDLE error
        Console.ReadKey();
    }
}

Upvotes: 0

Views: 1099

Answers (2)

David Heffernan
David Heffernan

Reputation: 612854

Your call to CreateFile fails. Of course you cannot know that because you omitted any error checking. Read the documentation. Errors for all three functions that you call are signaled by the return value. Which you ignore.

Your call to CreateFile returns INVALID_HANDLE_VALUE. You need to test for that. When you encounter that, and only then, call GetLastWin32Error. Likely ERROR_ACCESS_DENIED will be returned then.

  • Passing FILE_FLAG_DELETE_ON_CLOSE is a mistake. Remove that flag.
  • I believe that the share flags must be FILE_SHARE_READ | FILE_SHARE_WRITE.
  • The file name must be @"\\.\C:" with a trailing colon.
  • And you will need the process to be executed elevated.

Upvotes: 3

René Vogt
René Vogt

Reputation: 43876

You use GetLastWin32Error in a wrong way.

The method that fails here is CreateFile and it returns an INVALID_HANDLE_VALUE (indicating that it failed). To determine what went wrong you have to call GetLastWin32Error directly after CreateFile.
When you call it after trying to read, the error is of course ERROR_INVALID_HANDLE (6) as you passed an invalid handle to ReadFile.

If you call GetLastWin32Error directly after the failing CreateFile you get error 2:

The system cannot find the file specified.

That is because the the drive name misses a :

string Drive = @"\\.\C:"; // <- add colon :

I tried with that drive name, but then got the error 32:

The process cannot access the file because it is being used by another process.

I keep trying to figure out how that can be handled...

Upvotes: 0

Related Questions