• Chủ Nhật, 14/09/2008 08:37 (GMT+7)

    Lập trình Access lấy mã số của đĩa cứng

    Trên các file Access, bạn có thể lập trình dùng ngôn ngữ VBA (Visual Basic for Application). VBA là ngôn ngữ VB có tăng cường thêm một số đối tượng để bạn có thể xử lý các tài liệu MS Office được dễ dàng, VBA thực hiện được hầu hết các công việc mà ứng dụng VB bình thường làm được. Thí dụ trong VBA, bạn có thể dùng hàm API Windows có tên là DeviceIoControl() để truy xuất các thông tin vật lý của ổ cứng như Model number, Serial number, Firmware revision... Các hằng và các kiểu dữ liệu phục vụ cho việc truy xuất thông tin vật lý của ổ cứng được định nghĩa trong bộ DDK (Device Development Kit). Trong các số tạp chí trước, chúng tôi đã trình bày cách dùng VB để viết 1 ứng dụng truy xuất và hiển thị thông tin vật lý của ổ đĩa cứng. Sau đây chúng tôi xin giới thiệu lại qui trình điển hình để viết 1 Form VBA đơn giản chạy trong môi trường Access, Form này cho phép bạn chọn ổ cứng và xem các thông tin vật lý liên quan đến đĩa cứng.

    1. Chạy Access, tạo file Access mới hay mở lại file Access đã có.

    2. Chọn mục Form trong cửa sổ Objects, ấn kép chuột vào mục Create Form in Design View để mở cửa sổ thiết kế 1 form ứng dụng mới. Sau đó thiết kế Form có dạng sau:

    Trong đó TextBox có tên là txtDrive, button có tên là btnStart, ListBox có tên là lstInfo.

    3. Nhấn phải chuột vào button Start rồi chọn option Build Event để hiển thị cửa sổ Choose Builder, chọn mục Code Builder và button OK để mở cửa sổ soạn code. Tạo thủ tục xử lý sự kiện click chuột cho button này có tên là btnStart_Click(). Khi cửa sổ soạn code của Form hiển thị, bạn hãy nhập đoạn lệnh VB sau đây vào:

    'code cho Form1
    Option Explicit
    'định nghĩa các hằng cần dùng cho hàm CreateFile
    Private Const FILE_SHARE_READ = &H1
    Private Const FILE_SHARE_WRITE = &H2
    Private Const GENERIC_READ = &H80000000
    Private Const GENERIC_WRITE = &H40000000
    Private Const OPEN_EXISTING = 3
    Private Const CREATE_NEW = 1
    'định nghĩa các hằng, các kiểu cần dùng cho hàm DeviceIoControl
    'các thông tin này được lấy từ bộ DDK
    Private Const DFP_RECEIVE_DRIVE_DATA = &H7C088
    Private Enum HDINFO
        HD_MODEL_NUMBER
        HD_SERIAL_NUMBER
        HD_FIRMWARE_REVISION
    End Enum

    Private Type IDEREGS
        bFeaturesReg As Byte
        bSectorCountReg As Byte
        bSectorNumberReg As Byte
        bCylLowReg As Byte
        bCylHighReg As Byte
        bDriveHeadReg As Byte
        bCommandReg As Byte
        bReserved As Byte
    End Type

    Private Type SENDCMDINPARAMS
    cBufferSize As Long
    irDriveRegs As IDEREGS
    bDriveNumber As Byte
    bReserved(1 To 3) As Byte
    dwReserved(1 To 4) As Long
    End Type

    Private Type DRIVERSTATUS
        bDriveError As Byte
        bIDEStatus As Byte
        bReserved(1 To 2) As Byte
        dwReserved(1 To 2) As Long
    End Type
    Private Type SENDCMDOUTPARAMS
        cBufferSize As Long
        DStatus As DRIVERSTATUS
        bBuffer(1 To 512) As Byte
    End Type

    'Định nghĩa các hàm API cần dùng
    Private Declare Function CreateFile 
        Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, ByVal lpSecurityAttributes As Long, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
    Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
    Private Declare Function DeviceIoControl Lib "kernel32" (ByVal hDevice As Long, ByVal dwIoControlCode As Long, lpInBuffer As Any, ByVal nInBufferSize As Long, lpOutBuffer As Any, ByVal nOutBufferSize As Long, lpBytesReturned As Long, ByVal lpOverlapped As Long) As Long

    'Định nghĩa hàm GetHDInfo để đọc thông tin vật lý disk
    Private Function GetHDInfo(Drive As Integer, hdi As HDINFO) As String
        Dim bin As SENDCMDINPARAMS
        Dim bout As SENDCMDOUTPARAMS
        Dim hdh As Long
        Dim br As Long
        Dim ix As Long
        Dim hddfr As Long
        Dim hddln As Long
        Dim s As String
    Select Case hdi 'Kiểm tra chức năng
        Case HD_MODEL_NUMBER    
            hddfr = 55 'thiết lập vị trí buffer chứa ModelNumber
            hddln = 40 'thiết lập độ dài buffer chứa ModelNumber
        Case HD_SERIAL_NUMBER
            hddfr = 21 'thiết lập vị trí buffer chứa SerialNumber
            hddln = 20 'thiết lập độ dài buffer chứa SerialNumber
        Case HD_FIRMWARE_REVISION
            hddfr = 47 'thiết lập vị trí buffer chứa FirmwareRevision
            hddln = 8 'thiết lập độ dài buffer chứa FirmwareRevision
        Case Else
        Err.Raise 10001, "Illegal HD Data type" 'Báo lỗi
    End Select
    'tạo file nhận dạng ổ cứng cần đọc thông tin
    hdh = CreateFile("\\.\PhysicalDrive" & Drive, GENERIC_READ + GENERIC_WRITE, FILE_SHARE_READ + FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0)
    'kiểm tra việc tạo file
    If hdh = 0 Then
        Err.Raise 10003, , "Error on CreateFile"
    End If
    'thiết lập các thông số cần truyền
    With bin
        .bDriveNumber = Drive
    .cBufferSize = 512
    With .irDriveRegs
        If (Drive And 1) Then
            .bDriveHeadReg = &HB0
    Else
        .bDriveHeadReg = &HA0
    End If
        .bCommandReg = &HEC
        .bSectorCountReg = 1
        .bSectorNumberReg = 1
    End With
    End With
    'gọi hàm DeviceIoControl để đọc thông tin
    DeviceIoControl hdh, DFP_RECEIVE_DRIVE_DATA, bin, Len(bin), bout, Len(bout), br, 0
    'copy thông tin cần truy xuất
        s = ""
    For ix = hddfr To hddfr + hddln - 1 Step 2
    If bout.bBuffer(ix + 1) = 0 Then Exit For
        s = s & Chr(bout.bBuffer(ix + 1))
    If bout.bBuffer(ix) = 0 Then Exit For
        s = s & Chr(bout.bBuffer(ix))
    Next ix
    GetHDInfo = Trim(s)
    'Đóng handle disk
    CloseHandle hdh
    End Function

    'thủ tục xử lý click chuột trên button Start
    Private Sub btnStart_Click()
    Dim Drive As Integer
    Drive = Val(txtDrive)
        lstInfo.RowSource = ""
        lstInfo.AddItem "Current drive: " & Drive
        lstInfo.AddItem ""
        lstInfo.AddItem "Model number: " & GetHDInfo(Drive, HD_MODEL_NUMBER)
        lstInfo.AddItem "Serial number: " & GetHDInfo(Drive, HD_SERIAL_NUMBER)
        lstInfo.AddItem "Firmware Revision: " & GetHDInfo(Drive, HD_FIRMWARE_REVISION)
    End Sub

    4. Đóng cửa sổ thiết lập Form lại, đặt tên cho cửa sổ để dễ nhận dạng, rồi nhấn đúp chuột vào Form trong cửa sổ chọn Form của Access để chạy thử Form, nhập 0 vào TextBox (tương ứng với đĩa cứng đầu tiên của máy), chọn button Start và xem kết quả trong ListBox.
    Ngoài ra, bạn cũng có thể truy xuất các thông tin đĩa (hay một tài nguyên nào đó của hệ thống) thông qua thư viện WMI (Windows Management Instrumentation). Sau đây là đoạn code VBA hiển thị "model number" và "device id" của đĩa cứng.

    'thủ tục xử lý click chuột trên button Start
    Private Sub btnDiskDisp_Click()
    Dim i As Integer
        i = 0
    On Error Resume Next
        lstInfo.RowSource = ""
    For Each Disk In GetObject("winmgmts:").InstancesOf("CIM_DiskDrive")
        lstInfo.AddItem "Current drive: " & i
        lstInfo.AddItem ""
        lstInfo.AddItem "Model number: " & Disk.Properties_.Item("Model").Value
        lstInfo.AddItem "Device ID : " & Disk.Properties_.Item("DeviceID").Value
    i = i + 1
    Next
    If Err <> 0 Then
        Set lasterr = CreateObject("WbemScripting.SWbemLastError")
        MsgBox lasterr.Operation & lasterr.ParameterInfo & lasterr.ProviderName
    End If
    End Sub

    Nguyễn Văn Hiệp
    nvhiep@hotmail.com

    ID: A0808_142