Click to See Complete Forum and Search --> : Accessing CView controls from worker thread


Steve McNeese
April 8th, 1999, 06:09 AM
Is it possible for a worker thread to access and update control on a CView of the main application thread? I have a worker thread the sleeps for a set number of seconds via the WaitForSingleObject() funtion. When it timesout, I do some processing and go back to sleep. This continues until the Kill event is returned in the wait. During my processing, I want to update a listbox and start and avi playing on the cview and the stop the avi just before the thread goes to sleep again. Since the controls are not part of the thread, I am not sure how to access them. I tried the following:


UINT CPickThread::threadProc ()
{
DWORD dwResult;
CAWIMSApp* pApp = (CAWIMSApp*)AfxGetApp();
CString t_cConnect;
CDatabase t_PickDB;
CPickQueueSet rsPickQueue;

// Here is the work to be done !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
int t_iRefresh;
t_iRefresh=pApp->GetProfileInt("AWIMS Client","PQ_Refresh_Seconds",-1);
if(t_cUser.CompareNoCase("inquiry")==0)
t_cConnect="UID=inquiry;PWD=inquiry;DSN=AWIMS";
else
t_cConnect.Format("UID=%s;PWD=%s;DSN=AWIMS",t_cUser,t_cPass);
try {
t_PickDB.OpenEx(t_cConnect,CDatabase::noOdbcDialog | CDatabase::useCursorLib);
}
// Catch any DB exceptions that may have been thrown by the Open call
catch (CDBException* e) {
AfxMessageBox(e->m_strError,MB_ICONEXCLAMATION);
return 1;
}
rsPickQueue.m_pDatabase=&(t_PickDB);
rsPickQueue.m_strSort="REQUEST_TIME";
if(!rsPickQueue.Open(CRecordset::snapshot, NULL, CRecordset::none)) {
AfxMessageBox(IDP_FAILED_OPEN_DATABASE);
return 2;
}

---> everything works up to this point of the thread "initialization"
// Switch to the Pick pane and activate the pick tab

Fails on this call with an unhandled exception
|
---> ((MainFrame *)(::AfxGetMainWnd()))->m_wndSplitter.SetActivePane(0, 0);
CView *view = ((CFrameWnd *) AfxGetMainWnd())->GetActiveView();
if(view->IsKindOf(RUNTIME_CLASS(CPickTabView))) {
((CPickTabView *)view)->SetActiveTab(0);
}
// t->pPick is a pointer to the view which is a tab on the CPickTabView
(((CPickTabView *)view)->t_pPick)->m_PickAVI.Open(IDR_AWIMS);

while(TRUE) {
dwResult=WaitForSingleObject(m_hEventStop,(t_iRefresh * 1000));
if(dwResult == WAIT_TIMEOUT) {
(((CPickTabView *)view)->t_pPick)->m_PickAVI.Play(0,-1,-1);
::Beep(5000,100);
::Sleep(5000);
rsPickQueue.Requery();
while(!rsPickQueue.IsEOF()) {
rsPickQueue.MoveNext();
}
(((CPickTabView *)view)->t_pPick)->m_PickAVI.Stop();
}
else {
rsPickQueue.Close();
(((CPickTabView *)view)->t_pPick)->m_PickAVI.Close();
return 0;
}
}

}


Steven M. McNeese
steven.mcneese@boeing.com

Bogdan Matasaru
April 8th, 1999, 05:22 PM
I think the problem is caused because you are not allowed to pass CWnd between threads, but HWNDs.

April 8th, 1999, 06:58 PM
I agree with Bogdan. Use HWND!!!

As well, make sure the two threads can't access the listbox at the same time

Masaaki
April 8th, 1999, 08:48 PM
Hi.

I was disagree with using HWND as long as we focus on MFC.
In addition, I don't know that we can use HWND.

In my case, I use SendMessage function with use-defined WM_USER.
So we can freely use the other class like CView and so on
in this message handler because this message handler resides outside threadProc().

Hope for help.
-Masaaki Onishi-

Dave Lorde
April 9th, 1999, 05:55 AM
Microsoft recommend passing the window handle rather than the CWnd because MFC message mapping uses thread-local storage. In the thread, the hWnd mapped to the passed CWnd is not guaranteed to be the same as that mapped to the CWnd in the caller.

Dave

Masaaki
April 9th, 1999, 12:37 PM
Hi.

For example,
UINT CMyDialog::ThreadFunc(LPVOID pParam)
{
.......................
AfxGetMainWnd()->SendMessage(WM_USER, 0,0);
............................
return 0;
}

void CMyDialog::OnUserMessage()//WM_USER message handler.
{
write code here
}

I never say that I pass CWnd of parameter of SendMessage func.
However, this code is dialog base application.
So, when we write doc-view application, it seems to be a little tricky.

Regards.
-Masaaki Onishi-

Steve McNeese
April 9th, 1999, 01:44 PM
Well, I did it a little different. When adding a CView as a tab to my tab control, it returns a pointer the the view. I keep this pointer as a member of my main App class. Then I reference the controls on the view like this:

CAWIMSApp* pApp = (CAWIMSApp*)AfxGetApp();
((CPick *)pApp->t_pPick)->m_PickAVI.Play(0,-1,-1);
((CPick *)pApp->t_pPick)->m_ListPick.DeleteAllItems();
.
.
.
etc.

Works great! Though I was going to have to use CSemaphor between to two threads, but I have not run into any problems with that either. The worker thread is constantly refreshing the listctrl and the main app thread can select items within the listctrl and delete them, move them, etc. Not sure if I understand that based on what I have read about threads but, If it aint broke don't fix it....yet!



Steven M. McNeese
steven.mcneese@boeing.com