本人写了一个程序,使用了一个开源的ChartCtrl(http://www.codeproject.com/KB/miscctrl/High-speedCharting.aspx),控件在刷新时要使用GetTextExtent来获取控件上字符串的尺寸。
在界面视图A上放置CChartCtrl控件,一个工作线程去定时取数据,然后调用界面视图A的方法将数据数据在CChartCtrl控件上界面出来,程序在运行的时候有时出现f:\rtm\vctools\vc7libs\ship\atlmfc\include\afxwin1.inl,即GetTextExtent内部调用GetExtentPoint32()返回FALSE导致VERIFY失败而弹出的对话框,如果DEBUG模时,忽略掉该问题了,程序又可以正常运行了,但过一段时间又出这样的问题。仔细分析了CChartCtrl的代码,m_hDC绝对是有效的,而且在运行过程中没有改过CDC对象。并且不存在多线程访问界面视图A。
出现问题后调用GetLastError()都返回0,即正常。好奇怪的问题了,搞了一周了还没有找到解决方案,先谢谢各位的帮助了。
在界面视图A上放置CChartCtrl控件,一个工作线程去定时取数据,然后调用界面视图A的方法将数据数据在CChartCtrl控件上界面出来,程序在运行的时候有时出现f:\rtm\vctools\vc7libs\ship\atlmfc\include\afxwin1.inl,即GetTextExtent内部调用GetExtentPoint32()返回FALSE导致VERIFY失败而弹出的对话框,如果DEBUG模时,忽略掉该问题了,程序又可以正常运行了,但过一段时间又出这样的问题。仔细分析了CChartCtrl的代码,m_hDC绝对是有效的,而且在运行过程中没有改过CDC对象。并且不存在多线程访问界面视图A。
出现问题后调用GetLastError()都返回0,即正常。好奇怪的问题了,搞了一周了还没有找到解决方案,先谢谢各位的帮助了。
解决方案 »
- MFC中动态创建BUTTON
- 在ocx控件中动态取除edit的边框
- delete的问题
- Mid界面,如何在开始的时候直接创建2个子窗口?
- 关于VC中使用ADO进行事务处理BeginTrans()的问题,很奇怪。(内有代码,非常疑惑!求助)
- 请问theApp和(CMyApp*)AfxGetApp()有什么联系和区别?
- 喜欢看书的朋友请进来
- ado方法,怎么将Ctime类型赋值给_variant_t 类型?
- windows中有没有什么API函数可以运行一个window程序,列如notepad.exe??
- MFC分割窗口奇怪现象
- 在VC++6.0中使用TeeChart控件在定义了控件变量后不能编译执行的问题
- 能否给传一份明日科技编的Visual C++程序开发范例宝典电子书(源码已经有了)
TO Conry:
即使是多线程但每次数据刷新界面都是由工作线程来驱动,其他情况下,不会得画控件的啊。现在只能通过减少重画控件的次数来避免这个问题。太奇怪了,如果VERIFY是由于CDC句柄造成的话,继续运行应该就会不断重复出现才对啊。
Reading 1 byte from 0x031dc480 (1 byte at 0x031dc480 uninitialized)
Address 0x031dc480 is argument #6 of ExtTextOutA
Address 0x031dc480 is 56 bytes into a 63 byte block at 0x031dc448
Address 0x031dc480 points to a HeapAlloc'd block in heap 0x02450000
Thread ID: 0xde4
Error location
ExtTextOutA [GDI32.dll]
CDC::ExtTextOutA(int,int,UINT,tagRECT const*,CStringT <char,StrTraitMFC <char,ChTraitsCRT <char>::ATL>>::ATL const&,int *) [afxwin1.inl:609]
CChartTitle::Draw(CDC *) [charttitle.cpp:115]
CChartCtrl::DrawChart(CDC *,CRect) [chartctrl.cpp:468]
CChartCtrl::RefreshCtrl(void) [chartctrl.cpp:436]
CChartCtrl::EnableRefresh(bool) [chartctrl.cpp:376]
CSmsFlowFormView::Init(void) [smsflowformview.cpp:125]
CSmsFlowFormView::OnInitialUpdate(void) [smsflowformview.cpp:67]
CWnd::OnWndMsg(UINT,UINT,long,long *) [wincore.cpp:2027]
CWnd::WindowProc(UINT,UINT,long) [wincore.cpp:1741]
Allocation location
HeapAlloc [KERNEL32.dll]
heap_alloc_base [malloc.c:105]
heap_alloc_dbg [dbgheap.c:409]
nh_malloc_dbg [dbgheap.c:266]
malloc [dbgheap.c:152]
CAfxStringMgr::Allocate(int,int) [strcore.cpp:141]
CSmsFlowFormView::Init(void) [smsflowformview.cpp:125]
CSmsFlowFormView::OnInitialUpdate(void) [smsflowformview.cpp:67]
CWnd::OnWndMsg(UINT,UINT,long,long *) [wincore.cpp:2027]
CWnd::WindowProc(UINT,UINT,long) [wincore.cpp:1741]
Allocation location
HeapAlloc [KERNEL32.dll]
heap_alloc_base [malloc.c:105]
heap_alloc_dbg [dbgheap.c:409]
nh_malloc_dbg [dbgheap.c:266]
malloc [dbgheap.c:152]
CAfxStringMgr::Allocate(int,int) [strcore.cpp:141]
ATL::CSimpleStringT <char,0>::Fork(int) [atlsimpstr.h:794]
ATL::CSimpleStringT <char,0>::PrepareWrite2(int) [atlsimpstr.h:835]
ATL::CSimpleStringT <char,0>::PrepareWrite(int) [atlsimpstr.h:821]
ATL::CSimpleStringT <char,0>::GetBuffer(int) [atlsimpstr.h:528]
Reading 1 byte from 0x031dc348 (1 byte at 0x031dc348 uninitialized)
Address 0x031dc348 is argument #2 of GetTextExtentPoint32A
Address 0x031dc348 is 56 bytes into a 63 byte block at 0x031dc310
Address 0x031dc348 points to a HeapAlloc'd block in heap 0x02450000
Thread ID: 0xde4
Error location
GetTextExtentPoint32A [GDI32.dll]
CDC::GetTextExtent(CStringT <char,StrTraitMFC <char,ChTraitsCRT <char>::ATL>>::ATL const&)const [afxwin1.inl:666]
{
ASSERT(m_hAttribDC != NULL);
SIZE size;
=> VERIFY(::GetTextExtentPoint32(m_hAttribDC, str, (int)str.GetLength(), &size));
return size;
}
CChartTitle::GetSize(CDC *) [charttitle.cpp:154]
[W] UMR: Uninitialized memory read in GetTextExtentPoint32A {1 occurrence}
CChartTitle::GetSize(CDC *) [charttitle.cpp:154]
CChartCtrl::DrawChart(CDC *,CRect) [chartctrl.cpp:461]
CChartCtrl::RefreshCtrl(void) [chartctrl.cpp:436]
CChartCtrl::EnableRefresh(bool) [chartctrl.cpp:376]
CSmsFlowFormView::Init(void) [smsflowformview.cpp:125]
CSmsFlowFormView::OnInitialUpdate(void) [smsflowformview.cpp:67]
CWnd::OnWndMsg(UINT,UINT,long,long *) [wincore.cpp:2027]
CWnd::WindowProc(UINT,UINT,long) [wincore.cpp:1741]
---------------------
你线程中将数据数据在CChartCtrl控件上显示出来,会调用GetDC,但是别忘了界面也是会刷新的,也需要调用GetDC,这就是两个线程在抢DC,当然可能会失效了。
应该找到问题了,每次工作线程调用添加点的函数AddPoint(),AddPoint()返回前都要调用CWnd::Invalidate()让ChartCtrl客户区无效,并产生一条WM_PAINT消息到窗口的消息队列中,未等WM_PAINT消息处理之前,Invalid()就返回了,未重画前,应该客户区的CDC对象也可能无效。
但如果工作线程在此时来刷新窗口时,使用到的CChartCtrl的客户区的CDC对象可能无效(在调用了Invalidate()之后、WM_PAINT消息处理之前),所以导致了GetTextPoint32()函数失败。
VERIFY(::GetTextExtentPoint32(m_hAttribDC, str, (int)str.GetLength(), &size));
继续的话,会正常运行,请问你这种问题如何解决的?请指教。
that is valid for all UI related stuff: never access anything UI related from outside the main thread.You could instead put all your data in a buffer and send a message to the UI thread to signal that data is ready. You'll need to protect the access to the buffer properly.
There is a very good article about threading here[^], it is a very good read for anybody working with threads.
BTW, why don't you send each point of data to the control ? This way you could see the data "live" (exactly like an oscilloscope) ?