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