Windows提供了API函数:NetScheduleJobEnum可以用于枚举Windows计划任务(Schedule Job)。其C++原形为:
NET_API_STATUS NetScheduleJobEnum( __in_opt LPCWSTR Servername, __out LPBYTE *PointerToBuffer, __in DWORD PreferredMaximumLength, __out LPDWORD EntriesRead, __out LPDWORD TotalEntries, __inout LPDWORD ResumeHandle );
(参数说明详见:http://msdn.microsoft.com/en-us/library/aa370616(VS.85).aspx)
该函数执行成功的话,最后一个参数ResumeHandle包含指向了AT_ENUM结构数组指针,可枚举的个数保存在参数EntriesRead中。
在MASM32自带的 Windows.inc 中,AT_ENUM结构的定义如下:
AT_ENUMstruct
JobIddd?
JobTimedd?
DaysOfMonthdd?
DaysOfWeekUCHAR?
FlagsUCHAR?
Commanddd?
AT_ENUMends
这与MSDN网站上的是一致的:
typedef struct _AT_ENUM { DWORD JobId; DWORD_PTR JobTime; DWORD DaysOfMonth; UCHAR DaysOfWeek; UCHAR Flags; LPWSTR Command; }AT_ENUM, *PAT_ENUM, *LPAT_ENUM;
(详见:http://msdn.microsoft.com/en-us/library/aa370247(VS.85).aspx)
但程序输出的枚举结果不正确:第1个任务的JobId等信息是正确的,但Command不正确。从2个任务开始,所有信息都不正确。
经过测试发现,AT_ENUM实际长度字节数要比上面定义的多2个字节。
之所以会多出来2个字节,是因为DaysOfWeek、Flags两个成员的类型是UCHAR,也就是一个字节的长度,为了对齐,Flags后面加了两个字节,AT_ENUM结构的实际定义如下:
_AT_ENUMstruct
JobIddd?
JobTimedd?
DaysOfMonthdd?
DaysOfWeekUCHAR?
FlagsUCHAR?
align1db?
align2db?
Commanddd?
_AT_ENUMends
这样程序输出的结果就正常了。完整的代码如下:
(源代码+EXE下载:
1、http://download.youkuaiyun.com/source/1795004
2、http://purpleendurer.ys168.com)
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
;文件名:EnumTask.asm(控制台程序)
;功能:枚举通过At命令创建的计划任务
;开发环境:WinXPPROSP3+MASM32v8
;作者:PurpleEndurer,广西河池
;log
;--------------------------------------------------
;2009-11-05将AT_ENUM修改为_AT_ENUM,OK!
;2009-10-30
;将
;addedi,sizeofAT_ENUM
;改为
;addedi,sizeofAT_ENUM+2
;输出的JobId,JobTime值正确,但Command值不对:-(
;2009-10-27开始编写
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
.586
.MODELFLAT,STDCALL
OPTIONCASEMAP:NONE
INCLUDE/masm32/include/windows.inc
INCLUDE/masm32/include/kernel32.inc
INCLUDELIB/masm32/lib/kernel32.lib
INCLUDE/masm32/include/Netapi32.inc
INCLUDELIB/masm32/lib/Netapi32.lib
INCLUDE/masm32/include/user32.inc
INCLUDELIB/masm32/lib/user32.lib
INCLUDE/masm32/include/masm32.inc
INCLUDELIB/masm32/lib/masm32.lib
WriteJobListproto
FormatJobInfoproto:LPSTR
_AT_ENUMstruct
JobIddd?
JobTimedd?
DaysOfMonthdd?
DaysOfWeekUCHAR?
FlagsUCHAR?
align1db?
align2db?
Commanddd?
_AT_ENUMends
;ssssssssssssssssssssssss
.CODE
;ssssssssssssssssssssssss
g_szAppInfodb"EnumScheduleTaskbyPurpleEndurerwithMASM32",0dh,0ah,0
start:
invokeStdOut,addrg_szAppInfo
invokeWriteJobList
invokeExitProcess,0
g_szFaildb"失败信息:",0
;g_szFmtEAXdb"(%d)",0dh,0ah,0
g_szNoTaskdb"无计划任务!",0
WriteJobListproc
LOCALpBuf:LPBYTE;DWORD;ponterto_AT_ENUM
LOCALdwRead,dwLeftBeforeCall,dwJobCount:DWORD
LOCALbuf512[512]:byte
movdwLeftBeforeCall,0
.repeat
invokeNetScheduleJobEnum,NULL,addrpBuf,MAX_PREFERRED_LENGTH/
,addrdwRead,addrdwJobCount,addrdwLeftBeforeCall
pusheax
.if(eax!=NERR_Success&&eax!=ERROR_MORE_DATA)
;pusheax
;invokewsprintf,addrbuf512,addrg_szFmtEAX,eax
;invokeStdOut,addrbuf512
;popeax
invokeGetLastError
movedi,eax
invokeFormatMessage,FORMAT_MESSAGE_ALLOCATE_BUFFERor/
FORMAT_MESSAGE_FROM_SYSTEM,NULL,edi,0,addrpBuf,0,NULL
testeax,eax
.IF!ZERO?
invokeStdOut,addrg_szFail
invokeStdOut,pBuf
invokeLocalFree,pBuf
.ENDIF
.else
movedi,pBuf
testedi,edi
.ifZERO?
invokeStdOut,addrg_szNoTask
.break
.endif
.while(dwRead>0)
pushedi
invokeFormatJobInfo,addrbuf512
invokeStdOut,addrbuf512
popedi
addedi,sizeof_AT_ENUM
decdwRead
.endw
.IF(pBuf!=NULL)
invokeNetApiBufferFree,pBuf
.ENDIF
.endif
popeax
.until(eax!=ERROR_MORE_DATA)
ret
WriteJobListendp
;
;功能:格式化任务信息
;输入:edi-指向_AT_ENUM结构的指针
;lpszBuf-指向存储格式化任务信息的缓冲区地址的指针
;输出:无
;
g_szFmtdb0dh,0ah,"%08lu%02d:%02d%S",0dh,0ah,0
FormatJobInfoproclpszBuf:LPSTR
;--计算小时
moveax,(_AT_ENUMptr[edi]).JobTime
xoredx,edx
movecx,3600000
divecx
movebx,eax;将小时值存入ebx
;--计算分钟,存于eax
moveax,edx
xoredx,edx
movecx,60000
divecx
invokewsprintf,lpszBuf,addrg_szFmt,(_AT_ENUMptr[edi]).JobId/
,ebx,eax,(_AT_ENUMptr[edi]).Command
ret
FormatJobInfoendp
ENDstart
可惜的是,NetScheduleJobEnum只能枚举AT命令创建的计划任务,不能枚举“任务计划”向导创建的任务。