问一个比较难的问题?可能涉及Windows的消息循环机制,请高手帮忙!(里面内容很多,请耐心地读!)??????????????????

KissYou 2001-07-27 09:30:52
是这样的。在一个对话框里,单击某一按钮后用函数AfxBeginThread(Function,this)开始启动一个线程。显然这里this应该是指向当前对话框的指针,Function为我定义的线程函数。
在Function里,它所接收的唯一参数就应该是指向对话框的指针了。我在这个函数里用一个循环不断的向对话框发送消息,如下:
::SendMessage(pDlg->m_hWnd,WM_FRESH,0,0);
pDlg是通过this得到的对话框指针。
WM_FRESH是我在对话框类中定义的一个消息 #define WM_FRESH WM_USER+6
对话框类中也有相应的消息响应函数及ON_MESSAGE宏的申明,一切正常。
上述程序在debug版本运行正常,设断点调试表明pDlg也确实指向了这个对话框。但改成release版本后循环第二次就出错,说“[0x004372a5]指令引用的[0x00360936]内存。该内存不能为[read]。”
我实在搞不明白怎么回事,求高手指点!
...全文
204 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
HowUCan 2001-07-31
  • 打赏
  • 举报
回复
各位,我试了试singlerace(独行者)的建议,改了一下OnFresh的参数,没有问题了。
所以好像不应该怀疑ON_MESSAGE宏!!!
KissYou 2001-07-30
  • 打赏
  • 举报
回复
多谢MSVCer(家宝)!我的程序也通过了!看来传this是没问题的!错误就出在ON_MESSAGE宏上。我原先是通过定义一个全局的变量来在线程间传递数据,但也是通过SetWindowText来改变对话框内容的!后来又改用this指针直接访问对话框的成员变量的值,也通过了!
ShyWJB 2001-07-28
  • 打赏
  • 举报
回复

这个问题解决了!

下面是运行成功后的代码:
// MsgDlg.cpp : implementation file
//

#include "stdafx.h"
#include "csdn_kissyou.h"
#include "MsgDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CMsgDlg dialog
#define WM_FRESH WM_USER+6 //<=定义


CMsgDlg::CMsgDlg(CWnd* pParent /*=NULL*/)
: CDialog(CMsgDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CMsgDlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
}


void CMsgDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CMsgDlg)
DDX_Control(pDX, IDC_EDIT1, m_edit);
//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CMsgDlg, CDialog)
//{{AFX_MSG_MAP(CMsgDlg)
ON_BN_CLICKED(IDC_BUTTON1, OnButton1)
//}}AFX_MSG_MAP
// ON_MESSAGE(WM_FRESH,OnFresh) //<=不响应自定义消息
ON_COMMAND(ID_FRESH,OnFresh) //<=响应命令消息
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMsgDlg message handlers

void f(CMsgDlg *pDlg)
{
for(;;) //<=线程中向对话框发送消息
{
::SendMessage(
pDlg->GetSafeHwnd(),
WM_COMMAND,
MAKEWORD(ID_FRESH,0),
NULL);
}
}

void CMsgDlg::OnButton1()
{
AfxBeginThread((AFX_THREADPROC)f,this); //<=在按钮处理函数中建立线程
}

void CMsgDlg::OnFresh()//界面更新,提示线程中的变化
{
CString s;
static int i=0;
s.Format("%d",i++);
m_edit.SetWindowText(s);
}

好象错误原因在MFC查内部消息映射表时有问题,也许别的,还请高人在此继续指点迷津
我在此处用发送Windows定义的消息方法解决,太因了,别的方法没试,
HowUCan 2001-07-28
  • 打赏
  • 举报
回复
我也试了试,如果发消息是
::SendMessage(hwnd,WM_RBUTTONDOWN,0,0);

void CMyDlg::OnRButtonDown(UINT nFlags, CPoint point)
{
AfxMessageBox("RBD");
CDialog::OnRButtonDown(nFlags, point);
}
不会有错,但发自定义消息并且用了ON_MESSAGE就会出错
azuo_lee 2001-07-28
  • 打赏
  • 举报
回复
详细情况可在MSDN中搜索标题:Multithreading: Programming Tips,里面的Windows Handle Maps一节有介绍。关于MFC对象的“线程间不安全性”,MSDN中的很多文档都有介绍,主要原因是MFC使用了Thread Local Storage。
出错往往出在类似ASSERT(m_hWnd!=NULL)这种地方。还是不要冒险为妙。
ShyWJB 2001-07-28
  • 打赏
  • 举报
回复
对MFC了解不深,因此楼上说法不太明白,但MFC在Debug&Release时是否维护的是不同的“Handle Map”呢?感觉不是,因此原因另有,下面是我模拟的代码,不知与贴子作者代码相似否?
#define WM_FRESH WM_USER+6

BEGIN_MESSAGE_MAP(CMsgDlg, CDialog)
//{{AFX_MSG_MAP(CMsgDlg)
ON_BN_CLICKED(IDC_BUTTON1, OnButton1)
//}}AFX_MSG_MAP
ON_MESSAGE(WM_FRESH,OnFresh)
END_MESSAGE_MAP()

void CMsgDlg::OnButton1()
{
//AfxBeginThread((AFX_THREADPROC)f,this) ;
::SendMessage(this->GetSafeHwnd(),WM_FRESH,0,0);
}

void CMsgDlg::OnFresh()
{
CString s;
static int i=0;
s.Format("%d",i++);
m_edit.SetWindowText(s);//显示变化现象
}
我发现只要将ON_MESSAGE注释掉,异常就没有了,无论在什么编译环境下,我再找找原因,宁可不睡觉,Aa~~~~~~~~~~~~~~,Really sleepy,Aa~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
azuo_lee 2001-07-28
  • 打赏
  • 举报
回复
MFC会为每个线程维护一个Handle Map,由于这个Handle Map是线程相关的,而每个MFC的对象都会被记录在Handle Map之中,所以MFC对象不是线程间安全的。换句话说,你在一个线程中创建的CDialog对象,当传递到另一线程中时,它就失效了。常见的另外一种情况是CSocket,由于CSocket也要维护自己的一个Handle(用于接受通知消息),所以它也不是线程间安全的。但像一般的CRect之类的对象一般不会有此问题。
你可以直接传递windows的Handle,可以避免此问题。
KissYou 2001-07-28
  • 打赏
  • 举报
回复
我传了句柄后,用FromHandle函数试图得到指向对话框的指针,但所有对话框成员变量的值都得不到,好象是未被初始化。而实际上在开始这个线程之前,对话框类的成员变量都已有了定值。
看来:在新的线程里,似乎又创建了一个新的对话框类的对象,它与我的程序中的对话框类占用了不同的地址空间?不知这种认识对否?
请各位高手继续指点!
allfresh 2001-07-28
  • 打赏
  • 举报
回复
同意 singlerace
Leemaasn 2001-07-28
  • 打赏
  • 举报
回复
study
NewFoundFriend 2001-07-28
  • 打赏
  • 举报
回复
学习学习!
MSVCer 2001-07-28
  • 打赏
  • 举报
回复
同意singlerace(独行者)观点,azuo_lee也已经说明原因了,重建对象的方法在线程间修改对象行不通,这里给你个可行的办法
看看下面修改过的代码,用传递对象指针的方法可以修改对象的值
// MsgDlg.cpp : implementation file
//

#include "stdafx.h"
#include "csdn_sdi.h"
#include "MsgDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CMsgDlg dialog
#define WM_FRESH WM_USER+6 //<=定义


CMsgDlg::CMsgDlg(CWnd* pParent /*=NULL*/)
: CDialog(CMsgDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CMsgDlg)
//}}AFX_DATA_INIT
m_sedit = "雄纠纠,气昂昂,跨进县城";
}


void CMsgDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CMsgDlg)
DDX_Control(pDX, IDC_EDIT1, m_edit);
DDX_Text(pDX, IDC_EDIT1, m_sedit);
//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CMsgDlg, CDialog)
//{{AFX_MSG_MAP(CMsgDlg)
ON_WM_DESTROY()
ON_BN_CLICKED(IDC_BUTTON1, OnButton1)
ON_BN_CLICKED(IDC_BUTTON2, OnButton2)
//}}AFX_MSG_MAP
//ON_MESSAGE(WM_FRESH,OnFresh) //<=不响应自定义消息
//ON_COMMAND(ID_FRESH,OnFresh) //<=响应命令消息
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMsgDlg message handlers
volatile int quit=0;
void f(CMsgDlg *pDlg)
{
static int i=0;
for(;!quit;)
{
CString s;
s.Format("[%d]",i++);
s = pDlg->m_sedit + s;
pDlg->m_edit.SetWindowText( s );//<=直接控制对话框中对象
Sleep(1000);
}
pDlg->m_sedit = "从县城中载誉归来";//<=直接控制对话框中对象
}

void CMsgDlg::OnButton1()
{
AfxBeginThread((AFX_THREADPROC)f,this); //<=在按钮处理函数中建立线程
}

void CMsgDlg::OnFresh()//界面更新,提示线程中的变化
{
// CString s;//在此例中用不着了
// static int i=0;
// s.Format("%d",i++);
// m_edit.SetWindowText(s);
}

void CMsgDlg::OnDestroy()
{
CDialog::OnDestroy();

quit = 1;
}

void CMsgDlg::OnButton2()
{
//停止线程并显示线程中改变的值,多按几次
quit = 1;
static int i=0;
if( i )
{
UpdateData(0);
}
else
i=1;
}
singlerace 2001-07-28
  • 打赏
  • 举报
回复
对于ON_MESSAGE消息,MFC会给Fresh传递两个参数:Fresh( wParam, lParam)
向你那样声明会导致Fresh()调用前后栈指针esp不一致(有两个参数没有出栈),
在Debug版中,函数调用前的esp值保存在[ebp]中,因此即使esp不对也可以由ebp恢复;
在Release版中代码经过优化,函数调用前后esp一旦不一致就无法恢复了。
singlerace 2001-07-28
  • 打赏
  • 举报
回复
void CMsgDlg::OnFresh()声明不对,应为:
LRESULT CMsgDlg::OnFresh(WPARAM, LPARAM);
老问题了。
KissYou 2001-07-28
  • 打赏
  • 举报
回复
push
KissYou 2001-07-28
  • 打赏
  • 举报
回复
push
coppermine 2001-07-27
  • 打赏
  • 举报
回复
我好像也遇到过类似的问题。在线程中控制主窗口(对话框)上的Control,GetDlgItem()
老是报错,遇到ASSERT(!IsWindow());

后来我给线程传handle,用API获取Control的指针,就可以用了。

但为什么这样也不清楚
ni_ch 2001-07-27
  • 打赏
  • 举报
回复
用生命周期长一点的变量试试
KissYou 2001-07-27
  • 打赏
  • 举报
回复
我试过了,不行的!
ssh_zy 2001-07-27
  • 打赏
  • 举报
回复
用PostMessage试试

16,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧