在Delphi中嵌入汇编的问题

时间:2021-07-18 03:12:27
在汇编中定义一个过程,

如下段:
.
.
.

128  WaitWhileBusy proc
129    MOV  EBX, 100000
130    MOV  DX, dwBaseAddress
131    ADD  DX, 7
132  @LoopWhileBusy:
133    DEC  EBX
134    CMP  EBX, 0
135    JZ   @Timeout
136    in   AL, DX
137    TEST AL, btBusy
138    JNZ  @LoopWhileBusy
139    JMP  @DriveReady
140  @Timeout:   // 超时,直接退出
141    JMP  @LeaveRing0
142  @DriveReady:
143    RET
144    ENDP   // End of WaitWhileBusy Procedure
.
.
.

编译后提示错误:
1、Undeclared identifier: 'WaitWhileBusy'       //第128行
2、Invalid combination of opcode and operands   //第137行
3、Undeclared identifier: 'ENDP'                //第144行

请问各位高手,此问题如何解决?

谢谢

9 个解决方案

#1


请各位高手帮帮忙,谢谢。

#2


按你提供的片段, 只能写个如下的能通过编译的代码供你参考了:

var
  dwBaseAddress : Word;

const
  btBusy = 1;

procedure MyASM;
begin
  asm
    @WaitWhileBusy:
      MOV  EBX, 100000
      MOV  DX, dwBaseAddress
      ADD  DX, 7
    @LoopWhileBusy:
      DEC  EBX
      CMP  EBX, 0
      JZ   @Timeout
      in   AL, DX
      TEST AL, btBusy
      JNZ  @LoopWhileBusy
      JMP  @DriveReady
    @Timeout:   // 超时,直接退出
      JMP  @LeaveRing0
    @DriveReady:
      RET
    @LeaveRing0:
  end;
end;

#3


也就是说,Delphi中的汇编段不能定义过程吗?

#4


Delphi中是有过程和函数的定义的,所以宏汇编中的proc endp之类的自然就不需要了。连TASM中都可以不要这个。
另外你可以写纯汇编过程,即以procedure asm end定义的过程,不需要procedure begin asm end end这种结构。
还有在BASM过程中是不需要写ret的,最后那个end就指示编译器自动生成ret、ret n这种返回指令。

#5


实际上我是想把下面这段获取硬盘序列号的C++程序转换为Delphi程序,
在网上有很多获取硬盘序列号的资料,但绝大多数都只能在NT环境下有效,在9X下就不行了,下面这段程序在NT和9X下都行,就是在转为Delphi的过程中遇到很多问题,
希望jadeluo(秀峰) 或其他高手帮忙转一下,谢谢。

//---------------------------------------------------------------------------

#include <vcl.h>
#include <WinIOCtl.h>
#include <stdio.h>
#pragma hdrstop
#pragma inline

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------

// 辅助函数
char *__fastcall ConvertToString(DWORD dwDiskData[256], int nFirstIndex, int nLastIndex);
// Windows 9X函数
void __fastcall ReadPhysicalDriveOnW9X(TStrings *pSerList, TStrings *pModeList);
void __fastcall ReadPhysicalDriveOnW9X_Ring0(bool IsFirst, WORD BaseAddress,
        BYTE MoS, bool &IsIDEExist, bool &IsDiskExist, WORD *OutData);
//---------------------------------------------------------------------------

// ConvertToString
char *__fastcall ConvertToString(DWORD dwDiskData[256], int nFirstIndex, int nLastIndex)
{
static char szResBuf[1024];
int nIndex = 0;
int nPosition = 0;

// Each integer has two characters stored in it backwards
for(nIndex = nFirstIndex; nIndex <= nLastIndex; nIndex++)
{
// Get high BYTE for 1st character
szResBuf[nPosition] = (char)(dwDiskData[nIndex] / 256);
nPosition++;

// Get low BYTE for 2nd character
szResBuf[nPosition] = (char)(dwDiskData[nIndex] % 256);
        nPosition++;
}

    // End the string
szResBuf[nPosition] = '\0';

    // Cut off the trailing blanks
for(nIndex = nPosition - 1; nIndex > 0 && ' ' == szResBuf[nIndex]; nIndex--)
        szResBuf[nIndex] = '\0';

return szResBuf;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Windows 95/98/ME 代码
//---------------------------------------------------------------------------
// ReadPhysicalDriveOnW9X
void __fastcall ReadPhysicalDriveOnW9X(TStrings *pSerList, TStrings *pModeList)
{
WORD wOutData[256];
    SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);

    // 经过测试,发现第一次调用而且Drive >= 2时会在Ring0代码中出现错误,导致蓝屏。
    // 经过N(N > 15)次的蓝屏后仍找不到原因:(,不得不在这里增加一段无用代码以
    // 避免蓝屏的出现。(期待高人能指出原因)
    for(int nDrive = 0; nDrive < 8; nDrive++)
    {
        WORD dwBaseAddress;
        BYTE btMasterSlave;         // Master Or Slave
        bool bIsIDEExist;
        bool IsDiskExist;

        switch(nDrive / 2)
        {
            case 0: dwBaseAddress = 0x01F0; break;
            case 1: dwBaseAddress = 0x0170; break;
            case 2: dwBaseAddress = 0x01E8; break;
            case 3: dwBaseAddress = 0x0168; break;
        }

        btMasterSlave = (BYTE)(((nDrive % 2) == 0) ? 0xA0 : 0xB0);

        // 进入Ring0
        ReadPhysicalDriveOnW9X_Ring0(true, dwBaseAddress, btMasterSlave,
                bIsIDEExist, IsDiskExist, wOutData);
    }

    // 开始读取
    for(int nDrive = 0; nDrive < 8; nDrive++)
    {
        WORD dwBaseAddress;
        BYTE btMasterSlave;         // Master Or Slave
        bool bIsIDEExist;
        bool bIsDiskExist;
        switch(nDrive / 2)
        {
            case 0: dwBaseAddress = 0x01F0; break;
            case 1: dwBaseAddress = 0x0170; break;
            case 2: dwBaseAddress = 0x01E8; break;
            case 3: dwBaseAddress = 0x0168; break;
        }

        btMasterSlave = (BYTE)(((nDrive % 2) == 0) ? 0xA0 : 0xB0);

        // 进入Ring0
        bIsIDEExist  = false;
        bIsDiskExist = false;
        ZeroMemory(wOutData, sizeof(wOutData));

        ReadPhysicalDriveOnW9X_Ring0(false, dwBaseAddress, btMasterSlave,
                bIsIDEExist, bIsDiskExist, wOutData);

        if(bIsIDEExist && bIsDiskExist)
        {
            DWORD dwDiskData[256];
            char  szSerialNumber[21];
            char  szModelNumber[41];

            for(int k=0; k < 256; k++)
                dwDiskData[k] = wOutData[k];

            // 取系列号
            ZeroMemory(szSerialNumber, sizeof(szSerialNumber));
            strcpy(szSerialNumber, ConvertToString(dwDiskData, 10, 19));

            // 取模型号
            ZeroMemory(szModelNumber, sizeof(szModelNumber));
            strcpy(szModelNumber, ConvertToString(dwDiskData, 27, 46));

            pSerList->Add(szSerialNumber);
            pModeList->Add(szModelNumber);
        }
    }
    SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
}

#6


//---------------------------------------------------------------------------
// 为防止不负责任的转载者,在此注明原出处信息,请见谅。
// 资料收集整理:ccrun(老妖),欢迎光临C++Builder研究: http://www.ccrun.com
//---------------------------------------------------------------------------
// ReadPhysicalDriveOnW9X_Ring0()
//
// dwBaseAddress = IDE(0,1,2,3) : 1F0h, 170h, 1E8h, 168h
// btMasterSlave = Master(0xA0) Or Slave(0xB0)
//---------------------------------------------------------------------------
void __fastcall ReadPhysicalDriveOnW9X_Ring0(bool bIsFirst, WORD dwBaseAddress,
        BYTE btMasterSlave, bool &bIsIDEExist, bool &bIsDiskExist, WORD *pOutData)
{
    BYTE  btIDTR1[6];
    DWORD dwOldExceptionHook;
    const int nHookExceptionNo = 5;

    BYTE  btIsIDEExist = 0;
    BYTE  btIsDiskExist = 0;
    WORD  wOutDataBuf[256];

    BYTE  btIsFirst = (BYTE)bIsFirst;

    const BYTE btBit00 = 0x01;
    // const BYTE btBit02 = 0x04;
    const BYTE btBit06 = 0x40;
    const BYTE btBit07 = 0x80;
    // const BYTE btERR  = btBit00;
    const BYTE btBusy = btBit07;
    const BYTE btAtaCmd   = 0xEC;
    const BYTE btAtapiCmd = 0xA1;

    __asm
    {
        // 必须先执行这条语句
        JMP EnterRing0

        // 定义过程
        // 等待IDE设备直到其不为忙为止
        WaitWhileBusy proc

        MOV  EBX, 100000
        MOV  DX, dwBaseAddress
        ADD  DX, 7

        LoopWhileBusy:

        DEC  EBX
        CMP  EBX, 0
        JZ   Timeout
        in   AL, DX
        TEST AL, btBusy
        JNZ  LoopWhileBusy
        JMP  DriveReady

        // 超时,直接退出
        Timeout:
        JMP  LeaveRing0
        DriveReady:
        RET
        ENDP   // End of WaitWhileBusy Procedure

        // 设置主盘和从盘标志
        SelectDevice proc

        MOV  DX, dwBaseAddress
        ADD  DX, 6
        MOV  AL, btMasterSlave

        out  DX, AL
        RET

ENDP  // End of SelectDevice Procedure

        // 向IDE设备发送存取指令
        SendCmd proc

        MOV DX, dwBaseAddress
        ADD DX, 7
        MOV AL, BL // BL是主从盘标识,在过程外设置
        out DX, AL
        RET
        ENDP  // End of SendCmd Procedure

        // Ring0代码
        Ring0Proc:
        PUSHAD
        // 查询IDE设备是否存在
        MOV DX, dwBaseAddress
        ADD DX, 7
        in  AL,DX

        // 当AL的值是0xFF或者0x7F时,IDE设备不存在,这时候直接返回
        CMP AL,0xFF
        JZ  LeaveRing0
        CMP AL, 0x7F
        JZ  LeaveRing0

        // 设置IDE设备存在标志
        MOV btIsIDEExist, 1

        // 查询IDE设备上的驱动器是否存在(有IDE插槽在主板上,但是却不一定有硬盘插在上面)
        CALL WaitWhileBusy
        CALL SelectDevice

        // 如果是第一次调用,则直接返回,否则执行下行语句时会出现蓝屏
        CMP  btIsFirst, 1
        JZ   LeaveRing0

        // 第一次调用时,如果执行这行语句会导致蓝屏,Why???
        CALL WaitWhileBusy

        // AL的值等于cBit06时,不存在驱动器,直接返回
        TEST AL, btBit06
        JZ   LeaveRing0

        // 设置驱动器存在标志
        MOV  btIsDiskExist, 1

        // 发送存取端口命令
        // 无法像NT/2000/XP那样可以通过查询VERSION的值得到驱动器的类型,
        // 所以只能一步一步地测试,如果不是ATA设备,再尝试使用ATAPI设备命令
        CALL WaitWhileBusy
        CALL SelectDevice    // 设置主从盘标识
        MOV  BL, btAtaCmd      // 发送读取命令
        CALL SendCmd
        CALL WaitWhileBusy

        // 检查是否出错
        MOV  DX, dwBaseAddress
        ADD  DX, 7

        in   AL, DX

        TEST AL, btBit00
        JZ   RetrieveInfo   // 没有错误时则读数据

        // 如果出错,则进一步尝试使用ATAPI设备命令
        CALL WaitWhileBusy
CALL SelectDevice
        MOV  BL, btAtapiCmd
        CALL SendCmd
        CALL WaitWhileBusy

        // 检查是否还出错
        MOV  DX, dwBaseAddress
        ADD  DX, 7
        in   AL, DX
        TEST AL, btBit00
        JZ   RetrieveInfo   // 没有错误时则读数据
        JMP  LeaveRing0     // 如果还是出错,直接返回

        // 读取数据
        RetrieveInfo:

        LEA  EDI, wOutDataBuf
        MOV  ECX, 256
        MOV  DX, dwBaseAddress
        CLD

        REP  INSW

        // 退出Ring0代码
        LeaveRing0:

        POPAD
        IRETD

        // 激活Ring0代码
        EnterRing0:

        // 修改中断门
        SIDT FWORD PTR btIDTR1
        MOV EAX, DWORD PTR btIDTR1 + 02h
        ADD EAX, nHookExceptionNo * 08h + 04h
CLI

        // 保存原异常处理例程入口
        MOV ECX, DWORD PTR [EAX]
        MOV CX, WORD PTR [EAX-04h]
        MOV dwOldExceptionHook, ECX

        // 指定新入口
        LEA EBX, Ring0Proc
        MOV WORD PTR [EAX-04h],BX
        SHR EBX, 10h
        MOV WORD PTR[EAX+02h], BX

        // 激活Ring0代码
        INT nHookExceptionNo

        // 复原入口
        MOV ECX,dwOldExceptionHook
        MOV WORD PTR[EAX-04h], CX
        SHR ECX,10h
MOV WORD PTR[EAX+02h], CX
        STI
    }
    if(!bIsFirst)
    {
        bIsIDEExist  = (bool)btIsIDEExist;
        bIsDiskExist = (bool)btIsDiskExist;
        CopyMemory(pOutData, wOutDataBuf, sizeof(wOutDataBuf));
    }
}

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  Memo1->Lines->Clear();
  Memo2->Lines->Clear();
  Memo1->Lines->Add("硬盘序列号:");
  Memo2->Lines->Add("硬盘型号:");

  if (Win32Platform!=VER_PLATFORM_WIN32_NT)
ReadPhysicalDriveOnW9X(Memo1->Lines, Memo2->Lines);
}
//---------------------------------------------------------------------------

#7


请帮帮忙

#8


我也需要这个的Delphi代码。

#9


请帮帮忙,谢谢

而且这段代码在9X下是不需要SmartVSD的。

#1


请各位高手帮帮忙,谢谢。

#2


按你提供的片段, 只能写个如下的能通过编译的代码供你参考了:

var
  dwBaseAddress : Word;

const
  btBusy = 1;

procedure MyASM;
begin
  asm
    @WaitWhileBusy:
      MOV  EBX, 100000
      MOV  DX, dwBaseAddress
      ADD  DX, 7
    @LoopWhileBusy:
      DEC  EBX
      CMP  EBX, 0
      JZ   @Timeout
      in   AL, DX
      TEST AL, btBusy
      JNZ  @LoopWhileBusy
      JMP  @DriveReady
    @Timeout:   // 超时,直接退出
      JMP  @LeaveRing0
    @DriveReady:
      RET
    @LeaveRing0:
  end;
end;

#3


也就是说,Delphi中的汇编段不能定义过程吗?

#4


Delphi中是有过程和函数的定义的,所以宏汇编中的proc endp之类的自然就不需要了。连TASM中都可以不要这个。
另外你可以写纯汇编过程,即以procedure asm end定义的过程,不需要procedure begin asm end end这种结构。
还有在BASM过程中是不需要写ret的,最后那个end就指示编译器自动生成ret、ret n这种返回指令。

#5


实际上我是想把下面这段获取硬盘序列号的C++程序转换为Delphi程序,
在网上有很多获取硬盘序列号的资料,但绝大多数都只能在NT环境下有效,在9X下就不行了,下面这段程序在NT和9X下都行,就是在转为Delphi的过程中遇到很多问题,
希望jadeluo(秀峰) 或其他高手帮忙转一下,谢谢。

//---------------------------------------------------------------------------

#include <vcl.h>
#include <WinIOCtl.h>
#include <stdio.h>
#pragma hdrstop
#pragma inline

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------

// 辅助函数
char *__fastcall ConvertToString(DWORD dwDiskData[256], int nFirstIndex, int nLastIndex);
// Windows 9X函数
void __fastcall ReadPhysicalDriveOnW9X(TStrings *pSerList, TStrings *pModeList);
void __fastcall ReadPhysicalDriveOnW9X_Ring0(bool IsFirst, WORD BaseAddress,
        BYTE MoS, bool &IsIDEExist, bool &IsDiskExist, WORD *OutData);
//---------------------------------------------------------------------------

// ConvertToString
char *__fastcall ConvertToString(DWORD dwDiskData[256], int nFirstIndex, int nLastIndex)
{
static char szResBuf[1024];
int nIndex = 0;
int nPosition = 0;

// Each integer has two characters stored in it backwards
for(nIndex = nFirstIndex; nIndex <= nLastIndex; nIndex++)
{
// Get high BYTE for 1st character
szResBuf[nPosition] = (char)(dwDiskData[nIndex] / 256);
nPosition++;

// Get low BYTE for 2nd character
szResBuf[nPosition] = (char)(dwDiskData[nIndex] % 256);
        nPosition++;
}

    // End the string
szResBuf[nPosition] = '\0';

    // Cut off the trailing blanks
for(nIndex = nPosition - 1; nIndex > 0 && ' ' == szResBuf[nIndex]; nIndex--)
        szResBuf[nIndex] = '\0';

return szResBuf;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Windows 95/98/ME 代码
//---------------------------------------------------------------------------
// ReadPhysicalDriveOnW9X
void __fastcall ReadPhysicalDriveOnW9X(TStrings *pSerList, TStrings *pModeList)
{
WORD wOutData[256];
    SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);

    // 经过测试,发现第一次调用而且Drive >= 2时会在Ring0代码中出现错误,导致蓝屏。
    // 经过N(N > 15)次的蓝屏后仍找不到原因:(,不得不在这里增加一段无用代码以
    // 避免蓝屏的出现。(期待高人能指出原因)
    for(int nDrive = 0; nDrive < 8; nDrive++)
    {
        WORD dwBaseAddress;
        BYTE btMasterSlave;         // Master Or Slave
        bool bIsIDEExist;
        bool IsDiskExist;

        switch(nDrive / 2)
        {
            case 0: dwBaseAddress = 0x01F0; break;
            case 1: dwBaseAddress = 0x0170; break;
            case 2: dwBaseAddress = 0x01E8; break;
            case 3: dwBaseAddress = 0x0168; break;
        }

        btMasterSlave = (BYTE)(((nDrive % 2) == 0) ? 0xA0 : 0xB0);

        // 进入Ring0
        ReadPhysicalDriveOnW9X_Ring0(true, dwBaseAddress, btMasterSlave,
                bIsIDEExist, IsDiskExist, wOutData);
    }

    // 开始读取
    for(int nDrive = 0; nDrive < 8; nDrive++)
    {
        WORD dwBaseAddress;
        BYTE btMasterSlave;         // Master Or Slave
        bool bIsIDEExist;
        bool bIsDiskExist;
        switch(nDrive / 2)
        {
            case 0: dwBaseAddress = 0x01F0; break;
            case 1: dwBaseAddress = 0x0170; break;
            case 2: dwBaseAddress = 0x01E8; break;
            case 3: dwBaseAddress = 0x0168; break;
        }

        btMasterSlave = (BYTE)(((nDrive % 2) == 0) ? 0xA0 : 0xB0);

        // 进入Ring0
        bIsIDEExist  = false;
        bIsDiskExist = false;
        ZeroMemory(wOutData, sizeof(wOutData));

        ReadPhysicalDriveOnW9X_Ring0(false, dwBaseAddress, btMasterSlave,
                bIsIDEExist, bIsDiskExist, wOutData);

        if(bIsIDEExist && bIsDiskExist)
        {
            DWORD dwDiskData[256];
            char  szSerialNumber[21];
            char  szModelNumber[41];

            for(int k=0; k < 256; k++)
                dwDiskData[k] = wOutData[k];

            // 取系列号
            ZeroMemory(szSerialNumber, sizeof(szSerialNumber));
            strcpy(szSerialNumber, ConvertToString(dwDiskData, 10, 19));

            // 取模型号
            ZeroMemory(szModelNumber, sizeof(szModelNumber));
            strcpy(szModelNumber, ConvertToString(dwDiskData, 27, 46));

            pSerList->Add(szSerialNumber);
            pModeList->Add(szModelNumber);
        }
    }
    SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
}

#6


//---------------------------------------------------------------------------
// 为防止不负责任的转载者,在此注明原出处信息,请见谅。
// 资料收集整理:ccrun(老妖),欢迎光临C++Builder研究: http://www.ccrun.com
//---------------------------------------------------------------------------
// ReadPhysicalDriveOnW9X_Ring0()
//
// dwBaseAddress = IDE(0,1,2,3) : 1F0h, 170h, 1E8h, 168h
// btMasterSlave = Master(0xA0) Or Slave(0xB0)
//---------------------------------------------------------------------------
void __fastcall ReadPhysicalDriveOnW9X_Ring0(bool bIsFirst, WORD dwBaseAddress,
        BYTE btMasterSlave, bool &bIsIDEExist, bool &bIsDiskExist, WORD *pOutData)
{
    BYTE  btIDTR1[6];
    DWORD dwOldExceptionHook;
    const int nHookExceptionNo = 5;

    BYTE  btIsIDEExist = 0;
    BYTE  btIsDiskExist = 0;
    WORD  wOutDataBuf[256];

    BYTE  btIsFirst = (BYTE)bIsFirst;

    const BYTE btBit00 = 0x01;
    // const BYTE btBit02 = 0x04;
    const BYTE btBit06 = 0x40;
    const BYTE btBit07 = 0x80;
    // const BYTE btERR  = btBit00;
    const BYTE btBusy = btBit07;
    const BYTE btAtaCmd   = 0xEC;
    const BYTE btAtapiCmd = 0xA1;

    __asm
    {
        // 必须先执行这条语句
        JMP EnterRing0

        // 定义过程
        // 等待IDE设备直到其不为忙为止
        WaitWhileBusy proc

        MOV  EBX, 100000
        MOV  DX, dwBaseAddress
        ADD  DX, 7

        LoopWhileBusy:

        DEC  EBX
        CMP  EBX, 0
        JZ   Timeout
        in   AL, DX
        TEST AL, btBusy
        JNZ  LoopWhileBusy
        JMP  DriveReady

        // 超时,直接退出
        Timeout:
        JMP  LeaveRing0
        DriveReady:
        RET
        ENDP   // End of WaitWhileBusy Procedure

        // 设置主盘和从盘标志
        SelectDevice proc

        MOV  DX, dwBaseAddress
        ADD  DX, 6
        MOV  AL, btMasterSlave

        out  DX, AL
        RET

ENDP  // End of SelectDevice Procedure

        // 向IDE设备发送存取指令
        SendCmd proc

        MOV DX, dwBaseAddress
        ADD DX, 7
        MOV AL, BL // BL是主从盘标识,在过程外设置
        out DX, AL
        RET
        ENDP  // End of SendCmd Procedure

        // Ring0代码
        Ring0Proc:
        PUSHAD
        // 查询IDE设备是否存在
        MOV DX, dwBaseAddress
        ADD DX, 7
        in  AL,DX

        // 当AL的值是0xFF或者0x7F时,IDE设备不存在,这时候直接返回
        CMP AL,0xFF
        JZ  LeaveRing0
        CMP AL, 0x7F
        JZ  LeaveRing0

        // 设置IDE设备存在标志
        MOV btIsIDEExist, 1

        // 查询IDE设备上的驱动器是否存在(有IDE插槽在主板上,但是却不一定有硬盘插在上面)
        CALL WaitWhileBusy
        CALL SelectDevice

        // 如果是第一次调用,则直接返回,否则执行下行语句时会出现蓝屏
        CMP  btIsFirst, 1
        JZ   LeaveRing0

        // 第一次调用时,如果执行这行语句会导致蓝屏,Why???
        CALL WaitWhileBusy

        // AL的值等于cBit06时,不存在驱动器,直接返回
        TEST AL, btBit06
        JZ   LeaveRing0

        // 设置驱动器存在标志
        MOV  btIsDiskExist, 1

        // 发送存取端口命令
        // 无法像NT/2000/XP那样可以通过查询VERSION的值得到驱动器的类型,
        // 所以只能一步一步地测试,如果不是ATA设备,再尝试使用ATAPI设备命令
        CALL WaitWhileBusy
        CALL SelectDevice    // 设置主从盘标识
        MOV  BL, btAtaCmd      // 发送读取命令
        CALL SendCmd
        CALL WaitWhileBusy

        // 检查是否出错
        MOV  DX, dwBaseAddress
        ADD  DX, 7

        in   AL, DX

        TEST AL, btBit00
        JZ   RetrieveInfo   // 没有错误时则读数据

        // 如果出错,则进一步尝试使用ATAPI设备命令
        CALL WaitWhileBusy
CALL SelectDevice
        MOV  BL, btAtapiCmd
        CALL SendCmd
        CALL WaitWhileBusy

        // 检查是否还出错
        MOV  DX, dwBaseAddress
        ADD  DX, 7
        in   AL, DX
        TEST AL, btBit00
        JZ   RetrieveInfo   // 没有错误时则读数据
        JMP  LeaveRing0     // 如果还是出错,直接返回

        // 读取数据
        RetrieveInfo:

        LEA  EDI, wOutDataBuf
        MOV  ECX, 256
        MOV  DX, dwBaseAddress
        CLD

        REP  INSW

        // 退出Ring0代码
        LeaveRing0:

        POPAD
        IRETD

        // 激活Ring0代码
        EnterRing0:

        // 修改中断门
        SIDT FWORD PTR btIDTR1
        MOV EAX, DWORD PTR btIDTR1 + 02h
        ADD EAX, nHookExceptionNo * 08h + 04h
CLI

        // 保存原异常处理例程入口
        MOV ECX, DWORD PTR [EAX]
        MOV CX, WORD PTR [EAX-04h]
        MOV dwOldExceptionHook, ECX

        // 指定新入口
        LEA EBX, Ring0Proc
        MOV WORD PTR [EAX-04h],BX
        SHR EBX, 10h
        MOV WORD PTR[EAX+02h], BX

        // 激活Ring0代码
        INT nHookExceptionNo

        // 复原入口
        MOV ECX,dwOldExceptionHook
        MOV WORD PTR[EAX-04h], CX
        SHR ECX,10h
MOV WORD PTR[EAX+02h], CX
        STI
    }
    if(!bIsFirst)
    {
        bIsIDEExist  = (bool)btIsIDEExist;
        bIsDiskExist = (bool)btIsDiskExist;
        CopyMemory(pOutData, wOutDataBuf, sizeof(wOutDataBuf));
    }
}

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  Memo1->Lines->Clear();
  Memo2->Lines->Clear();
  Memo1->Lines->Add("硬盘序列号:");
  Memo2->Lines->Add("硬盘型号:");

  if (Win32Platform!=VER_PLATFORM_WIN32_NT)
ReadPhysicalDriveOnW9X(Memo1->Lines, Memo2->Lines);
}
//---------------------------------------------------------------------------

#7


请帮帮忙

#8


我也需要这个的Delphi代码。

#9


请帮帮忙,谢谢

而且这段代码在9X下是不需要SmartVSD的。