Link to home
Start Free TrialLog in
Avatar of jellison
jellison

asked on

Direct reading of disk sectors

I need to read a hard disk sector by sector using Delphi3
under W95. The disk is not the W95 system disk - the idea
is that it will be added by using a "slot-in" disk caddy.
It will have a dos partition on it but also non-dos ones
which I also need to read.
I have seen references to Vwin32.vxd and Ints 25h and 26h
but how do you access them? Any code snippets etc would be
very useful.
Avatar of Madshi
Madshi

Run "win32.help". Choose from the index listing "Calling DeviceIoControl on Windows 95". This is all I can tell you. Sorry - have no sources...

Regards, Madshi.
ASKER CERTIFIED SOLUTION
Avatar of inter
inter
Flag of Türkiye image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Sorry, Igor...

your code will definitely not work with Win95!    :-(

Regards, Madshi.
Ok, I'll dig up the 95 code tomorrow,
c.u. igor
Avatar of jellison

ASKER

Igor,
Following your answer I looked at the Win32 Help & it does suggest that using a filename
of \\.\PHYSICALDRIVEn will work with W95 although, as you said, logical partitions won't.
I did try it to see what happened but all I got was a "cannot open" result - so I guess
Madshi is right.
I look forward to your W95 solution.
Regards, JohnE.
Igor,
Are you getting anywhere with the problem?  Following your comments I have been
experimenting with the \\.\vwin32 as documented in the Win32 help file. I have managed
to read floppy disk sectors but can't get anything to read the HD? Very frustrating.

Regards, JohnE

Jellison,

how about posting your floppy disk source code here?
Then perhaps we can find out why it doesn't work with HD.

Regards, Madshi.
I am back again,
since I have no 95 I try to code it on my mind post it, then you test it and comment...etc..
OK?
Yes man, the win95 lowlevel HD operations are troublesome. But it would be much easier if you only want to READ from drive, so do you need to WRITE something on harddisk?
Yes, I only need to read. The writing is being done by another system. I will then remove
the drive, put it into my PC and try to read it.

JohnE
Hi,
The following code compiles without error but I can not run it on NT...Supply a buffer to the read sector and sector to be read (the buffer should be at least 512 bytes and test to see if it can read the data...). I just conduct the example from several sources so I AM REALLY NOT SURE but I am sure this is the way...


const
  VWIN32_DIOC_DOS_INT13 = 4;      //do not use this it requires thunking
  VWIN32_DIOC_DOS_INT25 = 2;      //Performs the Absolute Disk Read command (Interrupt 25h).
  VWIN32_DIOC_DOS_INT26 = 3;      //Performs the Absolute Disk Write command (Interrupt 25h).
  VWIN32_DIOC_DOS_IOCTL = 1;      //Performs the specified MS-DOS device I/O control function                         //(Interrupt 21h Function 4400h through 4411h).

type
 PDIOC_REGISTERS = ^TDIOC_REGISTERS;
 TDIOC_REGISTERS = packed record
    reg_EBX,
    reg_EDX,
    reg_ECX,
    reg_EAX,
    reg_EDI,
    reg_ESI,
    reg_Flags : DWORD;
 end;

function ReadSector(nSector : DWORD; var inBuffer : Pointer):boolean;
var
  hDevice : THandle;
  reg     : TDIOC_REGISTERS;
  cb      : DWORD;
const
  DRIVE_C = 2;  // Drive C:
begin
  hDevice := CreateFile('\\.\vwin32',
    0, 0, nil, 0, FILE_FLAG_DELETE_ON_CLOSE, 0);

  reg.reg_EAX := DRIVE_C;          // which drive
  reg.reg_EBX := DWORD(inBuffer);         // pointer to input buffer
  reg.reg_ECX := 1;                // how many sectors to read
  reg.reg_EDX := nSector;          // read which sector
  reg.reg_Flags := 0;              // no error


  Result := DeviceIoControl(hDevice,
    VWIN32_DIOC_DOS_INT25,
    @reg, sizeof(reg),
    @reg, sizeof(reg),
    cb, nil);

  Result := Result and ((reg.reg_Flags and $0001) = 0);

  CloseHandle(hDevice);
end;

regards, igor (wow man who says delphi is not a tool for real programmers ;-)

Wait............!!!!!!!!!!!!!!!!!
I strongly suggest you to change DRIVE_C = 0 to test the routines on floppy. If every thing ok test is on harddisk..........
Igor,

Good grief. I know more about HD drives than I ever wanted to - & I still can't make it
work. I tried Int25 and it works BUT it only supports the old bios read and is therefore
restricted to 528Mb because of the limits on sector/head/cylinder values. There is an
extended version of the call by setting CX to $FFFF but that is limited to 2Gb. I need
more and the only place I can find support for bigger drives is in extended Int13 calls
with functions $41 to $48. These address drives with Logical Block Addressing and
support huge block numbers.
Now, despite your comment re thunking (which I don't really understand) I tried some
Int13 calls using Vwin32. The strange thing is that the install check function ($41)
returns a valid response from the floppy drive (drive 0) although when I try to read it
(Func $42) I get an invalid seek. Perhaps that's to do with thunking.
When I try the install check on my HD however (drive $80 - a 4Gb drive in LBA mode
as far as the bios is concerned) it returns an invalid response. I am suspecting 3 things:
1. It's failing because of thunking
2. W95 needs some sort of lock on the HD before it will allow access
3. My bios isn't up to the job.
Before I check on (3) I would be grateful for your comments on (1) and (2).

Thanks,

JohnE
So, lets try to proceed in the following order(fm easy to hard)
1 - try to lock hd
2 - try to write thunk between our 32 bit process and 16 bit subsystem dlls (this is the basic explanation of thunking)
sorry, i can not be here for long try to dig it up tomorrow(sorry again I should go)
regards, igor
To lock/unlock the drive, call DeviceIOControl with VWIN32_DIOC_DOS_IOCTL and

            reg.reg_EAX:=$440D;                        // IOCTL for block devices
            reg.reg_EBX:=ord(drive)-ord('A')+1;        // zero-based drive ID
            reg.reg_ECX:=$084A;
            reg.reg_EDX:=0;

To unlock it again, call:

            reg.reg_EAX:=$440D;                        // IOCTL for block devices
            reg.reg_EBX:=ord(drive)-ord('A')+1;        // zero-based drive ID
            reg.reg_ECX:=$086A;

Regards, Madshi.
Thanks man,
here for a while....
Ok.. after much experimentation:

I think I have the vwin32 interface sorted out for everything but Int13 calls. I can get
successful locks on any physical drive using ECX := $084B and unlock it with
ECX := $086B. If I lock a drive then do an Int13 with AH=$41, BX=$55AA, DL=Drive
number that should tell me whether the IBM/MS extensions are valid for that drive.
If I set the drive to 0 (the A drive) the install check returns saying the extensions are
installed with bit flags indicating that I can use the IBM/MS extended functions and
that removable media extensions are valid too. If I set the drive to $80 (the HD) then I
can lock and unlock it but the extensions install check returns an error??
Theory - could this be because of thunking?  If the drive number is not being passed to
the Int function properly then 00 might work but anything else is scrambling the bits?
I have tried it on two separate machines with different bios's and HD's with exactly the same results so I don't think it's a bios problem.
So what's thunking?

Regards,

JohnE
The thunking is a mechanism to call 16bit DLL functions from within your 32 bit native code.

|32 bit APP|---->|16 bit thunk DLL|----->|16 bit DLL that performs the required operations|

You may ask why we can not call the required functions directly from 32 bit APP. For int 13 we should call DPMI functions which is not allowed by the design of the Win95. So we can only call then in asm from 16 bit code. There are several methods of thunking but the best way for win95 is to use so called 'flat thunking' with the 'undocumented' method. I have long ago learn this from one of the friends. If we use that undocumented function exported by kernel32 (callled QT_Thunk) we do not need to write 16 bit thunkDLL. So what should we do is:

1 - Create 16 bit DLL that calls the DPMI and emulates int 13 call
2 - Link that dll into our 32 bit app with QT_Thunk

Questions:
1 - Do you have 16 bit compiler (such as delphi 1.x, BC 4.5) etc...?
2 - Do you have any questions regarding the mechanism?

regards, igor (please do not disapointed we can make this out but I have no 16 bit compiler by now)
Igor,

Sorry for the delay in reply but I think the server crashed and then the net was impossibly
slow yesterday. Anyway - I do have Delphi1 and even an old TP6 somewhere but I would
like to take a step back before launching into thunking.
Where did you get the info that the Int13  calls need thunking? I have been posting a few
questions around and looking at web sites & help files, and you are the only one who has said it's required. Having said that, you have also given the most time & effort to solving the problem so please don't take it as a crticism - I just want to be sure before spending a lot of time, effort (and I suspect pain) on thunking.
Regards,
JohnE
You don't need thunking to call int13 in 32bit windows. You just CANNOT call int13 in 32bit windows - with thunking or without thunking.
So you have to call that int13 in a 16bit dll. That will work. But it doesn't solve all problems, because now is the question: How can you call the 16bit dll from your 32bit application. "LoadLibrary" and that stuff won't work.
And this is exactly the point, where you need thunking. With thunking you can't call int13. But with thunking you can call a 16bit dll. And this 16bit dll can call int13.
Everything unclear now?   :-)
Very unclear!  I understand what you are saying but..  I refer you to the Win32 Help file (not sure which version but I'm pretty sure it's OSR2). There is a page headed "Using VWIN32 to Carry Out MS-DOS Functions" which explains about using Vwin32.vxd. That documents a control code value "VWIN32_DIOC_DOS_INT13 (4)      Performs Interrupt 13h commands.". Now I can call Int13 using this mechanism and read a floppy disk - so presumably it does what it says?  Nowhere in the pages regarding Vwin32 does it say anything about thunking?  It does talk about needing to lock devices but it's not very clear. That's why I'm not sure about thunking.
Now, there are a number of virus progs out there which run under W95 and check the Master Boot Record which (as I understand it) is outside the normal logical partitions and therefore needs direct access to the disk. So how do they do it?
Regards,
JohnE
Ooops. I looked in my win32 help file. I know, some time ago there were these infos. But now I've Delphi 4 and I don't find "Using VWin32".
I trusted in Igor. He said you need thunking for int13. Perhaps he is wrong. What I wanted to say in my last comment is that you don't need thunking for calling interrupts, but for calling a 16 bit dll.
Ok, I've copied some sources from our sources at work. Psst. Please don't tell my boss about this...
With these functions you can test if the given drive has a partition table. Hope, this helps. We don't use int13 at all. Don't know if we just don't need it, or if it doesn't work. But - if it stands in your win32 help file - it should really work - and without thunking.

function DosInt25(var reg : TReg; txt : string) : boolean;
const VWIN32_DIOC_DOS_INT25 = 2;
var s1 : string;
    cb : DWORD;
    hq : THandle;
    b  : boolean;
begin
  result:=false;
  hq:=CreateFile('\\.\vwin32', 0, 0, nil, 0, 0, 0);
  if hq=INVALID_HANDLE_VALUE then
    begin AlertError('Öffnen Treiber',LastErrStr); exit; end;
  try
    s1:='';
    b:=DeviceIoControl(hq, VWIN32_DIOC_DOS_INT25,
                      @reg, sizeof(reg), @reg, sizeof(reg), cb, nil);
    if (not b) or odd(reg.reg_Flags) then begin
      if reg.reg_EAX<>$8002 then AlertError(txt,'AX:'+IntToHex(reg.reg_EAX,4))
      else                       AlertError(txt,'Es ist keine Diskette eingelegt.');
      exit;
    end;
  finally CloseHandle(hq) end;
  result:=true;
end;

function TestPartTable(drive: char) : boolean;
var bu    : TFATBootSec;
    para  : packed record
             esec   : cardinal;
             anzsec : word;
             buf    : DWORD;
           end;
    reg   : TReg;
    hq    : THandle;
    anz,e : cardinal;
begin
  result:=true; exit;
  result:=false;
  AddExcStack([unitName,'TestPartTable']);
  try try
    drive:=Upcase(drive); if (drive<'A') or (drive>'Z') then exit;
    zeroMemory(@bu,sizeof(bu)); bu.hidd:=1;
    if GetOperatingSystem=osWinNT4 then begin
      hq:=CreateFile(PChar('\\.\'+drive+':'),GENERIC_READ or GENERIC_WRITE,
                               FILE_SHARE_WRITE or FILE_SHARE_READ,NIL,
                               OPEN_EXISTING,0,0);
      try
        if hq=INVALID_HANDLE_VALUE then
          begin AlertError('Öffnen '+Drive,LastErrStr); exit; end;
        (*AlertInfo('Size bu:'+IntToStr(sizeof(bu)));*)
        if not ReadFile(hq,bu,sizeof(bu),anz,nil) then begin
          e:=GetLastError;
          (*AlertError('ReadErr '+Drive,WinErrStr(e)+' '+IntToStr(e));*)
          if e<>87 then begin
            AlertError('Read '+Drive,WinErrStr(e)); exit;
          end;
        end;
      finally
        CloseHandle(hq);
      end;
    end else begin
      hq:=CreateFile('\\.\vwin32', 0, 0, nil, 0, 0, 0);
      if hq=INVALID_HANDLE_VALUE then
         begin AlertError('Öffnen '+Drive,LastErrStr); exit; end;
      try
        with para do begin
          esec:=0; anzsec:=1;
          buf :=DWORD(@bu);
        end;
        with reg do begin
          reg_ECX:=$FFFF;
          reg_EAX:=ord(drive)-ord('A');     // zero-based drive ID
          reg_EDX:=DWORD(@para);
          reg_EBX:=DWORD(@para);
        end;
        if not DosInt25(reg,'Lese Bootsektor (Laufwerk '+drive+':).') then exit;
      finally
        CloseHandle(hq);
      end;
    end;
    (*AlertInfo('hidd:'+IntToStr(bu.hidd)+', booter:'+IntToStr(bu.booter[0]));*)
    result:=(bu.hidd=32) or ((bu.hidd=0) and (bu.booter[0]=0));
    if not result then
      AlertInfo('Die MO-Diskette im Laufwerk '+drive+': hat noch keine|'+
                'Partition-Table!||'+
                'Bitte zuerst mit dem NT-Festplatten-Manager auf dieser|'+
                'MO-Diskette eine "Partition" "erstellen"!');
  except ExceptionProc end finally DelExcStack end;
end;

Regards, Madshi.

P.S: Remove the lines where the compiler stops...
Thanks guys. I appreciate the last message but again it uses int25 which relies on there being a FAT partition of some kind.

I have posted messages all over the place with no success. I have to come to the conclusion that either MS are lying (surely not :-)) or vwin32 is buggy and because it's such an unusual thing to want to do, no-one has noticed or cares?

I really do appreciate your time on this and the acception mark acknowledges that - even if I have to admit defeat.

Regards,
JohnE
Lets take it easy friend. One day there will be no need to cheat in every occasion on WEIRD operating systems. Some team will surely give us fully documented OS we all hope...
igor