共用方式為


Windows 機密文件 Windows 不是不能,而是不要

Raymond Chen

其實 Windows 不是不能更換使用中的 DLL 檔,它只要將原始檔案重新命名,然後將命名後的新檔案複製妥當就行了。但是 Windows 不想這麼做。為什麼呢?

即使換掉使用中的檔案,系統仍有程式碼想要使用舊版檔案。舉個例說,假設您有兩個彼此合作的檔案 A.DLL 和 B.DLL,而且您想要更新這兩個檔案,於是便發出一個修補程式,但此時 A.DLL 正在使用中。不必客氣,儘管一起換。結果,A.DLL 這一方是新程式採用新版檔案,而正在使用舊版檔案的程式,則仍然繼續使用舊版檔案。但是 B.DLL 這一方則是所有程式全部採用新版檔案。

假設當時正在使用舊版 A.DLL 檔的某個程式,現在決定要呼叫一個函數。它自然會以為呼叫的是舊版 B.DLL 檔,不料呼叫到的卻是新版檔案。呼叫也許成功,也許失敗,要看您對 B.DLL 做了哪些變更而定。這兩個 DLL 都認定對方是來自同一個組合的夥伴。

就算您現在只是更新一個沒有相依性的 DLL,還是會有潛在問題,因為 DLL 必須與「本身」的舊版交互操作。

假設您在 ole32.dll 正在使用時將它更換。那麼新啟動的程式會呼叫新版的 ole32.dll,並且起始拖放作業。使用者會將物件拖曳到更新前啟動的其中一個程式所建立的視窗上面。這麼一來,新版 ole32.dll 就會傳送訊息給舊版 ole32.dll。

當您編寫處理序之間通訊的程式碼時,通常會認定每一個處理序中所執行的程式碼是同一個版本,因為通訊通道中的兩個端點,必須對於它們的通訊方式達成共識。「我現在要傳給你訊息 5 (亦即「要求文字」),而我認定你會傳給我訊息 12 (亦即「這就是你要求的文字」) 作為回覆」。如果兩端執行的程式碼不是同一版本,通訊機制就不一定相同;差異也許微乎其微,但仍會導致不相容的情況。

假設您在某個結構加入一個欄位,而該結構碰巧是訊息 5 的一部分。乖乖!這下您就有兩個互不同容的訊息 5 版本了 — 一個使用舊結構,另一個使用新結構。如果通訊雙方對於結構沒有達成共識,訊息 5 就傳不成了。

如果您要支援並行執行舊版和新版,必須另起一個新訊息 (假設是 52 吧),然後讓新版 DLL 支援訊息 5 和訊息 52。它必須先判斷在另一端執行的是哪一版的 DLL,然後再傳給它適當的訊息。

就算您沒更改過結構本身,也可能更改過結構中某些欄位的意義。如果該結構原本有一個列舉細目,新版本又在該列舉細目加了一個新值,那麼新版和舊版之間仍然不相容。

當然囉,您可以在每發出一個修補程式就定義新訊息,並且編寫程式碼,在兩個相衝突版本的 DLL 同時執行的視窗中,支援新舊版間的交互操作。但是這麼一來,訊息組合就會越來越多,光是發到第三個修補程式時,就已經多達四個訊息組合了 (其中一個是針對原始版的訊息組合,另一個則是針對每一個修補程式的訊息組合)。

就算您要求這些修補程式必須依序安裝,也不會為您節省半絲精力;因為只要您容許原始程式保持執行,就必須持續與它交互操作。

接著開始就有人撰文罵您笨蛋,因為您發出修補程式的速度實在太慢了!

所以 Windows 並不是不想面對更換使用中檔案之後必須重開機的麻煩,而是不想面對因為不重開機所帶來的麻煩。凡是工程設計都需要取捨和平衡。您真的想花功夫支援舊版,來換取一個連穩定狀態設定都談不上的結果嗎?

Raymond Chen 的網站「The Old New Thing」以及同名著作均探討 Windows 的歷史和 Win32 程式設計。他的心願就是您能夠平安回家。