junfei's profilesheep的随手涂鸦BlogLists Tools Help

Blog


    8/7/2007

    地推日记 1

    ff说要从低做起,今天就真的从低做起了。。。成为了一个全职的地推人员,工作嘛。。。嗯就是对所属的网吧进行3p(嗯,对3p)
    想不到3p是从老地方--赤岗开始。。。。
    中学的时候,这边的网吧来过不少次,记忆中当时这里是星际和cs的天下,不过到了今天,已经没有一款游戏能独霸网吧了。
    今天终于见识到“脑白金”地推团队的厉害,他们的效率是在太惊人了。。。甚至到了会覆盖自己海报的地步。。。实在太bt了。。。感觉就是魔兽里面的亡灵...
    今天特意为李mm看看休闲的情况。。事实证明想靠一般的小休闲游戏把用户从tx哪里抢过来几乎是不可能de。。只能靠一些“大”作才可以。。。李mm要加油啦。。。
    今天是和一个很有“爱”资深的地推人员一起去3p的,他可能读书不多,但他热爱他的工作,对工作一丝不苟,认真程度令我这种做事丢三落四的认汗颜。他可能不懂得太多技术上的东西,但他对游戏的平衡性和玩家的需求有很深刻的见解。也许以后技术部做游戏的同学都应该先到市场部去3p一下,看看现实中玩家的需求,虽然说玩家的需求不是上帝的圣旨,一定要全部满足。但知道玩家的需求,才会知道你应该做些什么。
    今天暂时乱写这么多 明天 继续3p ^^
    5/3/2007

    discuz源码研究

    在计算电磁学大山的重压之下,拿discuz的喘一口气。。。。。
    粗看了一下,d5.5代码大概有4M,上百个文件,而且能下载的版本是去注释+代码混乱版。。。。

    啊!!我要罗塞达碑石!!!!

    4/20/2007

    cs3 来了

    dreamweaver cs3 285M
    Flash cs3 451M
    fireworks cs3 250M
     
    adobe就喜欢把东西搞到那么大。。。。
     
     
    3/18/2007

    初试Ruby

    我觉得动态语言的魅力在于真正的动态绑定看下面
    现在看看Ruby 的Mix-in
    module MySampleModule
        def show
            puts @name
        end
    end
    class MyClass
        include MySampleModule
        def initialize
            @name= 'sheep';
        end
    end
    x = MyClass.new
    x.show
    module 能绑定到任何一个类当中,比起java只能定义没有实现的interface实用得多,而比C#复杂的delegate又来得简单
     
    总之ruby真的几好玩^^
     
    2/24/2007

    google image SafeSearch

     
    网页    图片    资讯    地图新!    更多 »
      高级图片搜索 | 使用偏好

    使用了 SafeSearch 功能。(了解更多)

    SafeSearch

    SafeSearch 是一种从搜索结果中过滤掉色情内容的技术。通常我们为用户提供不同级别的SafeSearch,用户可据需要设定所需级别。例如,用户可只对图像使用 SafeSearch,或对图像及网页均使用 SafeSearch。根据当地法律法规和政策,Google.cn 上设定基本的SafeSearch 技术。

     

    google的search AI已经进步到图像的境界了?????竟能分析那些图片是工口的?
    本来毕业设计想搞图像识别的,后来发现要识别一个圆球比跑得比刘翔快更难。。。。于是放弃了。。。。

    google竟然能识别工口图了。。。
    也许以后google会推出收费服务只是识别工口图^^

    9/1/2006

    俄罗斯方块

    相对于曲面积分
    俄罗斯方块就真的简单多了。。。
    一个多小时就搞定了
     
     
     
    佩服想出这征服的游戏的Alexey Pajitnov
    1/26/2006

    wysiwyg 编辑器 自虐的开始

    搞了差不多一个礼拜的wysiwyg(waht you see is what you get)的在线编辑器(大概就是像msn space发布日志时的编辑器),感觉上就是自己虐待自己:
    用javascript古怪的protochain来承继扩展类.....
    还没有好的debug工具,出错难以调试。。。
    各个浏览器的标准不尽相同,明明在MSIE里面好好的,可是Firefox里面就出错了,还有opeara 和safariMSIE, Firefox, Mozilla, Netscape, Safari, Opera
    同一浏览器的不同版本兼容型也不同
    同一浏览器同一版本不同操作系统上的表现也不同。。。。。
     
    快疯掉了
     
    看来RIA没有一个统一的开发环境痛苦的还是开发人员。。。。还是用回flash好。。。
    11/19/2005

    mysql的乱码。。。。

    终于感受到felix所说的乱码问题,导出的数据除了乱码还是乱码。。。。。。导出正确了,但又由于网上服务器的版本和本机的版本不同,所以还是乱码
    看来下次要换PostgreSQL了。。。
     
    还有谢谢所有朋友的关心
    现在脚没什么事了
     
    ps 下周就是广工一年一度,举世欢腾,人人开心的女生节啦,据说几年赞助特多,而且还有超女助阵,大家有空就来大学城看啦,而且只要你看上去像女生都有一大堆礼物免费拿哦
    10/22/2005

    更新狂潮

    年末,各大厂商的都发布自己新版本的软体,也许旧的技术你还没有来得及研究,新的已经摆在你面前了,想起周星星的一句对白:人生大起大落的太快,实在是太刺激了。软件也是这样,今天我觉得技术的更新会给我带来兴奋,但会不会有一天因技术更新太快而感觉到累呢?
     
     
    我还在用命令行的时候,Jbuilder已经是2006了
     
    11.7 vs 2005强势发布,没了后缀的的.net不知这次ms又为我们带来什么呢

     

    12.1发布Delphi已经不仅仅是pascal的RAD IDE了,cpp,c#在2006里面都是delphi的支持对象

     

    11.?? mysql5终于支持触发器了

     

     

    Flex builder + AS3 MM真正成为RIA领导者

    10/1/2005

    《德军总部3D》 in flash --- DOOM ...

    symphonyplanet.com/glenrhodes/index.php?option=com_content&task=view&id=89&Itemid=54
    symphonyplanet.com/glenrhodes/wolf/myRay.html
    注:需要注册才能观看... flash player 8












    想不到借助flash8的新特性,flash也能做出如此出色的3D游戏,我也要加油!!

    这个游戏应用了doom1里面用的raycasting算法,以下的链接有相关的介绍

    以后flash游戏可再不停留在连连看水平了

    http://www.permadi.com/tutorial/raycast/index.html

    9/26/2005

    无题

    发信人: nwamtfo (nwamtfo), 信区: ZSU_Info
    标  题: 紧急!艾晓明老师正在遭到追杀
    发信站: 逸仙时空 Yat-sen Channel (Mon Sep 26 20:18:05 2005)

          今日下午,艾晓明老师与一位凤凰周刊记者及两名律师在taishicun遭到一群不明身
    份者的围殴,车档风玻璃被砸碎,四人是否受伤现还不得而知。
    四人报警后,由番禺区警方派警车护送乘车逃离现场。行至半途警车调头而去,旋即遭到
    数辆车的围追堵截,车内歹徒挥舞棍棒、匕首。
    现艾老师四人正在逃亡之中,准备前往就近派出所避难。

    说明:由于是短暂电话联络,细节尚不太清楚。       
    --

    ※ 来源:.逸仙时空 Yat-sen Channel http://bbs.zsu.edu.cn [FROM: 192.168.12.117]

     

    未经证实的消息,希望不要是真的

     

     

    相关链接

    温家宝总理,请救救太石村的村民!


    9/24/2005

    超BT的

     
    kao,竟然做一题就能排名第二,题目也真的是tmd的太难了吧??!#◎¥!◎
    希望明天多一两道简单点的,最少也能拿来提高自信嘛......
     
    9.25 god bless us
    9/18/2005

    霸度也搞程序大赛

    想不到霸度也向google靠拢搞程序大赛
    第一二题真的是简单题,十多分钟搞定,不过不是即时判定,不知道对错(第二题题目我觉得有错。。。!)
    第三四题完全是搜索引擎的核心问题,大概是hash+搜索书,不过不知道怎样在gcc下处理中文字符,所以只能放弃,那位大牛A了就告诉我一声哦

    baidu 第一题

    题目描述:一个正整数有可能可以被表示为n(n>=2)个连续正整数之和,如:
        15=1+2+3+4+5
        15=4+5+6
        15=7+8
        请编写程序,根据输入的任何一个正整数,
        找出符合这种要求的所有连续正整数序列。   
        输入数据:一个正整数,以命令行参数的形式提供给程序。  
        输出数据:在标准输出上打印出符合题目描述的全部正整数序列,
        每行一个序列,每个序列都从该序列的最小正整数开始、
        以从小到大的顺序打印。如果结果有多个序列,
        按各序列的最小正整数的大小从小到大打印各序列。
        此外,序列不允许重复,序列内的整数用一个空格分隔。
        如果没有符合要求的序列,输出“NONE”。
        例如,对于15,其输出结果是:
        1 2 3 4 5
        4 5 6
        7 8
        对于16,其输出结果是:
        NONE
       评分标准:程序输出结果是否正确。


     第二题(共四题100分):重叠区间大小(20分)
     
       题目描述:请编写程序,找出下面“输入数据及格式”中所描述的输入数据文件中最大重叠区间的大小。
        对一个正整数n,如果n在数据文件中某行的两个正整数(假设为A和B)之间,即A<=n<=B或A>=n>=B,则n属于该行;如果n同时属于行i和j,则i和j有重叠区间;重叠区间的大小是同时属于行i和j的整数个数。
        例如,行(10 20)和(12 25)的重叠区间为[12 20],其大小为9;行(20 10)和(12 18)的重叠区间为[10 12],其大小为3;行(20 10)和(20 30)的重叠区间大小为1。   输入数据:程序读入已被命名为input.txt的输入数据文本文件,该文件的行数在1到1,000,000之间,每行有用一个空格分隔的2个正整数,这2个正整数的大小次序随机,每个数都在1和2^32-1之间。(为便于调试,您可下载测试input.txt文件,实际运行时我们会使用不同内容的输入文件。)   输出数据:在标准输出上打印出输入数据文件中最大重叠区间的大小,如果所有行都没有重叠区间,则输出0。   评分标准:程序输出结果必须正确,内存使用必须不超过256MB,程序的执行时间越快越好。

    第三题(共四题100分):字符串替换(30分)
     
       题目描述:请编写程序,根据指定的对应关系,把一个文本中的字符串替换成另外的字符串。    输入数据:程序读入已被命名为text.txt和dict.txt的两个输入数据文本文件,text.txt为一个包含大量字符串(含中文)的文本,以whitespace为分隔符;dict.txt为表示字符串(s1)与字符串(s2)的对应关系的另一个文本(含中文),大约在1万行左右,每行两个字符串(即s1和s2),用一个\t或空格分隔。dict.txt中各行的s1没有排序,并有可能有重复,这时以最后出现的那次s1所对应的s2为准。text.txt和dict.txt中的每个字符串都可能包含除whitespace之外的任何字符。text.txt中的字符串必须和dict.txt中的某s1完全匹配才能被替换。(为便于调试,您可下载测试text.txt和dict.txt文件,实际运行时我们会使用不同内容的输入文件。)   输出数据:在标准输出上打印text.txt被dict.txt替换后了的整个文本。   评分标准:程序输出结果必须正确,内存使用越少越好

    第四题(共四题100分):低频词过滤(40分)
     
       题目描述:请编写程序,从包含大量单词的文本中删除出现次数最少的单词。如果有多个单词都出现最少的次数,则将这些单词都删除。   输入数据:程序读入已被命名为corpus.txt的一个大数据量的文本文件,该文件包含英文单词和中文单词,词与词之间以一个或多个whitespace分隔。(为便于调试,您可下载测试corpus.txt文件,实际运行时我们会使用不同内容的输入文件。)   输出数据:在标准输出上打印删除了corpus.txt中出现次数最少的单词之后的文本(词与词保持原来的顺序,仍以空格分隔)。    评分标准:程序输出结果必须正确,内存使用越少越好,程序的执行时间越快越好。

    9/11/2005

    3d_maze

    用flash重新写了上学期数据结构的课程设计,代码作了些优化,可惜flash的延时始终没有搞好暂时还没有动画的效果....
    想生成另外的maze可以按rainstudio的n,呵呵
    以后要告flash RPG还可以用这个地图模型
    rainstudio.onlinecq.coml/sheep/lab/3d_maze/3d_maze.html
     
    ps
    为了测试flash movieclip的onenterfame的重载,还搞了个小磁铁
    rainstudio.onlinecq.coml/sheep/lab/magnetic/magnetic.html
    8/9/2005

    终于来啦Macromedia Studio 8

    Macromedia Studio 8功能预览 
     
    2005-08-09 08:16 作者:蓝色理想 Danger 来源:转载 

    --------------------------------------------------------------------------------
     

    【简 介】
      Macromedia于美过西部时间2005年8月8日上午8时,发布最新的Studio8系列套装。Studio8中包括Dreamweaver8,Flash 8 Professional or Basic,Fireworks 8,Flash Paper2和Contribute3。

     

    Flash Professional 8 / Flash Player 8 新特性总结


     

     

    Flash 8.0 分为两个版 Flash Professional 8 和 Flash Basic 8,之前我们所猜测的 Flash MX 2006 是不存在的.

    1,滤镜效果
    Flash Professional 8 滤镜可以让你给影片剪辑(MovieClip)添加特殊效果,例如阴影,模糊等等(滤镜同样可以应用到按钮和文本上),可以通过面板进行设置,就像Photoshop那样(也可用AS控制)

    2,混合模式
    多种MovieClip特效与背景进行融合的模式.

    3,Flash视频与新的编码技术.
    *On2 VP6编码让Flash视频(FLV)质量更清晰
    *Flash 视频支持Alpha通道
    *附带了一个独立的FLV转换工具.
    *新版的视频媒体播放组件
    *视频导入流程有所改进了.

    4,新的文本渲染引擎
    新的文字渲染引擎Saffron让Flash中的文字在屏幕上更清晰的显示,文本工具也有改进.

    5,实时位图处理
    你可以在运行时动态获取Flash中位图的颜色值,复制象素区域,使用象素绘图等等.

    6,文件上传/下载接口.
    Flash 上传接口可直接调用系统文件对话框(以前要通过Javascript),选择文件并获得文件路径.然后传给后台程序进行上传.

    Flash 文件下载可让你将任何文件下载到硬盘上,你可以选择下载路径,并可以控制显示下载进度.

    7,位图缓冲
    简单说就是将自身无变化的矢量图按位图来显示.提高影片播放速度.但如果你的矢量图频繁变化(旋转,缩放)这个特性也就无效果了.

    8,运行稳定性和启动速度都有提升

    9,增强了与Javascript之间的通讯能力.
    使 Flash 与 Javascript 之间实现无缝连接.

    10,Mobile 模拟器
    手机模拟器,用来模拟运行 Flash Lite 应用程序

    12,自定义缓冲
    可自定义弹性,缓入,缓出等各种缓冲效果

    13,SWF文件元数据(meta-data)
    可在SWF文件中加入一些版权信息,标题与描述信息.

    14,库面板有所改进
    方便在多个文件的库之间切换

    15,改进了面板管理功能
    可将你需要的面板合并到一个面板中,通过标签访问(又回到Flash 5)

    16,脚本助手
    ActionScript 脚本编辑器的普通模式又回来了,叫作"脚本助手"

    17,动态载入外部GIF,PNG图片

    更多信息可访问产品页面:
    http://www.macromedia.com/software/flash/flashpro

    新特性展示:
    http://www.macromedia.com/software/flash/flashpro/productinfo/features/
     
     
     ps大家可以到http://www.dengjie.com/flash8/感受一下flash8带来的震撼,一个字cool,两个字好cool,三个字好鬼cool!!!

    8/4/2005

    郁闷的平方

    想不到,修炼了一个月,成果还是。。。。。。
    想到4题,不过有两题老wa。。。。
    5/17/2005

    [转]under the hood

    November 1996

    Microsoft Systems Journal Homepage

    Matt Pietrek is the author of Windows 95 System Programming Secrets (IDG Books, 1995). He works at NuMega Technologies Inc., and can be reached at 71774.362@compuserve.com.

    Click to open or copy the PSAPI project files.

    In my August 1996 column, I described some of the APIs in PSAPI.DLL. This DLL is the closest thing that Windows NT¨ has to true system-level information APIs. For example, PSAPI.DLL lets you obtain system information like the list of running processes. While you can get much of this information from the performance data in the Windows NT registry, it's messy and complicated. PSAPI.DLL is much simpler and faster to use than the registry. PSAPI.DLL isn't a standard part of Windows NT, but it is a redistributable component from the new Win32¨ SDK that supports Windows NT 4.0.

    This month, let's go over the remaining APIs in PSAPI.DLL. These APIs fall into two categories that are related enough for me to incorporate them all into a demo program. The first category obtains information about the working set of a process, while the second category relates to retrieving the names of memory-mapped files. First, I'll examine all of these APIs, then finish by walking through the demonstration program.

    Have you ever wondered about the "Mem Usage" column in the Windows NT 4.0 Task Manager? Where does it get those numbers from? Those numbers are the actual working set of each process. What exactly is a working set? Alas, the term has at least two different meanings. In the traditional computer science sense, the working set of a process is the absolute smallest amount of physical RAM for the process to continue executing without incurring any page faults. A process with a working set of 12KB would only take up 12KB of physical RAM to hold all the code and data that's being accessed at the moment.

    The other meaning of the term "working set" is the amount of physical RAM that a process is currently using. This second interpretation is what Microsoft uses. To quote from the Win32 SDK documentation:

    The working set of a process is the set of memory pages currently visible to the process in physical RAM memory. These pages are resident and available for an application to use without triggering a page fault. The size of the working set of a process is specified in bytes. The minimum and maximum working set sizes affect the virtual memory paging behavior of a process.

    PSAPI.DLL provides access to process working-set information in two ways. The first is via the QueryWorkingSet API. This API fills a buffer with information about every page that's currently part of the working set of the specified process. The only memory pages reported are those physically present at the exact moment you call QueryWorkingSet. The other type of working set information comes from the GetWsChanges API. This routine reports just the pages that have been mapped into memory since monitoring began (you begin monitoring with the InitializeProcessForWsWatch API, which I will discuss later). This is useful for situations such as finding out how much additional RAM a particular operation (for instance, saving a file) takes.

    Let's look at the QueryWorkingSet API first, since it's conceptually simpler.

    BOOL WINAPI QueryWorkingSet( HANDLE hProcess, PVOID pv, DWORD cb );

    The first parameter is a process handle for a running process. The easiest way to get a process handle for an arbitrary process is with the Win32 OpenProcess API. If you're not up on the OpenProcess API and process IDs, my August column on PSAPI.DLL describes them.

    Returning to the QueryWorkingSet API, the second parameter is a pointer to a memory buffer that QueryWorkingSet writes a series of DWORDs to. The third parameter tells QueryWorkingSet how big the buffer is so that QueryWorkingSet won't write past the end of the buffer. Unfortunately, there's no way to find out ahead of time how big a buffer QueryWorkingSet will need. You have to pass a buffer that's hopefully big enough and be prepared to handle the case where it's not (the API will return FALSE, and you need to try again with a bigger buffer).

    The meanings of the DWORDs that QueryWorkingSet writes to the buffer are slightly strange, as I found out the hard way! The first DWORD contains the number of valid DWORD values that follow the first DWORD in the buffer. Each remaining DWORD represents one page in the process working set, and is composed of a linear address combined with various flag values.

    To decode these DWORDs, it's necessary to split apart the bits in the high 20 bits from the low 12 bits (actually, it's 13 bits for the DEC Alpha, which has 8KB pages). It's easy to do this with the bitwise AND operator. The high 20 bits (obtained by doing a bitwise AND with 0xFFFFF000) contain the linear address of a page of memory mapped into the specified process. The bottom 12 bits are flag values that define operating system attributes for the page.

    The exact meaning of the bit values in the low 12 bits aren't defined in PSAPI.H or anywhere else that I'm aware of. Some experimentation showed the following bit interpretations to be consistent:

    0x001

    The page is read-only (if bit 0x004 not set)

    0x002

    The page is executable (code)

    0x004

    The page is writeable (if bit 0x001 is not set)

    0x005

    The page is copy-on-write (bits 0x001 and 0x004 are both set)

    0x100

    The page can be shared across processes, given the right conditions

    As an example of what QueryWorkingSet returns, consider the following DWORDs:

    0x00000003 0x00400103 0x00480101 0x00500004

    Breaking apart the bits, these DWORDs would be interpreted like this:

    0x00000003

    3 DWORDs to follow

    0x00400103

    Linear address 0x00400000, read-only, executable, shared

    0x00480101

    Linear address 0x00480000, read-only, shared

    0x00500004

    Linear address 0x00500000, writeable

    Now that you know how to get the entire working set of a process using QueryWorkingSet, let's examine the other working set APIs. The primary API is GetWsChanges.

    BOOL WINAPI GetWsChanges(HANDLE hProcess, PPSAPI_WS_WATCH_INFORMATION lpWatchInfo, DWORD cb );

    The first parameter is a process handle specifying which process you want information for. The last two parameters specify the buffer GetWsChanges writes its information to.

    As mentioned earlier, GetWsChanges returns information on what changes to the working set have occurred since monitoring began. The format of the data returned by GetWsChanges is quite a bit different than what QueryWorkingSet returns. Luckily, PSAPI.H tells you exactly what the format of the return data is:

    typedef struct _PSAPI_WS_WATCH_INFORMATION { LPVOID FaultingPc; LPVOID FaultingVa; } PSAPI_WS_WATCH_INFORMATION...

    GetWsChanges fills in an array of these structures, one structure for each new page added to the working set of the process. The second LPVOID in the structure (FaultingVa) contains the linear memory address of the page that was added to the working set. The first LPVOID in the structure (FaultingPc) is the address of the instruction that caused the page fault referred to by the FaultingVa address. In simpler terms, the structure tells you which pages are in memory, and what caused them to be paged in.

    Before racing out and experimenting with GetWsChanges, there's another API, InitializeProcessForWsWatch, that you need to know about. Before you can use GetWsChanges, you need to first pass the process handle to InitializeProcessForWsWatch. Not all processes let you read their working set information due to the security in Windows NT, so be sure that the API returns TRUE.

    The last working set API in PSAPI.DLL is EmptyWorkingSet. It takes one parameter, (you guessed it) a process handle. Calling the API causes Windows NT to remove as many pages as possible from the process working set. Why would you want to do this? Primarily for testing and tuning. One note on EmptyWorkingSet: the API is, in essence, obsolete. The Win32 SetProcessWorkingSetSize API does the same thing if you pass it 0xFFFFFFFF for the minimum and maximum sizes.

    With the working-set APIs out of the way, the only remaining APIs to cover in PSAPI.DLL are GetMappedFileNameA and GetMappedFileNameW. As you can probably guess, the version ending in A is the ANSI version, while the version ending in W is the Unicode version. The ANSI version of GetMappedFileName is prototyped like this:

    DWORD WINAPI GetMappedFileNameA(HANDLE hProcess, LPVOID lpv, LPSTR lpFilename, DWORD nSize );

    The hProcess and lpv parameters specify a linear address in a specific process. If this address is somewhere within a memory-mapped file, the lpFilename buffer is filled with the name of that memory-mapped file. The nSize parameter tells the API how big the lpFilename buffer is. It's interesting that the filenames returned by GetMappedFileName don't use drive letters. Rather, they're in their device form. For example:

    \Device\Harddisk0\Partition1\WINNT\System32\ctype.nls The PSAPIWorkingSetDemo Program

    To pull together all of the APIs that I've described here, I wrote the PSAPIWorkingSetDemo program (see Figure 1). This program was a real stretch for me, at least the user interface was. Normally, for a demo program, I would create an app with a dialog as the main window. For PSAPIWorkingSetDemo, I used two, count 'em, two dialogs. I hope you appreciate my extra labor.

    The main window of PSAPIWorkingSetDemo is shown in Figure 2. The top list box contains a list of all processes (and their IDs) that I obtained using the PSAPI APIs described in my earlier column. Whenever you click on a process in the top list box, the bottom list box updates with detailed information about the working set of the selected process.

    Figure 2 PSAPI Working Set Demo

    On the top-right side, you'll find a summary of the working set information shown in the bottom list box. The "total" field is exactly how much RAM is used for the selected process (including RAM used by shared system DLLs like KERNEL32.DLL). This number should always be the same value that you see reported from the Windows NT 4.0 Task Manager. I didn't invest the time to make PSAPIWorkingSetDemo update these fields automatically. Instead, I'll drag out the old "Left as an exercise for the reader" ploy.

    The Private field shows the amount of memory used by pages that cannot be shared with other processes in the system. Examples of this would be stack and heap pages. The Shared field shows how much memory is used by pages that could theoretically be shared with other processes. For example, the code pages of EXEs and DLLs can usually be shared across processes. The Page Tables field shows how much RAM is taken up by the page mapping tables that translate between virtual addresses and the physical addresses that go out on the computer's bus.

    Along the bottom row of the main PSAPIWorkingSetDemo window are four buttons. When pressed, the Empty working set button calls EmptyWorkingSet on the process that's selected in the top list box. The Start Delta and End Delta buttons are used in tandem. I'll come back to them later when I describe the other dialog.

    Let's zoom in on the bottom list box (the working set details) and see what it's all about. The list box is populated by calling QueryWorkingSet and analyzing the output before sending it on to the list box. All of this is done by the AddWorkingSetInfo routine in PSAPIWorkingSetDemo.CPP. As I describe what happens, refer to that routine's code to see my implementation.

    The AddWorkingSetInfo routine starts by calling OpenProcess on the specified process ID to get back a process handle. Next, the code calls QueryWorkingSet to get an array of all the pages in the process. Since the addresses in the array aren't sorted, I call qsort to put them into ascending address order. Once sorted, the bulk of the routine just iterates through every page and adds information about the page to the bottom list box. Actually, this isn't strictly true. Whenever I see two or more adjacent memory pages with the same attributes (for example, readonly, shared, and so on), I combine them into one line in the output. This is why the second column in every output line is a size that's a multiple of 4KB.

    For each reported range of pages in the output list box, the function emits the starting address of the range, the size of the range, the attributes of the pages and, if possible, where the page came from. The attributes of the page are extracted from the bottom 12 bits of the page's DWORD description, and are exactly the attributes I described earlier (readonly, executable, and so on). In the list box, I've abbreviated the attributes as follows:

    0x001

    RO (read-only)

    0x002

    E (executable)

    0x004

    RW (readable,writeable)

    0x005

    CW (copy-on-write)

    0x100

    S (shared)

    0x000

    P (private, if 0x100 bit not set)

    The last column for each page is the owner of the page (if I was able to determine an owner). The primary means of identifying who owns a page is the GetModuleNameAndSectionInfo function, a routine I wrote, which I'll describe later. If GetModuleNameAndSectionInfo didn't find an owner, the page may be from a memory-mapped file. I check for this possibility by calling GetMappedFileNameA. If the page is from a memory-mapped file, the API returns TRUE, and my code emits the memory-mapped file's name as the page's owner.

    If a working-set page doesn't come from an EXE or DLL, and if it's not from a memory-mapped file, its owner field will be blank. There are numerous ways that this can happen. For starters, all pages with addresses above 2GB are from the ring 0 (kernel mode) portion of Windows NT. I wasn't able to come up with a good way to identify the owners of these pages while working within the confines of ring 3 user-mode code. As for pages below 2GB in memory without a listed owner, owners could be part of a stack, a heap, or belong to system data structures like the thread information block. See my May 1996 column for details on the thread information block.

    Having explained the working-set information in the main dialog, let's now turn to those Start Delta and End Delta buttons. These two buttons demonstrate the other portion of PSAPI.DLL's working set functionality, the GetWsChanges API. When you press Start Delta, PSAPIWorkingSetDemo begins collecting working set additions to the currently selected process. The End Delta dialog causes PSAPIWorkingSetDemo to display a second dialog with information about each new page added since the Start Delta button was pressed. This dialog, entitled Working Set Delta, is shown in Figure 3.

    Figure 3 Working Set Delta

    When you press the Start Delta button, the StartWorkingSetDelta function in PSAPIWorkingSetDelta.CPP gets control. It begins by opening a handle to the selected process, and then passes that handle to InitializeProcessForWsWatch. Next, the function calls GetWsChanges. The code ignores the results of this call. Why bother to call GetWsChanges and then ignore the results? Calling this API clears out all of the information about working-set pages up to the moment that the Start Delta button was pressed.

    The End Delta button causes the EndWorkingSetDelta function, also in PSAPIWorkingSetDelta.CPP, to take over. This function calls GetWsChanges to get all the working set additions into an array of PSAPI_WS_WATCH_INFORMATION structures. The FillDeltaList box function is where all processing of the working-set additions occurs. The outermost loop of this function walks through every valid PSAPI_WS_WATCH_INFORMATION and throws out all working set changes made by ring 0 system code above 2GB. The end of the PSAPI_WS_WATCH_INFORMATION array is indicated by an entry with a NULL linear address for either the FaultingVa or FaultingPc field.

    For every remaining PSAPI_WS_WATCH_INFORMATION, FillDeltaListbox adds a line to the Working Set Delta list box. Each line contains the FaultingVa and FaultingPc addresses at a minimum. In addition, the code attempts to decode those addresses to something more meaningful. Once again, I fall back on my GetModuleNameAndSectionInfo function. In the best case, my code can give information about where the new page is from and who forced it into memory. For example, the line below says that the page encompassing the address 10190275 was faulted in by the instruction at 1017FFAF.

    10190275 1017FFAF CWDLL32.DLL!.data(4) via CWDLL32.DLL!.text(1)

    The remainder of the line gives more information. The page at 10190275 is in the CWDLL32.DLL .data section (section 4). The faulting instruction at address 1017FFAF is in the .text section (section 1) of CWDLL32.DLL.

    The last part of the PSAPIWorkingSetDemo code to describe is the GetModuleNameAndSectionInfo function from PSAPIHELPER.CPP. This function takes a process handle, a linear address, and output buffers to write its results to. Using the process handle and the linear address, the function tries to determine which EXE or DLL the address falls within. Not content to stop there, the function burrows down another level and attempts to determine the specific code or data section within the EXE or DLL. If everything goes well, the function could tell you (for instance) that a particular address is within the .rsrc section of KERNEL32.DLL, and that the .rsrc section is the fourth section within KERNEL32.DLL.

    The GetModuleNameAndSectionInfo code starts with a call to VirtualQueryEx. VirtualQueryEx fills in a MEMORY_ BASIC_INFORMATION structure with information about the input address. It seems to be a little known fact that after a VirtualQueryEx call, one of the MEMORY_BASIC_ INFORMATION fields (AllocationBase) contains the load address of the EXE or DLL that the input address belongs to. For instance, if you pass an address within USER32.DLL to VirtualQueryEx, upon return the AllocationBase field will contain USER32.DLL's load address.

    Once you know that a particular address falls within an EXE or DLL, a little more work yields the specific section within the module. To figure out which section the address falls within, you need to look at the module's IMAGE_SEC-TION_HEADER table. The IMAGE_SECTION_HEADER and other executable file data structures are defined in WINNT.H. I won't attempt to describe the intricacies of locating the IMAGE_SECTION_HEADER here. The code in PSAPIHELPER.CPP is the best description.

    One key point about GetModuleNameAndSectionInfo is that the code for traversing the module's data structures can't just access the data using pointers. Remember, the module being examined is in another process. The function has to use ReadProcessMemory to get at the module's data structures. That's why the code may seem a little more complex than it needs to be.

    This ends my little tour of PSAPI.DLL. This month, I described the working set and memory-mapped file APIs. Be sure to refer back to my August column for a description of the process, module, and memory-management APIs. It would be nice if there was a set of unified Win32 API APIs to retrieve this information on both Windows NT and Windows¨ 95. But, given all of the information that PSAPI.DLL provides, at least there's no reason for Windows NT programmers to be envious of the Windows 95 TOOLHELP32 APIs.

    Have a question about programming in Windows? Send it to Matt at 71774.362@compuserve.com.

    From the November 1996 issue of Microsoft Systems Journal.

    [转]程序员不是神 心态决定一切

    近来看了很多程序员的言论……感觉都是满腹牢骚,一肚子愤懑。我想要说的是,程序员不是神。时下一些程序员所能作的,其实大多数普通人通过一段时间的培训和学习都可以作。编程工具已越来越容易使用,编程思想越来越成熟,计算机书籍更是琳琅满目,开发过程中的规范性也已经越来越重要。作为一个普普通通的程序员,只是几个通宵的投入,1-2个月囫囵吞枣的学习,又能有什么理由能奢求太多?

      其实当很多人计算着自己一行代码值几毛钱的时候,或许他从来没有踏踏实实去考虑自己的能力和水平究竟如何。坦诚的讲,大多数程序员的代码质量和设计质量充其量只能算入门水平,学什么东西也只是皮毛而已,尽管可能简历上写得是精通……

      这社会是现实的,发展的。十多年前,程序员是个真正的有门槛的行业。因为那时候没那么多漂亮的开发工具,没有高级语言的支持,甚至连面向对象的开发思想都还仅仅是萌芽,更不用说什么质量控制体系。那时候要掌握开发技术远比其他行业的技术困难得多,只有少数精英才能做到,而且还需要有过人的智力、耐心与毅力。要付出很多很多。这些“精英”,自然也能得到社会足够的尊重。而现在,在前辈的辛苦耕耘下,进入这个行业几乎已经没有了门槛。当你怀着对前人获得的财富、荣誉和使命感走上程序员这条路的时候,可能你根本就不知道等待自己的将是什么……其实,而今在自己公司一小群程序员里“冒充”某某方面专家的时候,很多人却不知道甚至根本无法想像,在不很久远的过去,自己或许只能选择中途放弃。

      虽然不是每个人都这样,但是我还是要说:有人根本没毅力,他们只想轻轻松松的赚钱,却从来不想承担自己该承担的责任;有人根本没创造性,他唯一会作的就是把别人的代码抓来抄袭一下;有人始终自以为是,代码能编译通过和运行了就觉得可以OK完工了;有人的设计和代码糟糕冗余,可被其他人精简2-3倍长,性能也可优化数十倍;有人技术视野狭隘,搞C++的就觉得Java是个Sun的新式玩具,搞Java就鄙夷C++为洪水猛兽和怪物;更有人还把用别人发现的漏洞、别人开发的工具去黑黑别人的电脑当做自己已经是牛人和所谓的“黑客”。这些“程序员”真的能算程序员么?如果这也算程序员,我认为他们也只是现在这个时代最平庸的一群程序员而已……

      其实任何行业、任何职业都会面临这样或那样的机遇,总有不知道的困难、烦恼在前面等着你。大家羡慕的只是成功时的鲜花和啤酒,又有几个人真正去羡慕成功背后的艰辛和苦楚呢?作销售好,作管理好,作老板好,作XX好……这样类似的话我听得都厌烦了。要我说,作自己最好。

      在这社会上,我们或许习惯了用社会的、他人的标准去衡量、去比较,比如什么女朋友好不好、老婆好不好、工作好不好、老板好不好之类的。诚然,人不能脱离现实、脱离社会,人需要生存。但今天社会给我们所提供的机会,已经比我们的父辈开阔了许多许多。我不认为一个有才能、肯吃苦的人会失去谋生的机会,或者说会生存得比我们的父辈还要艰辛,我们还有什么可抱怨的?也许我们没有搭上某趟快速致富的列车,也许我们看到其他搭上列车的人的成功心理难以平衡,但是不是说我们就因此无法自信的在朋友面前抬起头,无法博得一份属于自己的爱情,无法获得其他人的尊重,无法去作一份有意义的工作,无法享受一份美好的生活呢?

      其实,没人能剥夺别人的快乐,没人能总结出一条适用于所有人的所谓“成功”标准,没人能鱼和熊掌兼得。有些人茫然的来,如同另外一些人茫然的走,没有带来什么,更没有留下什么,这就是而今大多数浮躁的程序员的道路。或许,我们的国家现在还没有美国那样重视知识、重视科学、重视创新,然而除非你自己拒绝所有的机会,不然社会也同样不会让有开发知识、有创新能力的人都被逼得当街卖烧烤。

      不懂得珍惜现在的人,永远不可能把握未来……没有好的心态,就已经先失败了一半。作什么其实不重要,然而智慧的人知道怎么踏踏实实的去走脚下的路,平庸的人却只知道羡慕和抱怨,从来不留意脚下的路。

      最后用一句话来总结:程序员不是神,心态决定一切,成功在你