分享
 
 
 

Visual C++ 6.0 编 程 经 验

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

另 一 种 改 变 窗 口 标 题 的 方 法 ---- 在1997 年9 月1 日 出 版 的《 计 算 机 世 界》 上 有 一 篇 名 为《Visual C++ 4.0 编 程 经 验 谈》 的 文 章, 其 中 提 到 过 一 种 改 变 窗 口 标 题 的 方 法, 即 在 应 用 程 序 的 框 架 类CMainFrame 类( 注: 它 是CFrameWnd 类 的 派 生 类) 的 成 员 函 数PreCreateWindow() 中 修 改CFrameWnd 类 的 成 员 变 量m_strTitle 的 值。 这 种 方 法 的 不 足 之 处 就 是 只 能 一 次 性 的 设 置 窗 口 标 题 的 内 容, 不 能 在 程 序 运 行 过 程 中 随 时 修 改 它。 比 如 当 需 要 把 鼠 标 的 当 前 坐 标 在 窗 口 标 题 上 显 示 时, 我 们 就 要 使 用 到Visual C++ 提 供 的 全 程 函 数 BOOL SetWindowText( HWND hWnd, LPCTSTR lpString )。 这 个 函 数 实 际 上 是 一 个Win32 函 数。 它 的 第 一 个 参 数 要 求 是 一 个 窗 口 框 架 的 句 柄, 而 第 二 个 参 数 要 求 是 一 个 指 向 一 个 常 量 字 符 串 的32 位 指 针, 即LPCTSTR 类 型 的 变 量。 通 常 情 况 下, 我 们 往 往 会 在 应 用 程 序 的 文 档 类 或 视 类 中 动 态 改 变 窗 口 标 题 的 内 容, 从 而 没 有 现 成 的 指 向 窗 口 框 架 的 句 柄 供 我 们 使 用, 因 此 我 们 还 需 要 在 使 用SetWindowText() 函 数 前 先 调 用 另 一 个Win32 函 数AfxGetMainWnd(), 来 获 得 一 个 指 向 应 用 程 序 的 框 架 类 的 指 针, 例 如 使 用 语 句

---- CWnd* m_pCWnd= AfxGetMainWnd()

---- 然 后, 再 以 如 下 形 式 调 用SetWindowText() 函 数:

---- SetWindowText(*m_pCWnd, (LPCTSTR) m_WindowText);// m_WindowText 可 以 是 一 个CString 类 的 变 量

---- 如 何 把 多 于256 色 的 位 图 作 为 资 源 加 入 到 应 用 程 序 中

---- 曾 经 使 用 过Visual C++ 进 行 应 用 程 序 开 发 的 同 行 们 都 知 道,Visual C++ 5.0 以 前 版 本 中 自 带 的 位 图 编 辑 器 不 能 浏 览 和 编 辑256 色 以 上 的 位 图, 并 且 资 源 文 件 中 也 不 允 许 嵌 入(Import)256 色 以 上 的 位 图 作 为 资 源( 否 则, 在 应 用 程 序 运 行 时 会 报 错)。 这 一 特 性 使 得 我 们 用Visual C++ 开 发 应 用 程 序 时 不 得 不 使 用 其 他 方 法 来 增 强 界 面 图 画 的 美 观 性, 于 是 就 有 使 用Visual C++ 开 发 应 用 程 序 内 核, 用Visual Basic 开 发 界 面 部 分 的 组 合 方 法。 好 在Visual C++ 5.0 中 这 个 问 题 有 了 改 善。 首 先, 位 图 编 辑 器 可 以 创 建 并 编 辑256 色 的 位 图 了。 另 外,Visual C++ 5.0 允 许 程 序 员 把256 色 以 上 的 位 图 嵌 入 到 资 源 中, 尽 管 仍 然 无 法 在Visual C++ 的 位 图 编 辑 器 中 浏 览, 并 且 还 要 求 必 须 选 择Win32 Release 作 为 编 译 方 式 生 成 可 执 行 的 应 用 程 序。 另 外 一 个 限 制 条 件 是 作 为 资 源 的256 色 以 上 的 位 图 不 能 由 应 用 程 序 内 核 自 动 打 开 和 关 闭。 比 如 说, 在 上 述 那 篇 名 为《Visual C++ 4.0 编 程 经 验 谈》 的 文 章 中 曾 经 提 到 过 一 种 为 对 话 框 加 入 位 图 式 按 钮 的 方 法, 即 由 程 序 开 发 者 为 每 个 按 钮 创 建 四 幅 位 图, 分 别 用 于 表 示 按 钮 的 弹 起 状 态(UP)、 按 下 状 态(DOWN)、 输 入 焦 点 状 态(FOCUS) 和 禁 止 状 态(DISABLE), 并 且 必 须 以 该 按 钮 的 标 题 名 与 上 述 四 种 状 态 之 一 的 组 合 作 为 位 图 的 标 识, 以 便 应 用 程 序 在 绘 制 位 图 按 钮 时, 可 以 自 动 地 找 到 相 应 的 资 源( 即 位 图)。 然 而 这 一 自 动 映 射 只 限 制 于Visual C++ 位 图 编 辑 器 能 够 打 开 的 位 图。 因 此 如 果 选 择256 色 以 上 的 位 图 作 为 位 图 按 钮 的 资 源, 并 也 希 望 达 到 上 述 四 状 态 的 相 互 切 换 的 话, 就 必 须 用 到 下 述 的 函 数 和 程 序 设 计 参 考 模 型。

设 置 四 个 常 量,BUTTON_UP,BUTTON_DOWN,BUTTON_FOCUS,BUTTON_DISABLE, 分 别 用 于 标 识 各 按 钮 的 当 前 状 态。

在 应 用 程 序 的 相 应 对 话 框 类 中 为 每 个 位 图 按 钮( 为 下 面 叙 述 方 便, 不 妨 假 设 为 两 个) 设 置 一 个CRect 类 的 对 象,m_rect1 和m_rect2, 来 记 载 各 按 钮 在 对 话 框 中 所 占 据 的 坐 标 矩 形。 再 在 该 对 话 框 类 中 为 每 个 按 钮 设 置 一 个 整 型 变 量,Buton1_Status,Button2_Status, 记 录 各 按 钮 的 当 前 状 态。 然 后 在 对 话 框 的 构 造 函 数 中 初 始 化 这 些CRect 类 的 对 象 和 整 型 变 量。

在 该 对 话 框 类 中 创 建 分 别 响 应 鼠 标 各 种 状 态 的 消 息 处 理 函 数, 如OnMouseMove(),OnLButtonUp(),OnLButtonDown() 等。

同 时 按 下Ctrl 和W 键 或 直 接 单 击 工 具 条 上 的ClassWizard 按 钮, 打 开ClassWizard 对 话 框。 在 类 名(Class name) 列 表 框 中 选 择 对 话 框 类, 在Object IDs 列 表 框 中 选 择 该 类 的 类 名 后, 在 消 息(Messages) 列 表 框 中 选 择WM_PAINT 消 息 并 双 击 它, 这 时ClassWizard 就 会 在 该 对 话 框 类 中 加 入 一 个OnPaint() 函 数。 该 函 数 将 在 我 们 的 程 序 中 起 重 要 作 用。 之 后, 再 在Object IDs 列 表 框 中 选 择 新 加 入 的 工 具 条 按 钮 的 标 识 名, 双 击 消 息 列 表 框 中 的COMMAND 消 息,ClassWizard 又 会 在 对 话 框 类 中 加 入 相 应 的 消 息 处 理 函 数。 关 闭ClassWizard 对 话 框。

---- 下 面 给 出 部 分 程 序 代 码, 仅 供 参 考。

void CTESTDlg::OnPaint()

{

CWnd* pWnd;

CDC* pDC;

CDC* pDisplayMemDC;

CBitmap* pBitmap;

pWnd=GetDlgItem(IDC_IMAGE1);//得到指向第一个位图按钮的指针

pDC=pWnd->GetDC();//获得一个窗口设备用于画图

pWnd->Invalidate();//使窗口无效,从而更新它

pWnd->UpdateWindow();

pDisplayMemDC=new CDC;

pBitmap=new CBitmap;

pDisplayMemDC->CreateCompatibleDC(pDC);

if (Change1) {//说明第一个按钮的状态发生了变化

switch (Button1_Status){

case BUTTON_DISABLE:

pBitmap->LoadBitmap(IMAGE1_DISABLE);//装入位图

pDisplayMemDC->SelectObject(pBitmap);

pDC->BitBlt(0,0,140,30,pDisplayMemDC,0,0,SRCCOPY);

//把位图拷贝到指定区域

break;

case BUTTON_UP:

pBitmap->LoadBitmap(IMAGE1_UP);

pDisplayMemDC->SelectObject(pBitmap);

pDC->BitBlt(0,0,140,30,pDisplayMemDC, 0,0,SRCCOPY);

break;

case BUTTON_FOCUS:

pBitmap->LoadBitmap(IMAGE1_FOCUS);

pDisplayMemDC->SelectObject(pBitmap);

pDC->BitBlt(0,0,140,30,pDisplayMemDC,0,0,SRCCOPY);

break;

case BUTTON_DOWN:

pBitmap->LoadBitmap(IMAGE1_DOWN);

pDisplayMemDC->SelectObject(pBitmap);

pDC->BitBlt(0,0,140,30,pDisplayMemDC,0,0,SRCCOPY);

break;

}

}

delete pDisplayMemDC;

delete pBitmap;

pWnd=GetDlgItem(IDC_IMAGE2);

pDC=pWnd->GetDC();

pWnd->Invalidate();

pWnd->UpdateWindow();

pDisplayMemDC=new CDC;

pBitmap=new CBitmap;

pDisplayMemDC->CreateCompatibleDC(pDC);

if (Change2) {//说明第二个按钮的状态发生了变化

switch (Button2_Status){

case BUTTON_DISABLE:

pBitmap->LoadBitmap(IMAGE2_DISABLE);

pDisplayMemDC->SelectObject(pBitmap);

pDC->BitBlt(0,0,140,30,pDisplayMemDC,0,0,SRCCOPY);

break;

case BUTTON_UP:

pBitmap->LoadBitmap(IMAGE2_UP);

pDisplayMemDC->SelectObject(pBitmap);

pDC->BitBlt(0,0,140,30,pDisplayMemDC,0,0,SRCCOPY);

break;

case BUTTON_FOCUS:

pBitmap->LoadBitmap(IMAGE2_FOCUS);

pDisplayMemDC->SelectObject(pBitmap);

pDC->BitBlt(0,0,140,30,pDisplayMemDC,0,0,SRCCOPY);

break;

case BUTTON_DOWN:

pBitmap->LoadBitmap(IMAGE2_DOWN);

pDisplayMemDC->SelectObject(pBitmap);

pDC->BitBlt(0,0,140,30,pDisplayMemDC,0,0,SRCCOPY);

break;

}

}

delete pDisplayMemDC;

delete pBitmap;

CDialog::OnPaint();

}

void CTESTDlg::OnMouseMove(UINT nFlags, CPoint point)

{

CRect rect=CRect(0,0,1,1);

CRgn rgn1,rgn2;//记录各位图按钮所占据的矩形区域

rgn1.CreateRectRgnIndirect(m_rect1);

//rgn1记录第一个位图按钮所占据的矩形区域

if (rgn1.PtInRegion(point))

{//鼠标当前是否已落入第一个位图按钮所占据的矩形区域

if ( (Button1_Status!=BUTTON_FOCUS)

&& (Button1_Status!=BUTTON_DISABLE) ) {

//如果位图按钮的当前状态不是输入焦点状态并且也不是禁止状态

Button1_Status= BUTTON_FOCUS;

Change1=true;

InvalidateRect(rect,FALSE);

}

if ( (Button2_Status!=BUTTON_UP) &&

(Button2_Status!=BUTTON_DISABLE) ) {

Button2_Status= BUTTON_UP;

Change2=true;

InvalidateRect(rect,FALSE);

}

}

else{

rgn2.CreateRectRgnIndirect(m_rect2);

if (rgn2.PtInRegion(point)){

if ( (Button2_Status!=BUTTON_FOCUS)

&& (Button2_Status!=BUTTON_DISABLE) ) {

Button2_Status= BUTTON_FOCUS;

Change2=true;

InvalidateRect(rect,FALSE);

}

if ( (Button1_Status!=BUTTON_UP)

&& (Button1_Status!=BUTTON_DISABLE) ) {

Button1_Status= BUTTON_UP;

Change1=true;

InvalidateRect(rect,FALSE);

}

}

}

CDialog::OnMouseMove(nFlags, point);

}

void CTESTDlg::OnLButtonUp(UINT nFlags, CPoint point)

{

CRect rect=CRect(0,0,1,1);

CRgn rgn1,rgn2;

rgn1.CreateRectRgnIndirect(m_rect1);

if (rgn1.PtInRegion(point)){

if ( (Button1_Status!=BUTTON_UP)

&& (Button1_Status!=BUTTON_DISABLE) ) {

Button1_Status=BUTTON_UP;

Change1=true;

InvalidateRect(rect,FALSE);

}

}

else{

rgn2.CreateRectRgnIndirect(m_rect2);

if (rgn2.PtInRegion(point)){

if ( (Button2_Status!=BUTTON_UP)

&& (Button2_Status!=BUTTON_DISABLE) ) {

Button2_Status=BUTTON_UP;

Change2=true;

InvalidateRect(rect,FALSE);

}

}

}

CDialog::OnLButtonUp(nFlags, point);

}

void CTESTDlg::OnLButtonDown(UINT nFlags, CPoint point)

{

CRect rect=CRect(0,0,1,1);

CRgn rgn1,rgn2;

rgn1.CreateRectRgnIndirect(m_rect1);

if (rgn1.PtInRegion(point)){

if ( (Button1_Status!=BUTTON_DOWN)

&& (Button1_Status!=BUTTON_DISABLE) ) {

Button1_Status=BUTTON_DOWN;

Change1=true;

InvalidateRect(rect,FALSE);

}

if ( (Button2_Status!=BUTTON_UP)

&& (Button2_Status!=BUTTON_DISABLE) ) {

Button2_Status=BUTTON_UP;

Change2=true;

InvalidateRect(rect,FALSE);

}

}

else{

rgn2.CreateRectRgnIndirect(m_rect2);

if (rgn2.PtInRegion(point)){

if ( (Button2_Status!=BUTTON_DOWN)

&& (Button2_Status!=BUTTON_DISABLE) ) {

Button2_Status=BUTTON_DOWN;

Change2=true;

InvalidateRect(rect,FALSE);

}

if ( (Button1_Status!=BUTTON_UP)

&& (Button1_Status!=BUTTON_DISABLE) ) {

Button1_Status=BUTTON_UP;

Change1=true;

InvalidateRect(rect,FALSE);

}

}

}

CDialog::OnLButtonDown(nFlags, point);

}

如 何 在 应 用 程 序 中 不 加 载 菜 单、 工 具 条 和 状 态 条 ---- 在 通 过AppWizard 生 成 的 具 有 窗 口 框 架 结 构 的 应 用 程 序(SDI 和MDI) 中,MFC 类 库 已 为 我 们 加 载 上 了 菜 单( 包 括 一 个 系 统 菜 单)、 工 具 条 和 状 态 条。 但 有 时 由 于 特 殊 需 要, 我 们 可 能 希 望 在 自 己 的 应 用 程 序 中 事 先 不 加 载 菜 单、 工 具 条 和 状 态 条。 这 时 就 需 要 我 们 手 动 地 删 除 和 修 改 一 些 类 中 的 语 句。

打 开MainFrm.cpp 文 件, 使 用 工 具 条 上 的 函 数 下 拉 列 表 框 找 到OnCreate() 函 数。 按 照 下 述 程 序 注 释 掉 创 建 工 具 条 和 状 态 条 部 分 的 语 句。 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

if (CFrameWnd::OnCreate(lpCreateStruct) == -1)

return -1;

//在此处开始加注释符号

/*if (!m_wndToolBar.Create(this) ||

!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))

{

TRACE0("Failed to create toolbar\n");

return -1; // fail to create

}

if (!m_wndStatusBar.Create(this) ||

!m_wndStatusBar.SetIndicators(indicators,

sizeof(indicators)/sizeof(UINT)))

{

TRACE0("Failed to create status bar\n");

return -1; // fail to create

}

// 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);

// TODO: Delete these three lines if you don't want the toolbar to be dockable

m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);

EnableDocking(CBRS_ALIGN_ANY);

DockControlBar(&m_wndToolBar);

在处结束注释*/

return 0;

}

在MainFrm.cpp 文 件 中, 使 用 工 具 条 上 的 函 数 下 拉 列 表 框 找 到PreCreateWindow() 函 数。 参 照 第 三 部 分 中 的 程 序, 加 入 特 定 的 窗 口 框 架 属 性, 不 妨 把cs.style 设 置 成 如 下 形 式, 即 不 加 载 系 统 菜 单。

// Create a window without min/max buttons,system menu, or sizable border

cs.style =WS_OVERLAPPED | WS_BORDER;

在 主 应 用 程 序, 即 含 有 定 义theApp 全 程 变 量 的.cpp 文 件 中, 使 用 工 具 条 上 的 函 数 下 拉 列 表 框 找 到InitInstance() 函 数。 在“pDocTemplate = new CSingleDocTemplate” 一 句 中, 用NULL 替 换IDR_MAINFRAME。 如 下 段 程 序 所 示。 BOOL CYourMainApp::InitInstance()

{

//.....此处略去一部分无关语句

CSingleDocTemplate* pDocTemplate;

pDocTemplate = new CSingleDocTemplate(

NULL, //IDR_MAINFRAME,

//用NULL替换IDR_MAINFRAME

RUNTIME_CLASS(CNoBarDoc),

RUNTIME_CLASS(CMainFrame),

// main SDI frame window

RUNTIME_CLASS(CNoBarView));

AddDocTemplate(pDocTemplate);

//.....此处略去一部分无关语句

}

找 到Visual C++ 编 辑 器 的 工 具 条 上 的 编 译 方 式 下 拉 列 表 框, 选 择Win32 Release, 生 成Release 版 本 的 应 用 程 序。

---- 至 此, 我 们 就 得 到 了 不 含 菜 单、 工 具 条 和 状 态 条 结 构 的 应 用 程 序。

实 现 操 作 过 程 提 示 对 话 框 的 一 种 方 法 ---- 在 使 用Windows95 进 行 文 件 拷 贝 或 者 删 除 操 作 时, 您 一 定 见 到 过 那 种 具 有 飞 文 件 动 画 的 操 作 过 程 提 示 对 话 框。 这 一 功 能 的 加 入 不 仅 使 我 们 能 够 在 操 作 过 程 当 中 随 时 取 消 操 作, 而 且 也 使 文 件 拷 贝 或 者 删 除 操 作 变 得 生 动 活 泼。 其 实, 在 使 用Visual C++ 进 行 应 用 程 序 设 计 时, 我 们 也 可 以 使 用 下 述 方 法 在 适 当 位 置 加 入 自 己 的 操 作 过 程 提 示 对 话 框。

为 每 一 个 操 作 过 程 提 示 对 话 框 创 建 一 个 对 话 框 类。 为 了 下 面 叙 述 方 便, 我 们 只 假 设 应 用 程 序 需 要 一 个 操 作 过 程 提 示 对 话 框 并 以“CModel” 作 为 对 应 的 对 话 框 类 的 名 字。

使 用Visual C++ 提 供 的 资 源 编 辑 器 编 辑 提 示 对 话 框, 比 如 加 入 一 些 文 字 说 明 和 动 画 等。

在CModel 类 的 头 文 件(Model.h) 中, 加 入 两 个 成 员 变 量,

CWnd* m_pParent; // 指 向 调 用 该 提 示 对 话 框 的 框 架 类( 或 对 话 框 类), 即 它 的“ 父 类” int m_nID;// 记 录 该 提 示 对 话 框 的ID 号

以 及 下 面 两 个 成 员 函 数:

CModel(CWnd* pParent = NULL); // 舍 弃 原 有 的 构 造 函 数, 或 者 把 原 函 数 修 改 成 这 种 无 模 式 对 话 框 的 构 造 函 数

BOOL Create(); // 该 函 数 将 调 用 创 建 基 类 的Create() 函 数 创 建 对 话 框

在Model.cpp 文 件 中, 加 入 相 应 函 数 的 实 现 部 分。 CModel::CModel(CWnd* pParent /*=NULL*/)

: CDialog(CModel::IDD, pParent)

{

m_pParent=pParent;

m_nID=CModel::IDD;

//{{AFX_DATA_INIT(CModel)

// NOTE: the ClassWizard will add member initialization here

//}}AFX_DATA_INIT

}

BOOL CModel::Create()

{

return CDialog::Create(m_nID,m_pParent);

}

同 时 按 下Ctrl 和W 键 或 直 接 单 击 工 具 条 上 的ClassWizard 按 钮, 打 开ClassWizard 对 话 框。 在 类 名(Class name) 列 表 框 中 选 择 该 提 示 对 话 框 类, 在Object IDs 列 表 框 中 选 择 该 类 的 类 名 后, 在 消 息(Messages) 列 表 框 中 选 择PostNcDestroy 消 息 并 双 击 它, 这 时ClassWizard 就 会 在 该 对 话 框 类 中 加 入 一 个PostNcDestroy() 函 数。 该 函 数 将 会 在 对 话 框 窗 口 消 失 后, 由OnNcDestroy() 函 数 调 用。 因 此, 可 以 在 该 函 数 中 加 入 一 些 扫 尾 工 作, 例 如 数 据 传 送, 释 放 指 针 空 间 等。 void CModel::PostNcDestroy()

{

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

delete this;

CDialog::PostNcDestroy();

}

在 要 调 用 提 示 对 话 框 类 的 类 的 头 文 件 中, 先 包 含(#include)CModel 类 的 头 文 件, 再 声 明 一 个 指 向CModel 类 的 对 象 的 指 针, 如m_Dlg, 并 在 该 类 的 构 造 函 数 中, 加 入“m_Dlg = NULL;” 一 句。 然 后, 在 打 开 和 关 闭 提 示 对 话 框 的 函 数 中 加 入 如 下 一 段 程 序: if (m_Dlg==NULL) {//如果当前没用提示对话框在活动,就创建一个

m_Dlg = new CModel(this);

m_Dlg->Create();

GetDlgItem(IDC_EXPORT)->EnableWindow(FALSE);

}

else//否则就激活它

m_Dlg->SetActiveWindow();

另外,再在要关闭提示对话框的地方,加入如下语句:

m_Dlg->DestroyWindow();

m_Dlg=NULL;

---- 至 此, 您 已 经 拥 有 了 自 己 的 过 程 操 作 提 示 对 话 框。 不 过, 它 还 不 具 有 动 画 和 随 时 取 消 操 作 的 功 能。 您 不 妨 尝 试 着 加 入 这 些 功 能。 另 外, 笔 者 也 曾 尝 试 过 用 下 面 介 绍 的 方 法 实 现 过 程 操 作 提 示 对 话 框。 两 种 方 法 比 较, 可 谓 各 有 千 秋。 如 果 您 希 望 上 面 设 计 的 过 程 提 示 对 话 框 能 够 被 多 个 应 用 程 序 共 享, 那 么 最 好 把 提 示 对 话 框 作 为 独 立 的 进 程 来 调 用。 但 是, 当 您 还 希 望 在 提 示 对 话 框 与 调 用 者 之 间 传 输 数 据 的 话, 似 乎 这 一 部 分 介 绍 的 实 现 方 法 更 简 洁 且 更 有 效。

应 用 进 程 实 现 对 其 他 应 用 程 序 的 调 用 ---- 在 我 们 设 计 的 应 用 程 序 中, 很 可 能 会 用 到 其 他 应 用 程 序 来 完 成 某 一 特 定 功 能。 例 如, 当 我 们 为 了 便 于 数 据 的 传 输 而 对 诸 多 文 件 进 行 压 缩 和 解 压 缩 时, 一 种 作 法 是 我 们 自 己 设 计 一 个 这 样 的 压 缩/ 解 压 缩 程 序, 然 后 以 动 态 链 接 库(DLL) 或 者 函 数 库 的 形 式 由 主 应 用 程 序 调 用。 但 更 方 便 而 且 高 效 的 作 法 是 利 用 现 有 的 这 方 面 的 优 秀 软 件, 比 如ARJ.EXE, 并 以 进 程 的 形 式 调 用 它, 再 在 适 当 时 候 关 闭 它。 下 面 将 以 上 面 所 述 为 例, 具 体 介 绍 后 一 种 方 法 的 实 现 过 程。

在 需 要 调 用ARJ.EXE 进 行 压 缩/ 解 压 缩 的 类 中, 创 建 一 个 成 员 函 数, 不 妨 称 作CreateBat(), 其 作 用 是 生 成 一 个 批 处 理 文 件。 由 该 批 处 理 文 件 调 用ARJ.EXE, 并 给 出 具 体 压 缩/ 解 压 缩 参 数。 之 后, 再 利 用MS-DOS 的DIR 命 令 生 成 一 个 临 时 文 件, 以 作 为 压 缩/ 解 压 缩 工 作 完 成 的 标 志。 void CMyCompress:: CreateBat(CString BatPath,CString ArjPath,

CString BatName,CString ArjFileName,

CString TempPath,CString ExitFlag,BOOL out)

{

LPTSTR lpBuffer;

UINT uSize;

HANDLE hHeap;

uSize=(GetCurrentDirectory(0,NULL))*sizeof(TCHAR);

hHeap=GetProcessHeap();

lpBuffer=(LPSTR)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,uSize);

GetCurrentDirectory(uSize,lpBuffer);

//得知当前目录信息,以便根据需要变换目录

if (lpBuffer!=BatPath) //diferent dir

SetCurrentDirectory(BatPath);

CStdioFile f;

CFileException e;

if (!f.Open( BatName, CFile::modeCreate|CFile::modeWrite, &e))

//以BatName的内容创建一个批处理文件

{

AfxMessageBox("不能创建文件"+BatName);

return ;

}

char density[6];

sprintf(density,"%d",mTotalBytes);

---- //mTotalBytes 是 由 其 他 函 数 设 定 的 变 量, 用 于 记 录 用 于 拷 入 或 拷 出 文 件 的 磁 盘 所 具 有 的 最 大 可 用 空 间

CString Density=density;

CString string;

if (out)//说明是生成做压缩工作的批处理文件

string="arj a -v"+Density;

else //说明是生成做解压缩工作的批处理文件

string="arj e -v"+Density;

string+=" ..\\"+ArjPath+"\\"+ArjFileName+" ";

if (out)

string=string+"..\\"+TempPath+"\\*.* -y -jm\n";

else

string=string+"..\\"+TempPath+"\\ -y -jm\n";

f.WriteString(string);

string="dir >"+ExitFlag+"\n";

f.WriteString(string);

f.Close();

SetCurrentDirectory(lpBuffer);//回复到原来的目录下

}

---- 该 函 数 执 行 后, 将 生 成 一 个 批 处 理 文 件, 内 容 大 致 是:

---- ARJ A -V1440 压 缩 后 文 件 的 路 径 名+ 文 件 名 被 压 缩 文 件 的 路 径 名+ 文 件 名 -Y -JM

---- DIR > 临 时 文 件 名

---- 或 者 是:

---- ARJ E -V1440 被 解 压 缩 文 件 的 路 径 名+ 文 件 名 解 压 缩 后 文 件 的 路 径 名+ 文 件 名 -Y -JM

---- DIR > 临 时 文 件 名

在 需 要 调 用ARJ.EXE 进 行 压 缩/ 解 压 缩 的 类 中, 再 创 建 一 个 成 员 函 数, 不 妨 称 作RunBat(), 其 作 用 是 创 建 和 执 行 进 程 来 运 行 上 述 所 生 成 的 批 处 理 文 件, 并 在 适 当 时 候 撤 消 进 程。 void CMyCompress::RunBat(CString

BatPath,CString fileName,CString ExitFlag)

{

CString lpApplicationName=BatPath+"\\"+fileName;

// 进 程 执 行 的 应 用 程 序 的 完 全 路 径 名

STARTUPINFO StartupInfo;// 创 建 进 程 所 需 的 信 息 结 构 变 量

GetStartupInfo(&StartupInfo);

StartupInfo.lpReserved=NULL;

StartupInfo.lpDesktop=NULL;

StartupInfo.lpTitle=NULL;

StartupInfo.dwX=0;

StartupInfo.dwY=0;

StartupInfo.dwXSize=200;

StartupInfo.dwYSize=300;

StartupInfo.dwXCountChars=500;

StartupInfo.dwYCountChars=500;

StartupInfo.dwFlags=STARTF_USESHOWWINDOW;

StartupInfo.wShowWindow=SW_HIDE;

// 说 明 进 程 将 以 隐 藏 的 方 式 在 后 台 执 行

StartupInfo.cbReserved2=0;

StartupInfo.lpReserved2=NULL;

StartupInfo.hStdInput=stdin;

StartupInfo.hStdOutput=stdout;

StartupInfo.hStdError=stderr;

LPTSTR lpBuffer;

UINT uSize;

HANDLE hHeap;

uSize=(GetCurrentDirectory(0,NULL))*sizeof(TCHAR);

hHeap=GetProcessHeap();

lpBuffer=(LPSTR)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,uSize);

GetCurrentDirectory(uSize,lpBuffer);

// 得 知 当 前 目 录 信 息, 以 便 根 据 需 要 变 换 目 录

if (lpBuffer!=BatPath) //diferent dir

SetCurrentDirectory(BatPath);

// 创 建 进 程

if (CreateProcess(lpApplicationName,NULL,NULL,

NULL,FALSE,CREATE_DEFAULT_ERROR_MODE,

NULL,NULL,&StartupInfo,&pro_info))

{

MSG Message;

DeleteFile(ExitFlag);

SetTimer(1,100,NULL);// 设 置 计 时 器

Search=TRUE;

while(Search) {

if (::PeekMessage(&Message,NULL,0,0,PM_REMOVE)) {

::TranslateMessage(&Message);

::DispatchMessage(&Message);

}

}

// 进 程 结 束 前 后 的 处 理 工 作

DWORDExitCode;

if (!GetExitCodeProcess(pro_info.hProcess,&ExitCode))

AfxMessageBox("GetExitCodeProcess is Failed!");

if (!TerminateProcess(pro_info.hProcess,(UINT)ExitCode))

// 终 止 进 程

AfxMessageBox("TerminateProcess is Failed!");

if (!CloseHandle(pro_info.hProcess))

// 释 放 被 终 止 进 程 的 句 柄

AfxMessageBox("CloseHandle is Failed!");

KillTimer(1);// 撤 消 计 时 器

}

else AfxMessageBox("Process Is Not Created!");

SetCurrentDirectory(lpBuffer);// 回 复 到 原 来 的 目 录 下

}

同 时 按 下Ctrl 和W 键 或 直 接 单 击 工 具 条 上 的ClassWizard 按 钮, 打 开ClassWizard 对 话 框。 在 类 名(Class name) 列 表 框 中 选 择 需 要 调 用ARJ.EXE 进 行 压 缩/ 解 压 缩 的 类, 在Object IDs 列 表 框 中 选 择 该 类 的 类 名 后, 在 消 息(Messages) 列 表 框 中 选 择WM_TIMER 消 息 并 双 击 它, 这 时ClassWizard 就 会 在 该 类 中 加 入 一 个OnTimer() 函 数。 该 函 数 将 以 一 定 的 时 间 间 隔 检 查 压 缩/ 解 压 缩 程 序 是 否 已 经 执 行 完 毕, 即 检 查 作 为 标 志 的 临 时 文 件 是 否 已 经 存 在, 并 及 时 修 改 状 态 变 量“Search”, 以 便 通 知RunBat() 函 数 结 束 进 程。 void CMyCompress::OnTimer(UINT nIDEvent)

{

// TODO: Add your message handler code here and/or call default

CFile file;

CFileException Error;

if (file.Open(ExitFlag,CFile::modeRead,&Error)) {

Search=FALSE;

file.Close();

}

}

自 编 删 除 目 录 及 其 下 属 文 件 的 函 数 ---- 高 版 本 的MS-DOS 和Windows 95 都 提 供 了 一 个 可 以 删 除 一 个 或 多 个 目 录 及 其 下 属 文 件 和 目 录 的 命 令, 即DeleteTree 命 令。 然 而, 无 论 在MFC 类 库 还 是 在Win32 函 数 库 中, 都 没 有 相 应 的 函 数 与 之 对 应。 这 样, 当 我 们 在 自 己 设 计 的 应 用 程 序 中 需 要 用 到DeleteTree 的 功 能 时, 自 然 想 到 的 方 法 是 通 过 进 程 调 用 或 者 系 统 调 用 的 方 式( 正 如 上 面 部 分 所 述 的 那 样) 调 用MD-DOS 或Windows 95 下 的DeleteTree 命 令。 然 而,Win32 函 数 库 已 经 为 我 们 提 供 了 多 种 用 于 文 件 和 目 录 操 作 的 函 数, 利 用 它 们 不 难 设 计 出 自 己 的DeleteTree() 函 数。

---- 读 者 读 到 这 里, 也 许 会 感 到 有 些 疑 惑, 为 什 么 第 六 部 分 强 调 进 程 调 用 优 于 自 我 设 计 的 函 数, 而 这 一 部 分 又 反 了 过 来 ? 是 的, 在 通 常 情 况 下, 调 用 应 用 程 序 内 部 的 函 数 比 使 用 进 程 或 者 调 用 外 部 函 数 更 灵 活 并 且 可 以 提 高 执 行 效 率, 也 便 于 修 改。 所 以, 象DeleteTree() 这 样 的 功 能, 利 用 现 有 的 函 数 并 不 难 实 现, 自 然 就 最 好 通 过 内 部 函 数 的 方 式 来 完 成。 然 而, 象 设 计 一 个 压 缩/ 解 压 缩 这 样 的 函 数 的 工 作 量, 并 不 比 通 过 进 程 调 用 来 使 用 现 成 品 的 开 销 更 合 算, 因 为 它 至 少 需 要 我 们 了 解 压 缩/ 解 压 缩 的 复 杂 算 法, 而 且 调 试 和 维 护 它 也 需 要 一 定 代 价。 于 是, 这 个 时 候, 还 是 采 用“ 拿 来 主 义” 为 好。

---- 下 面, 给 出 我 自 己 设 计 的DeleteTree() 函 数, 仅 供 参 考。

BOOL DeleteTree(CString DirName)

{ //成功:返回TRUE;否则,返回FALSE

BOOL Result;

Result=PreRemoveDirectory(DirName)

&& RemoveDirectory(DirName);

return Result;

}

BOOL PreRemoveDirectory(CString DirName)

{//成功:返回TRUE;否则,返回FALSE

LPTSTR lpBuffer;

UINT uSize;

CString fileName;

HANDLE hHeap;

BOOL result;

HANDLE hFindFile;

WIN32_FIND_DATAFindFileData;

uSize=(GetCurrentDirectory(0,NULL))*sizeof(TCHAR);

hHeap=GetProcessHeap();

lpBuffer=(LPSTR)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,uSize);

GetCurrentDirectory(uSize,lpBuffer);

if (lpBuffer!=DirName) {//调整当前目录

SetCurrentDirectory(DirName);

}

hFindFile=FindFirstFile("*.*",&FindFileData);

CString tFile;

if (hFindFile!=INVALID_HANDLE_VALUE) {

do {

tFile=FindFileData.cFileName;

if ((tFile==".")||(tFile=="..")) continue;

if (FindFileData.dwFileAttributes==

FILE_ATTRIBUTE_DIRECTORY){

if (DirName[DirName.GetLength()-1]!='\\')

PreRemoveDirectory(DirName+'\\'+tFile);

else

PreRemoveDirectory(DirName+tFile);

if (!RemoveDirectory(tFile))

result=FALSE;

else

result=TRUE;

}

else

if (!DeleteFile(tFile)) result=FALSE;

else result=TRUE;

}

while (FindNextFile(hFindFile,&FindFileData));

FindClose(hFindFile);

}

else {

SetCurrentDirectory(lpBuffer);

return FALSE;

}

SetCurrentDirectory(lpBuffer); //回复到原来的目录下

return result;

}

如 何 得 到 并 修 改 各 驱 动 器 的 信 息 ---- 在 设 计 和 文 件 输 入/ 输 出 有 关 的 应 用 程 序 时, 我 们 很 可 能 在 输 入/ 输 出 文 件 前, 需 要 了 解 一 下 源 驱 动 器 或 者 目 标 驱 动 器 的 各 项 信 息, 比 如 是 否 有 磁 盘 在 软 驱 中, 它 是 否 已 打 开 写 保 护, 以 及 现 有 磁 盘 的 容 量 等。 遗 憾 的 是,MFC 类 库 中 没 有 提 供 支 持 这 些 功 能 的 类, 所 以 我 们 只 能 通 过Win32 提 供 的 函 数 来 完 成 我 们 的 要 求。 下 面, 我 根 据 自 己 的 编 程 实 践, 通 过 几 段 程 序, 来 说 明 如 何 利 用Win32 提 供 的 函 数 实 现 对 驱 动 器 的 操 作。 读 者 可 以 根 据 自 己 的 需 要, 把 介 绍 的 函 数 稍 加 修 改 后, 即 可 插 入 到 自 己 设 计 的 应 用 程 序 中 去。

下 面 程 序 的 功 能 是 搜 索 计 算 机 中 所 有 驱 动 器, 选 择 出 其 中 软 盘 驱 动 器 的 驱 动 器 号, 依 次 加 入 到 一 个 下 拉 列 表 框 中。 void FindDriverInfo()

{

CComboBox* Driver=(CComboBox*)GetDlgItem(IDC_DRIVER);

DWORD dwNumBytesForDriveStrings;

HANDLE hHeap;

LPSTR lp;

CString strLogdrive;

int nNumDrives=0, nDriveNum;

dwNumBytesForDriveStrings=GetLogicalDriveStrings(0,NULL)

*sizeof(TCHAR);//实际存储驱动器号的字符串长度

if (dwNumBytesForDriveStrings!=0) {

hHeap=GetProcessHeap();

lp=(LPSTR)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,

dwNumBytesForDriveStrings);//

GetLogicalDriveStrings(HeapSize(hHeap,0,lp),lp);

StringBox.SetSize(dwNumBytesForDriveStrings/sizeof(TCHAR)+1);

while (*lp!=0) {

if (GetDriveType(lp)==DRIVE_REMOVABLE){

Driver->AddString(lp);

StringBox[nNumDrives]=lp;

nNumDrives++;

}

lp=_tcschr(lp,0)+1;

}

}

else AfxMessageBox("Can't Use The Function GetLogicalDriveStrings!");

}

下 面 介 绍 的EmptyDiskSpace() 函 数 主 要 负 责 清 空 指 定 驱 动 器 中 的 磁 盘, 同 时 它 还 负 责 记 录 指 定 驱 动 器 中 磁 盘 的 容 量, 并 得 到 该 磁 盘 的 序 列 号。 在 该 函 数 中, 还 将 调 用 第 七 部 分 提 到 的PreRemoveDirectory() 函 数, 来 完 成 清 空 工 作。 BOOL EmptyDiskSpace(CString Driver)

{

BOOLresult=TRUE;

DWORDSectorsPerCluster;// address of sectors per cluster

DWORDBytesPerSector;// address of bytes per sector

DWORDNumberOfFreeClusters;// address of number of free clusters

DWORDTotalNumberOfClusters;

DWORDTotalBytes;

DWORDFreeBytes;

intbContinue=1;

char DiskVolumeSerialNumber[30];

//存储驱动器内当前磁盘的序列号

LPCTSTRlpRootPathName;

// address of root directory of the file system

LPTSTRlpVolumeNameBuffer=new char[12];

// address of name of the volume

DWORDnVolumeNameSize=12;

// length of lpVolumeNameBuffer

DWORDVolumeSerialNumber;

// address of volume serial number

DWORD MaximumComponentLength;

// address of system's maximum filename length

DWORD FileSystemFlags;

// address of file system flags

LPTSTRlpFileSystemNameBuffer=new char[10];

// address of name of file system

DWORDnFileSystemNameSize=10;

// length of lpFileSystemNameBuffer

lpRootPathName=Driver;

while (1){

if (GetDiskFreeSpace(Driver, &SectorsPerCluster,

&BytesPerSector, &NumberOfFreeClusters,

&TotalNumberOfClusters))

{//驱动器中有磁盘

TotalBytes=SectorsPerCluster*BytesPerSector

*TotalNumberOfClusters;//磁盘总容量

FreeBytes=SectorsPerCluster*BytesPerSector

*NumberOfFreeClusters;//磁盘空闲空间容量

GetVolumeInformation(lpRootPathName,

lpVolumeNameBuffer, nVolumeNameSize,

&VolumeSerialNumber,

&MaximumComponentLength,

&FileSystemFlags,

lpFileSystemNameBuffer, nFileSystemNameSize);

sprintf(DiskVolumeSerialNumber,"%X",VolumeSerialNumber);

//得到驱动器内当前磁盘的序列号

SetmTotalBytes(TotalBytes/1024);//存储指定驱动器中磁盘的容量

if (TotalBytes!=FreeBytes){//当磁盘总容量不等于空闲空间容量时,

应该执行清空操作

while (bContinue) {

if ((bContinue==2)||(MessageBox

("在驱动器 "+m_Driver+"中的磁盘尚存有数据.

\n您愿意让系统为您删除它们吗?",

"提问",MB_YESNO|MB_ICONQUESTION)==IDYES))

if (!PreRemoveDirectory(Driver))//无法执行清空操作

if (MessageBox("因某种原因系统无法删除

在驱动器 "+m_Driver+"中的磁盘上的数据.

\n请检查磁盘是否没有关闭写保护.

\n您愿意再试一次吗?",

"问题",MB_YESNO|MB_ICONERROR)==IDYES) {

bContinue=2;

continue;

}

else {

bContinue=0;

result=FALSE;

}

else {

MessageBox("成功删除磁盘上的数据!",

"提示信息",MB_OK|MB_ICONINFORMATION);

bContinue=0;

result=TRUE;

}

else {//THE FIRST IF'S ELSE

bContinue=0;

result=FALSE;

}

}

}

else result=TRUE;

break;

}

else {

if (MessageBox("没有磁盘在驱动器 "+m_Driver+"中.

\n您愿意插入一张磁盘再来一次吗?",

"问题",MB_YESNO|MB_ICONASTERISK)==IDYES)continue;

else break;

}

}//END OF WHILE

return result;

}

在MS-DOS 和Windows95 中, 磁 盘 卷 标 最 多 由11 个 字 符 组 成, 并 且 字 母 的 大 小 写 不 加 区 分。 当 需 要 设 定 指 定 驱 动 器 中 磁 盘 的 卷 标 时, 只 要 调 用Win32 的SetVolumeLabel() 函 数 即 可, 并 在 第 一 个 参 数 中 指 明 磁 盘 所 在 的 驱 动 器 号, 在 第 二 个 参 数 中 指 明 新 的 卷 标 号。 例 如,SetVolumeLabel(DriverNum, NewVolumeLabel)。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有