在windows系列上做編程,gdi是一個很重要的技術(shù)點,有很多程序在運行多次后出現(xiàn)異常,除了眾所周知的內(nèi)存泄露以外,gdi資源泄露也是一個很直接的原因.今天就把我自己在編程中總結(jié)的一些經(jīng)驗給大家分享,歡迎高手補充.
1.Create出來的gdi對象,一定要用DeleteObject來釋放,釋放順序是先Create的后釋放,后Create的先釋放.
這里的Create指的是以它為開頭的gdi函數(shù),比如,CreateDIBitmap,CreateFont等等,最后都要調(diào)用DeleteObject來釋放.
2.Create出來的dc要用DeleteDC來釋放,Get到的要用ReleaseDC釋放.
3.確保釋放DC的時候DC中的各gdi對象都不是你自己創(chuàng)建的;確保個gdi對象在釋放的時候不被任何dc選中使用.
假如我們要使用gdi函數(shù)畫圖,正確的步驟應(yīng)該如下:
a.創(chuàng)建一個內(nèi)存兼容dc(CreateCompatibleDC)
b.創(chuàng)建一個內(nèi)存兼容bitmap(CreateCompatibleBitmap)
c.關(guān)聯(lián)創(chuàng)建的內(nèi)存兼容dc和bitmap(SelectObject)
d.畫圖
e.BitBlt到目的dc上
f.斷開內(nèi)存兼容dc和bitmap關(guān)聯(lián)(SelectObject)
g.銷毀內(nèi)存兼容bitmap
h.銷毀內(nèi)存兼容dc
由于SelectObject在選入一個新的gdi對象的時候會返回一個原來的gdi對象(假如成功的話),所以需要在步驟c的時候保存返回值,在步驟f的時候當作入口參數(shù)使用.還有,步驟g和步驟h實際上順序可以隨意,因為他們兩個此刻已經(jīng)沒有關(guān)系了,但是為了結(jié)構(gòu)清晰,我建議按照"先Create的后釋放,后Create的先釋放"的原則進行.
關(guān)于步驟f,可能會有爭議,因為即使省略這一步,步驟g和步驟h看起來照樣可以返回一個成功的值.但實際上可能并沒有執(zhí)行成功,至少boundschecker會報告有錯,錯誤信息大致是說,在釋放dc的時候還包含有非默認的gdi對象,在釋放gdi對象的時候又說這個gdi對象還被一個dc在使用.所以,我建議保留步驟f.
4.關(guān)于98下使用CreateCompatibleBitmap
按照msdn的說法,創(chuàng)建出來的size不能超過16m.實際情況是這樣嗎?非也~!從我自己做的測試結(jié)果來看(win98se-sc),這個值在2044*2043和2044*2044之間,然而,后來在另外一個98系統(tǒng)上這個值也不行,后來我干脆把上限給成了2000*2000.很幸運,到現(xiàn)在還沒有出問題,但我不能保證這個數(shù)字就是正確的.還有一點,假如寬或高有一個超過32768,哪怕另外一個值是1,也會創(chuàng)建失敗,有興趣的可以自己做個測試.如果要想保證這個函數(shù)在98下永遠成功,可以試試下面的代碼:
float factor = 10.f;
while(!bitmap.CreateCompatibleBitmap(&dc ,nWidth*factor ,nHeight*factor))
{
factor -= 0.01f;
}
這樣至少可以保證寬和高是成比例的:)
5.關(guān)于在打印機上使用BitBlt
有時候在內(nèi)存兼容dc里面已經(jīng)做好圖了,但在使用BitBlt的時候卻會失敗.這個時候,首先確認創(chuàng)建的內(nèi)存兼容dc和bitmap是不是使用打印機的dc,如果確認無誤,還是執(zhí)行BitBlt失敗,那80%可能是內(nèi)存兼容bitmap太大了,請按如下方法再試試:
創(chuàng)建另外一個內(nèi)存兼容dc2和一個比較小的內(nèi)存兼容biimap2,大概是1000*1000吧,我是這樣用的:)然后把dc里面的內(nèi)容分成塊(1000*1000),把每一塊BitBlt到dc2上面,再從dc2里面BitBlt到打印dc上.有人可能會有這樣的疑問:那為什么不直接把dc里面的內(nèi)容分幾次BitBlt到打印機上呢?有區(qū)別嗎?答案是肯定的,如果dc里面的bitmap太大,哪怕你想BitBlt一個10*10的區(qū)域到打印機上都會失敗.