darrylbraaten.com

Software Development and System Architecture

 

Welcome to darrylbraaten.com Sign in | Join | Help
in Search

Darryl's Homepage

Random Ramblings

StackOverflow is getting pretty good

I got into the beta for stackoverflow.com a couple of weeks ago.  I have been answering a few questions and asking a few over that time.  Even with just shy of 4000 users it is a very effective place to get answers to your programming questions.  

I was having trouble figuring out how to read directly from a device in .Net today so I decided to ask the question on stackoverflow. Within a few minutes I got the answer use CreateFile call in Win32, and the person helpfully linked to the MSDN article for CreateFile which had an example in it for what I wanted to do.  Surprisingly the offline MSDN article for CreateFile leaves out this information.  I had also forgotten that CreateFile is the master call for opening things in Win32, files, pipes, com ports, pretty much any device that moves bits around.  Though it is a bit hard to find it in the help if you don't know that to open files you need to call create.  


With that information I was able to create a little program to read the information I needed. 
using System;
using System.Runtime.InteropServices;
using System.IO;
using Microsoft.Win32.SafeHandles;
namespace ReadFromDevice
{
public class DeviceStream : Stream, IDisposable
{
public const short FILE_ATTRIBUTE_NORMAL = 0x80;
public const short INVALID_HANDLE_VALUE = -1;
public const uint GENERIC_READ = 0x80000000;
public const uint GENERIC_WRITE = 0x40000000;
public const uint CREATE_NEW = 1;
public const uint CREATE_ALWAYS = 2;
public const uint OPEN_EXISTING = 3;
// Use interop to call the CreateFile function.
// For more information about CreateFile,
// see the unmanaged MSDN reference library.
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess,
uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition,
uint dwFlagsAndAttributes, IntPtr hTemplateFile);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool ReadFile(
IntPtr hFile, // handle to file
byte[] lpBuffer, // data buffer
int nNumberOfBytesToRead, // number of bytes to read
ref int lpNumberOfBytesRead, // number of bytes read
IntPtr lpOverlapped
//
// ref OVERLAPPED lpOverlapped // overlapped buffer
);
private SafeFileHandle handleValue = null;
private FileStream _fs = null;
public DeviceStream(string device)
{
Load(device);
}
private void Load(string Path)
{
if (string.IsNullOrEmpty(Path))
{
throw new ArgumentNullException("Path");
}
// Try to open the file.
IntPtr ptr = CreateFile(Path, GENERIC_READ, 0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
handleValue = new SafeFileHandle(ptr, true);
_fs = new FileStream(handleValue, FileAccess.Read);
// If the handle is invalid,
// get the last Win32 error
// and throw a Win32Exception.
if (handleValue.IsInvalid)
{
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
}
public override bool CanRead
{
get { return true; }
}
public override bool CanSeek
{
get { return false; }
}
public override bool CanWrite
{
get { return false; }
}
public override void Flush()
{
return;
}
public override long Length
{
get { return -1; }
}
public override long Position
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
/// <summary>
/// </summary>
/// <param name="buffer">An array of bytes. When this method returns,
 the buffer contains the specified byte array with the values between offset and 
/// (offset + count - 1) replaced by the bytes read from the current source. </param>
/// <param name="offset">The zero-based byte offset in buffer at which to begin storing the
 data read from the current stream. </param>
/// <param name="count">The maximum number of bytes to be read from the current stream.</param>
/// <returns></returns>
public override int Read(byte[] buffer, int offset, int count)
{
int BytesRead =0;
var BufBytes = new byte[count];
if (!ReadFile(handleValue.DangerousGetHandle(), BufBytes, count, ref BytesRead, IntPtr.Zero))
{
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
for (int i = 0; i < BytesRead; i++)
{
buffer[offset + i] = BufBytesIdea;
}
return BytesRead;
}
public override int ReadByte()
{
int BytesRead = 0;
var lpBuffer = new byte[1];
if (!ReadFile(
handleValue.DangerousGetHandle(), // handle to file
lpBuffer, // data buffer
1, // number of bytes to read
ref BytesRead, // number of bytes read
IntPtr.Zero
))
{ Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); ;}
return lpBuffer[0];
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotImplementedException();
}
public override void SetLength(long value)
{
throw new NotImplementedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotImplementedException();
}
public override void Close()
{
handleValue.Close();
handleValue.Dispose();
handleValue = null;
base.Close();
}
private bool disposed = false;
new void Dispose()
{
Dispose(true);
base.Dispose();
GC.SuppressFinalize(this);
}
private new void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if (!this.disposed)
{
if (disposing)
{
if (handleValue != null)
{
_fs.Dispose();
handleValue.Close();
handleValue.Dispose();
handleValue = null;
}
}
// Note disposing has been done.
disposed = true;
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ReadFromDevice
{
class Program
{
private const int MB = 1024*1024;
static void Main(string[] args)
{
var reader = new BinaryReader(new DeviceStream(@"\\.\PhysicalDrive3"));
var writer = new BinaryWriter(new FileStream(@"g:\test.dat", FileMode.Create));
var buffer = new byte[MB];
int count;
int loopcount=0;
try{
while((count=reader.Read(buffer,0,MB))>0)
{
writer.Write(buffer,0,count);
System.Console.Write('.');
if(loopcount%100==0)
{
System.Console.WriteLine();
System.Console.WriteLine("100MB written");
writer.Flush();
}
loopcount++;
}
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
reader.Close();
writer.Flush();
writer.Close();
}

}
}
Published Monday, September 01, 2008 3:10 PM by darryl
Filed under:

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

No Comments

Leave a Comment

(required) 
(optional)
(required) 
Submit