??xml version="1.0" encoding="utf-8" standalone="yes"?>久久国产精品99精品国产,免费精品久久天干天干,中文字幕日本人妻久久久免费http://www.shnenglu.com/tgh621/archive/2011/01/17/138663.html大v大vMon, 17 Jan 2011 04:57:00 GMThttp://www.shnenglu.com/tgh621/archive/2011/01/17/138663.htmlhttp://www.shnenglu.com/tgh621/comments/138663.htmlhttp://www.shnenglu.com/tgh621/archive/2011/01/17/138663.html#Feedback2http://www.shnenglu.com/tgh621/comments/commentRss/138663.htmlhttp://www.shnenglu.com/tgh621/services/trackbacks/138663.html如果你是C++E序员,如果你写q一个很复杂的程序,如果你经常碰到莫名其妙的崩溃问题。那么你有可能遭遇了野指针。如果你比较l心Q注意了Debug Output输出H口的话Q那么你有可能注意到这样一行提C:
HEAP:   Free   Heap   block   xxxxxxxx modified   at   xxxxxxxx  after   it   was   freed

 

GFlags是Windows debug tools 工具包下的一个工?在Windows 2000的Resource Kit中也可以扑־到。用来设|一些调试属性,M上分?个别SystemQKernel和Image File。我们设|好Path环境变量,其指向Debug tools工具的目录下?/p>

下蝲安装 gflags:

http://www.microsoft.com/whdc/devtools/debugging/installx86.mspx

http://www.ithov.com/Soft/system/systest/38210.shtml

GFlags 

老牌的PageHeap配置工具Q有命o行和GUI两种操作方式Q功能比较全Q包含在Windbg调试器安装包内。同样在Windows 2000 Professional SP2 以上可用?/span>

一些用GFlags命o行的例子Q?/span>

配置正常堆Q?/span>

"C:\Program Files\Debugging Tools for Windows (x86)\gflags.exe" /p /enable qq.exe

配置完全堆Q?/span>

"C:\Program Files\Debugging Tools for Windows (x86)\gflags.exe" /p /enable qq.exe /full

列出当前启动了页堆的q程列表Q?/span>

"C:\Program Files\Debugging Tools for Windows (x86)\gflags.exe" /p

取消堆讄Q?/span>

"C:\Program Files\Debugging Tools for Windows (x86)\gflags.exe" /p /disable qq.exe

一些特D选项解释Q?/span>

/unaligned

q个选项只能用于完全堆。当我们从普通堆理器分配一块内存时Q内存L8字节寚w的,堆默认情况下也会用这个对齐规则,但是q会D分配的内存块的结不能跟边界精对齐,可能存在0-7个字节的间隙Q显Ӟ对位于间隙范围内的访问是不会被立卛_现。更准确的说Q读操作永q不能被发现Q写操作则要{到内存块释放时校验间隙I间内的填充信息时才发现?unaligned用于修正q个~陷Q它指定堆理器不必遵?字节寚w规则Q保证内存块N_寚w边界?/span>

需要注意的是,一些程序启用这个选项可能出现异常Q例如IE和QQ׃支持?/span>

/backwards

q个选项只能用于完全堆。这个选项使得分配的内存块头部与页边界寚wQ而不是尾部与边界寚wQ,通过q个选项来检查头部的讉K界?/span>

/debug

指定一启动q程即Attach到调试器Q对于那些不能自动生成dump的程序,是比较有用的选项?/span>

完全堆Q?/span>

    当分配一块内存时Q通过调整内存块的分配位置Q其结恰好与pȝ分页边界寚wQ然后在边界处再多分配一个不可访问的作Z护区域。这P一旦出现内存读/写越界时Q进E就会CrashQ从而帮助及时检查内存越界?/span>

因ؓ每次分配的内存都要以q种形式布局Q尤其对于小片的内存分配Q即使分配一个字节,也要分配一个内存页Q和一个保留的虚拟内存(注意在目前的实现中,q个用作边界保护区域的页从来不会被提交)。这需要大量的内存Q到底一个进E需要多内存,很难估算Q因此在使用Page Heap前,臛_保证你的机器臛_讄?G虚拟内存以上?/span>

正常堆

    正常堆原理与CRT调试内存分配函数cMQ通过分配量的填充信息,在释攑ֆ存块时检查填充区域。来内存是否被损坏Q此Ҏ的优Ҏ极大的减了内存耗用量。缺Ҏ只能在释攑֝时检,不太好跟t出错的代码位置?/span>

堆能处理的错误cdQ?/span>

错误cd                    正常堆               整页?nbsp;

堆句柄无?nbsp;                    立即发现                 立即发现 

堆内存块指针无效               立即发现                 立即发现 

多线E访问堆不同?nbsp;            立即发现                 立即发现 

假设重新分配q回相同地址(realloc)  90% 内存释放后发?nbsp;  90% 立即发现 

内存块重复释?nbsp;                90% 立即发现             90% 立即发现 

讉K已释攄内存?nbsp;            90% 在实际释攑֐发现     90% 立即发现 

讉K块结之后的内容           在释攑֐发现             立即发现 

讉K块开始之前的内容           在释攑֐发现             立即发现 

以下是D例:

前期工作Q?gflagsQ默认安装在C:\Program Files\Debugging Tools for Windows (x86)Q加入到path

案例1Q?/strong>
int _tmain(int argc, _TCHAR* argv[])
{
     char *p = new char[8];
     p[8] = 10;

     delete[] p;
     return 0;
}
E序本n是有问题的。数l已l越界,但是debug模式下ƈ不报错,release模式下也很大可能是不crash的?/p>

在命令提C符下运行:

>gflags /p /enable test.exe /full

在release模式q行test.exe。exception直接定位到 p[8] = 10; q一?/p>

案例2Q?/strong>
int _tmain(int argc, _TCHAR* argv[])
{
     char *p = new char[9];
     p[9] = 10;

     delete[] p;
     return 0;
}
以上代码和案?仅有一点不同,是数组大小。但是如果运?br>gflags /p /enable test.exe /full

在release模式下ƈ不会出现exceptionq定位到 p[9] = 10;
原因是没有设|?/unaligned 参数Q具体看说明。案?中,数组?字节大小Q按内存8字节寚w的说法,q块内存应该?/p>

16字节Q后面还?字节的空_所?p[9] = 10; q不会生exception。设|?/unaligned 参数Q禁?字节寚wQ就

可以跟踪?p[9] = 10; q个exception

>gflags /p /enable test.exe /full /unaligned

案例3Q?br>class A
{
public:
 int a;
 void del(){
  delete this;
  a = 10;
 }
};
int _tmain(int argc, _TCHAR* argv[])
{
 A* a = new A();
 a->del();
 return 0;
}

在debug模式下可能生exception:
HEAP:   Free   Heap   block   xxxxxxxx modified   at   xxxxxxxx  after   it   was   freed
在release模式下运行ƈ不报错,但是E序本n是有问题的,delete this; 之后Q又l成员变?a=10;

q显然是不对的?/p>

>gflags /p /enable test.exe /full
此时在debug下运行程序,会生exceptionQƈ定位?nbsp;  a = 10;



大v 2011-01-17 12:57 发表评论
]]>
[转]如何手工抓取dump文ghttp://www.shnenglu.com/tgh621/archive/2010/10/27/131525.html大v大vWed, 27 Oct 2010 09:38:00 GMThttp://www.shnenglu.com/tgh621/archive/2010/10/27/131525.htmlhttp://www.shnenglu.com/tgh621/comments/131525.htmlhttp://www.shnenglu.com/tgh621/archive/2010/10/27/131525.html#Feedback0http://www.shnenglu.com/tgh621/comments/commentRss/131525.htmlhttp://www.shnenglu.com/tgh621/services/trackbacks/131525.html在生产环境下q行故障诊断ӞZ不终止正在运行的服务或应用程序,有两U方式可以对正在q行的服务或应用E序的进E进行分析和调试?/p>

首先一U比较直观简z的方式是用WinDbg{调试器直接attach到需要调试的q程Q调试完毕之后再detach卛_。但是这U方式有个缺点就是执行debugger命o时必dbreakq个q程Q执行完debug命o之后又得赶紧F5让他l箋q行Q因你break住的时候意味着整个q程也已l被你挂赗另外也l常会由于First Chance Excetpion而自动breakQ你得时ȝ意避免长旉break整个q程。所以这L调试方式Ҏ间是个很大的考验Q往往没有充裕的时间来做仔l分析?/p>

另一U方式则是在出现问题的时候,比如CPU持箋长时?00%Q内存突然暴涨等非正常情况下Q通过Ҏ务进Esnapshot抓取一个dump文gQ完成dump之后先deatchQ让q程l箋q行。然后用windbg{工h分析q个抓取到的dump文g?/p>

那么如何在不l止q程的情况下抓取dump文g呢?Debugging Tools for Windows里提供了一个非常好的工Padplus.vbs。从名字可以看出Q实际上是一个vb脚本Q只是对cdb调试器作的一个包装脚本?/p>

其\径与Debugging Tools for Windows的安装\径相同,使用的方法也很简单,如下所C?

adplus.vbs -hang -p 1234 -o d:\dump

其中-hang指明使用hang模式Q亦卛_q程q行q程中附加上去snapshot抓取一个dump文gQ完成之后detach。与之对应的?crash崩溃模式Q用户先启动adplusQ然后由它启动要监控的程序,在出现异常崩溃时自动生成dump文gQ或者通过Ctrl-CZؓ发出抓取指o。但?crash模式在抓取完成之后,被监控的q程必ȝ止。因此我们在q里只选用-hang模式?/p>

-p是要调试的进EIDQ比如ASP.NET应用U程池,在Win2003下就是w3wp.exe

-o 指定要output的dump文g路径?/p>

另外Q与adpluscM的,有个UserDump工具Q但是抓取用h式的q程Q而adplus则是内核模式和用h式两者皆可?/p>

而L周至的Dr. WastonQ则会在q程崩溃之后的自动时候抓取dump文gQ一样可以用于windbg{调试器来事后分析程序崩溃时的状态?/p>

Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=
0:000> !dumpheap -stat
No export dumpheap found
======解决ҎQ?br>.load clr20\sos.dllQ你要先执行的。sos.dll在默认的c:\windows\microsoft.net\framework\v2.....下面Q你复制到c:\program files\debugging tools for windows下面的clr20目录下面Qclr20是你手工创徏的)
 Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q?br>    
  ?NET下开发时Q最基本的调试方法就是用Visual Studio的单步调试。但是对于一些特D情况,特别是涉及到CLR内部的时候用这U方式就达不到目的了?
  如果要查看运行时内存使用情况QIL代码QCLR信息{可以用以下两U方式:
  1、用VS2005 + sos.dll
  2、用Windbg + sos.dll
  W二U方式功能更加强大,下面我就通过实际操作展示一下怎么使用q种Ҏ得到q行时ArrayList内部的倹{?
  有h可能会说Q我直接用Visual Studio的单步调试岂不是更快Q当Ӟq个只是一个演C,通过q个演示是ؓ以后的高U调试打下基
  
  在操作之前,先熟悉一下基本知识:
  A、用VS2005 + sos.dll调试
  1、需要在目->属?>调试-〉启用非托管代码调试
  2、打开调试-〉窗?〉即?
  3、在xH口中输?!load sos 加蝲调试模块
  4、输入其它调试语?
  
  B、用Windbg + sos.dll
  1、去微Y的网站下载最新的Windbg
  2、打开Windbg在File-〉Symbol File Path ...H口中输?srv*c:\symbols*http://msdl.microsoft.com/download/symbols
  3、运行需要调试的E序Q然后在Windbg中File-〉Attach to Process中选择刚才q行的程?
  4、在出现的CommandH口中就可以输入调试语句
  5、常用调试语句:
   lm //查看加蝲了哪些模?
   .load C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\sos.dll //加蝲调试模块
   ld TestClass //加蝲调试W号
   !name2ee TestClass.exe TestClass.Program.test //昄testҎ相关的地址
   !dumpmt -md 00976d48 //得到cȝ成员函数详细信息
   !dumpil 00973028 // 昄q个Ҏ被编译器~译之后的IL代码
   !dumpheap -stat //该命令显C程序中所有对象的l计信息Q显C的大小是对象本w的大小Q不包括对象里面值的大小
   !dumpheap -mt 790fcb30 //该命令显CMethodTable 790fcb30的详l信?
   !gcroot 012919b8 //来显CZ个实例的所属关p?
   !dumpobj(do) 012a3904 //昄一个对象的具体内容Q看对象里面有什么,值是什?
   !ObjSize 012a1ba4 //对象实际在内存中的大?
   !eeheap -gc //查看托管堆的情况(包括大小)
   !DumpArray //查看数组信息
   下面来看看具体的调试步骤:
  1、我们的试代码
  
  
  namespace TestClass
  {
   class Program
   {
   [STAThread]
   static void Main(string[] args)
   {
   ArrayList list = new ArrayList();
   list.Add("aaaa");
   list.Add("bbbb");
   Console.ReadLine();
   }
   }
  }很简单,是一个ArrayList
  
  q行q个E序(开始执行,不调?Q然后进入WindbgQAttach到这个进E?
  
  2、查看所有堆栈信?
  0:004> !dumpheap -stat
   MT Count TotalSize Class Name
  7910062c 1 12 System.Security.Permissions.SecurityPermission
  7918e284 1 16 System.IO.TextReader+SyncTextReader
  79102d10 1 20 Microsoft.Win32.SafeHandles.SafeFileMappingHandle
  79102cb4 1 20 Microsoft.Win32.SafeHandles.SafeViewOfFileHandle
  79101d30 1 20 System.Text.InternalEncoderBestFitFallback
  79100a7c 1 20 Microsoft.Win32.SafeHandles.SafeFileHandle
  79105cd4 1 24 System.Collections.ArrayList
  ......
  7912ad90 11 9036 System.Object[]
  790fcb30 2083 131492 System.String
  Total 2202 objects
  除了我们的ArrayList外,q有很多其它的系l信息,先不用管?
  
  3、查看我们的ArrayList的信?
  0:004> !dumpheap -mt 79105cd4
   Address MT Size
  012a1b88 79105cd4 24
  total 1 objects
  Statistics:
   MT Count TotalSize Class Name
  79105cd4 1 24 System.Collections.ArrayList
  Total 1 objects
  
  4、查看对应地址内部实际的?
  0:004> !do 012a1b88
  Name: System.Collections.ArrayList
  MethodTable: 79105cd4
  EEClass: 79105c28
  Size: 24(0x18) bytes
   (C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
  Fields:
   MT Field Offset Type VT Attr Value Name
  7912ad90 40008df 4 System.Object[] 0 instance 012a1bb0 _items
  791018e0 40008e0 c System.Int32 1 instance 2 _size
  791018e0 40008e1 10 System.Int32 1 instance 2 _version
  790fc35c 40008e2 8 System.Object 0 instance 00000000 _syncRoot
  7912ad90 40008e3 1c0 System.Object[] 0 shared static emptyArray
   >> Domain:Value 00149c58:012a1ba0 <<
  可以看到ArrayList的大ؓ2Q具体的g存在地址012a1bb0中,是一个System.Object[]cd的数l?
  
  5、查看数l信?
  0:004> !DumpArray 012a1bb0
  Name: System.Object[]
  MethodTable: 7912ad90
  EEClass: 7912b304
  Size: 32(0x20) bytes
  Array: Rank 1, Number of elements 4, Type CLASS
  Element Methodtable: 790fc35c
  [0] 012a1b50
  [1] 012a1b6c
  [2] null
  [3] null
  
  6、查看数l内对象的?
  0:004> !do 012a1b50
  Name: System.String
  MethodTable: 790fcb30
  EEClass: 790fca90
  Size: 26(0x1a) bytes
   (C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
  String: aaaa
  Fields:
   MT Field Offset Type VT Attr Value Name
  791018e0 4000096 4 System.Int32 1 instance 5 m_arrayLength
  791018e0 4000097 8 System.Int32 1 instance 4 m_stringLength
  790fe534 4000098 c System.Char 1 instance 61 m_firstChar
  790fcb30 4000099 10 System.String 0 shared static Empty
   >> Domain:Value 00149c58:790d81bc <<
  7912b1d8 400009a 14 System.Char[] 0 shared static WhitespaceChars
   >> Domain:Value 00149c58:012a16f0 << 
Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=

windbg使用ȝ
【抓dump?br>1、一般抓?br>adplus -hang -p 3230 -quiet ?230 pidq程Qhang模式Q相当于把那个进E暂停住Q取内存快照
adplus -crash -pn w3wp -quiet 抓w3wpq程Qcrash模式Q当那个q程崩溃l束的时候自动抓取当时的内存
adplus -hang -iis -quiet 抓IIS相关q程Q包括其上host的web应用Q以及iis自n
2、抓window服务
http://support.microsoft.com/kb/824344/zh-cn
3、远E抓
http://blog.joycode.com/tingwang/archive/2006/08/11/79763.aspx
4、抓蓝屏和死机的dump
电脑无故重启或者蓝屏会在C:\WINDOWS\Minidump\下保存一个minidumpQ但是这个minidump可用的命令很,一般只?analyze –v看到是哪个进E引LQ还有相关的驱动模块基本定位问题了?br>5、IIS回收的时候抓
http://blog.yesky.com/blog/omakey/archive/2006/12/17/1618015.html
6、计划Q务抓
比如一个进Ev来后不知道它什么时候会意外崩溃Q可以在计划d里用crash里抓Q当那个q程意外l止的时候,cdb可以直接附加上去Q抓取当时的dumpQ如果要抓一些会自动重启的进E,而且要抓每次重启前的dumpQ可以参考附录里一节?/p>

【常用命令?br>1、先path C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727Q把.net路径讄为path环境变量Q一遍在windbg里可以直?load sosQ而不?load C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\sos.dll
2、ld demoQ加载你E序的pdb文gQ调?netE序一般要把kernel32和mscorwks的符号加载上Q关于这两个东西大家可以查资料,其是后者有哪些函数可以多了解一些?br>3、在windbg的file/symbol file path对话框里输入以下文字Q以便自动加载和下蝲W号
C:\WINDOWS\Symbols;d:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\symbols;.sympath SRV*d:\localsymbols*http://msdl.microsoft.com/download/symbols
其中有windows?net2.0和自动从|上下蝲的调试符P注意Ҏ自己的情况适当修改目录

【调试死锁?br>1?syncblkQ查看哪些线E拿C?br>2、~67e!clrstack 跛_某个拿到锁的U程看它正在q什么操作,q迟不肯释放?br>3?runaway 查看q个占有锁的U程q行了多长时间?br>4、~*e!clrstack查看所有线E的托管堆栈Q看看哪些是正在{待锁的Q比如hang在System.Threading.Monitor.Enter(System.Object)
5、~136s选择该线E,昄如下
0:000> ~136s eax=00005763 ebx=08deeb5c ecx=03eff0d4 edx=5570ab69 esi=08deeb5c edi=7ffd6000 eip=7c95ed54 esp=08deeb10 ebp=08deebb8 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ntdll!KiFastSystemCallRet: 7c95ed54 c3 ret
扑ֈecx寄存器的|复制后ctrl+fQ向上查找,会找?syncblk的地方,如下
0:000> !syncblk Index SyncBlock MonitorHeld Recursion Owning Thread Info SyncBlock Owner 1906 03ee4be4 5 1 03ee8f88 22c8 67 185e2ef0 System.Object 5390 052ca39c 3 1 05292b30 1dd4 49 1060d3ac System.Object 9372 0530702c 15 1 0012d3a8 1aa8 80 185e7704 System.Object 11428 03eff0d4 35 1 053b8fa8 169c 120 166acd98 System.Object 15278 0531c6b4 61 1 06bc1430 26d8 86 1a5bea88 System.Object
可以看到136U程{待的锁?20LE占着不放Q格式有点ؕQ凑合看Q,
6、有时候通过ecx寄存器找锁不是很定Q可以用~* kb来把所有线E堆栈打出来Q然后根?syncblk出来的同步快的值去搜烦大概有多个U程在等那个锁。因为同h{待锁,可等的状态不一P有的在Q里,有的锁已l升U,有的d试去拉K了,所以不一定当时ecx寄存器指向那块内存,具体如何扑ֈ某个正在{待锁的U程{待的锁的内存地址Q以及它正等待的q个锁被哪个U程拿着Q我q没琢磨律来Q但一般情况下Q如果有其它同步对象的话Q更难查?net里用我上面说的几步就能查出锁的问题了?/p>


【内存泄漏?br>1?dumpheap -stat看看哪些对象个数最多,占内存最大,
2、找到某个格式比较多的对象,可以看它的方法表Q然后用!dumpheap -mt 66398fa4去随机找几个对象的地址
3、用!do 1e5a22bc命oL看几个对象的状态,属性的值等Q看看正怸正常
4、用!gcroot -nostacks 1e5a22bcL看几个对象的Ҏ怸正常Q如果有些对象的根不是自己预先设计的那样Q很可能被自己没惛_的对象强引用了,所以GC无法回收它,泄漏了?br>【CPU癑ֈ百?br>主要用几个计数器?runaway命oQ具体见以下链接
http://www.cnblogs.com/onlytianc ... 7/06/03/769307.html
【线E池耗尽?br>!threadpool 能看到完成端口,U程池工作线E和timer回调各占U程池的情况?br>【其它?br>1?eestack -short -ee查看所有重?获取锁的Q托的Q停止ƈ允许回收?U程的dumpstackQ差不多相当于~*e!dumpstack
2?time 可以看到q程跑了多少旉
3?dso 查看当前U程里有哪些对象Q分析内存泄漏问题也怼用到
【小l?br>要想很好的用windbg排查.net问题Q首先要了解一些clr宿主的基知识Q以及IL的一些基Q还有简单的寄存器和汇编试Q再是有个好的思\Q最后就是经验和对代码逻辑的理解?/p>


【附录:写了一个自动抓dump的工P可在E序异常退出的时候抓dump?br>【用方法?br>1、先在cmd下运行以下命令确保计划Q务开着
net start "task scheduler"
2、执行以下命令安排自动抓?br>at 13:27 d:\myapp\autodump\processmon.exe
其中计划启动的时间和自动抓包的程序\径要Ҏ情况讄Q计划启动之前当前用户一定要注销?br>【相关配|?br><appSettings>
  <add key="adplusPath" value="D:\MyApp\Debugging\adplus.vbs"/><!--adplus的\?->
  <add key="ProcessName" value="w3wp"/><!--要抓dump的进E的名字Q可用部分名字,不用完整?->
</appSettings>


【源码?/p>


using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;

namespace ProcessMon
{
    class Program
    {
        static readonly List<int> _dumpPIDs = new List<int>();
        private static readonly string _processName = System.Configuration.ConfigurationManager.AppSettings["ProcessName"];
        private static readonly string _adplusPath = System.Configuration.ConfigurationManager.AppSettings["adplusPath"];
        static void Main(string[] args)
        {
            while(true)
            {
                Console.WriteLine("..");
                ThreadProc();
                Thread.Sleep(10000);
            }
        }

        private static void ThreadProc()
        {
            foreach(Process vProcess in Process.GetProcesses())
            {
                try
                {             
                    string  processName  =  vProcess.ProcessName.ToLower();
                    if (processName.IndexOf(_processName) >= 0)
                    {
                        Console.WriteLine("{0}-{1}", vProcess.ProcessName, vProcess.Id);

                        if (_dumpPIDs.Contains(vProcess.Id))
                            continue;
                        _dumpPIDs.Add(vProcess.Id);
     
                        DumpProcessDeg d = DumpProcess;
                        d.BeginInvoke(vProcess.Id, null, null);
                        DumpProcess(vProcess.Id);
                    }
                }
                catch(Exception ex)
                {
                    Console.WriteLine(ex);
                }
            }
        }

        private delegate void DumpProcessDeg(int pid);
        static  void  DumpProcess(int pid)
        {
            ProcessStartInfo  Info  =  new  System.Diagnostics.ProcessStartInfo();
            Info.FileName = _adplusPath;
            Info.Arguments = string.Format("-crash -p {0} -quiet",pid);
            Info.WorkingDirectory  =  "C:\\";
            Process  Proc  ;
            try
            {
                Proc  =  Process.Start(Info);
            }
            catch(System.ComponentModel.Win32Exception  e)
            {
                Console.WriteLine("pȝ找不到指定的E序文g。\r{0}",  e);
                return;
            }
            Proc.EnableRaisingEvents = true;
            Console.WriteLine("外部E序的开始执行时_{0}",  Proc.StartTime);
            Proc.WaitForExit(60000);
            if(Proc.HasExited  ==  false){
                Console.WriteLine("׃E序l止外部E序的运行!");
                Proc.Kill();
            }
            else{
                Console.WriteLine("由外部程序正帔R出!");
            }
            Console.WriteLine("外部E序的结束运行时_{0}",  Proc.ExitTime);
            Console.WriteLine("外部E序在结束运行时的返回|{0}",  Proc.ExitCode);
        }
    }
}

===============
补充几个命o:

1?analyze -v Q用于分析挂掉线E的详细情ŞQ错误原因?/p>

2?locks Q列出全部资源用情c?/p>

3?locks -v 0x???????? Q特定地址的死锁分析?/p>

4?thread 0x????????Q特定线E详情?/p>

5?thread 0x????????Q{到某个线E堆栈?br> 



大v 2010-10-27 17:38 发表评论
]]>
sse2指o?/title><link>http://www.shnenglu.com/tgh621/archive/2010/08/20/124113.html</link><dc:creator>大v</dc:creator><author>大v</author><pubDate>Fri, 20 Aug 2010 09:53:00 GMT</pubDate><guid>http://www.shnenglu.com/tgh621/archive/2010/08/20/124113.html</guid><wfw:comment>http://www.shnenglu.com/tgh621/comments/124113.html</wfw:comment><comments>http://www.shnenglu.com/tgh621/archive/2010/08/20/124113.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.shnenglu.com/tgh621/comments/commentRss/124113.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/tgh621/services/trackbacks/124113.html</trackback:ping><description><![CDATA[     摘要:   1Ud指o: 1.       Movapsmovaps XMM,XMM/m128 movaps XMM/128,XMM把源存储器内容值送入目的寄存?当有m128?必须寚w内存16字节,也就是内存地址?位ؓ0. 2.       Movupsmovups...  <a href='http://www.shnenglu.com/tgh621/archive/2010/08/20/124113.html'>阅读全文</a><img src ="http://www.shnenglu.com/tgh621/aggbug/124113.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/tgh621/" target="_blank">大v</a> 2010-08-20 17:53 <a href="http://www.shnenglu.com/tgh621/archive/2010/08/20/124113.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Shell_NotifyIcon在Q务栏d一个图?/title><link>http://www.shnenglu.com/tgh621/archive/2009/02/26/75001.html</link><dc:creator>大v</dc:creator><author>大v</author><pubDate>Thu, 26 Feb 2009 10:44:00 GMT</pubDate><guid>http://www.shnenglu.com/tgh621/archive/2009/02/26/75001.html</guid><wfw:comment>http://www.shnenglu.com/tgh621/comments/75001.html</wfw:comment><comments>http://www.shnenglu.com/tgh621/archive/2009/02/26/75001.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/tgh621/comments/commentRss/75001.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/tgh621/services/trackbacks/75001.html</trackback:ping><description><![CDATA[memset(&ntfData,0,sizeof(ntfData));<br> ntfData.cbSize = sizeof(NOTIFYICONDATA);<br> ntfData.hWnd = this->GetSafeHwnd();<br> if(m_hCurrentIcon)<br>  ntfData.hIcon = m_hCurrentIcon;<br> ntfData.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP;<br> ntfData.uID = IDR_MAINFRAME;<br> memcpy(ntfData.szTip, m_strTipNormal, sizeof(ntfData.szTip)-1);<br> ntfData.uCallbackMessage = WM_COMMANDNOTIFY;<br> Shell_NotifyIcon(NIM_ADD, &ntfData); <img src ="http://www.shnenglu.com/tgh621/aggbug/75001.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/tgh621/" target="_blank">大v</a> 2009-02-26 18:44 <a href="http://www.shnenglu.com/tgh621/archive/2009/02/26/75001.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MFCH口的清除过E[转]http://www.shnenglu.com/tgh621/archive/2009/02/11/73433.html大v大vWed, 11 Feb 2009 02:50:00 GMThttp://www.shnenglu.com/tgh621/archive/2009/02/11/73433.htmlhttp://www.shnenglu.com/tgh621/comments/73433.htmlhttp://www.shnenglu.com/tgh621/archive/2009/02/11/73433.html#Feedback0http://www.shnenglu.com/tgh621/comments/commentRss/73433.htmlhttp://www.shnenglu.com/tgh621/services/trackbacks/73433.html对于vc++初学者来?总觉得窗口对象的清除q程有些莫名其妙.在程序中看不到对delete的显式调?q似乎违反了c++中有兛_始化和清除的规则.那么,E序是怎样取消一个窗口对?

要消除窗口对?必须清楚H口对象的构?在一个通常的程序中Q先创徏c++H口对象,然后由Windows创徏实际的窗口结?q返回句柄与c++对象q接.也就是说,H口对象包含c++H口对象和WindowsH口对象,两者通过句柄HWND联系.

现在,让我们看?正规"的窗口对象清除流E?所谓对象的清除是指释放对象所占的资源,H口对象中WindowsH口对象占有的是pȝ资源,c++对象占有的是内存资源.释放pȝ资源相对要简单一?调用虚函数DestroyWindow删除WindowsH口对象.如果DestroyWindow删除的是父窗?Windows会自动ؓ子窗口调用DestroyWindow.一般来?E序不必调用DestroyWindow.因ؓ当用户关闭窗口时,Windows便发送WM_CLOSE消息,WM_CLOSE的缺省消息处理函数CWnd::OnClose调用DestroyWindow.

到这?清除工作已经完成了一?屏幕上的H口已经不见?但是别忘?在内存中q有一个c++H口对象.让我们再看看c++对象清除的过E?当窗口被取消?H口最后发送的一个消息是WM_NCDESTROY.它缺省的消息处理函数CWnd::OnNcDestroy把c++H口对象与句柄HWND分离,q调用一个很重要的虚函数PostNcDestroy.q个函数是搞清窗口对象清除的关键.Cwnd中的PostNcDestroy什么都不做.有些MFCH口cM重蝲?q加入delete this代码删除c++对象.q些H口cd常是以new操作W徏立在堆中?׃重蝲了PostNcDestroy,使窗口有自动清除功能.因此,我们不用兛_清除问题?另外的一些MFCH口cM般是以变量Ş式创建的,MFC没有Z没必要ؓ它们重蝲PostNcDestroy函数.

不具备自动清除功能的H口c?一般在堆栈中创建或嵌入于其它c++对象?

所有标准的Windows控gc?如CStatic, CEdit, CListBox{等)

由CWndcȝ接派生出来的子窗口对?如用户定制的控g)

拆分H口c?CSplitterWnd)

~省的控制条c?CControlBar的派生类)

对话框类(CDialog)在堆栈上创徏的模态对话框c?/p>

所有的Windows通用对话?除CFindReplaceDialog)

由ClassWizard创徏的对话框

h自动清除功能的窗口类,一般在堆中创徏:

L架窗口类(直接或间接从CFrameWndcL?

视图c?直接或间接从CViewcL?

从某U程度上来说,MFC?服务到家"使初学者有些找不着?不过,不得不承?MFCq的很漂?

谈到q里,我们应该明白c++里一条重要的准则:用DestroyWindow清除H口对象,不要?delete".

对于不具备自动清除功能的H口cM?delete"?"delete"先调用析构函数里的DestroyWindow,׃在析构函C,虚机制不起作?q里只能调用本地版本(Cwndc?DestroyWindow函数,昄q不是我们想要的.对于有自动清除功能的H口c?好象问题更严重一?前面提到了重载的PostNcDestroy已经含有?delete this",q样c++对象p释放了两?

很多?vc++同vb一?是一个完全可视化的?不用在看c++的书?通过上面对窗口对象的清除的介l?可以发现,WindowsE序是与Windows紧密l合?而且牉|到很多c++的知?如虚函数、析构函数、new操作W等).要对vc++有进一步理?必须理解Windows机制,深入学习c++.



大v 2009-02-11 10:50 发表评论
]]>
[转]可在q行时编辑的加速键?/title><link>http://www.shnenglu.com/tgh621/archive/2009/01/12/71821.html</link><dc:creator>大v</dc:creator><author>大v</author><pubDate>Mon, 12 Jan 2009 09:22:00 GMT</pubDate><guid>http://www.shnenglu.com/tgh621/archive/2009/01/12/71821.html</guid><wfw:comment>http://www.shnenglu.com/tgh621/comments/71821.html</wfw:comment><comments>http://www.shnenglu.com/tgh621/archive/2009/01/12/71821.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/tgh621/comments/commentRss/71821.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/tgh621/services/trackbacks/71821.html</trackback:ping><description><![CDATA[Q*Q简 介*Q* <p>  本文首先要介l了一?a target=_blank><u><font color=#0000ff>Windows</font></u></a>中的几个?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表有关的API函数及结构。然后对在WIN32位程序中实现<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表进行了探讨Q分别就API下的E序设计及MFC下的E序设计q行了叙q?br>  对于q行时可~辑?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表仅在MFC下进行了详细描述。包括其实现原理Qƈ引导大家建立了一个用于编?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>的对话框Q含详细的代码。关于在API下实现运行时的可~辑<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表不再叙qͼ可参考MFC下的代码?br>  我们通常希望编辑过?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表保存v来,以便下次q行E序时保持我们编辑后的风根{在本文的最后,介绍了如何将<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表保存至文g中,q从文g中读取我们保存的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表。你若是有意?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表保存至<a target=_blank><u><font color=#0000ff>注册?/font></u></a>或其它什么地方,可参考其它的有关资料。本人徏议保存至文g比较恰当?br>  本文介绍的所有方法及代码都是?Windows98SE + Microsoft Visual <a target=_blank><u><font color=#0000ff>C++</font></u></a> 6.0 中进行编制和调试的。 </p> <p><br>  一、与<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表有关的几个API函数和结构?/p> <p>  操作<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表用的几个API函数Q关于这几个函数的详l说明请参考有关书c)Q?br>  HACCEL LoadAccelerators(HINSTANCE hInstance, LPCTSTR lpTableNAme);<br>  LoadAccelerators函数从程序的资源中加载一?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表,加蝲成功后返回一个加速健表的句柄。其中:<br>  hInstance  应用E序的实例句柄?br>  lpTableName 指向<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表名U字W串的指针?/p> <p>  HACCEL CreateAcceleratorTable(LPACCEL lpaccl, int cEntries);<br>  CreateAcceleratorTable函数Ҏ一个ACCELl构数组创徏一?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表。该函数与LoadAccelerators不同的是QLoadAccelerators函数加蝲?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表在E序l束后系l会自动该<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表从内存中清除,但CreateAcceleratorTable函数创徏?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表需要用函数DestoryAceleratorTable函数q行清除?br>  lpaccl   一个指向ACCELl构数组的指针?br>  cEntries  数组中元素的个数?/p> <p>  BOOL DestoryAcceleratorTable(HACCEL hAccel);<br>  DestoryAcceleratorTable函数清除由CreateAcceleratorTable函数创徏?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表,成功则返回TRUE。其中:<br>  hAccel   需要清除的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表句柄?/p> <p>  int TranslateAccelerator(HWND hWd, HACCEL hAccTable, LPMSG lpMsg);<br>  TranslateAccelerator函数负责译<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>。其中:<br>  hWnd     H口句柄Q翻译后的消息将被发往该窗?br>  hAccTable  <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表句柄?br>  lpMsg    指向MSGl构的指针?/p> <p>  ACCELl构的定义:<br>typedef struct tagACCEL{<br>    BYTE    fVirt;<br>    WORD    key;<br>    WORD    cmd;<br>}ACCEL,*LPACCEL;</p> <p>其中Q?br>  fVirt   <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>的标记?br>  key    键的代码。如fVirt成员包含FVIRTKEY标志Q则key指一个虚键码Q否则是一个ASCII码?br>  cmd    命oIDP该参数将被放入WMQCOMMAND或WMQSYSCOMMAND消息的wParam参数的低位字发至H口?/p> <p><br>  二、在windows下如何?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表?/p> <p>  在window下?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表一般有两种ҎQ?Q创Z?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>资源Q在E序中用API函数LoadAccelerators来将<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表加载入内存。ƈ在消息@环中使用API函数TranslateAccelerator来翻译该<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表?、在E序中填充一个ACCEL数组。然后调用API函数CreateAcceleratorTable来创建加速表Q翻?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>同上Q但不要忘记在退出程序前使用API函数DestoryAcceleratorTable来清除它。下面分别给Z个例子:</p> <p>/*?:使用LoadAccelerators?br> 假设你已l徏立了一?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>资源QID为IDRQACCEL?br> 假设你已l定义了初始化函数InitApplication(HINSTANCE hInstance,int nCmdShow),<br> 该函数执行注册窗口类和创建窗口操作?br>*/<br>#include <windows.h><br>#include "rc/resource.h"<br>BOOL InitApplication(HINSTANCE hInstance,int nCmdShow);</p> <p>int APIENTRY WinMain(HINSTANCE hInstance,<br>                     HINSTANCE hPrevInstance,<br>                     LPSTR     lpCmdLine,<br>                     int       nCmdShow) <br>{<br>     MSG msg;<br>     HANDLE hAccelTable;<br>     // 初始化应用程序,q生成主H口.<br>     if (!InitApplication(hInstance, nCmdShow))<br>     {<br>         return FALSE;           // 初始化失?br>     }<br>      //使用函数LoadAccelerators从程序资源中加蝲<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>?br>      hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCEL));<br>      // 取得q分发消息直到接收到 WM_QUIT 消息.<br>     while (GetMessage(&msg, NULL, 0, 0))<br>     {<br>         //在分发消息前首先试着?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表进行翻译,如果是一?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>则由<br>         //TranslateAccelerator函数q行译Q不再l处理该消息?br>         if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))<br>         {<br>             TranslateMessage(&msg);<br>             DispatchMessage(&msg);<br>         }<br>     }<br>     return msg.wParam;  // Returns the value from PostQuitMessage <br>} <br> </p> <p><br>/*?:使用CreateAcceleratorTable?br> 假设你已l定义了初始化函数InitApplication(HINSTANCE hInstance,int nCmdShow),<br> 该函数执行注册窗口类和创建窗口操作?br>*/</p> <p>#include <windows.h><br>#include "rc/resource.h"</p> <p>Qdefine ID_CMD_A      0x00000230<br>Qdefine ID_CMD_B      0x00000231<br>Qdefine ID_CMD_C      0x00000232<br>Qdefine ID_CMD_D      0x00000233<br>Qdefine ID_CMD_E      0x00000234<br>Qdefine ID_CMD_F      0x00000235<br>Qdefine ID_CMD_G      0x00000236</p> <p>//定义了七?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>,请在消息回调函数中处理这七个命oID?br>static ACCEL accel[]={<br>    {FVIRTKEY|FCONTROL,VK_F5,ID_CMD_A},<br>    {FVIRTKEY|FCONTROL,VK_F6,ID_CMD_B},<br>    {FVIRTKEY|FCONTROL,VK_HOME,ID_CMD_C},<br>    {FVIRTKEY|FCONTROL,VK_END,ID_CMD_D},<br>    {FVIRTKEY|FCONTROL,"G",ID_CMD_E},<br>    {FVIRTKEY|FCONTROL,VK_SPACE,ID_CMD_F},<br>    {FVIRTKEY|FCONTROL,"K",ID_CMD_G},<br>};    </p> <p>BOOL InitApplication(HINSTANCE hInstance,int nCmdShow);</p> <p>int APIENTRY WinMain(HINSTANCE hInstance,<br>                     HINSTANCE hPrevInstance,<br>                     LPSTR     lpCmdLine,<br>                     int       nCmdShow) <br>{<br>     MSG msg;<br>     HANDLE hAccelTable;<br>     // 初始化应用程序,q生成主H口.<br>     if (!InitApplication(hInstance, nCmdShow))<br>     {<br>         return FALSE;           // 初始化失?br>     }<br>      //使用函数CreateAcceleratorTable从数laccel中加?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>?br>      hAccelTable = CreateAcceleratorTable(accel, sizeof(accel)/sizeof(ACCEL));<br>      // 取得q分发消息直到接收到 WM_QUIT 消息.<br>     while (GetMessage(&msg, NULL, 0, 0))<br>     {<br>         //在分发消息前首先试着?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表进行翻译,如果是一?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>则由<br>         //TranslateAccelerator函数q行译Q不再l处理该消息?br>         if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))<br>         {<br>             TranslateMessage(&msg);<br>             DispatchMessage(&msg);<br>         }<br>     }<br>     //删除<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>?br>     DestoryAcceleratorTable(hAccelTable);<br>     return msg.wParam;  // Returns the value from PostQuitMessage <br>} <br> </p> <p><br>  在MFCE序设计中,有关?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表的操作已经被CFrameWndc进行了装。通常Q我们的E序的主框架cCMainFrame从CFrameWndcL生(SDI界面E序Q,或者从CMDIFrameWndcL生(MDI界面E序Q,而CMDIFrameWndcM是从CFrameWndcL生的。所以,我们q不用去兛_那个资源号ؓIDR_MAINFRAME?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表是如何加蝲的,如果你只是需要一个这L静态的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表的话?br>  那么我们能不能用自q<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表呢Q答案是Q可以的?br>  创徏<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表的Ҏ同前。由于在MFC中,WinMain函数被隐藏,我们不能直接修改WinMain函数Q所以,<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表的创徏在CMainFrame的OnCreate函数中创建?br>  1、在CMainFramecMd一个HACCELcd保护成员变量Qm_hMyAccel。在构造函C初始化ؓNULL?br>  2、在CMainFrame::OnCreate函数?“return 0;”句前增加创徏<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表的代码。返回的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表句柄保存在m_hMyAccel中:</p> <p>   Ҏ1Q?IDRQMYACCELZ定义?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表资源号)<br>   m_hMyAccel=LoadAccelerators(AfxGetApp()->m_hInstance,MAKEINTRESOURCE(IDR_MYACCEL));</p> <p>   Ҏ2Q?accel同前面的例子一样在本文件的开头部分进行定?<br>   m_hMyAccel=CreateAcceleratorTable(accel,sizeof(accel)/sizeof(ACCEL));</p> <p>  3、如果是使用CreateAccelTable函数创徏的,则重载虚拟函数DestoryWindow()。在该函数的“return CMDIFrameWnd::DestroyWindow();”前增加如下代?</p> <p>    if(m_hMyAccel!=NULL){<br>        DestroyAcceleratorTable(m_hMyAccel);<br>        m_hMyAccel=NULL;<br>    }</p> <p>  通过前面的三步,<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表已l能正确地被创徏和删除了Q但是它q没有工作。下面就是要让我们刚才所创徏?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表工作v来?br>  在APIE序设计中大家已l知道了<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>是如何工作的。也是在消息还没有分发出去之前先检查是不是一?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>。我们通过API函数TranslateAccelerator来实现。在MFC中,消息机制已经被封装了Q我们不能去修改消息循环。但是,框架在分发消息前会调用虚拟函数PerTranslateMessageQƈ且如果该函数q回TRUEQ则不再处理该消息。这正是我们所需要的?br>  让我们再回到CMainFramec,生成PerTranslateMessage函数的覆盖版本。修改函C如下Q?/p> <p>BOOL CMainFrame::PreTranslateMessage(MSG* pMsg) <br>{<br>    // TODO: Add your specialized code here and/or call the base class<br>    if(m_hMyAccel&&TranslateAccelerator(m_hWnd, m_hMyAccel, pMsg))<br>        return TRUE;<br>    return CMDIFrameWnd::PreTranslateMessage(pMsg);<br>}</p> <p>  好了Q现在我们的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>已经能正常地工作了。以上方法用在其它窗口同h效(如对话框中,你不妨在对话框中试试Q?/p> <p><br>  三、可在运行时~辑?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表?/p> <p>  通过上面的叙qͼ你可能已l对可编辑的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表有了一定的轮廓。其实其实现思想很简单:只要对一个ACCEL数组q行修改Q然后重新生?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表就行了?br>  Z区分命oQ我们ؓ每个命o取一个名字。在CMainFramecd义的前面加上下面的一个结构定义:</p> <p>typedef struct{<br>    char cCmd[32];<br>    ACCEL accel;<br>}ACCELITEM,*LPACCELITEM;</p> <p>  我们用该l构来保?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表的数据。在CMainFramecMd两个保护成员变量Q?/p> <p>    LPACCELITEM m_lpAccel;<br>    DWORD m_dwAccelCount;</p> <p>  在构造函Cm_lpAccel初始化ؓNULLQm_dwAccelCount初始化ؓ0。在数组accel的定义下面增加一个字W串数组的静态变量的定义Q用来指定命令的名称,请仿照下面自己定义,个数多少不限Q字W串长度不要过31个字W)Q?/p> <p>static char strCmd[][32]={<br>    "Command One",<br>    "Command Two",<br>    "Command Three",<br>    "Command Four",<br>    "Command Five"<br>};</p> <p><br>  在CMainFramecMd一个保护成员函数LoadAccel(),该函数用来将<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表装入,定义如下Q?/p> <p>BOOL CMainFrame::LoadAccel()<br>{<br>    ASSERT(m_hActAccel==NULL);<br>    ASSERT(m_lpAccel==NULL);<br>    m_dwAccelCount=sizeof(accel)/sizeof(ACCEL);<br>    m_lpAccel=new ACCELITEM[m_dwAccelCount];<br>    memset(m_lpAccel,0,sizeof(ACCELITEM)*m_dwAccelCount);<br>    DWORD dwCmdStr=sizeof(strCmd)/sizeof(char[32]);<br>    for(DWORD dw=0;dw<m_dwAccelCount;dw++){<br>        m_lpAccel[dw].accel=accel[dw];<br>        strcpy(m_lpAccel[dw].cCmd,dw<dwCmdStr?strCmd[dw]:"Command Unknow");<br>    }</p> <p>    m_hActAccel=CreateAcceleratorTable(accel,m_dwAccelCount);<br>    return TRUE;</p> <p>}</p> <p>  删除OnCreate函数中原来创?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表的代码Q改成对LoadAccel()的调用:</p> <p>    LoadAccel();</p> <p>  在CMainFrame的析构函C增加以下内容Q?/p> <p>    if(m_lpAccel)<br>        delete[] m_lpAccel;</p> <p>  Z能够?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>数据q行~辑Q我们在工程中添加一个对话框资源QID?#8220;IDD_ACCELEDIT”Q在对话框上攄三个成组框(Group BoxQ,左边一个标题ؓ“命o”Q中间一个标题ؓ“l合?#8221;Q右边一个标题ؓ“虚键?#8221;。在左边成组框中攄一个列表框QList BoxQ,ID?#8220;IDC_LST_CMD”。在中间成组框中攄三个栔R框QCheck BoxQ,上下排列。上面的栔R框的ID?#8220;IDC_CHK_ALT”Q标题ؓ“Alt”QƈN?#8220;Group”属性;中间的核选框的ID?#8220;IDC_CHK_SHIFT”Q标题ؓ“Shift”Q取?#8220;Group”属性;下面的核选框的ID?#8220;IDC_CHK_CTRL”Q标题ؓ“Ctrl”Q取?#8220;Group”属性。在双的成l框中放|一个列表框QID?#8220;IDC_LST_KEY”。调整各个控件的寸及位|至合适。设|控件的TAB跌{序Q从左至叟뀁从上到下。依ơؓQ左成组框、IDC_LST_CMD列表框、中成组框、IDC_CHK_ALT栔R框、IDC_CHK_SHIFT栔R框、IDC_CHK_CTRL栔R框、右成组框、IDC_LST_KEY列表框、OK按钮、CANCEL按钮?br>  打开cd|为对话框新徏一个类Q类名ؓ“CDlgEditAccel”。ؓ两个列表框和三个栔R框映射变量Q如下:<br>  控gID:ID_LST_CMDQ类?Control/CListBoxQ名U?m_LstCmdQ?br>  控gID:ID_LST_KEYQ类?Control/CListBoxQ名U?m_LstKeyQ?br>  控gID:ID_CHK_ALTQ类?Control/CButtonQ名U?m_ChkAltQ?br>  控gID:ID_CHK_SHIFTQ类?Control/CButtonQ名U?m_ChkShiftQ?br>  控gID:ID_CHK_CTRLQ类?Control/CButtonQ名U?m_ChkCtrlQ?/p> <p>  在类CDlgEditAccel的定义前加入下面的定义:<br>typedef struct tag_KeyName{<br>    CString m_strName;<br>    WORD m_wID;<br>    tag_KeyName(CString str,WORD id){m_strName=str,m_wID=id;}<br>}KEYNAME,*LPKEYNAME;</p> <p>typedef struct tag_ActAccel{<br>    CString m_strCmd;<br>    ACCEL m_Accel;<br>}ACTACCEL,*LPACTACCEL;</p> <p>class CActAccelList<br>{<br>public:<br>    CActAccelList();<br>    ~CActAccelList();</p> <p>protected:<br>    LPACTACCEL m_lpActAccel;<br>    int m_iCount;</p> <p>public:<br>    ACTACCEL& operator[](int index);<br>    BOOL SetSize(int iSize);<br>    int GetSize();<br>};</p> <p><br>  在文件DlgEditAccel.cpp文g中定义类CActAccelList的成员函敎ͼ代码如下Q?br>CActAccelList::CActAccelList()<br>{<br>    m_lpActAccel=NULL;<br>   m_iCount=0;<br>}</p> <p>CActAccelList::~CActAccelList()<br>{<br>    if(m_iCount>0&&m_lpActAccel)<br>        delete[] m_lpActAccel;<br>}</p> <p>int CActAccelList::GetSize()<br>{<br>    return m_iCount;<br>}</p> <p>ACTACCEL& CActAccelList::operator []( int index)<br>{<br>    if(!(index>=0&&index<m_iCount))<br>    AfxThrowMemoryException();<br>    return m_lpActAccel[index];<br>}</p> <p>BOOL CActAccelList::SetSize(int iSize)<br>{<br>    if(iSize<0)<br>        return FALSE;<br>    if(m_iCount>0&&m_lpActAccel)<br>        delete[] m_lpActAccel;<br>    m_iCount=0;<br>    m_lpActAccel=new ACTACCEL[iSize];<br>    if(m_lpActAccel==NULL)<br>        return FALSE;<br>    m_iCount=iSize;<br>    return TRUE;<br>}</p> <p><br>  在DlgAccelEdit.cpp文g头部定义全局变量Q-数组keyQ?br>static KEYNAME key[]={<br>    KEYNAME("Left mouse button",VK_LBUTTON),<br>    KEYNAME("Right mouse button",VK_RBUTTON),<br>    KEYNAME("Control-break processing",VK_CANCEL),<br>    KEYNAME("Middle mouse button",VK_MBUTTON),<br>    KEYNAME("Back Space",VK_BACK),<br>    KEYNAME("Tab",VK_TAB),<br>    KEYNAME("Clear",VK_CLEAR),<br>    KEYNAME("Enter",VK_RETURN),<br>    KEYNAME("Shift",VK_SHIFT),<br>    KEYNAME("Ctrl",VK_CONTROL),<br>    KEYNAME("Alt",VK_MENU),<br>    KEYNAME("Pause",VK_PAUSE),<br>    KEYNAME("Caps Lock",VK_CAPITAL),<br>    KEYNAME("Esc",VK_ESCAPE),<br>    KEYNAME("Space",VK_SPACE),<br>    KEYNAME("Page Up",VK_PRIOR),  <br>    KEYNAME("Page Down",VK_NEXT),<br>    KEYNAME("End",VK_END),<br>    KEYNAME("Home",VK_HOME),<br>    KEYNAME("Left",VK_LEFT),<br>    KEYNAME("Up",VK_UP),<br>    KEYNAME("Right",VK_RIGHT),<br>    KEYNAME("Down",VK_DOWN),<br>    KEYNAME("Select",VK_SELECT),<br>    KEYNAME("Excute",VK_EXECUTE),<br>    KEYNAME("Print Screen",VK_SNAPSHOT),<br>    KEYNAME("Insert",VK_INSERT),<br>    KEYNAME("Delete",VK_DELETE),<br>    KEYNAME("Help",VK_HELP),<br>    KEYNAME("0",'0'),<br>    KEYNAME("1",'1'),<br>    KEYNAME("2",'2'),<br>    KEYNAME("3",'3'),<br>    KEYNAME("4",'4'),<br>    KEYNAME("5",'5'),<br>    KEYNAME("6",'6'),<br>    KEYNAME("7",'7'),<br>    KEYNAME("8",'8'),<br>    KEYNAME("9",'9'),<br>    KEYNAME("A",'A'),<br>    KEYNAME("B",'B'),<br>    KEYNAME("C",'C'),<br>    KEYNAME("D",'D'),<br>    KEYNAME("E",'E'),<br>    KEYNAME("F",'F'),<br>    KEYNAME("G",'G'),<br>    KEYNAME("H",'H'),<br>    KEYNAME("I",'I'),<br>    KEYNAME("J",'J'),<br>    KEYNAME("K",'K'),<br>    KEYNAME("L",'L'),<br>    KEYNAME("M",'M'),<br>    KEYNAME("N",'N'),<br>    KEYNAME("O",'O'),<br>    KEYNAME("P",'P'),<br>    KEYNAME("Q",'Q'),<br>    KEYNAME("R",'R'),<br>    KEYNAME("S",'S'),<br>    KEYNAME("T",'T'),<br>    KEYNAME("U",'U'),<br>    KEYNAME("V",'V'),<br>    KEYNAME("W",'W'),<br>    KEYNAME("X",'X'),<br>    KEYNAME("Y",'Y'),<br>    KEYNAME("Z",'Z'),<br>    KEYNAME("Left windows",VK_LWIN),<br>    KEYNAME("Right windows",VK_RWIN),<br>    KEYNAME("Applications",VK_APPS),<br>    KEYNAME("Numeric keypad 0", VK_NUMPAD0),<br>    KEYNAME("Numeric keypad 1", VK_NUMPAD1),<br>    KEYNAME("Numeric keypad 2", VK_NUMPAD2),<br>    KEYNAME("Numeric keypad 3", VK_NUMPAD3),<br>    KEYNAME("Numeric keypad 4", VK_NUMPAD4),<br>    KEYNAME("Numeric keypad 5", VK_NUMPAD5),<br>    KEYNAME("Numeric keypad 6", VK_NUMPAD6),<br>    KEYNAME("Numeric keypad 7", VK_NUMPAD7),<br>    KEYNAME("Numeric keypad 8", VK_NUMPAD8),<br>    KEYNAME("Numeric keypad 9", VK_NUMPAD9), <br>    KEYNAME("Multiply",VK_MULTIPLY),<br>    KEYNAME("Add",VK_ADD),<br>    KEYNAME("Separator",VK_SEPARATOR),<br>    KEYNAME("Subtract",VK_SUBTRACT),<br>    KEYNAME("Decimal Point",VK_DECIMAL),<br>    KEYNAME("Divide",VK_DIVIDE),<br>    KEYNAME("F1",VK_F1),<br>    KEYNAME("F2",VK_F2),<br>    KEYNAME("F3",VK_F3),<br>    KEYNAME("F4",VK_F4),<br>    KEYNAME("F5",VK_F5),<br>    KEYNAME("F6",VK_F6),<br>    KEYNAME("F7",VK_F7),<br>    KEYNAME("F8",VK_F8),<br>    KEYNAME("F9",VK_F9),<br>    KEYNAME("F10",VK_F10),<br>    KEYNAME("F11",VK_F11),<br>    KEYNAME("F12",VK_F12),<br>    KEYNAME("F13",VK_F13),<br>    KEYNAME("F14",VK_F14),<br>    KEYNAME("F15",VK_F15),<br>    KEYNAME("F16",VK_F16),<br>    KEYNAME("F17",VK_F17),<br>    KEYNAME("F18",VK_F18),<br>    KEYNAME("F19",VK_F19),<br>    KEYNAME("F20",VK_F20),<br>    KEYNAME("F21",VK_F21),<br>    KEYNAME("F22",VK_F22),<br>    KEYNAME("F23",VK_F23),<br>    KEYNAME("F24",VK_F24),<br>    KEYNAME("Attn",VK_ATTN),<br>    KEYNAME("CrSel",VK_CRSEL),<br>    KEYNAME("ExSel",VK_EXSEL),<br>    KEYNAME("Erase",VK_EREOF),<br>    KEYNAME("Play",VK_PLAY),<br>    KEYNAME("Zoom",VK_ZOOM),<br>    KEYNAME("Reserved for future use",VK_NONAME ),<br>    KEYNAME("PA1",VK_PA1),<br>    KEYNAME("Clear(OEM)",VK_OEM_CLEAR ),</p> <p>    KEYNAME("<a href="file://%22,'//'"><u><font color=#0000ff>file://",'//'</font></u></a>),<br>    KEYNAME("-",'-'),<br>    KEYNAME("=",'='),<br>    KEYNAME("[",'['),<br>    KEYNAME("]",']'),<br>    KEYNAME(";",';'),<br>    KEYNAME("\'",'\''),<br>    KEYNAME(",",','),<br>    KEYNAME(".",'.'),<br>    KEYNAME("/",'/'),<br>    KEYNAME("`",'`')<br>};</p> <p><br>  在类CDlgAccelEdit中响应Windows消息QWM_INITDIALODQ代码如下:<br>BOOL CDlgEditAccel::OnInitDialog() <br>{<br>    CDialog::OnInitDialog();</p> <p>    // TODO: Add extra initialization here<br>    SetWindowText("Edit Accelerator Table");</p> <p>    int iCount=m_AccelList.GetSize();<br>    int i;<br>    for(i=0;i<iCount;i++){<br>        m_LstCmd.AddString(m_AccelList[i].m_strCmd);<br>    }<br>    for(i=0;i<sizeof(key)/sizeof(KEYNAME);i++)<br>    {<br>        m_LstKey.AddString(key[i].m_strName);<br>    }<br>    m_LstCmd.SetCurSel(0);<br>    OnSelchangeLstCmd();<br>    return TRUE;  // return TRUE unless you set the focus to a control<br>                  // EXCEPTION: OCX Property Pages should return FALSE<br>}</p> <p><br>  为类CDglAccelEdit增加一个保护成员函敎ͼ<br>    void SaveChange(int index=-1);</p> <p>  在文件DlgAccelEdit中定义该函数Q代码如下:</p> <p>void CDlgEditAccel::SaveChange(int index)<br>{<br>    if(index>=0||(index=m_LstCmd.GetCurSel())>=0)<br>    {<br>        if(m_LstKey.GetCurSel()<0){<br>            AfxMessageBox("你必需选择一个键?");<br>            return;<br>        }<br>        BYTE btCmp=((m_ChkAlt.GetCheck()==1)?FALT:NULL)|<br>                   ((m_ChkCtrl.GetCheck()==1)?FCONTROL:NULL)|<br>                   ((m_ChkShift.GetCheck()==1)?FSHIFT:NULL)|FVIRTKEY;<br>        WORD wKey=key[m_LstKey.GetCurSel()].m_wID;</p> <p>        m_AccelList[index].m_Accel.fVirt=btCmp;<br>        m_AccelList[index].m_Accel.key=wKey;<br>        return;<br>    }<br>}</p> <p>  响应列表框ID_LST_CMD的通知消息“LBN_SELCHANGE”Q函C码如下:<br>void CDlgEditAccel::OnSelchangeLstCmd() <br>{<br>    // TODO: Add your control notification handler code here<br>    int iCmd=m_LstCmd.GetCurSel();<br>    WORD wKey=m_AccelList[iCmd].m_Accel.key;<br>    BYTE btCmp=m_AccelList[iCmd].m_Accel.fVirt;<br>    m_ChkAlt.SetCheck(btCmp&FALT);<br>    m_ChkCtrl.SetCheck(btCmp&FCONTROL);<br>    m_ChkShift.SetCheck(btCmp&FSHIFT);<br>    int iCount=sizeof(key)/sizeof(KEYNAME);<br>    int id=-1;<br>    for(int i=0;i<iCount;i++)<br>    {<br>        if(key[i].m_wID==wKey){<br>            id=i;<br>            break;<br>        }<br>    }<br>    m_LstKey.SetCurSel(id);</p> <p>}</p> <p>  响应列表框ID_LST_KEY的通知消息“LBN_SELCHANGE”Q函C码如下:<br>void CDlgEditAccel::OnSelchangeLstKey() <br>{<br>    SaveChange(); <br>}</p> <p>  响应栔R框ID_CHK_ALT的通知消息“BN_CLICKED”Q函C码如下:<br>void CDlgEditAccel::OnChkAlt() <br>{<br>    SaveChange();<br>}</p> <p>  响应栔R框ID_CHK_SHIFT的通知消息“BN_CLICKED”Q函C码如下:<br>void CDlgEditAccel::OnChkShift() <br>{<br>    SaveChange();<br>}</p> <p>  响应栔R框ID_CHK_CTRL的通知消息“BN_CLICKED”Q函C码如下:<br>void CDlgEditAccel::OnChkCtrl() <br>{<br>    SaveChange();<br>}</p> <p>  xQ用于编?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>的对话框已经完成。我们现在要做的是在程序中打开对话框来~辑了。让我们回到CMainFramecM。我们将在该cM响应一个命令来打开~辑对话框,?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表进行编辑。完成后ҎOK回到ȝ序中Q然后更?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表。这样后Q我们刚刚编辑好?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表就开始v作用了?br>  首先Q打开菜单。在“查看”后增加一?#8220;工具(&T)”下拉菜单Q在下拉菜单中增加一个了菜单Q?#8220;~辑<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>?&A)...”QID?#8220;ID_TOOL_ACCELEDIT”。打开cd|选择CMainFramec,响应“ID_TOOL_ACCELEDIT”命o。编辑响应函数如下:</p> <p>void CMainFrame::OnToolAcceledit() <br>{<br>    // TODO: Add your command handler code here<br>    CDlgEditAccel dlg;</p> <p>    DWORD i;<br>    dlg.m_AccelList.SetSize(m_dwAccelCount);<br>    for(i=0;i<m_dwAccelCount;i++){<br>        dlg.m_AccelList[i].m_strCmd=m_lpAccel[i].cCmd;<br>        dlg.m_AccelList[i].m_Accel=m_lpAccel[i].accel;<br>    }<br>    if(IDOK==dlg.DoModal()){<br>        ACCEL* pAccel=new ACCEL[m_dwAccelCount];<br>        for(DWORD dw=0;dw<m_dwAccelCount;dw++){<br>            m_lpAccel[dw].accel=pAccel[dw]=dlg.m_AccelList[dw].m_Accel;<br>        }</p> <p>        if(m_hActAccel!=NULL)<br>        DestroyAcceleratorTable(m_hActAccel);<br>        m_hActAccel=CreateAcceleratorTable(pAccel,m_dwAccelCount);<br>    }<br>}</p> <p>  在该文g的头部包含类CDlgEditAccel的头文gQ?/p> <p>#include "DlgEditAccel.h"</p> <p>  xQ可~辑?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表已l完成了。不妨试试看?/p> <p>  三、将<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表保存至文gQƈ在程序运行时自动从文件中加蝲?/p> <p>  上面我们实现了可~辑?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表。但是,当程序退出后Q我们编辑过?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>数据消׃Q下ơ运行程序时q是和以前一样了。将<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表保存v来以备下ơ用,q是我们所希望的。下面讨论的Ҏ是用文件来保存我们?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表?br>  首先Q在MainFrm.cpp文g的头部定义一个全局字符Ԍ也就是用于保?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>的文件名Q?/p> <p>static char strAccelFileName[]="Accel.cus";</p> <p>  定义一个DWORDg为文件头Q我们通过该DWORD值来判断是否是一个有效格式的文gQ?/p> <p>#define ACCEL_FILE_HEAD 0x00434341</p> <p><br>  其次QؓCMainFramecL加一个保护的成员函数Q?#8220;BOOL SaveAccel()”Q编辑其代码如下Q?br>BOOL CMainFrame::SaveAccel()<br>{<br>    char lpAppName[256];<br>    char lpAppPath[256];<br>    char* lpFilePart=NULL;<br>    GetModuleFileName(AfxGetInstanceHandle(),lpAppName,255);<br>    GetFullPathName(lpAppName,255,lpAppPath,&lpFilePart);<br>    TRACE1("Application File Name:%s.\n",lpAppName);<br>    strcpy(lpFilePart,strAccelFileName);<br>    TRACE1("Accelerator File Name:%s.\n",lpAppPath);<br>    try<br>    {<br>        DWORD dwHead=ACCEL_FILE_HEAD;<br>        DWORD dwCount=m_dwAccelCount;</p> <p>        CFile fAccel(lpAppPath,CFile::modeCreate|CFile::modeWrite);<br>        fAccel.SeekToBegin();<br>        fAccel.Write(&dwHead,sizeof(DWORD));<br>        fAccel.Write(&dwCount,sizeof(DWORD));<br>        for(DWORD dw=0;dw<dwCount;dw++)<br>        {<br>            fAccel.Write(m_lpAccel+dw,sizeof(ACCELITEM));<br>        }</p> <p>        return TRUE;</p> <p>    }</p> <p>    catch(CFileException* e)<br>    {<br>        char buf[256];<br>        char buf2[512];<br>        int iError;<br>        iError=e->m_cause;<br>        e->GetErrorMessage(buf,256);<br>        sprintf(buf2,"?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表保存到文g \"%s\" 中时发生错误!\n"<br>                     "???%d\n"<br>                     "错误描述:%s\n"<br>                     "\0",<br>                     strAccelFileName,iError,buf);<br>        AfxMessageBox(buf2,MB_OK|MB_ICONSTOP|MB_DEFBUTTON1);<br>        return FALSE;<br>    }<br>}</p> <p>  再次Q修改LoadAccel()函数如下Q?/p> <p>BOOL CMainFrame::LoadAccel()<br>{<br>    char lpAppName[256];<br>    char lpAppPath[256];<br>    char* lpFilePart=NULL;<br>    GetModuleFileName(AfxGetInstanceHandle(),lpAppName,255);<br>    GetFullPathName(lpAppName,255,lpAppPath,&lpFilePart);<br>    TRACE1("Application File Name:%s.\n",lpAppName);<br>    strcpy(lpFilePart,strAccelFileName);<br>    TRACE1("Accelerator File Name:%s.\n",lpAppPath);<br>    try<br>    {<br>        DWORD dwHead;<br>        DWORD dwCount;</p> <p>        CFile fAccel(lpAppPath,CFile::modeRead);<br>        fAccel.SeekToBegin();<br>        if(fAccel.Read(&dwHead,sizeof(DWORD))!=sizeof(DWORD))<br>            AfxThrowFileException(CFileException::endOfFile,12,lpAppPath);<br>        if(dwHead!=ACCEL_FILE_HEAD)<br>            AfxThrowFileException(CFileException::invalidFile,13,lpAppPath);</p> <p>        if(fAccel.Read(&dwCount,sizeof(DWORD))!=sizeof(DWORD))<br>            AfxThrowFileException(CFileException::endOfFile,12,lpAppPath);<br>        <br>        ASSERT(m_lpAccel==NULL);<br>        <br>        m_lpAccel=new ACCELITEM[dwCount];<br>        memset(m_lpAccel,0,sizeof(ACCELITEM)*dwCount);<br>        m_dwAccelCount=dwCount;</p> <p>        for(DWORD dw=0;dw<dwCount;dw++)<br>        {<br>            if(fAccel.Read(m_lpAccel+dw,sizeof(ACCELITEM))!=sizeof(ACCELITEM))<br>                AfxThrowFileException(CFileException::endOfFile,12,lpAppPath);<br>        }</p> <p>        ACCEL* pAccel=new ACCEL[dwCount];<br>        for(dw=0;dw<dwCount;dw++){<br>            pAccel[dw]=m_lpAccel[dw].accel;<br>        }</p> <p>        m_hActAccel=CreateAcceleratorTable(pAccel,dwCount);</p> <p>        return TRUE;</p> <p>    }</p> <p>    catch(CFileException* e)<br>    {<br>        char buf[256];<br>        char buf2[512];<br>        int iError;<br>        iError=e->m_cause;<br>        e->GetErrorMessage(buf,256);<br>        sprintf(buf2,"从文?\"%s\" 中加?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表时发生错误!\n"<br>                     "???%d\n"<br>                     "错误描述:%s\n"<br>                     "是否生成默认?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>?\n\0",<br>                     strAccelFileName,iError,buf);<br>        if(IDYES==AfxMessageBox(buf2,MB_YESNO|MB_SYSTEMMODAL|MB_ICONSTOP|MB_DEFBUTTON1))<br>        {<br>            ASSERT(m_hActAccel==NULL);<br>            ASSERT(m_lpAccel==NULL);<br>            m_dwAccelCount=sizeof(accel)/sizeof(ACCEL);<br>            m_lpAccel=new ACCELITEM[m_dwAccelCount];<br>            memset(m_lpAccel,0,sizeof(ACCELITEM)*m_dwAccelCount);<br>            DWORD dwCmdStr=sizeof(strCmd)/sizeof(char[30]);<br>            for(DWORD dw=0;dw<m_dwAccelCount;dw++){<br>                m_lpAccel[dw].accel=accel[dw];<br>                strcpy(m_lpAccel[dw].cCmd,dw<dwCmdStr?strCmd[dw]:"Command Unknow");<br>            }<br>            <br>            m_hActAccel=CreateAcceleratorTable(accel,m_dwAccelCount);<br>            SaveAccel();<br>            return TRUE;<br>        }<br>        return FALSE;<br>    }<br>}</p> <p>  最后,在DestroyWindow()函数头部增加对SaveAccel()函数的调用:</p> <p>    SaveAccel();<br>    ...</p> <p>  好了Q你自己?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>数据已经能保存在文g中了Qƈ能从中正加载。如果文件不存在或程序读取时发现错误则提醒你是否建立~省?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表,如你认的话则生成缺省的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表ƈ立刻保存x件中?br>  ׃水^有限Q其中难免有误,Ƣ迎批评指正、发表你的意见。本Z胜感Ȁ?br></p> <img src ="http://www.shnenglu.com/tgh621/aggbug/71821.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/tgh621/" target="_blank">大v</a> 2009-01-12 17:22 <a href="http://www.shnenglu.com/tgh621/archive/2009/01/12/71821.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用WaitForSingleObject{待事g处理http://www.shnenglu.com/tgh621/archive/2009/01/12/71782.html大v大vMon, 12 Jan 2009 02:17:00 GMThttp://www.shnenglu.com/tgh621/archive/2009/01/12/71782.htmlhttp://www.shnenglu.com/tgh621/comments/71782.htmlhttp://www.shnenglu.com/tgh621/archive/2009/01/12/71782.html#Feedback0http://www.shnenglu.com/tgh621/comments/commentRss/71782.htmlhttp://www.shnenglu.com/tgh621/services/trackbacks/71782.html 1void ClearMessage(HWND hWnd,BOOL bExtMsg)
 2{
 3    MSG GetMsg;
 4    while(PeekMessage(&GetMsg,hWnd,0,0,PM_REMOVE))
 5    {        
 6        if(GetMsg.message == WM_TIMER) continue;
 7        TranslateMessage(&GetMsg);
 8        DispatchMessage(&GetMsg);
 9    }
            
10    if(hWnd != NULL && bExtMsg)
11    {    
12        while(PeekMessage(&GetMsg,NULL,WM_WINDOWPOSCHANGING,WM_WINDOWPOSCHANGED,PM_REMOVE))
13        {        
14            TranslateMessage(&GetMsg);
15            DispatchMessage(&GetMsg);
16        }
                                
17        while(PeekMessage(&GetMsg,NULL,0,0,PM_QS_PAINT))
18        {        
19            TranslateMessage(&GetMsg);
20            DispatchMessage(&GetMsg);
21        }

22    }

23}

24
25void CExportRegeditToXml::OnBnClickedCancel()
26{
27
28
29    if ( ( NULL != m_TransRegedit )  && ( !pThreadData->m_brepalce) ) 
30    {
31        if(MessageBox(_T("目前正在导出注册表,是否取消!"),_T("警告"),MB_YESNO)!=IDYES)
32            return;
33        pThreadData->m_brepalce = TRUE;
34
35        while (m_TransRegedit && WaitForSingleObject(m_TransRegedit->m_hThread,40)!=WAIT_OBJECT_0) 
36        {
37            ClearMessage(NULL, TRUE);
38        }

39        m_TransRegedit = NULL;
40    }

41
42    OnCancel();
43}


大v 2009-01-12 10:17 发表评论
]]>
[转]PSD格式文g的读?/title><link>http://www.shnenglu.com/tgh621/archive/2008/12/26/70462.html</link><dc:creator>大v</dc:creator><author>大v</author><pubDate>Fri, 26 Dec 2008 10:15:00 GMT</pubDate><guid>http://www.shnenglu.com/tgh621/archive/2008/12/26/70462.html</guid><wfw:comment>http://www.shnenglu.com/tgh621/comments/70462.html</wfw:comment><comments>http://www.shnenglu.com/tgh621/archive/2008/12/26/70462.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/tgh621/comments/commentRss/70462.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/tgh621/services/trackbacks/70462.html</trackback:ping><description><![CDATA[<font size=2> PhotoShopQ我x有h会不知道吧。如今最新的版本?.0Q其图象文g*.PSD?.5相比变化q不太大。以下我׃l?.PSD文g的读取方法,q提供完整读取函数。其中:m_Rect为目标区域,m_lpDDS7为目标DirectDraw表面Qm_pbAlphaMask为目标Aplha通告指针。Read16函数Z指定文g当前位置d一个WORDQRead32函数Z指定文g当前位置d一个DWORD。MAX_PSD_CHANNELS?4。以下就?.PSD文g的读取方法,有兴的朋友可以l箋深入研究Q到时可别忘了发我一份?br></font></font><font class=f14 id=zoom><font face=宋体><br></font></font><font face=宋体></font></font><font face=Arial><font class=f14 id=zoom><font face=宋体><font color=#99ccff><font size=2><span id="nvxhxrb" class=ColorCode>  HRESULT LoadPSD( LPSTR strFilename )</span> </font><font color=#c0c0c0><span id="ltvxhrp" class=ColorCatchword><font size=2>// dPSD文g</font></span></font><font size=2><br><span id="vnjjndt" class=ColorCode>  {<br>    DWORD dwWidth, dwHeight;</span> <font color=#c0c0c0><span id="ltvhztv" class=ColorCatchword>// 宽高</span></font><br><span id="jblvpfn" class=ColorCode>    long lSurfWidth = m_Rect.right - m_Rect.left;<br>    long lSurfHeight = m_Rect.bottom - m_Rect.top;<br>    WORD CompressionType;</span> <font color=#c0c0c0><span id="lrnpbrn" class=ColorCatchword>// 压羃cd</span></font><br><span id="dbvvhpl" class=ColorCode>    HDC hDC;<br>    FILE *fpPSD;<br>    WORD ChannelCount;</span> <font color=#c0c0c0><span id="jhbnpft" class=ColorCatchword>// 通道?/span></font><br><br><span id="jhtpdrp" class=ColorCatchword>    <font color=#c0c0c0>// 打开PSD文g</font></span><br><span id="hpzdzfl" class=ColorCode>    if ( ( fpPSD = fopen ( strFilename, "rb" ) ) == NULL ) {<br>      return E_FAIL;<br>    }<br></span><br><span id="hzbdfbr" class=ColorCatchword>    <font color=#c0c0c0>// 头四个字节ؓ"8BPS"</font><br></span><span id="zpzbxpx" class=ColorCode>    char signature[5];<br>    signature[0] = fgetc( fpPSD );<br>    signature[1] = fgetc( fpPSD );<br>    signature[2] = fgetc( fpPSD );<br>    signature[3] = fgetc( fpPSD );<br>    signature[4] = '\0';<br>    if ( strcmp( signature,"8BPS" ) != 0 ) {<br>      return E_FAIL;<br>    }<br></span><br><span id="jptlnvt" class=ColorCatchword>    <font color=#c0c0c0>// 版本必须?</font></span><br><span id="xfhbbbz" class=ColorCode>    if ( Read16( fpPSD ) != 1 ) {<br>      return E_FAIL;<br>    }<br></span><br><span id="xtxhrhx" class=ColorCatchword>    <font color=#c0c0c0>// 跌一些数?(L0)</font></span><br><span id="fvxzjpx" class=ColorCode>    Read32( fpPSD );<br>    Read16( fpPSD );<br></span><br><span id="xlxzbzp" class=ColorCatchword>    <font color=#c0c0c0>// d通道?/font><br></span><span id="dlnhjzf" class=ColorCode>    ChannelCount = Read16( fpPSD );</span><br><br><span id="lrbfpfl" class=ColorCatchword>    <font color=#c0c0c0>// 定臛_有一个通道</font><br></span><span id="fvpjtbr" class=ColorCode>    if ( ( ChannelCount < 0 ) || ( ChannelCount > MAX_PSD_CHANNELS ) ) {<br>      return E_FAIL;<br>    }<br></span><br><span id="plfzbxf" class=ColorCatchword>    <font color=#c0c0c0>// d宽和?/font><br></span><span id="lbxhtpf" class=ColorCode>    dwHeight = Read32( fpPSD );<br>    dwWidth = Read32( fpPSD );<br>    if ( dwWidth != ( DWORD )lSurfWidth ||</span> <span id="hxhtdjj" class=ColorCode>dwHeight != ( DWORD )lSurfHeight ) {<br>      return E_FAIL;<br>    }<br></span><br><span id="hxlfzxv" class=ColorCatchword>    <font color=#c0c0c0>// 只读?位通道</font></span><br><span id="hdhzdbp" class=ColorCode>    if ( Read16( fpPSD ) != 8 ) {<br>      return E_FAIL;<br>    }<br></span><br><span id="ndnhrph" class=ColorCatchword><font color=#c0c0c0>    // 定模式为RGB.<br>    // 可能|<br>    // 0: 位图<br>    // 1: 灰阶<br>    // 2: 索引<br>    // 3: RGB<br>    // 4: CMYK<br>    // 7: Multichannel<br>    // 8: Duotone<br>    // 9: Lab</font><br></span><span id="rrblpvb" class=ColorCode>    if ( Read16( fpPSD ) != 3 ) {<br>      return E_FAIL;<br>    }<br></span><br><span id="llvfbpn" class=ColorCatchword>    <font color=#c0c0c0>// 跌数据Q如调色板)</font><br></span><span id="dbnfrhf" class=ColorCode>    int ModeDataCount = Read32( fpPSD );<br>    if ( ModeDataCount )<br>      fseek( fpPSD, ModeDataCount, SEEK_CUR );<br></span><br><span id="pdfjlrz" class=ColorCatchword>    <font color=#c0c0c0>// 跌数据Q如Qpen tool paths, etcQ?/font><br></span><span id="fdxpljx" class=ColorCode>    int ResourceDataCount = Read32( fpPSD );<br>    if ( ResourceDataCount )<br>      fseek( fpPSD, ResourceDataCount, SEEK_CUR );<br><br></span><span id="hfxbdxj" class=ColorCatchword>    <font color=#c0c0c0>// 条过保留数据</font><br></span><span id="hhjlpnb" class=ColorCode>    int ReservedDataCount = Read32( fpPSD );<br>    if ( ReservedDataCount )<br>      fseek( fpPSD, ReservedDataCount, SEEK_CUR );<br></span><br><span id="tjdxhxv" class=ColorCatchword><font color=#c0c0c0>    // 0: 非压~?br>    // 1: RLE压羃</font><br></span><span id="jhrtvtt" class=ColorCode>    CompressionType = Read16( fpPSD );<br>    if ( CompressionType > 1 ) {<br>      return E_FAIL;<br>    }<br><br>    BYTE* PSDPixels = new BYTE[ ( lSurfWidth * lSurfHeight ) * 4 ];<br></span><br><span id="zpjtnfd" class=ColorCatchword><font color=#c0c0c0>    // 解包数据</font><br></span><span id="fnprvtj" class=ColorCode>    UnPackPSD( fpPSD, lSurfWidth, lSurfHeight, PSDPixels, ChannelCount, CompressionType );<br><br>    fclose( fpPSD );<br></span><br><span id="vdnrrzx" class=ColorCatchword><font color=#c0c0c0>    // 复制信息</font><br></span><span id="tztnzxn" class=ColorCode>    BITMAPINFO BitmapInfo;<br>    ZeroMemory( &BitmapInfo, sizeof( BitmapInfo ) );<br>    BitmapInfo.bmiHeader.biSize = sizeof( BitmapInfo.bmiHeader );<br>    BitmapInfo.bmiHeader.biWidth = lSurfWidth;<br>    BitmapInfo.bmiHeader.biHeight = -lSurfHeight;<br>    BitmapInfo.bmiHeader.biPlanes = 1;<br>    BitmapInfo.bmiHeader.biBitCount = 32;<br><br>    m_lpDDS7->GetDC( &hDC );<br><br>    int rc = StretchDIBits( hDC,<br>                0,<br>                0,<br>                lSurfWidth,<br>                lSurfHeight,<br>                0,<br>                0,<br>                lSurfWidth,<br>                lSurfHeight,<br>                PSDPixels,<br>                &BitmapInfo,<br>                DIB_RGB_COLORS,<br>                SRCCOPY );<br><br>    m_lpDDS7->ReleaseDC( hDC );<br><br>    if ( rc == GDI_ERROR ) {<br>      H_ARRAY_DELETE( PSDPixels );<br><br>  #ifdef _DEBUG<br>    g_pHERR->OutDebugMsg( 3, H2DSERR_INVALID_PSD );<br>  #endif<br>    return E_FAIL;<br><br>    }<br><br></span></font><span id="hhblxvr" class=ColorCatchword><font size=2>   <font color=#c0c0c0> // 是否dAlpha混合通道</font><br></font></span><span id="zvrttjp" class=ColorCode><font size=2>    if( ChannelCount > 3 ) {<br>      m_pbAlphaMask = new BYTE[ lSurfWidth * lSurfHeight ];<br><br>    for ( int x = 0; x < lSurfWidth; x++ )<br>      for ( int y = 0; y < lSurfHeight; y++ ) {<br>        m_pbAlphaMask[ ( y * lSurfWidth ) + x ] =<br>                PSDPixels[ ( ( ( y * lSurfHeight ) + x ) * 4 ) + 3 ];<br>      }<br>    }<br>    else {<br>      m_pbAlphaMask = NULL;<br>    }<br><br>    H_ARRAY_DELETE( PSDPixels );<br><br>    return DD_OK;<br>  }<br><br></font><span id="dzvfzpf" class=ColorCatchword><font size=2>  </font><font color=#c0c0c0 size=2>// PSD文g解包</font><font size=2><br> </font></span></span></font> <div align=left><font color=#99ccff><span id="ftxpjjp" class=ColorCode><font size=2>  void CHades2DSurface::UnPackPSD( FILE *fp,</font></span><font size=2><span id="zhzdvdb" class=ColorCatchword>     // fp为PSD文g指针Q?/span><span id="vbnphhf" class=ColorCode><br>                   DWORD dwWidth,   </span><span id="bzrdfvl" class=ColorCatchword>// dwWidth、dwHeight为宽高,</span><span id="nvfzjzx" class=ColorCode><br>                   DWORD dwHeight,<br>                   BYTE* pixels,</span><span id="rhvztbh" class=ColorCatchword>   // pixels包目标指针,</span><span id="pnjlvtr" class=ColorCode><br>                   WORD ChannelCnt,</span><span id="xvhjltr" class=ColorCatchword>  // ChannelCnt为通道敎ͼ</span><span id="nlxjtbz" class=ColorCode><br>                   WORD Compression )</span></font><span id="hnrbflb" class=ColorCatchword><font size=2> // Compression位压~类型?</font></span></font></div> <div align=left><font color=#99ccff><span id="zrxtlbz" class=ColorCatchword><font size=2>                <br>                 <br></font></span><font size=2><span id="nlfhtzp" class=ColorCode>  {<br>    int Default[4] = { 0, 0, 0, 255 };<br>    int chn[4] = { 2, 1, 0, 3};<br>    int PixelCount = dwWidth * dwHeight;<br><br>    if ( Compression ) {<br>      fseek( fp, dwHeight * ChannelCnt * 2, SEEK_CUR );<br><br>      for ( int c = 0; c < 4; c++ ) {<br>        int pn = 0;<br>        int channel = chn[c];<br><br>        if ( channel >= ChannelCnt ) {<br>          for ( pn=0; pn < PixelCount ;pn++ ) {<br>            pixels[ ( pn * 4 ) + channel ] = Default[ channel ];<br>          }<br>        }<br>        else</span> <span id="hfprdbp" class=ColorCatchword>// 非压~?br></span></font><span id="pfpjljh" class=ColorCode><font size=2>        {<br>          int count = 0;<br>          while( count < PixelCount ) {<br>            int len = fgetc( fp );<br>            if( len == 128 ) { }</font></span></font></div> <div align=left><font color=#99ccff><span id="flpzbbh" class=ColorCode><font size=2>            else if ( len < 128 )</font></span><font size=2> </font><span id="jhbvpvt" class=ColorCatchword><font size=2>// 非RLE</font></span></font></div> <div align=left><font color=#99ccff><span id="flnxzzt" class=ColorCode><font size=2>            {<br>              len++;<br>              count += len;<br>              while(len) {<br>                pixels[ ( pn * 4 ) + channel ] = fgetc( fp );<br>                pn++;<br>                len--;<br>              }<br>            }<br>             else if ( len > 128 )</font></span><font size=2> <span id="znpjtrb" class=ColorCatchword>// RLE打包</span><br></font><span id="llnpjzf" class=ColorCode><font size=2>            {<br>              len ^= 0x0FF;<br>              len += 2;<br>              unsigned char val = fgetc( fp );<br>              count += len;<br>              while( len ) {<br>                pixels[ ( pn * 4 ) + channel ] = val;<br>                pn++;<br>                len--;<br>              }<br>            }<br>          }<br>        }<br>      }<br>    }<br>    else<br>    {<br>      for ( int c=0; c < 4; c++ ) {<br>        int channel = chn[c];<br>        if ( channel > ChannelCnt ) {<br>          for( int pn = 0; pn < PixelCount; pn++ ) {<br>            pixels[ ( pn * 4 ) + channel ] = Default[ channel ];<br>          }<br>        }<br>        else {<br>          for( int n = 0; n < PixelCount; n++ ) {<br>            pixels[ ( n * 4 ) + channel ] = fgetc( fp );<br>          }<br>        }<br>      }<br>    }<br>  }</font></span></font></div> </font></font><font face=宋体></font></font> <img src ="http://www.shnenglu.com/tgh621/aggbug/70462.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/tgh621/" target="_blank">大v</a> 2008-12-26 18:15 <a href="http://www.shnenglu.com/tgh621/archive/2008/12/26/70462.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]GIF文档http://www.shnenglu.com/tgh621/archive/2008/12/26/70461.html大v大vFri, 26 Dec 2008 10:14:00 GMThttp://www.shnenglu.com/tgh621/archive/2008/12/26/70461.htmlhttp://www.shnenglu.com/tgh621/comments/70461.htmlhttp://www.shnenglu.com/tgh621/archive/2008/12/26/70461.html#Feedback0http://www.shnenglu.com/tgh621/comments/commentRss/70461.htmlhttp://www.shnenglu.com/tgh621/services/trackbacks/70461.html阅读全文

大v 2008-12-26 18:14 发表评论
]]>
2021ھƷþþþþӰԺ| ŷ˾þƬ| þ99Ʒŷ| ӰԺ˾þ| þþƷһ| ŷͽxxxxѿþþ| ĻƷѾþ| 㽶þۺӰ| ŷþۺŷ| þþֻоƷձ| þøݾƷԴվ| Ƭѹۿþ| þerƵᆱƷ| ޹˾þۺҰ| þþþëƬ| һһþaþþƷۺ | ɫɫۺϾþҹҹ| ƷȾþþø| Ʒþþþþר| þ99ֻƵƷ6| Ʒ99þþþþլ| þþƷAV| ģ˽ĹƷþ| þùƷһ| ޹ƷȾþ| ߳߳þþ| Ů޾Ʒþþۺ| ձƷһþþ| 91Ʒ91Ⱦþþþø| ۺþþ| ɫۺϾþĻ| ޾ƷþþþþðĦ | 99þһ| Ʒ԰״̼þþ| þۺŷ| ĻþþƷˮ | 99þþùƷţ| Ʒ18þþ⺾ | ɫۺϾþ۾Ʒ| 91ƷۺϾþ| ޾ƷþרӰҵ|