html tool

显示标签为“阅读笔记”的博文。显示所有博文
显示标签为“阅读笔记”的博文。显示所有博文

2024年10月10日星期四

笔记-格鲁夫给经理人的第一课-第11章P173~180

 

关于激励和培训,如何区分是缺乏哪个,用不做就没命方式【eg:不会弹某个曲子就没命,你会弹吗?去考虑是要激励还是要培训,如果还是不会就是要培训了,如果会那就是要激励了】。
关于激励使用马斯特的五个层次的需求,基本需求,安全感,认同,归属和尊重,自我实现;
       前三个是出现在这里的理由,
       但后两个才是更好自我实现的动力
[popexizhi:自己的问题是对自己现在的状态感觉一直是在安全感上有问题,但自己每次操作和努力又是在自我实现上,感觉自己有点儿矛盾,但这里给出的5个阶梯说的是外部看内部,而自己对自己的评估是内部看内部,自己的不安全感应是一些特定情况下出现的,内心最原始的问题;而自我实现是自己的理想,现在意识中认为对的,来源不一致,但如何把这个意识中的追求内化,也不是问题,感觉安全感和这个自我实现不冲突,现在看来不冲突是两个要解决的问题]
 [可剧本lab] 

2019年7月8日星期一

KeDetachProcess与KeAttachProcess的使用场景



KeDetachProcess


  • https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ntifs/nf-ntifs-kedetachprocess

    The KeDetachProcess routine is exported to support existing driver binaries and is obsolete. Use KeUnstackDetachProcess instead

    [popexizhi:
    https://blog.csdn.net/dasgk/article/details/17741289

    KeDetachProcess
      当线程从新的进程中脱离时(KeDetachProcess), 任何在新的进程地址空间中等待执行的未决的内核APCs被派发执行。随后SavedApcState 域的内容被拷贝回ApcState域。SavedApcState 域的内容被清空,线程的ApcStateIndex域被设为OriginalApcEnvironment,ApcStatePointer域更新,当前进程上下文切换到线程所属进程。
        Dettach时,先派发APC State里面的APC,然后再恢复,也就是挂靠过程中线程被插apc现在要集中解决

    [popexizhi: 总结一下,这里KeDetachProcess,是在 KeAttachProcess完成后,将线程从新的进程中脱离过程,这里要先处理APC队列,之后再恢复ApcState域]
    ]
    code 分析
    • + -

      KeAttachProcess

      KiAttachProcess - KeAttachProcess仅仅是对这个函数的封装
      KiSwapProcess - 更换地址空间。(本质上就是重新加载CR3)
      SwapContext - 更换上下文。一般不管地址空间的切换,只调整线程上下文。
      KiSwapThred - 切换到链表中的下一个线程(SwapContext)调用

      • -----------------------------------------------------------------------------
        /************************ KeAttachProcess ***************************/
        // just wrapper
        //
        KeAttachProcess(EPROCESS *Process)
        {
        KiAttachProcess(Process,KeRaiseIrqlToSynchLevel);
        }
        /************************ KiAttachProcess ***************************/

        KiAttachProcess(EPROCESS *Process,Irql){

        //CurThread=fs:124h
        //CurProcess=CurThread->ApcState.Process;

        if(CurProcess!=Process){
        //[popexizhi: 如果要attach 的process非当前进程,才如下操作:]
                if(CurProcess->ApcStateIndex || KPCR->DpcRoutineActive)KeBugCheckEx...
                //[popexizhi:如果当前进程有Apc状态的索引,这个应该是进入apc列表了 CurProcess->ApcStateIndex
                //或者: KPCR 中 有DPC队列,这个是cpu的队列,这里注意是判断是不是这两种软中断中,如果是后面就KeBugCheckEx.. ,传说的系统崩溃吗?
        //]
        }

        //if we already in process's context,
        //[popexizhi: 要attach 的process 就是当前进程,恢复lrql,返回就ok,不用特殊处理了]
        if(CurProcess==Process){KiUnlockDispatcherDatabase(Irql);return;}

        Process->StackCount++;//[?-ok 1- 这是堆栈计数增加一个吗? 不是,参见下文]
        // 注意代码中的Process->StackCount与进程的“堆栈”并无关系,而是指进程挂靠的嵌套深度。
        // http://www.voidcn.com/article/p-umtyvddi-qc.html


        KiMoveApcState(&CurThread->ApcState,&CurThread->SavedApcState);//[ 2-KiMoveApcState, 将当前线程的APC状态保持到SavedApcState中
        //    http://codewarrior.cn/ntdoc/win2k/ke/KiMoveApcState.htm
        //    This function moves the APC state from the source structure to the
        //    destination structure and reinitializes list headers as appropriate.

        // init lists
        CurThread->ApcState.ApcListHead[0].Blink=&CurThread->ApcState.ApcListHead[0]; //[?]3 这里的ApcListHead[01].[Blink,Flink]分别是什么,这操作的目的是?
        /*  [popexizhi: 自己在另外的版本中查到的初始化如下: 这里的InitializeListHead与下面的区别是什么,只是这里做封装了吗?]
        InitializeListHead(&Thread->ApcState.ApcListHead[KernelMode]); //ApcState被初始化
        InitializeListHead(&Thread->ApcState.ApcListHead[UserMode]);
        */
          CurThread->ApcState.ApcListHead[0].Blink=&CurThread->ApcState.ApcListHead[0]; //[?]3 这里的ApcListHead[01].[Blink,Flink]分别是什么,这操作的目的是?
          CurThread->ApcState.ApcListHead[0].Flink=&CurThread->ApcState.ApcListHead[0];
          CurThread->ApcState.ApcListHead[1].Blink=&CurThread->ApcState.ApcListHead[1];
          CurThread->ApcState.ApcListHead[1].Flink=&CurThread->ApcState.ApcListHead[1];;

         //fill curtheads's fields
         CurThread->ApcState.Process=Process;
        //
        CurThread->ApcState.ApcListHead[0].Flink=&CurThread->ApcState.ApcListHead[0];
        CurThread->ApcState.ApcListHead[1].Blink=&CurThread->ApcState.ApcListHead[1];
        CurThread->ApcState.ApcListHead[1].Flink=&CurThread->ApcState.ApcListHead[1];;

        //fill curtheads's fields
        CurThread->ApcState.Process=Process;

        CurThread->ApcState.KernelApcInProgress=0;
        CurThread->ApcState.KernelApcPending=0;
        CurThread->ApcState.UserApcPending=0;

        CurThread->ApcState.ApcStatePointer.SavedApcState=&CurThread->SavedApcState;
        CurThread->ApcState.ApcStatePointer.ApcState=&CurThread->ApcState;

        CurThread->ApcStateIndex=1;

        //if process ready, just swap it...
        if(!Process->State)//state==0, ready
        {
        KiSwapProcess(Process,CurThread->SavedApcState.Process);
        KiUnlockDispatcherDatabase(Irql);
        return;
        }

        CurThread->State=1; //ready?
        CurThread->ProcessReadyQueue=1;

        //put Process in Thread's waitlist
        CurThread->WaitListEntry.Flink=&Process->ReadyListHead.Flink;
        CurThread->WaitListEntry.Blink=Process->ReadyListHead.Blink;

        Process->ReadyListHead.Flink->Flink=&CurThread->WaitListEntry.Flink;
        Process->ReadyListHead.Blink=&CurThread->WaitListEntry.Flink;

        // else, move process to swap list and wait
        if(Process->State==1){//idle?
        Process->State=2; //trans
        Process->SwapListEntry.Flink=&KiProcessInSwapListHead.Flink;
        Process->SwapListEntry.Blink=KiProcessInSwapListHead.Blink;
        KiProcessInSwapListHead.Blink=&Process->SwapListEntry.Flink;
        KiSwapEvent.Header.SignalState=1;
        if(KiSwapEvent.Header.WaitListHead.Flink!=&KiSwapEvent.Header.WaitListHead.
        Flink)
        KiWaitTest(&KiSwapEvent,0xa); //fastcall
        }

        CurThread->WaitIrql=Irql;
        KiSwapThread();
        return;
        }

        从这个函数可以得到以下结论。进程可以处于以下状态——0(准备),1(Idle),2(Tra
        ns——切换)。这证实了高层次的信息。KiAttachProcess使用了另外两个函数KiSwapProce
        ss和KiSwapThread。

        /************************* KiSwapProcess ****************************/

        KiSwapProcess(EPROCESS* NewProcess, EPROCESS* OldProcess)
        {
        // just reload cr3 and small work with TSS

        // TSS=KPCR->TSS;
        // xor eax,eax
        // mov gs,ax
        TSS->CR3=NewProcess->DirectoryTableBase;//0x1c
        // mov cr3,NewProcess->DirectoryTableBase
        TSS->IopmOffset=NewProcess->IopmOffset;//0x66
        if(WORD(NewProcess->LdtDescriptor)==0){lldt 0x00; return;//}
        //GDT=KPCR->GDT;
        (QWORD)GDT->0x48=(QWORD)NewProcess->LdtDescriptor;
        (QWORD)GDT->0x108=(QWORD)NewProcess->Int21Descriptor;
        lldt 0x48;
        return;
        }

        切换进程上下文。正如我所料,这个函数只是重新加载CR3寄存器,再加上一点相关的操作。
        例如,用IopmOffset域的值建立TSS中的I/O位图的偏移。还必需将选择子的值加载到ldt(只
        用于VDM session)。

        /************************* SwapContext ******************************/

        SwapContext(NextThread,CurThread,WaitIrql)
        {

        NextThread.State=ThreadStateRunning; //2
        KPCR.DebugActive=NextThread.DebugActive;

        cli();

        //Save Stack
        CurThread.KernelStack=esp;

        //Set stack
        KPCR.StackLimit=NextThread.StackLimit;
        KPCR.StackBase=NextThread.InitialStack;

        tmp=NextThread.InitialStack-0x70;
        newcr0=cr0&0xfffffff1|NextThread.NpxState|*(tmp+0x6c);
        if(newcr0!=cr0)reloadcr0();
        if(!*(tmp-0x1c)&0x20000)tmp-=0x10;
        TSS=KPCB.TSS;
        TSS->ESP0=tmp;

        //set pTeb
        KPCB.Self=NextThread.pTeb;
        esp=NextThread.KernelStack;
        sti();

        //correct GDT
        GDT=KPCB.GDT;
        WORD(GDT->0x3a)=NextThread.pTeb;
        BYTE(GDT->0x3c)=NextThread.pTeb>>16;
        BYTE(GDT->0x3f)=NextThread.pTeb>>24;

        //if we must swap processes, do it (like KiSwapProcess)

        if(CurThread.ApcState.Process!=NextThread.ApcState.Process)
        {
        //******** like KiSwapProcess
        }

        NextThread->ContextSwitches++;

        KPCB->KeContextSwitches++;

        if(!NextThread->ApcState.KernelApcPending)return 0;

        //popf;
        // jnz HalRequestSoftwareInterrupt// return 0

        return 1;
        }

        切换堆栈,修正GDT,以使FS寄存器指向TEB。如果线程属于当前进程,则不进行上下文切换
        。否则,进行的操作和KiSwapProcess中的大致差不多。


5.Hook/Notity-eg中book的code与项目中不一致的问题

P476 - 5eg :

book code : 
InjectShellCodeToProcess(pTargetProc, pContext, g_DllPathToInject)
source code:
status = InjectShellCodeToProcessByModifyContext(pContext,g_DllPathToInject);

list ?:

  • why change? pTargetProc 去哪里了?不需要了吗?

  • 回答:  [这里的过程, InjectShellCodeToProcessByModifyContext 的input是改自身copy的pContext,不用pTargetProc 了.]

  • what for 这里的功能解释是?

  • 回答: [修改copy 自目标targetThread 的 pContext]
  • NTSTATUS InjectShellCodeToProcessByModifyContext(PCONTEXT pContext,WCHAR *wstrDllPath)
    的定义中如下:
    uNtdllBase = FindImageBase(NtCurrentProcess(),L"ntdll.dll");   
    //[popexizhi: ?why? ntdll.dll 这个和下面的LdrLoadDll 都是要注册的目标线程中的吗?  ]                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
    if (uNtdllBase != 0)
    {
    //先申请内存
    status = ZwAllocateVirtualMemory(NtCurrentProcess(),
    &pData,0,&MemSize,MEM_COMMIT,PAGE_EXECUTE_READWRITE);

    if (NT_SUCCESS(status))
    {
    dprintf("Allocated Mem = 0x%p\n",pData);
    dprintf("ntdll.dll Base = 0x%p \n",uNtdllBase);
    AddrOfLdrLoadDll = KeGetProcAddress(uNtdllBase,"LdrLoadDll");
    dprintf("LdrLoadDll = 0x%p \n",AddrOfLdrLoadDll);

2019年7月4日星期四

认知天性-记忆宫殿的另一种使用

认知天性-记忆宫殿的另一种使用
P206

"记忆宫殿不仅是一种学习工具,还是一种将所学组织起来的,以便...随时检索的方法",从开始学习记忆宫殿到现在有10多年了,但是一直感觉这种方法的有一个巨大的弊端就是没有对知识本身的进一步理解,只是为了记忆而记忆,效果只是看上去和听说起来像一个传说,对学习本身没有更大的帮助,自己以为如果这个不值得深入,所以也没有精通的练习,但这里很好的解答了我的这个疑问,是没有想到这个用法,这里作者提到的金成铉的使用就很好的解答了可以进一步加深对学习内容的理解和使用的问题。
打算好好实验和练习!!!
另外此书是指导性的,指南性质的,感觉要看就一定要联系和使用,否则本身的意义不大。本来有不少原书的笔记,但是鉴于多是练习的,就不再写了,去练习了,在练习中检索和获得了:)

2018年11月1日星期四

PE文件结构-导出表


看到PE导出表一处,如下写:
扩展名为.exe 的PE 文件中一般不存在导出表,而大部分的.dll 文件中都包含导出表。但注意,这并不是绝对的。例如纯粹用作资源的.dll 文件就不需要导出函数啦,另外有些特殊功能的.exe 文件也会存在导出函数。 

[go] 了一下这个有导出表的exe,---

ntoskrnl.exe 


参考:https://blog.csdn.net/stjkwsry/article/details/1480268

刚刚知道这个ntoskrnl.exe是windows的核心啊,它就是当前在运行的windows本身,上面如此介绍:

ntoskrnl.exe是保护性的进程,在你计算机反复启动的情况下出现。在正常情况下,在任务管理器是不会有该进程的


2018年4月26日星期四

转:摘抄 :我在商学院学了什么



https://www.douban.com/note/255174701/



就像我所喜欢的老师 Richard Mitchell 在他的书“The Gift of Fire”【2】所说的,教育不是我们坐在教室里就自然发生了。仅仅告诉我们一些理论,一些知识,是没用的。(天知道我多少次告诉自己要把时间精力花在最有用的行为上,而不是节省些无关大局的小钱。)我们需要被打动,让所听到的东西真正印入脑海,在未来关键的时刻浮现,改变我们的行为,让我们做出正确的决定

2017年5月21日星期日

好久没看的的 语不惊人系列笔记




  1. 许多人总感觉自己努力无效,那是因为你意识不到努力与产出的周期。有人今天稍有点努力,就迫不及待与他人相比,却不知道你要比的是人家三年之累积,这种比较让许多人生出无力感——必须要记住,今天的努力,是为了三年后甚至十年后的效果。而你今天的状态,是你三年前甚至十年前努力的结果。
  2. 我们总是喜欢拿“顺其自然”来敷衍人生道路上的荆棘坎坷,却很少承认,真正的顺其自然,其实是竭尽所能之后的不强求,而非两手一摊的不作为。——瑞卡斯
  3. 只有一件事会使人疲劳:摇摆不定和优柔寡断。——斯蒂芬·茨威格《人类群星闪耀时》
  4. 如果一样东西你得到了,却觉得不过如此,那么这个想得到其实就是你的欲望,如果一样东西你得到以后依然爱不释手,这才是你真正想要的。popexizhi:可以一试
  5. 什么是自卑?阿德勒给出的定义是:当一个人面对他无法应付的问题时,他表示绝对无法解决这个问题,此时出现的便是自卑情结。战胜自卑也就意味着战胜自我。这是一场自己与自己的角逐,是一次与自己内心的真实对话,是一个自己向自己学习的过程,更是另外一次与自己息息相关的人生。
  6. 人们看上去很懒散的时候,通常是因为已经精疲力尽了。表面上的顽固不化经常是因为缺乏清晰的方向所导致的。 这恰好是骑象人所处的窘境,他原地打转,左顾右盼且苦恼不堪,却永远无法迈出一步。
  7. 不要怕某种性格会得罪人,要知道世界上没有任何一种性格能避免得罪人,说话直的会得罪小人,说话委婉的会得罪急脾气,老好人会得罪有原则的人,圆滑的人会得罪聪明人……既然都会得罪人,那就做你自己,做好了自己,就不怕得罪人,因为你可以承担后果。——刘同
  8. 太把自己当回事,内心就不会有真正的自由。:)
  9. 工作的能力就是能把一个大目标,拆解成小步骤,问题如果没有被拆解不仅自己会乱作一团,别人也没法帮你。工作能力强的高手,并不是说他什么事儿都能搞定,而是指他能把目标拆解成一个个要么自己可以搞定,要么可以明确求助于别人的小步骤,把怎么做的大问题变成了选择什么资源做的小问题,这就是工作能力。
  10. 笑的确可以说是人面上的电光,眼睛突然增添了明亮,唇吻间闪烁着牙齿的光芒。——钱钟书
  11. 你一定要有断舍离的勇气,有断才有续,有舍才有得,有离才有合。当一种关系需要你委曲求全去继续,不断牺牲利益去维护时,其实,它早该结束了。你若没这魄力,那么就会被拖入万丈深渊,你若有这果断,前面自是阳光明媚,如何选择,端看自己。
  12. 正确的思考来源于对概念边界的正确界定和操作
  13. 一位印度老人对孙子说:“每个人身体里都有两只狼,它们残酷的相互搏杀。一只代表:愤怒、嫉妒、骄傲、害怕、耻辱;另一只代表:温柔、善良、感恩、希望、微笑和爱。” 小男孩问:“爷爷,哪只狼更厉害?” 爷爷回答:“你喂食的那一只。”
摘录:http://www.zreading.cn/wap/index-wap2.php?p=5875

2015年3月18日星期三

Dive into Python 的我的翻译------Chapter 15. Refactoring VII [15.3.Refactoring I]

The best thing about comprehensive unit testing is not the feeling you get when all your test cases finally pass, or even the feeling you get when someone else blames you for breaking their code and you can actually prove that you didn't. The best thing about unit testing is that it gives you the freedom to refactor mercilessly.
[pope译]

       完整的单元测试的最大好处,不是当你测试用例全部通过测试的感觉;甚至也不是有人指责{blames}你引起他的代码问题{breaking their code}时 ,你可以证明你没有;单元测试带给你最好的事情是你可以自由的狠狠的{mercilessly}重构你的代码。    

Refactoring is the process of taking working code and making it work better. Usually, "better" means "faster", although it can also mean "using less memory", or "using less disk space", or simply "more elegantly". Whatever it means to you, to your project, in your environment, refactoring is important to the long-term health of any program.
[pope译]

       重构在使用中代码的过程是使其工作得更好,一般来说,"更好"意味着"更快",尽管{although}它可能也意味这着"使用更少的内存",或者“使用更少的磁盘空间”,或者更简单“更加优雅{elegantly}”.无论在你的环境中它对你和你的项目意味着什么,重构对任何程序的长期健康{long-term health}都很重要。

 Here, "better" means "faster". Specifically, the fromRoman function is slower than it needs to be, because of that big nasty regular expression that you use to validate Roman numerals. It's probably not worth trying to do away with the regular expression altogether (it would be difficult, and it might not end up any faster), but you can speed up the function by precompiling the regular expression.
[pope译]
这里,"更好"意味着"更快"。特别是{specifically},这个fromRoman函数比需要的慢,由于这个大而不好的是用来确定{validate}罗马字符的正则表达式.它可能并不值得尝试去除在一起的正则表达(这个可能有点儿难,并且它可能还没更快点儿),但你可以通过预编译{precompiling}这个正则表达式来达到提速这个函数。     

2015年3月17日星期二

Dive into Python 的我的翻译------Chapter 15. Refactoring VI [15.2. Handling changing requirements IV]

Example 15.8. Coding the new requirements

  •        1.toRoman only needs one small change, in the range check. Where you used to check 0 < n < 4000, you now check 0 < n < 5000. And you change the error message that you raise to reflect the new acceptable range (1..4999 instead of 1..3999). You don't need to make any changes to the rest of the function; it handles the new cases already. (It merrily adds 'M' for each thousand that it finds; given 4000, it will spit out 'MMMM'. The only reason it didn't do this before is that you explicitly stopped it with the range check.)
    [pope译]toRoman 仅需要在范围检查中做一个小的改变。在你使用0 2.You don't need to make any changes to fromRoman at all. The only change is to romanNumeralPattern; if you look closely, you'll notice that you added another optional M in the first section of the regular expression. This will allow up to 4 M characters instead of 3, meaning you will allow the Roman numeral equivalents of 4999 instead of 3999. The actual fromRoman function is completely general; it just looks for repeated Roman numeral characters and adds them up, without caring how many times they repeat. The only reason it didn't handle 'MMMM' before is that you explicitly stopped it with the regular expression pattern match
    [pope译]
    你不需要为fromRoman做任何改变。唯一要变的是romanNumeralPattern;如果你仔细看{look closely}你会主要到在正则表达式的第一块{section}加入一个M.这样允许4个M代替3个M,这意味着你将允许罗马字符4999来替代3999.这个实际上{actual}fromRoman函数是完全可以的{completely general};它仅寻找替代的罗马字符并将其拼装起来,不关心{caring}替换了多少次.之前唯一没有打出'MMMM'的原因是你在正则表达执行匹配式停止了它.
    You may be skeptical that these two small changes are all that you need. Hey, don't take my word for it; see for yourself:
    [pope译]
    你可能怀疑{skeptical} 你只要做两个小的改变。嗨,别看这个,注意你自己的
    [popexizhi]这个 don't take your word for it,see for yourself.可以这样翻译吗?
  •  Example 15.9. Output of romantest72.py against roman72.py
    • All the test cases pass. Stop coding.
      Comprehensive unit testing means never having to rely on a programmer who says "Trust me."
      [pope译]
      所有的测试用例通过了,停止编码。
      完整的单元测试意味着从没有依赖{rely on}编程者说"相信{trust}我"    
        

获得控制台打印信息[java&python]

问题:如何获得命令行的打印信息到程序中
[解决]
python版一直在用,总结一下:
add:http://www.360doc.com/content/13/1226/23/8504707_340405307.shtml
ss=os.popen("1.sh").readlines()
    print ss
#获得sh脚本打印内容并输出
[popexizhi]获得python 的print的输出值
self.__console__=sys.stdout
-------------------------------------------------
java版
add:http://zhidao.baidu.com/question/541158774.html
//测试cmd打印导入
import java.lang.System;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.IOException;
     //testcmd 打印信息
    try {
       Process child=Runtime.getRuntime().exec("ping 192.168.20.10");
       final InputStream inputStream = child.getInputStream();
       final BufferedReader brOut = new BufferedReader(new InputStreamReader(inputStream));
       String line = null;
       while ((line = brOut.readLine()) != null) {
           //将文本打印到控制台
           System.out.println(line);
       }
                                                                                                               
    } catch (IOException e1) {
       e1.printStackTrace();
    }

2015年3月10日星期二

Dive into Python 的我的翻译------Chapter 15. Refactoring V [15.2. Handling changing requirements III]

Example 15.7. Output of romantest71.py against roman71.py

  • code
    • fromRoman should only accept uppercase input ... ERROR ----------------1
      toRoman should always return uppercase ... ERROR
      fromRoman should fail with blank string ... ok
      fromRoman should fail with malformed antecedents ... ok
      fromRoman should fail with repeated pairs of numerals ... ok
      fromRoman should fail with too many repeated numerals ... ok
      fromRoman should give known result with known input ... ERROR-----------2
      toRoman should give known result with known input ... ERROR-------------3
      fromRoman(toRoman(n))==n for all n ... ERROR----------------------------4
      toRoman should fail with non?integer input ... ok
      toRoman should fail with negative input ... ok
      toRoman should fail with large input ... ok
      toRoman should fail with 0 input ... ok
    1.Our case checks now fail because they loop from 1 to 4999, but toRoman only accepts numbers from 1 to 3999, so it will fail as soon the test case hits 4000.
    [pope译]
    我们的用例检查失败了因为他们是从1到4999的循环,但是toRoman仅仅支持从1到3999的循环,所以在它遇到4000的测试用例时失败了。
    2.The fromRoman known values test will fail as soon as it hits 'MMMM', because fromRoman still thinks this is an invalid Roman numeral
    [pope译]fromRoman在遇到'MMMM'时测试失败了,因为fromRoman仍然认为这是一个有问题的罗马数字
    3.The toRoman known values test will fail as soon as it hits 4000, because toRoman still thinks this is out of range
    [pope译] toRoman知道它遇到4000的值时测试失败,因为toRoman仍然认为这个超出范围了。
    4.The sanity check will also fail as soon as it hits 4000, because toRoman still thinks this is out of range.
    [pope译]
    这个完整性{sanity}测试在撞到4000时仍然失败,以为toRoman认为这个超出范围
    Now that you have test cases that fail due to the new requirements, you can think about fixing the code to bring it in line with the test cases. (One thing that takes some getting used to when you first start coding unit tests is that the code being tested is never "ahead" of the test cases. While it's behind, you still have some work to do, and as soon as it catches up to the test cases, you stop coding.)

    [pope译]现在测试用例由于新的需求而失败,你可以想想如何修改这些代码向这些测试用例看齐{to bring it in line}(有件事要花些时间适应{one thing that takes some getting used to},当你首次开始单元测试,那些被测代码从未"领先"{ahead}于测试用例。当它们在后面时{behind},你仍有些工作要做,在它们赶上测试用例后,你才可以停止编码)
    [popexizhi]这个就是TDD的要求吧,自己一直在转变自己的coding方式,这个应该多思考和实践,我现在遇到的新问题是,测试代码如何测试?:)我说的至少包括testcase和自动化的测试代码部分两种。    

2015年3月5日星期四

Dive into Python 的我的翻译------Chapter 15. Refactoring IV [15.2. Handling changing requirements II]


Example 15.6. Modifying test cases for new requirements (romantest71.py)

  • + - code
    • import roman71
      import unittest
      class KnownValues(unittest.TestCase):
      knownValues = ( (1, 'I'),
      (2, 'II'),
      (3, 'III'),
      (4, 'IV'),
      (5, 'V'),
      (6, 'VI'),
      (7, 'VII'),
      (8, 'VIII'),
      (9, 'IX'),
      (10, 'X'),
      (50, 'L'),
      (100, 'C'),
      (500, 'D'),
      (1000, 'M'),
      (31, 'XXXI'),
      (148, 'CXLVIII'),
      (294, 'CCXCIV'),
      (312, 'CCCXII'),
      (421, 'CDXXI'),
      (528, 'DXXVIII'),
      (621, 'DCXXI'),
      (782, 'DCCLXXXII'),
      (870, 'DCCCLXX'),
      (941, 'CMXLI'),
      (1043, 'MXLIII'),
      (1110, 'MCX'),
      (1226, 'MCCXXVI'),
      (1301, 'MCCCI'),
      (1485, 'MCDLXXXV'),
      (1509, 'MDIX'),
      (1607, 'MDCVII'),
      (1754, 'MDCCLIV'),
      (1832, 'MDCCCXXXII'),
      (1993, 'MCMXCIII'),
      (2074, 'MMLXXIV'),
      (2152, 'MMCLII'),
      (2212, 'MMCCXII'),
      (2343, 'MMCCCXLIII'),
      (2499, 'MMCDXCIX'),
      (2574, 'MMDLXXIV'),
      (2646, 'MMDCXLVI'),
      (2723, 'MMDCCXXIII'),
      (2892, 'MMDCCCXCII'),
      (2975, 'MMCMLXXV'),
      (3051, 'MMMLI'),
      (3185, 'MMMCLXXXV'),
      (3250, 'MMMCCL'),
      (3313, 'MMMCCCXIII'),
      (3408, 'MMMCDVIII'),
      (3501, 'MMMDI'),
      (3610, 'MMMDCX'),
      (3743, 'MMMDCCXLIII'),
      (3844, 'MMMDCCCXLIV'),
      (3888, 'MMMDCCCLXXXVIII'),
      (3940, 'MMMCMXL'),
      (3999, 'MMMCMXCIX'),
      (4000, 'MMMM'),            ----------------------------------------------1
      (4500, 'MMMMD'),
      (4888, 'MMMMDCCCLXXXVIII'),
      (4999, 'MMMMCMXCIX'))
      def testToRomanKnownValues(self):
      """toRoman should give known result with known input"""
      for integer, numeral in self.knownValues:
      result = roman71.toRoman(integer)
      self.assertEqual(numeral, result)
      def testFromRomanKnownValues(self):
      """fromRoman should give known result with known input"""
      for integer, numeral in self.knownValues:
      result = roman71.fromRoman(numeral)
      self.assertEqual(integer, result)
      class ToRomanBadInput(unittest.TestCase):
      def testTooLarge(self):
      """toRoman should fail with large input"""
      self.assertRaises(roman71.OutOfRangeError, roman71.toRoman, 5000)-----------2
      def testZero(self):
      """toRoman should fail with 0 input"""
      self.assertRaises(roman71.OutOfRangeError, roman71.toRoman, 0)
      def testNegative(self):
      """toRoman should fail with negative input"""
      self.assertRaises(roman71.OutOfRangeError, roman71.toRoman, ?1)
      def testNonInteger(self):
      """toRoman should fail with non?integer input"""
      self.assertRaises(roman71.NotIntegerError, roman71.toRoman, 0.5)
      class FromRomanBadInput(unittest.TestCase):
      def testTooManyRepeatedNumerals(self):
      """fromRoman should fail with too many repeated numerals"""
      for s in ('MMMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):  --------------3
      self.assertRaises(roman71.InvalidRomanNumeralError, roman71.fromRoman, s)
      def testRepeatedPairs(self):
      """fromRoman should fail with repeated pairs of numerals"""
      for s in ('CMCM', 'CDCD', 'XCXC', 'XLXL', 'IXIX', 'IVIV'):
      self.assertRaises(roman71.InvalidRomanNumeralError, roman71.fromRoman, s)
      def testMalformedAntecedent(self):
      """fromRoman should fail with malformed antecedents"""
      for s in ('IIMXCC', 'VX', 'DCM', 'CMM', 'IXIV',
      'MCMC', 'XCX', 'IVI', 'LM', 'LD', 'LC'):
      self.assertRaises(roman71.InvalidRomanNumeralError, roman71.fromRoman, s)
      def testBlank(self):
      """fromRoman should fail with blank string"""
      self.assertRaises(roman71.InvalidRomanNumeralError, roman71.fromRoman, "")
      class SanityCheck(unittest.TestCase):
      def testSanity(self):
      """fromRoman(toRoman(n))==n for all n"""
      for integer in range(1, 5000):    --------------------------------------------4
      numeral = roman71.toRoman(integer)
      result = roman71.fromRoman(numeral)
      self.assertEqual(integer, result)
      class CaseCheck(unittest.TestCase):
      def testToRomanCase(self):
      """toRoman should always return uppercase"""
      for integer in range(1, 5000):
      numeral = roman71.toRoman(integer)
      self.assertEqual(numeral, numeral.upper())
      def testFromRomanCase(self):
      """fromRoman should only accept uppercase input"""
      for integer in range(1, 5000):
      numeral = roman71.toRoman(integer)
      roman71.fromRoman(numeral.upper())
      self.assertRaises(roman71.InvalidRomanNumeralError,
      roman71.fromRoman, numeral.lower())
      if __name__ == "__main__":
      unittest.main()
    1.The existing known values don't change (they're all still reasonable values to test), but you need to add a few more in the 4000 range. Here I've included 4000 (the shortest), 4500 (the second shortest), 4888 (the longest), and 4999 (the largest).
    [pope译]
    当前知道值并没有改变(它们仍然是合理的测试值),但你需要在4000的行后添加更多的测试数据。这里我加入了4000(最小值),4500(第二小的值),4888(较大值),4999(最大值)
    2.The definition of "large input" has changed. This test used to call toRoman with 4000 and expect an error; now that 4000-4999 are good values, you need to bump this up to 5000
    [pope译]
    定义"最大输入"的改变.这个测试使用的4000调用toRoman并且预期一个错误抛出,现在4000~4999都是正常值,你需要修改为5000
    3.The definition of "too many repeated numerals" has also changed. This test used to call fromRoman with 'MMMM' and expect an error; now that MMMM is considered a valid Roman numeral, you need to bump this up to 'MMMMM'.
    [pope译] "过多重复字符"的定义也需要改变。这个测试使用"MMMM"调用fromRoman 并且 预期一个错误抛出,现在MMMM被认为是一个有效个罗马字符,你需要跟新它为'MMMMM'.
    4.The sanity check and case checks loop through every number in the range, from 1 to 3999. Since the range has now expanded, these for loops need to be updated as well to go up to 4999.
    [pope译]
    完整性测试{santiy check}用例通过检查范围中的1~3999的每个数字。由于这个范围限制扩展了,循环上限要跟新到4999.
    Now your test cases are up to date with the new requirements, but your code is not, so you expect several of the test cases to fail.
    [pope译]
    现在你的测试用例跟新需求的新数据,但你的代码没有更新,所以执行测试测试用例有失败的。    

Dive into Python 的我的翻译------Chapter 15. Refactoring III [15.2. Handling changing requirements]

       15.2. Handling changing requirements
       Despite your best efforts to pin your customers to the ground and extract exact requirements from them on pain of horrible nasty things involving scissors and hot wax, requirements will change.
Most customers don't know what they want until they see it, and even if they do, they aren't that good at articulating what they want precisely enough to be useful. And even if they do, they'll want more in the next release anyway. So be prepared to update your test cases as requirements change.

[pope译] 尽管{despite}你尽力{efforts}站在{pin}客户的角度,提取出{extract}准确的{exact}需求,来自于他们可怕{horribe}污秽{nasty}之物的痛苦{pain} 包括 剪刀{scissors}和很烫的蜡油{hot wax},需求还是会变动。
多数客户并不知道他们到底要什么直到他们看到所要的;并且即使他们知道自己想要什么,他们也不能清晰的{articulating}描述出什么对他们有用;并且即使他们可以清晰描述他们想要的,他们也将在下个版本要求的更多。所以准备{prepared}更新你的测试用例在需求改变时。
[popexizhi]"from them on pain of horrible nasty things involving scissors and hot wax"这个的准确翻译是什么比较好呢?从水深火热中抢救出?! :)好吧反正是琐碎痛苦的事。

  Suppose, for instance, that you wanted to expand the range of the Roman numeral conversion functions. Remember the rule that said that no character could be repeated more than three times? Well, the Romans were willing to make an exception to that rule by having 4 M characters in a row to represent 4000. If you make this change, you'll be able to expand the range of convertible numbers from 1..3999 to 1..4999. But first, you need to make some changes to the test cases.

[pope译]
假设,这个例子中,你想要扩展罗马字符转换函数的行列内容。记得那个规则说的是不能有字符多于三次出现吗?很好,罗马字母将扩展这个规则为可以有4个M来描述4000.如果你实现这个改变,你将扩展这个字符串从1~3999为1~4999.但首先你需要在测试用例中做一些改变。     

2014年6月26日星期四

转载:对不起,我并不愿意说服你

来源地址:http://www.xiaoqiushui.com/archives/8892.html

人很难说服固执的人,也无法叫醒装睡的人,事实上,一个人固执久了,不见得清楚,反而觉得自己掌握了真理,装睡久了,会以为自己真的睡着了,而且沉浸于美好的幻梦。对于叫醒他们的人,他们未必会感激,反而可能愤恨——“给我一颗唆麻。”他们想要的,其实是这个。

唆麻是有的,身心灵、开悟、成功学、灵修、五颜六色各种滋味的鸡汤……没有免费的唆麻,都需要购买,金钱、时间,或者灵魂。

我不卖唆麻。我固然是一个传道者,但不是传教者。脱离了传统组织的好处,就是自由。以前,为了公司利益,总需要扛着枪往前闯,违心的话也必须说,现在,都不用了。
我虽然也是一个销售者,销售书籍、培训、课程、顾问服务等,不过,我只想找到需要这些产品或服务的人。不多,可能只是小众。人太多的话,我和我的团队服务不过来。我又不想发展成人多事杂的公司。我做广告,测试各种手法,但是必然适度,我不做我自己都反感的事,我更愿意成为一个营销艺术家。
所以,我并不想说服谁,等他们自己需要的时候,也许会想起我。想不起也没关系,市面上类似的服务提供者有很多,从中受益就好。

同样的一篇文章,有人激赞,有人痛骂,赞和骂,都有道理,每个人是透过自己的心智模式看世界,一句话,可能说到一个人心坎上,也可能正踩了另一人的痛脚。我看人们的反应,觉得也是有趣的事情:每一个ID背后,都是一个真实的人,都有一份不同的人生路线。一个人的心迹,其实可能在虚拟空间里展露无遗,而在现实世界里,也许还需要伪装。

有次,一个人,应该是小女孩吧,从语气里猜的,问我一个问题,我答了,可能她对我的答复不够满意,对我说,“愿你终生孤独!”我惊了一下,不是被这句看似诅咒的话本身,而是她语气中的怨毒,当然我不会因此中蛊,我担忧她怀着这样的怨毒生活,会不会遇到阻碍多些——当然我很快就放下了,因为为陌生人实在操不上心,各有各的缘法。

人们不同意我的话,有些,是我思考不周密,我会吸取、改正; 有些,是人们自己的知障,对于一些人,我愿意诚恳指出,因为从态度上可以判断,如果对方不开心,我就道歉、后退。对于一些人,我肯定不说,不是藏私,而是说了也没有用。有人说《犬夜叉》这样幼稚的内容竟然推荐,我也无话好说。看热闹和学习的心是不一样的,但是,后者,也是一种“揭破”,“揭破”有时候是残忍的,就象陷入传销迷局的人们,他们相信明天就会成为亿万富翁,兴奋得眼睛都红了,如果有人告诉他,那不过是骗局,他可能会拿刀砍人——砍的不是骗他的人,而是揭破真相的人。

世界上总有爱智求真的人,多和他们在一起,多在他们身上尽点心,不是不悲悯,而是,时间太紧迫,人生几十年,说过也就过了,我不是佛陀,没有能力普渡众生。世界太美丽,它催促我前去,匆忙的行道途中,我一直都在分享所知所得,我也许在明天获取新的知识之后,推翻我今日所说,然而自始至终,我都是真诚的。在这个缺少信任的世界,信任是奢侈品,穿着布鞋的我,只享受一部分人的信任就好了。

有这些信任,世界已经足够美好。
……………………
本站采用创作共用版权协议, 要求署名、非商业用途和保持一致. 转载本站内容必须也遵循“署名-非商业用途-保持一致”的创作共用协议.除非注明,均为原创文章,转载请注明:
 转载自逍遥游·萧秋水

2014年5月11日星期日

摘录:语不惊人死不休(123)夫天地者,万物之逆旅,光阴者,百代之过客


add:http://www.zreading.cn/archives/4349.html
---------------------------------------------------------
很喜欢一类人,他们本身很有故事却不会夸夸其谈,善于发现倾听者的情绪并且及时克制转而变成倾听者。你会感受到他们的自信,又能感到他对世界的谦和。大概他们一路努力之后,发现了更多的故事,并且学会了从自身得到肯定和对他人尊重。有自己的坚持,不随意批判别人,不会引起他人的不适。[popexizhi:这个就是传说中的绅士吧:)]
[北京 异地就医登记表 可以报销医保内容]
这些年,我已逐渐学会接受,接受意外,接受变节,接受误解,接受努力了却得不到回报,接受世界的残忍和人性的残缺。但这不代表我妥协,我还会去努力,去爱,去为遥不可及的一切付出心血。不患得患失,不怕翻脸,不惯着任何人,亦不做亏心事。朝着这个目标前行。因为,我还相信梦想,相信奇迹。[popexizhi:很美好的感觉,希望自己也可以做到]
怎样做个好丈夫,就是在太太喜欢的时候,你跟着喜欢,可是太太生气的时候,你不要跟着生气。一一林语堂[:)]
男人要记住,与女人吵架的要领是,要像在安装软件或注册网站时阅读“服务条款”那样,直接忽略所有的内容,到最后面勾选“我同意”,然后点击“确定”[:)]
某天和女友躺一起看电视,女友突然问我:“你喜欢日本姑娘吗?” 我回答:“当然不喜欢”。 其实我想说我只喜欢你,话还没说出,一巴掌过来了:“不喜欢今晚睡沙发去”。 我瞬间凌乱了。。.. PS看了3遍才明白!![popexizhi: :) 我也看了好几遍啊]
[当我抱着她的时候,我想的是另一个她。这时我突然在想,那她抱著我的时候,是不是想的是另一个他。——@朱德庸[?-?]]
[如何降低自己的择偶标准? 神回复:照镜子,拿存折,看尺子!]
适合的恋爱的男人,有几个大原则:遵守契约,爱情与婚姻都是两个人的约定,大到需不需要独占的忠诚,小到能不能干涉对方的生活习惯,未必会一条条详细开列,但双方应该都有大致的方案,不遵守约定,要么关系破裂,要么胁迫、强压另一方接受,都不让人开心。[popexizhi:不止男士吧,健康的婚姻应该双方都如此吧]
这就好比是花。要是你爱上了某颗星星上的一朵花,那么,当你在夜间仰望星空的时候,你就会感到甜蜜愉快,满天的星星都开遍了鲜花。——《小王子》[popexizhi:好美的景象,但确实如此啊]
在这世界上生存,具备一定的预见能力和宽恕能力合乎我们争取幸福的目的:前者帮助我们避免受到伤害和损失,后者则为我们免除了人事纷争和吵闹。——叔本华 +1000
成长是一件很奇妙的事情。成长是,不再为理想或者现实忧伤或者愤怒,而是成功地进行人格分裂。分裂的两边彼此清醒地看着对方的迷醉、狂欢和追求。这分裂的两边相离得越远,二者便越是接近,抵达幸福的理想边缘。很多时候我们的生活中学到的不过是技巧,很多人以为那些与世界周旋的技巧就是生活本身,谓之“成熟”。你可能对生活已经比从前宽容很多,对别人也是,你越来越没有脾气。可是很多事情,一点没有变,那关乎你的本质。——月亮湖 [popexizhi:宽容真的要包括自己的:)]
痛苦是财富,这话是扯淡。姑娘,痛苦就是痛苦,对痛苦的思考才是财富。——柴静《看见》:)
在拒绝这件事上,越简单越好,我帮不上你,不行,不可以。绕来绕去解释半天,只会让自己感觉亏欠了别人,或者让对方觉得你亏欠了他,徒增出许多烦恼。明明是别人需求自己帮忙,是他亏欠你人情,如果你帮不上就明确拒绝,如果你这不好意思那不好意思,就成了你亏欠了他。人际交往,简单明了有时最恰当。——琢磨先生[popexizhi:其实自己一直也没想好如何处理这个问题]
现代四大俗:从小有个音乐梦,辞职开间咖啡馆,改变世界要创业,放下一切去旅行。[popexizhi:这个应该也是创意和抄袭的问题吧]
把岁月长河中的这些点滴感受窜起来就是珍珠,散落了就成了流年里的细沙,所以我总是不厌其烦的在当下就把它们写下来。睁着眼睛回味着刚才的那个梦,头脑中有在夕阳下携手信步的一对老人,不远处海边的沙滩上,孩子们和孩子的孩子们在那嬉戏着。——勺子[popexizhi:把写日记说的这么美:),不过自己的回味不是那夕阳暮年,而是为了成长:)]
锤子手机是不是会成功我不知道,甚至我也只看好老罗这个人,不是很看好他的手机。但我知道历史会记住一个对手机啥都不懂的人,通过自己的偏执、爱好从零开始做了这么一款手机,历史不会记得那些给他泼冷水的人。做事的人生可能错,不做事的人生就是垃圾。——@五岳散人[popexizhi:其实自己和吞从开始就没有看好老罗这个决定,但就像柴可夫说罗琳一样,“真正励志的是,在一个人人都以豪车名宅和光鲜亮丽、退一步也要安顿稳定为终极追求的社会里,有一位徘徊在贫困线边缘的单身母亲从未放弃,待到功成名就后也转型尝试其他类型的写作——你当然可以说《偶发空缺》是部烂书,新近那本假托退役军人为名出版的侦探小说是个笑话,但她本可年复一年地炮制魔法世界的外传坐等万两黄金自动进账的。此刻再回顾罗琳那破碎的家庭、幻灭的婚姻、十年的寂寞与一腔从未更迭过的写作热情,也便能体会到这番奋斗有多么的不易了:年轻时谁他妈没有过个把超功利的理想,可又有几个人能独自拖着孩子在完全看不到希望的情况下坚持到三十三岁呢?”]
丑陋都是相似的,美却各有各的美。正如哈耶克在《通往奴役之路》里所说的,“各个人的教育和知识越高,他们的见解和趣味就越不相同,而他们赞同某种价值观的可能性就越小。如果我们希望找到具有高度一致性和相似性的观念,我们必须降格到道德和知识标准比较低级的地方去,在那里比较原始和‘共同’的本能与趣味占统治地位。”所以,在我们这种价值观具有高度相似性的地方,基于饥饿感的道德(也就是物质需求)是首要的,真、善、美,都是稀缺品。——侯虹斌[popexizhi:好吧,自己的哈耶克读到哪了?]
读书不是为了增加智慧,扩大眼界,这些都是宣传广告。读书的真实目的是为了打发时间,绝大部分情况下都是如此,只是大家都心照不宣。非功利性地读书?臣妾做不到哇。写情书能在短期内提升写作水平,谁又曾指责爱情太功利呢?有人说,读书可以认识到自己的无知。可是我的经历告诉我,读书增长了“原来你也没辙啊”这种对世界的无力感。——和菜头[popexizhi: "原来你也没辙啊"+1000 :)]
一个人,半年之内混得好,是运气;五年之内混得好,是能力;二十年之内混得还很好,是哲学;四十年之内若还是混得很好,那叫命运。
新华社:曾经对股市充满热情的股民们都去哪儿了?――你以为装傻很可爱吗?一顿饭120万人民币,你还指望股市回报股民?有人短短数月一票获利就搞了7000多万元,你说股民去哪了?狼把吃羊吃完了,吐着骨头说:那么多羊都到哪儿去了?我不相信你不知道答案。——@段贵发12:32 PM
当与另外一个人一起讨论问题时,人的自信心会不知不觉“膨胀”,导致双方都很难接受他人的意见,容易出现针锋相对、各执己见的局面。此时,如果再多加一两个人参与讨论,矛盾点可能分散,容易达成一致。——朱莉亚·明森[popexizhi:可以试试:)]

2013年8月8日星期四

转:调用SendMessage 产生死锁的问题分析

来源:http://www.cppblog.com/woaidongmao/archive/2008/12/17/69696.html

[popexizhi:吞在使用一个临界资源在界面调试信息时发现死锁问题,原问题描述参见:
http://www.cnblogs.com/Esperanto/p/3227478.html [吞的窗口消息函数处理阻塞推断]  
pope详细查询了一下 看到下文,感觉吞在分析窗口函数使用时,如果SendMessage都入消息队列,还是不会出现他遇到的死锁,只有下文的解释才很好的说明的问题的来源。昨晚交流了一下,吞表示同意了,如果都入消息队列就成为PostMessage的使用了:),而这里的问题根源是这样的设计本身的问题,工作线程和界面线程不应该直接通讯的,这样的设计使得两者之间的耦合性太大的,测试MFC机制可以使用,但在工程代码中使用潜在问题太恐怖了:)。这个同步的使用是不合理的。
ps:
1.Call Stack 的使用太帅了,要好好思考一下如何改进以后的使用
2.对MFC的设计思想和Unix体系的设计思想不应该有轻重彼此之分,好好了解都是大有裨益的
3.想起上次的Mysql的DNS询问机制,自己是不是应该再做点儿什么好好整理一下这里的good idea啊?
]
------------------------------------------正文分割线----------------------
()       SendMessage 的工作机制
首先我要先简要的说明一个和这个话题有关系的消息处理机制:
    Window操作系统当中,窗口时属于所在Thread的也就是说 你这个窗口在那个Thread 当中Create 的那么你这个窗口就属于那个Thread。同时窗口的消息处理函数也都会在这个Thread 当中被执行的。(不要问为什么 Window 就是这么设计的 嘿嘿)

在讲死锁之前我们先把SendMessage的工作机制搞清楚;
SendMessage 发送出来的消息 到底进入不进入消息队列,有人说进入,有人说不进入,其实都是错误的,确切的说是有时进入,有时不进入。那么什么时候进入,什么时候不进入呢? 我们举一例子来说:假如在 Thread A  中有一个 窗口W1,那么 在 Thread A 中像 W1 SendMessage 一个消息,那么这个消息将不会被放入消息队列,而是直接调用了W1的消息处理函数来直接处理了这个消息。这是不被放入队列的情况;假如现在又多了一个Thread B ,那么在 Thread B 中 像 W1 SendMessage 发送消息 这个时候 W1 将被放入到 Thread A 的消息队列当中,这些Thread A 中的消息循环的GetMessage Get到这个消息 并处理之。 这就是进入消息队列情况;根据在哪里我们来看看我的测试结果:

测试1我创建了一个无DOC/View 之支持的单文档工程:
我在CMainFrame添加如下代码:
        BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
               ON_WM_CREATE()
               ON_WM_SETFOCUS()
               ON_MESSAGE(WM_USER + 100,OnMy)
ON_MESSAGE(WM_USER + 200,OnMy2)
END_MESSAGE_MAP()

LRESULT CMainFrame::OnMy(WPARAM wParam,LPARAM lParam)
{
             int i = 0;
             return TRUE;
}

LRESULT CMainFrame::OnMy2(WPARAM wParam,LPARAM lParam)
{
             int i = 2;
             return TRUE;
}
然后我再 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) 的最后 加入了一行代码:
SendMessage(WM_USER + 100,0,0);

此主题相关图片如下:
clip_image002
然后直接 F5 运行程序 等到 程序停止在断点上,我们看看Call Stack 的调用顺序:

clip_image001
此主题相关图片如下:
clip_image003

然后 我又将 SendMessage 改成:
PostMessage(WM_USER + 100,0,0);
然后直接 F5 运行程序 等到 程序停止在断点上,我们再看看Call Stack 的调用顺序:

clip_image001
此主题相关图片如下:
clip_image004
通过这2 Call Stack 大家可以很清楚的看到,执行SendMessage的时候,是直接调用了 AfxWndProcBase 这个 消息处理函数(MFC 通过HOOK 将所有窗口的处理函数都重定向到这个 函数上了,AfxWndProcBase()不明白的自己去看《MFC深入浅出》),大家可以很清楚的看到,在SendMessage  AfxWindProcBase 之间根本没有调用CWinApp::Run() ,也就是说从SendMessage 到执行OnMy()根本没有通过程序的主消息循环的GetMessage Run 内部好像用的PeekMessage记不清楚了)取消息。那么有人会问,SendMessage的内部就不会先发消息放入队列再通过GetMesssage把消息取出来了吗?答根本没必要那样做,那是脱裤子放P多此一举。
从这个测试例子的结果我判定SendMessage  Thread A 中向  W1
SendMessage 的消息根本不进入消息队列。
测试2那么什么时候进入队列呢我来看看这个例子
沿用上面那个例子的代码我将 OnCreate 中的 SendMessage  PostMessage 都删除掉。然后加入如下代码:
//Thread Proc
UINT ThreadProc(LPVOID lParam)
{
             CMainFrame * v_pFrameWnd = (CMainFrame *)lParam;
             if(v_pFrameWnd)
             {
                v_pFrameWnd->SendMessage(WM_USER + 100,0,0);
             }
             return 0;
}
并且 在 OnCreate 种加入如下代码:
AfxBeginThread(ThreadProc,this);
然后F5 运行 等待程序停在断点处,看Call Stack 如下:

clip_image001
此主题相关图片如下:
clip_image005
我们发现这个 Call Stack 就和刚才那个PostMessage Call Stack 是一样的 这个 WM_USER + 100 消息是通过 Run 内部的 GetMessage 取出来的 。所以我断定:

 Thread B 中向W1 SendMessage 发送消息 ,消息是放入了 Thread  A 的消息队列中。由于SendMessage的特性只有当消息被执行完毕才能够返回,所以Thread  B 中的SendMessage 要等 Thread A 当中消息执行完毕后才能够返回。
()       SendMessage 产生的 死锁问题
Thread 死锁肯定是发生在2Thread 之间,AB A,就产生了死锁。大家看了上面测试之后一定会发现,SendMessage的死锁和上面的第二个例子有关系,也就是 说 通过 Thread  B  W1 发送消息的时候又可能会产生死锁。


那么死锁 何时产生呢 ?通过上面的例子我们知道了  如果Thread B  W1 SendMessage一个消息,那么 Thread B 的这个SendMessage 就要等 Thread A 的队列中的 消息执行完毕才能够返回,如果在 Thread B SendMessage 的同时  Thread A 等待 Thread B 中的某一处理完毕才能够继续处理消息的话,那么这个时候就发送了死锁。

我们继续以测试来说明:
测试3
    首先在 CMainFrame中加入一个 成员变量:m_bThreadExit Public
    我们将 UINT ThreadProc(LPVOID lParam) 加入一样代码如下:
       UINT ThreadProc(LPVOID lParam)
{
          CMainFrame * v_pFrameWnd = (CMainFrame *)lParam;
          if(v_pFrameWnd)
          {
             v_pFrameWnd->SendMessage(WM_USER + 100,0,0);
          }
          v_pFrameWnd->m_bThreadExit = TRUE;
          return 0;
}
然后再 OnCreate 当中添加如下代码:
                             m_bThreadExit = FALSE;
          AfxBeginThread(ThreadProc,this);

          while(TRUE)
          {
             if(m_bThreadExit)
                break;
             Sleep(55);
}

 OK 编译 F5 运行 发现程序 进入无响应状态,好这时我么让程序 暂停:
看看 2Thread  Call Stack 都停在那里了?
Main Thread如下:

clip_image001此主题相关图片如下:
clip_image006
在看看 另一个线成:


clip_image001
此主题相关图片如下:
clip_image007
这会 是不是 很明了了
MainThread  停在 循环内 等待 m_bThreadExit  True,而 另一个线成 则等待 MainThread 处理完毕 WM_USER + 100 这个消息,结果你等我,我等你,死了。。。。
()       处理办法
1  针对上面的例子 我们 可以通过 把SendMessage 改成 PostMessage 的方法来放弃等待。 这样就解决了
2  有些时候 第1种方法不符合要求比如下面这中情况
UINT ThreadProc(LPVOID lParam)
{
          CMainFrame * v_pFrameWnd = (CMainFrame *)lParam;
          if(v_pFrameWnd)

          {
          v_pFrameWnd->SetWindowText("lvyang");
          }
          v_pFrameWnd->m_bThreadExit = TRUE;
          return 0;
}
这里面的CWnd::SetWindowText里面实际上调用的是::SetWindowText 而::SetWindowText 里面有调用 SendMessage发送一个消息给CWnd 的窗口 ,因为::SetWindowText 内部的我们没有办法来修改,那我只能去修改 MainThread 当中的 While 循环了。

那如何修改呢? ThreadProc 当中 SetWindowText之所以被诸塞,就是因为 它向 MainThread SendMessage 的消息没有得到处理,那么我们让他处理的不就OK了吗?好那我们就让他处理,代码如下:
MSG msg;
       while(TRUE)
       {
          if(m_bThreadExit)
             break;
          if(::PeekMessage(&msg,NULL,NULL,NULL,PM_NOREMOVE))
          {
             if(::GetMessage(&msg,NULL,NULL,NULL))
             {
                if(!PreTranslateMessage(&msg))
                {
                   ::TranslateMessage(&msg);
                   ::DispatchMessage(&msg);
                }
             }
          }
          Sleep(55);
}
终于搞完了