日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

自定义ActiveX组件在设计阶段,切换属性页后出现异常

發布時間:2023/12/9 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 自定义ActiveX组件在设计阶段,切换属性页后出现异常 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

源碼下載:ActiveX-Clock-OCX

?

參照孫鑫的<<VC++深入詳解>>中第18章自定義ActiveX中的Clock例子(到18.3節之前),完成了OCX控件的制作,而且也編譯(Debug模式)、注冊成功了!于是又創建了一個MFC基于對話框的測試程序,在對話框中放入了這個Clock控件,界面如下:

接下來右擊Clock控件,選擇“屬性”,切換到“設置時間間隔面板”,更改時間后,切換到其他一個屬性頁,這時就出現assert宏異常了,看圖:

?

?

?

真是奇怪,孫鑫的教程里也沒提到有這個問題。后來試了下在Release模式下編譯成功的OCX,發現在切換屬性頁時卻沒有這樣的問題,一切都是正常的。

看來是優化的問題吧,詳情未知,猜測而已!

?

看到第18章的總結(Page708)才發現,原來孫鑫老師還是提到了這個問題的。

他說出現這種錯誤的原因是:當將Clock控件放到VB的Form上時,該控件的窗口已經創建,也就是說,CClockCtrl類的OnCreate()方法被執行了,這樣就設置了定時器。而在VC的對話框上插入Clock控件時,卻沒有調用CClockCtrl類的OnCreate()方法,當修改Interval屬性時,會調用CClockCtrl類的OnIntervalChanged()方法,在這個方法中,調用了KillTimer(1),因為定時器根本沒有創建,因此就出現了非法操作。解決辦法是:用一個變量保存定時器的返回值,然后在OnIntervalChanged()方法中對返回值進行判斷。

?于是我將代碼改成下面的樣子:

void CClockCtrl::OnIntervalChanged() {if(m_nInterval < 0 || m_nInterval > 6000)m_nInterval = 1000;elsem_nInterval = m_nInterval / 1000 * 1000;//if(timer_flag != 0){MessageBox("OnIntervalChanged: going to do KillTimer()");//KillTimer(1);timer_flag = 0;}MessageBox("OnIntervalChanged: going to do SetTimer()");//timer_flag = SetTimer(1, m_nInterval, NULL);SetTimer(1, m_nInterval, NULL);char message[100] = {0};sprintf(message, "timer_flag = %d", timer_flag);MessageBox(message);SetModifiedFlag(); }


再經過測試,發現在切換屬性頁時,彈出窗口輸出了“OnIntervalChanged: going to do SetTimer()”后就出現了ASSERT()宏異常,可見這個異常是出現在SetTimer()內部的。我們都知道,ASSERT()宏只有在Debug模式下才會起作用,在Release下是不會起作用的,這就是為什么使用Release時生成的ocx時不會彈出ASSERT()宏異常窗口的原因了。可是為什么SetTimer()會失敗呢???

先來看下Plateform SDK中的SetTimer()原型吧:

UINT_PTR SetTimer(HWND hWnd, // handle to windowUINT_PTR nIDEvent, // timer identifierUINT uElapse, // time-out valueTIMERPROC lpTimerFunc // timer procedure );


看到第一個參數hWnd了嗎,這是與窗口的句柄相關聯的,但是孫鑫老師也說了“將Clock控件放到VB的Form上時,該控件的窗口已經創建”,但是“在VC的對話框上插入Clock控件時,卻沒有調用CClockCtrl類的OnCreate()方法?”,這里的關鍵不是指“OnCreate()中的SetTimer()”,而是指“窗口沒有創建”,所以“窗口對應的句柄又將是多少”呢?正是因為控件窗口沒有創建,所以“CClockCtrl::OnIntervalChanged() ”中的“SetTimer()”和“KillTimer()”都將會失敗,而且失敗的主要原因是在其函數內部對“窗口句柄”的ASSERT()判斷。因此,我認為孫鑫老師說的“解決辦法”是行不通的,除非不調用KillTimer()和SetTimer(),但是這樣的話,就達不到控制多少秒觸發一次OnDraw()的效果了!

經過調試,終于在“D:\Program Files\Microsoft Visual Studio\VC98\MFC\Include\AFXWIN2.INL文件中的第166-171行”找到了SetTimer()和KillTimer()的具體實現:

_AFXWIN_INLINE UINT CWnd::SetTimer(UINT nIDEvent, UINT nElapse,void (CALLBACK* lpfnTimer)(HWND, UINT, UINT, DWORD)){ ASSERT(::IsWindow(m_hWnd)); return ::SetTimer(m_hWnd, nIDEvent, nElapse,(TIMERPROC)lpfnTimer); } _AFXWIN_INLINE BOOL CWnd::KillTimer(int nIDEvent){ ASSERT(::IsWindow(m_hWnd)); return ::KillTimer(m_hWnd, nIDEvent); }


因此,我認為解決的辦法有3種

1. 使用“Release方式生成的OCX”

2. 越過KillTimer()和SetTimer()中“ASSERT(::IsWindow(m_hWnd)); ”,即將CClockCtrl::OnIntervalChanged() 中的內容修改如下:

void CClockCtrl::OnIntervalChanged() {if(m_nInterval < 0 || m_nInterval > 6000)m_nInterval = 1000;elsem_nInterval = m_nInterval / 1000 * 1000;//KillTimer(1); // 為了越過KillTimer()中的ASSERT(::IsWindow(m_hWnd)); ::KillTimer(m_hWnd, 1);::SetTimer(m_hWnd, 1, m_nInterval, NULL);//SetTimer(1, m_nInterval, NULL);SetModifiedFlag(); }


這時,在切換屬性頁時雖然也會執行::KillTimer和::SetTimer(),而且其中的m_hWnd可能為一個非法的值,但是起碼不會彈出ASSERT()宏異常窗口,大不了就是這兩個函數調用失敗而已,所以也解決了這個問題。

3. 判斷控件當前狀態是否為運行狀態,如果是才調用SetTimer()和KillTimer(),即修改CClockCtrl::OnIntervalChanged()的內容如下:

?

void CClockCtrl::OnIntervalChanged() {if(m_nInterval < 0 || m_nInterval > 6000)m_nInterval = 1000;elsem_nInterval = m_nInterval / 1000 * 1000;if(AmbientUserMode()){KillTimer(1); // 為了越過KillTimer()中的ASSERT(::IsWindow(m_hWnd)); //::KillTimer(m_hWnd, 1);//::SetTimer(m_hWnd, 1, m_nInterval, NULL);SetTimer(1, m_nInterval, NULL);}SetModifiedFlag(); }


如果各位有什么不同的看法,歡迎提出來探討!

總結

以上是生活随笔為你收集整理的自定义ActiveX组件在设计阶段,切换属性页后出现异常的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。