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_ENUM struct
JobId dd ?
JobTime dd ?
DaysOfMonth dd ?
DaysOfWeek UCHAR ?
Flags UCHAR ?
Command dd ?
AT_ENUM ends
这与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_ENUM struct
JobId dd ?
JobTime dd ?
DaysOfMonth dd ?
DaysOfWeek UCHAR ?
Flags UCHAR ?
align1 db ?
align2 db ?
Command dd ?
_AT_ENUM ends
这样程序输出的结果就正常了。完整的代码如下:
(源代码+EXE下载:
1、http://download.csdn.net/source/1795004
2、http://purpleendurer.ys168.com)
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; 文 件 名:EnumTask.asm (控制台程序)
; 功 能: 枚举通过At命令创建的计划任务
; 开发环境:Win XP PRO SP3 + MASM32 v8
; 作 者:PurpleEndurer, 广西河池
; log
; --------------------------------------------------
; 2009-11-05 将AT_ENUM 修改为 _AT_ENUM, OK!
; 2009-10-30
; 将
; add edi, sizeof AT_ENUM
; 改为
; add edi, sizeof AT_ENUM + 2
; 输出的JobId, JobTime值正确,但Command值不对 :-(
; 2009-10-27 开始编写
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
.586
.MODEL FLAT,STDCALL
OPTION CASEMAP: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
WriteJobList proto
FormatJobInfo proto :LPSTR
_AT_ENUM struct
JobId dd ?
JobTime dd ?
DaysOfMonth dd ?
DaysOfWeek UCHAR ?
Flags UCHAR ?
align1 db ?
align2 db ?
Command dd ?
_AT_ENUM ends
;ssssssssssssssssssssssss
.CODE
;ssssssssssssssssssssssss
g_szAppInfo db "Enum Schedule Task by PurpleEndurer with MASM32", 0dh, 0ah, 0
start:
invoke StdOut, addr g_szAppInfo
invoke WriteJobList
invoke ExitProcess, 0
g_szFail db "失败信息:", 0
;g_szFmtEAX db "(%d)", 0dh, 0ah, 0
g_szNoTask db "无计划任务!", 0
WriteJobList proc
LOCAL pBuf: LPBYTE ;DWORD; ponter to _AT_ENUM
LOCAL dwRead, dwLeftBeforeCall, dwJobCount: DWORD
LOCAL buf512[512]: byte
mov dwLeftBeforeCall, 0
.repeat
invoke NetScheduleJobEnum, NULL, addr pBuf, MAX_PREFERRED_LENGTH/
, addr dwRead, addr dwJobCount, addr dwLeftBeforeCall
push eax
.if (eax != NERR_Success && eax != ERROR_MORE_DATA)
;push eax
;invoke wsprintf, addr buf512, addr g_szFmtEAX, eax
;invoke StdOut, addr buf512
;pop eax
invoke GetLastError
mov edi, eax
invoke FormatMessage, FORMAT_MESSAGE_ALLOCATE_BUFFER or/
FORMAT_MESSAGE_FROM_SYSTEM, NULL, edi, 0, addr pBuf, 0, NULL
test eax, eax
.IF !ZERO?
invoke StdOut, addr g_szFail
invoke StdOut, pBuf
invoke LocalFree, pBuf
.ENDIF
.else
mov edi, pBuf
test edi, edi
.if ZERO?
invoke StdOut, addr g_szNoTask
.break
.endif
.while (dwRead > 0)
push edi
invoke FormatJobInfo, addr buf512
invoke StdOut, addr buf512
pop edi
add edi, sizeof _AT_ENUM
dec dwRead
.endw
.IF (pBuf != NULL)
invoke NetApiBufferFree, pBuf
.ENDIF
.endif
pop eax
.until (eax != ERROR_MORE_DATA)
ret
WriteJobList endp
;////////////////////////////////////////////////////////
; 功能:格式化任务信息
; 输入:edi - 指向 _AT_ENUM 结构的指针
; lpszBuf - 指向存储格式化任务信息的缓冲区地址的指针
; 输出:无
;////////////////////////////////////////////////////////
g_szFmt db 0dh, 0ah, "%08lu %02d:%02d %S", 0dh, 0ah, 0
FormatJobInfo proc lpszBuf: LPSTR
;-- 计算小时
mov eax, (_AT_ENUM ptr [edi]).JobTime
xor edx, edx
mov ecx, 3600000
div ecx
mov ebx, eax ;将小时值存入ebx
;-- 计算分钟,存于eax
mov eax, edx
xor edx, edx
mov ecx, 60000
div ecx
invoke wsprintf, lpszBuf, addr g_szFmt, (_AT_ENUM ptr [edi]).JobId/
, ebx, eax, (_AT_ENUM ptr [edi]).Command
ret
FormatJobInfo endp
END start
可惜的是,NetScheduleJobEnum只能枚举AT命令创建的计划任务,不能枚举“任务计划”向导创建的任务。