What this class is for?
CFloppyDisk is a class that allows you to read and write physical floppy disk
sectors directly. The class provides static member functions for resetting the
floppy disk controller, for reading a physical sector and for writing a physical
sector. I am using the term, physical sector, to avoid confusion with absolute
sectors.
Honestly, these three functions might as well have been put into a single
header file and distributed as a sort of source code library. But I made it a
class, so that people will find it easier to use it. These days people prefer
classes for everything.
Why this class was made?
In Windows NT/2000 we can read and write directly onto a floppy disk by using
the CreateFile API call. You can simply open \\.\A:
Unfortunately this technique will not work under Windows 95, 98 and ME. This
probably is an indicator that underneath the GUI, ME is more 98 than 2000 as is
popularly believed. Well that shortcoming is now solved. This class will serve
you well, I hope.
One class - Any OS
As I just mentioned there is a huge difference in the techniques used for
directly accessing a floppy in the NT/2K set of Operating Systems and the
Windows 9x/ME set of Operating Systems. With this class, you need not bother
with what version of Windows your program will be running on. Internally the
class has separate sets for functions, but the user can simply call the generic
functions. The class will make the required OS version checks and call the
appropriate function internally.
Requirements
- You must be running one of Windows 95/98/ME/NT/2K/XP
Using the class.
There are three static functions which you can use. Thus you should not
instantiate the class. Simply include the header file and call the static
functions directly.
ResetDisk
static void ResetDisk()
ResetDisk resets the floppy disk
controller and drive. It does not do anything to the floppy disk. But the floppy
drive's read/write head will be recalibrated. Normally you might want to start
off a series of reads and writes with a controller reset. But you must also use
this when you get an error. If you do not reset the controller after an error,
then consequent behavior of the disk controller will be random and
unpredictable.
ReadFloppyDisk
static int ReadFloppyDisk(BYTE *buffer, WORD cylinder, WORD sector, WORD head)
ReadFloppyDisk is used to read a single
physical sector into a buffer. Floppy disk sectors are 512 bytes for most
standard floppies. So buffer should be allocated at least 512 bytes. You might
want to find out the number of bytes per sector, that your floppy drive supports. The
other parameters are cylinder, sector and head which are the physical parameters
required to specify where you want to read the sector from. This function will
return 0 for success and non-zero for failure, make sure you check the return
value, always.
WriteFloppyDisk
static int WriteFloppyDisk(BYTE *buffer, WORD cylinder, WORD sector,WORD head)
WriteFloppyDisk is the analogous function
to ReadFloppyDisk that does just the
opposite. It writes the bytes contained in buffer onto the physical sector
specified by cylinder, sector and head. This function will return 0 for success
and non-zero for failure, make sure you check the return value, always.
Some points to remember
The floppy drive motor might take some time to catch up with our function
calls. These functions will not wait for that to happen. So you must be careful
that you do not do successful reads and writes onto the same sector till you are
sure the data has been successfully read from or written into the sector in
question. Often you will find that the functions return failure. This happens
because most floppy drives are now thoroughly unused or over-used and are often
in a very bad state. The quality of floppy diskettes also leaves a lot to be
desired. The solution is to loop all calls thrice.
For example, if you are performing a read or a write, call the function and
if it fails, call it again. Repeat this three times. I have found that three
times is a pretty alright number to get a reasonable success rate. Also, it
helps if you call the reset function after long operations. And please remember
that the floppy drive is the slowest working part in your computer and keep that
in mind. What that means is, don't try to rush it. If you are writing critical
information into a sector, perhaps for copy protection, then it would be a good
idea to use a Sleep in between.
Example usage
void CCFloppyDiskTestDlg::OnButton1()
{
unsigned char buff[512];
strcpy((char*)buff,"This is kinda cool");
CFloppyDisk::ResetDisk();
if(CFloppyDisk::WriteFloppyDisk(buff,3,1,0)==NISH_ERROR)
MessageBox("write failed");
if(CFloppyDisk::ReadFloppyDisk(buff,3,1,0)==NISH_ERROR)
MessageBox("read failed");
MessageBox((char*)buff);
}
How to loop calls to improve success rate.
int m_return_code;
int count=0;
while(m_return_code=CFloppyDisk::ReadFloppyDisk(buff,3,1,0))
{
count++;
if(count==3)
break;
}
if(m_return_code)
{
MessageBox("After three attempts, we still failed. Destroy the floppy");
}
Technical Note regarding ResetDisk
Under Windows NT/2K we cannot directly make Interrupt 13h calls. For the Win
9x/ME set of Operating Systems the class makes a call to Interrupt 13h Function
0h which resets the floppy disk controller. To achieve the same in the Windows
NT/2K set of Operating Systems, I have taken a different approach.
Initially I took the mistaken attitude that Windows NT/2K will not have
resetting problems, but unfortunately I was wrong. Then I was stuck with the
problem of resetting the internal buffers and error flags that NT/2K maintains
when a floppy disk is directly opened. That's when I found out that all I had to
do was to open the floppy disk and then close it immediately. I tried this out
with bad floppies. And my success percentage improved from a very low 20% to
almost 95% [I still got the occasional error]. But that can be improved to
99.999% by using the triple-loop method I have mentioned above. I believe what
happens is that when we close the file handle, NT/2K flushes its internal
buffers. This might internally result in a resetting of the floppy drive. I am
not certain about this but that inference seems highly probable.
Version History
- Version 2.0 - This now supports Windows 95/98/ME/NT/2K/XP
- Version 1.0 - This supported only Windows 95/98/ME
Acknowledgements
Todd C. Wilson - It was Todd who suggested that I write a combined
version of the class that supports both sets of Operating Systems. I owe version
2.0 to Todd.
Michael Dunn & Tim Smith - As you might observe, if you look
through the source code, the entire functionality of the class is implemented
via static functions. And I badly wanted some kind of static construction for
some of my static members via calls to static functions. Without Tim's and
Mike's help, I'd still have been sitting here puzzled and swearing at Microsoft.
Nish is a real nice guy who has been writing code since 1990 when he first got his hands on an 8088 with 640 KB RAM. Originally from sunny Trivandrum in India, he has been living in various places over the past few years and often thinks it’s time he settled down somewhere.
Nish has been a Microsoft Visual C++ MVP since October, 2002 - awfully nice of Microsoft, he thinks. He maintains an MVP tips and tricks web site -
www.voidnish.com where you can find a consolidated list of his articles, writings and ideas on VC++, MFC, .NET and C++/CLI. Oh, and you might want to check out his blog on C++/CLI, MFC, .NET and a lot of other stuff -
blog.voidnish.com.
Nish loves reading Science Fiction, P G Wodehouse and Agatha Christie, and also fancies himself to be a decent writer of sorts. He has authored a romantic comedy
Summer Love and Some more Cricket as well as a programming book –
Extending MFC applications with the .NET Framework.
Nish's latest book
C++/CLI in Action published by Manning Publications is now available for purchase. You can read more about the book on his blog.
Despite his wife's attempts to get him into cooking, his best effort so far has been a badly done omelette. Some day, he hopes to be a good cook, and to cook a tasty dinner for his wife.