UINT Ctest8Dlg:: ThreadProc(LPVOID p)
{
/*Ctest8Dlg* pthis=(Ctest8Dlg*)p;
pthis->m_str=_T("hello");
pthis->UpdateData(FALSE);*/
Ctest8Dlg obj;
HWND hWnd=(HWND)p;
obj.Attach(hWnd);
obj.m_str=_T("xx");
obj.UpdateData(FALSE);
obj.Detach();
return 0;
}
代碼出現(xiàn)的意義在于驗證 網(wǎng)上流傳的跨線程傳遞窗口對象指針的法子是否正確,
所以回答:采用發(fā)送消息給ui線程的人 勿擾。
謝謝。
問題2: 故意多次去釋放dll里的內(nèi)存,程序死活不崩潰。 dll里: char* _stdcall Test() { return new char[50]; }; exe里: for(int i=0; i<50;i++) { char* p=Test(); delete []p; } 這么多次循環(huán), 程序也不崩潰 回復(fù)討論(解決方案)用指針: Ctest8Dlg *pDlg = FromHandle(hWnd); 用指針: Ctest8Dlg *pDlg = FromHandle(hWnd); pthis->m_str=CString(_T("hello")); 按照你的修改,這一句崩潰了 原因不詳細。 另外: 你提供的法子,似乎是什么臨時的,網(wǎng)上有,但是我沒有看懂,臨時是否說明: 有隱患呢? 2個問題,謝謝解答。 問題1: 因為AfxBeginThread內(nèi)部已經(jīng)Attach了一次主界面 CWnd threadWnd; .... // thread inherits app's main window if not already set CWinApp* pApp = AfxGetApp(); ... threadWnd.Attach(pApp->m_pMainWnd->m_hWnd); pThread->m_pMainWnd = &threadWnd; 所以再次Attach是會斷言在 ASSERT(FromHandlePermanent(hWndNew) == NULL); // must not already be in permanent map 同一線程不能多次Attach同一窗口? 忽略彈出窗口,可繼續(xù)執(zhí)行。 如果用CWnd::FromHandle,獲得的將是上面的(&threadWnd)指針 由于是CWnd實體對象,強轉(zhuǎn)為Ctest8Dlg對象后,因為m_str不是CWnd成員,pthis->m_str可能會破壞內(nèi)存 或出現(xiàn)不可預(yù)料的結(jié)果 解決方法之一是將AfxBeginThread換成_beginthreadex(NULL, 0, ThreadProc, m_hWnd, 0, NULL); 另外記得在ThreadProc加上WINAPI(__stdcall) static UINT WINAPI ThreadProc(LPVOID p); 使用Attach的方法 如果用CWnd::FromHandle,還是會出錯,因為此時獲得是臨時的CWnd*對象指針,強轉(zhuǎn)為Ctest8Dlg*后,同樣會出錯。 問題2 這個起因是分配和釋放的CRT Heap不相同造成 CRT源碼里有一個全局句柄HANDLE _crtheap 如果exe和dll都使用動態(tài)DLL編譯,那么這個_crtheap只會存在一個,在msvcrXX.dll里 另外3中情況,靜態(tài)編譯會將_crtheap編譯進去,就會出錯 exe動態(tài) 和 dll靜態(tài)編譯:msvcrXX.dll和dll各1份_crtheap exe靜態(tài) 和 dll動態(tài)編譯:msvcrXX.dll和exe各1份_crtheap exe靜態(tài) 和 dll靜態(tài)編譯:exe和dll各1份_crtheap 1. Ctest8Dlg *pDlg = (Ctest8Dlg *)p; obj.m_str=_T("xx"); //這種操作本身不安全 比較好的方法是SendMessage以自定義消息的形式通知pDlg來修改m_str的值。絕對不會崩潰。 SendMessage(pDlg->GetSafeHwnd(),自定義消息編號,參數(shù)1,參數(shù)2); 2.為什么要崩潰?我倒不理解了。 樓主指針概念有問題吧。 問題1: 因為AfxBeginThread內(nèi)部已經(jīng)Attach了一次主界面 C/C++ code12345678 CWnd threadWnd;.... // thread inherits app's main window if not already set CWinApp* pApp = AfxGetApp();...…… 你好,老師 問題2 待會驗證回復(fù)你 問題1 我似乎沒有在帖子里提到用AfxBeginThread吧,最初我是用它創(chuàng)建線程,靈機一動,換成CreateThread 原因是這個函數(shù)是 mfc提供的,怕其不崩潰,所以換成win32的,創(chuàng)建線程后,依然崩潰。 所以你對其的回復(fù),可能不是很精準。 代碼為: CreateThread(NULL,0,ThreadProc,this,0,NULL); 線程代碼為: DWORD WINAPI Ctest8Dlg:: ThreadProc(LPVOID p) { Ctest8Dlg* pthis=(Ctest8Dlg*)FromHandle((HWND)p); pthis->m_str=CString(_T("hello")); pthis->UpdateData(FALSE); /*Ctest8Dlg obj; HWND hWnd=(HWND)p; obj.Attach(hWnd); obj.m_str=_T("xx"); obj.UpdateData(FALSE); obj.Detach();*/ return 0; } 線程函數(shù),我知道發(fā)送消息其實是可以解決的,但是不選擇發(fā)送消息的路線,是因為驗證 采用attach或者 FromHandle的法子如何解決。 這是第一個帖子的目的。 謝謝大家。 問題1: 因為AfxBeginThread內(nèi)部已經(jīng)Attach了一次主界面 C/C++ code12345678 CWnd threadWnd;.... // thread inherits app's main window if not already set CWinApp* pApp = AfxGetApp();...…… 問題2:4中情形我都驗證了,卻是如你所說的。 順便問一句,,困惑很久的一個小技巧 從vs2008開始,所有的工程里有個工程屬性叫: mfc的使用,有3個選項: 使用標準windows庫 mfc共享 mfc靜態(tài) 非mfc工程,默認是mfc共享, mfc靜態(tài)自然是你說的 靜態(tài)編譯了 那么使用標準windows庫是什么東西? 比如:我想寫一個超級簡單的控制臺程序,然后發(fā)布出去,選擇哪一個? 此時,是不是有些無奈? 多了一個window標準庫。 如果是我,我選擇靜態(tài)mfc。 實在不知道widnows 標準庫是靜態(tài)的,還是動態(tài)等。 老師,你有空,可以幫我看看,謝謝 1. Ctest8Dlg *pDlg = (Ctest8Dlg *)p; obj.m_str=_T("xx"); //這種操作本身不安全 比較好的方法是SendMessage以自定義消息的形式通知pDlg來修改m_str的值。絕對不會崩潰。 SendMessage(pDlg->GetSafeHwnd(),自定義消息編號,參數(shù)1,參數(shù)2); 2…… 看我的回復(fù),我已經(jīng)驗證,卻是崩潰了 MFC規(guī)定了一個線程僅僅能訪問它所創(chuàng)建的MFC對象。 為了阻止多個線程并發(fā)的訪問同一個MFC對象,MFC對象和WIndows對象之間有一個一一對應(yīng)的關(guān)系。這種關(guān)系以映射的形式保存在創(chuàng)建線程的當前模塊的模塊-線程狀態(tài)信息中。當一個線程使用某個MFC對象指針P時,ASSERT_VALID(p)將驗證當前線程的當前模塊是否有Windows句柄和p對應(yīng),即是否創(chuàng)建了p所指的Windows對象,驗證失敗導(dǎo)致ASSERT斷言中斷程序的執(zhí)行,如果一個線程要使用其它線程的Windows對象,則必須傳遞Windows對象的句柄,不能傳遞MFC對象的指針。 http://support.microsoft.com/kb/147578/zh-cn?wa=wsignin1.0 MFC規(guī)定了一個線程僅僅能訪問它所創(chuàng)建的MFC對象。 為了阻止多個線程并發(fā)的訪問同一個MFC對象,MFC對象和WIndows對象之間有一個一一對應(yīng)的關(guān)系。這種關(guān)系以映射的形式保存在創(chuàng)建線程的當前模塊的模塊-線程狀態(tài)信息中。當一個線程使用某個MFC對象指針P時,ASSERT_VALID(p)將驗證當前線程的當前模塊是否有Windows句柄和p對應(yīng),即是否創(chuàng)建了p所指的Wi…… 老師你好,對于這個知識點,我早有所聞, 只是不知道為什么mfc要有這么個規(guī)定 mfc一共引入了4個狀態(tài):模塊狀態(tài),線程狀態(tài), 模塊-線程狀態(tài), 進程狀態(tài)。 前3個狀態(tài)似乎是為 mfc的tls服務(wù)的, 理解起來也比較費勁。 DWORD WINAPI Ctest8Dlg:: ThreadProc(LPVOID p) { Ctest8Dlg* pthis=(Ctest8Dlg*)FromHandle((HWND)p); pthis->m_str=CString(_T("hello")); pthis->UpdateData(FALSE); /*Ctest8Dlg obj; HWND hWnd=(HWND)p; obj.Attach(hWnd); obj.m_str=_T("xx"); obj.UpdateData(FALSE); obj.Detach();*/ return 0; } 我已經(jīng)按照這個法子了,依然會有崩潰。 崩潰在m_str賦值這里,原因不詳! 原因是FromHandle這個函數(shù)返回的是CWnd*指針,但是你將它強制轉(zhuǎn)化成了Ctest8Dlg*指針,這樣本身就是很危險的,而你后面又訪問了Ctest8Dlg類自己定義的成員變量(而這個成員變量在CWnd類中并沒有定義它),所以這里就錯了。 原因是FromHandle這個函數(shù)返回的是CWnd*指針,但是你將它強制轉(zhuǎn)化成了Ctest8Dlg*指針,這樣本身就是很危險的,而你后面又訪問了Ctest8Dlg類自己定義的成員變量(而這個成員變量在CWnd類中并沒有定義它),所以這里就錯了。 有些道理, CWnd的派生類過多,而且其本身也有基類,那么最終拍攝各類Ctest8dlg* 所指向的內(nèi)存就不是爺爺基類 Cwnd的地址了,所以這里就錯誤了。 如此說來, 這個法子是個雞肋了, 對任何CWnd的派生類來說,都比較危險,除非用該指針去訪問 CWnd的成員函數(shù)才沒事情, 否則只要訪問派生類CDialog 或者Ctest8dlg里的 自己增加的函數(shù)或者成員,都會出錯。 引用 10 樓 VisualEleven 的回復(fù):原因是FromHandle這個函數(shù)返回的是CWnd*指針,但是你將它強制轉(zhuǎn)化成了Ctest8Dlg*指針,這樣本身就是很危險的,而你后面又訪問了Ctest8Dlg類自己定義的成員變量(而這個成員變量在CWnd類中并沒有定義它),所以這里就錯了。 有些道理, CWnd的派生類過多,而且其本身也有基類,那么最終…… CWnd* pthis=FromHandle((HWND)p); //pthis->m_str=CString(_T("hello")); if(pthis) { pthis->SetWindowText(_T("xx")); } setwindowtext 崩潰。 說明這個法子,太危險了, 很多東西搞不定。 指針我調(diào)試過了,是有值的。 雞肋法子啊,都不知道CWnd的哪一個成員函數(shù)可以使用了。 引用 10 樓 VisualEleven 的回復(fù):原因是FromHandle這個函數(shù)返回的是CWnd*指針,但是你將它強制轉(zhuǎn)化成了Ctest8Dlg*指針,這樣本身就是很危險的,而你后面又訪問了Ctest8Dlg類自己定義的成員變量(而這個成員變量在CWnd類中并沒有定義它),所以這里就錯了。 有些道理, CWnd的派生類過多,而且其本身也有基類,那么最終…… 訪問函數(shù)沒有關(guān)系,只要該函數(shù)中沒有訪問該類中自己定義的成員變量即可 this = 0x002cfdc4 {Ctest8Dlg hWnd=0x00680342} pthis = 0x001a9eac {CWnd hWnd=0x00680342} 這是我做的實驗, 在線程里獲得CWnd指針是最后那個, CXXdlg指針是上的那個。 可見,F(xiàn)romHandle獲得的指針是祖父類的。并非孫類的。 那么自然就不能使用祖父類的指針去調(diào)用非祖父類的函數(shù)了,對吧。 除非動態(tài)綁定技術(shù)。 這個從c++語法的角度分析,我覺得沒有問題吧。 順便糾正12樓,12樓是錯誤的, 原因在于,我傳參數(shù)的時候,不小心沒有把句柄,從線程里傳進去。 是我的失誤 引用 3 樓 stjay 的回復(fù):問題1: 因為AfxBeginThread內(nèi)部已經(jīng)Attach了一次主界面 C/C++ code12345678 CWnd threadWnd;.... // thread inherits app's main window if not already set CWinApp* pApp …… 同時跟正第5樓的實驗 和 15樓一樣, 線程傳參數(shù)失誤了, 代碼是沒有問題的。 感謝大家的熱心解答。 引用 3 樓 stjay 的回復(fù):問題1:
因為AfxBeginThread內(nèi)部已經(jīng)Attach了一次主界面 C/C++ code12345678 CWnd threadWnd;.... // thread inherits app's main window if not already set CWinApp* pApp …… 剩下第6樓的問題 windows標準庫是動態(tài)的,還是靜態(tài)編譯的? |
|
|