gdi使用經驗分享

在windows系列上做編程,gdi是一個很重要的技術點,有很多程序在運行多次後出現異常,除了衆所周知的內存泄露以外,gdi資源泄露也是一個很直接的原因.今天就把我自己在編程中總結的一些經驗給大家分享,歡迎高手補充.
1.Create出來的gdi對象,一定要用DeleteObject來釋放,釋放順序是先Create的後釋放,後Create的先釋放.
這裏的Create指的是以它爲開頭的gdi函數,比如,CreateDIBitmap,CreateFont等等,最後都要調用DeleteObject來釋放.

2.Create出來的dc要用DeleteDC來釋放,Get到的要用ReleaseDC釋放.

3.確保釋放DC的時候DC中的各gdi對象都不是你自己創建的;確保個gdi對象在釋放的時候不被任何dc選中使用.
假如我們要使用gdi函數畫圖,正確的步驟應該如下:
a.創建一個內存兼容dc(CreateCompatibleDC)
b.創建一個內存兼容bitmap(CreateCompatibleBitmap)
c.關聯創建的內存兼容dc和bitmap(SelectObject)
d.畫圖
e.BitBlt到目的dc上
f.斷開內存兼容dc和bitmap關聯(SelectObject)
g.銷燬內存兼容bitmap
h.銷燬內存兼容dc
由於SelectObject在選入一個新的gdi對象的時候會返回一個原來的gdi對象(假如成功的話),所以需要在步驟c的時候保存返回值,在步驟f的時候當作入口參數使用.還有,步驟g和步驟h實際上順序可以隨意,因爲他們兩個此刻已經沒有關係了,但是爲了結構清晰,我建議按照"先Create的後釋放,後Create的先釋放"的原則進行.
關於步驟f,可能會有爭議,因爲即使省略這一步,步驟g和步驟h看起來照樣可以返回一個成功的值.但實際上可能並沒有執行成功,至少boundschecker會報告有錯,錯誤信息大致是說,在釋放dc的時候還包含有非默認的gdi對象,在釋放gdi對象的時候又說這個gdi對象還被一個dc在使用.所以,我建議保留步驟f.

4.關於98下使用CreateCompatibleBitmap
按照msdn的說法,創建出來的size不能超過16m.實際情況是這樣嗎?非也~!從我自己做的測試結果來看(win98se-sc),這個值在2044*2043和2044*2044之間,然而,後來在另外一個98系統上這個值也不行,後來我乾脆把上限給成了2000*2000.很幸運,到現在還沒有出問題,但我不能保證這個數字就是正確的.還有一點,假如寬或高有一個超過32768,哪怕另外一個值是1,也會創建失敗,有興趣的可以自己做個測試.如果要想保證這個函數在98下永遠成功,可以試試下面的代碼:
float factor = 10.f;
while(!bitmap.CreateCompatibleBitmap(&dc ,nWidth*factor ,nHeight*factor))
{
factor -= 0.01f;
}
這樣至少可以保證寬和高是成比例的:)

5.關於在打印機上使用BitBlt
有時候在內存兼容dc裏面已經做好圖了,但在使用BitBlt的時候卻會失敗.這個時候,首先確認創建的內存兼容dc和bitmap是不是使用打印機的dc,如果確認無誤,還是執行BitBlt失敗,那80%可能是內存兼容bitmap太大了,請按如下方法再試試:
創建另外一個內存兼容dc2和一個比較小的內存兼容biimap2,大概是1000*1000吧,我是這樣用的:)然後把dc裏面的內容分成塊(1000*1000),把每一塊BitBlt到dc2上面,再從dc2裏面BitBlt到打印dc上.有人可能會有這樣的疑問:那爲什麼不直接把dc裏面的內容分幾次BitBlt到打印機上呢?有區別嗎?答案是肯定的,如果dc裏面的bitmap太大,哪怕你想BitBlt一個10*10的區域到打印機上都會失敗

發佈了3 篇原創文章 · 獲贊 0 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章