bcg知识

9月28日
爱着你,恨着你——BCGControlBar的Menu字体

在BCGControlbar很好用,但是中如果自定义字体的话比较难看

image

注意菜单好像饱受压迫的一样,郁闷,在mainfrm中的oncreate中加入

LOGFONT lf; //lf定义字体属性
lf.lfOutPrecision= OUT_STROKE_PRECIS;
lf.lfClipPrecision= CLIP_STROKE_PRECIS;
lf.lfQuality = DRAFT_QUALITY;
lf.lfPitchAndFamily= VARIABLE_PITCH|FF_MODERN;

lf.lfHeight = 12;
lf.lfWidth = 0;
lf.lfEscapement = 0;
lf.lfOrientation = 0;
lf.lfWeight = FW_HEAVY;
lf.lfItalic = FALSE;
lf.lfUnderline = FALSE;
lf.lfStrikeOut = FALSE;
lf.lfCharSet = GB2312_CHARSET; strcpy(lf.lfFaceName,"宋体");

m_wndMenuBar.SetMenuFont(&lf,TRUE);

image

结果还是比较满意,嘿嘿

9月23日
BcgControlbar是个好东西——界面用

解压缩 BCGControlBar.zip (比如,到 c:/bcg 目录中)
把 c:/bcg/bin 增加到你的 path 环境变量中,
运行 Visual C++ 并且打开 Tools | Options 对话框,切换到Directories 页并且把 c:/bcg/bcgcontrolbar 加入到 include 目录 中,把 c:/bcg/bin 加入 library 和 executable 目录中;
打开Bcgcontrolbar 和/或 BcgcontrolbarStatic 项目(路径是 c:/bcg/bcgcontrolbar) 并且选择需要的选项;
如果要安装 BCGControlBar 应用程序向导,只需要打开BCGBAppWizard 项目并编译链接。你将在项目列表中看到一个新的条目。
你必须编译链接所有的 BCGControlBar 库的 DLL 文件;

打开 BCGControlBar 项目并编译链接。下面是一个你将得到的 DLLs 和 库文件列表:

BCGCB***D.dll, BCGCB***D.lib DLL debug version
BCGCB***.dll, BCGCB***.lib DLL release version
BCGCB***UD.dll, BCGCB***UD.lib DLL debug version, UNICODE
BCGCB***U.dll, BCGCB***U.lib DLL release version UNICODE
BCGCB***StaticD.lib static library debug version
BCGCB***StaticDS.lib static library debug version, MFC shared DLL*
BCGCB***Static.lib static library release version
BCGCB***StaticS.lib static library release version, MFC shared DLL*
BCGCB***StaticUD.lib static library debug version, UNICODE
BCGCB***StaticUDS.lib static library debug version, UNICODE, MFC shared DLL*
BCGCB***U.lib static library release version, UNICODE
BCGCB***US.lib static library release version, UNICODE, MFC shared DLL*

*** 表示版本号。比如,如果你使用的库版本为 5.00 发行版, DLL 的相应的发行版本为 BCGCB500.dll
* static library version with MFC shared DLL 适用于 4.7 或更高版本。

所有这些文件将定位在你的 /Bin 目录中。 记得要把这些目录加入你的系统目录中(把其中的dll全部拷贝到system32下)。

请按如下内容改变你的源代码:

添加 BCGControlBar 路径到 INCLUDE 路径
确定你在你的应用程序中调用 了 AfxOleInit() InitInstance()
添加下列语句到 stdafx.h 文件:
#include "BCGCBProInc.h"

添加 CBCGWorkspace-派生到你的应用程序类:
class CMyApp : public CWinApp,
public CBCGWorkspace

首先,你必须定义在注册表中存放你自定义数据的位置和你 需要什么样的自定义(鼠标、键盘、上下文菜单),为了做这些工作,在CMyApp::InitInstance 中设置注册表入口并初始化自定义管理器:
SetRegistryBase (_T("Settings"));

// 初始化自定义管理器:
InitMouseManager();
InitContextMenuManager();
InitKeyboardManager();

如果你已经决定使用鼠标或上下文菜单的自定义功能,你必 须在鼠标自定义管理器中附加一个视图,或初始化上下文菜单。重载CBCGWorkspace::PreLoadState 行为:
class CMyApp ....
{
...
virtual void PreLoadState();
...
};

void CMyApp::PreLoadState()
{
// 把鼠 标事件连接到特定 的视图 :
GetMouseManager()->AddView (iIdTestView, _T("Test view"), IDR_VIEW);

// 初始化上下文菜单:
GetContextMenuManager()->AddMenu (_T("Test menu"), idMenu);
}

同时在 mainfrm.h 和 mainfrm.cpp 文件中 把 CMDIFrameWnd 变成 CBCGMDIFrameWnd ,(在 SDI 应用程序的情况下, 把 CFrameWnd 变成 CBCGPFrameWnd)
把 CMDIChildWnd 变成 CBCGMDIChildWnd
把 CToolbar 变成 CBCGPToolBar 并且添加一个内嵌菜单栏对象到你的 CMainFrame 类中:
CBCGPMenuBar m_wndMenuBar; // 新的菜单栏
CBCGPToolBar m_wndToolBar; // 应用程序工具栏

在 CMainFrame::OnCreate() 行为中添加如下的行,以便使能菜单栏功能:
// 创建菜单栏(替换标准菜单):
if (!m_wndMenuBar.Create (this))
{
TRACE0("Failed to create menubar/n");
return -1; //创建失败
}
m_wndMenuBar.SetBarStyle (m_wndMenuBar.GetBarStyle() |
CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);

为了使能菜单栏停靠,你应当添加如下代码:
m_wndMenuBar.EnableDocking (CBRS_ALIGN_ANY);
DockControlBar (&m_wndMenuBar);

重要之处: 你可以在应用程序中使用任何数目的CBCGToolBar 工具栏。所有的工具栏图像将被合并到一个位图文件中。 无论如何,仅仅有一个CBCGMenuBar 对象被使用。

为了使能 工具栏/菜单 的自定义,请作出如下改变:

添加 工具栏/菜单 自定义命令(比如,View | Customize...)
实现 OnViewCustomize 行为。代码看起来如下:
void CMainFrame::OnViewCustomize()
{
// 创建一个自定义工具栏对话框:
CBCGToolbarCustomize* pDlgCust = new CBCGToolbarCustomize (this,
TRUE /* Automatic menus scaning */);
// 添加预定义工具栏:
pDlgCust->AddToolBar ("Main", IDR_MAINFRAME);
....

// 添加用户自定义命令:
pDlgCust->AddButton ("User", CBCGToolbarButton (ID_USER_TOOL1, 1, "User Tool 1", TRUE));
pDlgCust->AddButton ("User", CBCGToolbarButton (ID_USER_TOOL2, 2, "User Tool 2", TRUE));
pDlgCust->AddButton ("User", CBCGToolbarButton (ID_USER_TOOL3, 3, "User Tool 3", TRUE));
....

pDlgCust->SetUserCategory ("User");

// 使能用户自定义工具栏的 Create/Delete :
pDlgCust->EnableUserDefinedToolbars ();

pDlgCust->Create ();
}

为了使能 Microsoft?Office 2000 菜单:

定义你自己的基本命令集合(通常在CMainFrame::OnCreate()中):
CList lstBasicCoomads;

lstBasicCoomads.AddTail (ID_FILE_NEW);
lstBasicCoomads.AddTail (ID_FILE_OPEN);
lstBasicCoomads.AddTail (ID_FILE_SAVE);

......
lstBasicCoomads.AddTail (ID_APP_ABOUT);

CBCGToolBar::SetBasicCommands (lstBasicCoomads);

这些命令将显示在下拉菜单中:
为了使能菜单阴影:

CBCGMenuBar::EnableMenuShadows (BOOL bEnable = TRUE)

注意 如果你查看的内容可能动态改变就不要在弹出式菜单中使用菜单 阴影(比如,视图显示动画、HTML页)在这种情况下,菜单阴影 会记忆以前的视图图像。

为了在运行时改变菜单字体:

CBCGMenuBar::SetMenuFont (LPLOGFONT lpLogFont, BOOL bHorz = TRUE);

为了使能“页面”(自定义)按钮,只需要调用:

m_wndToolBar.EnableCustomizeButton (TRUE, id_of_customize_command,
_T("Customize..."));

为了使能图像覆盖下的文字:

m_wndToolBar.EnableTextLabels (BOOL bEnable = TRUE);

为了使能用户自定义工具:

添加一个新的菜单条目:ID_TOOLS_ENTRY。该条目将 自动被实际存在的工具列表取代。
添加如下的条目到 STRING 资源:

ID_TOOL1 "Activates user-defined tool/nUser Tool"
ID_TOOL2 "Activates user-defined tool/nUser Tool"
....
ID_TOOLx "Activates user-defined tool/nUser Tool"

在应用程序的InitInstance() 中调用:
EnableUserTools (ID_TOOLS_ENTRY, ID_TOOL1, ID_TOOLx);

一个 "Tools" 新页面将加入到自定义对话框中
为了使能动态可裁剪菜单:

在 STRING 资源表中保留部分条目。这些标识符将被当作控制栏标识符使用。

ID_TEAR_OFF1 ""
ID_TEAR_OFF2 ""
.......
ID_TEAR_OFFx ""

对于每一个可裁剪弹出式菜单,把 "Break" 属性改位 "Bar" (MF_MENUBARBREAK)
在应用程序的 InitInstance() 中调用:
EnableTearOffMenus (_T("RegBase", ID_TEAR_OFF1, ID_TEAR_OFFx);

为了使能静态可裁剪菜单

在 STRING 资源表中保留一个条目。这个标识符将区别于动态 可裁剪 标识符(如上所述)。

ID_TEAR_OFF_BAR ""

在主框架的 OnShowPopupMenu,为特定的菜单按钮使能可裁剪:
pMenuButton->SetTearOff (D_TEAR_OFF_BAR);

以下地址有破解版下载
http://www.skkk.net/Download.asp?ID=22532&URL=http://http.skkk.net/061124/download/BCGControlBar.Professional.v7.31.Final.rar

安装密码 TEAM   ZWT

9月20日
VC在对话框中实现分割窗口

中对话框中实现窗口的分割(FormView一样,只是将函数构造函数和内部的所有CDialog改成CFormView就OK了)

具体类如附件所示

并且在Oninitidialog中添加:

LPCTRLINFO pInfoLeft = new CTRLINFO( &m_ctrlLeft, CSize( 50, 100 ), 95, 0 );
LPCTRLINFO pInfoRight = new CTRLINFO( &m_ctrlRight, CSize( 50, 100 ), 0, 0 );

// Initialize of the splitter dialog
InitDialog( pInfoLeft, pInfoRight, 40 );   

VC中给工具栏上的按钮添加文字

//  这个例子演示了如何将文字添加到工具栏按钮上
int  CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if  (CMDIFrameWnd::OnCreate(lpCreateStruct)  ==   - 1 )
       return   - 1 ;

    // Create a toolbar. Resource ID of the toolbar to be loaded
    // is IDR_MAINFRAME.

    if  ( ! m_wndToolBar.CreateEx( this , TBSTYLE_FLAT, WS_CHILD  |  WS_VISIBLE
       |  CBRS_TOP)  ||   ! m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
   {
      TRACE0( " Failed to create toolbar  " );
       return   - 1 ;   //  fail to create
   }
    // 在工具栏按钮上显示文字
   VERIFY(m_wndToolBar.SetButtonText( 0 , " New " ));
   VERIFY(m_wndToolBar.SetButtonText( 1 , " Open " ));
   VERIFY(m_wndToolBar.SetButtonText( 2 , " Save " ));
   VERIFY(m_wndToolBar.SetButtonText( 4 , " Cut " ));
   VERIFY(m_wndToolBar.SetButtonText( 5 , " Copy " ));
   VERIFY(m_wndToolBar.SetButtonText( 6 , " Paste " ));
   VERIFY(m_wndToolBar.SetButtonText( 8 , " Print " ));
   VERIFY(m_wndToolBar.SetButtonText( 9 , " About " ));

   CRect temp;
   m_wndToolBar.GetItemRect( 0 , & temp);
   m_wndToolBar.SetSizes(CSize(temp.Width(),
      temp.Height()),CSize( 16 , 15 ));

    return   0 ;
}

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/tg2003/archive/2009/07/21/4365372.aspx

VC++对话框添加工具栏

1、添加工具栏资源ID为IDR_TOOLBAR
2、在对话框的类定义中加:
CToolBar m_ToolBar;
3、在OnInitDialog中或其它合适的消息响应中加如下代码:(函数可查看MSDN)
m_ToolBar.Create(this); //创建工具栏
m_ToolBar.LoadToolBar(IDR_TOOLBAR);//加载工具栏
//得出控件条大小.
CRect rect;
CRect rectNow;
GetClientRect(rect);
RepositionBars(AFX_IDW_CONTROLBAR_FIRST,AFX_IDW_CONTROLBAR_LAST,0,reposQuery,rectNow);

//放置控件条位置
CPoint ptOffset(rectNow.left-rect.left,rectNow.top-rect.top);

CRect rcChild;
CWnd* pwndChild=GetWindow(GW_CHILD);
while (pwndChild)
{                              
   pwndChild->GetWindowRect(rcChild);
   ScreenToClient(rcChild);
   rcChild.OffsetRect(ptOffset);
   pwndChild->MoveWindow(rcChild,FALSE);
   pwndChild=pwndChild->GetNextWindow();
}

//调整对话框尺寸
CRect rcWindow;
GetWindowRect(rcWindow);
rcWindow.right+=rect.Width()-rectNow.Width();
rcWindow.bottom+=rect.Height()-rectNow.Height();
MoveWindow(rcWindow, FALSE);
//控件条定位
RepositionBars(AFX_IDW_CONTROLBAR_FIRST,AFX_IDW_CONTROLBAR_LAST,0);
//对框居中
CenterWindow();

4、手工添加处理函数
afx_msg void OnBtnXXX();//消息响应函数声明
ON_COMMAND(ID_BTN_XXX/*工具按钮ID*/,OnBtnXXX/*函数名*/)//消息映射
         void CXXXDlg::OnBtnXXX(){}//消息处理函数

9月18日
VC自定义消息

第一:

简易版本:

定义一个自定义消息号:const UINT WM_MYMESSAGE = WM_USER + n; // 自定义消息一般大于WM_USER
,然后就可以为该消息添加映射了
afx_msg LRESULT OnMyMessage ( WPARAM wParam, LPARAM lParam );
ON_MESSAGE ( WM_MYMESSAGE, OnMyMessage )
LRESULT cxx::OnMyMessage ( WPARAM wParma, LPARAM lParam )
{
...
}
如果该消息不需要返回值,也不需要参数,那么可以使用宏ON_MESSAGE_VOID来映射
afx_msg void OnMyMessage ();
ON_MESSAGE_VOID ( WM_MYMESSAGE, OnMyMessage )
void cxx::OnMyMessage ()
{
...
}

复杂全面版本:

消息映射、循环机制是Windows程序运行的基本方式。VC++ MFC 中有许多现成的消息句柄,可当我们需要完成其它的任务,需要自定义消息,就遇到了一些困难。在MFC ClassWizard中不允许添加用户自定义消息,所以我们必须在程序中添加相应代码,以便可以象处理其它消息一样处理自定义消息。通常的做法是采取以下步骤:

第一步:定义消息。

  推荐用户自定义消息至少是WM_USER+100,因为很多新控件也要使用WM_USER消息。

#define WM_MY_MESSAGE (WM_USER+100)

第二步:实现消息处理函数。

该函数使用WPRAM和LPARAM参数并返回LPESULT。

LPESULT CMainFrame::OnMyMessage(WPARAM wParam, LPARAM lParam)
{
// TODO: 处理用户自定义消息
...
return 0;
}

第三步:在类头文件的AFX_MSG块中说明消息处理函数:

class CMainFrame:public CMDIFrameWnd
{
...
// 一般消息映射函数
protected:
// {{AFX_MSG(CMainFrame)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnTimer(UINT nIDEvent);
afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
}

第四步:在用户类的消息块中,使用ON_MESSAGE宏指令将消息映射到消息处理函数中。

BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
ON_WM_CREATE()
ON_WM_TIMER()
ON_MESSAGE(WM_MY_MESSAGE, OnMyMessage)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
如果用户需要一个定义整个系统唯一的消息,可以调用SDK函数RegisterWindowMessage定义消息:

static UINT WM_MY_MESSAGE=RegisterWindowMessage("User");

  并使用ON_REGISTERED_MESSAGE宏指令取代ON_MESSAGE宏指令,其余步骤同上。

  当需要使用自定义消息时,可以在相应类中的函数中调用函数PostMessage或SendMessage发送消息PoseMessage(WM_MY_MESSAGE,O,O); 如果向其他进程发送消息可通过如下方法发送消息:

DWORD result;
SendMessageTimeout(wnd->m_hWnd, // 目标窗口
WM_MY_MESSAGE, // 消息
0, // WPARAM
0, // LPARAM
SMTO_ABORTIFHUNG |
SMTO_NORMAL,
TIMEOUT_INTERVAL,
&result);
以避免其它进程如果被阻塞而造成系统死等状态。

  可是如果需要向其它类(如主框架、子窗口、视类、对话框、状态条、工具条或其他控件等)发送消息时,上述方法显得无能为力,而在编程过程中往往需要获取其它类中的某个识别信号,MFC框架给我们造成了种种限制,但是可以通过获取某个类的指针而向这个类发送消息,而自定义消息的各种动作则在这个类中定义,这样就可以自由自在的向其它类发送消息了。
  下面举的例子叙述了向视类和框架类发送消息的方法:
  在主框架类中向视类发送消息:
  视类中定义消息:
ON_REGISTERED_MESSAGE(WM_MY_MESSAGE,OnMyMessage) //定义消息映射
视类定义消息处理函数:

// 消息处理函数
LRESULT CMessageView::OnMyMessage(WPARAM wParam, LPARAM lParam)
{
// TODO: 处理用户自定义消息
...return 0;
}
//发送消息的测试函数
void CMainFrame::OnTest()
{
CView * active = GetActiveView();//获取当前视类指针
if(active != NULL)
active->PostMessage(WM_MY_MESSAGE,0,0);
}
  在其它类中向视类发送消息:
//发送消息的测试函数
void CMainFrame::OnTest()
{
CMDIFrameWnd *pFrame;
CMDIChildWnd *pChild;
CView *pView;
//获取主窗口指针
pFrame =(CMDIFrameWnd*)AfxGetApp()->m_pMainWnd;
// 获取子窗口指针
pChild = (CMDIChildWnd *) pFrame->GetActiveFrame();
//获取视类指针
pView = pChild->GetActiveView();
if(pView != NULL)
pView->PostMessage(WM_MY_MESSAGE,0,0);//发送消息
}
  其余步骤同上。

在视类中向主框架发送消息:
  首先在主框架中定义相关的消息,方法同上,然后在发送消息的函数中添加代码如下
//发送消息的测试函数
void CMessageView::OnTest()
{
CFrameWnd * active = GetActiveFrame();//获取当前主窗口框架指针
if(active != this)
active->PostMessage(WM_MY_MESSAGE,0,0);
return 0;
}
  在其它类中向不同的类发送消息可依次方法类推,这样我们的程序就可以的不受限制向其它类和进程发送消息,而避免了种种意想不到的风险。

  下面一个例子程序为多文档程序里在一对话框中向视类发送消息,详述了发送自定义消息的具体过程。
实现步骤:
  第一步:在VC++中新建工程Message,所有ClassWizard步骤选项均为缺省,完成。
  第二步:在主菜单中添加测试菜单为调出对话框,在框架类中建立相应函数OnTest()
  第三步:在资源中建立对话框,通过ClassWizard添加新类TestDialog,添加测试按钮,
  在对话框类中建立相应函数OnDialogTest()
//通过对话框按钮发送消息的函数
void TestDialog::OnDialogTest()
{
CMDIFrameWnd *pFrame;
CMDIChildWnd *pChild;
CView *pView;
//获取主窗口指针
pFrame =(CMDIFrameWnd*)AfxGetApp()->m_pMainWnd;
// 获取子窗口指针
pChild = (CMDIChildWnd *) pFrame->GetActiveFrame();
//获取视类指针
pView = pChild->GetActiveView();
if(active != NULL)
active->PostMessage(WM_MY_MESSAGE,0,0);//发送消息
}
  在Message.h头文件中添加如下语句:
static UINT WM_MY_MESSAGE=RegisterWindowMessage("Message");

第四步:在视类中添加自定义消息:
  在头文件MessageView.h中添加消息映射
protected:
//{{AFX_MSG(CMessageView)
//}}AFX_MSG
afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam); //此行为添加代码
DECLARE_MESSAGE_MAP()
在视类文件MessageView.cpp中的消息映射中添加自定义消息映射
BEGIN_MESSAGE_MAP(CMessageView, CView)
//{{AFX_MSG_MAP(CMessageView)
//}}AFX_MSG_MAP
// Standard printing commands
ON_REGISTERED_MESSAGE(WM_MY_MESSAGE,OnMyMessage) //此行添加代码定义唯一消息
END_MESSAGE_MAP()
  添加相应的0消息处理函数
LRESULT CMessageView::OnMyMessage(WPARAM wParam, LPARAM lParam)
{
CRect rect;
GetClientRect(&rect);
InvalidateRect(&rect);
test=!test;
return 0;
}
  在MessageView.h中添加布尔变量 public:BOOL test;
  在视类构造函数中初始化 test变量:test=FALSE;
  修改CMessageView::OnDraw()函数
void CMessageView::OnDraw(CDC* pDC)
{
CMessageDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// 以下程序显示消息响应效果
if(test)
pDC->TextOut(0,0,"消息响应!");
}

第五步:显示测试对话框
  在MainFrame类中包含对话框头文件:
#include "TestDialog.h";
OnTest()函数中添加代码
void CMainFrame::OnTest()
{
TestDialog dialog;
dialog.DoModal();
}

第二:

/*
创建自定义消息程序步骤:
1:用ClassWard创建一个新project命名为:MessageTest
2:此project选单文档,取消Active X支持,取消打印支持,其它默认。finish.
3:在菜单中添加一个菜单“测试”其子菜单为"test",并映射其执行方法:OnTest
4: 制造消息发送者:在资源中新增一个对话框,并用classward为其创建类名为
TestDialog.然后在此对话框中加入一个Button,并用classward为其映射执行函数
OnButton1()。
5:在TestDialog.h文件中加入一行#define WM_MY_MESSAGE (WM_USER+100)
用来定义自己的消息
6:在TestDialog.cpp文件中加入一行:#include "MainFrm.h"
7:为对话框的Button按钮加入发送消息代码如下:
void TestDialog::OnButton1()
{
// TODO: Add your control notification handler code here
//获取当前框架指针
CMainFrame *pMainFrame=(CMainFrame *)AfxGetApp()->m_pMainWnd;
//获取当前view指针
CView *pView=pMainFrame->GetActiveView();
if(pView!=NULL)
{
pView->PostMessage(WM_MY_MESSAGE,0,0);
}
}
以上是对于消息的发送者工作己完成
8:以下是对于消息接收者
在MessageTestView.h中也要定义:#define WM_MY_MESSAGE (WM_USER+100)
9:并在MessageTestView.h中定义消息映射函数如下:
protected:
//{{AFX_MSG(CMessageTestView)
afx_msg void OnTest();
afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam); //此处为自定义消息映射函数
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
10:在MessageTestView.cpp文件中,声明消息响应函数如下:
BEGIN_MESSAGE_MAP(CMessageTestView, CView)
//{{AFX_MSG_MAP(CMessageTestView)
ON_MESSAGE(WM_MY_MESSAGE,OnMyMessage) //自定义消息响应函数
ON_COMMAND(ID_TEST, OnTest)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
11:在MessageTestView.cpp文件中实现消息响应函数如下:
LRESULT CMessageTestView::OnMyMessage(WPARAM wParam,LPARAM lParam)
{
MessageBox("OnMyMessage!Receiver");
return 0;
}
12:将消息发送者与消息响应者联系起来。即:将对话框与菜单联系起来。
实现CMessageTestView的OnTest方法如下:
void CMessageTestView::OnTest()
{
// TODO: Add your command handler code here
TestDialog dlg;
dlg.DoModal();
}

9月17日
从VC6.0到VC2008

一、_WIN32_WINNT 与 _WIN32_IE 设置冲突

    _WIN32_WINNT 与 _WIN32_IE设置不兼容会导致如下C1189致命错误:

StdAfx.cpp
c:/program files/microsoft sdks/windows/v6.0a/include/sdkddkver.h(217) : fatal error C1189: #error :  _WIN32_WINNT settings conflicts with _WIN32_IE setting

StdAfx.cpp通常是项目中第一个编译的文件,这个错误将导致编译无法继续进行。产生这个错误的原因是原因是_WIN32_WINNT的版本定义太老,老的VC代码对_WIN32_WINNT的典型设置是:

#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0400
#endif

0x0400相对于VS2008所带的Plarform SDK(在文件sdkddkver.h中)中_WIN32_IE的定义来说太老了,导致不兼容,可以将其改成0x0501或更高的版本避免这个问题,如下所示:

#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0501
#endif

也可以将这三行_WIN32_WINNT定义删除,这样就会使用Plarform SDK中的_WIN32_WINNT定义,自然就不存在不兼容问题了。不过出于对老版本VC的兼容考虑(毕竟以后可能还要使用VC6编译代码),最好这样修改:

#if _MSC_VER <= 1200 // MFC 6.0 or earlier
    #ifndef _WIN32_WINNT
    #define _WIN32_WINNT 0x0400
    #endif
#endif

二、afximpl.h文件中的语法错误

    MFC出现的时候STL还没有成为C++的标准,所以MFC使用一套自己的模版库,比如CArray、CList、CMap等等,这些类型声明都在afximpl.h文件中。原来在VC6编译器适用的模版语法可能不适用VC9,特别是当以下四个环境变量设置不兼容时,就会出现这个编译错误,大致情况如下:

e:/software/microsoft visual studio 9.0/vc/atlmfc/src/mfc/afximpl.h(625) : error C2059: syntax error : '<L_TYPE_raw>'
e:/software/microsoft visual studio 9.0/vc/atlmfc/src/mfc/afximpl.h(625) : error C2238: unexpected token(s) preceding ';'
e:/software/microsoft visual studio 9.0/vc/atlmfc/src/mfc/afximpl.h(629) : error C2059: syntax error : '<L_TYPE_raw>'
e:/software/microsoft visual studio 9.0/vc/atlmfc/src/mfc/afximpl.h(629) : error C2238: unexpected token(s) preceding ';'

合理调整stdafx.h中WINVER、_WIN32_WINNT、_WIN32_WINDOWS和_WIN32_IE的设置可以避免这个问题,将三个与Windows版本有关的环境变量设置为0x0501或更高版本,将IE版本的环境变量设置为0x0500以后的版本就可以解决这个问题。当然,考虑到与旧的VC6代码兼容,可以采用上一个问题中提到的最后一个解决办法,用_MSC_VER进行隔离。

三、 旧的CRT库和新的安全CRT库引起的C4996告警

    解决了环境变量设置不匹配导致的问题后,编译过程就真正开始了,不过首先映入眼帘的应该是成堆的C4996编译告警,对每个使用了含字符串参数的CRT库函数都会有C4996编译告警,一个典型的输出如下所示:

f:/project/...../commonfunc.cpp(280) : warning C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
e:/software/microsoft visual studio 9.0/vc/include/string.h(74) : see declaration of 'strcpy'

    MSDN online 是这样解释的:为了显著增加CRT库的安全性,许多CRT函数都有了一个更安全的新版本,新版本和旧版本的区别就是新版本函数名多了一个_s后缀。只要一个CRT函数有新的安全版本,编译器就会产生一个C4996告警,不过,出现这个告警的目的并不是说旧版本的CRT函数将淡出CRT库,告警出现只是为了提醒程序员这个函数有更安全的版本存在。一种安全的或者是被鼓励的做法是用安全版本的函数替换现有的CRT函数,不过对于一个有相当代码量的项目,替换工作量也是巨大的,这可不是用名称查找、替换就能简单解决的问题,因为许多安全版本的CRT函数参数个数也发生了变化。也可以用预处理指令消除这个告警:
#pragma warning( disable : 4996 )
或者定义 _CRT_SECURE_NO_WARNINGS 压制这个告警(在stdafx.h中define或在项目属性中设置预处理符号,PreProcessor Definitions)。

    除了C语言的CRT函数外,POSIX 兼容函数也存在这个告警,解决方法是用POSIX标准名称替换(比如access换成_access)或者是定义 _CRT_NONSTDC_NO_WARNINGS 压制这个告警(方法同上)。

四、“CWinApp::Enable3dControls”引起的C4996告警

    这个是编译使用了老的向导生成的MFC代码时遇到的问题,一个典型的告警信息输出如下所示:

CrpFileCrack.cpp
f:/project/...../crpfilecrack.cpp(52) : warning C4996: 'CWinApp::Enable3dControls': CWinApp::Enable3dControls is no longer needed. You should remove this call.
        e:/software/microsoft visual studio 9.0/vc/atlmfc/include/afxwin.h(4818) : see declaration of 'CWinApp::Enable3dControls'

通常向导生成的代码是:

#ifdef _AFXDLL
    Enable3dControls();            // Call this when using MFC in a shared DLL
#else
    Enable3dControlsStatic();    // Call this when linking to MFC statically
#endif

这两个函数的调用是旧的MFC版本对新版本的操作系统特性的支持,在新的(那个时候是新的)Windows 95平台上要这样调用一下才能使用新的Windows 3D样式的控件,否则就是老的Win 3.2样子的控件。想当初喜欢OWL就是因为感觉它的控件比较“酷”,比如那个带底纹的对话框,菱形的checkbox,还有带图标的“OK”按钮,看到MFC作出来的灰灰的界面就觉得土,不过后来就知道MFC做界面也是很漂亮的,比如我做的。。。。,再打住。对于新的MFC版本来说已经不需要再调用这两个函数了,参考前面的方法,用_MSC_VER对其隔离就行了:

#if _MSC_VER <= 1200 // MFC 6.0 or earlier
    #ifdef _AFXDLL
        Enable3dControls();            // Call this when using MFC in a shared DLL
    #else
        Enable3dControlsStatic();    // Call this when linking to MFC statically
    #endif
#endif

五、.def文件引起的连接告警

    对于普通的DLL项目中使用的.def文件通常会引起LNK4017链接告警,如下所示:

./ComFunc.def(4) : warning LNK4017: DESCRIPTION statement not supported for the target platform; ignored
   Creating library ./../Debug/ComFunc.lib and object ./../Debug/ComFunc.exp

一个典型的.def文件通常有以下内容:

LIBRARY      "XorCryptor"
DESCRIPTION  'XorCryptor Windows Dynamic Link Library'

EXPORTS
    ; Explicit exports can go here
    ..................
消除这个连接告警的方法就是从.def文件中删除DESCRIPTION描述信息,不过这个告警也不是什么大问题,不删也可以。另一个可能产生的连接告警是LNK4222,通常出现在ocx控件和com组件的项目中,一个典型输出是:

Linking...
./PlusInModule.def : warning LNK4222: exported symbol 'DllCanUnloadNow' should not be assigned an ordinal
./PlusInModule.def : warning LNK4222: exported symbol 'DllGetClassObject' should not be assigned an ordinal
./PlusInModule.def : warning LNK4222: exported symbol 'DllRegisterServer' should not be assigned an ordinal
./PlusInModule.def : warning LNK4222: exported symbol 'DllUnregisterServer' should not be assigned an ordinal

出现这个告警的原因是旧的项目的.def文件通常这样定义ocx和com必需的四个导出函数:
EXPORTS
    DllCanUnloadNow     @1 PRIVATE
    DllGetClassObject   @2 PRIVATE
    DllRegisterServer   @3 PRIVATE
    DllUnregisterServer    @4 PRIVATE

其中为这四个重要的导出函数指定了四个顺序号。Windows平台上通常用两种方式定位DLL文件中的导出函数,一种是根据导出函数名称,一种是根据顺序号,上学时曾经写过一个显示图片的程序,能处理大多数当时流行的图像格式文件,唯独jpeg格式的搞不定,有一次看到一个图像处理软件中包含了一个LoadJpeg.dll,很显然这个DLL是处理jpeg格式的图像文件的嘛,于是赶快用depends look了一下,顿时高喊:鬼啊~~~。原来这个depends竟然查不到导出函数的名字,后来才知道还有NONAME参数强制用顺序号定位导出函数,于是就常常弄个没有导出函数名字的DLL到处show。。。。嗯,又扯远了。话说为什么旧的系统要以此指定这四个导出函数的顺序号我就没有研究了,反正现在不需要指定了,只要将@1,@2之类的删除就行了,不过不删好像也没什么问题,它们会被自动忽略。

六、使用MFC的消息映射宏引起的编译错误

    错误现象之一:

f:/project/...../plusmaindlg.cpp(220) : error C2440: 'static_cast' : cannot convert from 'void (__thiscall CPlusMainDlg::* )(int,BOOL)' to 'LRESULT (__thiscall CWnd::* )(WPARAM,LPARAM)'
        None of the functions with this name in scope match the target type

    错误现象之二:
f:/project/...../crpfileopavdlg.cpp(87) : error C2440: 'static_cast' : cannot convert from 'LRESULT (__thiscall CCrpFileOpavDlg::* )(LPCTSTR,int)' to 'LRESULT (__thiscall CWnd::* )(WPARAM,LPARAM)'
        None of the functions with this name in scope match the target type

    以上两个编译错误产生是因为新旧版本的MFC 中对ON_MESSAGE消息映射宏定义不同引起的,先看看老版本的MFC的ON_MESSAGE消息宏定义:

#define ON_MESSAGE(message, memberFxn) /
    { message, 0, 0, 0, AfxSig_lwl, /
        (AFX_PMSG)(AFX_PMSGW)(LRESULT (AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM))&memberFxn },

再看看新版本的ON_MESSAGE定义:

#define ON_MESSAGE(message, memberFxn) /
    { message, 0, 0, 0, AfxSig_lwl, /
        (AFX_PMSG)(AFX_PMSGW) /
        (static_cast< LRESULT (AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM) > /
        (memberFxn)) },

注意,函数类型没有变化,都是:
LRESULT (AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM);
类型的函数指针(CWnd以及派生类的类成员函数指针),区别之处是新的ON_MESSAGE宏使用C++的 static_cast 操作符代替了C类型的强制转换。产生这两个错误其实是因为用户没有按照ON_MESSAGE宏的约定声明和定义消息响应函数造成的,比如,对于某些不需要处理返回值的消息响应函数,用户通常这样声明和定义消息响应函数:

在头文件中声明:
afx_msg void OnFileProcess(WPARAM wParam,LPARAM lParam);

在源文件中实现:
void CCrpFileOpavDlg::OnFileProcess(WPARAM wParam, LPARAM lParam)
{
.......
}

或者更过分一些,直接指定为实际参数类型:

在头文件中声明:
afx_msg void OnFileProcess(LPCTSTR lpszMessage, int nPercent);

在源文件中实现:
void CCrpFileOpavDlg::OnFileProcess(LPCTSTR lpszMessage, int nPercent)
{
.......
}

旧版本的ON_MESSAGE使用了C类型的强制转换,宏解开后的代码后不会产生错误信息,但是改成对类型检查很严格的static_cast 操作符时就出问题了,因为通不过static_cast 操作符的检查。解决方法就是修改代码,同时吸取教训,普遍使用的方法并不一定就能约定俗成,一切还是要按照规矩来。

    错误现象之三:

f:/project/...../WzButton.cpp(74) : error C2440: 'static_cast' : cannot convert from 'UINT (__thiscall CWzButton::* )(CPoint)' to 'LRESULT (__thiscall CWnd::* )(CPoint)'
        Cast from base to derived requires dynamic_cast or static_cast

    出现这个错误的原因可是“人力不可抗拒”之原因造成的,因为旧版本的 ON_WM_NCHITTEST 宏使用了
UINT (__thiscall CWzButton::* )(CPoint);
类型的类成员函数指针,其定义如下:

#define ON_WM_NCHITTEST() /
    { WM_NCHITTEST, 0, 0, 0, AfxSig_wp, /
        (AFX_PMSG)(AFX_PMSGW)(UINT (AFX_MSG_CALL CWnd::*)(CPoint))&OnNcHitTest },

但是新版本变成了:

#define ON_WM_NCHITTEST() /
    { WM_NCHITTEST, 0, 0, 0, AfxSig_l_p, /
        (AFX_PMSG)(AFX_PMSGW) /
        (static_cast< LRESULT (AFX_MSG_CALL CWnd::*)(CPoint) > (&ThisClass :: OnNcHitTest)) },

注意返回值类型由UINT改成了LRESULT,再加上static_cast的严格检查,所以就出错了。修改的方法就是将你的OnNcHitTest函数由:

afx_msg UINT OnNcHitTest(CPoint point);

改成:

afx_msg LRESULT OnNcHitTest(CPoint point);

不必太在意,这个不是你的错,不过,如果你要维护一个老的界面库(通常很多控件的subclass都会用到ON_WM_NCHITTEST),改起来还是很痛苦地,不扯了,继续下一个。

七、statreg.cpp 和 atlimpl.cpp 的废弃(obsolete)问题

    在编译老的ATL向导生成的代码时,会遇到下面的编译输出:

StdAfx.cpp
statreg.cpp is obsolete. Please remove it from your project.
atlimpl.cpp is obsolete. Please remove it from your project.

因为老的ATL向导生成的代码通常在stdafx.cpp文件中添加以下代码:

#ifdef _ATL_STATIC_REGISTRY
#include <statreg.h>
#include <statreg.cpp>
#endif

#include <atlimpl.cpp>

根据提示删除#include <statreg.cpp>和#include <atlimpl.cpp>两行代码就行了,不过更好的办法是这样改:

#ifdef _ATL_STATIC_REGISTRY
#include <statreg.h>
#if _MSC_VER <= 1200 // MFC 6.0 or earlier
#include <statreg.cpp>
#endif
#endif

#if _MSC_VER <= 1200 // MFC 6.0 or earlier
#include <atlimpl.cpp>
#endif

八、新的C++编译器不再支持默认类型的变量定义

错误现象是:

f:/project/...../WzCheckBox.cpp(464) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int

产生这个错误的原因是程序中出现了这样的代码:

const some_const_var = 10;

static some_static_bool = FALSE;

新的C++编译器严格按照C++标准,不再支持默认类型的变量定义方式,必须严格指定变量类型,如下使用:

const int some_const_var = 10;

static BOOL some_static_bool = FALSE;

九、for 语句的变量作用域问题

    考察下面的代码:

for(int i = 0; i < 120; i++)
{
    if(something_happen)
    {
         break;
    }
.............
}

if(i < 120)
{
    //something happen
}

在VC6的编译器中,这样的代码是没有问题的,因为VC6的编译器为了兼容旧的Microsoft C/C++编译器,没有严格按照C++标准执行,但是从VC7开始,VC的编译器开始遵守C++标准,所以就会出现“变量i没有定义的错误”。解决的方法也很简单,按照Jim Hyslop 和 Herb Sutter的经典对话系列的第四篇中的方法,改成如下就可以了:

int i;
for(i = 0; i < 120; i++)

十、字符串函数的返回值问题

    strchr(_tcschr)、strpbrk(_tcspbrk ??)、strrchr(_tcsrchr)和strstr(_tcsstr)这四个函数在VC6的CRT库中定义的返回值都是char *(TCHAR *),所以以前的代码通常是这样使用的:

TCHAR *cp = _tcschr( pszPath, _T('//') );
//使用*cp,可以通过cp指针修改pszPath的内容

这其实是一个“漏洞”,因为如果pszPath是const char(TCHAR) *字符串,那么就表示它不希望修改字符串的内容,但是调用strchr(_tcschr)函数后就可以通过cp指针修改其内容了,这岂不荒谬?所有在新版本的CRT库中,这几个函数的返回值都改成const char *,这就会导致上面的代码产生编译错误。建议的修改方式是改成如下方式:

const TCHAR *cp = _tcschr( pszPath, _T('//') );
//不能再通过cp指针修改pszPath的内容

但是这样修改可能对代码的影响比较大,比如下面的代码:
TCHAR buf[256]; //局部缓冲区
......
TCHAR *cp = _tcschr( buf, _T('//') );
//作为局部缓冲区(非const),希望通过cp修改buf的内容

这种情况怎么办呢?对了,C++还有个const_cast操作符,这时就可以排上用场了:

TCHAR *cp = const_char<TCHAR *>(_tcschr( buf, _T('//') ));

不过上面的方法要慎用,除非确定buf是非const的,否则最好老老实实地修改代码。

十一、类成员函数指针做为函数参数的“C3867”错误

    考察下面的代码,CWzWindowsHook类的构造函数使用一个该类的成员函数指针,这样构造对象时可以选择消息过滤的handler,可以是MouseMsgFilter,也可以是KeyboardMsgFilter:

typedef  BOOL (CWzWindowsHook::*FILTERPROC)(WPARAM wParam, LPARAM lParam);

// A hook used in customization sheet to filter keyboard/mouse events
class CWzWindowsHook
{
private:
    FILTERPROC m_pFilter;
    BOOL MouseMsgFilter(WPARAM wParam, LPARAM lParam);
    BOOL KeyboardMsgFilter(WPARAM wParam, LPARAM lParam);
public:
    CWzWindowsHook(FILTERPROC pFilter) : m_pFilter(pFilter)

旧的遗留代码存在这样的用法:

CWzWindowsHook mouseHooker(CWzWindowsHook::MouseMsgFilter);

在VC6的编译器下编译可能没有问题,但是在VC9的编译器下编译会有如下报错:

f:/project/...../WzWindowsHook.cpp(272) : error C3867: 'CWzWindowsHook::MouseMsgFilter': function call missing argument list; use '&CWzWindowsHook::MouseMsgFilter' to create a pointer to member

虽然C++从C继承来了函数名即是函数地址的语法规则,但是根据C++的标准,类成员函数的指针仍然需要一个取地址符“&”。解决方法很简单,按照提示改成如下代码即可:

CWzWindowsHook mouseHooker(&CWzWindowsHook::MouseMsgFilter);

十二、wchar_t *类型与USHORT *的转换错误

    VC6的编译器不支持wchar_t数据类型,wchar_t实际上被定义成unsigned short,VC9的编译器已经支持wchar_t为内置数据类型,但是由一个编译选项控制,这个选项默认是打开的,也就是将wchar_t作为编译器的内置数据类型。但是OLECHAR和WCHAR的定义仍然是unsigned short,在VC6的编译环境中,两者的指针都是USHORT *,相互赋值和做为函数参数传递没有问题,但是如果wchar_t作为编译器的内置数据类型,那就意味着wchar_t *与OLECHAR *或WCHAR *是两种不同类型的指针,相互赋值就会报编译错误,下面的信息就是一个典型的错误输出:

f:/project/...../shellpidl.cpp(290) : error C2664: 'MultiByteToWideChar' : cannot convert parameter 5 from 'USHORT *' to 'LPWSTR'
        Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast

解决的方法就是使用C++的reinterpret_cast操作符或使用C-style强制转换,当然也可以在项目属性设置中关闭前面提到的那个选项(这个偶美试过,不知道会不会有其它问题)。

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/orbit/archive/2008/11/28/3405309.aspx

ShockWaveFlash控件中VC2008中应用

AlignMode (读写)
语法:AlignMode As Long
说明:对齐方式(与 SAlign 属性联动)。当控件的 长宽比例与影片不一致且 WMode 不为 ExactFit 时,影片
(没有被放大的)在控件中显示的位置可用该属性调整。 该属性值由标志位组成。如图,将该属性值(二进制)中相 应的位标记为 1 就设置了相应的对齐方向。
属性值与相应的对齐方式(后面括号里是二进制数)
1:左对齐(0001)  2:右对齐(0010)  4:顶对齐
(0100)  8:底对齐(1000)
也可以组合各种对齐方式,同时将两个或以上的位标 记为 1 ,也就是将这四个基本值组合相加。比如同时左对齐 和顶对齐,属性值则设为 5(0101)。
例子 : 设置影片为右对齐 :
movie.AlignMode = 2
2.BackgroundColor(读写) 语法:BackgroundColor As Long 说明:影片的背景色(与 BGColor 联动)。以(红
× 65536 +绿× 256 +蓝)计算颜色值。红绿蓝颜色取 值范围(0-255 )。默认的影片背景色为 -1 。如果影片 设置了底色或有图片当作背景,那么看不出来该属性值的 改变会有什么影响 。
例子:将影片背景色设为蓝色 :
movie.BackgroundColor = 255
3.Base (读写)
语法:Base As String
说明:指定用于解决影片中所有相对路径的声明的基 地址。当影片与其需要的其他文件不在同一目录中的时候该 属性特别有用。如不特别指定,Base 的值默认为 ".",也就 是当前影片所在的路径。
例子 :
movie.Base = "Http://www.domain.com/pathname1/
pathname2"
4.BGColor (读写)
语法:BGColor As String
说明:影片的背景色(与 BackgroundColor 联动)。与 BackgroundColor 不同的是,BGColor 是一个六位的十六进 制数,每两位分别代表红绿蓝颜色值。如:FFEEAA 表示 红色值为 FF、绿色值为 EE 、蓝色值为 AA 。
例子:将影片背景色设为红色 :
movie.BGColor = "FF0000"
5.DeviceFont (读写)
语法:DeviceFont As Boolean
说明 : 决定是否使用影片内嵌的字体 , 默认值为 False 。将该属性值设为 True 则强制播放器不使用影片中 内嵌的字体而使用本地系统字体。
例子:movie.DeviceFont = True
6.EmbedMovie (读写)
语法:EmbedMovie As Boolean
说明:影片是否被存贮到控件所在的容器中。当你已 载入一个影片后将该属性设为 True ,播放影片时就不必再 去读 SWF 文件了。这使得在 PowerPoint 简报或 VB 程序 里使用 Flash 影片更容易。但将该属性设为 True 后,控 件的 Movie 属性就不再接受新的值了。要想播放另一个影 片(给 Movie 属性赋新值),必须先将 EmbedMovie 属 性设为 False 。
例子 :
movie.EmbedMovie = True
7.FrameNum (读写)
语法:FrameNum As Long
说明:影片当前帧的编号 (从 0 开始计数 )。设置 该属性值将使影片停在由 FrameNum 指定的帧处。
例子 : 显示当前帧数 :
MsgBox " 当前显示的是第 " & movie.FrameNum &
" 帧。"
使影片显示第 10 帧: Bomovie.FrameNum = 9
8.Loop (读写)
语法:Loop As Boolean
说明:是否循环播放。设为 True 是循环播放,设为 False 则只播放一次。
例子 :
movie.Loop = True
9.Menu (读写)
语法:Menu As Boolean
说明:是否显示菜单。设为 True 显示所有菜单,设 为 False 菜单被屏蔽,但仍有一项“About Macromedia Flash Player...”。如果你实在不喜欢这个菜单,应该在程 序中通过拦截鼠标消息的方法来达到目的。与在独立的 F l a s h 播放器中不同的是 ,在控件的右键菜单里点 
“About...”的话,将打开浏览器到 Macromedia 的网站上去 看 About 了。
例子 :
movie.Menu = False
10.Movie (读写)
语法:Movie As String
说明:要播放的影片路径(URL )。设置该属性为 一个 SWF 文件的 URL 将载入文件并播放它。若影片是在 本地硬盘上,要写成从盘符开始的绝对路径;若影片是在 某网站上,也要写全 URL 地址。
例子 :
movie.Movie = "http://www.domain.com/path1/
path2/filename.swf" 或
movie.Movie = "c:/temp/test.swf"
11.Playing (只读)
语法:Playing As Boolean
说明:当前播放状态。如果影片正在播放,该属性 值为 True ,否则为 False 。
例子 :
If movie.Playing = False Then MsgBox " 影片已停止播放! " End If
12.Quality (读写)
语法:Quality As Long
说明:画面质量(与 Quality2 联动)。Quality 可 以取:
0 ——相当于 Quality2 取 "Low"
1 ——相当于 Quality2 取 "High"
2 ——相当于 Quality2 取 "AutoLow"
3 ——相当于 Quality2 取 "AutoHigh" 例子 :
movie.Quality = 1
13.Quality2(读写)
语法:Quality As String
说明:画面质量(与 Quality 联动)。Quality2 可以取: Low :偏重于播放速度而不管显示效果,而且不启用
消锯齿功能 。
High :偏重于画面而不管播放速度,并且总是启用 消锯齿功能。如果影片中不包含动画就平滑处理位图;如 果有动画,那么位图就不被平滑处理。(这里的动画应该 是把一张图片做平移或旋转)
AutoLow :先着重于播放速度,但只要有可能就改 善显示效果。一开始播放时先禁用消锯齿功能。如果播放 器检测到处理器能承受得了 ,就启用消锯齿功能 。
AutoHigh:一开始是播放速度和显示效果并重,但 如有必要就牺牲画质确保速度。开始播放时就启用消锯齿 功能。但如果实际的帧速率比设计时指定的速率慢了,就 禁用消锯齿功能来提高播放速度。
例子 :
movie.Quality2 = "High"
14.ReadyState(只读)
语法:ReadyState As Long
说明:影片的当前状态。ReadyState 可以取:
0 ——正在载入
1 ——未初始化
2 ——已载入
3 ——正在交互
4 ——完成 例子 :
If movie.ReadyState = 4 Then
MsgBox " 影片载入完成! " End If
15.SAlign (读写)
语法:SAlign As String
说明:对齐模式(与 AlignMode 联动)。当 AlignMode
代表各对齐模式的位被置“1”时,SAlign 值也相应被设为
“L”(Left)、“T”(Top)、“R”(Right)、“B”(Bottom)各 字符的组合。(‘L’、‘T’、‘R’、‘B’的先后顺序不变)
例子:设置影片为左对齐和顶对齐:
movie.SAlign = "LT"
16.Scale (读写)
语法:scale As String
说明:缩放模式(与 ScaleMode 联动)。Scale 可以 取:
ShowAll ——在控件内显示全部影片区域,保持影片 长宽比例不变,影片的大小决定于控件长或宽中较小的一 边 。
NoBorder ——在控件内显示部分影片区域,保持影片 长宽比例不变,影片的大小决定于控件长或宽中较大的一 边 。
ExactFit ——在控件内显示全部影片区域,将影片的长 宽比例强制等于控件的长宽比例。
例子 :
MsgBox " 当前的缩放模式是:" & movie.Scale
17.ScaleMode(读写)
语法:ScaleMode As Long
说明:缩放模式(与 Scale 联动)。ScaleMode 可以取:
0 ——相当于 Scale 取 "ShowAll"
1 ——相当于 Scale 取 "NoBorder"
2 ——相当于 Scale 取 "ExactFit"
例子:使影片的缩放模式改成“ExactFit ”:
movie.ScaleMode = 2
18.Stacking (读写)
语法:Stacking As String
说明:用于 HTML,将 Flash Player 当成 HTML 中 的一种“行为”使用时,该属性决定 Flash 影片相对于与其 参照的 HTML 内容如何显示。(有关“行为”请参阅样式表 的资料)。Stacking 可以取:
none ——“行为”不显示。
replaceall ——“行为”的显示取代全部其他元素的内 容 , 包括背景 。
content ——“行为”的显示只取代其他元素的内 容。
background ——“行为”的显示只取代其他元素的背 景 。
below ——“行为”在所有其他元素内容的下面显 示。
belowflow ——“行为”以反向 Z 顺序显示在其他元素 的子对象之上 ,但在该元素主要内容之上。
aboveflow ——“行为”以正向 Z 顺序显示在其他元素 的子对象之下 ,但在该元素主要内容之上。
above ——“行为”显示在所有其他元素的内容之上。
top ——“行为”的显示置于整个页面内容之上。 例子 :
movie.Stacking = "below"
19.TotalFrames(只读)
语法:TotalFrames As Long
说明:返回影片中总帧数。该参数要到影片载入完成 才有效(ReadyState=4)。
例子 :
If movie.ReadyState = 4 Then
MsgBox " 本影片共有 " & movie.TotalFrames & " 帧。"
End If
20.WMode (读写)
语法:WMode As String
说明:控件的窗口模式。WMode 可以取: Window —— WMode 属性的默认值,按 Flash 播放器
典型的方式工作,即在控件的矩形窗口中播放影片,这样一 般都能提供最快的动画效果。
Opaque ——使影片不透明。 Transparent ——创建一个透明的影片。如果影片中有
透明的片段,放到这里时,就可以看到控件下面的背景。但 使用此属性值,动画的播放速度可能会慢一些。
例子 :
movie.WMode = "Transparent"
看完了上面的内容,你对如何获得影片的各项数据一 定非常了解了。但那些大都是静态的内容,影片终究还是要 连续地播放来看的,它动起来后,如何进行控制呢?那你还 要耐下心来看下面的方法篇。
二、方法篇
我们都知道,在独立的播放器中,我们只能从头到尾地 看,最多是中间停下来,前进一帧或后退一帧,如果有一些 地方还没看清楚就一闪而过,再想回头看那可真是麻烦透 了。片子短点的还好,大不了再放一遍,要是大文件,可真 没耐心再看一遍,那就拿着鼠标或键盘使劲敲吧。这样的设 计真让人怀疑是不是收了鼠标键盘厂商的回扣 ;-P
要超越 Flash 自带的播放器,这一点首当其冲要改进!
看完了下面的介绍,你就知道,这些控制也不是那么难。
Flash 控件还提供了更多的方法来与影片进行交互。 如果你对 Flash 的制作有深入了解的话,理解起来一定更 快,也就能做出功能更强的 Flash 影片和程序。让 Flash 真正在程序或网页中 “ 活 ” 起来 。
下面中的方法不返回值:
1.Back
语法:Back() 
说明 : 影片后退一帧 , 并且停止播放 。 例子 :
movie.Back
2.Forward
语法:Forward()
说明 : 影片前进一帧 , 并且停止播放 。 例子 :
movie.Forward
3.GotoFrame
语法:GotoFrame(FrameNum As Long) 说明:将影片跳转到由 FrameNum 指定的帧,并且
停止播放。如果所指定的帧还未载入,播放器前进到最后 的可用帧并停下,在调用过程中会产生无法预料的后果。 最好使用 PercentLoaded 方法来确定是否已载入足够的影片 来执行本方法。参数 FrameNum 是从 0 开始的,这和 Flash 中的 Goto 动作不一样,它是从 1 开始的。
例子:跳转到影片的第 20 帧:
movie.GotoFrame 20
4.LoadMovie
语法:LoadMovie(layer As Long, url As String) 说明:将由 url 指定的影片载入到由 layer 指定的层上。 例子:将 movie.swf 载入至 0 层:
movie.LoadMovie 0, "movie.swf"
5.Pan
语法:Pan(x As Long, y As Long, mode As Long) 说明:将一个放大过的影片平移由 x 和 y 指定的距离。
x 和 y 均为相对值。即控件相对于影片来说平移的距离(你 可以想象控件是一个窗户,影片是我们从窗户里看到的放 在外面的布景, 我们看到窗户相对于布景平移了一些距离, 那是外面的布景在动,而窗户是不动的)。用 mode 参数 来指定 x 和 y 的值是像素还是窗口的百分比,当 mode=0 时 坐标系以像素为单位;mode=1 时坐标系就以窗口的百分 比来计算。   平移并不能超出影片的边框,也就是说,往 一个方向平移最多到达影片的边缘与控件对齐的程度。
例子:控件相对于影片向左向上各平移 5 个像素(当 然控件不会动 ,是影片向右向下平移了 ):
movie.Pan 5,5,0
6.Play
语法:Play()
说明: 开始播放影片。 例子:
movie.Play
7.Rewind
语法:Rewind()
说明: 倒带。返回到影片的第一帧 。 例子:
movie.Rewind
8.SetVariable
语法:SetVariable(name As String, value As String) 说明:将由 name 指定的 Flash 变量值设为 value。 例子:movie.SetVariable "/Form:UserName", "John Smith"

VS2005 C++ str.Format 编译错误error C2664解决方法

郁闷了半天才找到。
int i =  sizeof(_T(""));
str.Format("%d",i);

error C2664: 'void ATL::CStringT<BaseType,StringTraits>::Format(const wchar_t *,...)' : cannot convert parameter 1 from 'const char [3]' to 'const wchar_t *'

改为,加L即可

str.Format(L"%d",i);
结果弹出i为2.

更改CDialogBar的背景颜色

BOOL   CDialogBarMy::OnEraseBkgnd(CDC*   pDC)    
  {  
          CBrush   brush(RGB(255,0,0));  
          CRect   rectClient;  
          GetClientRect   (rectClient);  
          pDC->FillRect   (rectClient,   &brush);  
          return   TRUE;  
  }  

VC++界面编程总结(二)

1."属性页的添加:
创建对话框的类,该类要从CpropertyPage继承;然后在要添加该对话框为属性页的类(头文件)里创建CpropertySheet类的一个对象m_tabsheet和新创建的对话框类的对象m_skatch;最后,在.cpp文件里的OnInitDialog()之类的函数里实现如下代码:
m_tabsheet.Create(this, WS_CHILD | WS_VISIBLE, 0);
"//使选项卡的按钮在下面
"if(m_tabsheet.m_hWnd)
"m_tabsheet.ShowWindow(SW_MAXIMIZE);//显示选项卡
//加入标签,标签名由各个子对话框的标题栏决定
"m_tabsheet.AddPage(&m_skatch);
"//用Create来创建一个属性页
"m_tabsheet.Create(this, WS_CHILD | WS_VISIBLE, WS_EX_CONTROLPARENT);
"
RECT rect;
"m_tabsheet.GetWindowRect(&rect);
"int width = rect.right - rect.left;
"int height = rect.bottom - rect.top;
"
"//调整属性页的大小和位置
"m_tabsheet.SetWindowPos(NULL, 225, 225, width-82, height,SWP_NOACTIVATE);
属性页的添加完成。如果要添加多个属性页,则只需要增加多个对象,如下:m_tabsheet.AddPage(&m_skatch1);
  m_tabsheet.AddPage(&m_skatch2);
. . . . . .
2."List Control中标题栏(Column)的添加:
创建一个List Control,其ID为IDC_LIST,在其Styles属性项下的View项里选择Report、Align项里选择Top、Sort项里选择None.
然后在该List所在对话框的类(头文件)里创建ClistCtrl的一个对象m_list然后在.cpp文件的OnInitDialog()之类的函数里实现如下代码:
CString strname[3];
strname[0]="Screen Name";
strname[1]="Form ID";
strname[2]="Category Path";
for(int i=0;i<3;i++)
{
m_List.InsertColumn(i,strname[i],LVCFMT_LEFT,130);
}
在这之前也要将List Control的ID与ClistCtrl的对象m_list在DoDataExchange(CDataExchange* pDX)函数里绑定,如下:
DDX_Control(pDX, IDC_LIST, m_List);
3."ToolBar和StatusBar中控件的添加:
方法⑴.只能在ToolBar里创建控件:首先,在ToolBar中创建一个Button,其ID为ID_TOOL_COMBO(我们要将创建的控件放在该Button的位置上).
其次,新创建一个类CMainToolBar,要从CToolBar继承(创建过程大概如下:选择工程/增加到工程/新的类;也可以选择工程的根,然后点击右键,选择新的类;或者CTL+W,选择增加类/新的类 --- 然后在class type里选择Generic Class,在Name栏里输入新类的名字,Base class里输入CToolBar),创建成功后在该类里创建要增加的控件的对象,如:
CComboBox""m_wndMyCombo;
CStatic""m_wndCategory, m_wndCategoryPath;
CButton""m_wndOpenButton;
Cedit"""m_wndEdit;
然后在构造函数里初始化如:
m_wndMyCombo.m_hWnd = NULL;
m_wndCategory.m_hWnd = NULL;
m_wndCategoryPath.m_hWnd = NULL;
m_wndOpenButton.m_hWnd = NULL;
m_wndEdit.m_hWnd = NULL;
接着在CMainframe的头文件里创建CMainToolBar的一个对象m_wndToolBar,最后在.cpp文件的OnCreate函数的最后实现如下:
"int index = 0;
"CRect rect;  // 可定义在头文件当中
"// ComboBox
"{
""//找到指定的工具项
""while(m_wndToolBar.GetItemID(index)!=ID_TOOL_COMBO)
"""index++;
""//设置指定工具项的宽度并获取新的区域 120是宽度
""m_wndToolBar.SetButtonInfo(index, ID_TOOL_COMBO, TBBS_SEPARATOR, 120);
""m_wndToolBar.GetItemRect(index, &rect);
""
""//设置位置
""rect.top+=1;
""rect.bottom += 200;
""
""// 创建并显示控件
""if(!m_wndToolBar.m_wndMyCombo.Create(WS_CHILD|WS_VISIBLE| CBS_AUTOHSCROLL|
"""CBS_DROPDOWNLIST | CBS_HASSTRINGS , rect, &m_wndToolBar, ID_TOOL_COMBO))
""{ 
"""TRACE0("Failed to create combo-box/n");
"""return FALSE;
""}
""m_wndToolBar.m_wndMyCombo.ShowWindow(SW_SHOW);
""
""//填充内容"
""m_wndToolBar.m_wndMyCombo.AddString("25%");
""m_wndToolBar.m_wndMyCombo.AddString("50%");
""m_wndToolBar.m_wndMyCombo.AddString("75%");
"
""//选择默认项
""m_wndToolBar.m_wndMyCombo.SetCurSel(0);
""
""//获取到内容并MSGBOX显示出来
""CString strContent;
""m_wndToolBar.m_wndMyCombo.GetWindowText(strContent);
""index = 0;
"}
其他控件都类似创建(只需要注意一下各自的Create函数的参数即可)。
方法⑵.这种方法创建不太容易控制:直接在CMainframe的头文件中创建要增加的控件的对象,如CButton"的对象m_wndAboutButton,然后创建CToolBar或者CstatusBar的对象,如:CstatusBar的对象_wndStatusBar;再增加几个函数如下:
Protected:
virtual void RecalcLayout(BOOL bNotify = TRUE);
"afx_msg void CMainFrame::OnViewStatusBar();
接着在.cpp文件中将StatusBar的ID和OnViewStatusBar 函数绑定在一起,如下所示:BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
"  // {{AFX_MSG_MAP(CMainFrame)
"  ON_COMMAND(ID_VIEW_STATUS_BAR, OnViewStatusBar)
"  ON_WM_CREATE()
"  // }}AFX_MSG_MAP
END_MESSAGE_MAP()
然后Create函数的最后(返回值之前)实现如下代码:
CRect rc;
"VERIFY(m_wndAboutButton.Create(_T("MyAbout"),
""  WS_VISIBLE,rc,this,ID_APP_ABOUT));
"// TODO: Remove this if you don't want tool tips or a resizeable toolbar
"m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() |
"CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);
再在RecalcLayout函数里实现:
CRect rc;
if (m_wndStatusBar.m_hWnd)
{
""m_wndStatusBar.GetWindowRect(&rc);
""ScreenToClient(&rc);
""rc.right -= 50;
""m_wndStatusBar.SetWindowPos(NULL,rc.left,rc.top,rc.Width(),rc.Height(),
"""SWP_NOZORDER);
""rc.left = rc.right;
""rc.right += 50;
""m_wndAboutButton.SetWindowPos(NULL,rc.left,rc.top,rc.Width(),rc.Height(),
"""SWP_NOZORDER);
"}
最后在OnViewStatusBar()里实现:
BOOL bShow = m_wndStatusBar.GetStyle() & WS_VISIBLE;
"m_wndAboutButton.SetWindowPos(NULL, 0, 0, 0, 0,
SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|
(bShow ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
ToolBar中的创建与此相同,只需更改一下句柄即可。
4."通过Control创建的控件,对其属性的动态控制:
在对话框类的头文件里创建所要改变属性的控件的对象,如要改变一个Button(其ID为IDC_MyButton)的属性,则需创建Cbutton的对象m_button。然后在.cpp中的DoDataExchange函数里将Button的ID和创建的对象绑定在一起:
//{{AFX_DATA_MAP(CPrintDlg)
""// NOTE: the ClassWizard will add DDX and DDV calls here
"DDX_Control(pDX, IDC_MyButton, m_button);
"//}}AFX_DATA_MAP
然后可以在该函数的最后进行初始化:
"m_button.EnableWindow(FALSE);
到这里已经实现了改变属性。如果要动态改变其属性,可如下实现(通过两个Button的点击改变起属性):
// RadioAll Button的点击响应函数
void CPrintDlg::OnRadioAll()
{
""// TODO: Add your control notification handler code here
""m_button.EnableWindow(TRUE);
}
// RadioSelect Button的点击响应函数
void CPrintDlg::OnRadioSelect()
{
""// TODO: Add your control notification handler code here
""m_button.EnableWindow(FALSE);
}
也可以通过一个Check Button的点击来改变,在其点击响应函数里实现:
m_button.EnableWindow(!m_button.IsWindowEnabled());
其余控件属性的改变都如此。
5."窗口的分割与停靠:                        
一、新建一个类CMySplitter,基类为CSplitterWnd
二、重载该类的OnMouseMove函数:
void CMySplitter::OnMouseMove(UINT nFlags, CPoint point)
{
"// 限制切分条的运动范围。
"if(point.x<228||point.x>600)
"{
""CWnd::OnMouseMove(nFlags, point);
"}
"else
"{
""CSplitterWnd::OnMouseMove(nFlags, point);
"}
}
三、 然后就可以跟一般的窗口分割那样去做了,if(point.x<228||point.x>600)这里的范围可以随你去设置了 ^_^,够简单吧。
四、切分窗口
在MaiFram.h建立切分条对象:
protected:
CMySplitter m_wndSplitter; //切分窗口对象
//在MaiFram.cpp中实现窗口切分:
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/,CCreateContext* pContext)
{
"// 创建拆分器窗口
if (!m_wndSplitter.CreateStatic(this, 1, 2))
""return FALSE;
if (!m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CLeftView),CSize(228,100), pContext) ||!m_wndSplitter.CreateView(0,1, RUNTIME_CLASS(CDataEditView), CSize(100, 100), pContext))
"{
""m_wndSplitter.DestroyWindow();
""return FALSE;
"}
"return TRUE;
}
6. ①怎样在程序开始的时候让它最大化?
②vc++做出来的exe文件在窗体的右上方是没有最大化和最小化按钮的,怎样实现这一功能?
③如何在显示窗口时,使最大化按钮变灰?
①在App类里的C…App::InitInstance()中把m_pMainWnd->ShowWindow(SW_SHOW)改成m_pMainWnd->ShowWindow(SW_MAXIMIZE);
②在CreateWidnow时用WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX 风格.
  ③ 第一种方法:
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
// disable the maxmini box
cs.style &= ~WS_MAXIMIZEBOX;
return TRUE;
}
第二种方法:
CMenu *pMenu=AfxGetApp()->m_pMainWnd->GetSystemMenu(FALSE);
  int x=pMenu->GetMenuItemCount( );
  UINT pID=pMenu->GetMenuItemID(x-1);
  pMenu->EnableMenuItem(pID, MF_DISABLED);
第三种方法:
ModifyStyle(WS_MAXIMIZEBOX, 0);
这个函数也可以是最大化按钮失效!
并且可以在程序中动态的改变窗口的风格
7. 更改属性页标题
void CProSheet::SetPageTitle(int nPage, int nImage, CString strTitle)
{
 TC_ITEM item;
 //item.mask = TCIF_TEXT|TCIF_IMAGE;  //设置图标+文字
 item.mask = TCIF_IMAGE;    //只设置图标
 item.iImage = nImage;
// item.pszText = strTitle.GetBuffer(0);  //设置文字
 GetTabControl ()->SetItem (nPage, &item);
//要设置文字时就将上面2行有注释符的代码前的注释符去掉
}
8. 创建动态菜单
void CMainFrame::OnSelectState(NMTOOLBAR* pnmtb, LRESULT *plr)
{
"CMenu menu;
"if(!menu.CreateMenu())
"return;
"menu.AppendMenu(MF_STRING,0,"开始");
"menu.AppendMenu(MF_STRING,0,"结束");
"CRect rc;
"m_wndToolBar.SendMessage(TB_GETRECT, pnmtb->iItem, (LPARAM)&rc); 
"m_wndToolBar.ClientToScreen(&rc);
"menu.TrackMenu( TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_VERTICAL,
"""rc.left, rc.bottom, this, &rc);
//"menu.DestroyMenu();
"menu.detach();
}
9.关于打印
1.要打印哪个视就
((CMainFrame*)AfxGetMainWnd())->m_wndSplitter.SetActivePane(...)
//要打印的那个视对应的Pane
2.有一个单文档工程,文档窗口被切分:左视图由CTreeView 的派生类管理,右视图由CListView 的派生类CMyListView(其为风格为LVS_REPORT)管理,我想为右视图添加打印和打印预览,我在MyListView.cpp中添加了
  ON_COMMAND(ID_FILE_PRINT,CListView::OnFilePrint)
  ON_COMMAND(ID_FILE_PRINT_PREVIEW,CListView::OnFilePrintPreview)还有
  BOOL CMyListView::OnPreparePrinting(CPrintInfo* pInfo)
  {
  // TODO: call DoPreparePrinting to invoke the Print dialog box
  // return CListView::OnPreparePrinting(pInfo);
  pInfo->SetMaxPage(2);
  BOOL bret=DoPreparePrinting(pInfo);
  pInfo->m_nNumPreviewPages=2;
  return bret;
  }
3. 下面是从MSDN中摘出来的一段,是用来改变消息路由的。用了这段代码之后,CView中的消息(菜单,控件,子窗口)将先被CMyShape类来处理。不知道你要的是不是这样的效果。
  // This example illustrates extending the framework's standard command
  // route from the view to objects managed by the view. This example
  // is from an object-oriented drawing application, similar to the
  // DRAWCLI sample application, which draws and edits "shapes".
  BOOL CMyView::OnCmdMsg(UINT nID, int nCode, void* pExtra,
  AFX_CMDHANDLERINFO* pHandlerInfo)
  {
  // Extend the framework's command route from the view to
  // the application-specific CMyShape that is currently selected
  // in the view. m_pActiveShape is NULL if no shape object
  // is currently selected in the view.
  if ((m_pActiveShape != NULL)
        && m_pActiveShape->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
  return TRUE;
  // If the object(s) in the extended command route don't handle
      // the command, then let the base class OnCmdMsg handle it.
      return CView::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
     }
     // The command handler for ID_SHAPE_COLOR (menu command to change
     // the color of the currently selected shape) was added to
     // the message map of CMyShape (note, not CMyView) using ClassWizard. 
     // The menu item will be automatically enabled or disabled, depending
     // on whether a CMyShape is currently selected in the view, that is,
     // depending on whether CMyView::m_pActiveView is NULL. It is not
     // necessary to implement an ON_UPDATE_COMMAND_UI handler to enable
     // or disable the menu item. 
   BEGIN_MESSAGE_MAP(CMyShape, CCmdTarget)
  //{{AFX_MSG_MAP(CMyShape)
  ON_COMMAND(ID_SHAPE_COLOR, OnShapeColor)
  //}}AFX_MSG_MAP
   END_MESSAGE_MAP()
如果你只是想调用OnFilePrint( )函数,可以试一试下面的代码,就和调用其它类中的函数一样。
CMDIFrameWnd *pFrame =
  (CMDIFrameWnd*)AfxGetApp()->m_pMainWnd;
// Get the active MDI child window.
CMDIChildWnd *pChild =
  (CMDIChildWnd *) pFrame->GetActiveFrame();
// or CMDIChildWnd *pChild = pFrame->MDIGetActive();
// Get the active view attached to the active MDI child
// window.
CMyView *pView = (CMyView *) pChild->GetActiveView();
pView->OnFilePrint( );
4.
void CMyReportView::OnFileOpen()
{
char Filter[] = "Crystal Report files(*.rpt)|*.rpt|All files(*.*)|*.*||";
CRect rect;
CFileDialog OpenDlg(TRUE,0,0,OFN_HIDEREADONLY|OFN_FILEMUSTEXIST,(LPCTSTR)Filter,NULL);
if(OpenDlg.DoModal()!=IDOK) ///显示文件对话框
return;
CString m_fName=OpenDlg.GetPathName(); ///取得文件名
if(m_CrystalReport)
m_CrystalReport.DestroyWindow();
GetClientRect(rect);
///创建控件///
if (!m_CrystalReport.Create(AfxRegisterWndClass(0, AfxGetApp()->LoadStandardCursor(IDC_ARROW)),WS_CHILD|WS_VISIBLE,rect,this,IDC_CRYSTALREPORT1))
{
AfxMessageBox("控件创建失败!");
return ;
}
m_CrystalReport.SetWindowParentHandle((long)(this->m_hWnd));///设置父窗口
m_CrystalReport.SetWindowBorderStyle(0); ///设置为没有边框
m_CrystalReport.SetWindowLeft(0); ///左空间
m_CrystalReport.SetWindowTop(0); ///顶部空间
m_CrystalReport.SetWindowControls(FALSE); ///不显示工具条
m_CrystalReport.SetReportFileName(m_fName); ///设置报表文件
m_CrystalReport.SetWindowWidth(rect.Width()); ///设置窗口宽度
m_CrystalReport.SetWindowHeight(rect.Height()); ///设置窗口高度
m_CrystalReport.SetFormulas(0, "Company=/"VC知识库/""); ///将报表中的Company变量的值设置为VC知识库
m_CrystalReport.SetDestination(0); ///设置输出对象是屏幕
m_CrystalReport.PrintReport(); ///显示报表
}
void CMyReportView::OnFilePrint()
{
if(m_CrystalReport && m_CrystalReport.GetReportFileName() != "")
{
m_CrystalReport.SetDestination(1); ///设置输出对象是打印机
m_CrystalReport.PrintReport(); ///打印
}
10. Scroll
创建一个基于CScrollview的SDI Project(在第6步中选CScrollview)
若你已创建了,这步可以省略。
然后:
改为如
void CTestView::OnInitialUpdate()
{
CScrollView::OnInitialUpdate();
CSize sizeTotal;
// TODO: calculate the total size of this view
sizeTotal.cx = 1024; //改这两个
sizeTotal.cy = 768;  //
SetScrollSizes(MM_TEXT, sizeTotal);
}

11. 修改主窗口风格
AppWizard生成的应用程序框架的主窗口具有缺省的窗口风格,比如在窗口标题条中自动添加文档名、窗口是叠加型的、可改变窗口大小等。要修改窗口的缺省风格,需要重载CWnd::PreCreateWindow(CREATESTRUCT& cs)函数,并在其中修改CREATESTRUCT型参数cs。
CWnd::PreCreateWindow 函数先于窗口创建函数执行。如果该函数被重载,则窗口创建函数将使用CWnd::PreCreateWindow 函数返回的CREATESTRUCT cs参数所定义的窗口风格来创建窗口;否则使用预定义的窗口风格。
CREATESTRUCT结构定义了创建函数创建窗口所用的初始参数,其定义如下:
typedef struct tagCREATESTRUCT {
LPVOID lpCreateParams; // 创建窗口的基本参数
HANDLE hInstance; // 拥有将创建的窗口的模块实例句柄
HMENU hMenu; // 新窗口的菜单句柄
HWND hwndParent; // 新窗口的父窗口句柄
int cy; // 新窗口的高度
int cx; // 新窗口的宽度
int y; // 新窗口的左上角Y坐标
int x; // 新窗口的左上角X坐标
LONG style; // 新窗口的风格
LPCSTR lpszName; // 新窗口的名称
LPCSTR lpszClass; // 新窗口的窗口类名
DWORD dwExStyle; // 新窗口的扩展参数
} CREATESTRUCT;
CREATESTRUCT结构的style域定义了窗口的风格。比如,缺省的MDI主窗口的风格中就包括FWS_ADDTOTITLE(在标题条中显示当前的工作文档名)、FWS_PREFIXTITLE(把文档名放在程序标题的前面)、WS_THICKFRAME(窗口具有可缩放的边框)等风格。由于多种风格参数由逻辑或(“|”)组合在一起的,因此添加某种风格,就只需用“|”把对应的参数加到CREATESTRUCT结构的style域中;删除已有的风格,则需用“&”连接CREATESTRUCT结构的style域与该风格的逻辑非值。
CREATESTRUCT结构的x、y、cx、cy域分别定义了窗口的初始位置和大小,因此,在CWnd::PreCreateWindow 函数中给它们赋值,将能定义窗口的初始显示位置和大小。
下例中的代码将主框窗口的大小将固定为1/4屏幕,标题条中仅显示窗口名,不显示文档名。
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
// 修改主窗风格
cs.style &= ~FWS_ADDTOTITLE; //去除标题条中的文档名
cs.style &= ~WS_THICKFRAME; //去除可改变大小的边框
cs.style |= WS_DLGFRAME; //增加不能改变大小的边框
// 确定主窗的大小和初始位置
int cxScreen = ::GetSystemMetrics(SM_CXSCREEN);//获得屏幕宽
int cyScreen = ::GetSystemMetrics(SM_CYSCREEN); //获得屏幕高
cs.x = 0; // 主窗位于左上角
cs.y = 0;
cs.cx = cxScreen/2; // 主窗宽为1/2屏幕宽
cs.cy = cxScreen/2; // 主窗高为1/2屏幕高
return CMDIFrameWnd::PreCreateWindow(cs);
}
12. 控制滚动条
BOOL CDiagramShowView::PreTranslateMessage(MSG* pMsg)
{
"CFileTreeDoc* pDoc = (CFileTreeDoc*)GetDocument();
"CPoint point = GetScrollPosition();
"
"if(pMsg->message == WM_KEYDOWN)
"{
""switch(pMsg->wParam)
""{
""case VK_LEFT:
"""if( point.x > 10)
"""{
""""EndPoint.x = EndPoint.x - 10;
""""EndPoint.y = EndPoint.y;
"""}
"""else
"""{
""""EndPoint.x = 0;
""""EndPoint.y = EndPoint.y;
"""}
"""ScrollToPosition(EndPoint);
"""InvalidateRect(NULL,TRUE);
"""break;
""case VK_RIGHT:
"""if( point.x < pDoc->intDiagramColumnCount * pDoc->intColumnWidth - 10 )
"""{
""""EndPoint.x = EndPoint.x + 10;
""""EndPoint.y = EndPoint.y;
"""}
"""else
"""{
""""EndPoint.y = pDoc->intDiagramColumnCount * pDoc->intColumnWidth;
""""EndPoint.x = EndPoint.x;
"""}
"""ScrollToPosition(EndPoint);
"""InvalidateRect(NULL,TRUE);
"""break;
""case VK_UP:
"""if( point.y > 10)
"""{
""""EndPoint.y = EndPoint.y - 10;
""""EndPoint.x = EndPoint.x;
"""}
"""else
"""{
""""EndPoint.y = 0;
""""EndPoint.x = EndPoint.x;
"""}
"""ScrollToPosition(EndPoint);
"""InvalidateRect(NULL,TRUE);
"""break;
""case VK_DOWN:
"""if( point.y < pDoc->intDiagramRowCount * pDoc->intRowHeight - 10 )
"""{
""""EndPoint.y = EndPoint.y + 10;
""""EndPoint.x = EndPoint.x;
"""}
"""else
"""{
""""EndPoint.y = pDoc->intDiagramRowCount * pDoc->intRowHeight;
""""EndPoint.x = EndPoint.x;
"""}
"""ScrollToPosition(EndPoint);
"""InvalidateRect(NULL,TRUE);
"""break;
""default:
"""break;
""}
"}
"return FALSE;
}
// 通过正负号判断是向上还是向下滚动
if(zDelta==120) 
向上滚动
if(zDelta==-120)
向下滚动
BOOL CDiagramShowView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
"CFileTreeDoc* pDoc = (CFileTreeDoc*)GetDocument();
"CPoint point = GetScrollPosition();
"
"if(zDelta==120)
"{
""if( point.y >= 20 )
""{
"""EndPoint.x = point.x;
"""EndPoint.y = point.y;
"""
"""EndPoint.x = EndPoint.x;
"""EndPoint.y = EndPoint.y - 20;
""}
""else
""{
"""EndPoint.x = EndPoint.x;
"""EndPoint.y = 0;
""}
"}
"
"if(zDelta==-120)
"{
""if( point.y <= pDoc->intDiagramRowCount * pDoc->intRowHeight - 20 )
""{
"""EndPoint.x = point.x;
"""EndPoint.y = point.y;
"""
"""EndPoint.x = EndPoint.x;
"""EndPoint.y = EndPoint.y + 20;
""}
""else
""{
"""EndPoint.x = EndPoint.x;
"""EndPoint.y = EndPoint.y;
""}
"}
"
"ScrollToPosition(EndPoint);
"InvalidateRect(NULL,TRUE);
"return CScrollView::OnMouseWheel(nFlags, zDelta, pt);
}
13. 属性页处理通知消息
CPropertyPageImpl有一个消息映射处理WM_NOTIFY。如果通知代码是PSN_*的值,OnNotify()就会调用相应的通知处理函数。这使用了编译阶段虚函数机制,从而使得派生类可以很容易的重载这些处理函数。
由于WTL 3和WTL 7设计的改变,从而存在两套不同的通知处理机制。在WTL 3中通知处理函数返回的值与PSN_*消息的返回值不同,例如,WTL 3是这样处理PSN_WIZFINISH的:
case PSN_WIZFINISH:
lResult = !pT->OnWizardFinish();
break;
OnWizardFinish()期望返回TRUE结束向导,FALSE阻止关闭向导。这个方法很简陋,但是IE5的通用控件对PSN_WIZFINISH处理的返回值添加了新解释,他返回需要获得焦点的窗口的句柄。WTL 3的程序将不能使用这个特性,因为它对所有非0的返回值都做相同的处理。
在WTL 7中,OnNotify() 没有改变 PSN_* 消息的返回值,处理函数返回任何文档中规定的合法数值和正确的行为。当然,为了向前兼容,WTL 3 仍然使用当前默认的工作方式,要使用WTL 7的消息处理方式,你必须在中including atldlgs.h一行之前添加一行定义:
#define _WTL_NEW_PAGE_NOTIFY_HANDLERS
编写新的代码没有理由不使用WTL 7的消息处理函数,所以这里就不介绍WTL 3的消息处理方式。
CPropertyPageImpl 为所有消息提供了默认的通知消息处理函数,你可以重载与你的程序有关的消息处理函数完成特殊的操作。默认的消息处理函数和相应的行为如下:
int OnSetActive() - 允许页面成为激活状态
BOOL OnKillActive() - 允许页面成为非激活状态
int OnApply() - 返回 PSNRET_NOERROR 表示应用操作成功完成
void OnReset() - 无相应的动作
BOOL OnQueryCancel() - 允许取消操作
int OnWizardBack() - 返回到前一个页面
int OnWizardNext() - 进行到下一个页面
INT_PTR OnWizardFinish() - 允许向导结束
void OnHelp() - 无相应的动作
BOOL OnGetObject(LPNMOBJECTNOTIFY lpObjectNotify) - 无相应的动作
int OnTranslateAccelerator(LPMSG lpMsg) - 返回 PSNRET_NOERROR 表示消息没有被处理
HWND OnQueryInitialFocus(HWND hWndFocus) - 返回 NULL 表示将按Tab Order顺序的第一个控件设为焦点状态
14.使工具条上的按钮点击一次为按下,再点击才弹起
bCheck=m_RtfEditToolBar.GetToolBarCtrl().IsButtonChecked(ID_TB_BOLD);
m_RtfEditToolBar.GetToolBarCtrl().CheckButton(ID_TB_BOLD, !bCheck);
15. VC中基于 Windows 的精确定时
在工业生产控制系统中,有许多需要定时完成的操作,如定时显示当前时间,定时刷新屏幕上的进度条,上位 机定时向下位机发送命令和传送数据等。特别是在对控制性能要求较高的实时控制系统和数据采集系统中,就更需要精确定时操作。
  众所周知,Windows 是基于消息机制的系统,任何事件的执行都是通过发送和接收消息来完成的。 这样就带来了一些问题,如一旦计算机的CPU被某个进程占用,或系统资源紧张时,发送到消息队列 中的消息就暂时被挂起,得不到实时处理。因此,不能简单地通过Windows消息引发一个对定时要求 严格的事件。另外,由于在Windows中已经封装了计算机底层硬件的访问,所以,要想通过直接利用 访问硬件来完成精确定时,也比较困难。所以在实际应用时,应针对具体定时精度的要求,采取相适 应的定时方法。
  VC中提供了很多关于时间操作的函数,利用它们控制程序能够精确地完成定时和计时操作。本文详细介绍了 VC中基于Windows的精确定时的七种方式.
  方式一:VC中的WM_TIMER消息映射能进行简单的时间控制。首先调用函数SetTimer()设置定时 间隔,如SetTimer(0,200,NULL)即为设置200ms的时间间隔。然后在应用程序中增加定时响应函数 OnTimer(),并在该函数中添加响应的处理语句,用来完成到达定时时间的操作。这种定时方法非常 简单,可以实现一定的定时功能,但其定时功能如同Sleep()函数的延时功能一样,精度非常低,最小 计时精度仅为30ms,CPU占用低,且定时器消息在多任务操作系统中的优先级很低,不能得到及时响 应,往往不能满足实时控制环境下的应用。只可以用来实现诸如位图的动态显示等对定时精度要求不高的情况。如示例工程中的Timer1。
  方式二:VC中使用sleep()函数实现延时,它的单位是ms,如延时2秒,用sleep(2000)。精度非常 低,最小计时精度仅为30ms,用sleep函数的不利处在于延时期间不能处理其他的消息,如果时间太 长,就好象死机一样,CPU占用率非常高,只能用于要求不高的延时程序中。如示例工程中的Timer2。
  方式三:利用COleDateTime类和COleDateTimeSpan类结合WINDOWS的消息处理过程来实现秒级延时。如示例工程中的Timer3和Timer3_1。以下是实现2秒的延时代码:
   COleDateTime   start_time = COleDateTime::GetCurrentTime();
   COleDateTimeSpan end_time= COleDateTime::GetCurrentTime()-start_time;
   while(end_time.GetTotalSeconds()< 2) //实现延时2秒
  {
       MSG  msg;
       GetMessage(&msg,NULL,0,0);
       TranslateMessage(&msg);
       DispatchMessage(&msg);
  //以上四行是实现在延时或定时期间能处理其他的消息,
  //虽然这样可以降低CPU的占有率,
  //但降低了延时或定时精度,实际应用中可以去掉。
  end_time = COleDateTime::GetCurrentTime()-start_time;
   }//这样在延时的时候我们也能够处理其他的消息。   
  方式四:在精度要求较高的情况下,VC中可以利用GetTickCount()函数,该函数的返回值是 DWORD型,表示以ms为单位的计算机启动后经历的时间间隔。精度比WM_TIMER消息映射高,在较 短的定时中其计时误差为15ms,在较长的定时中其计时误差较低,如果定时时间太长,就好象死机一样,CPU占用率非常高,只能用于要求不高的延时程序中。如示例工程中的Timer4和Timer4_1。下列代码可以实现50ms的精确定时:
  DWORD dwStart = GetTickCount();
  DWORD dwEnd  = dwStart;
  do
  {
     dwEnd = GetTickCount()-dwStart;
  }while(dwEnd <50);
为使GetTickCount()函数在延时或定时期间能处理其他的消息,可以把代码改为:
  DWORD dwStart = GetTickCount();
  DWORD dwEnd  = dwStart;
  do
  {
       MSG  msg;
       GetMessage(&msg,NULL,0,0);
       TranslateMessage(&msg);
       DispatchMessage(&msg);
       dwEnd = GetTickCount()-dwStart;
  }while(dwEnd <50);
虽然这样可以降低CPU的占有率,并在延时或定时期间也能处理其他的消息,但降低了延时或定时精度。
  方式五:与GetTickCount()函数类似的多媒体定时器函数DWORD timeGetTime(void),该函数定时精 度为ms级,返回从Windows启动开始经过的毫秒数。微软公司在其多媒体Windows中提供了精确定时器的底 层API持,利用多媒体定时器可以很精确地读出系统的当前时间,并且能在非常精确的时间间隔内完成一 个事件、函数或过程的调用。不同之处在于调用DWORD timeGetTime(void) 函数之前必须将 Winmm.lib 和 Mmsystem.h 添加到工程中,否则在编译时提示DWORD timeGetTime(void)函数未定义。由于使用该 函数是通过查询的方式进行定时控制的,所以,应该建立定时循环来进行定时事件的控制。如示例工程中的Timer5和Timer5_1。
  方式六:使用多媒体定时器timeSetEvent()函数,该函数定时精度为ms级。利用该函数可以实现周期性的函数调用。如示例工程中的Timer6和Timer6_1。函数的原型如下:
  MMRESULT timeSetEvent( UINT uDelay,
  UINT uResolution,
  LPTIMECALLBACK lpTimeProc,
  WORD dwUser,
  UINT fuEvent )
  该函数设置一个定时回调事件,此事件可以是一个一次性事件或周期性事件。事件一旦被激活,便调用指定的回调函数, 成功后返回事件的标识符代码,否则返回NULL。函数的参数说明如下:
  uDelay:以毫秒指定事件的周期。
  Uresolution:以毫秒指定延时的精度,数值越小定时器事件分辨率越高。缺省值为1ms。
  LpTimeProc:指向一个回调函数。
  DwUser:存放用户提供的回调数据。
  FuEvent:指定定时器事件类型:
  TIME_ONESHOT:uDelay毫秒后只产生一次事件
  TIME_PERIODIC :每隔uDelay毫秒周期性地产生事件。   
  具体应用时,可以通过调用timeSetEvent()函数,将需要周期性执行的任务定义在LpTimeProc回调函数 中(如:定时采样、控制等),从而完成所需处理的事件。需要注意的是,任务处理的时间不能大于周期间隔时间。另外,在定时器使用完毕后, 应及时调用timeKillEvent()将之释放。
  方式七:对于精确度要求更高的定时操作,则应该使用QueryPerformanceFrequency()和 QueryPerformanceCounter()函数。这两个函数是VC提供的仅供Windows 95及其后续版本使用的精确时间函数,并要求计算机从硬件上支持精确定时器。如示例工程中的Timer7、Timer7_1、Timer7_2、Timer7_3。
QueryPerformanceFrequency()函数和QueryPerformanceCounter()函数的原型如下:
  BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);
  BOOL QueryPerformanceCounter(LARGE_INTEGER *lpCount);
  数据类型ARGE_INTEGER既可以是一个8字节长的整型数,也可以是两个4字节长的整型数的联合结构, 其具体用法根据编译器是否支持64位而定。该类型的定义如下:
  typedef union _LARGE_INTEGER
  {
  struct
  {
       DWORD LowPart ;// 4字节整型数
       LONG HighPart;// 4字节整型数
  };
  LONGLONG QuadPart ;// 8字节整型数
    }LARGE_INTEGER ;
  在进行定时之前,先调用QueryPerformanceFrequency()函数获得机器内部定时器的时钟频率, 然后在需要严格定时的事件发生之前和发生之后分别调用QueryPerformanceCounter()函数,利用两次获得的计数之差及时钟频率,计算出事件经 历的精确时间。下列代码实现1ms的精确定时:
  LARGE_INTEGER litmp;
  LONGLONG QPart1,QPart2;
  double dfMinus, dfFreq, dfTim;
  QueryPerformanceFrequency(&litmp);
  dfFreq = (double)litmp.QuadPart;// 获得计数器的时钟频率
  QueryPerformanceCounter(&litmp);
  QPart1 = litmp.QuadPart;// 获得初始值
  do
  {
     QueryPerformanceCounter(&litmp);
     QPart2 = litmp.QuadPart;//获得中止值
     dfMinus = (double)(QPart2-QPart1);
     dfTim = dfMinus / dfFreq;// 获得对应的时间值,单位为秒
  }while(dfTim<0.001);
  其定时误差不超过1微秒,精度与CPU等机器配置有关。 下面的程序用来测试函数Sleep(100)的精确持续时间:
  LARGE_INTEGER litmp;
  LONGLONG QPart1,QPart2;
  double dfMinus, dfFreq, dfTim;
  QueryPerformanceFrequency(&litmp);
  dfFreq = (double)litmp.QuadPart;// 获得计数器的时钟频率
  QueryPerformanceCounter(&litmp);
  QPart1 = litmp.QuadPart;// 获得初始值
  Sleep(100);
  QueryPerformanceCounter(&litmp);
  QPart2 = litmp.QuadPart;//获得中止值
  dfMinus = (double)(QPart2-QPart1);
  dfTim = dfMinus / dfFreq;// 获得对应的时间值,单位为秒 
  由于Sleep()函数自身的误差,上述程序每次执行的结果都会有微小误差。下列代码实现1微秒的精确定时:
  LARGE_INTEGER litmp;
  LONGLONG QPart1,QPart2;
  double dfMinus, dfFreq, dfTim;
  QueryPerformanceFrequency(&litmp);
  dfFreq = (double)litmp.QuadPart;// 获得计数器的时钟频率
  QueryPerformanceCounter(&litmp);
  QPart1 = litmp.QuadPart;// 获得初始值
  do
  {
     QueryPerformanceCounter(&litmp);
     QPart2 = litmp.QuadPart;//获得中止值
     dfMinus = (double)(QPart2-QPart1);
     dfTim = dfMinus / dfFreq;// 获得对应的时间值,单位为秒
  }while(dfTim<0.000001);
其定时误差一般不超过0.5微秒,精度与CPU等机器配置有关。
16. 为对话框中的控件增加提示的简单方法
我学VC从VC知识库中得到不少好处,相来都是一些热心朋友们的帮助,在此表示感谢!本工程可分五步:
1、建一个基于对话框的程序TipTest,在CTipTestDlg中增加成员变量:CToolTipCtrl m_tip[2],CWnd *m_pSub[2];
2、在CTipTestDlg::OnInitDialog()函数中增加如下代码:
  pSub[0] = GetDlgItem(IDC_RADIO1);  //得到单选按钮的指针
  pSub[1] = GetDlgItem(IDC_BUTTON1);
"m_tip[0].Create(pSub[0],TTS_ALWAYSTIP); //创建CToolTipCtrl
"m_tip[0].AddTool(pSub[0]);  //将CToolTipCtrl与相应的控件对应起来
"m_tip[1].Create(pSub[1],TTS_ALWAYSTIP);
"m_tip[1].AddTool(pSub[1]);
"m_tip[0].SetTipTextColor(RGB(0,0,255)); //设定文字的颜色
  m_tip[0].SetDelayTime(150);       //设定提示文字在控件上停留的时间
3、重载CTipTestDlg::PreTranslateMessage(MSG* pMsg)函数,增加如下代码:
   if(m_tip[0].m_hWnd!=NULL)
  m_tip[0].RelayEvent(pMsg);  //如果m_tip[0]句柄不为空,就从主窗口中捕获消息,如WM_MOUSEMOVE,WM_LBUTTONDOWN等消息
   if(m_tip[1].m_hWnd!=NULL)
  m_tip[1].RelayEvent(pMsg); 
4、捕获主窗口的WM_MOUSEMOVE消息,在CTipTestDlg::OnMouseMove(UINT nFlags, CPoint point)函数中增加如下代码:
  m_tip[0].UpdateTipText("VC知识库欢迎你!",pSub[0]);    //鼠标在相应的控件上移动时显示提示文字
"m_tip[1].UpdateTipText("http://vckbase.com",pSub[1]);
17.删除文件夹
// 删除文件夹及其所有内容
void CBaseDoc::RemoveFolder(const CString &strPathName)
{
  CString path = strPathName;
  if (path.Right(1) != _T("//"))
    path += _T("//");
  path += _T("*.*");
  CFileFind ff;
  BOOL res = ff.FindFile(path);
  while (res)
  {
    res = ff.FindNextFile();
    // 是文件时直接删除
    if (!ff.IsDots() && !ff.IsDirectory())
      DeleteFile(ff.GetFilePath());
    else if (ff.IsDots())
      continue;
    else if (ff.IsDirectory())
    {
      path = ff.GetFilePath();
      // 是目录时继续递归,删除该目录下的文件
      RemoveFolder(path);
      ::RemoveDirectory(path);
    }
  }
}
18.消息映射
有对话框A,B
从A中发消息给B然后B处理。
准备工作,先定义消息,如下
#define WM_B_NOTIFY WM_USER + 300
首先,必须将B的对话框句柄传送给A,暂时叫m_hWndB;
在A的发送消息的地方这样写:
::SendMessage( m_hWndB,WM_B_NOTIFY,TRUE,NULL );
这样A中的处理就完了,下面说B 中的
首先定义消息处理函数,如下
void B::ModiNotify( WPARAM wParam, LPARAM lParam )
{
  MessageBox("小样,我就不信,搞不定你!");
}
然后加消息隐射,如下:
BEGIN_MESSAGE_MAP(CB, CDialog)
  //{{AFX_MSG_MAP(CRPServerDlg)
  ON_MESSAGE( WM_B_NOTIFY,ModiNotify )
  //}}AFX_MSG_MAP
END_MESSAGE_MAP()
19.给从CWnd派生的窗口添加滚动条
ModifyStyle(0,WS_VSCROLL);
20. SetWindowPos
函数功能:该函数改变一个子窗口,弹出式窗口式顶层窗口的尺寸,位置和Z序。子窗口,弹出式窗口,及顶层窗口根据它们在屏幕上出现的顺序排序、顶层窗口设置的级别最高,并且被设置为Z序的第一个窗口。 
     函数原型:BOOL  SetWindowPos(HWN  hWnd,HWND  hWndlnsertAfter,int  X,int  Y,int  cx,int  cy,UNIT.Flags); 
     参数: 
     hWnd:窗口句柄。 
     hWndlnsertAfter:在z序中的位于被置位的窗口前的窗口句柄。该参数必须为一个窗口句柄,或下列值之一: 
     HWND_BOTTOM:将窗口置于Z序的底部。如果参数hWnd标识了一个顶层窗口,则窗口失去顶级位置,并且被置在其他窗口的底部。 
     HWND_DOTTOPMOST:将窗口置于所有非顶层窗口之上(即在所有顶层窗口之后)。如果窗口己经是非顶层窗口则该标志不起作用。 
     HWND_TOP:将窗口置于Z序的顶部。 
     HWND_TOPMOST:将窗口置于所有非顶层窗口之上。即使窗口未被激活窗口也将保持顶级位置。 
     查g看该参数的使用方法,请看说明部分。 
     x:以客户坐标指定窗口新位置的左边界。 
     Y:以客户坐标指定窗口新位置的顶边界。 
     cx:以像素指定窗口的新的宽度。 
     cy:以像素指定窗口的新的高度。 
     uFlags:窗口尺寸和定位的标志。该参数可以是下列值的组合: 
     SWP_ASNCWINDOWPOS:如果调用进程不拥有窗口,系统会向拥有窗口的线程发出需求。这就防止调用线程在其他线程处理需求的时候发生死锁。 
     SWP_DEFERERASE:防止产生WM_SYNCPAINT消息。 
     SWP_DRAWFRAME:在窗口周围画一个边框(定义在窗口类描述中)。 
     SWP_FRAMECHANGED:给窗口发送WM_NCCALCSIZE消息,即使窗口尺寸没有改变也会发送该消息。如果未指定这个标志,只有在改变了窗口尺寸时才发送WM_NCCALCSIZE。 
     SWP_HIDEWINDOW;隐藏窗口。 
     SWP_NOACTIVATE:不激活窗口。如果未设置标志,则窗口被激活,并被设置到其他最高级窗口或非最高级组的顶部(根据参数hWndlnsertAfter设置)。 
     SWP_NOCOPYBITS:清除客户区的所有内容。如果未设置该标志,客户区的有效内容被保存并且在窗口尺寸更新和重定位后拷贝回客户区。 
     SWP_NOMOVE:维持当前位置(忽略X和Y参数)。 
  SWP_NOOWNERZORDER:不改变z序中的所有者窗口的位置。 
  SWP_NOREDRAW:不重画改变的内容。如果设置了这个标志,则不发生任何重画动作。适用于客户区和非客户区(包括标题栏和滚动条)和任何由于窗回移动而露出的父窗口的所有部分。如果设置了这个标志,应用程序必须明确地使窗口无效并区重画窗口的任何部分和父窗口需要重画的部分。 
  SWP_NOREPOSITION;与SWP_NOOWNERZORDER标志相同。 
  SWP_NOSENDCHANGING:防止窗口接收WM_WINDOWPOSCHANGING消息。 
  SWP_NOSIZE:维持当前尺寸(忽略cx和Cy参数)。 
  SWP_NOZORDER:维持当前Z序(忽略hWndlnsertAfter参数)。 
  SWP_SHOWWINDOW:显示窗口。 
  返回值:如果函数成功,返回值为非零;如果函数失败,返回值为零。若想获得更多错误消息,请调用GetLastError函数。 
  备注:如果设置了SWP_SHOWWINDOW和SWP_HIDEWINDOW标志,则窗口不能被移动和改变大小。如果使用SetWindowLoog改变了窗口的某些数据,则必须调用函数SetWindowPos来作真正的改变。使用下列的组合标志:SWP_NOMOVEISWP_NOSIZEISWP_FRAMECHANGED。 
  有两种方法将窗口设为最顶层窗口:一种是将参数hWndlnsertAfter设置为HWND_TOPMOST并确保没有设置SWP_NOZORDER标志;另一种是设置窗口在Z序中的位置以使其在其他存在的窗口之上。当一个窗口被置为最顶层窗口时,属于它的所有窗口均为最顶层窗口,而它的所有者的z序并不改变。 
  如果HWND_TOPMOST和HWND_NOTOPMOST标志均未指定,即应用程序要求窗口在激活的同时改变其在Z序中的位置时,在参数hWndinsertAfter中指定的值只有在下列条件中才使用: 
  在hWndlnsertAfter参数中没有设定HWND_NOTOPMOST和HWND_TOPMOST标志。 
  由hWnd参数标识的窗口不是激活窗口。 
  如果未将一个非激活窗口设定到z序的顶端,应用程序不能激活该窗口。应用程序可以无任何限制地改变被激活窗口在Z序中的位置,或激活一个窗口并将其移到最高级窗口的顶部或非最高级窗口的顶部。 
  如果一个顶层窗口被重定位到z序的底部(HWND_BOTTOM)或在任何非最高序的窗口之后,该窗口就不再是最顶层窗口。当一个最顶层窗口被置为非最顶级,则它的所有者窗口和所属者窗口均为非最顶层窗口。 
  一个非最顶端窗口可以拥有一个最顶端窗口,但反之则不可以。任何属于顶层窗口的窗口(例如一个对话框)本身就被置为顶层窗口,以确保所有被属窗口都在它们的所有者之上。 
  如果应用程序不在前台,但应该位于前台,就应调用SetForegroundWindow函数来设置。 
  Windows  CE:如果这是一个可见的顶层窗口,并且未指定SWP_NOACTIVATE标志,则这个函数将激活窗口、如果这是当前的激活窗口,并且指定了SWP_NOACTIVATE或SWP_HIDEWINDOW标志,则激活另外一个可见的顶层窗口。 
  当在这个函数中的nFlags参数里指定了SWP_FRAMECHANGED标志时,WindowsCE重画窗口的整个非客户区,这可能会改变客户区的大小。这也是重新计算客户区的唯一途径,也是通过调用SetwindowLong函数改变窗口风格后通常使用的方法。 
  SetWindowPos将使WM_WINDOWPOSCHANGED消息向窗口发送,在这个消息中传递的标志与传递给函数的相同。这个函数不传递其他消息。 
  Windows  CE  1.0不支持在hWndlnsertAber参数中的HWND_TOPMOST和HWND_NOTOPMOST常量。 
  Windows  CE1.0不支持在fuFags参数中的SWP_DRAWFRAME和SWP_NOCOPYBITS标志。 
  速查:Windows  NT:3.1以上版本;Windows:95以上版本;Windows  CE:1.0以上版本;头文件:winuser.h库文件:eser32lib

21. 介绍函数过程中一种任意键退出同时能处理消息的实现方法
1. 设置定时器,用于使::GetMessage(...)函数总能快速取到消息.
2. 在函数处理中加入:
函数每执行完一步后执行下面的代码.
if (::GetMessage(&msg, 0, 0, 0))
{
  if (msg.message >= WM_KEYFIRST && msg.message <= WM_KEYLAST) return ;
  ::TranslateMessage(&msg);
  ::DispatchMessage(&msg);
}
else ::PostQuitMessage(0);
22. 如何隐藏工具栏
添加如下两个函数
隐藏:
void CMainFrame::OnHide()
{
  if(m_wndToolBar.IsWindowVisible())
    m_wndToolBar.ModifyStyle(WS_VISIBLE,0);
  SendMessage(WM_SIZE);
}
显示:
void CMainFrame::OnShow()
{
  if(!m_wndToolBar.IsWindowVisible())
    m_wndToolBar.ModifyStyle(0,WS_VISIBLE);
  SendMessage(WM_SIZE);
}
23. 如何动态获取工具条指针并给工具条加标题?
[问题提出]
工具条也是窗口,是窗口就有标题,如何给工具条加标题?
[程序实现]
不想动态改变工具条的标题就在CMainFrame::OnCreate()中:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
......
m_wndToolBar.SetWindowText(_T("Standdard"));
return 0;
}
若想动态改变工具条的标题,如下:
声明一个菜单,并响应事件,如响应:OnMyToolBar()函数
void CMainFrame::OnMyToolBar()
{
// TODO: Add your command handler code here
CToolBar *pToolBar = (CToolBar *)AfxGetMainWnd()->GetDescendantWindow(AFX_IDW_TOOLBAR);
pToolBar->SetWindowText (_T("Standdard"));
}
不要在TooBar悬浮时做OnMyToolBar()会出错的.
顺便提一下如何获得状态条的指针:
CStatusBar * pStatusBar =(CStatusBar *)AfxGetMainWnd()->GetDescendantWindow(AFX_IDW_STATUS_BAR);
24. 在状态条中显示鼠标的设备坐标与逻辑坐标
显示器的设备坐标系的原点在客户区的左上角,x轴向右增长,y轴向下增长。我们要设置的逻辑坐标系的原点则在客户区的中心,x轴向右增长,y轴向上增长,如一个笛卡尔坐标系一般。
为CChildView添加一个成员函数void OnPrepareDC(CDC * pDC, CPrintInfo * pInfo = NULL);
void OnPrepareDC(CDC * pDC, CPrintInfo * pInfo){
 CRect rect;
 // 设置映射模式为LOMETRIC (0.1mm),右上为增长方向
 pDC->SetMapMode (MM_LOMETRIC);
 // 将坐标原点定在客户区的中心
 GetClientRect(rect);
 pDC->SetViewportOrg(rect.Width()/2, rect.Height()/2);
}
为CChildView响应鼠标移动消息,并在状态条中显示鼠标的坐标值。m_ptMouse数据成员是原打算做十字交叉线用的,在此使用没有实际意义。
void CChildView::OnMouseMove(UINT nFlags, CPoint point){
 CClientDC dc(this);
 CString str;
 OnPrepareDC(&dc);
 //要访问类CMainFrame,需要将mainfrm.h文件引入
 CMainFrame * pFrame = (CMainFrame *) AfxGetApp()->m_pMainWnd;
 //要访问CMainFrame的数据成员m_wndStatusBar,需要手工修改mainfrm.h,public这个数据成员
 CStatusBar * pStatus = (CStatusBar *) &pFrame->m_wndStatusBar;
 m_ptMouse = point;
 str.Format ("设备坐标 X=%i pixel, Y=%i pixel", m_ptMouse.x, m_ptMouse.y);
 pStatus->SetPaneText(1, str);
 dc.DPtoLP(&m_ptMouse);
 str.Format ("逻辑坐标 X=%i * 0.1mm, Y=%i * 0.1mm", m_ptMouse.x, m_ptMouse.y);
 pStatus->SetPaneText(2, str);
}
25. 如何用VC++ 动态修改应用程序菜单
 [问题提出]
  本文将介绍一些使用CMenu的方法,如查找指定菜单,在指定选项前添加菜单项.....
 [解决方法]
  使用CWnd::GetMenu( )访问主菜单,GetMenu( )返回指向CMenu对象的指针,它有一些成员函数,允许我们修改一个菜单。
  1) 如何实现找到一个菜单项:
  步骤如下:
  {
  //动态修改菜单:
  // Get the Main Menu
  CMenu* pMainMenu = AfxGetMainWnd()->GetMenu();
  CMenu* pSubMenu = NULL;
  int i;
  for (i=0; i<(int)pMainMenu->GetMenuItemCount(); i++)
  {
      pSubMenu = pMainMenu->GetSubMenu(i);
      if (pSubMenu && pSubMenu->GetMenuItemID(0) == ID_FILE_NEW)
  break;
  }
  CString s;
  s.Format("%d",i);//菜单项的位数.
  AfxMessageBox(s);
  ASSERT(pSubMenu);
  }
  2) 动态编辑菜单:
  步骤如下(可以用上例的pSubMenu,要加的菜单你自己定义.):
  1) 添加一个称为Wzd2,命令ID为IDC_NAME_NEW1的菜单命令到该菜单中,可以用:
  pSubMenu->AppendMenu(0,IDC_NAME_NEW1,"New&1");
  2) 在New1前插入New2,可以用:
  pSubMenu->InsertMenu(IDC_NAME_NEW1,MF_BYCOMMAND,IDC_NAME_NEW2, "New&2");
  3) 把New1改变成New3,可以用:
  pSubMenu->ModifyMenu(IDC_NAME_NEW1,MF_BYCOMMAND,IDC_NAME_NEW3, "New&3");
  4) 删除该菜单中第二项,可以用:
  pSubMenu->RemoveMenu(1,MF_BYPOSITION);
26. VC++中的3D按钮的编程
运行AppWizard生成一个基于对话框的test工程,在对话框中加入一个CButton控件。在CButton控件的General属性页将控件的ID改为IDC_3DTEXTBTN,Caption改为“谁与争疯”,在控件Styles属性页选中OwnerDraw,其余设置保持默认。
  用classwizard创建一个新类:C3dTextButton,基类为CButton。为C3dTextButton类添加一个protected的函数void Draw(CDC* pDC, const CRect& rect, UINT state)。如下所示编写代码:
  void C3dTextButton::Draw(CDC *pDC, const CRect &rect, UINT state)
  {
   CString text; GetWindowText(text);
   int l=text.GetLength();
   CRect rectClient=rect;
   //获得控件的字体
   CFont* pFont=GetFont();
   //确定所选字体有效高度和宽度
   LOGFONT logfont;
   pFont->GetObject(sizeof(LOGFONT),&logfont);
   if(logfont.lfHeight==0)logfont.lfHeight=20;
   logfont.lfWidth=0;//宽度设为0,宽度值由高度确定
   logfont.lfWeight=1000;
   logfont.lfEscapement=logfont.lfOrientation=0;
   CFont tryfont; VERIFY(tryfont.CreateFontIndirect(&logfont));
   CFont* pFontOld=pDC->SelectObject(&tryfont);
   //根据控件大小,调整字体的高度,使文本与控件协调
   CSize textSizeClient=pDC->GetTextExtent(text,l);
   if(rectClient.Width()*textSizeClient.cy>rectClient.Height()*textSizeClient.cx)
   {
    logfont.lfHeight=::MulDiv(logfont.lfHeight,rectClient.Height(),textSizeClient.cy);
   }
   else{
    logfont.lfHeight = ::MulDiv(logfont.lfHeight,rectClient.Width(),textSizeClient.cx);
   }
   //创建并选择协调后的字体
   CFont font; font.CreateFontIndirect(&logfont);
   pDC->SelectObject(&font);
   textSizeClient=pDC->GetTextExtent(text,l);
   //确定文本与控件边界的距离minx,miny
   int minx=rectClient.left+(rectClient.Width()-textSizeClient.cx)/2;
   int miny=rectClient.top+(rectClient.Height()-textSizeClient.cy)/2;
   int oldBkMode=pDC->SetBkMode(TRANSPARENT);
   COLORREF textcol=::GetSysColor(COLOR_BTNTEXT);
   COLORREF oldTextColor=pDC->SetTextColor(textcol);
   int cx = minx;
   int cy = miny;
   int s=(state&ODS_SELECTED)?-1:+1;
   cx+= 3; cy+= 3;
   //实现3D效果
   pDC->SetTextColor(::GetSysColor(COLOR_3DDKSHADOW));
   pDC->TextOut(cx-s*2,cy+s*2,text);
   pDC->TextOut(cx+s*2,cy-s*2,text);
   pDC->TextOut(cx+s*2,cy+s*2,text);
   pDC->SetTextColor(::GetSysColor(COLOR_3DHILIGHT));
   pDC->TextOut(cx+s*1,cy-s*2,text);
   pDC->TextOut(cx-s*2,cy+s*1,text);
   pDC->TextOut(cx-s*2,cy-s*2,text);
   pDC->SetTextColor(::GetSysColor(COLOR_3DSHADOW));
   pDC->TextOut(cx-s*1,cy+s*1,text);
   pDC->TextOut(cx+s*1,cy-s*1,text);
   pDC->TextOut(cx+s*1,cy+s*1,text);
   pDC->SetTextColor(::GetSysColor(COLOR_3DLIGHT));
   pDC->TextOut(cx,cy-s*1,text);
   pDC->TextOut(cx-s*1,cy,text);
   pDC->TextOut(cx-s*1,cy-s*1,text);
   pDC->SetTextColor(textcol);
   //输出标题
   pDC->TextOut(cx,cy,text);
   //恢复设备描述表
   pDC->SetTextColor(oldTextColor);
   pDC->SetBkMode(oldBkMode);
   pDC->SelectObject(pFontOld);
  }
  用classwizard重载C3dTextButton类的DrawItem函数。编写代码如下所示:
  void C3dTextButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
  {
   CDC* pDC=CDC::FromHandle(lpDrawItemStruct->hDC);
   ASSERT_VALID(pDC);
   CRect rectClient=lpDrawItemStruct->rcItem;
   Draw(pDC,rectClient,lpDrawItemStruct->itemState);
  }
  用classwizard为IDC_3DTEXTBTN建立一个C3dTextButton控件变量m_3dTextButton1。
把“3dTextButton.h”加入testDlg头文件。编译并测试应用程序。
27. 如何正确的得到ComBox的指针
CComboBox *mComb = (CComboBox*)GetDlgItem(IDC_DuanCB);
CComboBox *mComb = (CComboBox*)::GetDlgItem(m_hWnd,IDC_DuanCB);
28. 如何让对话框中的CEdit控件类接收对话框的消息

// 如何让对话框中的CEdit控件类接收对话框的消息

1、在对话框中增加一个ID 为IDC_EDIT1的CEdit1控件
2、通过ClassWizard 生成一个基于CEdit的新类CMyEdit,
CMyEdit m_wndEdit;
3、在对话框OnInitDialog()中,将m_wndEdit子类化,使其能够接受对话框的消息。
m_wndEdit.SubclassDlgItem (IDC_EDIT1,this);
29.利用WM_CTLCOLOR消息实现编辑控制(Edit Control)的文本与背景色的改变
首先要明白:WM_CTLCOLOR是一个由控制(Control)发送给它父窗口的通知消息(Notification message)。
实现步骤:
生成一个标准的单文档应用程序框架,假设应用程序的名称为Color。我将利用它的About对话框做示范。在About dialog中添加两个Edit control,设定其ID为IDC_EDIT1与IDC_EDIT2。
第一种方法(对应于IDC_EDIT1): 按照标准的Windows编程,由其父窗口的消息处理函数负责处理WM_CTLCOLOR消息。
1. 在CAboutDlg中添加一个数据成员:HBRUSH m_brMine;
2. 利用向导映射AboutDlg的WM_CTLCOLOR消息,产生函数:HBRUSH CAboutDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
pDC是AboutDlg的设备上下文,pWnd是AboutDlg中发送该消息的control指针,nCtlColor市Control的类型编码。对其进行如下修改:
HBRUSH CAboutDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
 if ((pWnd->GetDlgCtrlID() == IDC_EDIT1) && (nCtlColor == CTLCOLOR_EDIT))
 {
   COLORREF clr = RGB(255,0,0);
   pDC->SetTextColor(clr);  //设置红色的文本
   clr = RGB(0,0,0);
   pDC->SetBkColor(clr);  //设置黑色的背景
   m_brMine = ::CreateSolidBrush(clr);
   return m_brMine; //作为约定,返回背景色对应的刷子句柄
 }
 else
 {
   HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
   return hbr;
 }
}
第二种方法(对应于IDC_EDIT2):
利用MFC 4.0的新特性: Message reflection。
1.利用向导添加一个新的类:CColorEdit,基类为CEdit;
2.在CColorEdit中添加一个数据成员: HBRUSH m_bkBrush;
3.利用向导映射CColorEdit的"=WM_CTLCOLOR"消息,产生函数:
HBRUSH CColorEdit::CtlColor(CDC* pDC, UINT nCtlColor);
对其进行如下修改:
HBRUSH CColorEdit::CtlColor(CDC* pDC, UINT nCtlColor)
{
 COLORREF clr = RGB(0,0,0);
 pDC->SetTextColor(clr);  //设置黑色的文本
 clr = RGB(255,0,0);
 pDC->SetBkColor(clr);  //设置红色的背景
 m_bkBrush = ::CreateSolidBrush(clr);
 return m_bkBrush; //作为约定,返回背景色对应的刷子句柄
}
4.利用向导为IDC_EDIT2生成一个数据成员CColorEdit m_coloredit;
5.在定义CAboutDlg的color.cpp文件中加入:#include "coloredit.h"
30. 如何防止密码被非法获取?
 [问题提出]
  这两天大家比较专注在获取Edit密码框的密码.在盗取时,我们如何防范呢?
 [解决方法]
  此方法针对于通过SendMessage向此窗口发送WM_GETTEXT或EM_GETLINE消息来取得密码.跟我来.
 [程序实现]
  方法很简单,用CWnd::DefWindowProc函数拦截得到的消息(向Edit发的).
  建立名为My的对话框工程.建立一个Edit控件ID=IDC_EDIT1.建一个新类名为CMyProtectEdit,派生于CEdit.
  在MyDlg.cpp中声明全局变量:BOOL g_bIdentity;
  BOOL g_bIdentity;
  在MyProtecEdit.cpp中:
  extern BOOL g_bIdentity;
  响应CMyProtectEdit的DefWindowProc函数:
  LRESULT CMyProtectEdit::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
  {
  // TODO: Add your specialized code here and/or call the base class
  // 对Edit的内容获取必须通过以下两个消息之一,不对其采用默认的处理:
  if(( message == WM_GETTEXT) || ( message == EM_GETLINE))
  {  //检查是否为合法
     if(!g_bIdentity)
     {  //非法获取,显示非法信息
  AfxMessageBox(_T("不能让你看我的密码,:( !"));
  return 0;
     )
     g_bIdentity = FALSE;//合法获取
  }
  return CEdit::DefWindowProc(message, wParam, lParam);
  }
  然后在MyDlg.cpp中
  void CMyDlg::DoDataExchange(CDataExchange* pDX)
  {
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CGetPasswordDlg)
    // NOTE: the ClassWizard will add DDX and DDV calls here
  if( pDX->m_bSaveAndValidate)
  {
     g_bIdentity = TRUE;
  }   
  //}}AFX_DATA_MAP
  }
  即可.找个程序(盗取)的试试.

31. 如何在编辑控件中以追加的方式添入字符?
 [问题提出]
  SetDlgItemText可以向Edit控件中输入字符,发送更新的消息也可是Edit控件显示与其关联的变量的值,但若是向已有的Edit字符后追加字符,该如何做?
 [程序实现]
  建立名为My的对话框工程,添加一个Edit和一个Button控件.Edit的ID=IDC_EDIT1,Button的ID=IDC_BUTTON1.建立和IDC_BUTTON1的响应函数:OnButton1()
  void CMyDlg::OnButton1()
  {
  CString pText="你好";
  CEdit *m_Edit=(CEdit *)GetDlgItem(IDC_EDIT1);
  int nLen=m_Edit->GetWindowTextLength();
  m_Edit->SetFocus();
  m_Edit->SetSel(nLen, nLen);
  m_Edit->ReplaceSel(pText);
  }
  在Edit控件中输入字符,想追加时按IDC_BUTTON1按钮.看看效果.
32.属性页标题改名
我用CPropertySheet创建属性页,用的CPropertyPage对象只有一个,也就是每个属性页的内容一样.现在的问题是:这样每个属性页的标题都是一样的,是对话框的标题!怎样动态的改变这个标题,使每个属性页的标签的名称都不同??
CTabCtrl * pCtrl = pSheet->GetTabControl();
TCITEM tc;
tc.mask = TCIF_TEXT;
tc.pszText = "新标题";
pCtrl->SetItem(0,&tc);//0即是你要改的TAb的索引

VC++界面编程总结(一)

一、改变视图背景色:
    在CView的OnDraw函数中添写如下一段程序代码:
    void CFileNameView::OnDraw(CDC* pDC)
    {
CFileNameDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
CRect rectClient;
CBrush brushBkColor;
GetClientRect(rectClient);
brushBkColor.CreateSolidBrush(RGB(255,0,0)); //颜色设置
pDC->DPtoLP(rectClient);
pDC->FillRect(rectClient,&brushBkColor);

    }
二、往基于对话框的程序添加菜单:
[1] 先添加菜单(IDR_MENU1)资源,并加上需要的菜单项。
[2] 编辑对话框资源IDD_DLGMENUTOOLBAR_DIALOG的属性,在属性对话框中选择IDR_MENU1即可。
[3] 假如您不希望在对话框属性中直接设置菜单,而通过代码在程序中动态生成可以采用如下方法:
在CFileNameDlg类声名中添加成员变量CMenu m_menu,再在CFileNameDlg::OnInitDialog() 中添加如下代码:
//加载菜单
m_menu.LoadMenu(IDR_MENU1);
//设置当前菜单
SetMenu(&m_menu);
//当你不需要菜单时可以用 SetMenu(NULL);来取消当前菜单
三、往基于Dialog的程序添加工具栏:
[1] 先添加工具栏(IDR_TOOLBAR1)资源,并画好各个按钮。
[2] 在CFileNameDlg类声名中添加成员变量 CToolBar m_wndtoolbar;
[3] 在CFileNameDlg::OnInitDialog() 中添加如下代码
//添加一个平面工具条
if (!m_wndtoolbar.CreateEx( this,TBSTYLE_FLAT ,  WS_CHILD | WS_VISIBLE | CBRS_ALIGN_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS, CRect(4,4,0,0)) || !m_wndtoolbar.LoadToolBar(IDR_TOOLBAR1) )
{
TRACE0("failed to create toolbar/n");
return FALSE;
}
m_wndtoolbar.ShowWindow(SW_SHOW);
RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 0);
四、改变对话框背景色:
在CDlgMenuToolbarDlg::OnPaint()中修改代码实现Dialog 填充颜色:
CPaintDC dc(this);
CRect rect;
GetClientRect(rect);
dc.FillSolidRect(rect, RGB(60,110,170));
方法二、在InitInstance()(不是OnInitDialog())中加入:
SetDialogBkColor(RGB(255,0,0),RGB(0,255,0));
注意:要放在InitInstance函数的最前面!
五、为dialog的工具栏添加工具提示:
[1] 在CFileNameDlg类定义中手工添加消息映射函数的定义,如下黑体部分
   //{{AFX_MSG(CFileNameDlg)
virtual BOOL OnInitDialog();
afx_msg void OnPaint();
afx_msg BOOL OnToolTipText(UINT, NMHDR* pNMHDR, LRESULT* pResult);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
[2] 在CFileNameDlg.cpp添加函数的实现代码
//工具栏提示
BOOL CFileNameDlg::OnToolTipText(UINT, NMHDR* pNMHDR, LRESULT* pResult)
{
ASSERT(pNMHDR->code == TTN_NEEDTEXTA || pNMHDR->code == TTN_NEEDTEXTW);
// UNICODE消息
TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;
TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;
//TCHAR szFullText[512];
CString strTipText;
UINT nID = pNMHDR->idFrom;
if (pNMHDR->code == TTN_NEEDTEXTA && (pTTTA->uFlags & TTF_IDISHWND) ||
  pNMHDR->code == TTN_NEEDTEXTW && (pTTTW->uFlags & TTF_IDISHWND))
{
  // idFrom为工具条的HWND
  nID = ::GetDlgCtrlID((HWND)nID);
}
if (nID != 0) //不为分隔符
{
  strTipText.LoadString(nID);
  strTipText = strTipText.Mid(strTipText.Find(’/n’,0)+1);
#ifndef _UNICODE
  if (pNMHDR->code == TTN_NEEDTEXTA)
  {
   lstrcpyn(pTTTA->szText, strTipText, sizeof(pTTTA->szText));
  }
  else
  {
   _mbstowcsz(pTTTW->szText, strTipText, sizeof(pTTTW->szText));
  }
#else
  if (pNMHDR->code == TTN_NEEDTEXTA)
  {
   _wcstombsz(pTTTA->szText, strTipText,sizeof(pTTTA->szText));
  }
  else
  {
   lstrcpyn(pTTTW->szText, strTipText, sizeof(pTTTW->szText));
  }
#endif 
  *pResult = 0; 
  // 使工具条提示窗口在最上面
  ::SetWindowPos(pNMHDR->hwndFrom, HWND_TOP, 0, 0, 0, 0,SWP_NOACTIVATE|
   SWP_NOSIZE|SWP_NOMOVE|SWP_NOOWNERZORDER);
  return TRUE;
}
return TRUE;
}
[3] 在CFileNameDlg.cpp中添加消息映射,请看如下代码中的黑体部分
BEGIN_MESSAGE_MAP(CFileNameDlg, CDialog)
//{{AFX_MSG_MAP(CFileNameDlg)
ON_WM_PAINT()
ON_NOTIFY_EX( TTN_NEEDTEXT, 0, OnToolTipText )
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
[4] 在CFileNameDlg.h中添加声明:
BOOL CFileNameDlg::OnToolTipText(UINT, NMHDR* pNMHDR, LRESULT* pResult);
六、给没有工具栏的窗口添加工具栏:
在资源管理器中编辑工具栏,并将其属性改为IDR_MAINFRAME,然后在MainFrm.h中声明:
CToolBar m_wndToolBar;
在MainFrm.cpp中添加:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
m_wndToolBar.Create(this);
m_wndToolBar.LoadToolBar(IDR_MAINFRAME);
……;

停靠工具栏:在刚才添加的后面加入下面代码:
m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle()|CBRS_TOOLTIPS|CBRS_SIZE_DYNAMIC);
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);//控制是否开启任意停靠
完善一下功能:
在菜单中添加一项“工具栏”,ID设为ID_VIEW_TOOLBAR,一切OK,试试吧!
七、创建分隔窗口:
只有框架类可以创建分隔,分隔可以嵌套。
在.h文件中声明 CSplitterWnd m_wndSplitter;并且包含COneView.h(新建视图类)和CWinFrame.h(新建框架类)文件;
然后在.cpp文件中加入:
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
if(!m_wndSplitter.CreateStatic(this,1,2))
    return FALSE;
if(!m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(COneView),CSize(240,420),pContext))
    return FALSE;
if(!m_wndSplitter.CreateView(0,1,RUNTIME_CLASS(CWinFrame),CSize(300,500),pContext))
    return FALSE;
return TRUE;
}
当用户创建好分割窗口后,有时并不希望通过拖动切分条来调节窗口的大小。这时就必须锁定切分条。锁定切分条的最简单的方法莫过于不让 CSplitterWnd来处理WM_LBUTTONDOWN,WM_MOUSEMOVE,WM_SETCURSOR消息,而是将这些消息交给CWnd窗口进行处理,从而屏蔽掉这些消息。拿WM_LBUTTONDOWN处理过程来说。修改为如下:
void CXXSplitterWnd::OnLButtonDown(UINT nFlags,CPoint point)
{
  CWnd::OnLButtonDown(nFlags,point);
}
其余的处理方法类似。
八、“打开”按钮的设置:
    用类向导创建该按钮的click函数,选择默认值OnOpen,加入以下代码:
void CYourDlg::OnOpen()
{
char szFileFilter[]=
       "BIN File(*.bin)|*.bin|"
       "All File(*.*)|*.*||";//文件类型过滤
CFileDialog dlg(TRUE,NULL,NULL,OFN_HIDEREADONLY,szFileFilter);
/* CFileDialog dlg(FALSE);
   dlg.m_ofn .lpstrFilter =_T("文本文件(*.txt)*.txt所有文件(*.*)*.*");
   dlg.m_ofn.lpstrDefExt=_T("txt"); */
if(dlg.DoModal()==IDOK)
{
  m_path = dlg.GetPathName();//将显示路径的Edit控件命名为m_path,并增加CString变量m_path
  UpdateData(FALSE);
}
}
九、窗口居中:
在初始化(OnInit)函数中增加:CenterWindow();即可
十、对话框加状态条:
    UINT indicators[]={ID_INITMESSAGE,ID_SEPARATOR,ID_TIMEMESSAGE,ID_PROGRESS};
    m_statusbar.CreateEx(this,0,WS_CHILD | WS_VISIBLE | CBRS_BOTTOM);
    m_statusbar.SetIndicators(indicators,4);
    m_statusbar.ShowWindow (SW_SHOW);
    RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 0);
十一、设置初始窗口状态:
BOOL CObjectNameApp::InitInstance()
{
m_pMainWnd->SetWindowText(""); //设置初始窗口标题文本
m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED);//设置初始窗口为最大化
m_pMainWnd->UpdateWindow();

对于MDI函数SetWindowText无效,主窗口的标题只能在资源列表中修改,子窗口标题在**doc.cpp中重载OnNewDocument(),调用SetTitle("LGdownload中文版");来修改。
设置初始窗口最大化的另一优化方法:
void CMainFrame::ActivateFrame(int nCmdShow)
{
    // TODO: Add your specialized code here and/or call the base class
    nCmdShow=SW_MAXIMIZE;
    CFrameWnd::ActivateFrame(nCmdShow);
}
十二、对话框透明特效:
在OnInitDialog()中加入以下代码:
//加入WS_EX_LAYERED扩展属性
SetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE,
GetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE)^0x80000);
HINSTANCE hInst = LoadLibrary("User32.DLL");
if(hInst)
{
typedef BOOL (WINAPI *MYFUNC)(HWND,COLORREF,BYTE,DWORD);
MYFUNC fun = NULL;
//取得SetLayeredWindowAttributes函数指针
fun=(MYFUNC)GetProcAddress(hInst, "SetLayeredWindowAttributes");
if(fun)fun(this->GetSafeHwnd(),0,128,2);
FreeLibrary(hInst);
}
注意:fun的参数128不能太小,否则就完全透明了!
十三、设置对话框里的STATIC控件颜色属性:
在该对话框增加WM_CTLCOLOR事件,加入以下代码:
if( nCtlColor==CTLCOLOR_STATIC )
{
    pDC->SetTextColor(RGB(255,255,255));
    pDC->SetBkColor(RGB(91,145,244));
  pDC->SetBkMode(TRANSPARENT); //设置透明
}
设置STATIC控件背景透明:
if( nCtlColor==CTLCOLOR_STATIC )
{
pDC->SetBkMode(TRANSPARENT); //设置透明
return (HBRUSH)::GetStockObject(NULL_BRUSH);
}
十四、使窗口的最大化和最小化按钮消失:
在PreCreateWindow函数中添加以下代码即可:
    int xSize = ::GetSystemMetrics( SM_CXSCREEN );
    int ySize = ::GetSystemMetrics( SM_CYSCREEN );
    cs.cx = xSize * 6 / 10;
    cs.cy = ySize * 6 / 10;
    cs.x = ( xSize - cs.cx ) / 2;
    cs.y = ( ySize - cs.cy ) / 2;
    cs.style &= ~WS_THICKFRAME;
    cs.style &= ~( WS_MAXIMIZEBOX | WS_MINIMIZEBOX );
    cs.dwExStyle |= WS_EX_TOOLWINDOW;
十五、设置控件字体颜色:(例如STATIC控件)
在OnCtlColor函数中添加如下代码:(可能需要选择STATIC的简单属性)
if(nCtlColor==CTLCOLOR_STATIC) 
{  pDC->SetTextColor(RGB(255,0,0));
   pDC->SetBkColor(RGB(128,128,128));//设置文本背景色
pDC->SetBkMode(TRANSPARENT);//设置背景透明
}
其他控件的宏定义为:
  .CTLCOLOR_BTN       按钮控件
  .CTLCOLOR_DLG       对话框
  .CTLCOLOR_EDIT      编辑框
  .CTLCOLOR_LISTBOX   列表控件
  .CTLCOLOR_MSGBOX    消息控件
  .CTLCOLOR_SCROLLBAR 滚动条控件
  .CTLCOLOR_STATIC    静态控件 
十六、将字符转换为数字:
int i = atoi("12345"); 或 sscanf("12345","%d",&i); 
十七、调用外部应用程序可使用的函数:
  CreateProcess、WinExec、ShellExecute。
例:ShellExecute(pWnd->m_wnd, "open", "my.exe", NULL, NULL, SW_NORMAL)
一、父窗体句柄,二、命令"open",三、文件路径,四、参数,五、运行路径,六、显示方式
十八、经典安装程序制作软件:InstallShield for Microsoft Visual C++6.0
release 方式是在build菜单中的Set Active configuration中改
在project菜单里面,选Add to Project的component and control来加入ocx控件
十九、控件的注册:
1.注册
regsvr32 x:/xxx/demo.ocx 不一定非得在 Windows 系统目录
2.卸载
regsvr32 /u x:/xxx/demo.ocx
二十、获取当前时间:
CTime m_time=CTime::GetCurrentTime();
char szText[100];
memset(szText,0,100);
sprintf(szText,"%d_%d_%d",m_time.GetHour(),m_time.GetMinite(),m_time.GetSecond());
  // 如何得到当前时间日期
    CTime time = CTime::GetCurrentTime(); 
    CString m_strTime = time.Format("%Y-%m-%d %H:%M:%S");
    // 方法二
    SYSTEMTIME ti;
    GetSystemTime(&ti); // 如何得到当前时间日期
    ti.wMilliseconds; // 得到毫秒时间
SYSTEMTIME time;
CString str;
GetLocalTime( &time );
str.Format( "%04d:%02d:%02d",time.wYear,time.wMonth.....);
二一、修改单文档程序的标题:
OnCreat()中加入  SetWindowText("weichao");
CMainFrame::PreCreateWindow(CREATESTRUCT& cs)中加入  cs.style =WS_OVERLAPPEDWINDOW;
二二、隐藏程序在任务栏的图标:
对话框程序放OnInitDialog()函数:
SetWindowLong(this->m_hWnd,GWL_EXSTYLE,WS_EX_TOOLWINDOW);//隐藏任务拦按钮
二三、读取编辑框内容:
    GetDlgItemText(IDC_EDIT_TXDATA,m_strTXData);
二四、自绘菜单宽度不对,高度是对的,解决办法:
在ClassWizard中的ClassName下,选CMianFrame,在Messages下选WM_CONTEXTMENU并生成相应的函数,如下:
void CMainFrame::OnContextMenu(CWnd* pWnd, CPoint point)
{
  CMenu menu;
     menu.LoadMenu(IDR_MENU1);//IDR_MENU1是你要弹出菜单的ID号.
     CMenu *popup=menu.GetSubMenu(0);
     popup->TrackPopupMenu(TPM_LEFTALIGN,point.x,point.y,this);
}
二五、重启计算机:
调用一个API函数ExitWindowsEx就可以了, 两个参数:UFlag,标记,可以选择EWX_REBOOT,EWX_SHUTDOWN,EWX_POWEROFF再或上EWX_FORCE第二个参数就是0了
二六、无title对话框的移动:
void CScreenSnapDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
    //实现窗体无标题移动
    PostMessage(WM_NCLBUTTONDOWN,HTCAPTION,MAKELPARAM(point.x,point.y));
    CDialog::OnLButtonDown(nFlags, point);
}
二七、获取操作系统版本:
OSVERSIONINFO OsVersionInfo;//包含操作系统版本信息的数据结构
OsVersionInfo.dwOSVersionInfoSize= sizeof(OSVERSIONINFO);
GetVersionEx(&OsVersionInfo);//获取操作系统版本信息
二八、设置对话框为最顶层:(在OnInitDialog中添加)
SetWindowPos(&wndTopMost,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
二九、对话框程序不在任务栏显示:(在OnInitDialog中添加)
ModifyStyleEx(WS_EX_APPWINDOW,WS_EX_TOOLWINDOW);
三十、向对话框窗口添加右键菜单:
CMenu  menu,*pmenu; 
menu.LoadMenu(IDR_MENU1); 
pmenu=menu.GetSubMenu(0); 
CPoint  ptScreen(point); 
ClientToScreen(&ptScreen); 
pmenu->TrackPopupMenu(TPM_RIGHTBUTTON,ptScreen.x,ptScreen.y,this); 
三一、文件查找:(例查找连续的换行符)
FILE *fp,*fp1;
int flag=0;
int ch;
fp=fopen("c://test.txt","r");
fp1=fopen("c://wrttest.txt","w");
while(!feof(fp))
{
  ch=fgetc(fp);
  if(feof(fp))
   break;
  if(ch==’/n’&&flag==1)
   continue;
  else if(ch==’/n’&&flag==0)
   flag=1;
  else
   flag=0;
  fputc(ch,fp1);
}
fclose(fp1);
fclose(fp);
三二、托盘菜单不点击不能消失的解决办法:
在菜单之后使用下述代码:
        CPoint pt;
        GetCursorPos(&pt);
        SetForegroundWindow();
        NotifyMenu.TrackPopupMenu(TPM_RIGHTBUTTON,pt.x,pt.y,this);
        PostMessage(WM_NULL,0,0);
三三、对话框由小到大显示的动画效果:
在InitDialog中增加:
ShowWindow(SW_HIDE);
CRect dlgRect;
GetClientRect(&dlgRect);
CPoint centerPoint;
centerPoint.x=dlgRect.Width()/2;
centerPoint.y=dlgRect.Height()/2;//得到对话框的中点坐标
CRgn testrgn;
this->ShowWindow(SW_HIDE); 
int m=GetSystemMetrics(SM_CYSIZEFRAME);
//以下代码实现对话框的动态弹出
for (int i=10;i<dlgRect.Width()/2+m;i+=1)
{  
  testrgn.CreateRectRgn(centerPoint.x-i,centerPoint.y-i,centerPoint.x+i,centerPoint.y+i);
  SetWindowRgn((HRGN) testrgn,TRUE);
  ShowWindow(SW_SHOW);
  CenterWindow();
  testrgn.DeleteObject();
}
三四、按行读出文本文件:
下面的例子演示了一行一行取,直到取完。
CStdioFile myFile;
   CString ReadFileString;
if(myFile.Open("C://Readme.txt", Cfile::modeRead) == TRUE)
{
  while(myFile.ReadString(ReadFileString) != FALSE)
  {
                      //... 处理代码
                   }
           }
三五、使用IDC_HAND时提示未定义,加入以下代码:
#if(WINVER >= 0x0500)
#define IDC_HAND            MAKEINTRESOURCE(32649)
#endif /* WINVER >= 0x0500 */
三六、使应用程序启动时不自动创建新文档
在默认情况下,用AppWizard开发的SDI/MDI应用程序在启动时创建一个新的文档。如果要使应用程序在启动时不创建新文档,只需在应用类 CmyApp::InitInstance()函数的ProcessShellCommand调用前加上下面的语句就可以了:
cmdInfo.m_nShellCommand = CComandLineInfo::FileNothing;
三七、播放mp3:
    CFileDialog file(true);
    if(file.DoModal()==IDOK)
    {
        CString filename=file.GetFileName();
        if(hwnd!=NULL)
        {
            MCIWndDestroy(hwnd);
        }
        hwnd=MCIWndCreate(this->m_hWnd,NULL,MCIWNDF_NOPLAYBAR,filename);
        ::ShowWindow(hwnd,SW_HIDE);
        MCIWndSetVolume(hwnd,1000);
        MCIWndPlay(hwnd);
    }
三八、获取屏幕RGB值:OnTimer中添加
CPoint pos;
GetCursorPos(&pos);//获取鼠标坐标
HDC hDC = ::GetDC(NULL);
COLORREF clr = ::GetPixel(hDC, pos.x, pos.y);
CString ClrText;
ClrText.Format("R:%d G:%d B:%d",GetRvalue(clr),GetGvalue(clr),GetBvalue(clr));
三九、打开一个网址:
打开[url]http://www.sina.com.cn[/url]这个站点如下:
ShellExecute(NULL, "open", "http://www.sina.com.cn",NULL, NULL, SW_MAXIMIZE );
此命令将以默认浏览器打开[url]http://www.sina.com.cn[/url],并将加开后的窗口最大化。
又例:
ShellExecute(NULL, "open", "IEXPLORE.exe [url]http://www.sina.com.cn[/url]",NULL, NULL, SW_MAXIMIZE );
此命令将直接用IE打开一个sina的站点。不过将开一个新的窗口。
四十、位图按钮:
CButton *pRadio = (CButton*)GetDlgItem(IDC_RADIO);
pRadio->SetBitmap(::LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_BITMAP)));

一、创建DialogBar的派生类
首先,创建对话框资源:在对话框资源编辑器内生成一个Dialog资源,并将其风格(Style)属性必须设置为Child,不能设置为Overlapped或Popup,否则运行肯定出错;至于边界属性则随用户自己喜欢,一般都是选择None。其余属性也随用户选择,一般没有特殊要求还是选择默认的好。
其次,创建基于CDialog的派生类:打开ClassWizard,为以上创建的资源添加一个以CDialog为基类的派生类(因为ClassWizard没有将CDialogBar列在基类目录清单中,所以用户只能先以CDialog类派生)。
再次,修改派生类以CDialogBar为基类:通常需要手工修改几处代码,在本例中派生类以CDataStatus命名。(注:以后讲解中凡是手工改动都是以灰背景显示)
1、 在头文件中修改继承关系
将class CDataStatus : public CDialog 改为class CDataStatus : public CDialogBar
2、 在代码文件中修该构造函数继承关系
将CDataStatus::CDataStatus(CWnd* pParent /*=NULL*/)
: CDialog(CDataStatus::IDD, pParent)
{
       //{{AFX_DATA_INIT(CDataStatus)
              // NOTE: the ClassWizard will add member initialization here
       //}}AFX_DATA_INIT
}
改为
CDataStatus::CDataStatus(CWnd* pParent /*=NULL*/)

{

       //{{AFX_DATA_INIT(CDataStatus)

              // NOTE: the ClassWizard will add member initialization here

       //}}AFX_DATA_INIT

}

3、 将DDX绑定函数中的继承关系去掉
即将void CDataStatus::DoDataExchange(CDataExchange* pDX)
{
       CDialog::DoDataExchange(pDX);
       //{{AFX_DATA_MAP(CCurrentCheckDlg)
       ………..
       //}}AFX_DATA_MAP
}
改为
void CDataStatus::DoDataExchange(CDataExchange* pDX)

{

       //{{AFX_DATA_MAP(CCurrentCheckDlg)

       ………….

       //}}AFX_DATA_MAP

}

4、 重新初始化函数(这个相当重要,如果不这么做的话,DDX函数形同虚设,当然用户的工具条如果没有用到DDX的话当然可以不加这段代码):
首先在ClassWizard的MessageMap中对消息该CDataStatus类的WM_INITDIALOG消息添加处理函数默认名为OnInitDialog。
其次手工修改代码如下:
1、             添加消息映射函数。由于对话框形式的初始化函数消息并未加载到消息映射内,为此我们需要手工添加,要不然代码无法拦截该工具条的初始化消息,形式如下:
将BEGIN_MESSAGE_MAP(CDataStatus, CDialogBar)
   //{{AFX_MSG_MAP(CDataStatus)
   .......
   //}}AFX_MSG_MAP
END_MESSAGE_MAP()
改为:
BEGIN_MESSAGE_MAP(CDataStatus, CDialogBar)

   //{{AFX_MSG_MAP(CDataStatus)

   .......

   ON_MESSAGE(WM_INITDIALOG,OnInitDialog)

   //}}AFX_MSG_MAP

END_MESSAGE_MAP()

2、             修改OnInitDialog函数,此函数并未传递参数,但是在这里我们需要让它传递参数,代码如下修改(当然头文件中,对声明也要做修改,在这里就不作赘述了)
将BOOL CDataStatus::OnInitDialog()
{
   CDialogBar::OnInitDialog();
   // TODO: Add extra initialization here
   return TRUE; // return TRUE unless you set the focus to a control
              // EXCEPTION: OCX Property Pages should return FALSE
}
改为:
BOOL CDataStatus::OnInitDialog(UINT wParam,LONG lParam)

{

   //CDialogBar::OnInitDialog();

   // TODO: Add extra initialization here

   BOOL bRet = HandleInitDialog(wParam,lParam);

   if (!UpdateData(FALSE))

   {

          TRACE("InitCDataStatus Failed!");

   }

   return TRUE; // return TRUE unless you set the focus to a control

                 // EXCEPTION: OCX Property Pages should return FALSE

}

二、在框架类中实现该派生类的对象化
首先,在框架类的头文件内声明实例对象,本例实例化:CDataStatus      m_wndDataStatus;当然头文件中不可避免要包含新派生类的头文件。
其次,在框架类的OnCreate函数内创建对象并将对象绑定对话框资源。形式与创建ToolBar原理一样,本例实例如下:
if (!m_wndDataStatus.Create(this,IDD_DATASTATUS,WS_VISIBLE|WS_CHILD

|CBRS_SIZE_DYNAMIC|CBRS_BOTTOM,IDD_DATASTATUS))

       {

              TRACE0("Failed to create CDataStatus bar!");

              return -1;

       }

再次,最为关键的一点就是重写框架类的OnCmdMsg虚函数。如果不重写该函数,那么不光DDX功能无法实现,连最基本的OnCommand事件都无法实现。而且还得手工添加代码,形式如下:
BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
       // TODO: Add your specialized code here and/or call the base class
       return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}
改为:
BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)

{

       // TODO: Add your specialized code here and/or call the base class

       if (m_wndDataStatus.OnCmdMsg(nID,nCode,pExtra,pHandlerInfo))

              return    TRUE;

       return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);

}

三、在CReBar上添加该实例化对象
其实这一步倒是相当简单,只是自己以前没用过这个类,所以在这里也顺便用了一下。
首先,在框架类的头文件中用CRebar声明一个对象,如CReBar   m_wndReBar;
其次,在框架类的代码文件中的OnCreat函数体内,生成对象,代码如下:
if (!m_wndReBar.Create(this,RBS_BANDBORDERS,WS_CHILD |

WS_VISIBLE| CBRS_BOTTOM|WS_CLIPSIBLINGS|WS_CLIPCHILDREN))

       {

              TRACE0("Failed to create Rebar /n");

              return -1;

       }

再次,就是将所要添加的toolbar以及新生成的CDataStatus对象m_wndDataStatus加进Rebar的对象m_wndReBar中,代码如下:
m_wndReBar.AddBar(&m_wndDataStatus,NULL,NULL,

RBBS_GRIPPERALWAYS|RBBS_FIXEDBMP);

具体查看附件中DIalogBarTest.rar

开发应用程序的时候,常会用到多视图结构。《VC6 技术内幕》第 20 章“Splitter Windows and Multiple Views”专门讨论了这个问题。本文讨论的 MDI 多视图结构利用了 MDI 多文档的特性产生多视图,每个文档对应一个视图,首次打开某个文档时会新建一个视图,以后再打开该文档时只会激活相应的视图。下面详述开发流程。

1、新建工程
应用类型为 MDI(Multiple document),名称为 TMDI。

2、添加新文档
添加新文档“1”、“2”、“3”、“4”、“5”、“6”、“7”。下面以文档“1”为例。

2.1 添加 C1Frame、C1Doc 和 C1View
添加方法是在 ClassView 下右键单击 TMDI classes,选择“New Class”,新类的名称及其父类如下:
class C1Frame : public CMDIChildWnd
class C1Doc : public CDocument
class C1View : public CView

2.2 添加 IDR_1TYPE 资源

2.2.1 Menu
按住 Ctrl 时拖放 IDR_TMDITYPE。将 IDR_TMDITYPE1 改名为 IDR_1TYPE。

2.2.2 Icon
导入一个图标,将 IDI_ICON1 改名为 IDR_1TYPE。

2.2.3 String Table
选择 IDR_TDITYPE 所在行(第二行),右键单击并选“Copy”,右键单击再选“Paste”。将 IDR_TMDITYPE2 改名为 IDR_1TYPE,Caption 改为“/n1/n1/n/n/n1.Document/n1 Document”。(非常重要,后面判断谁是谁都靠他了)

2.3 添加新文档模板
打开 TMDI.cpp,在开头 #ifdef _DEBUG 之前包含头文件:
#include "1Frame.h"
#include "1Doc.h"
#include "1View.h"

在 CTMDIApp::InitInstance() 中 CMultiDocTemplate* pDocTemplate; 之前添加:
CMultiDocTemplate* pDoc1Template;
pDoc1Template = new CMultiDocTemplate(
IDR_1TYPE,
RUNTIME_CLASS(C1Doc),
RUNTIME_CLASS(C1Frame), // custom MDI child frame
RUNTIME_CLASS(C1View));
AddDocTemplate(pDoc1Template);

注释 CTMDIApp::InitInstance() 末尾的两句:
// if (!ProcessShellCommand(cmdInfo))
//  return FALSE;

2.4 添加菜单项
打开菜单资源 IDR_MAINFRAME,在 File 菜单下添加菜单项(ID:ID_NAV_1,Caption:1)。再将这个菜单项复制到菜单资源 IDR_TMDITYPE 和 IDR_1TYPE。然后删除这三个菜单资源中 File 下的 New 菜单项。

2.5 让应用类处理 ID_NAV_1 菜单命令

void CTMDIApp::OnNav1()
{
OnNav(_T("1"));
}

void CTMDIApp::OnUpdateNav1(CCmdUI* pCmdUI)
{
CMDIFrameWnd *pFrame = (CMDIFrameWnd*)AfxGetApp()->m_pMainWnd;
if (pFrame)
{
CMDIChildWnd *pChild = (CMDIChildWnd *) pFrame->GetActiveFrame();
pCmdUI->SetCheck(pChild->IsKindOf(RUNTIME_CLASS(C1Frame)) ? 1 : 0);
}
}

// Refer to MSDN Sample MDIDOCVIEW [10/18/2006]
void CTMDIApp::OnNav(const CString& strDoc)
{
// Searches template list for a document type
// containing the "strDoc"
POSITION curTemplatePos = GetFirstDocTemplatePosition();
while(curTemplatePos != NULL)
{
CDocTemplate* curTemplate =
GetNextDocTemplate(curTemplatePos);
CString str;
curTemplate->GetDocString(str, CDocTemplate::docName);
if(str == strDoc)//_T("XBScan"))
{
// Refer to "Single View in MultiDoc-Application" in CodeProject.com [10/18/2006]
POSITION Pos = curTemplate->GetFirstDocPosition();
if( NULL == Pos ) // No
{
curTemplate->OpenDocumentFile(NULL);// Initialize
return;
}
// Is there an entry for that document type?
CDocument *pDoc = curTemplate->GetNextDoc(Pos);
if( NULL == pDoc )// No
{
curTemplate->OpenDocumentFile(NULL);// Initialize
return;
}
// Is the View for that document type initialized?
Pos = pDoc->GetFirstViewPosition();
if( NULL == Pos )// No
{
curTemplate->OpenDocumentFile(NULL);// Initialize
return;
}
// Exists a view for that document type?
CView *pView = pDoc->GetNextView(Pos);
if( NULL == pView )// No
{
curTemplate->OpenDocumentFile(NULL);// Create view
return;
}
//Exists a window for that view?
CWnd *pWnd = pView->GetParent();
if( NULL == pWnd )//No
{
curTemplate->OpenDocumentFile(NULL);// Create view
return;
}
// Update the relative view [10/19/2006]
pDoc->UpdateAllViews(NULL);
// A View and a window exists. Restore or activate?
WINDOWPLACEMENT wpl;
pWnd->GetWindowPlacement(&wpl);
if( SW_SHOWMINIMIZED  == wpl.showCmd )// Iconized window must be restored
{
wpl.showCmd = SW_RESTORE;
if( WPF_RESTORETOMAXIMIZED == wpl.flags )
wpl.showCmd = SW_SHOWMAXIMIZED;
pWnd->SetWindowPlacement(&wpl);
}
else
{
wpl.showCmd = SW_SHOWMAXIMIZED;//SW_RESTORE; // Bring window to top
pWnd->SetWindowPlacement(&wpl);
pWnd->BringWindowToTop();
}
}
}
}

2.6 最大化子窗口
覆盖 C1Frame 的虚函数 ActivateFrame。
void C1Frame::ActivateFrame(int nCmdShow)
{
nCmdShow = SW_SHOWMAXIMIZED;
CMDIChildWnd::ActivateFrame(nCmdShow);
}

2.7 修改子窗口的标题
默认情况下,打开自窗口“1”后,主标题由 TMDI 变为 TMDI - [11]。想将方括号中的 11 改为 Monday,就需要覆盖 C1Doc 的虚函数 SetTitle。
void C1Doc::SetTitle(LPCTSTR lpszTitle)
{
lpszTitle = _T("Monday");
CDocument::SetTitle(lpszTitle);
}

3、用工具栏辅助菜单
使用菜单命令来打开文档不是很方便,用工具栏就方便多了。

先插入工具栏资源 IDR_XTOOLBAR,添加 7 个按钮,按钮 ID 从 ID_NAV_1 到 ID_NAV_7。再将 CMainFrame::OnCreate() 中的 !m_wndToolBar.LoadToolBar(IDR_MAINFRAME)) 一句改为 !m_wndToolBar.LoadToolBar(IDR_XTOOLBAR)) 。

参考:

使用方法: 1、解压至C:\Program Files目录下(密码:xiaoqing); 2、双击导入注册表C:\Program Files\BCGSoft\BCGControlBarPro\bcgcontrolbarpro.12.00.reg; 3、运行向导C:\Program Files\BCGSoft\BCGControlBarPro\BCGCBProIntegrationWizard.exe。 与其它不同之处: 1、包含完整的源代码、帮助文件; 2、已经对 BCGPAppWizard2005 中的向导进行汉化,在 Visual Studio 2008(2010) 中可使用中文向导 BCGPAppWizard (参考 Visual Studio 2008 原有的中文向导,如果您想学习汉化向导,参考目录是:C:\Program Files\Microsoft Visual Studio 9.0\VC\VCWizards\AppWiz\MFC\Application\templates\2052) 关于静态链接: 1、首先必须在运行向导BCGCBProIntegrationWizard.exe时已经编译静态库; 2、在 Visual Studio 建立项目向导时,选择静态链接即可。 关于使用 Office2007、2010 风格: 如果您使用了这些新风格,必须在项目中包括这些资源,否则 debug 版本启动时会报错(缺少资源,release版本不会提示,但显示不正常),具体有二种方法: 1、直接在“解决方案资源管理器”-“资源文件”中点右键,“添加”-“现有项”,把C:\Program Files\BCGSoft\BCGControlBarPro\BCGCBPro\Styles中所有扩展名为 .rc 的资源包括进来即可。 2、直接在“资源视图”-“您的项目”上点右键,选择“资源包括”,在“资源包括”中的“编译时指令”中的#include "BCGCBPro.rc"后面添加以下代码: #include "C:\Program Files\BCGSoft\BCGControlBarPro\BCGCBPro\Styles\BCGPStyle2007Aqua.rc" #include "C:\Program Files\BCGSoft\BCGControlBarPro\BCGCBPro\Styles\BCGPStyle2007Luna.rc" #include "C:\Program Files\BCGSoft\BCGControlBarPro\BCGCBPro\Styles\BCGPStyle2007Obsidian.rc" #include "C:\Program Files\BCGSoft\BCGControlBarPro\BCGCBPro\Styles\BCGPStyle2007Silver.rc" #include "C:\Program Files\BCGSoft\BCGControlBarPro\BCGCBPro\Styles\BCGPStyle2010White.rc" #include "C:\Program Files\BCGSoft\BCGControlBarPro\BCGCBPro\Styles\BCGPStyleCarbon.rc" #include "C:\Program Files\BCGSoft\BCGControlBarPro\BCGCBPro\Styles\BCGPStyleScenic.rc" 3、如果使用动态库链接,请手工编译C:\Program Files\BCGSoft\BCGControlBarPro\BCGCBPro\Styles\Office2007_styles.sln或者build_all.dsp 仅为学习使用,下载后24小时内删除,请支持 BCGSoft 购买正版,本人不提供技术支持,不对任何负责。 尊重他人劳动成果,欢迎与大家分享成果。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值