屏幕保护程序的编写
相关的例子:下载>>> 作者:谢平 于2008-7-19上传
--------------------------------------------------------------------------------
by 谢平
记得一两年之前试着用汇编语言编写屏幕保护程序的时候,本人还是一个菜菜的单细胞生物,当然现在也只是一个菜菜的多细胞生物而已0_0.
因为那时候比较的菜,所以当时我没有成功。其实问题出在程序中用到的ScrnSave.Lib文件,这次我用的是从vc 6.0里COPY过来的,在附件里的ScrnSave.Lib比masm中的要大的多,我们需要用附件中的替换掉masn中的那个lib文件。
关于屏幕保护的编写,罗老师在n (n>=6)年之前就已经专门作文阐述,这篇文章现在在网络上广为流传,家喻户晓,地址是http://211.90.241.130:22366/view.asp?file=71。
本文不想浪费口水并污染大家的耳朵,其实是眼睛啦!~~附件里实现的是半个XP系统附带的那个图片浏览幻灯片屏幕保护程序,由于牵涉到图片的处理,所以偷懒使用了aogo.yeah.net 上的image.lib,这个库“灰常”好用,省了我不少功夫。
附件里一共包括screen.asm, screen.scr, screen.rc, image.inc, image.lib, scrnsave.lib等六个文件。代码没有什么技术含量,相信聪明的你肯定可以看明白的,目前程序只能显示jpg和bmp两种最常见的图像文件。由于本两人没有足够的艺术头脑,所以做出的东东往往不够美观。您可以任意修改程序以使其臻于完美。
程序的具体思路如下,你应当先看罗老师的那篇教程,我的代码都是在他的基础上修改的。哎呀又要贴代码啦:
1.RegisterDialogClasses保持罗的代码不变化。
2.在ScreenSaverConfigureDialog函数中,打开文件,保存设置的结果。设置对话框的运行效果如下,可以在文本框中输入合法的包含图片的路径。
结果保存在config.ini文件中,这个文件是由我们自己创建的,你也可以通过注册表传递设置的信息。
3.修改ScreenSaverProc函数代码
其中WM_CREATE消息响应中设置一个定时器
.elseif eax == WM_CREATE
invoke SetTimer,hWnd,TIMER,3000,NULL ;set the timer
在WM_DESTORY中,取消这个定时器,并退出程序
.elseif eax == WM_DESTROY
invoke KillTimer,hWnd,TIMER ;Kill the timer
invoke ExitProcess,NULL
在WM_TIMER消息响应中添加如下代码
.if eax == WM_TIMER
;擦除上次图片显示的矩形区域,不擦除影响美观
mov stRect.left,0 ;stRecr是一个结构,每次在WM_TIMER的最后修改
mov stRect.top,0 ;dwHeight和dwWidth
push dwWidth
pop stRect.right
push dwHeight
pop stRect.bottom
invoke GetDC,hWnd
mov hDC,eax
invoke GetClientRect,hWnd,addr stRect
invoke GetStockObject,BLACK_BRUSH ;使用黑画刷
invoke FillRect,hDC,addr stRect,eax
invoke ReleaseDC,hWnd,hDC
从config.ini中读取设置的路径
invoke CreateFile,addr szConfigFile,GENERIC_READ,FILE_SHARE_READ,\
0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0
.if eax != INVALID_HANDLE_VALUE
mov @hNewFile,eax
invoke ReadFile,@hNewFile,addr szPath,dwBufferSize,\
addr @nNumOfBytesRead,NULL
invoke CloseHandle,@hNewFile
.endif
;先搜索所有的jpg文件,然后是bmp文件,这段代码出自罗的教材
.if dwFlag == FIND_JPG
;find every jpg file in the directory
.if hFindFile == 0
invoke lstrlen,addr szPath
.if eax == 0 ;if the directory NULL,use the current directory
invoke GetCurrentDirectory,dwBufferSize,addr szPath
.endif
invoke SetCurrentDirectory,addr szPath ;this line is needed!!!
mov dwFlag,FIND_JPG
invoke FindFirstFile,addr szFindJpg,addr stFindFileData
.if eax != INVALID_HANDLE_VALUE
mov hFindFile,eax
.endif
.else
@@:
invoke FindNextFile,hFindFile,addr stFindFileData
.if eax == FALSE
invoke FindClose,hFindFile
mov hFindFile,0
mov dwFlag,FIND_BMP
.endif
.endif
.else
;find every bmp file in the directory
.if hFindFile == 0
invoke lstrlen,addr szPath ;if the directory NULL,use the current directory
.if eax == 0
invoke GetCurrentDirectory,dwBufferSize,addr szPath
.endif
invoke SetCurrentDirectory,addr szPath ;this line is needed!!!
mov dwFlag,FIND_JPG
invoke FindFirstFile,addr szFindBmp,addr stFindFileData
.if eax != INVALID_HANDLE_VALUE
mov hFindFile,eax
.endif
.else
@@:
invoke FindNextFile,hFindFile,addr stFindFileData
.if eax == FALSE
invoke FindClose,hFindFile
mov hFindFile,0
mov dwFlag,FIND_JPG
.endif
.endif
.endif
.if stFindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
jmp @B ;if a directory continue
.endif
;得到文件的全路径
invoke lstrcpy,addr szPic,addr szPath
invoke lstrcat,addr szPic,addr szSUB
invoke lstrcat,addr szPic,addr stFindFileData.cFileName
;加载图片文件
invoke BitmapFromFile,addr szPic ;using the image.lib from aogo.yeah.net
.if eax!=0
mov hPic,eax
.endif
;显示图片
invoke GetDC,hWnd
mov hDC,eax
invoke CreateCompatibleDC,hDC
mov DC,eax
invoke SelectObject,DC,hPic
invoke GetObject,hPic, sizeof stBMP,addr stBMP
invoke BitBlt,hDC,0,0,stBMP.bmWidth, \
stBMP.bmHeight,DC,0,0,SRCCOPY
invoke ReleaseDC,hWnd,hDC
;保存显示当前图片的矩形区域,待下次擦除
push stBMP.bmWidth
pop dwWidth
push stBMP.bmHeight
pop dwHeight
使用生成常规可执行程序的方式编译链接,生成后将.exe文件的扩展名改为.scr,点右键选择配置将会出现上图的配置对话框,设置合法的路径保存会生成config.ini配置文件。程序运行的结果当然是显示指定目录下的图片文件,顺便提一下,可以使用以下代码激活屏幕保护程序:
.386
.model flat,stdcall
option casemap:none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
.code
start:
invoke SendMessage, HWND_BROADCAST,\
WM_SYSCOMMAND,SC_SCREENSAVE,0
invoke ExitProcess,0
end start
PS:
由于image.Lib是专门为masm32 v8而写的,作者的源代码中包含头文件的部分是这样子写的:
Include \masm32\lib\user32.lib
Include \masm32\lib\masm32.lib
Include \masm32\lib\kernel32.lib
Include \masm32\lib\gdi32.lib
Include \masm32\lib\ole32.lib
Include \masm32\lib\oleaut32.lib
Include \masm32\lib\COMCTL32.LIB\masm32\lib\user32.lib
\masm32\lib\masm32.lib
\masm32\lib\kernel32.lib
\masm32\lib\gdi32.lib
\masm32\lib\ole32.lib
\masm32\lib\oleaut32.lib
\masm32\lib\COMCTL32.LIB
\masm32\lib\user32.lib
\masm32\lib\masm32.lib
\masm32\lib\kernel32.lib
\masm32\lib\gdi32.lib
\masm32\lib\ole32.lib
\masm32\lib\oleaut32.lib
\masm32\lib\COMCTL32.LIB
其实这种写法是和路径有一定关系的,因为必须存在\masm32\lib目录,如果没有这个目录会出现麻烦。
所以我一般的写法是这样的
Include user32.lib
Include masm32.lib
Include kernel32.lib
Include gdi32.lib
Include ole32.lib
Include oleaut32.lib
Include COMCTL32.LIB\masm32\lib\user32.lib
\masm32\lib\masm32.lib
\masm32\lib\kernel32.lib
\masm32\lib\gdi32.lib
\masm32\lib\ole32.lib
\masm32\lib\oleaut32.lib
\masm32\lib\COMCTL32.LIB
\masm32\lib\user32.lib
\masm32\lib\masm32.lib
\masm32\lib\kernel32.lib
\masm32\lib\gdi32.lib
\masm32\lib\ole32.lib
\masm32\lib\oleaut32.lib
\masm32\lib\COMCTL32.LIB
这样的话就和路径无关了,(因为使用的是当前目录)。
这个问题产生的后果是,使用masmPlus无法正常链接。感谢Ziv同志发现这个问题。
这个问题的解决办法是:
1. 我尝试给作者(ernie@surfree.com)发信件,请求作者修改源代码并重新build,可是系统提示“发送失败“。
2. 无奈之下,我只好手动修改image.lib文件,希望作者不要因为版权的问题给我发来一份法院的传单^_^。如果懂得lib文件格式的话其实修改很容易。在这里略去。在附件里有image.lib和修改之前的image.Lib文件,有兴趣可以比较一下这两个文件。
--------------------------------------------------------------------------------