第 23 章 通用控制項(3):工具提示 ( Tool Tip )


工具提示 ( Tool Tip )

當使用者把滑鼠游標移到事先指定好的區域時,系統會顯示一視窗,此視窗包含一段文字說明某件事,這一視窗稱為工具提示 ( Tool Tip )。如下圖所示的「登錄編輯程式」,如果使用者在右上角的「最小化按鈕」按鈕停留一段時間,就會出現一個黃底黑字的小視窗,上面寫「最小化」,這個小視窗就是「工具提示」。微軟把事先指定好的區域稱為「tool」,小木偶翻成監視區域,當使用者把滑鼠游標由監視區域移走時,工具提示旋即消失。「工具提示」也是一種通用控件。

五種通用控制項

工具提示控制項還有另外幾種較特殊樣子:Tracking ToolTips ( 可以由程式而非系統設定在顯示位置的工具提示 )、Multiline ToolTips ( 多行的工具提示 )、Balloon ToolTips ( 氣球形狀的工具提示 )、In-Place ToolTips ( 以滑鼠點選後出現的工具提示 )。不過不管是哪一種工具提示,其實也都是子視窗,所以要建立工具提示,可以用呼叫 CreateWindowEx。此步驟為:

  1. 在程式任意一處,呼叫 InitCommonControls 或 InitCommonControlsEx,以初始化通用控件。這也是使用通用控件的必要步驟。
  2. 定義視窗類別為『TOOLTIPS_CLASS32』,並以 NULL 結尾。
  3. 一般在處理 WM_CREATE 時,呼叫 CreateWindowEx,建立工具提示,並取得其視窗代碼。
  4. 呼叫 SendMessage,發送訊息給工具提示,以設定工具提示的行為。

呼叫 CreateWindowEx 建立工具提示時,第一個參數,dwExStyle,可設為 NULL;第二個參數,lpClassName,須指向『TOOLTIPS_CLASS32』字串位址;第三個參數,lpWindowName,因不需視窗標題,可設為 NULL;第四個參數,dwStyle,有七種風格可供選擇:

風格數值說明
TTS_ALWAYSTIP1h 只要滑鼠在監視區域上,就會顯示工具提示,不論父視窗是否是活動的。如果沒有設定此風格,只有在父視窗為活動的時候,才會顯示工具提示。
TTS_BALLOON40h 此風格為 5.80 版本的 COMCTRL32.DLL 及其以後才有的風格,5.80 版本的 COMCTL32.DLL 是隨 Internet Explorer 5 ( IE5 ) 散佈的,因此在安裝有 IE5 的 Windows 作業系統中,就可使用此風格。此風格的工具提示如同漫畫中,人物的對話框框,如圖。
TTS_NOANIMATE10h 此風格為 5.80 版本的 COMCTRL32.DLL 及其以後才有的風格。一般而言,工具提示出現時,會逐漸浮現在螢幕上;消失時,是逐漸隱沒。如果您想看見前述效果,必須以滑鼠右鍵按「我的電腦」→「內容」→「進階」→「設定」→「視覺效果」,確定「自訂」中「工具提示逐漸消失或滑動到檢視」為勾選。此風格會抑制逐漸浮現在螢幕上的效果。
TTS_NOFADE20h 此風格為 5.80 版本的 COMCTRL32.DLL 及其以後才有的風格,此風格會抑制逐漸隱沒的效果。
TTS_NOPREFIX2h 具有此風格時,工具提示能顯示『&』字元。
TTS_CLOSE80h 如果工具提示具有標題,且具有 TTS_CLOSE 時,會在工具提示右上方顯示關閉按鈕。我們可以對工具提示發送 TTM_SETTITLE 設定標題。
TTS_USEVISUALSTYLE100h 具有此風格時,能顯示主題連結,需要和 TTF_PARSELINKS 搭配使用。

除此之外,工具提示還具備有 WS_POPUP 和額外的 WS_EX_TOOLWINDOW 風格,但這兩種風格會由『TOOLTIPS_CLASS32』類別指定,所以不需特別指定。接下來的四個參數是視窗位置與視窗大小均由系統設定,皆設為『CW_USEDEFAULT』即可。第九個參數,hWndParent,可以填入父視窗代碼。第十個參數,hMenu,不需要,因為工具提示不會有選單,設為 NULL。第十一個參數,hInstance,應填入工具提示所屬的模組代碼。最後一個參數,lpParam,則是需要而定。


工具提示的訊息

與其他控制項一樣,吾人以呼叫 SendMessage 對工具提示發出訊息,以設定其行為。此時第一個參數,hWnd,填入工具提示代碼;第二個參數,uMsg,須依不同需要而設定,工具提示的訊息都是以「TTM_」為字頭;第三與最後一個參數,wParam 與 lParam,則是依 uMsg 不同而設不同的數值。如下︰

        INVOKE  SendMessage,hToolTip,uMsg,wParam,lParam

底下先介紹如何在工具提示中,新增監視區域,亦即發送 TTM_ADDTOOL 訊息給工具提示。

TTM_ADDTOOL︰添加監視區域

對工具提示發出 TTM_ADDTOOL 訊息時,wParam 必須設為 0,lParam 是 TOOLINFO 結構體位址。TOOLINFO 結構體包含了有關監視區域的資料及要顯示的文字,它的欄位如下:

TOOLINFO        STRUC
cbSize          DWORD   ?
uFlags          DWORD   ?
hwnd            DWORD   ?
uId             DWORD   ?
rect            RECT    <?>
hinst           DWORD   ?
lpszText        DWORD   ?
lParam          DWORD   ?
TOOLINFO        ENDS

TOOLINFO 的第一個欄位,cbSize,是 TOOLINFO 結構體大小,以位元組為單位,在呼叫 SendMessage 之前必須填入正確的大小,以便讓作業系統能辨識版本。TOOLINFO 的第五個欄位,rect,就是監視區域,監視區域其實是一塊矩形區域,我們有時把整個工作區都當成監視區域 ( 例如把按鈕控制項當成監視區域時,就很好用 );有時僅僅把部份工作區當成監視區域,有時亦可把工作區切割成數個矩形區域,當成數個監視區域,滑鼠移過不同的監視區域可以顯示不同的文字。底下小木偶分別說明這兩種情形:

發送 TTM_ADDTOOL 給工具提示後,如果返回時,EAX 為 TRUE 表示呼叫成功,若為 FALSE 表示失敗。

TOOLINFO 也可以為其它訊息使用,如 TTM_DELTOOL,因此 uFlags 欄位功能不是只有 TTF_IDISHWND 和 TTF_SUBCLASS 兩種而已,小木偶整理如下︰

  1. TTF_IDISHWND:如果指定這個旗標,就表示監視區域是整個工作區,此時必須把該視窗的代碼填入 uID 欄位,lpszText 填上要顯示的文字位址。IDISHWND 是「ID is hWnd」之意,亦即 uID 並非識別碼而是視窗代碼。
  2. TTF_SUBCLASS:此旗標表示工具提示會子類化監視區域所在的視窗,亦即工具提示會攔截監視區域所在視窗的訊息,例如 WM_MOUSEMOVE。事實上,當滑鼠游標在監視區域上移動或停留時,系統只會把訊息傳給監視區域所在的視窗,而不是工具提示。因此如果不使用 TTF_SUBCLASS 把此訊息攔截而傳遞給工具提示,我們就得使用 TTM_RELAYEVENT,把訊息轉發至工具提示。
  3. TTF_CENTERTIP:一般工具提示是在滑鼠游標的右下方顯示,但設定此旗標時,會在監視區域下方的正中間顯示。
  4. TTF_PARSELINKS:6.0 版及其以後的 COMCTL32.DLL 可以使用,此版 COMCTL32.DLL 是隨著 XP 販售。
  5. TTF_RTLREADING:如果系統是阿拉伯或希伯來語系,設定此旗標可以使文字由右至左的順序顯示,在其它語系是無效。
  6. TTF_ABSOLUTE:必須配合 TTF_TRACK 旗標,可以使工具提示在 TTM_TRACKPOSITION 所指定的螢幕座標顯示。
  7. TTF_TRACK:工具提示會顯示在監視區域旁邊,而且以不擋住監視區域為原則。具有此旗標的工具提示,必須由程式自行處理訊息並顯示工具提示,所以不可和 TTF_SUBCLASS 並用,即使使用了,TTF_SUBCLASS 仍是無效而多餘的。
  8. TTF_TRANSPARENT:使工具提示跟著滑鼠移動,但效果並不好。

TOOLINFO 結構體的 lpszText 欄位可以是字串位址,也可以是字串資源的識別碼,假如是後者,那麼還要再設定 hinst 欄位,hinst 是包含有文字字串資源的模組代碼,它只有在 lpszText 是代表字串資源的識別碼時才需要設定,其他情形是無用的。最後一個欄位 lParam

TTM_SETDELAYTIME︰設定延遲時間

發送 TTM_SETDELAYTIME 訊息給工具提示,可以設定工具提示的延遲時間,方法是︰

        INVOKE  SendMessage,hToolTip,TTM_SETDELAYTIME,wParam,lParam

其中最後一個參數,lParam,是指延遲的時間,以毫秒為單位。而 wParam 是設定延遲哪一種時間,可以是下面幾四種︰

  1. TTDT_INITIAL︰設定滑鼠游標停留在監視區域多少毫秒,才顯示工具提示。
  2. TTDT_AUTOPOP︰工具提示顯示以後,多少毫秒才消失。
  3. TTDT_RESHOW︰當滑鼠游標由一個監視區域移到另一個監視區域後,要花多少毫秒,才顯示工具提示。
  4. TTDT_AUTOMATIC︰將前述三個延遲時間恢復成系統預設的比例關係,上述三種延遲時間的比例關係依次是 5:50:1。參數 lParam 為正值,則設定 initial 延遲時間,另兩項時間則依比例設定;若為負值,則會取得上述延遲時間。

TTM_SETMAXTIPWIDTH

這個訊息是用來設定工具提示的最大寬度。我們可以用這種方法來設定多行字串。方法如下︰

        INVOKE  SendMessage,hToolTip,TTM_SETMAXTIPWIDTH,0,iWidth

參數中的 wParam 必須設為 0,而 lParam 為要設定的寬度,以點為單位。如果要顯示的字串長度超過工具提示的最大寬度,那麼剩下的字串會顯示在下一行。這堜瓵蛌熙怳j寬度,並不是指工具提示不能超過此寬度。因為英文字長短不同,並且考慮不要讓一個英文字切成兩行,所以系統在字串超過最大寬度時,如遇空白字元,才會被切成兩行。此外,如果沒有設定 TTM_SETMAXTIPWIDTH,即使使用換行字元 ( 0dh、0ah ) 也不能切成兩行;但是設定過 TTM_SETMAXTIPWIDTH 後,即使在最大寬度內,使用換行字元也可以換行。

TTM_SETTITLE

這個訊息是用來在工具提示內的上方顯示標題。方法如下︰

        INVOKE  SendMessage,hToolTip,TTM_SETTITLE,icon,pszTitle

參數 icon 是在標題欄左方設定圖示,可以是下面幾種︰TTI_NONE、TTI_INFO、TTI_WARNING、TTI_ERROR、TTI_INFO_LARGE、TTI_WARNING_LARGE、TTI_ERROR_LARGE,如果是 Windows XP SP2 以後的版本,也可以使用圖示代碼。pszTitle 為標題字串位址,以零結尾。返回時,TRUE 表示成功;FALSE 表示失敗。


範例

底下小木偶將實作一個程式,MEMFREE1.ASM,此程式會把電腦中的剩餘的實體記憶體、分頁檔、虛擬記憶體顯示出來,當使用者把滑鼠移到相關的資料時,就會出現工具提示,解釋相關的術語。

原始碼如下:

        .586
        .MODEL  FLAT,STDCALL
        OPTION  CASEMAP:NONE

INCLUDE         WINDOWS.INC
INCLUDE         GDI32.INC
INCLUDE         KERNEL32.INC
INCLUDE         USER32.INC
INCLUDE         COMCTL32.INC
INCLUDELIB      GDI32.LIB
INCLUDELIB      KERNEL32.LIB
INCLUDELIB      USER32.LIB
INCLUDELIB      COMCTL32.LIB

GlobalMemoryStatusEx    PROTO   :DWORD

MEMORYSTATUSEX          STRUC
dwLength                DWORD   ?
dwMemoryLoad            DWORD   ?
ullTotalPhys            QWORD   ?
ullAvailPhys            QWORD   ?
ullTotalPageFile        QWORD   ?
ullAvailPageFile        QWORD   ?
ullTotalVirtual         QWORD   ?
ullAvailVirtual         QWORD   ?
ullAvailExtendedVirtual QWORD   ?
MEMORYSTATUSEX          ENDS

;*********************************************************************
.CONST
WND_WIDTH               EQU     200
WND_HEIGHT              EQU     120
ID_TIMER                EQU     2000
FONT_SIZE               EQU     12
TTF_ABSOLUTE            EQU     80h
TTF_TRACK               EQU     20h
TTM_TRACKPOSITION       EQU     412h
TTM_SETMAXTIPWIDTH      EQU     418h
TTM_TRACKACTIVATE       EQU     WM_USER + 17
rect            RECT    <0,0,WND_WIDTH,WND_HEIGHT>
szAppName       BYTE    '剩餘記憶體',0
szClassName     BYTE    'MemFree',0
szMemIcon       BYTE    'CHIP',0
szToolTipClass  BYTE    'TOOLTIPS_CLASS32',0
szFont          BYTE    '新細明體',0
szMemFmt        BYTE    '全部實體記憶體:%dKB',0dh,0ah,'剩餘實體記憶體:%dKB',0dh,0ah
                BYTE    '全部分頁檔大小:%dKB',0dh,0ah,'剩下分頁檔大小:%dKB',0dh,0ah
                BYTE    '全部虛擬記憶體:%dKB',0dh,0ah,'剩下虛擬記憶體:%dKB',0
szPhyMem        BYTE    '實體記憶體是指安裝在電腦主機板',0dh,0ah
                BYTE    '上的動態隨機存取記憶體 ( Dynamic ',0dh,0ah
                BYTE    'Random Access Memory,簡稱 DRAM )',0dh,0ah
                BYTE    '它是一顆顆的積體電路組成的。',0
szPageFile      BYTE    '分頁檔本指建立在硬碟中的虛擬記憶',0dh,0ah
                BYTE    '體,此處是指實體記憶體與分頁檔大',0dh,0ah
                BYTE    '小,也是系統所能使用的記憶體上限',0dh,0ah
                BYTE    '大小與剩餘大小。',0
szVirtual       BYTE    '一個程式所能使用的虛擬記憶體,此',0dh,0ah
                BYTE    '虛擬記憶體必須扣除系統用去的部份',0dh,0ah
                BYTE    ',對 Win32 系統而言大約是 2GB。',0
;*********************************************************************
.DATA?
hInstance       HINSTANCE               ?
hwnd            HWND                    ?
hFont           HFONT                   ?
hWndToolTip     HWND                    ?
wc              WNDCLASSEX              <?>
msg             MSG                     <?>
msex            MEMORYSTATUSEX          <?>
iccex           INITCOMMONCONTROLSEX    <?>
ti              TOOLINFO                <?>
buffer          BYTE                    160 DUP (?)
;*********************************************************************
.CODE
;---------------------------------------------------------------------
BytesToKB       PROC
                shl     edx,22
                shr     eax,10
                add     eax,edx
                ret
BytesToKB       ENDP
;---------------------------------------------------------------------
SetToolInfo     PROC    id:DWORD
                sub     edx,edx
                mov     eax,id
                mov     ti.uId,eax
                mov     ecx,FONT_SIZE*2
                mul     ecx
                mov     ti.rect.top,eax
                mov     ti.rect.left,0
                add     eax,ecx
                mov     ti.rect.right,WND_WIDTH
                mov     ti.rect.bottom,eax
        .IF id==0
                mov     ti.lpszText,OFFSET szPhyMem
        .ELSEIF id==1
                mov     ti.lpszText,OFFSET szPageFile
        .ELSEIF id==2
                mov     ti.lpszText,OFFSET szVirtual
        .ENDIF
                INVOKE  SendMessage,hWndToolTip,TTM_ADDTOOL,0,OFFSET ti
                ret
SetToolInfo     ENDP
;---------------------------------------------------------------------
WndProc         PROC    hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
                LOCAL   ps:PAINTSTRUCT
                LOCAL   hDC:HDC

.IF uMsg==WM_PAINT
                INVOKE  BeginPaint,hWnd,ADDR ps
                INVOKE  CreateFont,FONT_SIZE,0,0,0,FW_NORMAL,0,0,0,ANSI_CHARSET,\
                        OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,\
                        NULL,OFFSET szFont
                mov     hFont,eax
                INVOKE  SelectObject,ps.hdc,eax
                INVOKE  DeleteObject,eax
                mov     msex.dwLength,SIZEOF MEMORYSTATUSEX
                INVOKE  GlobalMemoryStatusEx,OFFSET msex
                mov     edx,DWORD PTR msex.ullAvailVirtual[4]
                mov     eax,DWORD PTR msex.ullAvailVirtual
                call    BytesToKB
                push    eax
                mov     edx,DWORD PTR msex.ullTotalVirtual[4]
                mov     eax,DWORD PTR msex.ullTotalVirtual
                call    BytesToKB
                push    eax
                mov     edx,DWORD PTR msex.ullAvailPageFile[4]
                mov     eax,DWORD PTR msex.ullAvailPageFile
                call    BytesToKB
                push    eax
                mov     edx,DWORD PTR msex.ullTotalPageFile[4]
                mov     eax,DWORD PTR msex.ullTotalPageFile
                call    BytesToKB
                push    eax
                mov     edx,DWORD PTR msex.ullAvailPhys[4]
                mov     eax,DWORD PTR msex.ullAvailPhys
                call    BytesToKB
                push    eax
                mov     edx,DWORD PTR msex.ullTotalPhys[4]
                mov     eax,DWORD PTR msex.ullTotalPhys
                call    BytesToKB
                push    eax
                push    OFFSET szMemFmt
                push    OFFSET buffer
                call    wsprintf
                INVOKE  DrawText,ps.hdc,OFFSET buffer,eax,OFFSET rect,DT_LEFT
                INVOKE  EndPaint,ps.hdc,ADDR ps

.ELSEIF uMsg==WM_TIMER
                INVOKE  InvalidateRect,hWnd,NULL,TRUE

.ELSEIF uMsg==WM_CREATE
                INVOKE  SetTimer,hWnd,ID_TIMER,1000,NULL
                mov     iccex.dwSize,SIZEOF INITCOMMONCONTROLSEX
                mov     iccex.dwICC,ICC_BAR_CLASSES
                INVOKE  InitCommonControlsEx,OFFSET iccex
                INVOKE  CreateWindowEx,0,OFFSET szToolTipClass,0,TTS_NOPREFIX OR TTS_ALWAYSTIP,\
                        CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,hWnd,0,hInstance,0
                mov     hWndToolTip,eax
                INVOKE  SendMessage,eax,TTM_SETMAXTIPWIDTH,0,200
                mov     ecx,hWnd
                mov     ti.cbSize,SIZEOF TOOLINFO
                mov     ti.uFlags,TTF_SUBCLASS
                mov     ti.hWnd,ecx
                INVOKE  SetToolInfo,0
                INVOKE  SetToolInfo,1
                INVOKE  SetToolInfo,2

.ELSEIF uMsg==WM_DESTROY
                INVOKE  KillTimer,hWnd,ID_TIMER
                INVOKE  PostQuitMessage,NULL

.ELSE
                INVOKE  DefWindowProc,hWnd,uMsg,wParam,lParam
                ret

.ENDIF
                xor     eax,eax
                ret
WndProc         ENDP
;---------------------------------------------------------------------
start:  INVOKE  GetModuleHandle,NULL
        mov     hInstance,eax
        mov     wc.cbSize,SIZEOF WNDCLASSEX
        mov     wc.style,CS_HREDRAW OR CS_VREDRAW OR CS_DBLCLKS
        mov     wc.lpfnWndProc,OFFSET WndProc
        mov     wc.cbClsExtra,NULL
        mov     wc.cbWndExtra,NULL
        mov     wc.hInstance,eax
        INVOKE  LoadIcon,eax,OFFSET szMemIcon
        mov     wc.hIcon,eax
        mov     wc.hIconSm,eax
        INVOKE  LoadCursor,NULL,IDC_ARROW
        mov     wc.hCursor,eax
        mov     wc.hbrBackground,COLOR_WINDOW+1
        mov     wc.lpszMenuName,NULL
        mov     wc.lpszClassName,OFFSET szClassName
        INVOKE  RegisterClassEx,OFFSET wc
        INVOKE  GetSystemMetrics,SM_CXSCREEN
        sub     eax,WND_WIDTH
        shr     eax,1
        push    eax
        INVOKE  GetSystemMetrics,SM_CYSCREEN
        sub     eax,WND_HEIGHT
        pop     edx
        shr     eax,1
        INVOKE  CreateWindowEx,NULL,OFFSET szClassName,OFFSET szAppName,\ 
                WS_SYSMENU OR WS_MINIMIZEBOX,edx,eax,WND_WIDTH,WND_HEIGHT,0,\
                NULL,hInstance,NULL 
        mov     hwnd,eax
        INVOKE  ShowWindow,eax,SW_SHOWDEFAULT
        INVOKE  UpdateWindow,hwnd
.WHILE TRUE
        INVOKE  GetMessage,OFFSET msg,NULL,0,0
.BREAK .IF !eax
        INVOKE  TranslateMessage,OFFSET msg
        INVOKE  DispatchMessage,OFFSET msg
.ENDW
        mov     eax,msg.wParam
        INVOKE  ExitProcess,eax
;*********************************************************************
        END     start

資源檔,MEMFREE.RC,僅一行:

CHIP    ICON    CHIP3.ico

依下面方法組譯:

E:\HomePage\SOURCE\Win32\TOOLTIP>rc memfree.rc [Enter]

E:\HomePage\SOURCE\Win32\TOOLTIP>ml memfree1.asm /link memfree.res [Enter]
Microsoft (R) Macro Assembler Version 6.14.8444
Copyright (C) Microsoft Corp 1981-1997.  All rights reserved.

 Assembling: memfree1.asm
Microsoft (R) Incremental Linker Version 5.12.8078
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

/SUBSYSTEM:WINDOWS
"memfree1.obj"
"/OUT:memfree1.exe"
"memfree.res"

E:\HomePage\SOURCE\Win32\TOOLTIP>

您應當可以見到,MEMFREE.EXE 在處理 WM_CREATE 時,呼叫 CreateWindowEx 建立了工具提示控制項,然後把這個視窗代碼存在 hWndToolTip 變數堙C接著以 TTM_SETMAXTIPWIDTH 為參數呼叫 SendMessage,這一個步驟是限制工具提示的寬度。一般而言,工具提示會忽略換行、歸位字元,所以即是字串包含這兩個字元,工具提示仍是顯示一行。如果限制了工具提示寬度,就可以使它在超過此寬度之前自動到下一行顯示。

GlobalMemoryStatus 與 GlobalMemoryStatusEx

想要獲取記憶體使用情形資料,可以呼叫早期的 GlobalMemoryStatus 或是 GlobalMemoryStatusEx,兩者差別在後者只能在 Windows 2K/XP 及以後的版本,但是如果電腦中已安裝超過 4GB 的記憶體,GlobalMemoryStatusEx 也能在 64 位元的作業系統得到超過 4GB 的記憶體資料;而 GlobalMemoryStatus 則無法辦到。GlobalMemoryStatusEx 的原型在 MASM32 v7.0 並沒有定義,到了 MASM32 v8.2 以後的版本才在 KERNEL32.INC 中定義,所以假如您使用 MASM32 v7.0 組譯的話,請自行加入:

GlobalMemoryStatusEx    PROTO   :DWORD

GlobalMemoryStatusEx 只有一個參數,此參數指向 MEMORYSTATUSEX 結構體的位址,這個結構體在 MASM32 v7∼10 都沒有定義,所以得自行在原始碼中定義,其欄位如下:

MEMORYSTATUSEX          STRUC
dwLength                DWORD   ?
dwMemoryLoad            DWORD   ?
ullTotalPhys            QWORD   ?       ;電腦安裝的實體記憶體大小
ullAvailPhys            QWORD   ?       ;剩餘實體記憶體大小
ullTotalPageFile        QWORD   ?       ;系統所能使用的記憶體上限,包含分頁檔與實體記憶體大小
ullAvailPageFile        QWORD   ?       ;剩餘分頁檔與實體記憶體大小
ullTotalVirtual         QWORD   ?       ;虛擬記憶體大小
ullAvailVirtual         QWORD   ?       ;剩餘虛擬記憶體大小
ullAvailExtendedVirtual QWORD   ?       ;剩餘延伸虛擬記憶體大小
MEMORYSTATUSEX          ENDS

第一個欄位,dwLength,是 MEMORYSTATUSEX 結構體的大小,以位元組為單位,必須在呼叫 GlobalMemoryStatusEx 前填好這個欄位。由第二個欄位到最後的欄位是呼叫 GlobalMemoryStatusEx 之後,由作業系統填上的。第二個欄位,dwMemoryLoad,表示實體記憶體已使用的百分比,是 0 到 100 的整數。其餘的欄位都是各式記憶體的大小的資料,全是以位元組為單位。如果 GlobalMemoryStatusEx 成功的傳回 MEMORYSTATUSEX 結構體,則 EAX 為非零值,否則 EAX 為零。如果您用 MASM32 v7.0 組譯,因其 KERNEL32.LIB 並未包含 GlobalMemoryStatusEx 的資料,會形成無法連結的情形,請改用 MASM32 v9.0 以上組譯,或是在微軟網站下載 6.0.6001.18000.367-KRMSDK_EN.iso,這是 Windows SDK for Windows Server 2008 的光碟影像檔,在其『\Setup\WinSDKBuild-WinSDKBuild_VistaLibs_X86-common.0.cab』壓縮檔中萃取『Kernel32_Lib.34A9A805_A741_4A0D_A5EA_FE0276BE952C』檔案,將其改名為『KERNEL32.LIB』,再複寫到『C:\MASM32\LIB』子目錄堣]可以組譯成功。

至於 GlobalMemoryStatus API 與 GlobalMemoryStatusEx 相同,也都只有一個參數,此參數是指向 MEMORYSTATUS 結構體的位址,MEMORYSTATUS 結構體與 MEMORYSTATUSEX 也很相似,其差別是 MEMORYSTATUS 結構體少了最後一個欄位,而且所有欄位的長度都是雙字組,GlobalMemoryStatus 與 MEMORYSTATUS 在 MASM32 v7.0 都已定義,不須我們費心。


到第二十二章回到首頁到第二十四章