Problems using PInvoke to read a PhysicalDrive

J

Jerry

I am trying to read a physical sector off of the disk (the boot sector
for drive C:) from C#. I have no problems doing it from a C/C++
application using the Win32 API CreateFile and ReadFile. However, when
I attempt to use PInvoke to do the very same thing in C# the data read
in is somehow being altered from what is on disk. Several of the bytes
are being changed from their original value to 0x3f!?!?!

Anyone have any ideas as to what I am doing wrong? I have tried to use
others suggestions and create a FileStream from the file handle, but
all I get at runtime is a "The Parameter is incorrect" exception
thrown!?! So, I am trying to stick with ReadFile since it actually
will perform the read for now.

Below is the portion of the code which performs the calls to
CreateFile/ReadFile.

[StructLayout(LayoutKind.Sequential)]
public struct OVERLAPPED
{
public uint Internal;
public uint InternalHigh;
public uint Offset;
public uint OffsetHigh;
public int hEvent;
}

[DllImport("kernel32", SetLastError=true)]
static extern int CreateFile(
string filename,
uint desiredAccess,
uint shareMode,
IntPtr attributes,
uint creationDisposition,
uint flagsAndAttributes,
IntPtr templateFile);

[DllImport("kernel32", SetLastError=true)]
public static extern Boolean CloseHandle ( int handle );

[DllImport("kernel32.dll",SetLastError=true)]
public static extern Boolean ReadFile(
IntPtr hFile,
Byte[] buffer,
UInt32 BytesToRead,
ref UInt32 BytedRead,
OVERLAPPED OverLapped);
static int EIGHT_K = 8192;
static int FIVE_TWELVE_BYTES = 512;
static uint GENERIC_READ = 0x80000000;
static uint OPEN_EXISTING = 3;
static uint FILE_SHARE_READ = 0x00000001;
static uint FILE_SHARE_WRITE = 0x00000002;

public bool Create()
{
int fileHandle = 0;
bool returnVal = true;
try
{
// Open the device specified (Using the boot partition)
string deviceName = @"\\.\C:";
fileHandle = CreateFile ( deviceName, GENERIC_READ, FILE_SHARE_READ |
FILE_SHARE_WRITE, (IntPtr)0, OPEN_EXISTING, 0, (IntPtr)0);
if ( fileHandle != -1 )
{
Byte [] sector = new Byte[EIGHT_K];

UInt32 bytesRead = (uint) EIGHT_K;
OVERLAPPED ol = new OVERLAPPED();

bool worked = ReadFile ( (IntPtr) fileHandle, sector, (uint)
EIGHT_K, ref bytesRead, ol);
if ( worked == false || bytesRead != EIGHT_K )
{
returnVal = false;
}
..
..
 
M

MuZZy

Jerry said:
I am trying to read a physical sector off of the disk (the boot sector
for drive C:) from C#. I have no problems doing it from a C/C++
application using the Win32 API CreateFile and ReadFile. However, when
I attempt to use PInvoke to do the very same thing in C# the data read
in is somehow being altered from what is on disk. Several of the bytes
are being changed from their original value to 0x3f!?!?!

Anyone have any ideas as to what I am doing wrong? I have tried to use
others suggestions and create a FileStream from the file handle, but
all I get at runtime is a "The Parameter is incorrect" exception
thrown!?! So, I am trying to stick with ReadFile since it actually
will perform the read for now.

Below is the portion of the code which performs the calls to
CreateFile/ReadFile.

[StructLayout(LayoutKind.Sequential)]
public struct OVERLAPPED
{
public uint Internal;
public uint InternalHigh;
public uint Offset;
public uint OffsetHigh;
public int hEvent;
}

[DllImport("kernel32", SetLastError=true)]
static extern int CreateFile(
string filename,
uint desiredAccess,
uint shareMode,
IntPtr attributes,
uint creationDisposition,
uint flagsAndAttributes,
IntPtr templateFile);

[DllImport("kernel32", SetLastError=true)]
public static extern Boolean CloseHandle ( int handle );

[DllImport("kernel32.dll",SetLastError=true)]
public static extern Boolean ReadFile(
IntPtr hFile,
Byte[] buffer,
UInt32 BytesToRead,
ref UInt32 BytedRead,
OVERLAPPED OverLapped);
static int EIGHT_K = 8192;
static int FIVE_TWELVE_BYTES = 512;
static uint GENERIC_READ = 0x80000000;
static uint OPEN_EXISTING = 3;
static uint FILE_SHARE_READ = 0x00000001;
static uint FILE_SHARE_WRITE = 0x00000002;

public bool Create()
{
int fileHandle = 0;
bool returnVal = true;
try
{
// Open the device specified (Using the boot partition)
string deviceName = @"\\.\C:";
fileHandle = CreateFile ( deviceName, GENERIC_READ, FILE_SHARE_READ |
FILE_SHARE_WRITE, (IntPtr)0, OPEN_EXISTING, 0, (IntPtr)0);
if ( fileHandle != -1 )
{
Byte [] sector = new Byte[EIGHT_K];

UInt32 bytesRead = (uint) EIGHT_K;
OVERLAPPED ol = new OVERLAPPED();

bool worked = ReadFile ( (IntPtr) fileHandle, sector, (uint)
EIGHT_K, ref bytesRead, ol);
if ( worked == false || bytesRead != EIGHT_K )
{
returnVal = false;
}
.
.
.
}

Could you post a working example which would produce that problem with 0x3F?
 
J

Jerry

Here you go. If after running this code you open c:\sector.dat and
look at byte number 24 is is set to 0x3f, and it should be 0x20. This
is only one example of many characters changed from their original
value to 0x3f. I hope this helps. Thank you for your time.

using System;
using System.Runtime.InteropServices;
using System.IO;

namespace CSharpSectorTest
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class Class1
{
public class BootSector
{
[StructLayout(LayoutKind.Sequential)]
public struct OVERLAPPED
{
public uint Internal;
public uint InternalHigh;
public uint Offset;
public uint OffsetHigh;
public int hEvent;
}

[DllImport("kernel32", SetLastError=true)]
static extern int CreateFile(
string filename,
uint desiredAccess,
uint shareMode,
IntPtr attributes,
uint creationDisposition,
uint flagsAndAttributes,
IntPtr templateFile);

[DllImport("kernel32", SetLastError=true)]
public static extern Boolean CloseHandle ( int handle );

[DllImport("kernel32.dll",SetLastError=true)]
public static extern Boolean ReadFile(
IntPtr hFile,
Byte[] buffer,
UInt32 BytesToRead,
ref UInt32 BytedRead,
OVERLAPPED OverLapped);


static int EIGHT_K = 8192;
static int FIVE_TWELVE_BYTES = 512;
static uint GENERIC_READ = 0x80000000;
static uint OPEN_EXISTING = 3;
static uint FILE_SHARE_READ = 1;
static uint FILE_SHARE_WRITE =2;

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
int fileHandle = 0;
bool returnVal = true;

try
{
// Open the device specified (Using the boot partition)
string deviceName = @"\\.\C:";
fileHandle = CreateFile ( deviceName, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE, (IntPtr)0, OPEN_EXISTING, 0,
(IntPtr)0);
if ( fileHandle != -1 )
{
Byte [] sector = new Byte[EIGHT_K];
UInt32 bytesRead = (uint) EIGHT_K;
OVERLAPPED ol = new OVERLAPPED();

// Can't get a FileStream ctor to work so I am using Win32 API
ReadFile
bool worked = ReadFile ( (IntPtr) fileHandle, sector, (uint)
EIGHT_K, ref bytesRead, ol);
if ( worked == true && bytesRead == EIGHT_K )
{
//Write to the specified file
Char [] outdata = new Char[sector.Length];
sector.CopyTo( outdata, 0);

StreamWriter sw = new StreamWriter ( @"c:\sector.dat", false,
System.Text.Encoding.Default );
sw.Write ( outdata, 0, EIGHT_K );
sw.Close ();
return;
}
}
}
catch ( Exception ex )
{
return;
}
finally
{
CloseHandle(fileHandle);
}
return;
}
}
}
}
 
M

Mattias Sjögren

[DllImport("kernel32.dll",SetLastError=true)]
public static extern Boolean ReadFile(
IntPtr hFile,
Byte[] buffer,
UInt32 BytesToRead,
ref UInt32 BytedRead,
OVERLAPPED OverLapped);


The last parameter (overlapped) should be a ref parameter.

I recommend you try to find correct declarations at
http://www.pinvoke.net



Mattias
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top