multithreading - Can't get MFC worker thread to pass hWnd or MDI window pointer to thread -
for reason passing hwnd or pointer of newly created mdi window cannot recasted original value in worker thread. i've tried creating thread app class, document class , view class. have same effect. i'm using global function worker thread. funny thing i'm using same code used same thing in mfc mdi in 1998 , worked great doesn't seem work now.
perhaps i'm not seeing problem. going on here? want simple, create new view window, capture it's hwnd , pass hwnd worker thread worker thread can send messages window print strings , forth. i'd launch thread document class. compiler vs2010 , it's being run in debug.
after reading this: http://msdn.microsoft.com/en-us/library/h14y172e%28v=vs.100%29.aspx, realize can't pass pointer view class around worker threads. i'm focusing on hwnds. in ontestconnect block, valid hwnd returned valid pointer new view window.
here's code (from app class):
struct threadparms { hwnd hwndview; int test; };
(note, i've tried defining struct typedef , variable name, have same result)
uint starter( lpvoid pparms ) { threadparms* pthreadparms = (threadparms* )pparms; //this step shouldn't necesarry tried anyway. should //be able use pthreadparms->hwndview without casting. //the hwnd value not come across valid. valid before sending. hwnd hwnd = (hwnd)pthreadparms->hwndview; //the int comes across fine int inum = pthreadparms->test; chftappbview* pview = (chftappbview*) chftappbview::fromhandle(hwnd); //this bombs debug error becuase pview ptr invalid (though //valid before sending on pview->sendmessage( id_file_print, 0, 0 ); return 0; } void chftappbapp::ontestconnect() { threadparms* pthreadparms = new threadparms; //create window afxgetapp()->oncmdmsg( id_file_new, 0, null, null ); cmdiframewnd* pframe = (cmdiframewnd*)afxgetapp()->m_pmainwnd; cmdichildwnd* pchild = (cmdichildwnd*)pframe->getactiveframe(); chftappbview* pview = (chftappbview*)pchild->getactiveview(); pthreadparms->hwndview = pview->m_hwnd; pthreadparms->test = 10; afxbeginthread( starter, pthreadparms ); }
part 2
//create window afxgetapp()->oncmdmsg( id_file_new, 0, null, null ); cmdiframewnd* pframe = (cmdiframewnd*)afxgetapp()->m_pmainwnd; cmdichildwnd* pchild = (cmdichildwnd*)pframe->getactiveframe(); chftappbview* pview = (chftappbview*)pchild->getactiveview(); hwnd h = pview->m_hwnd; sendmessage( h, id_file_print, 0, 0 );
i'm trying determine if hwnd valid. pview valid. stepping through code , looking @ pointer stats in debugger watch shows helathy pointer references cview class. not return healthy hwnd. debugger watch says 'can't evaluate' hwnd memory address , says 'unused=0'. running past iswindow returns true, however. go figure. trying send cview message cview window handle gets ignored. why getavtiveview return valid pointer hwnd in class return garbage?
part 3
after more digging, turns out hwnd valid though hwnd variable displays 'unused=???' in watch window. assume it's valid because hwnd received in thread code matches hwnd attached pview pointer in main code. pview pointer hwnd taken valid because watch recognizes valid cview class pointer returning name of cview class represents. there still 2 problems however. 1 though system sends valid hwnd cview window (pview->m_hwnd), sendmessage(pview->m_hwnd, id_file_print_preview, 0, 0,) refuses work. system ignores it. expected fileprintpreview command in newly created view window run. second fromhandle returns cwnd object , casting cview fails using of these methods:
uint threadtest1( lpvoid pparms ) { threadparms* pthreadparms = (threadparms* )pparms; //returns cwnd though handle valid cview chftappbview* pview2 = (chftappbview*) chftappbview::fromhandle(hwnd); //doesn't seem anything. still returns hwnd system recognizes //a cwnd. that's reports in watch window. chftappbview* pview = reinterpret_cast<chftappbview*>(chftappbview::fromhandle(hwnd)); //doesn't appear dynamic_downcast( chftappbview, pview2 ); //confirms watch window says -- it's cwnd not cview. if ( !pview->iskindof( runtime_class(chftappbview) ) ) afxmessagebox( "not cview" ); ::sendmessage( hwnd, id_file_print, 0, 0 ); return 0; } void chftappbdoc::main() { afxgetapp()->oncmdmsg( id_file_new, 0, null, null ); threadparms* pthreadparms = new threadparms; cmdiframewnd* pframe = (cmdiframewnd*)afxgetapp()->m_pmainwnd; cmdichildwnd* pchild = (cmdichildwnd*)pframe->getactiveframe(); chftappbview* pview = (chftappbview*)pchild->getactiveview(); pthreadparms->hwndview = pview->m_hwnd; afxbeginthread( threadtest1, pthreadparms ); sendmessage( pview->m_hwnd, id_file_print, 0, 0 ); //or ::sendmessage( pview->m_hwnd, id_file_print, 0, 0 ); }
so questions how can hwnd converted correct window pointer in thread code? why can't system cast cview?
part 4
probem solved (for now). lessons:
- cannot pass cview window pointer worker thread. see link above this.
use sendmessage communicate between theads , windows
//this works worker thread now
threadparms* pthreadparms = (threadparms* )pparms;
hwnd hwnd = static_cast(pthreadparms->hwndview);
lresult lrst = ::sendmessage( pthreadparms->hwnd, wm_ggg, 0, 0 );
//or just
lresult lrst = ::sendmessage( pthreadparms->hwnd, wm_ggg, 0, 0 );
//as cdoc method creates thread:
chftappbview* pview = (chftappbview*)pchild->getactiveview();
lresult lrst = ::sendmessage( pview->m_hwnd, wm_ggg, 0, 0 );
cview's message map...
on_message( wm_ggg, kk )
pass hwnds worker threads identify cview windows
- cannot cast cwnd lower derrived class (and excpet work right).
- use on_message in view's message map capture commands sent sendmessage (be sure include method declaraion afx_msg in view's .h file)
all pretty straight forward looking answers (when faced myriad of possible causes) summary may help...
i still don't undertstand why casting fromhandle cview worked in old mfc app , not now. perhaps has code located. in old mfc app located in cview window , in code in cdoc class. cdocument not derrived cwnd cview is.
anyway, wraps problem up. big thank offered advice -- nik, scott, ulrich , mark. sage advice helpful.
you can call chftappbview::fromhandle(hwnd)
isn't pointer chftappbview
; it's pointer cwnd
. casting it, you're telling compiler "trust me, pointer chftappbview
. except isn't , shouldn't treat such or pretend is.
after all, if recipe calls orange juice, don't take lemon, paint orange, juice , call orange juice. you?
so do? well, if want send id_file_print
message, don't need cwnd
such. just do:
::sendmessage(hwnd, id_file_print, 0, 0);
of course, that's also wrong. meant this:
::sendmessage(hwnd, wm_command, id_file_print, 0);
update:
again, cannot trying do. let's go step step, shall we?
//returns cwnd though handle valid cview chftappbview* pview2 = (chftappbview*) chftappbview::fromhandle(hwnd);
right. cwnd::fromhandle
returns pointer cwnd
, not else. not giving pointer original chftappbview
. it's giving new cwnd
attached same hwnd
. not valid cast chftappbview
because new cwnd
not chftappbview
.
//doesn't seem anything. still returns hwnd system recognizes //a cwnd. that's reports in watch window. chftappbview* pview = reinterpret_cast<chftappbview*>(chftappbview::fromhandle(hwnd));
again, cwnd::fromhandle
returns pointer new cwnd
knows nothing chftappbview
. telling compiler "trust me, pointer chftappbview
object!" except not. pointer cwnd
attached hwnd
chftappbview
.
//doesn't appear dynamic_downcast( chftappbview, pview );
this still wouldn't anything. first of all, dynamic_downcast
returns pointer chftappbview
right there, you're calling mfc rtti functions not doing result. if did save result, wouldn't help. trying convert generic cwnd
not.
i'll try explain 1 more time: when create view, mfc creates chftappbview
object associated hwnd
of view. when call cwnd::fromhandle
passing in hwnd
of view, mfc creates new , distinct cwnd
instance points same hwnd
- second cwnd
not chftappbview
, hwnd
knows nothing mfc classes, views, documents or else.
you trying take cwnd *
cwnd::fromhandle
returns , hammer chftappbview *
. no matter how hard try, not work. can ever cwnd *
, nothing else.
as sidenote, cannot pass mfc objects 1 thread another, passing original chftappbview *
cause weird issues crop up, , may lead hard track errors.
update 2:
you ask "why can't cwnd object cast window class derrives cwnd?"
let's start cwnd::fromhandle
shall we?
cwnd* pascal cwnd::fromhandle(hwnd hwnd) { chandlemap* pmap = afxmaphwnd(true); //create map if not exist assert(pmap != null); cwnd* pwnd = (cwnd*)pmap->fromhandle(hwnd); #ifndef _afx_no_occ_support pwnd->attachcontrolsite(pmap); #endif assert(pwnd == null || pwnd->m_hwnd == hwnd); return pwnd; }
this leads chandlemap::fromhandle
. code bit complicated , posting here won't help, let's not clutter things up. here function does, conceptually:
if handle found in map, returns it; otherwise, creates new cwnd
, makes cwnd
point hwnd
passed in. returns pointer cwnd
you. notice, only cwnd
. nothiong else. see, cannot convert returned cwnd
else - if else derived cwnd
- because have cwnd
, nothing more.
let's have wife. beautiful , love much. carry picture of in wallet. now, when meet , ask if married, take out wallet , proudly show them picture. person you're talking doesn't think married picture. , don't think can magically "convert" picture wife.
the situation here similar. cwnd::fromhandle
gives "picture" of sorts. it's showing around, not else. asking "why can't transform picture wife?" answer because that's not how pictures work.
Comments
Post a Comment