ab.com コミュニティ https://www.activebasic.com/forum/ |
|
セクタ単位でディスクを読み込む https://www.activebasic.com/forum/viewtopic.php?t=1535 |
ページ 1 / 1 |
作成者: | イグトランス [ 2006年9月11日(月) 22:57 ] |
記事の件名: | セクタ単位でディスクを読み込む |
セクタ単位でディスクを読み込みます。 NT系,Win 95 OSR2以降,Win 95初期版で場合分けしています。 NT系はとても簡単で,普通のファイル同様ReadFileで読み込めます。 9xでは結構面倒くさく,VWIN32 VxDを通じてDOS IOCTLファンクションを呼ぶということを行っています。 詳しくはここを参照してください。 [SDK32]OSR2上の Int 21 読み取り/書き込みトラックが失敗する Win95 初期版で使えたファンクションがOSR2以降では使えないというバグがあるため, OSR2以降で新しく用意された別のファンクションの呼出に切り替えています。 [ここをクリックすると内容が表示されます]
コード: #strict Const CARRY_FLAG = 1 Const VWIN32_DIOC_DOS_INT25 = 2 Const VWIN32_DIOC_DOS_INT26 = 3 Const VWIN32_DIOC_DOS_DRIVEINFO = 6 Const INVALID_SET_FILE_POINTER = &HFFFFFFFF Type DIOC_REGISTERS reg_EBX As DWord reg_EDX As DWord reg_ECX As DWord reg_EAX As DWord reg_EDI As DWord reg_ESI As DWord reg_Flags As DWord End Type Type Align(1) DISKIO dwStartSector As DWord ' 論理セクタ番号の開始番号 wSectors As Word ' セクタ数 dwBuffer As DWord ' 読み込み/書き込みバッファのアドレス End Type Declare Function DeviceIoControl Lib "Kernel32" ( hDevice As HANDLE, dwIoControlCode As DWord, lpInBuffer As VoidPtr, nInBufferSize As DWord, lpOutBuffer As VoidPtr, nOutBufferSize As DWord, lpBytesReturned As DWordPtr, lpOverlapped As *OVERLAPPED) As Long ' GetClusterSize9x内部で呼んでいる関数 ' これはMSのCでのサンプルの関数をほぼそのままABに移植しただけ。 ' http://support.microsoft.com/?scid=kb;ja;174569 ' NewReadSectors, ReadLogicalSectors ' 引数 ' hDev vwin32のハンドル ' bDrive ドライブ番号(0=カレントドライブ, 1=Aドライブ, 2=B, 3=C 4=D, ……) ' dwStartSector 読み込み開始セクタ番号 ' wSectors 読み込むセクタ数 ' pSectBuff 読み込む先のバッファへのポインタ Function NewReadSectors(hDev As HANDLE, bDrive As Byte, dwStartSector As DWord, wSectors As Word, pSectBuff As VoidPtr) As BOOL Dim cb As DWord Dim reg As DIOC_REGISTERS Dim dio As DISKIO With dio .dwStartSector = dwStartSector .wSectors = wSectors .dwBuffer = pSectBuff As DWord End With With reg .reg_EAX = &h7305 ' Ext_ABSDiskReadWrite .reg_EBX = VarPtr(dio) As DWord .reg_ECX = -1 .reg_EDX = bDrive ' Int 21h, fn 7305h ドライブ番号は 1 ベースです。 End With If DeviceIoControl(hDev, VWIN32_DIOC_DOS_DRIVEINFO, VarPtr(reg), Len(reg), VarPtr(reg), Len(reg), VarPtr(cb), 0) Then ' DeviceIoControl および読み取りが成功しているかどうか検証します。 NewReadSectors = (reg.reg_Flags And CARRY_FLAG) <> 0 End If End Function Function ReadLogicalSectors(hDev As HANDLE, bDrive As Byte,dwStartSector As DWord, wSectors As Word, pSectBuff As *Byte) Dim cb As DWord Dim reg As DIOC_REGISTERS Dim dio As DISKIO With dio .dwStartSector = dwStartSector .wSectors = wSectors .dwBuffer = pSectBuff As DWord End With With reg .reg_EAX = bDrive - 1 ' Int 25h ドライブ番号は 0 ベースです。 .reg_EBX = VarPtr(dio) As DWord .reg_ECX = &hFFFF ' DISKIO 構造体を使用します。 End With If DeviceIoControl(hDev, VWIN32_DIOC_DOS_INT25, VarPtr (reg), Len (reg), VarPtr (reg), Len (reg), VarPtr (cb), 0) <> FALSE Then ' DeviceIoControl および読み取りが成功しているかどうか検証します。 ReadLogicalSectors = (reg.reg_Flags And CARRY_FLAG) = 0 End If End Function Dim vi As OSVERSIONINFO vi.dwOSVersionInfoSize = Len (vi) GetVersionEx(vi) Function IsWin95OSR2OrOver(ByRef vi As OSVERSIONINFO) As BOOL With vi If .dwPlatformId = VER_PLATFORM_WIN32_WINDOWS And _ .dwMajorVersion = 4 And _ (.dwMinorVersion >= 10 Or .szCSDVersion[0] = Asc("B") Or .szCSDVersion[0] = Asc("C")) Then IsWin95OSR2OrOver = TRUE Else IsWin95OSR2OrOver = FALSE End If End With End Function Const SectorSize = 512 ' ReadDriveSector - セクター単位読込 ' driveLatter ドライブ文字 ' startSector 読込を開始するセクタ番号(0から) ' sectors 読み込むセクタ数 ' buf 読み込むバッファ ' 注意:セクタサイズは512バイトで決め打ちしてある。 Function ReadDriveSector(driveLatter As Byte, startSector As DWord, sectors As Word, buf As *Byte) As BOOL If vi.dwPlatformId = VER_PLATFORM_WIN32_NT Then Dim drive[6] As Byte wsprintf(drive, "\\.\%c:", driveLatter) Dim hDrive As HANDLE hDrive = CreateFile(drive, GENERIC_READ, FILE_SHARE_READ, ByVal 0, OPEN_ALWAYS, 0, 0) If hDrive <> INVALID_HANDLE_VALUE Then If SetFilePointer(hDrive, startSector * SectorSize, 0, FILE_BEGIN) <> INVALID_SET_FILE_POINTER Then Dim readSize As DWord ReadDriveSector = ReadFile(hDrive, buf, sectors * SectorSize, VarPtr(readSize), ByVal 0) End If End If CloseHandle(hDrive) Else Dim driveNum As Byte driveNum = CharLower(driveLatter As ULONG_PTR As *Byte) As ULONG_PTR As Byte - Asc("a") driveNum++ Dim hDevice As HANDLE hDevice = CreateFile("\\.\vwin32", 0, 0, ByVal NULL, 0, FILE_FLAG_DELETE_ON_CLOSE, NULL) If hDevice <> INVALID_HANDLE_VALUE Then Dim ret As BOOL If IsWin95OSR2OrOver(vi) Then ReadDriveSector = NewReadSectors(hDevice, driveNum, startSector, sectors, buf) Else ReadDriveSector = ReadLogicalSectors(hDevice, driveNum, startSector, sectors, buf) End If CloseHandle(hDevice) End If End If End Function Dim buffer[ELM(SectorSize)] As Byte ReadDriveSector(Asc("A"), 0, 1, buffer) Dim hWrite As HANDLE hWrite = CreateFile("H:\out.bin", GENERIC_WRITE, 0, ByVal 0, CREATE_ALWAYS, 0, 0) If hWrite <> INVALID_HANDLE_VALUE Then Dim writtenSize As DWord WriteFile(hWrite, buffer, Len (buffer), VarPtr(writtenSize), ByVal 0) CloseHandle(hWrite) End If |
作成者: | イグトランス [ 2006年9月11日(月) 22:59 ] |
記事の件名: | |
解説忘れました。 このプログラムは,例としてAドライブの最初の1セクタ(おそらくはFDのブートセクタ)を読み込んでファイルに書き出しています。 |
作成者: | konisi [ 2006年9月12日(火) 20:55 ] |
記事の件名: | |
どうでもいい事ですが、DIOC_REGISTERS構造体にEBPとESPは入らないんですね。 因みに。 [ここをクリックすると内容が表示されます]
1セクタ目がブートセクタかどうかを判定する方法は簡単で、基本的に&H01FE-&H01FF番地の値が&H55AAになっているかを調べるだけで済みます。 1セクタ目は最初の3バイトが&HEB4E90で、その次の8バイトがブートセクタの名前、次の32バイトは色々と細々とした設定が続き、次の11バイトがディスク名、次の8バイトがフォーマット名(FAT)、その後18バイトが0で埋め尽くされていると思います。 FDから起動するようなOSは今はあまり在りませんが。 参考:OS自作入門(川合秀実 著) |
ページ 1 / 1 | 全ての表示時間は UTC+09:00 です |
Powered by phpBB® Forum Software © phpBB Limited https://www.phpbb.com/ |