VC6.0实现逆向操作并防止界面闪烁

浪潮CS5280H服务器UEFI下配置RAID卡,保姆级图文教程(含9361-8i等型号) 本文提供浪潮CS5280H服务器在UEFI环境下配置RAID卡的详细图文教程,涵盖9361-8i等型号。从准备工作到RAID级别选择、磁盘配置及性能优化,每个步骤均配有清晰说明和截图,帮助IT管理员和技术人员快速完成RAID设置,避免常见错误。 阅读详情
   在系统编程中,使用VC是很好的开发工具,而对于一个成熟的系统,几乎都需要有回退与重做功能(即文档操作逆向化)以防止用户误操作或不合适的操作,从而提高系统的友好性和可操作性。在很多VC技术文章中均提到过这个问题,不过总存在着界面闪烁或不完全可逆.

  本文提出一种对系统编程可实现完全可逆并防止闪屏的方法.

  一、基本原理

  要对文档进行回退重做功能,要做两方面的工作,一方面要保留删除的文档(在操作过程中,删除的文档资料一定能够保留),另一方面,系统必须能够记录进行文档操作的全过程及每个操作过程的参数。为了保留历史操作,所有数据非常占用内存空间,这就是一些系统只能进行有限次退步逆向操作的原因。本文提出的方法建立如下存储机制:建一个临时文件储存数据模拟堆栈,进行一次操作时将相关操作数据入栈.回退一次将相关数据弹出栈,重做一次又依据相关数据重新恢复原有数据.它的好处是在回退和重做时只入一次栈即申请一次内存。

  堆栈的数据排放如图:

  // Undo、Redo 数据排放示意图(m_UndoDataList)

//

// ====

// |###| }

// |###| }

// |###| } ----->> Redo 数据

// |###| }

// |###| }

// |///| }

// |///| }

// |///| }

// |///| } --->> Undo 数据(Undo数据弹出后将转换为Redo数据)

// |///| }

// |///| }

// =====

// Undo数据栈
  二、实现文档回退重做的引擎

  建一文档逆向化堆栈引擎.主要代码为:

  1.建立临时文件.(m_TempPath可以按照某种规则形成路径)

if(m_File.Open((LPCTSTR)m_TempPath, CFile::modeCreate|CFile::modeReadWrite|CFile::shareExclusive))

{

 m_File.SeekToBegin();

 m_UndoCount = 0; file://当前可重做的步数

 m_RedoCount = 0; file://当前可回退的步数



  2.保存回退数据模块.

// 保存一个Undo数据块(由用户提供)

int CRedoUndoEngine::PushData(

LPVOID pData,
// 由用户提供的内存块首地址,其中含有用户定义的待保存的数据。

// (注:如果函数成功,此内存块将会被本函数释放,因此,该内存块必须是用::GlobalAlloc()函数分配的)

DWORD size, // pData指向的内存块尺寸

DWORD param1,
// 用户提供的对该内存块的说明参数,含义由用户定义

DWORD param2,
// 用户提供的对该内存块的说明参数,含义由用户定义

int *pIndex
// 如果成功,本函数将返回压入的Undo块在栈中的索引值。
  如果不需要此返回值,可用NULL作为参数

)

{

// 删除Redo数据

if (m_RedoCount)

{

 while(m_RedoCount--)

  delete (LPISEEUNDOINFO)m_UndoDataList.RemoveTail();

  m_RedoCount = 0;

 }

// 填写Undo数据的索引信息(lpISeeUndoInfo为一个保存数据的结构体)

lpISeeUndoInfo->m_index = m_UndoCount; // 索引

lpISeeUndoInfo->m_UserData1 = param1;
// 用户定义的标识性数据1

lpISeeUndoInfo->m_UserData2 = param2;
// 用户定义的标识性数据2

lpISeeUndoInfo->m_DataSize = size; // 用户的Undo数据块尺寸

lpISeeUndoInfo->m_FilePosition =
    _get_current_overwrite_pos();

// 加新的Undo数据到Undo栈的尾部

m_UndoDataList.AddTail((void*)lpISeeUndoInfo);


// 将用户的Undo数据写入临时文件

m_File.Seek(lpISeeUndoInfo->m_FilePosition, CFile::begin);

m_File.Write((const void *)pData, size);

并使Undo块计数加1

m_UndoCount++;

// 此时用户传过来的数据块已经无用,删除!

::GlobalFree(pData);

return 1;

}

  3.弹出重做数据模块.

// 弹出一个Redo数据块

int CIUndoEngine::RedoData(

LPVOID *ppData, // 用于接收本函数返回的含有最近一个Redo数据的内存块首地址的指针

// (注:此内存块交由调用者释放,使用::GlobalFree()函数)

DWORD *pSize, // ppData内存块的尺寸(in byte) ,如果不需要此数据可用NULL作为参数

DWORD *pParam1, // 返回用户对该Redo块的附加信息,如果不需要此数据可用NULL作为参数

DWORD *pParam2, // 返回用户对该Redo块的附加信息,如果不需要此数据可用NULL作为参数

int *pIndex // 返回本Redo块的索引,如果不需要此数据可用NULL作为参数

)

{

if (!m_RedoCount)

return 0;

// 锁定待弹出的Redo索引信息块的地址

POSITION pos = m_UndoDataList.FindIndex(m_UndoCount);

ASSERT(pos);

LPISEEUNDOINFO lpISeeUndoInfo= (LPISEEUNDOINFO)m_UndoDataList.GetAt(pos);

ASSERT(lpISeeUndoInfo);

ASSERT(lpISeeUndoInfo->m_index == m_UndoCount);

if (!(*ppData))

return -1;



// 读出用户保存在临时文件中的Undo数据(也即Redo数据)

m_File.Seek((LONG)lpISeeUndoInfo->m_FilePosition, CFile::begin);

m_File.Read(*ppData, lpISeeUndoInfo->m_DataSize);

m_UndoCount++; // 可用Undo数据块个数加1

m_RedoCount--; // 可用Redo数据块个数减1

if (pSize)

*pSize = lpISeeUndoInfo->m_DataSize;

if (pParam1)

*pParam1= lpISeeUndoInfo->m_UserData1;

if (pParam2)

*pParam2= lpISeeUndoInfo->m_UserData2;

if (pIndex)

*pIndex = m_RedoCount;// 注:此处的索引是Redo的索引,而不是Undo的

return 1;

}

  由这个文档逆向化操作引擎,可以获得当前改动的文档的数据,并根据改动的数据更新视图,而不刷新没有更改数据的视图.从而防止了闪烁的产生.
 

  三、简单开发实例

  下面以我们开发服装CAD过程中加入的回退重做功能(文档逆向化)说明之。

  1.定义回退类型

#define REUNDO_MOV 0x0001  file://衣片移动回退重做

#define REUNDO_SEL 0x0002  file://衣片选择回退重做

……….

  2.保存某个操作之前和之后的数据(以衣片移动回退重做为例)

//----------申请内存----------------------//

int nByte = 4*sizeof(DWORD);

HGLOBAL hMem = GlobalAlloc(GMEM_FIXED,nByte);

LPVOID pData = (LPVOID) GlobalLock(hMem);

file://-----保存衣片移动前后的位置读入内存------//用移动前后衣片的某个坐标点表示

memcpy((DWORD*)pData, &m_oldPoint, 2*sizeof(DWORD));

memcpy((DWORD*)pData+2,&point, 2*sizeof(DWORD));

file://--------数据入栈---------------------------------------//

m_pReUndoEngine->PushData(pData,//衣片m_pReUndoEngine文档逆向化引擎对象指针

nByte,//保存数据衣片字节数

REUNDO_MOV,//回退类型

NULL,NULL);

  3.当回退操作事件触发时.

//弹出回退值

int nByte = m_pReUndoEngine->GetPopDataSize();

HGLOBAL hMem = GlobalAlloc(GMEM_FIXED,nByte);//申请内存

LPVOID pData = (LPVOID) GlobalLock(hMem);

DWORD undo_type;DWORD index;

m_pReUndoEngine->PopData(&pData,NULL,&undo_type,&index);

////////////////////////////////

switch(undo_type){//回退类型

 case REUNDO_SEL:

  SelUndo(pData,index,&dc);break;

 case REUNDO_MOV:

  MovUndo(pData);break;

  …………

}



void CMarkView::MovUndo(LPVOID pData) 函数功能

{

 CPoint pt1,pt2;

 memcpy(&pt1,(DWORD*)pData,8);

 memcpy(&pt2,(DWORD*)pData+2,8);

 …….由pt1 和pt2可以求出位移量,从而恢复原衣片的位置.

}

  4.当重做操作事件触发时

//弹出回退值

int nByte = m_pReUndoEngine->GetRedoDataSize();

HGLOBAL hMem = GlobalAlloc(GMEM_FIXED,nByte);//申请内存

LPVOID pData = (LPVOID) GlobalLock(hMem);

DWORD undo_type;DWORD index;

m_pReUndoEngine->RedoData(&pData,NULL,&undo_type,&index);

switch(undo_type){//回退类型

 case REUNDO_SEL:

  SelRedo(pData,index,&dc,nByte);break;
 
 case REUNDO_MOV:

  MovRedo(pData); break;

  …………

}

  函数MovRedo(pData)与MovUndo(pData)类似就不多说了.

  由3,4可以看出,在回退与重做过程中,只是保存和取出操作对象已变化的过程,使编程者很容易实现高效率刷新与充分节约存储空间.

  小结

  在系统编程中,文档的回退与重做几乎是必不可少的,本文提出了一种思路,即对文档的各种操作分解,并把每种操作下变化的对象的数据值保存于临时文件 (栈)中,在回退与重做时根据变化量很容易恢复操作之前状态或重做, 避免了有些系统(保存全部文档数据)占用大量内存空间而只能有限次文档逆向化,并且全部刷新而闪烁,破坏了界面的友好性。
VC6.0反汇编代码 //C代码如下所示: #include int add(int a, int b) { return a+b; } int main( void ) { int a, b, c; a=1; b=2; c=add(a, b); prinit("%d\n", c); return 0; } //几个寄存器的含义 ebp:基址指针 esp:堆栈指针 阅读详情

相关推荐

自学ROS完成智能小车路径规划(一)--配置功能包

此系列文章记录本人学习ros的过程,将会尽可能详细以便自己能够看懂 参考系列:古月居老师,CSDN,ROS tutorials,科大讯飞智能车竞赛线上赛 本文章的目标: 比较全局路径规划算法中A*算法与Dijkstra算法在该地图场景下的规划与运行时间 比较局部路径规划算法中DWA算法与TEB算法在该地图场景下的规划与运行时间 在同等参数条件下选择出各自适合的算法进行融合,经过比较,我将选择dijkstra算法作为全局路径规划算法,TEB算法为局部路径规划算法 第一步,按照科大讯飞的教程配置文件 科大讯

weixin_42621524的博客 9346

VC++实现多步Undo/Redo(撤销/恢复)功能源代码

内容索引:VC/C++源码,系统相关,撤销  VC++实现多步Undo/Redo(撤销/恢复)功能源代码,这个应该不需要多解释了吧?就是实现按下键盘CTRL+Z实现的连续撤销及恢复功能,很多软件中都有这两组快捷键。

CAPL未来发展方向展望

通过本文的学习,读者应该对CAPL的未来发展方向有了初步的了解。随着汽车电子系统的不断发展,CAPL也在不断演进,以支持更多的技术和应用场景。希望读者能够通过不断的学习和实践,掌握更多的CAPL技巧,提高自己的开发能力。

闲人编程的博客 1145

基于VC平台下C++反汇编与逆向分析研究——No.1

首先感谢小生我怕怕大神,这个是他的随笔,作为一个业余爱好者,确实挺喜欢这门技术,所以做了这个系列的转载,后面会慢慢更新! 不过时间有限,一边考研,为了给自己枯燥的生活带来点乐趣,故选择随便看些东西! ———————————————————————————————————————————————— 分析环境:WIN7sp1 所用工具:VC++6.0/OllyDBG/IDA 适用人群

三缺 4743

解决vc界面闪烁问题

这是个老生常谈的问题,有过vc编写界面的经验的人大都遇过,至于问题产生的原因,网上已有太多描述,这里只给出几个解决方法的建议。 1、双缓冲,这个是基本是必须的处理方式,同时最好处理WM_ERASEBKGND消息。 2、有些情况尽管使用了双缓冲,但是在窗口拉伸的时候还是有闪烁的情况,例如界面控件很复杂,基本都为自绘控件时。这时窗口的WS_CLIPCHILDREN | WS_CLIPSIBLING

码农的世界 1313

逆向基础---vc汇编(一)

首先介绍我们会经常看到的一些寄存器: 4个数据寄存器(EAX、EBX、ECX和EDX) 2个变址和指针寄存器(ESI和EDI) 2个指针寄存器(ESP和EBP)     4个数据寄存器(EAX、EBX、ECX和EDX): 32位CPU有4个32位的通用寄存器EAX、EBX、ECX和EDX。对低16位数据的存取,不会影响高16位的数据。这些低16位寄存器分别命名为:AX、BX、CX和D

songtzu的专栏 1240

Visual Basic 6 逆向工程与反逆向工程 (2)

<!--google_ad_client = "pub-2947489232296736";/* 728x15, 创建于 08-4-23MSDN */google_ad_slot = "3624277373";google_ad_width = 728;google_ad_height = 15;//--><script type="text/javascript"

zgqtxwd的专栏 938

关于Visual InterDev 6.0 调试ASP工程的个人方法。

关于Visual InterDev 6.0 调试ASP工程的个人方法。2004-12-1 苗涛运行环境: Winxp+Sp2,Visual Studio 6.0+ Sp6 参考: Microsoft MSDN在安装或升级到 Windows XP 后,Visual InterDev 6.0 Active Server Page (ASP) 调试可能无法正常运行,且您可能会遇到以下问

3720

如何配置才能使用InterDev 来调试ASP代码 zt

一、原因     现在我们一直用Microsoft Script Debugger 工具来调试ASP代码,调试过程中,大家都觉得他的调试功能不够强大.都希望是否能用Visual C++ 6.0 调试C++一样, 下面就是讲如何配置你的Web 服务器, 使之能用强大的Visual InterDev 来调试本地的和远程的ASP脚本.     安装手册里介绍的只是本地调试的配置, 远程调试未涉及.

在技术和生活的原野中梦游 1548

如何解决visual interdev的调试问题

微软的这篇文章能彻底解决visual interdev的调试问题需要安装visual interdev server,在visual studio 6.0的第二张盘上HOWTO: Configure Your Web Server for Visual InterDev 6.0 ASP Debugging ----------------------------------------------

蝈蝈俊.net 1817

Visual InterDev 6.0中调试ASP代码的设置方法

OverviewDebugging in Visual InterDev 6.0The distributed nature of Web applications requires that developers be able to seamlessly debug application logic across both the client and the server, and

陈坚 浙江绍兴 3968

在任意版本的 Window 上安装 VC6 的完美解决方案

在任意版本的 Window 上安装 VC6 的完美解决方

kaliu100的博客 388

VC防止窗口和控件闪烁的方法

1、将Invalidate()替换为InvalidateRect()  Invalidate()会导致整个窗口的图象重画,需要的时间比较长,而InvalidateRect()仅仅重画Rect区域内的内容,所以所需时间会少一些。虫虫以前很懒,经常为一小块区域的重画就调用Invalidate(),不愿意自己去计算需要重画的Rect,但是事实是,如果你确实需要改善闪烁的情况,计算一个Re

向往大海专栏 968

vc ++6.0打开或者添加出现错误解决方案

最近用VC6.0时,用file->open后,出现“Microsoft (R) Developer Studio 遇到问题需要关闭。我们对此引起的不便表示抱歉”, 垃圾微软,自己的东西还发生冲突, -----VC6.0和Visio都是开发者常用的工具,但是他们却存在冲突。当两个软件同时安装在一台机器上时,如果在VC6.0中的“FileView”右键点“add files to folder”...

weixin_30273931的博客 243

利用VC++进行逆向工程分析代码与结构[转]

  安装Microsoft Office Visio后,它就会自动内嵌VC++ 在Tools -> Customize -> Add-ins and Macro Files 中选中 Microsoft Visio UML add-in 然后VC就会自动创建新的Toolbar 新建或打...

weixin_34198797的博客 333

VC防止反汇编的办法(1)

最近在看IDA的书,讲汇编语言的部分提到了一种防止递归向下汇编器逆向程序的方法 这里esp指向栈顶,也就是调用方最后入栈的返回地址。然而实际在VC2017里用内联汇编这么做是不行的,原因可以看看VC生成的汇编 代码: 1 int __stdcall func1(int param) 2 { 3 00AC10A0 push ebp 4 00AC10...

数语轩 466

怎么使用pycharm开发图形化界面

这篇文章将为大家详细讲解有关怎么使用pycharm开发图形化界面,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。一、下载软...

2601_96238243的博客 240

Claude Code和VSCode集成

Claude Code和VSCode集成

qq_43494013的博客 295

南开大学《大学物理》历年期末考试试卷(含答案).pdf

南开大学《大学物理》历年期末考试试卷(含答案)

上一篇: Visual C++编程控制输入法
下一篇: 网卡MAC地址相关信息大全
xmlscript
博客等级 码龄25年 1粉丝 0原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值