南山狒狒

我梦江南好

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  7 随笔 :: 5 文章 :: 1 评论 :: 0 Trackbacks

2009年3月24日 #

     摘要: 原文:http://blog.csdn.net/hnhyhongmingjiang/archive/2008/03/06/2154009.aspx 1.头文件中要定义宏;         #define   UNICODE       &nbs...  阅读全文
posted @ 2009-03-24 11:21 iJrong 阅读(2388) | 评论 (0)编辑 收藏

2009年3月23日 #

  说明:
  以下用一个自创的对话框类(MyMessageDlg)向视图类(MessageTestView)
  发送自定义消息为例,说明这两种不同方法的自定义消息的
  总结:
  消息传递的方法一:使用ON_MESSAGE
  使用ON_MESSAGE响应消息,必须配合定义消息#define WM_MY_MESSAGE (WM_USER+100)
  对于发送消息者-MyMessageDlg,
  在其MyMessageDlg.h中,定义#define WM_MY_MESSAGE (WM_USER+100)
  在其MyMessageDlg.cpp中要先添加:#include "MainFrm.h"
  因为使用了CMainFrame*定义对象。
  并且要有测试消息的函数
  void MyMessageDlg::OnButtonMsg()
  {
   // TODO: Add your control notification handler code here
   CMainFrame* pMF=(CMainFrame*)AfxGetApp()->m_pMainWnd; //先通过获取当前框架指针
   CView * active = pMF->GetActiveView();//才能获取当前视类指针
   if(active != NULL) //获取了当前视类指针才能发送消息
   active->PostMessage(WM_MY_MESSAGE,0,0); //使用PostMessage发送消息
  }
  对于消息的接受者-MessageTestView,
  在其MessageTestView.h中,也要定义#define WM_MY_MESSAGE (WM_USER+100)
  并定义消息映射函数-OnMyMessage()
  protected:
  //{{AFX_MSG(CMessageTestView)
  afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);
  //}}AFX_MSG
  DECLARE_MESSAGE_MAP()
  在其MessageTestView.cpp中,
  先要声明响应消息:
  BEGIN_MESSAGE_MAP(CMessageTestView, CEditView)
  //{{AFX_MSG_MAP(CMessageTestView)
  ON_MESSAGE(WM_MY_MESSAGE, OnMyMessage)
  //}}AFX_MSG_MAP
  再添加消息响应的函数实现:
  LRESULT CMessageTestView::OnMyMessage(WPARAM wParam, LPARAM lParam)
  {
  MessageBox("OnMyMessage!");
  return 0;
  }
  消息传递的方法二:使用ON_REGISTERED_MESSAGE
  使用ON_REGISTERED_MESSAGE注册消息,必须配合
  static UINT WM_MY_MESSAGE=RegisterWindowMessage("Message");
  对于消息的发送者-MyMessageDlg,
  在其MyMessageDlg.h中,只要
  定义static UINT WM_MY_MESSAGE=RegisterWindowMessage("Message");
  就可以了。
  在其MyMessageDlg.cpp中要先添加:#include "MainFrm.h"
  因为使用了CMainFrame*定义对象。
  并且要有测试消息的函数:
  void MyMessageDlg::OnButtonMsg()
  {
   // TODO: Add your control notification handler code here
   CMainFrame* pMF=(CMainFrame*)AfxGetApp()->m_pMainWnd; //先通过获取当前框架指针
   CView * active = pMF->GetActiveView();//才能获取当前视类指针
   if(active != NULL) //获取了当前视类指针才能发送消息
   active->PostMessage(WM_MY_MESSAGE,0,0); //使用PostMessage发送消息
  }
  对于消息的接收者-MessageTestView,
  在其MessageTestView.h中不要定义
  static UINT WM_MY_MESSAGE=RegisterWindowMessage("Message");
  应该把这个定义放到MessageTestView.cpp中,要不会出现: redefinition
  在其MessageTestView.h中只要定义消息映射函数
  protected:
  //{{AFX_MSG(CMessageTestView)
  afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);
  //}}AFX_MSG
  DECLARE_MESSAGE_MAP()
  在其MessageTestView.cpp中,先定义
  static UINT WM_MY_MESSAGE=RegisterWindowMessage("Message");
  接着注册消息:
  BEGIN_MESSAGE_MAP(CMessageTestView, CEditView)
  //{{AFX_MSG_MAP(CMessageTestView)
   ON_REGISTERED_MESSAGE(WM_MY_MESSAGE,OnMyMessage)
  //}}AFX_MSG_MAP
  最后添加消息响应的函数实现:
  LRESULT CMessageTestView::OnMyMessage(WPARAM wParam, LPARAM lParam)
  {
  MessageBox("OnMyMessage!");
  return 0;
  }
  ----------------------------------------------------------------
  比较两种方法,只是略有不同。但也要小心谨慎,以免出现接收不到消息的情况。
  -------------------------------------------------------------------
  其他注意事项:
  发送消息的-MyMessageDlg.cpp前也要定义
  static UINT WM_MY_MESSAGE=RegisterWindowMessage("Message");
  接受消息的-MessageTestView.cpp前也要定义
  static UINT WM_MY_MESSAGE=RegisterWindowMessage("Message");
  RegisterWindowMessage("Message")中""的内容是什么不重要,写什么都可以,单必须
  发送者与接受者是一样的内容,例如:"Message"
posted @ 2009-03-23 09:08 iJrong 阅读(767) | 评论 (0)编辑 收藏

2009年3月20日 #

原文:http://www.cnblogs.com/mengshu-lbq/archive/2007/03/19/675882.html


       本文是针对作者本人的一个具体的移植项目,将碰到的所有问题列出来,并给出具体的解决方法。由于是一个具体的项目,因此不能把所有的EVC工程移植问题囊括进来。所以,在移植项目前,建议还是看看以下的文章:
循序渐进:将 eMbedded Visual C++ 应用程序迁移到 Visual Studio 2005
eMbedded Visual C++ 到 Visual Studio 2005 升级向导(注意其最后一句话:默认情况下,Embedded Visual C++ 4.0 版会将 MFC Pocket PC 应用程序的对话框样式(Border)设置为 DS_MODALFRAME。MFC 8.0 不支持此样式。 —— 应改为Thin,如果不改的话,窗口就无法弹出。)
从 eVC 移植所带来的已知问题
Migrating Microsoft eMbedded Visual C++ Projects to Visual Studio 2005
        开发环境:
Windows XP +SP2 Visual Studio 2005 professional, Windows Mobile 6.0 Professional SDK。
注:(1)
对于Windows Mobile 5.0 SDK 开发的程序在Windows Mobile 6.0 下也能运行,而且不需要对程序进行任何的修改。
      (2)由于有些错误,是环境配置问题,所以在Debug/Resease模式下,都需要进行修改,以下错误中,如果是这类错误,都在标号后面写着“Resealse 模式也需要改”,当天切换到别的SDK下,如Windows Mobile 5.0 SDK,也需要修改。
      以下是针对Debug模式下的:
1、StdAfx.cpp (Resealse 模式也需要改)
编译错误:D:\Program Files\Microsoft Visual Studio 8\VC\ce\atlmfc\include\afxver_.h(77) : fatal error C1189: #error : Please use the /MD switch for _AFXDLL builds
解决方法:右击工程名,打开Project properties对话框,切换到C/C++->Code generation页,将Runtime Libarary 设置成“Multi-threaded DLL(/MD)”,即可解决此问题。
2、编译错误:error C2065: 'i' : undeclared identifier
原因:是由于存在以下的代码段:
for (int i = 0; i < MAX_LEN; i ++)
{
   //……
}
for (i = 0; i < MAX_NUM; i ++)
{
    //……
}
对于evc离开循环后,循环变量仍然有效,并且仍可以使用,但是在VS2005下是不行的,由此可见VS2005对变量的定义与审查更为严格,还有就是对数组越界问题也比EVC来的强。
解决方法:(不能完全相信编译器,也不能把所有的语法检查都丢给编译器)
int i = 0;
for (i = 0; i < MAX_LEN; i ++)
{
    //……
}
for (i = 0; i < MAX_NUM; i ++)
{
     //……
}
3、error C2664: '_wcsnicmp' : cannot convert parameter 2 from 'LPWORD' to 'const wchar_t *'
 需要强制类型转换
4、error C2061: syntax error : identifier 'HELPINFO'
自己增加HELPINFO的类型,增加头文件HelpInfo.h
5、error C2146: syntax error : missing ';' before identifier 'm_wndCommandBar'
原因:在Windows Mobile 5.0/6.0 下CCeCommandBar类被CCommandBar替换
解决方法:
CCeCommandBar   m_wndCommandBar; ---- 〉CCommandBar   m_wndCommandBar;
6、error C2065: 'NUM_TOOL_TIPS' : undeclared identifier
解决:
//#if defined(_WIN32_WCE_PSPC) && (_WIN32_WCE >= 212)
#define NUM_TOOL_TIPS 8
//#endif
7、error C3861: 'ON_WM_HELPINFO': identifier not found
同 4
8、error C2440: 'static_cast' : cannot convert from 'void (__cdecl CMyAppView::* )(void)' to 'LRESULT (__cdecl CWnd::* )(WPARAM,LPARAM)'None of the functions with this name in scope match the target type
解决方法:
afx_msg void OnHotLinkExplain();  --- 〉
afx_msg LRESULT OnHotLinkExplain(WPARAM wParam,LPARAM lParam);
9、error C2664: 'CSize CDC::GetTextExtent(LPCTSTR,int) const' : cannot convert parameter 1 from 'WORD *' to 'LPCTSTR'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast需要强制转换
pDC->GetTextExtent(&i, 1).cx);   ——>
pDC->GetTextExtent((LPCTSTR)&i, 1).cx;
10、error C2039: 'OnHelpInfo' : is not a member of 'CView'
error C2039: 'OnHelpInfo' : is not a member of 'CFrameWnd'
error C2039: 'OnHelpInfo' : is not a member of 'CDialog'
解决方法:用TRUE替换相应的类成员函数OnHelpInfo'
return CView::OnHelpInfo(pHelpInfo); ——> return TRUE;
11、error C2039: 'm_bShowSharedNewButton' : is not a member of 'CCommandBar'
D:\Program Files\Microsoft Visual Studio 8\VC\ce\atlmfc\include\afxext.h(557) : see declaration of 'CCommandBar'
解决方法
直接注释掉 m_wndCommandBar.m_bShowSharedNewButton = FALSE;
12、.\MyApp.rc(380) : fatal error RC1015: cannot open include file 'wceres.rc'.
解决方法
直接注释掉:#include "wceres.rc"         // WCE-specific components
但是,这个错误很讨厌,每次你修改资源文件后,都得修改该语句,不知道为什么。
13、Resease 模式下也要修改
error LNK2019: unresolved external symbol SHInitExtraControls referenced in function "protected: __cdecl CMyAppView::CMyAppView(void)" (??0CMyAppView@@IAA@XZ)
问题:程序中调用了SHInitExtraControls();
error LNK2019: unresolved external symbol SHSipPreference referenced in function "protected: void __cdecl CMyAppView::OnKillfocusWord(void)" (?OnKillfocusWord@CMyAppView@@IAAXXZ)
问题:程序中调用了SHSipPreference
以上两个函数都在:Library: aygshell.lib里
解决方法:
工程-->属性-->Linker -->input -- > Additional Denpendencies :aygshell.lib
14、Resease 模式下也要修改
orelibc.lib(wwinmain.obj) : error LNK2019: unresolved external symbol wWinMain referenced in function wWinMainCRTStartup
属性—〉Linker—〉Anvanced—〉EntryPoint
将 wWinMainCRTStartup 更改为 WinMainCRTStartup
Entry Point是WinMainCRTStartup(ANSI)或wWinMainCRTStartup(UINCODE),即: ... WinMainCRTStartup 或wWinMainCRTStartup 会调用WinMain 或wWinMain。
15、  error C3861: 'LoadStdProfileSettings': identifier not found
注释掉函数 LoadStdProfileSettings
该函数的具体功能,看MSDN。 
       BTW:编译的时候,有可能会出现一些由以上错误产生的连锁错误,俗称“蝴蝶效应”,如error C2143: syntax error : missing ';' before '}'
error C2143: syntax error : missing ';' before ','
error C2143: syntax error : missing ';' before '{'
少了了'{'、'}'、';'等等,把以上的错误—主要矛盾解决了,这些错误—错误矛盾也就迎刃而解了。何况,这个工程是以前在EVC IDE下编译通过,MS再怎么优化或改进编译器,也总不可能发生自相矛盾的事情吧,总要考虑兼容性吧,要对自己或公司的前辈有信心!
      到此,已经能够编译通过,但是运行的时候,又出现如下的问题:
16、Resease 模式下也要修改
按F5,出现如下的对话框:

解决方法:
 右击工程的属性—〉General—〉Project Defaults –〉Use MFC :
Use MFC in a shared DLL ——> Use MFC in a static DLL
也正是因为这个,VS2005产生的EXE程序比EVC产生的要大200多k。

      这样,程序基本移植完成,但是还要把所有的功能过一遍,有可能还会碰到,诸如对话框出现乱码、菜单不对等问题。
posted @ 2009-03-20 00:19 iJrong 阅读(512) | 评论 (0)编辑 收藏

2008年5月19日 #

近日在开发过程中遇到WinCE应用程序开机自动运行的问题,在网上找了找,发现大概有以下三种方法:
1、将应用程序和应用程序快捷方式添加到映像里,再将快捷方式添加到StartUp目录下,这样当系统运行后应用程序就能自动运行;

2、直接替换Wince的SHELL,即修改注册表:
[HKEY_LOCAL_MACHINE\init]
"Launch50"="explorer.exe"
"Depend50"=hex:14,00, 1e,00
把这个explorer.exe改成你的应用程序(比如:MyApp.exe);

3、把应用程序加入到映像,修改注册表:
[HKEY_LOCAL_MACHINE\init]
"Launch80"="MyApp.exe"
"Depend80"=hex:1E,00
可以设置启动顺序和依赖程序;
以上方法都可行,但是都存在一个问题,就是应用程序是集成到NK里面的,也就是说每次升级应用程序都要重新编译下载内核,很麻烦,尤其在程序调试阶段,大家都希望把应用程序放在SD卡上,这样更新起来比较容易;据说通过第三种方法可以实现,即修改"Launch80"="MyApp.exe"为"Launch80"="\STDCard\MyApp.exe"( STDCard为SD卡目录),但是我试了一下没有成功,因为Launch80运行时SD卡的文件驱动还没有加载,找不到MyApp.exe文件。同样,采用快捷方式加载SD卡里的应用程序也不可行。
所以我采用了另一种方法,自己编了一个小程序,比如叫ShellExe.exe,将此程序加入到映像里,通过StartUp快捷方式调用ShellExe,ShellExe再去调用SD卡里的应用程序,具体实现步骤如下:
1、 在eVC下编译如下代码:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{    
 WIN32_FIND_DATA fd;
 HANDLE hd=INVALID_HANDLE_VALUE;  

 int iCount = 20;
    while(iCount--)      
    {
  hd=::FindFirstFile(lpCmdLine,&fd);  
  Sleep(500);  
  
  if(INVALID_HANDLE_VALUE!=hd)
   break;      
 }   
 
 if(0==iCount)
  return 0;  

 FindClose(hd);  

 SHELLEXECUTEINFO ShExeInfo={0};      
 ShExeInfo.cbSize=sizeof(SHELLEXECUTEINFO);      
 ShExeInfo.fMask=SEE_MASK_NOCLOSEPROCESS;      
 ShExeInfo.hwnd=NULL;      
 ShExeInfo.lpVerb=NULL;     
 ShExeInfo.lpFile=lpCmdLine;      
 ShExeInfo.lpParameters=L"";    
 ShExeInfo.lpDirectory=NULL;     
 ShExeInfo.nShow=SW_SHOW;      
 ShExeInfo.hInstApp=NULL;   

 ShellExecuteEx(&ShExeInfo);
 return 0;
}
  生成ShellExe.exe的可执行文件,此段代码主要功能是查找指定的应用程序,然后执行;下面这段代码可以保证在SD卡文件系统正确加载后才去执行应用程序; 

    while(iCount--)      
    {
  hd=::FindFirstFile(lpCmdLine,&fd);  
  Sleep(500);  
  
  if(INVALID_HANDLE_VALUE!=hd)
   break;      
 }  

文件的名称和路径由命令行参数指定:ShExeInfo.lpFile=lpCmdLine;

2、 新建一个快捷方式,如Autorun.lnk,按如下方式编辑其内容:
21#\windows\shellexe.exe \stdcard\MyApp.exe其中\stdcard\MyApp.exe应用程序的绝对路径;

3、 将MyApp.exe和Autorun.lnk添加到NK里,方法是在project.bib文件内加入如下内容:
ShellExe.exe f:\WINCE420\PBWORKSPACES\LioetEnTer\RelDir\ShellExe.exe NK SAutorun.lnk f:\WINCE420\PBWORKSPACES\LioetEnTer\RelDir\Autorun.lnk NK S注意:ShellExe.exe的属性不能带H(隐藏).

4、 在project.dat里加入如下内容:
Directory("\Windows\Startup"):-File("Autorun.lnk","\Windows\Autorun.lnk")5、 选择Make Image生成映像(当然Build也可以,就是慢点儿),烧到FLASH里,开机运行,可以看到SD卡里的MyApp.exe被正确执行。
总结
  这种方法用起来比较方便,ShellExe.exe不用每次都重新编译,只要根据应用程序路径修改Autorun.lnk即可,可以加载Flash、U盘、SD卡里的应用程序。调试及升级应用程序就不用重新烧写内核了。

posted @ 2008-05-19 19:12 iJrong 阅读(570) | 评论 (0)编辑 收藏

2008年5月5日 #

从网上看到用SetDevicePower可以开关WIFI,但郁闷的是不同的OEM厂商,甚至不同型号的手机,WIFI设备名称都可能不一样。

不过我想了想,还是搞定了 Windows Mobile 中开关 WIFI 的“通用”代码,基本上在各种WM手机中都能正常工作。

看下面的代码,主要是枚举所有的通讯设备,如果设备显示名称中包含特定字符串(如Wi-Fi,802.11等)就认为是WIFI设备,接下来的问题迎刃而解,OK,“完美”收工:)

 


附件是一个小程序,无参数执行自动切换 WIFI 开关SP/PPC通用。
点击这里下载文件: RadioSwitch.rar

posted @ 2008-05-05 23:13 iJrong 阅读(889) | 评论 (1)编辑 收藏

2008年5月4日 #

精华浓缩

         Windows中负责图形输出的是GDI(即Graphic Device Interface,图形设备接口)。这是Windows与硬件无关的图形输出模式的体现。GDI建立在硬件抽象层(HAL)之上,屏蔽了不同输出设备之间的差异,从而为用户提供了一个统一的“标准输出设备”。但是,与DOS不同,Windows是多任务、进程独立的,每一个窗口都应该有一个独立的输出通道。这样,GDI又使用了一种简单的机制来保证在窗口中画图的不同程序之间能共享“设备”而又互不干扰。这个机制就是DC(Device Context,设备描述表)。
     有人把DC比喻成画家的画室,这里有画布、画刷、画笔等等很多工具。

     就画布而言,画布形式可以不同,是的,我可以在桌上(desktop)的纸上(window)画,也可以就画在桌面上,还可以画在墙上(管的着吗!^_^)。
     为此,Windows MFC提供了四种不同的DC环境(封装为C++类),以标明不同的绘制权限,即:
        CPaintDC, 用于在窗口客户区画图(仅限于在OnPaint处理函数中使用);
        CClientDC, 也用于在窗口客户区画图(限于在OnPaint处理函数之外使用);
        CWindowDC, 用于在窗口内任意地方画图,包括非客户区;
        CMetaFileDC, 用于绘制GDI图元文件。

     这些类都可以直接实例化,如:
       CPaintDC dc(this);//this表示此DC所属窗口为当前窗口
创建了一个CPaintDC对象dc。
       CWindowDC一般不常用,如果想在窗口非客户区画图,可借助OnNcPaint()处理函数捕获WM_NCPAINT消息。
    
     刚才说了,DC中还有画刷、画笔等。这些都是DC的属性,可通过DC自身(调用其成员函数)获得。
        DC属性包括文本颜色、背景颜色、映射模式、绘图模式、当前位置、当前画笔(刷)和当前字体等。
     画笔(Pen)、画刷(Brush)都是独立的GDI对象,可通过CDC成员函数SelectObject()选入DC。同样操作方式的对象还有字体(Font)、位图(Bitmap)、调色板(Palette)和区域(Region)。
     关于SelectObject():在创建好GDI对象之后,SelectObject()接收该对象指针,其返回值为先前选入DC的相同类型的对象指针(通常用来恢复DC用)。
         Windows也预先定义了一些画笔、画刷、字体以及其他一些GDI对象。这些对象称为备用对象,用CGdiObject::SelectStockObject()选入。CGdiObject是表示GDI对象的CPen、CFont等类的基类。备用对象的属性说明可以查MSDN。
     由CGdiObject派生类创建的画笔、画刷和其他对象都要占用内存资源,因此使用后一定要删除它们。处理方法与其他window对象类似。在栈中创建的对象,当此CGdiObject超出范围时会自动析构。在堆中用new创建的CGdiObject对象,可通过调用CGdiObject::DeleteObject显式删除(这会引起对GDI对象析构函数的调用)或用相应的delete运算符。如果是备用对象,则没必要专门删除,留给windows就可以了。
        VC++有一种简单的方法用来确定是否成功的删除了GDI对象:只要在调试状态下运行应用程序的调试版本即可。在应用程序结束时,没有释放的资源会显示在调试窗口中。
    
     
一些知识点

1.绘图模式:GDI将象素点输出到逻辑显示平面上时,并不只是简单的输出象素颜色,而是通过一系列布尔运算将输出象素点的颜色和输出目标位置上象素点的颜色进行合成再显示。所使用的逻辑运算关系就由DC的绘图模式确定。使用CDC:SetROP2()可更改绘图模式(ROP2,Raster Operation To)。默认绘图模式是R2_COPYPEN,直接将象素点输出到显示平面上。常用的还有R2_NOT,用于实现鼠标绘图时的Rubber技术。

2.映射模式:这是DC的属性之一,用于确定从逻辑坐标到设备坐标的转换(或者说mapping,映射)方式。设备坐标是指窗口中相应的象素点位置。单位只有象素一种。而逻辑坐标依映射模式不同而单位各异。如默认的MM_TEXT模式下,一个单位恰恰是一个象素点。MM_LOENGLISH模式下,一个单位则相当于百分之一英寸长。windows支持8种映射模式,其中的MM_ISOTROPIC和MM_ANISOTROPIC是可编程的。这意味着是用户而不是windows确定从逻辑坐标到设备坐标的转换方式。换句话说,就是用户来自行定制逻辑单位的实际大小。这两种模式最常用于根据窗口尺寸按比例自动调节画图输出大小的场合。两者之间的唯一区别在于:前者中X方向和Y方向具有同一缩放比例因子。设置映射模式的函数是CDC::SetMapMode()。

3.坐标系常用技术:
1)坐标变换:调用CDC::LPtoDP可将逻辑坐标值转换为设备坐标值。反之,调用CDC::DPtoLP可将设备坐标值转换为逻辑坐标值。在相应鼠标单击区域命中测试时,将使用这两个函数。因为鼠标单击得到的是设备坐标,而很多GDI函数使用逻辑坐标,必须转换为统一坐标,操作才有意义。
2)原点移动:默认方式下,DC的原点位于相应显示平面的左上角。MFC提供了两个CDC类成员函数,可改变原点位置。CDC::SetWindowOrg()移动窗口原点,CDC::SetViewportOrg()移动视图原点(详见MSDN)。一般只能使用两者之一。原点移动技术在边框滚动条设置时有所体现。
3)用户坐标与屏幕坐标:前者是设立在窗口客户区左上角的设备坐标值,后者是原点位于屏幕左上角的设备坐标值。两者的相互转换用函数是CWnd::ClientToScreen()和CWnd::ScreenToClient()。

4.GDI绘图函数
1)画线:包括MoveTo、LineTo、Polyline、PolylineTo、Arc、ArcTo、PolyBezier等。其中Polyline和PolylineTo都可以一次画多条线,两者的区别是PolylineTo使用DC的当前位置,而Polyline则不需要。ArcTo在win98下未实现。另外,所有GDI画线函数有一个共同特点,就是从不画最后一个象素点。
2)画图形:画封闭图形的GDI函数以外接矩形的坐标为参数。常用函数有Rectangle、Ellipse、RoundRect、Pie、Chord等。

5.画笔与画刷:在MFC中,画笔对象封装为CPen类,画刷对象封装为CBrush类。创建两者都有三种方法。最简单的就是构造一个CPen对象,直接给出所用参数进行初始化。第二种方法是调用一个未初始化的CPen对象,用CreatePen()初始化。还有一种方法是构造一个未初始化的CPen对象,通过向LOGPEN结构中填充描述画笔特性的参数,然后调用CPen::CreatePenIndirect()生成画笔。画刷基本相同。
1)CPen:windows用当前选入DC的画笔绘制线条,并给封闭图形镶制边框。画笔有三个特性,即样式、宽度和颜色。样式有PS_SOLID、PS_INSIDEFRAME、PS_NULL等。PS_NULL一般称其为“NULL画笔”,想画一个没有边框的图形,就用到它了。笔宽以逻辑单位给出,实际意义与当前映射模式相同。颜色是通过RGB宏把三个独立颜色成分的值合成为一个可传递给GDI的COLORREF值来确定的。
2)CBrush:画刷有三种基本类型,即单色、带阴影线和带图案。其中图案画刷允许用位图填充图形内部(这样,窗口背景也就没啥新鲜的了)。常用函数有
CDC::SetBkMode()、CDC::SetBkColor()等。

6.文本与字体:CDC有一打文本处理函数,重要的几个是DrawText、TextOut、GetTextMetrics、SetTextColor和SetTextAlign等。其中GetTextMetrics()传给TEXTMETRIC结构关于字体性质的相关信息。字体是一组具有特定尺寸(高度)和字样的字符;字样指示字体共有属性,如粗细等。字体封装在CFont类中,建立字体对象,要在CFont构造之后,再调用CFont的成员函数CreateFont或CreateFontIndirect等来建立GDI字体资源。针对字体,有一个LOGFONT结构,其中定义了字体的所有特性。也可通过填充它来创建字体。

后记:写这一章的笔记时有一种被作者牵着鼻子走的感觉。知识点太多,写出来有一种罗列或拼凑的嫌疑。我不希望这样,但想一想,技术也就是这样。所以我希望大家看的时候,能够思考着看,而不是记忆着看。思考着看只要求我们知道技术点、怎么用,用熟了,用多了,也就记住了。精华是浓缩的,至于如何把它化开,可要靠你自己了。

堆与栈的问题:

  堆,heap,   可以动态的建立和删除的内存。  
  栈,stack,先进后出的数据结构,是用来暂时保存数据的。 

 

堆用来动态分配内存,栈由编译器自动使用,用来分配局部变量、函数参数。堆的增长由内存的底部向上,栈的增长由内存的高端向下。堆的大小一般比栈大得多。

 

  堆是用来实现动态存储分配的,和FILO没有关系。   
  栈由于它先进后出的特性适合作活动记录(包括函数返回地址,局部变量,对于pascal等语言还包括display表)的存储。(想一想如果你编写一个递归程序,栈是怎样起作用的。)   至于堆和栈的组织是不是相临的,这和OS的实现有关。 

 

  CObject   aboj;  
  则aobj建在堆栈中  
  CObject   *pAObj=new   CObject()  
  pAObj建在堆中,需要你用delete删除之。  
  比如用到DC对象的时候,可以这样:  
  CDC   dc(this)//建在堆栈中,函数结束后自动删除  
  CDC   *pDC                 //建在堆中,需要ReleaseDC(pDC)删除。

posted @ 2008-05-04 15:24 iJrong 阅读(2083) | 评论 (0)编辑 收藏

2008年5月1日 #

       在调用一个API函数以后,如果函数失败,通常可以紧接着调用另一个API函数“GetLastError”来返回一个错误代码,下面这个类可以根据Windows定义的错误代码,查找到用文字表示的错误信息:

00001: #ifndef _YHB_SYSERROR_INCLUDED_
00002: #define _YHB_SYSERROR_INCLUDED_
00003:
00004: #include <stdexcept>
00005: #include <string>
00006:
00007: namespace yhb {
00008:
00009: class SysError
00010: : public std::runtime_error
00011: {
00012: public:
00013: SysError(int err=0)
00014: : runtime_error(makeMsgFromErrorNum(err))
00015: {}
00016: SysError(const char *customMsg, int err = 0)
00017: : runtime_error(makeMsgFromErrorNum(customMsg, err))
00018: {}
00019: static std::string makeMsgFromErrorNum(unsigned err = 0);
00020: static std::string makeMsgFromErrorNum(const char *customMsg, unsigned err = 0);
00021: };
00022:
00023: } // end of namespace
00024:
00025: #endif

SysError从std::runtime_error派生,因此可以被抛出并被作为std::exception捕获。

如果不想使用异常,也可以用它的两个静态方法来返回错误信息。

实现

00001: #include "StdAfx.h"
00002: #include "./SysError.h"
00003: #include <sstream>
00004: #include <LMErr.h>
00005:
00006: #define WIN32_LEAN_AND_MEAN
00007: #include <Windows.h>
00008:
00009: using namespace std;
00010:
00011: namespace yhb {
00012:
00013: /************************************************************************
00014: 管理用LoadLibrary()加载的模块句柄
00015: ************************************************************************/
00016: class Module {
00017: public:
00018: explicit Module(HMODULE handle=0)
00019: : handle_(handle)
00020: {}
00021: ~Module() {
00022: free();
00023: }
00024: Module & operator = (HMODULE handle) {
00025: free();
00026: handle_ = handle;
00027: return *this;
00028: }
00029: bool isValid() const { return 0!=handle_; }
00030: operator HMODULE() const { return handle_; }
00031: private:
00032: Module(const Module &);
00033: Module & operator = (const Module &);
00034: void free() {
00035: if (0!=handle_) {
00036: ::FreeLibrary(handle_);
00037: handle_ = 0;
00038: }
00039: }
00040: HMODULE handle_;
00041: };
00042:
00043: /************************************************************************
00044: SysError
00045: ************************************************************************/
00046: string SysError::makeMsgFromErrorNum(unsigned err/* =0 */) {
00047: if (0==err) {
00048: err = GetLastError();
00049: if (NOERROR==err)
00050: return "no error!";
00051: }
00052: Module module;
00053: DWORD flag = FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM;
00054: if (err >= NERR_BASE && err <= MAX_NERR) {
00055: module = LoadLibraryExA("netmsg.dll", 0, LOAD_LIBRARY_AS_DATAFILE);
00056: if (module.isValid())
00057: flag |= FORMAT_MESSAGE_FROM_HMODULE;
00058: }
00059: char buf[1024];
00060: if (FormatMessageA(flag, static_cast<HMODULE>(module),
00061: err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
00062: buf, sizeof(buf), 0))
00063: {
00064: return buf;
00065: } else {
00066: ostringstream os;
00067: os << "Unknown error: " << err << " (0x" << hex << err << ')';
00068: return os.str();
00069: }
00070: }
00071:
00072: string SysError::makeMsgFromErrorNum(const char *customMsg, unsigned err/* =0 */) {
00073: string result(customMsg);
00074: result += ' ';
00075: result += makeMsgFromErrorNum(err);
00076: return result;
00077: }
00078:
00079: } //end of namespace

C++里一种比较常用的方法,是将资源封装成一个类,在析构的时候释放该资源,比如上面的Module,析构的时候调用FreeLibrary。

posted @ 2008-05-01 01:28 iJrong 阅读(528) | 评论 (0)编辑 收藏

仅列出标题