标签归档:MFC

MFC中跨线程UpdateData(FALSE)报错 ASSERT FAILD问题

MFC程序,在给控件关联的变量赋值后,需要调用UpdateData(FALSE)后才能更新到界面,但是有时候却报错:

断言宏失败,在wincore.cpp的如下位置:
  CObject* p=NULL;
  if(pMap)
  {
   ASSERT( (p = pMap->LookupPermanent(m_hWnd)) != NULL ||
     (p = pMap->LookupTemporary(m_hWnd)) != NULL);
  }
  ASSERT((CWnd*)p == this);   // must be us

这个问题其实是由于跨线程访问UI元素导致的,微软在MSDN中做了如下描述:

In a multi-threaded application written using MFC, you should not pass MFC objects across thread boundaries. As a general rule, a thread should access only those MFC objects that it creates. Failure to do so may cause run-time problems including assertions or unexpected program behavior.

 

也就是说,MFC的UI线程是线程相关的,每个窗口的HandleMap是储存在创建UI那个线程的堆栈里面的(thread-local-storage (TLS) ),所以,你要是在另一个线程里面通过某种方式调用UI的UpdateData(FALSE)函数,他将无法正确执行。

知道了原因就好办事了,下面提供两种解决方法:

1、通过GetDlgItem(IDC_XXX)取得控件后SetWindowText()

    这种方式之所以能得逞,是因为调用SetWindowText 会导致 WM_SETTEXT被发送给目标窗体,由消息机制负责处理
    ctrlDlg->GetDlgItem(IDC_EDIT19)->SetWindowText(A2W(pData));

2、自定义一个消息,将Update消息发送到UI线程,在UI线程的对话框中处理消息,自己执行UpdateData(FALSE)函数的调用。

VC MFC程序,在About对话框中获取并显示程序的版本号

 

=================================================
本文为HeYuanHui原作

转载必须确保本文完整并完整保留原作者信息及本文原始链接!

NN:      khler
E-mail: khler@163.com
QQ:     23381103
MSN:   pragmac@hotmail.com
=================================================

    用VC++写的MFC程序,不管是exe的或者dll,都有个’VERSION’资源,在里面可以指定程序的版本号,这样在程序文件上右键点击,查看属性,就可以看到内嵌的版本信息了。同样,所有程序都愿意在’About’对话框中显示程序的当前版本,但是这里如何显示,跟资源里的’VERSION’信息还是有好几毛钱的关系呢 :)

    如果我们从’VERSION’资源里获取版本信息并在about对话框中显示,那么我们每次发布的时候只要修改’VERSION’里的信息就行了,经过一定处理,就可以在about对话框中显示了。

    其实MSDN中也有说明,但是说实话,要想从’VERSION’中读取信息,还真不是件简单的事情,下面一一实现,代码大部分来自MSDN。

    结果如下图所示:

显示1.1.6 build 718

void CAboutDlg::OnShowWindow(BOOL bShow, UINT nStatus)
{
 CDialog::OnShowWindow(bShow, nStatus);

 // TODO: 在此处添加消息处理程序代码

 CString ver = GetAppVersion(L”TowerWatch.exe”);
 if(ver.IsEmpty()) return

;

 

 int pos = ver.ReverseFind(‘.’);
 CString mainVer = ver.Left(pos);
 CString build = ver.Right(ver.GetLength() – pos -1);
 GetDlgItem(IDC_STATIC_VER)->SetWindowText(mainVer);
 GetDlgItem(IDC_STATIC_BUILD)->

SetWindowText(build);

 

}

void ErrorExit(LPTSTR lpszFunction) 

 // Retrieve the system error message for the last-error code

 LPVOID lpMsgBuf;
 LPVOID lpDisplayBuf;
 DWORD dw =

 GetLastError(); 

 

 FormatMessage(
  FORMAT_MESSAGE_ALLOCATE_BUFFER | 
  FORMAT_MESSAGE_FROM_SYSTEM |
  FORMAT_MESSAGE_IGNORE_INSERTS,
  NULL,
  dw,
  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  (LPTSTR) &lpMsgBuf,
  0

, NULL );

 

 // Display the error message and exit the process

 lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, 
  (lstrlen((LPCTSTR)lpMsgBuf)+lstrlen((LPCTSTR)lpszFunction)+40)*sizeof(TCHAR)); 
 StringCchPrintf((LPTSTR)lpDisplayBuf, 
  LocalSize(lpDisplayBuf),
  TEXT(“%s failed with error %d: %s”), 
  lpszFunction, dw, lpMsgBuf); 
 MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT(“Error”

), MB_OK); 

 

 LocalFree(lpMsgBuf);
 LocalFree(lpDisplayBuf);
}

CString CAboutDlg::GetAppVersion(WCHAR*

 AppName) 
{
 CString   AppVersion; 

 

 DWORD   RessourceVersionInfoSize; 
 DWORD   JustAJunkVariabel; 
 WCHAR*   VersionInfoPtr; 
 struct   LANGANDCODEPAGE
 { 
  WORD   wLanguage; 
  WORD   wCodePage; 
 }   *TranslationPtr; 
 WCHAR*     InformationPtr; 
 UINT      VersionInfoSize; 
 WCHAR     VersionValue[255

]; 

 

 RessourceVersionInfoSize=GetFileVersionInfoSize(AppName,&JustAJunkVariabel); 
 if(0!=RessourceVersionInfoSize) 
 {
  VersionInfoPtr = new WCHAR[RessourceVersionInfoSize];
  if(!GetFileVersionInfo(AppName,0,RessourceVersionInfoSize,VersionInfoPtr)) 
  {
    ErrorExit((LPTSTR)L”GetFileVersionInfo”);
   delete[]   VersionInfoPtr; 
   return

 NULL; 
  } 

 

  if(!VerQueryValue( VersionInfoPtr, L”VarFileInfoTranslation”, (LPVOID*)&TranslationPtr, &VersionInfoSize)) 
  { 
   ErrorExit((LPTSTR)L”VerQueryValue”);
   delete[]   VersionInfoPtr; 
   return

 NULL; 
  } 

 

  // retrieve product version
  wsprintf(VersionValue, L”StringFileInfo%04x%04xProductVersion”, TranslationPtr[0].wLanguage, TranslationPtr[0

].wCodePage); 

 

  if(!VerQueryValue( VersionInfoPtr, VersionValue, (LPVOID*)&InformationPtr, &VersionInfoSize)) 
  { 
   ErrorExit((LPTSTR)L”VerQueryValue”);
   delete[]   VersionInfoPtr; 
   return NULL; 
  } 
  if(wcslen(InformationPtr)> 0)   //Not   Null 
  { 
   AppVersion=

CString(InformationPtr); 
  } 

 

  delete[]   VersionInfoPtr; 
 } 
 return   AppVersion; 

当然,你可以将分解Version和build部分代码也封装到GetAppVersion函数中。

基于MFC的截屏

#include “stdafx.h”
#include <afxwin.h>

void Screen(char filename[])
{
    CDC *pDC;//屏幕DC
    pDC CDC::FromHandle(GetDC(NULL));//获取当前整个屏幕DC
    int BitPerPixel pDC->GetDeviceCaps(BITSPIXEL);//获得颜色模式
    int Width pDC->GetDeviceCaps(HORZRES);
    int Height pDC->GetDeviceCaps(VERTRES);

    printf(“当前屏幕色彩模式为%d位色彩\n”, BitPerPixel);
    printf(“屏幕宽度:%d\n”, Width);
    printf(“屏幕高度:%d\n”, Height);
    
    CDC memDC;//内存DC
    memDC.CreateCompatibleDC(pDC);
    
    CBitmap memBitmap, *oldmemBitmap;//建立和屏幕兼容的bitmap
    memBitmap.CreateCompatibleBitmap(pDC, Width, Height);

    oldmemBitmap memDC.SelectObject(&memBitmap);//将memBitmap选入内存DC
    memDC.BitBlt(0, 0, Width, Height, pDC, 0, 0, SRCCOPY);//复制屏幕图像到内存DC

    //以下代码保存memDC中的位图到文件
    BITMAP bmp;
    memBitmap.GetBitmap(&bmp);//获得位图信息
    
    FILE *fp fopen(filename, “w+b”);

    BITMAPINFOHEADER bih {0};//位图信息头
    bih.biBitCount bmp.bmBitsPixel;//每个像素字节大小
    bih.biCompression BI_RGB;
    bih.biHeight bmp.bmHeight;//高度
    bih.biPlanes 1;
    bih.biSize sizeof(BITMAPINFOHEADER);
    bih.biSizeImage bmp.bmWidthBytes bmp.bmHeight;//图像数据大小
    bih.biWidth bmp.bmWidth;//宽度
    
    BITMAPFILEHEADER bfh {0};//位图文件头
    bfh.bfOffBits sizeof(BITMAPFILEHEADER) sizeof(BITMAPINFOHEADER);//到位图数据的偏移量
    bfh.bfSize bfh.bfOffBits bmp.bmWidthBytes bmp.bmHeight;//文件总的大小
    bfh.bfType (WORD)0x4d42;
    
    fwrite(&bfh, 1, sizeof(BITMAPFILEHEADER), fp);//写入位图文件头
    
    fwrite(&bih, 1, sizeof(BITMAPINFOHEADER), fp);//写入位图信息头
    
    byte new byte[bmp.bmWidthBytes bmp.bmHeight];//申请内存保存位图数据

    GetDIBits(memDC.m_hDC, (HBITMAP) memBitmap.m_hObject, 0, Height, p, 
        (LPBITMAPINFO) &bih, DIB_RGB_COLORS);//获取位图数据

    fwrite(p, 1, bmp.bmWidthBytes bmp.bmHeight, fp);//写入位图数据

    delete [] p;

    fclose(fp);

    memDC.SelectObject(oldmemBitmap);
}