2009年6月27日

Abstract

    This PEP proposes to introduce a syntax to declare the encoding of
    a Python source file. The encoding information is then used by the
    Python parser to interpret the file using the given encoding. Most
    notably this enhances the interpretation of Unicode literals in
    the source code and makes it possible to write Unicode literals
    using e.g. UTF-8 directly in an Unicode aware editor.

Problem

    In Python 2.1, Unicode literals can only be written using the
    Latin-1 based encoding "unicode-escape". This makes the
    programming environment rather unfriendly to Python users who live
    and work in non-Latin-1 locales such as many of the Asian 
    countries. Programmers can write their 8-bit strings using the
    favorite encoding, but are bound to the "unicode-escape" encoding
    for Unicode literals.

Proposed Solution

    I propose to make the Python source code encoding both visible and
    changeable on a per-source file basis by using a special comment
    at the top of the file to declare the encoding.

    To make Python aware of this encoding declaration a number of
    concept changes are necessary with respect to the handling of
    Python source code data.

Defining the Encoding

    Python will default to ASCII as standard encoding if no other
    encoding hints are given.

    To define a source code encoding, a magic comment must
    be placed into the source files either as first or second
    line in the file, such as:

          # coding=<encoding name>

    or (using formats recognized by popular editors)

          #!/usr/bin/python
          # -*- coding: <encoding name> -*-

    or

          #!/usr/bin/python
          # vim: set fileencoding=<encoding name> :

    More precisely, the first or second line must match the regular
    expression "coding[:=]\s*([-\w.]+)". The first group of this
    expression is then interpreted as encoding name. If the encoding
    is unknown to Python, an error is raised during compilation. There
    must not be any Python statement on the line that contains the
    encoding declaration.

    To aid with platforms such as Windows, which add Unicode BOM marks
    to the beginning of Unicode files, the UTF-8 signature
    '\xef\xbb\xbf' will be interpreted as 'utf-8' encoding as well
    (even if no magic encoding comment is given).

    If a source file uses both the UTF-8 BOM mark signature and a
    magic encoding comment, the only allowed encoding for the comment
    is 'utf-8'.  Any other encoding will cause an error.

Examples

    These are some examples to clarify the different styles for
    defining the source code encoding at the top of a Python source
    file:

    1. With interpreter binary and using Emacs style file encoding
       comment:

          #!/usr/bin/python
          # -*- coding: latin-1 -*-
          import os, sys
          ...

          #!/usr/bin/python
          # -*- coding: iso-8859-15 -*-
          import os, sys
          ...

          #!/usr/bin/python
          # -*- coding: ascii -*-
          import os, sys
          ...

    2. Without interpreter line, using plain text:

          # This Python file uses the following encoding: utf-8
          import os, sys
          ...

    3. Text editors might have different ways of defining the file's
       encoding, e.g.

          #!/usr/local/bin/python
          # coding: latin-1
          import os, sys
          ...

    4. Without encoding comment, Python's parser will assume ASCII
       text:

          #!/usr/local/bin/python
          import os, sys
          ...

    5. Encoding comments which don't work:

       Missing "coding:" prefix:

          #!/usr/local/bin/python
          # latin-1
          import os, sys
          ...

       Encoding comment not on line 1 or 2:

          #!/usr/local/bin/python
          #
          # -*- coding: latin-1 -*-
          import os, sys
          ...

       Unsupported encoding:

          #!/usr/local/bin/python
          # -*- coding: utf-42 -*-
          import os, sys
          ...

Concepts

    The PEP is based on the following concepts which would have to be
    implemented to enable usage of such a magic comment:

    1. The complete Python source file should use a single encoding.
       Embedding of differently encoded data is not allowed and will
       result in a decoding error during compilation of the Python
       source code.

       Any encoding which allows processing the first two lines in the
       way indicated above is allowed as source code encoding, this
       includes ASCII compatible encodings as well as certain
       multi-byte encodings such as Shift_JIS. It does not include
       encodings which use two or more bytes for all characters like
       e.g. UTF-16. The reason for this is to keep the encoding
       detection algorithm in the tokenizer simple.

    2. Handling of escape sequences should continue to work as it does 
       now, but with all possible source code encodings, that is
       standard string literals (both 8-bit and Unicode) are subject to 
       escape sequence expansion while raw string literals only expand
       a very small subset of escape sequences.

    3. Python's tokenizer/compiler combo will need to be updated to
       work as follows:

       1. read the file

       2. decode it into Unicode assuming a fixed per-file encoding

       3. convert it into a UTF-8 byte string

       4. tokenize the UTF-8 content

       5. compile it, creating Unicode objects from the given Unicode data
          and creating string objects from the Unicode literal data
          by first reencoding the UTF-8 data into 8-bit string data
          using the given file encoding

       Note that Python identifiers are restricted to the ASCII
       subset of the encoding, and thus need no further conversion
       after step 4.

Implementation

    For backwards-compatibility with existing code which currently
    uses non-ASCII in string literals without declaring an encoding,
    the implementation will be introduced in two phases:

    1. Allow non-ASCII in string literals and comments, by internally
       treating a missing encoding declaration as a declaration of
       "iso-8859-1". This will cause arbitrary byte strings to
       correctly round-trip between step 2 and step 5 of the
       processing, and provide compatibility with Python 2.2 for
       Unicode literals that contain non-ASCII bytes.

       A warning will be issued if non-ASCII bytes are found in the
       input, once per improperly encoded input file.

    2. Remove the warning, and change the default encoding to "ascii".

    The builtin compile() API will be enhanced to accept Unicode as
    input. 8-bit string input is subject to the standard procedure for
    encoding detection as described above.

    If a Unicode string with a coding declaration is passed to compile(),
    a SyntaxError will be raised.

    SUZUKI Hisao is working on a patch; see [2] for details. A patch
    implementing only phase 1 is available at [1].

Phases

    Implementation of steps 1 and 2 above were completed in 2.3,
    except for changing the default encoding to "ascii".

    The default encoding was set to "ascii" in version 2.5.
   

Scope

    This PEP intends to provide an upgrade path from the current
    (more-or-less) undefined source code encoding situation to a more
    robust and portable definition.

References

    [1] Phase 1 implementation:
        http://python.org/sf/526840
    [2] Phase 2 implementation:
        http://python.org/sf/534304
posted @ 2009-06-27 22:57 土豆皮 阅读(181) 评论(0) 编辑

2009年6月18日

  一个基础实例

BOOL AnimateWindow(
      HWND hwnd,
      DWORD dwTime,
      DWORD dwFlags
  ); 
  hWnd:指定产生动画窗口的句柄;
  dwTime:指明动画持续的时间(以微秒计),完成一个动画的标准时间为200微秒;
  dwFags:指定动画类型。这个参数可以是一个或多个标志的组合。
dwFlags:
  AW_SLIDE:使用滑动类型。缺省为滚动类型。使用AW_CENTER标志时被忽略;
  AW_ACTIVATE:激活窗口。在使用了AW_HIDE标志后不能使用这个标志;
  AW_BLEND:实现淡出效果。只有当hWnd为顶层窗口的时候才可以使用此标志;
  AW_HIDE:隐藏窗口,缺省则显示窗口;
  AW_CENTER:若使用了AW_HIDE标志,则使窗口向内重叠,即收缩窗口;若未使用AW_HIDE标志,则使窗口向外扩展,即展开窗口;
  AW_HOR_POSITIVE:自左向右显示窗口。该标志可以在滚动动画和滑动动画中使用。当使用AW_CENTER标志时,该标志将被忽略;
  AW_VER_POSITIVE:自顶向下显示窗口。该标志可以在滚动动画和滑动动画中使用。当使用AW_CENTER标志时,该标志将被忽略;
  AW_VER_NEGATIVE:自下向上显示窗口。该标志可以在滚动动画和滑动动画中使用。当使用AW_CENTER标志时,该标志将被忽略;
  返回值:如果函数成功,返回值为非零;如果函数失败,返回值为零。
    
    如果:
    1、窗口使用了窗口边界;
    2、窗口已经可见仍要显示窗口;
    3、窗口已经隐藏仍要隐藏窗口。
    函数将失败。
    在STDAFX.H中加入 
    #undef WINVER
    #define WINVER 0X500
    否则可能会产生如下错误(由于Windows版本问题):
   ’AnimateWindow’ : undeclared identifier
  ’AW_HIDE’ : undeclared identifier
  ’AW_CENTER’ : undeclared identifier
    一个例子:
    void CAboutDlg::OnClose() 
    {
           //实现淡出效果。
          AnimateWindow(GetSafeHwnd(),1000,AW_HIDE|AW_BLEND);         
          CDialog::OnClose(); 
      }

posted @ 2009-06-18 14:55 土豆皮 阅读(209) 评论(0) 编辑

2009年6月17日

 在vc++中程序中用了srandom()和random(),头文件为stdlib.h,但编译出现错误error C3861: “srandom”: 找不到标识符。

     原因是现在vc++编译器的库函数中没有randomize()和random(),分别用srand()和rand()代替了。

      #include <time.h> //定义关于时间的函数
      一般在用到time(NULL)(当前时间)函数时需要包含此头文件
      #include <stdlib.h> //定义杂项函数及内存分配函数
      一般在用到rand()和srand()函数时需要包含此头文件

     函数名: random 功 能: 随机数发生器,也就是产生一个随机数
     用 法: int random(int num);
     产生的随机数范围为0~num-1。

     函数名: randomize
     功 能: 初始化随机数发生器,相当于拨随机种子
     用 法: void randomize(void);

posted @ 2009-06-17 23:59 土豆皮 阅读(504) 评论(0) 编辑

At the core of any pseudorandom number generation software is a routine for generating uniformly distributed random integers.
In C++ TR1 you have your choice of several core generators that it calls “engines.” The following four engine classes are supported in the Visual Studio 2008 feature pack

 (微软已经发布了Visual Studio 2008的Services Pack 1,它包含了此前发布的feature pack,以及完整的TR1支持,后来又发布了一个修正:VC 2008 SP1: Problems with STL/TR1 after installing VS2008 SP1,关于:VC9 SP1 Hotfix For The vector<function<FT>> Crash,关于文档:微软TR1文档).

  • linear_congruential uses a recurrence of the form x(i) = (A * x(i-1) + C) mod M
  • mersenne_twister implements the famous Mersenne Twister algorithm
  • subtract_with_carry uses a recurrence of the form x(i) = (x(i - R) - x(i - S) - cy(i - 1)) mod M in integer arithmetic
  • subract_with_carry_01 uses a recurrence of the form x(i) = (x(i - R) - x(i - S) - cy(i - 1)) mod 1 in floating point arithmetic

Each engine has a seed() method that accepts an unsigned long argument to specify the random number generation seed. It is also possible to set the seed in more detail using template parameters unique to each engine.

微软的C++ TR1可以生成以下分布的随机数:

 

Generates a Bernoulli distribution.
Generates a binomial distribution.
Generates an exponential distribution.
Generates a gamma distribution.
Generates a geometric distribution.
Generates a normal distribution.
Generates a Poisson distribution.
Generates a uniform integer distribution.
Generates a uniform floating-point distribution.

 

试验一:在VS2008中先建一空的VC++项目文件,然后添加新建项cpp文件如下:

#include <random>
#include <iostream>

void main(){
 std::tr1::mt19937 eng;  // a core engine class:Mersenne Twister generator
 std::tr1::normal_distribution<double> dist;
 std::tr1::uniform_int<int>  unif(1, 52);
 
 for (int i = 0; i < 10; ++i)    //产生正态分布的10个随机数
  std::cout << dist(eng)<<std::endl;
 
 for(int i = 0; i < 5; ++i)      //产生均匀分布的在1到52之间的五个整数随机数
  std::cout << unif(eng) << std::endl;
}

 

 

在循环中,每循环一次,就调用mt19937 eng一次,产生一个随机数输出。

试验二:关于种子seed

 #include <random>
#include <iostream>
#include <time.h>


void main(){
 std::tr1::mt19937 eng;  // a core engine class:Mersenne Twister generator
 std::tr1::normal_distribution<double> dist;
 std::tr1::uniform_int<int>  unif(1, 52);
 eng.seed((unsigned int)time(NULL)); // reseed base engine 设置种子用#include <time.h>, 不能用#include <time>
 
 for (int i = 0; i < 10; ++i)    //产生正态分布的10个随机数
  std::cout << dist(eng)<<std::endl;
 //eng.seed(); // reseed base engine
 for(int i = 0; i < 5; ++i)      //产生均匀分布的在1到52之间的五个整数随机数
  std::cout << unif(eng) << std::endl;
}

 试验三:随机数写入文件

#include <random>
#include <iostream>
#include <fstream>
#include <time.h>

using namespace std;
using namespace std::tr1;

void main()
{
 mt19937 eng;  // a core engine class:Mersenne Twister generator
 normal_distribution<double> dist;
 uniform_int<int>  unif(1, 52);
 eng.seed((unsigned int)time(NULL)); // 设置种子用#include <time.h>, 不能用#include <time>
 

 for (int i = 0; i < 10; ++i)    //产生正态分布的10个随机数
  cout << dist(eng)<<endl;
 
 ofstream fileout("fileout.dat");
 for(int i = 0; i < 5; ++i)  //产生均匀分布的在1到52之间的五个整数随机数
  fileout << unif(eng)<< endl;
 
 fileout.close();
}

试验四:第三方"Mersenne Twister"随机数生成程序使用试验(程序来源:Agner Fog http://www.agner.org/random/)

// 使用说明:从网站下载压缩包,http://www.agner.org/random/randomc.zip
// 展开后,将其中的randomc.h头文件及mersenne.cpp文件Copy到项目文件夹,
// 并将它们加入到项目中,其中包括"Mersenne Twister"的实现

#include <iostream>
#include <time.h>
#include "randomc.h"      // define classes for random number generators

using namespace std;

void main()
{

 int seed = (int)time(0);            // random seed

 // choose one of the random number generators:
 CRandomMersenne RanGen(seed);       // make instance of random number generator
 cout<<"\n\nRandom integers in interval from 0 to 99:\n";
 for (int i = 0; i < 40; i++) {
  int ir = RanGen.IRandom(0,99);
  cout<<ir<<"  ";
 }
  
 cout <<endl;

 cout<<"\n\n\n\nRandom floating point numbers in interval from 0 to 1:\n";
 for (int i = 0; i < 40; i++) {
  float fr = RanGen.Random();
  cout<<fr<<"  ";
 }
 
 cout <<endl;
}

试验五:第三方"Mother-Of-All"随机数生成程序使用试验(程序来源:Agner Fog http://www.agner.org/random/)

// 使用说明:从网站下载压缩包,http://www.agner.org/random/randomc.zip
// 展开后,将其中的randomc.h头文件及mother.cpp文件Copy到项目文件夹,
// 并将它们加入到项目中,其中包括"Mother-Of-All" generator invented by George Marsaglia 的实现

#include <iostream>
#include <time.h>
#include "randomc.h"      // define classes for random number generators

using namespace std;

void main()
{

 int seed = (int)time(0);            // random seed

 // choose one of the random number generators:
 CRandomMother RanGen(seed);       // make instance of random number generator
 cout<<"\n\nRandom integers in interval from 0 to 99:\n";
 for (int i = 0; i < 40; i++) {
  int ir = RanGen.IRandom(0,99);
  cout<<ir<<"  ";
 }
  
 cout <<endl;

 cout<<"\n\n\n\nRandom floating point numbers in interval from 0 to 1:\n";
 for (int i = 0; i < 40; i++) {
  float fr = RanGen.Random();
  cout<<fr<<"  ";
 }
 
 cout <<endl;
}

 

试验六:第三方"SFMT"随机数生成程序使用试验(程序来源:Agner Fog http://www.agner.org/random/)

重要提示:在编译前,可以修改头文件sfmt.h中的#define MEXP以及下面相应的宏代码:Choose one of the possible Mersenne exponents. Higher values give longer cycle length and use more memory。SFMT利用了SSE2指令,速度最快,但只适合intel系列的部分芯片。

// 使用说明:从网站下载压缩包,http://www.agner.org/random/randomc.zip
// 展开后,将其中的头文件及sfmt.cpp文件Copy到项目文件夹,
// 并将它们加入到项目中,其中包括"SFMT" 的实现

#include <iostream>
#include <time.h>
#include "sfmt.h"      // define classes for random number generators

using namespace std;

void main()
{

 int seed = (int)time(0);            // random seed

 // choose one of the random number generators:
 CRandomSFMT1 RanGen(seed);  //注意可以是CRandomSFMT,是CRandomSFMT0,或CRandomSFMT1
 cout<<"\n\nRandom integers in interval from 0 to 99:\n";
 for (int i = 0; i < 40; i++) {
  int ir = RanGen.IRandomX(0,99);
  cout<<ir<<"  ";
 }
  
 cout <<endl;

 cout<<"\n\n\n\nRandom floating point numbers in interval from 0 to 1:\n";
 for (int i = 0; i < 40; i++) {
  float fr = RanGen.Random();
  cout<<fr<<"  ";
 }
 
 cout <<endl;
}

posted @ 2009-06-17 23:58 土豆皮 阅读(1704) 评论(2) 编辑

2009年2月24日

文章作者:Bideyore[E.S.T]
信息来源:邪恶八进制 中国(http://www.eviloctal.com/

 

对于熟悉Win API编程的同志们来说,windowsx.h这个头文件应该不会太陌生吧,这次要讲的内容就来自这个windowsx.h头文件。

经常能在msdn上查到这样一些函数,明明是个函数,而且模样长得和一般的api函数也一样一样的,可却叫做macro,为什么呢?留意一下函数使用的requirement,你会发现,它的声明正是在windowsx.h这个头文件里。

Windowsx.h包含了这样一些内容:
宏API,窗口消息分流器,控件API;

所有的这些宏定义,可以使你的程序更加安全,简洁,结构更清晰,大大提高程序的可读性;其中窗口消息分流器(message cracker)是我们今天要讨论的话题,它可以使我们的API程序变得更简洁。下面就进入我们的主题:(有关windowsx.h的更多内容,可以参考 MS Knowledge Base Article #83456.)

消息分流器是Windows提供的一组宏定义,它的两个最大的作用,用MS的话来说,就是:

● 安全的数据类型,因为消息分流器完成了大量的类型转换的工作;
● 使程序向32位windows的转化更简单;

当然,使用消息分流器会大大改变程序的面貌,你也可以选择不使用它。

下面我们就以一个对话框窗口的消息处理过程为例,看看消息分流器到底是怎么运作的。


1.消息分流器的基本使用
先看一个普通的窗口消息处理函数,它可能需要处理一些窗口的初始化,无效客户区重绘等消息:

LRESULT CALLBACK WndProc (HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
// ...
return 0;

case WM_PAINT:
// ...
return 0;

case WM_DESTROY:
//...
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}

而通过使用消息分流器,我们可以把每个case都写到相应的消息处理函数中,就像下面这样:

LRESULT CALLBACK WndProc (HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
return HANDLE_WM_CREATE(hwnd, wParam, lParam, Cls_OnCreate);

case WM_PAINT:
return HANDLE_WM_PAINT(hwnd, wParam, lParam, Cls_OnPaint);

case WM_DESTROY:
return HANDLE_WM_DESTROY(hwnd, wParam, lParam, Cls_OnDestroy);
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}

这里用到了三个宏定义:HANDLE_WM_CREATE, HANDLE_WM_PAINT, HANDLE_WM_DESTROY;这三个宏定义就是我们的三个消息分流器(别看叫什么分流器,说穿了也不值几个钱,呵呵),它们在windowsx.h中的定义如下:

#define HANDLE_WM_CREATE(hwnd, wParam, lParam, fn)
((fn)((hwnd), (LPCREATESTRUCT)(lParam)) ? 0L : (LRESULT)-1L)
#define HANDLE_WM_PAINT(hwnd, wParam, lParam, fn)
((fn)(hwnd), 0L)
#define HANDLE_WM_DESTROYCLIPBOARD(hwnd, wParam, lParam, fn)
((fn)(hwnd), 0L)

把这三个宏定义替换回去,就变成:

LRESULT CALLBACK WndProc (HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
return Cls_OnCreate(hwnd, (LPCREATESTRUCT)(lParam) ? 0L : (LRESULT)-1L;
// 如果处理了消息,则Cls_OnCreate应返回TRUE,导致WndProc返回0,否则Cls_OnCreate返回FALSE,导致WndProc返回-1;
case WM_PAINT:
return Cls_OnPaint(hwnd), 0L;
// 逗号表达式;Cls_OnPaint是void类型,这里返回0;
case WM_DESTROY:
return Cls_OnDestroy(hwnd), 0L; // 同Cls_OnPaint
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}

之后我们就可以按照消息分流器的定义编写相应的消息处理函数了:

BOOL Cls_OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct){…};
void Cls_OnPaint(HWND hwnd){…};
void Cls_OnDestroyClipboard(HWND hwnd){…};

windowsx.h还提供了一个更加简化的方法:使用HANDLE_MSG宏,这个宏是这样定义的:

#define HANDLE_MSG(hwnd, message, fn)
case (message): return HANDLE_##message((hwnd), (wParam), (lParam), (fn))

这个宏要做的就是根据不同的message(##用来连接前后的字符串),把自己“变成”相应的HANDLE_XXXXMESSAGE形式的宏,再通过相应的宏来执行消息处理代码;
比如实际代码中写入:

HANDLE_MSG(hwnd, WM_CREATE, Cls_OnCreate)

则经过转换就变成:

case (WM_CREATE): return HANDLE_WM_CREATE((hwnd), (wParam), (lParam), (Cls_OnCreate))

这样,我们就可以直接把程序写为:
LRESULT CALLBACK WndProc (HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
HANDLE_MSG(hwnd, WM_CREATE, Cls_OnCreate);
HANDLE_MSG(hwnd, WM_PAINT, Cls_OnPaint);
HANDLE_MSG(hwnd, WM_DESTROY, Cls_OnDestroy);
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}

之后直接编写相应的消息处理过程就可以了。是不是简洁多了?而且把消息处理封装到函数里面,就可以使用VS直接跳转到这个函数,再也不用费劲去找那个 case了。要注意的一点是,虽然windowsx.h里包括了所有消息对应的分流器,但它们的参数是宏定义显式说明的,在编写消息处理函数时,必须遵循宏定义中的参数类型,否则会导致错误;这么多消息分流器,我们每次新写一个消息处理函数时就得看看是否把参数设置正确了,整个过程繁琐冗长。好在已经有一个工具叫Message Cracker Wizard,可以帮助我们生成消息分流器和相关的处理过程,具体见:
http://www.codeproject.com/win32/msgcrackwizard.asp


2.在对话框中使用消息分流器
在对话框消息处理中,窗口子类化是我们经常使用的手段,这也可以通过消息分流器实现,但是有点小问题 :>
下面是一个使用了windowsx.h消息分流器的对话框及其处理过程:
……
int WINAPI _tWinMain(HINSTANCE hinstExe, HINSTANCE, PTSTR pszCmdLine, int)
{
DialogBoxParam(
hinstExe, MAKEINTRESOURCE(IDD_PASSTHRU), NULL, (DLGPROC)Dlg_Proc, 0);

return(0);
}
……

LRESULT CALLBACK Dlg_Proc (HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
HANDLE_MSG(hwnd, WM_INITDIALOG, Cls_OnInitDialog); // 不能直接使用HANDLE_MSG宏
HANDLE_MSG(hwnd, WM_COMMAND, Cls_OnCommand); // 不能直接使用HANDLE_MSG宏
}

return false;
}

以上程序中直接使用HANDLE_MSG可能导致错误;为什么呢?问题出在子类化的消息处理过程的返回值上,msdn中对于对话框消息处理过程的返回值有如下说明:

一般情况下,对话框过程函数应该在处理了消息的情况下返回TRUE,如果没有处理,则返回FALSE。如果对话框过程返回了FALSE,那么对话框管理器为这条消息准备默认的对话操作。

如果对话框处理了一个需要特定返回值的消息,则对话框的返回值应该被设置为调用SetWindowLong(
The SetWindowLong function changes an attribute of the specified window. The function also sets a 32-bit (long) value at the specified offset into the extra window memory of a window. )后的返回值,并在返回TRUE之前立即返回这个值。注意你必须立即调用SetWindowLong(这个函数用于调用窗口子类化的过程),这会导致DWL_MSGRESULT值被一个嵌套的对话框消息改写。返回值为特定值的消息有:
• WM_CHARTOITEM
• WM_COMPAREITEM
• WM_CTLCOLORBTN
• WM_CTLCOLORDLG
• WM_CTLCOLOREDIT
• WM_CTLCOLORLISTBOX
• WM_CTLCOLORSCROLLBAR
• WM_CTLCOLORSTATIC
• WM_INITDIALOG
• WM_QUERYDRAGICON
• WM_VKEYTOITEM
看到没有? 我们的消息WM_INITDIALOG也在其中,对这个消息进行处理的过程不能简单的返回TRUE表示对消息进行了处理,而是另有其意;它将转化为:

case (WM_INITDIALOG): return HANDLE_WM_INITDIALOG(hwnd, wParam, lParam, Cls_OnInitDialog);

宏HANDLE_WM_INITDIALOG定义如下:

#define HANDLE_WM_INITDIALOG(hwnd, wParam, lParam, fn)
(LRESULT)(DWORD)(UINT)(BOOL)(fn)((hwnd), (HWND)(wParam), lParam)

对WM_INITDIALOG的处理,如果返回TRUE,则表示设置键盘焦点到对话框的默认控件,否则返回FALSE;这时好像还看不出什么问题,而对于我们的另外一个消息WM_COMMAND,HANDLE_MSG简单的把它变成:

case (WM_COMMAND): return HANDLE_WM_COMMAND(hwnd, wParam, lParam, Cls_OnCommand);

宏HANDLE_WM_COMMAND定义如下:

#define HANDLE_WM_COMMAND(hwnd, wParam, lParam, fn)
((fn)((hwnd), (int)(LOWORD(wParam)), (HWND)(lParam), (UINT)HIWORD(wParam)), 0L)

问题出来了,我们的Cls_OnCommand由于是个void型的函数,是没有返回值的,因此windows默认这种消息处理过程必须返回一个0值,而返回0值不就表示我们的消息过程不处理这个消息么?这个矛盾是HANDLE_MSG无法解决的。怎么办才能使消息过程在处理完WM_COMMAND消息之后正确的返回一个TRUE呢? 答案是使用另一个windowsx.h中的宏:SetDlgMsgResult(hwnd, msg, result)

这个宏定义如下:

#define SetDlgMsgResult(hwnd, msg, result) ((
(msg) == WM_CTLCOLORMSGBOX ||
(msg) == WM_CTLCOLOREDIT ||
(msg) == WM_CTLCOLORLISTBOX ||
(msg) == WM_CTLCOLORBTN ||
(msg) == WM_CTLCOLORDLG ||
(msg) == WM_CTLCOLORSCROLLBAR ||
(msg) == WM_CTLCOLORSTATIC ||
(msg) == WM_COMPAREITEM ||
(msg) == WM_VKEYTOITEM ||
(msg) == WM_CHARTOITEM ||
(msg) == WM_QUERYDRAGICON ||
(msg) == WM_INITDIALOG
) ? (BOOL)(result) : (SetWindowLongPtr((hwnd), DWLP_MSGRESULT, (LPARAM)(LRESULT)(result)), TRUE))

(有没有注意到,里面多了一个WM_CTLCOLORMSGBOX ? 这个消息是16位WinAPI中的消息,一度被转换为Win32 API的一个消息;现在在最新的32位API中已经被删除了;保留它可能考虑到兼容性的问题,这里不做进一步讨论)
现在看到了,如果对话框过程处理的消息恰巧为返回特定值中的一个,则如实返回result;不要被前面的BOOL蒙蔽,BOOL在头文件中的定义实际上是一个int型,一旦需要返回非TRUE或FALSE的其他值,照样可以;这样,我们的Cls_OnInitDialog就能够正确的返回它的BOOL值了,而Cls_OnCommand在处理之后,也可以由后面的逗号表达式正确的返回一个TRUE表示消息已处理。

在《Windows核心编程》一书中,大牛Jeffrey自己定义了一个宏,使SetDlgMsgResult宏的使用更加方便:

#define chHANDLE_DLGMSG(hwnd, message, fn)
case (message): return (SetDlgMsgResult(hwnd, uMsg,
HANDLE_##message((hwnd), (wParam), (lParam), (fn))))

可见这个宏只是简单的对SetDlgMsgRseult宏进行了封装。

这样,我们最终的代码可以写成:

LRESULT CALLBACK Dlg_Proc (HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
chHANDLE_DLGMSG(hwnd, WM_INITDIALOG, Cls_OnInitDialog); // 使用大牛的chHANDLE_DLGMSG宏
chHANDLE_DLGMSG(hwnd, WM_COMMAND, Cls_OnCommand);
}

return false;
}



下面把原来程序整个框架列出来:

LRESULT CALLBACK Dlg_Proc(HWND hwnd, UNIT umsg, WPARAM wparam, LPARAM lparam)
{
switch(msg)
{
case WM_COMMAND: // 每个case都被一个message cracker代替,这里使用大牛同志的
// do something; // chHANDLE_DLGMSG宏;这个宏负责对消息筛选,处理并返回相应的值
return true;

case WM_INITDIALOG:
// do something;
return xxxx;
}

return false; // 如果消息不在我们的DlgProc过程中被处理,则告诉调用这个DlgProc的消息,
} //告诉系统的对话框管理器,这个消息我们不处理,交给你了

对比一下,消息分流器的作用不言自明。

以上只是介绍了消息分流器的部分应用,更多创造性的用法还等你自己在实践中发掘。

下面列出一些有用的参考资料:

http://support.microsoft.com/default.aspx?scid=kb;en-us;83456 介绍了STRICT宏定义以及windowsx.h
http://www.codeproject.com/win32/msgcrackwizard.asp 提供message cracker wizard的下载,而且附有源代码
《windows核心编程》windows系统编程,就跟定大牛了 :> 他在自己的sample中大量使用了message cracker

posted @ 2009-02-24 00:17 土豆皮 阅读(293) 评论(1) 编辑

2009年2月21日

编辑

 

Ctrl + Space 代码完成

Ctrl + Shift + Space代码完成

Ctrl + Alt + Space代码完成

Ctrl + P 显示参数信息

Alt + Insert 生成构造函数,属性,重载成员函数,实现接口

Ctrl + Alt + J 生成if,try..catch,#region

Ctrl + / 注释及取消//注释

Ctrl + Shift + / 注释及取消/**/注释

Ctrl + W 增量选择块

Ctrl + Shift + W 增量反选

Alt + Enter 显示错误的修正方法

Ctrl + Alt + F 格式化代码

Ctrl + Alt + O 根据指示修改优化

Ctrl + D 复制当前行或选定的块

 

查找

 

Alt + F7 查找变量,方法的引用

Alt + Shift + F7 在设定范围中查找

Ctrl + Shift + F7 高亮显示

Ctrl + Alt + Up / Down 定位到下/前一个引用

Ctrl + Alt + F7 快速定位引用位置

Ctrl + Shift + F4 关闭查找结果tab

Ctrl + Alt + U 定位到查找结果

 

导航

 

Ctrl + N 定位到类型

Ctrl + Shift + N根据文件名定位

Ctrl + E   最近文件列表

Ctrl + Shift +Backspace 上次编辑位置

Ctrl + B 跳到变量申明处

Ctrl + Alt + B 跳到继承类或接口处

Ctrl + U 调到基类

Ctrl + Shift + T 跳到类型申明处

Alt + Up / Down跳到下/上一个方法

Ctrl + F12

F2 / Shift + F2 /上一个高亮度显示的错误

Ctrl + Shift + E Stack Trace

 

Refactoring

F6 将类移入另外的命名空间

Shift + F6 方法更名

Ctrl + F6 更改签名

Ctrl + Alt + N

Ctrl + Alt + M 将选定块抽取为一个方法

Ctrl + Alt + V 更改变量名称和类型

 

模板

 

Tab 根据缩写生成模板

Ctrl + J 插入模板

 

内置模板:

asrt 生成assertion

ear生成空数组

foreach 生成foreach

ital生成ArrayList的迭代循环

itar 生成array的迭代循环

itdic 生成dictionary的迭代循环

loop生成loop循环

out 打印串

outv 打印变量值

pci public const int

pcs public const string

pro protected

psr public static readonly

psvm main() method declaration

ritar Iterate an array in reverse order

sfc Safely cast variable

thr throw new

toar ArrayList 转化为array

posted @ 2009-02-21 16:12 土豆皮 阅读(1390) 评论(0) 编辑

2007年7月21日

摘要: 如果你不懂.net逆向,又对它感兴趣,又不靠破程序吃饭,请进!阅读全文
posted @ 2007-07-21 02:13 土豆皮 阅读(460) 评论(0) 编辑
摘要: 本系列文章,将从系统层角度,通过对MS.Net CLR架构对PE映像结构的扩展的分析,解析MS.Net CLR架构的底层部分运行机制,帮助读者从更深层次理解CLR中某些重要概念阅读全文
posted @ 2007-07-21 01:55 土豆皮 阅读(167) 评论(0) 编辑

2007年7月15日

摘要: Thread.Sleep(0) 表示挂起0毫秒,你可能觉得没作用,你要写Thread.Sleep(1000) 就有感觉了。似乎毫无意义。阅读全文
posted @ 2007-07-15 02:29 土豆皮 阅读(2723) 评论(1) 编辑

2007年7月14日

摘要: TerryLee 前辈整理的:Enterprise Library系列文章回顾与总结阅读全文
posted @ 2007-07-14 22:39 土豆皮 阅读(73) 评论(0) 编辑

导航

公告

昵称:土豆皮
园龄:5年
粉丝:0
关注:0
<2012年2月>
2930311234
567891011
12131415161718
19202122232425
26272829123
45678910

统计

搜索

 
 

常用链接

我的标签

随笔分类

随笔档案

文章分类

相册

最新评论

阅读排行榜

评论排行榜

推荐排行榜