關於 Atom 數據表
atom 數據表 是儲存字串和對應識別子的系統定義數據表。 應用程式會將字串放在atom數據表中,並接收稱為 atom的16位整數,可用來存取字串。 已置入原子資料表中的字串稱為 原子名稱。
系統提供一些 Atom 數據表。 每個 Atom 數據表都有不同的用途。 例如,動態數據交換 (DDE) 應用程式會使用 全域 Atom 數據表 與其他應用程式共用專案名稱和主題名稱字串。 DDE 應用程式不會傳遞實際的字串,而是將全域原子傳遞至其夥伴應用程式。 夥伴會使用 atoms 從原子表中取得字串。
應用程式可以使用本機 Atom 數據表來儲存自己的專案名稱關聯。
系統會使用應用程式無法直接存取的 Atom 資料表。 不過,當呼叫各種函式時,應用程式會使用這些 Atom。 例如,已註冊的剪貼簿格式會儲存在系統所使用的內部 Atom 數據表中。 應用程式會使用 RegisterClipboardFormat 函式,將原子新增至此原子數據表。 此外,已註冊的類別會儲存在系統所使用的內部 Atom 數據表中。 應用程式會使用 RegisterClass 或 RegisterClassEx 函式,將原子新增至這個原子表。
本節將討論下列主題。
全域原子表格
全域 Atom 數據表可供所有應用程式使用。 當應用程式將字串放在全域 Atom 數據表時,系統會產生在整個系統中唯一的 Atom。 任何具有 Atom 的應用程式都可以藉由查詢全域 Atom 數據表來取得它所識別的字串。
定義私人 DDE 資料格式以便與其他應用程式共用資料的應用程式,應該將格式名稱放在全域 Atom 數據表中。 這項技術可防止與系統或其他應用程式所定義的格式名稱發生衝突,並讓訊息或格式的識別碼(原子)可供其他應用程式使用。
使用者原子數據表
除了全域 Atom 數據表之外,使用者 Atom 數據表是另一個系統 Atom 數據表,也會在所有進程之間共用。 使用者 Atom 數據表用於 win32k 內部的少數案例;例如,windows 模組名稱、win32k、OLE 格式等已知字串。雖然應用程式不會直接與使用者 atom 數據表互動,但它們會呼叫數個 API,例如 RegisterClass、RegisterWindowMessage,以及 RegisterClipboardFormat,將專案新增至使用者 atom 數據表。
UnregisterClass
可以刪除 RegisterClass
新增的條目。 不過,RegisterWindowMessage
和 RegisterClipboardFormat
新增的項目在會話結束前不會刪除。 如果使用者 Atom 數據表沒有更多空間,而且傳入的字串尚未在數據表中,呼叫將會失敗。
Atom 數據表大小
許多重要的 API,包括 CreateWindow,都依賴使用者原子。 因此,使用者 Atom 數據表中的空間耗盡會導致嚴重問題:例如,所有應用程式都可能無法啟動。 以下是一些建議,以確保您的應用程式有效率地利用 Atom 數據表,並保留應用程式和系統的可靠性和效能:
您應該限制應用程式使用使用者 Atom 資料表。 使用
RegisterClass
、RegisterWindowMessage
或RegisterClipboardFormat
等 API 儲存唯一字串,會佔用使用者 Atom 數據表的空間,而其他應用程式會全域使用字串來註冊窗口類別。 如果可能,應該使用 AddAtom/DeleteAtom,將字串儲存在本地原子表中;如果需要跨進程使用原子,則使用 GlobalAddAtom/GlobalDeleteAtom。如果擔心應用程式造成使用者 Atom 數據表問題,您可以藉由連接核心調試程式並中斷對
UserAddAtomEx
(bae1 win32kbase!UserAddAtomEx /p <eprocess> "kc10;g"
) 呼叫的程式,來調查根本原因。 在 callstack 上尋找user32!
,以查看正在呼叫哪個 API。 此方法類似於 中所述的識別全域性原子表洩漏的問題檢測方法。 另一種匯出使用者 Atom 表內容的方法,是在可能的原子範圍內從 0xC000 到 0xFFFF 呼叫 GetClipboardFormatName。 如果應用程式執行時,原子計數總計會穩定上升,或當應用程式關閉時不會返回基準,則發生問題。
本機 Atom 數據表
應用程式可以使用本機 Atom 數據表,有效率地管理只用於應用程式內的大量字串。 這些字串和相關聯的 Atom 僅適用於建立資料表的應用程式。
在數個結構中要求相同字串的應用程式可以使用本機 Atom 數據表來減少記憶體使用量。 應用程式可以將字串放在atom數據表中,並將產生的Atom包含在結構中,而不是將字串複製到每個結構中。 如此一來,字串只會在記憶體中出現一次,但可在應用程式中使用多次。
應用程式也可以使用本機 Atom 資料表,在搜尋特定字串時節省時間。 若要執行搜尋,應用程式只需要將搜尋字串放在atom數據表中,並將產生的Atom與相關結構中的原子進行比較。 比較原子通常比比較字串更快。
Atom 數據表會實作為哈希表。 根據預設,本機原子表會使用 37 個槽作為其哈希表。 不過,您可以呼叫 InitAtomTable 函式來變更所使用的貯體數目。 不過,如果應用程式呼叫 InitAtomTable,則必須先執行此動作,才能呼叫任何其他 atom 管理函式。
Atom 類型
應用程式可以建立兩種類型的 Atom:字串 atom 和整數 Atom。 整數 atom 和字串 atom 的值不會重疊,因此這兩種類型的 Atom 都可以在相同的程式代碼區塊中使用。
數個函式接受字串或 Atom 作為參數。 將原子傳送到這些函式時,應用程式可以使用 MAKEINTATOM 巨集指令,將原子轉換成函式可以使用的格式。
下列各節描述 Atom 類型。
字串原子
當應用程式將 null 終止的字串傳遞至 GlobalAddAtom、AddAtom、GlobalFindAtom和 FindAtom 函式時,它們會收到 字符串 atom (16 位整數)。 字串 Atom 具有下列屬性:
- 字串原子的值其範圍是從 0xC000(MAXINTATOM)到 0xFFFF。
- 在搜尋 atom 數據表中的 Atom 名稱時,案例並不重要。 此外,整個字串必須在搜尋作業中相符;不會執行任何子字串比對。
- 與字串 atom 相關聯的字串大小不能超過 255 個字節。 這項限制適用於所有 Atom 函式。
- 參考計數 與每個原子名稱相關聯。 每次將 Atom 名稱新增至資料表時,計數都會遞增,並在每次從數據表中刪除 Atom 名稱時遞減。 這可防止相同字串 atom 的不同使用者互相破壞對方的 atom 名稱。 當 Atom 名稱的參考計數等於零時,系統會從數據表中移除 atom 和 atom 名稱。
整數原子
整數原子與字串 atom 不同,方式如下:
- 整數原子的值在範圍中0x0001到0xBFFF(MAXINTATOM– 1)。
- 整數 atom 的字串表示法是 #dd,其中 dddd 所表示的值是十進制數。 將忽略前置零。
- 沒有與整數 Atom 相關聯的參考計數或記憶體額外負荷。
Atom 創建和使用計數
應用程式會藉由呼叫 AddAtom 函式來建立本機原子,並藉由呼叫 GlobalAddAtom 函式來建立全域原子。 這兩個函式都需要字串的指標。 系統會搜尋適當的 atom 數據表來尋找字串,並將對應的 Atom 傳回給應用程式。 在字串 Atom 的案例中,如果字串已經位於 atom 數據表中,系統就會在此程式期間遞增字串的參考計數。
重複呼叫以新增相同的 Atom 名稱會傳回相同的 Atom。 如果呼叫 addAtom時數據表中不存在原子名稱,則會將 Atom 名稱新增至數據表,並傳回新的 atom。 如果是字串 Atom,其參考計數也會設定為一。
當應用程式不再需要使用本機原子時,應呼叫 DeleteAtom 函式,應當在不再需要全域原子時呼叫 GlobalDeleteAtom 函式。 在字串 Atom 的情況下,這其中一個函式會將對應 Atom 的參考計數減少一個。 當參考計數達到零時,系統會從數據表中刪除 Atom 名稱。
只要字串 Atom 的參考計數大於零,字串 Atom 的 Atom 名稱就會保留在全域 Atom 數據表中,即使放置於數據表中的應用程式終止也一樣。 當相關聯的應用程式終止時,本地 Atom 表會被銷毀,無論該表中 Atom 的引用計數為何。
Atom-Table 查詢
應用程式可以使用 FindAtom 或 GlobalFindAtom 函式,判斷特定字串是否已經在 atom 數據表中。 這些函式會搜尋指定字串的 Atom 數據表,如果字串存在,則傳回對應的 Atom。
應用程式可以使用 getAtomName或 GlobalGetAtomName 函式,從 atom 數據表擷取 atom 名稱字串,前提是應用程式具有對應至所搜尋字串的 Atom。 這兩個函式會將指定之原子的名稱字串複製到緩衝區,並傳回複製的字串長度。 GetAtomName 會從本機 atom 數據表擷取 atom 名稱字串,GlobalGetAtomName 從全域 atom 數據表擷取 atom 名稱字元串。
Atom 字串格式
AddAtom、GlobalAddAtom、FindAtom和 GlobalFindAtom 函式會取得 null 終止字符串的指標。 應用程式可以使用下列其中一種方式來指定此指標。
字串格式 | 描述 |
---|---|
# dddd | 以十進位字串表示的整數。 用來建立或尋找整數原子。 |
字串 atom 名稱 | 字串原子名稱。 用來將字串 Atom 名稱新增至 atom 數據表,並接收傳回的 Atom。 |