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)的意義在于驗(yà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"));
按照你的修改,這一句崩潰了
原因不詳細(xì)。
另外: 你提供的法子,似乎是什么臨時的,網(wǎng)上有,但是我沒有看懂,臨時是否說明:
有隱患呢?
2個問題,謝謝解答。
問題1:
因?yàn)锳fxBeginThread內(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實(shí)體對象,強(qiáng)轉(zhuǎn)為Ctest8Dlg對象后,因?yàn)閙_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,還是會出錯,因?yàn)榇藭r獲得是臨時的CWnd*對象指針,強(qiáng)轉(zhuǎn)為Ctest8Dlg*后,同樣會出錯。
問題2
這個起因是分配和釋放的CRT Heap不相同造成
CRT源碼里有一個全局句柄HANDLE _crtheap
如果exe和dll都使用動態(tài)DLL編譯,那么這個_crtheap只會存在一個,在msvcrXX.dll里
另外3中情況,靜態(tài)編譯會將_crtheap編譯進(jìn)去,就會出錯
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:
因?yàn)锳fxBeginThread內(nèi)部已經(jīng)Attach了一次主界面
C/C++ code12345678 CWnd threadWnd;.... // thread inherits app's main window if not already set CWinApp* pApp = AfxGetApp();...……
你好,老師
問題2 待會驗(yàn)證回復(fù)你
問題1
我似乎沒有在帖子里提到用AfxBeginThread吧,最初我是用它創(chuàng)建線程,靈機(jī)一動,換成CreateThread
原因是這個函數(shù)是 mfc提供的,怕其不崩潰,所以換成win32的,創(chuàng)建線程后,依然崩潰。
所以你對其的回復(fù),可能不是很精準(zhǔn)。
代碼為: 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ā)送消息其實(shí)是可以解決的,但是不選擇發(fā)送消息的路線,是因?yàn)轵?yàn)證
采用attach或者 FromHandle的法子如何解決。
這是第一個帖子的目的。
謝謝大家。
問題1:
因?yàn)锳fxBeginThread內(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中情形我都驗(yàn)證了,卻是如你所說的。
順便問一句,,困惑很久的一個小技巧
從vs2008開始,所有的工程里有個工程屬性叫:
mfc的使用,有3個選項(xiàng):
使用標(biāo)準(zhǔn)windows庫
mfc共享
mfc靜態(tài)
非mfc工程,默認(rèn)是mfc共享, mfc靜態(tài)自然是你說的 靜態(tài)編譯了
那么使用標(biāo)準(zhǔn)windows庫是什么東西?
比如:我想寫一個超級簡單的控制臺程序,然后發(fā)布出去,選擇哪一個?
此時,是不是有些無奈? 多了一個window標(biāo)準(zhǔn)庫。
如果是我,我選擇靜態(tài)mfc。
實(shí)在不知道widnows 標(biāo)準(zhǔn)庫是靜態(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)驗(yàn)證,卻是崩潰了
MFC規(guī)定了一個線程僅僅能訪問它所創(chuàng)建的MFC對象。
為了阻止多個線程并發(fā)的訪問同一個MFC對象,MFC對象和WIndows對象之間有一個一一對應(yīng)的關(guān)系。這種關(guān)系以映射的形式保存在創(chuàng)建線程的當(dāng)前模塊的模塊-線程狀態(tài)信息中。當(dāng)一個線程使用某個MFC對象指針P時,ASSERT_VALID(p)將驗(yàn)證當(dāng)前線程的當(dāng)前模塊是否有Windows句柄和p對應(yīng),即是否創(chuàng)建了p所指的Windows對象,驗(yàn)證失敗導(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)建線程的當(dāng)前模塊的模塊-線程狀態(tài)信息中。當(dāng)一個線程使用某個MFC對象指針P時,ASSERT_VALID(p)將驗(yàn)證當(dāng)前線程的當(dāng)前模塊是否有Windows句柄和p對應(yīng),即是否創(chuàng)建了p所指的Wi……
老師你好,對于這個知識點(diǎn),我早有所聞,
只是不知道為什么mfc要有這么個規(guī)定
mfc一共引入了4個狀態(tài):模塊狀態(tài),線程狀態(tài), 模塊-線程狀態(tài),
進(jìn)程狀態(tài)。
前3個狀態(tài)似乎是為 mfc的tls服務(wù)的,
理解起來也比較費(fèi)勁。
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*指針,但是你將它強(qiáng)制轉(zhuǎn)化成了Ctest8Dlg*指針,這樣本身就是很危險(xiǎn)的,而你后面又訪問了Ctest8Dlg類自己定義的成員變量(而這個成員變量在CWnd類中并沒有定義它),所以這里就錯了。
原因是FromHandle這個函數(shù)返回的是CWnd*指針,但是你將它強(qiáng)制轉(zhuǎn)化成了Ctest8Dlg*指針,這樣本身就是很危險(xiǎn)的,而你后面又訪問了Ctest8Dlg類自己定義的成員變量(而這個成員變量在CWnd類中并沒有定義它),所以這里就錯了。
有些道理,
CWnd的派生類過多,而且其本身也有基類,那么最終拍攝各類Ctest8dlg* 所指向的內(nèi)存就不是爺爺基類
Cwnd的地址了,所以這里就錯誤了。
如此說來,
這個法子是個雞肋了,
對任何CWnd的派生類來說,都比較危險(xiǎn),除非用該指針去訪問
CWnd的成員函數(shù)才沒事情, 否則只要訪問派生類CDialog 或者Ctest8dlg里的
自己增加的函數(shù)或者成員,都會出錯。
引用 10 樓 VisualEleven 的回復(fù):原因是FromHandle這個函數(shù)返回的是CWnd*指針,但是你將它強(qiáng)制轉(zhuǎn)化成了Ctest8Dlg*指針,這樣本身就是很危險(xiǎn)的,而你后面又訪問了Ctest8Dlg類自己定義的成員變量(而這個成員變量在CWnd類中并沒有定義它),所以這里就錯了。
有些道理,
CWnd的派生類過多,而且其本身也有基類,那么最終……
CWnd* pthis=FromHandle((HWND)p);
//pthis->m_str=CString(_T("hello"));
if(pthis)
{
pthis->SetWindowText(_T("xx"));
}
setwindowtext 崩潰。
說明這個法子,太危險(xiǎn)了, 很多東西搞不定。
指針我調(diào)試過了,是有值的。
雞肋法子啊,都不知道CWnd的哪一個成員函數(shù)可以使用了。
引用 10 樓 VisualEleven 的回復(fù):原因是FromHandle這個函數(shù)返回的是CWnd*指針,但是你將它強(qiáng)制轉(zhuǎn)化成了Ctest8Dlg*指針,這樣本身就是很危險(xiǎn)的,而你后面又訪問了Ctest8Dlg類自己定義的成員變量(而這個成員變量在CWnd類中并沒有定義它),所以這里就錯了。
有些道理,
CWnd的派生類過多,而且其本身也有基類,那么最終……
訪問函數(shù)沒有關(guān)系,只要該函數(shù)中沒有訪問該類中自己定義的成員變量即可
this = 0x002cfdc4 {Ctest8Dlg hWnd=0x00680342}
pthis = 0x001a9eac {CWnd hWnd=0x00680342}
這是我做的實(shí)驗(yàn), 在線程里獲得CWnd指針是最后那個, CXXdlg指針是上的那個。
可見,F(xiàn)romHandle獲得的指針是祖父類的。并非孫類的。
那么自然就不能使用祖父類的指針去調(diào)用非祖父類的函數(shù)了,對吧。
除非動態(tài)綁定技術(shù)。
這個從c++語法的角度分析,我覺得沒有問題吧。
順便糾正12樓,12樓是錯誤的,
原因在于,我傳參數(shù)的時候,不小心沒有把句柄,從線程里傳進(jìn)去。
是我的失誤
引用 3 樓 stjay 的回復(fù):問題1:
因?yàn)锳fxBeginThread內(nèi)部已經(jīng)Attach了一次主界面
C/C++ code12345678 CWnd threadWnd;.... // thread inherits app's main window if not already set CWinApp* pApp ……
同時跟正第5樓的實(shí)驗(yàn)
和
15樓一樣, 線程傳參數(shù)失誤了, 代碼是沒有問題的。
感謝大家的熱心解答。
引用 3 樓 stjay 的回復(fù):問題1:
因?yàn)锳fxBeginThread內(nèi)部已經(jīng)Attach了一次主界面
C/C++ code12345678 CWnd threadWnd;.... // thread inherits app's main window if not already set CWinApp* pApp ……
剩下第6樓的問題
windows標(biāo)準(zhǔn)庫是動態(tài)的,還是靜態(tài)編譯的?