topameng's profileQuake3 启示录PhotosBlogListsMore Tools Help

Blog


    March 31

    PeekMessage 与 GetMessage

    PeekMessage 似乎是针对一个窗口线程的而GetMessage 是对整个进程的。当一个进程创建1个以上窗口的(这个很重要),当切换进程中不同窗口的时候PeekMessage 会得到WM_QUIT消息。而GetMessage不会. 似乎GetMessage比PeekMessage能更快的相应消息,但没有消息时GetMessage会挂起进程等待消息,所以好的做法是联合使用2个函数:

    while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))        //是否有消息
    {
        if ( !GetMessage (&msg, NULL, 0, 0) )               
        {
           //WM_QUIT 消息处理
        }

        TranslateMessage (&msg);
        DispatchMessage (&msg);
    }

    March 29

    锁定压缩纹理

    锁定纹理是指定区域是不需要除4 (压缩纹理是4*4块元素作为一个单位,如下面结构,即一个单位可以计算出16个像素值)。
    typedef struct ddsColorBlock_s
    {
        unsigned short          colors[ 2 ];
        unsigned char           row[ 4 ];
    }
    ddsColorBlock_t;
    所以压缩纹理长度宽度必须是4的倍数。
    dx9可能内部做了处理.使用LockRect是不需要自己对应到指定的块(如64,64 像素在压缩纹理文件中属于16*16 块的位置).
    //x,y 为像素位置
    D3DLOCKED_RECT LockedRect;
    RECT rt = {x,y,x+1,y+1};
    pTex->LockRect(0,&LockedRect,&rt,D3DLOCK_READONLY);

    //其实对于4*4 个像素,例如下面
    {0,0}{1,0}{2,0}{3,0}
    {0,1}{1,1}{2,1}{3,1}
    {0,2}{1,2}{2,2}{3,2}
    {0,3}{1,3}{2,3}{3,3}
    LockedRect.pBits 内容是相同的即一个ddsColorBlock_t结构元素(解压这个结构即可获得上面的数据)

    March 25

    VC的预编译功能

    这里介绍VC6的预编译功能的使用,由于预编译详细使用比较的复杂,这里只介绍几个最重要的预编译指令: /Yu, /Yc,/Yx,/Fp。其它的详细资料可以参考: MSDN -> Visual Studio 6.0 Document -> Visual C++ 6.0 Document -> VC++ Programmer Guider ->Compiler and Linker -> Details -> Creating Precompiled Header files
       预编译头的概念:
       所谓的预编译头就是把一个工程中的那一部分代码,预先编译好放在一个文件里(通常是以.pch为扩展名的),这个文件就称为预编译头文件这些预先编译好的代码可以是任何的C/C++代码,甚至是inline的函数,但是必须是稳定的,在工程开发的过程中不会被经常改变。如果这些代码被修改,则需要重新编译生成预编译头文件。注意生成预编译头文件是很耗时间的。同时你得注意预编译头文件通常很大,通常有6-7M大。注意及时清理那些没有用的预编译头文件。
       也许你会问:现在的编译器都有Time stamp的功能,编译器在编译整个工程的时候,它只会编译那些经过修改的文件,而不会去编译那些从上次编译过,到现在没有被修改过的文件。那么为什么还要预编译头文件呢?答案在这里,我们知道编译器是以文件为单位编译的,一个文件经过修改后,会重新编译整个文件,当然在这个文件里包含的所有头文件中的东西(.eg Macro, Preprocessor )都要重新处理一遍。 VC的预编译头文件保存的正是这部分信息。以避免每次都要重新处理这些头文件。
       根据上文介绍,预编译头文件的作用当然就是提高便宜速度了,有了它你没有必要每次都编译那些不需要经常改变的代码。编译性能当然就提高了。
       要使用预编译头,我们必须指定一个头文件,这个头文件包含我们不会经常改变的代码和其他的头文件,然后我们用这个头文件来生成一个预编译头文件(.pch文件)想必大家都知道 StdAfx.h这个文件。很多人都认为这是VC提供的一个“系统级别”的,编译器带的一个头文件。其实不是的,这个文件可以是任何名字的。我们来考察一个典型的由AppWizard生成的MFC Dialog Based 程序的预编译头文件。(因为AppWizard会为我们指定好如何使用预编译头文件,默认的是StdAfx.h,这是VC起的名字)。我们会发现这个头文件里包含了以下的头文件:
    #include <afxwin.h> // MFC core and standard components
    #include <afxext.h> // MFC extensions
    #include <afxdisp.h> // MFC Automation classes
    #include <afxdtctl.h> // MFC support for Internet Explorer 4 Common Controls
    #include <afxcmn.h>
       这些正是使用MFC的必须包含的头文件,当然我们不太可能在我们的工程中修改这些头文件的,所以说他们是稳定的。
       那么我们如何指定它来生成预编译头文件。我们知道一个头文件是不能编译的。所以我们还需要一个cpp文件来生成.pch 文件。这个文件默认的就是StdAfx.cpp。在这个文件里只有一句代码就是:#include“Stdafx.h”。原因是理所当然的,我们仅仅是要它能够编译而已―――也就是说,要的只是它的.cpp的扩展名。我们可以用/Yc编译开关来指定StdAfx.cpp来生成一个.pch文件,通过/Fp编译开关来指定生成的pch文件的名字。
    在vc文件列表中右键单击 stdafx.cpp->属性->c/c++ ->预编译头->创建使用预编译头 选择创建预编译头(/yc)
    对工程设置使用预编译头。在工程名上右击 属性->c/c++ ->预编译头->创建使用预编译头 选择使用预编译头(/yu)
    对于不需要预编译头的源文件,可以像设置stdafx.cpp属性一样。在其属性中选择不使用预编译头即可.
    默认的预编译头名字是stdafx.h.当然你也可以修改成其他名字.
    使用了预编译头的工程在其包含的源文件中开头必须 #include "stdafx.h"  注意即使不在同一目录也不需要指定相对路径.如:
    a.cpp 在common 目录 stadfx.h 在main 目录,不需要#include "../main/stdafx.h" 这样是错误的。

    在这里我们可以看到 /Yc开关,/Yc的作用就是指定这个文件来创建一个Pch文件。/Yc后面的文件名是那个包含了稳定代码的头文件,一个工程里只能有一个文件的可以有YC开关。VC就根据这个选项把 StdAfx.cpp编译成一个Obj文件和一个PCH文件。
    这样,我们就设置好了预编译头文件。也就是说,我们可以使用预编译头功能了。以下是注意事项:
       1)如果使用了/Yu,就是说使用了预编译,我们在每个.cpp文件的最开头,包含你指定产生pch文件的.h文件(默认是stdafx.h)不然就会有问题。如果你没有包含这个文件,就告诉你Unexpected file end.
       2)如果你把pch文件不小心丢了,根据以上的分析,你只要让编译器生成一个pch文件就可以了。也就是说把 stdafx.cpp(即指定/Yc的那个cpp文件)重新编译一遍就可以了。

    转载并补充了一点东西,使用预编译头之后,尽量在头文件中不包含其他头文件,可以提高编译速度。原来10几秒编译的工程现在都是秒过了。hoho

    March 21

    sdk 中使用 richedit2

    1 使用richedit 控件首先要加载 richedit 的dll.
    LoadLibrary(_T("riched20.dll"));
    2 加入对 richedit.h 头文件的引用后,创建窗口
    hwndBuffer    =   CreateWindow(RICHEDIT_CLASS,NULL,WS_CHILD|WS_VISIBLE|ES_MULTILINE|WS_VSCROLL|ES_SUNKEN
                                |ES_AUTOVSCROLL|ES_READONLY|ES_SAVESEL,6,30,526,354,hWnd,(HMENU)EDIT_ID,hInstance,NULL); 
    这里创建了一个只读的窗口,这样只能通过函数输入文字。
    3 设置颜色:
    //设置背景色
    SendMessage( hwndBuffer, EM_SETBKGNDCOLOR, 0, RGB(0,0,0) ); 
    //设置文字颜色
    CHARFORMAT2 charFmt;
    ZeroMemory(&charFmt,sizeof(charFmt));
    charFmt.cbSize = sizeof(charFmt);
    charFmt.dwMask = CFM_COLOR;      //只修改文字颜色标志
    charFmt.crTextColor = RGB(0,179,0);//设置字体颜色  
    SendMessage(hwndBuffer,EM_SETCHARFORMAT,0,(LPARAM)&charFmt);
    //修改部分文字颜色
    SendMessage(hwndBuffer,EM_SETSEL,0,10);    //选中0-10的文字
    charFmt.crTextColor = it->clr;
    //修改文字颜色
    SendMessage(hwndBuffer,EM_SETCHARFORMAT,SCF_SELECTION,(LPARAM)&charFmt);           
    注意对于richedit2.0  汉字仅作为一个字符。对于unicode 工程无所谓。但对于多字节来说一个汉字为2个字符。所以你通过strlen之类计算的字符串长度会比richedit 认为的要长如:
    "大家好"。计算为6长度。但对于richedit来说为3个.发送EM_SEL消息,设置选中消息时必须以richedit为准.
    SendMessage(hwndBuffer,EM_SETSEL,0,3);    如果指定为6将超出范围
    4 滚动滚动条:
    SendMessage(hwndBuffer,WM_VSCROLL, SB_BOTTOM, 0);    //滚动到文档的最后面
    5 游标
    int temp1,temp2;  //获取起始和结束位置
    SendMessage(hwndBuffer,EM_GETSEL,(WPARAM)&temp1,(LPARAM)&temp2);
    //在文档末尾输入字符:
    SendMessage(hwndBuffer, EM_SETSEL,-1,-1);
    SendMessage(hwndBuffer, EM_REPLACESEL, TRUE, (LPARAM) buffer );

    March 12

    WS_OVERLAPPED|WS_BORDER|WS_CAPTION|WS_VISIBLE|WS_SYSMENU bug ?

    无语了,当使用这个状态创建窗口后,移动窗口,窗口向左移动到windows 外,图形居然会自动和windows窗口对其。(当创建窗口分辨率大于等于windows分辨率的时候,郁闷的是小于当前桌面分辨率也没有这种情况)

    windowstylebug

    改为:WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_VISIBLE 后恢复正常
    windowstylebug1