在VB6 IDE中實現(xiàn)安全子類化

作者:胎神


原帖來源:【VB】 在VB6IDE中實現(xiàn)安全子類化? 文章鏈接會被屏蔽么鹤,請自己搜索?0xaa55?或?技術(shù)宅的結(jié)界?(出處:技術(shù)宅的結(jié)界,轉(zhuǎn)載請保留出處?)


文章最后有?源碼示例下 載服傍。

  VB6給我們開發(fā)者提供了非常簡單方便的GUI設(shè)計功能暇昂,因此受到了大多數(shù)開發(fā)者的喜愛“槲耍可是VB6提供的使用功能卻非常少急波,這個時候就通過子類化等手段繞過VB6的封裝,直接取接管底層的系統(tǒng)消息來對其擴(kuò)展瘪校。
  然而澄暮,VB6IDE的作者當(dāng)初犯了一個非常胎神的錯誤,那就是讓用戶編寫的代碼直接在IDE進(jìn)程中運行了阱扬,沒有通過子進(jìn)程+進(jìn)程調(diào)試模式(有的胎神看到這里會反駁說著就是VB6優(yōu)勢不用花大量時間去先編譯代碼泣懊,我表示VB6作者完全可以設(shè)計一個叫 解釋器.exe 的獨立可執(zhí)行程序到VB6安裝包中,在我們要調(diào)試運行的時候麻惶,它直接發(fā)代碼文本發(fā)送給這個子進(jìn)程不就行了馍刮,這樣不就既有解釋運行的快速啟動,又有不崩IDE的風(fēng)險嗎窃蹋?)卡啰,這就會導(dǎo)致程序一旦出現(xiàn)致命錯誤就把整個IDE給崩掉了(很多開發(fā)者這個時候都還沒來得及保存代碼)。
  言歸正傳警没,現(xiàn)在假如某個開發(fā)者本身技術(shù)確實比較牛批匈辱,不容易寫出本身有致命錯誤的代碼,但是在Form杀迹、控件被子類化的時候亡脸,VB6本身是回調(diào)機(jī)制就已經(jīng)自帶了極易導(dǎo)致致命錯誤的風(fēng)險(哪怕你本身代碼寫的再好),只要不小心下了斷點树酪、點了暫停浅碾、結(jié)束運行,或有沒有On Error的異常都會導(dǎo)致VB6IDE崩掉续语。

  經(jīng)過我多年的研究終于搞清楚了子類化極易導(dǎo)致IDE崩掉的根本原因:

  • 當(dāng)我們直接點擊IDE的<按鈕或用End語句結(jié)束執(zhí)行的時候垂谢,VB6釋放掉了AddressOf的地址,但是我們沒有代碼去及時移除子類化绵载,系統(tǒng)會仍然往已釋放的地址上回調(diào)埂陆。

  • 當(dāng)我們在點擊IDE的;按鈕或打上斷點觸發(fā)暫停的時候苛白,這時VB6雖然還沒有釋放AddressOf的地址娃豹,但是當(dāng)有新的窗口消息來時,會導(dǎo)致IDE進(jìn)入運行狀態(tài)直到該函數(shù)返回再重新恢復(fù)暫停狀態(tài)购裙,但是如果在這里如果又觸發(fā)了再次斷點懂版,就會發(fā)生和恐怖的事情:在斷點中又去執(zhí)行新的消息、新的消息有觸發(fā)斷點躏率、新的斷點又能接收更新的消息…躯畴。最后因為一直遞歸把堆椕窆模空間消耗完了蓬抄,導(dǎo)致了堆棧溢出錯誤丰嘉,結(jié)果在提示堆棧溢出的錯誤對話框的消息循環(huán)中還在繼續(xù)觸發(fā)子類化消息回調(diào),最終導(dǎo)致了IDE進(jìn)程崩掉嚷缭。

  • 在正常情況下的代碼出現(xiàn)錯誤時饮亏,VB6會彈出錯誤提示對話框,這時我們可以選擇 調(diào)試 或 停止 兩個選項阅爽,選擇 停止 會觸發(fā) 1 的流程路幸,選擇 調(diào)試 則觸發(fā) 2 的流程,最終還是會導(dǎo)致IDE進(jìn)程崩掉付翁,最蛋疼是報錯對話框是模態(tài)简肴,IDE主窗口被鎖住了,這時沒法點擊保存百侧。

  為了解決以上各種蛋疼問題砰识,我選擇了使用加載外部dll方案,因為:

  • 只要子類化回調(diào)函數(shù)的dll沒有被FreeLibrary佣渴,回調(diào)函數(shù)的地址就始終有效仍翰。

  • 即便VB6IDE進(jìn)入暫停模式,外部dll并沒有被暫停观话,它仍然可以正常工作(只要這時候它只做自己的工作予借,不回調(diào)給VB6IDE的臨時代碼就行,我在這時的做法就是判斷IDE在暫停狀態(tài)就直接執(zhí)行默認(rèn)處理频蛔,運行狀態(tài)才回調(diào)給VB6)灵迫。

  • dll使用COM接口機(jī)制,可以保證VB6會正確的自動釋放對象(哪怕是直接點擊IDE的<按鈕或用End語句結(jié)束執(zhí)行的時候)晦溪,這時我就可以利用COM對象的析構(gòu)函數(shù)去實現(xiàn)自動的安全移除子類化監(jiān)聽回調(diào)(注意:在VB6中End后瀑粥,IDE自身類模塊中的析構(gòu)函數(shù)是不會再執(zhí)行的,但外部dll不存在這個問題三圆,仍然會正確執(zhí)行)狞换。

  順便再說一下傳統(tǒng)的SetWindowLong的子類化方式的缺陷:

  • SetWindowLong 不兼容64位環(huán)境

  • SetWindowLong 沒有掛鉤順序管理:假如a先子類化b后子類化,就必須要b先還原子類化a后還原子類化才能正確執(zhí)行舟肉。如果a先還原子類化修噪,這時b就收不到任何消息了,等到b還原子類化的時候卻把a(bǔ)的回調(diào)地址給設(shè)置上去了路媚,使得a重新開始接收了子類化消息(但是這時a的地址是有可能已經(jīng)釋放掉了)黄琼。

  • SetWindowLong 不能給回調(diào)函數(shù)附加額外數(shù)據(jù),回調(diào)函數(shù)里面只能收到hWnd句柄整慎,但沒法直到hWnd句柄對應(yīng)的是哪個Form或哪個控件(這里肯定又有胎神會提到 SetWindowLong hWnd, GWL_USERDATA, ObjPtr(控件對象) 的操作了脏款,但是想想如果有 a 和 b 兩個人都子類化了同一個窗口會怎樣围苫?)。

  其實SetWindowLong的缺陷巨硬早在二十多年就給我們提供了解決方案撤师,使用新API SetWindowSubclass 來子類化(SetWindowSubclass 保證了32位和64位通用剂府、安全管理了多重掛鉤,支持了任意順序解除剃盾、并且提供了指針長度的任意附加數(shù)據(jù))周循。
  所以,最后我根據(jù)以上原理万俗,使用VC艸封裝一個叫 sscls.dll(全稱 SafeSubclass 安全子類化)的組件湾笛,內(nèi)部使用輕量級COM機(jī)制來實現(xiàn)既不需要注冊又能獲得COM對象自動安全析構(gòu),使用新子類化API SetWindowSubclass 來保證多次子類化的安全和回調(diào)對象關(guān)聯(lián)闰歪,調(diào)用VBA6.DLL的EbMode來監(jiān)測IDE執(zhí)行狀態(tài)嚎研,以防止暫停和停止時極易崩掉IDE的問題。

  以下則是 SafeSubclass(安全子類化)組件 的使用方法:

1-打開VBAIDE目錄

2-復(fù)制到VB6安裝目錄

3-在VB6工程中打開引用對話框

4-添加sscls.tlb文件的引用

5-編寫代碼進(jìn)行子類化

6-可以在消息中任意暫停

7-強(qiáng)制結(jié)束也可以正常退回IDE設(shè)計模式并自動釋放子類化對象的內(nèi)存

8-示例目錄中的sscls.dll用于最終發(fā)布的exe攜帶


下載:胎神作品SafeSubclass.rar

鏈接: https://pan.baidu.com/s/1jpvJRhd-Zs4VskSCQuTMHQ?pwd=rjtj 提取碼: rjtj

如對您有幫助库倘,可點個贊及關(guān)注我



?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末临扮,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子教翩,更是在濱河造成了極大的恐慌杆勇,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件饱亿,死亡現(xiàn)場離奇詭異椎瘟,居然都是意外死亡滩租,警方通過查閱死者的電腦和手機(jī)巢掺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進(jìn)店門淆九,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人配猫,你說我怎么就攤上這事幅恋。” “怎么了泵肄?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵捆交,是天一觀的道長。 經(jīng)常有香客問我腐巢,道長品追,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任系忙,我火速辦了婚禮诵盼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘银还。我一直安慰自己风宁,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布蛹疯。 她就那樣靜靜地躺著戒财,像睡著了一般。 火紅的嫁衣襯著肌膚如雪捺弦。 梳的紋絲不亂的頭發(fā)上饮寞,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天,我揣著相機(jī)與錄音列吼,去河邊找鬼幽崩。 笑死,一個胖子當(dāng)著我的面吹牛寞钥,可吹牛的內(nèi)容都是我干的慌申。 我是一名探鬼主播,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼理郑,長吁一口氣:“原來是場噩夢啊……” “哼蹄溉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起您炉,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤柒爵,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后赚爵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體棉胀,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年冀膝,在試婚紗的時候發(fā)現(xiàn)自己被綠了膏蚓。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,731評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡畸写,死狀恐怖驮瞧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情枯芬,我是刑警寧澤论笔,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站千所,受9級特大地震影響狂魔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜淫痰,卻給世界環(huán)境...
    茶點故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一最楷、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦籽孙、人聲如沸烈评。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽讲冠。三九已至,卻和暖如春适瓦,著一層夾襖步出監(jiān)牢的瞬間竿开,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工玻熙, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留否彩,地道東北人。 一個月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓嗦随,卻偏偏與公主長得像列荔,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子称杨,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,629評論 2 354

推薦閱讀更多精彩內(nèi)容