在自己的线程中开启的定时器,相应的WM_TIMER消息是由谁来接收呢?在线等!

时间:2021-08-15 23:43:47
程序的工作原理和流程:
当开启扫描底层数据的线程后,则给底层发送数据,如果底层设备是有电的,则它将返回相应的数据给上层,如此循环执行下去,
如果某个时刻底层设备没电了(通过底层是否返回数据了来判断),则退出循环,并结束当前线程,在此期间,当线程启动时,并
开启一个定时器,来不断地刷新当前对话框的内容,如果当前设备没电了,则不再刷新。此外,上层发送数据后,底层会返回相应
的数据,这时候程序会接收到(wMsg消息,这是自定义的),紧接着就会触发OnRecv函数来接收数据并将数据送到指定的位置。

请问各位:在ScanThread线程中调用的pDlg->SetTimer(13,100,NULL);(开启13号定时器),那么它产生的WM_TIMER
消息是不是由CDlgInfo来接收啊?同样的,12号定时器的消息是不是也由CDlgInfo来接收呢?
此外我这里的SendSnmp应该是在ScanThread线程中执行,而OnRecv是在主线程执行的吧?
在我这个程序中,我不需要在ScanThread中做消息处理的吧?



UINT CDlgInfo::ScanThread( LPVOID pParam)
{
CDlgInfo *pDlg=(CDlgInfo *)pParam;
    //创建一个CSingleLock对象,初始化为信号量sem
CSingleLock singlock(pDlg->sem);

//当前还未刷新界面
pDlg->m_bRefreshFlag=FALSE;

do
{
        //锁信号量
        singlock.Lock();

//发送snmp包到底层
pDlg->SendSnmp();

//当前设备有电,并且当前还未刷新界面,则开启定时器13,没隔100ms刷新一次
if((pDlg->m_bPowerFlag==TRUE)&&(pDlg->m_bRefreshFlag==FALSE))
        {
                pDlg->m_bRefreshFlag=TRUE;//已经开启定时器刷新界面了,不需要再次开启了 
pDlg->SetTimer(13,100,NULL);

        } 
//开信号量
singlock.Unlock();
//休眠1000ms
Sleep(1000);
TRACE("Thread\n");
}
while(pDlg->m_bPowerFlag==TRUE);//当前设备还有电,则继续扫描

   
pDlg->KillTimer(13);//线程即将退出,将刷新界面定时器关掉,不再刷新界面了

    TRACE("Thread Exit!!!!!!!!!!\n");
    
return 0;
}

void CDlgInfo::OnTimer(UINT nIDEvent) 
{
// TODO: Add your message handler code here and/or call default
switch (nIDEvent)
{
   
    case 12://一次查询结束
TRACE("time out\n");
KillTimer(12);
        //查询机架信息时超时,则表示设备没电了 
if(m_bJijiaFlag==TRUE)
m_bPowerFlag=FALSE;
    m_bReceived=TRUE;
break;
    
case 13:
m_bFlashFlag=!m_bFlashFlag;
InvalidateRect(CRect(0,50,ptRect[16].right,ptRect[16].bottom),FALSE);
break;
  }
CDialog::OnTimer(nIDEvent);
}

void CDlgInfo::SendSnmp()
{

//查询机架信息
m_bJijiaFlag=TRUE;


        /**********这里是发送snmp包到底层,当底层收到数据之后,接着立刻返回相应的数据,
在我程序里是通过 recv消息的接收函数OnRecv来实现的*************/
if(pSnmp.sessionID==FALSE)
{
pSnmp.CreateSession(m_hWnd,wMsg);
pSnmp.sessionID=TRUE;
}
pSnmp.CreateVbl("1.3.6.1.4.1.991.1.1.0",NULL);
pSnmp.SetVbl("1.3.6.1.4.1.991.1.2.0",NULL);
pSnmp.SetVbl("1.3.6.1.4.1.991.1.3.0",NULL);
pSnmp.SetVbl("1.3.6.1.4.1.991.1.4.0",NULL);
pSnmp.CreatePdu(SNMP_PDU_GET,NULL,NULL,NULL);
pSnmp.Send(m_sIP,"public");
/******snmp发送完毕*****/

   //设置当前还未收到底层的数据
   m_bReceived=FALSE; 
   
   //设置12号定时器来使当时间过了200ms还未收到数据后,使m_bReceived变为真,以便下一轮的发送
   KillTimer(12);
   SetTimer(12,delaytime,NULL);
   
    MSG message;

/*等待收取数据,如果数据还未收到,则等待,(过了200ms后还未收到数据后,
12号定时器,会强制使数据接收标志置为真,从而退出循环,准备下一轮发送
)*/
while(m_bReceived==FALSE)
{
Sleep(10);
}

  m_bJijiaFlag=FALSE;
 
}

void CDlgInfo::OnRecv(WPARAM wParam, LPARAM lParam)
{

CString strIp;
CString strTemp;
int nIpin=0;//保存接收的整数值
CString str="";//保存接收的字符串

pSnmp.Receive(m_sOid,m_value);

if(pSnmp.nCount>0)//收到了数据包
{
m_bPowerFlag=TRUE;
Module[16].m_bPowerFlag=TRUE;

for(int i=0;i<pSnmp.nCount;i++)
{
//接收数据
switch(m_value[i]->syntax)
{
case SNMP_SYNTAX_INT: 
//case SNMP_SYNTAX_INT32:
smiINT sNumber;
sNumber=m_value[i]->value.sNumber;
nIpin=sNumber;
str.Format("%d",sNumber);

break;
//省略若干

}
     
        //分析数据,并将数据存放到相应的地方去(存放到相应的数组中) 

}

//接收数据标志位置为真
                m_bReceived=TRUE;
  //关闭12号定时器,不需要判断数据包接收超时了
  KillTimer(12);


}


}   

7 个解决方案

#1


大家帮帮忙啊,我顶

#2


UINT CWnd::SetTimer( UINT nIDEvent, UINT nElapse, void (CALLBACK EXPORT* lpfnTimer)(HWND, UINT, UINT, DWORD) );事实上内部是调用API
UINT SetTimer(
  HWND hWnd,              // handle of window for timer messages
  UINT nIDEvent,          // timer identifier
  UINT uElapse,           // time-out value
  TIMERPROC lpTimerFunc   // address of timer procedure
);
所以,事件处理是由hWnd所代表的窗口过程处理的,也就是说是的,是由你的pDlg处理的

#3


哦,谢谢 xiaoqiqixiao(七七),那么是这样的画,接收到WM_TIMER消息后执行的程序都是在主线程中执行喽,和ScanThread线程无关喽?

此外在我这个ScanThread线程中就不要再做消息处理了吧

#4


pDlg->SetTimer(13,100,NULL);产生的定时器是由对话框pDlg来处理的

//记隹,最好不要跨线程使用CWnd*

#5


如果你想由自己的线程处理,应该使用

VOID CALLBACK MyTimerProc(          HWND hwnd,
    UINT uMsg,
    UINT_PTR idEvent,
    DWORD dwTime
);
为原型自己定义一个回调函数,然后将指针作为参数传递给最后一个参数
::SetTimer(NULL,13,1000,MyTimerProc);

#6


可以用回调函数来完成

#7


WM_TIMER消息和ScanThread线程无关

#1


大家帮帮忙啊,我顶

#2


UINT CWnd::SetTimer( UINT nIDEvent, UINT nElapse, void (CALLBACK EXPORT* lpfnTimer)(HWND, UINT, UINT, DWORD) );事实上内部是调用API
UINT SetTimer(
  HWND hWnd,              // handle of window for timer messages
  UINT nIDEvent,          // timer identifier
  UINT uElapse,           // time-out value
  TIMERPROC lpTimerFunc   // address of timer procedure
);
所以,事件处理是由hWnd所代表的窗口过程处理的,也就是说是的,是由你的pDlg处理的

#3


哦,谢谢 xiaoqiqixiao(七七),那么是这样的画,接收到WM_TIMER消息后执行的程序都是在主线程中执行喽,和ScanThread线程无关喽?

此外在我这个ScanThread线程中就不要再做消息处理了吧

#4


pDlg->SetTimer(13,100,NULL);产生的定时器是由对话框pDlg来处理的

//记隹,最好不要跨线程使用CWnd*

#5


如果你想由自己的线程处理,应该使用

VOID CALLBACK MyTimerProc(          HWND hwnd,
    UINT uMsg,
    UINT_PTR idEvent,
    DWORD dwTime
);
为原型自己定义一个回调函数,然后将指针作为参数传递给最后一个参数
::SetTimer(NULL,13,1000,MyTimerProc);

#6


可以用回调函数来完成

#7


WM_TIMER消息和ScanThread线程无关