全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:4903
推到 Plurk!
推到 Facebook!

BCB直接訪問硬體埠和實體記憶體 - WinIO的應用

 
conundrum
尊榮會員


發表:893
回覆:1272
積分:643
註冊:2004-01-06

發送簡訊給我
#1 引用回覆 回覆 發表時間:2004-02-14 11:09:51 IP:61.221.xxx.xxx 未訂閱
BCB直接訪問硬體埠和實體記憶體 - WinIO的應用    http://www.cppfans.com/articles/system/portrw_winio.asp    (讀硬碟參數和主板BIOS資訊, 支援 Win9x/NT/2k/XP/2003)    Victor Chen, (C++ 愛好者)    附完整的根源程式(本頁最下面的鏈結)    關於直接訪問埠, 有很多網站很多文章都討論過, 但總找不到非常理想的辦法。 我這裏用的是 Yariv Kaplan 的 WinIo 2.0。雖然 WinIO 也有缺陷, 但是是我用過的當中最好的了。 WinIO 是免費的, 並且是開放源代碼的, 可以直接到他的主頁下載, 也可以在這裏下載。 Yariv Kaplan 的主頁: http://www.internals.com/    WinIO 的使用非常簡單, 在程式的開始調用 InitializeWinIo(); 初始化 WinIO, 在程式的結束使用 ShutdownWinIo(); 這樣就可以在程式裏直接訪問埠和實體記憶體了。    在這裏仍然用的是讀硬碟參數和主板BIOS資訊。 本站在《硬碟參數讀取程式》這篇文章裏曾經介紹過利用 WinIO 讀取硬碟參數, 很多人提出程式太複雜, 並且在程式妍坋刓掍庛g常無效, 在這裏簡化了程式, 並且改善了性能, 在程式妍坋刓掍峇]可讀出參數了。    按鈕Button1: 硬碟參數:    型 號: MAXTOR 6L040J2 序 列 號: 662202841232 固件版本: AR1.0400 容 量: 38172 Mb 柱 面 數: 16383 磁 頭 數: 16 扇 區 數: 63 緩存容量: 1818 kb ECC 位元組: 4 bytes LBA 支援: 是  DMA 支援: 是 按鈕Button2: BIOS資訊:    Award Modular BIOS v6.00PG Copyright (C) 1984-2001, Award Software, Inc. 05/14/02 05/14/2002-i815-ITE87X2-6A69RPQRS-00      有關讀寫埠函數 inportb 和 outportb 等函數: 在 Win2000 等 NT 內核的 OS 可直接用彙編訪問埠, 但 Win9x 反而不可以     
#include "WinIO.h"
//--------------------------------------------------------------------------- 
unsigned char inportbNT(unsigned short p) { asm mov dx, p; asm in al, dx; return _AL; }
unsigned short inportwNT(unsigned short p) { asm mov dx, p; asm in ax, dx; return _AX; }
unsigned long inportdNT(unsigned short p) { asm mov dx, p; asm in eax,dx; return _EAX;}
void outportbNT(unsigned short p, unsigned char v) { asm mov dx, p; asm mov al, v; asm out dx,al; }
void outportwNT(unsigned short p, unsigned short v) { asm mov dx, p; asm mov ax, v; asm out dx,ax; }
void outportdNT(unsigned short p, unsigned long v) { asm mov dx, p; asm mov eax,v; asm out dx,eax;}
//---------------------------------------------------------------------------
unsigned char inportb9x(unsigned short p) { unsigned long v = 0; GetPortVal(p, &v, 1); return v; }
unsigned short inportw9x(unsigned short p) { unsigned long v = 0; GetPortVal(p, &v, 2); return v; }
unsigned long inportd9x(unsigned short p) { unsigned long v = 0; GetPortVal(p, &v, 4); return v; }
void outportb9x(unsigned short p, unsigned char v) { SetPortVal(p,v,1); }
void outportw9x(unsigned short p, unsigned short v) { SetPortVal(p,v,2); }
void outportd9x(unsigned short p, unsigned long v) { SetPortVal(p,v,4); }
//---------------------------------------------------------------------------
unsigned char (*inportb)(unsigned short) = inportbNT;
unsigned short (*inportw)(unsigned short) = inportwNT;
unsigned long (*inportd)(unsigned short) = inportdNT;
void (*outportb)(unsigned short, unsigned char ) = outportbNT;
void (*outportw)(unsigned short, unsigned short) = outportwNT;
void (*outportd)(unsigned short, unsigned long ) = outportdNT;
//---------------------------------------------------------------------------
void InitPortFuncs(void)
{
    OSVERSIONINFO osVer = {sizeof(OSVERSIONINFO)};
    GetVersionEx(&osVer);        if(osVer.dwPlatformId == VER_PLATFORM_WIN32_NT)
    {
        inportb = inportbNT; outportb = outportbNT;
        inportw = inportwNT; outportw = outportwNT;
        inportd = inportdNT; outportd = outportdNT;
    }
    else
    {
        inportb = inportb9x; outportb = outportb9x;
        inportw = inportw9x; outportw = outportw9x;
        inportd = inportd9x; outportd = outportd9x;
    }
} 
上面的程式 InitPortFuncs 就是判斷作業系統是否d NT 內核, 並且選擇合適的函數來訪問埠。
經過這樣處理, 在 Win2000 下訪問埠的速度就要比 98 的快了, Win2000 的速度比較理想。    具體程式: Button1 是讀硬碟參數, Button2 是讀主板BIOS資訊
#include "WinIO.h"
#pragma link "WinIo_bc.lib"
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
    bWinIoInitOK = InitializeWinIo();
    if(!bWinIoInitOK)
    {
        Application->MessageBox("不能裝載 WinIO 程式!","錯誤資訊",MB_OK|MB_ICONSTOP);
        Application->Terminate();
    }
    InitPortFuncs();
}
//---------------------------------------------------------------------------
__fastcall TForm1::~TForm1()
{
    if(bWinIoInitOK)
        ShutdownWinIo();
}
//--------------------------------------------------------------------------- 
bool ReadHddParams(unsigned short *params, int pn, int dn)
{
    int i,IdePort[2] = {0x1f0, 0x170}; //primary & secondary IDE Controller
    unsigned char HD_Selection[2]={0xa0,0xb0}; // Master Disk: 1010 0000, Slave Disk: 1011 0000
    unsigned short BasePort = IdePort[pn];
    for(i=0;i<500;i  ) //Get HDC Status, wait until HDC not busy
    {
        if((inportb(BasePort 7)&0x80)==0)
            break; //hdc is ready
        Sleep(1);
    }
    if(i>=300)return false; //HDC no response        outportb(BasePort 6, HD_Selection[dn]); //master or slave hard disk
    outportb(BasePort 7, 0x10); //HDD status
    for(i=0;i<300;i  ) //Get HDD Status, wait until HDD not busy
    {
        if((inportb(BasePort 7)&0x80)==0)
            break;
        Sleep(1);
    }
    if(i>=300)return false; //HDC no response
    if(inportb(BasePort 7)!=0x50)return false; //HDD ready: 0101 0000
    outportb(BasePort 6, HD_Selection[dn]); //master or slave hard disk
    outportb(BasePort 7, 0xec); //HDD parameters
    for(i=0;i<300;i  ) //wait for parameters retrieved
    {
        if(inportb(BasePort 7)==0x58) //retrieved OK
            break;
        Sleep(1);
    }
    if(i>=300)return false; //parameters retrieved error
    for(i=0;i<256;i  )
        params[i]=inportw(BasePort);
    return true;
}
//---------------------------------------------------------------------------
void WordToStr(unsigned char *s, unsigned short *w, int n) //硬碟參數轉成字串 
{
    int i;
    for(i=0; i>8;
        s[i*2 1] = w[i]&0x00ff;
    }
    s[i*2]=0;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    DWORD dwOldProcessP = GetPriorityClass(GetCurrentProcess());
    DWORD dwOldThreadP = GetThreadPriority(GetCurrentThread());
    SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
    SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);        AnsiString idename[2] = {"IDE0","IDE1"}, diskname[2] = {"主盤","從盤"};
    unsigned short params[256]; char Str[256];        for(int pn=0; pn<2; pn  ) //primary or secondary
    for(int dn=0; dn<2; dn  ) //master or slave
    {
        Memo1->Lines->Add(idename[pn] " " diskname[dn] ":");
        if(ReadHddParams(params,pn,dn))
        {
            WordToStr(Str,params 27,20); Memo1->Lines->Add("型 號: " AnsiString(Str));
            WordToStr(Str,params 10,10); Memo1->Lines->Add("序 列 號: " AnsiString(Str));
            WordToStr(Str,params 23, 4); Memo1->Lines->Add("固件版本: " AnsiString(Str));                unsigned long LbaCap = *(unsigned long *)(鷰s[60])/2048;
            unsigned long NomCap = ((unsigned long)(params[1])*(params[3])*(params[6]))/2048;
            Memo1->Lines->Add("容 量: "   AnsiString().sprintf("%lu Mb",LbaCap>NomCap?LbaCap:NomCap));                Memo1->Lines->Add(AnsiString().sprintf("柱 面 數: %u", params[1]));
            Memo1->Lines->Add(AnsiString().sprintf("磁 頭 數: %u", params[3]));
            Memo1->Lines->Add(AnsiString().sprintf("扇 區 數: %u", params[6]));                bool DMA = params[49]&0x0100; //D8:是否支援DMA
            bool LBA = params[49]&0x0200; //D9:是否支援LBA                Memo1->Lines->Add(AnsiString().sprintf("緩存容量: %u kb", params[21]>>1));
            Memo1->Lines->Add(AnsiString().sprintf("ECC 位元組: %u bytes", params[22]));
            Memo1->Lines->Add(AnsiString().sprintf("LBA 支援: %s", LBA?"是":"否"));
            Memo1->Lines->Add(AnsiString().sprintf("DMA 支援: %s", DMA?"是":"否"));
        }
        else
        {
            Memo1->Lines->Add("沒找到硬碟");
        }
        Memo1->Lines->Add("");
    }        SetThreadPriority(GetCurrentThread(), dwOldThreadP);
    SetPriorityClass(GetCurrentProcess(), dwOldProcessP);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
    HANDLE hPhyMem; //char *lpInfo = (char far *)0xf0000L;
    //下面的語句讓 0xf0000 位址的 65536 個位元組可直接讀寫
    char *lpInfo = MapPhysToLin((char*)0xf0000,65536,&hPhyMem);
    Memo1->Lines->Add(lpInfo 0xe061); //主板BIOS名稱 0xFE061
    Memo1->Lines->Add(lpInfo 0xe091); //主板BIOS版權 0xFE091
    Memo1->Lines->Add(lpInfo 0xfff5); //主板BIOS日期 0xFFFF5
    Memo1->Lines->Add(lpInfo 0xec71); //主板BIOS序列號 0xFEC71
    UnmapPhysicalMemory(hPhyMem, lpInfo);
}
//---------------------------------------------------------------------------
最後寫一下 WinIO 的缺陷:
會讓純DOS版本的程式無法接受鍵盤和滑鼠事件, 可現在用純DOS程式很少了, 所以影響不大。     
發表人 - conundrum 於 2004/02/14 11:11:33
附加檔案:44873_BCB_IO.rar
系統時間:2024-07-04 4:50:52
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!