关于脚本托盘图标鼠标操作与自启丢图标处理方法
#NoEnv
#MaxMem 2048
;#NoTrayIcon
#SingleInstance, Force
SetBatchLines, -1
#MaxThreadsPerHotkey 100
#MaxHotkeysPerInterval 400
#Persistent
#WinActivateForce
#Include %A_ScriptDir%
;;脚本托盘图标消息监控
OnMessage(0x404, "AHK_NOTIFYICON")
;自启任务名称
TaskName:="自启动示例脚本"
If !A_IsAdmin {
Try
{
If A_IsCompiled {
Run *RunAs "%A_ScriptFullPath%" /restart
ExitApp
}else{
Run *RunAs "%A_AhkPath%" /restart "%A_ScriptFullPath%"
}
}Catch e{
MsgBox, 262160,Error,% e.Extra?e.Extra:"以管理员身份运行失败!",15
ExitApp
}
}
;;检查开机自启后脚本是否出现丢失托盘图标,如果丢失托盘图标Reload至出现托盘图标为止
TrayIconInfo:=TrayIcon_GetInfo(A_IsCompiled?A_ScriptName:RegExReplace(A_AhkPath,".+\\"))
if (!A_IconHidden) {
if (A_IsCompiled&&!objcount(TrayIconInfo)){
Gosub OnReload
}else if (!A_IsCompiled&&!objcount(TrayIconInfo)){
Gosub OnReload
}else if (!A_IsCompiled&&objcount(TrayIconInfo)){
IsNoHide:=0
for key,value In TrayIconInfo
{
if (value.pid=DllCall("GetCurrentProcessId"))
IsNoHide++
}
if !IsNoHide
Gosub OnReload
}
}
;;检查脚本托盘图标是否末显示在任务栏被收缩托盘区并提示
if objcount(TrayIconInfo){
for key,value In TrayIconInfo
{
if (InStr(TrayIconInfo[key,"Tray"],"NotifyIconOverflowWindow")&&TrayIconInfo[key,"pid"]=DllCall("GetCurrentProcessId")){
Traytip,Warning,请把程序图标从托盘区移至`n任务栏以方便更好的操作!,,2
}Else if (!InStr(TrayIconInfo[key,"Tray"],"NotifyIconOverflowWindow")&&TrayIconInfo[key,"pid"]=DllCall("GetCurrentProcessId")){
Traytip,Warning,程序图标末收缩正常显示!,,1
}
}
}
Gosub TrayMenu
Return
;;==============================================================
TrayMenu:
Menu, TRAY, NoStandard
Menu, TRAY, DeleteAll
Menu, Tray, UseErrorLevel
Menu, TRAY,Color, ffffff
Menu, TRAY,Add, 自启,AutoRunScript
Menu, Tray, Icon, 自启,shell32.dll,234
;自启项有效性检测并自动校正
Try
{
if objCount(TaskActionExecPaths:=GetTaskActionExecPaths(TaskName)){
if A_IsCompiled {
if (TaskActionExecPaths[1,1]=A_ScriptFullPath){
Menu, TRAY,Check, 自启
}Else{
if DisableAutorun(TaskName){
if (EnableAutoRun(TaskName,"这是一个演示自启动示例",(A_IsCompiled?A_ScriptFullPath:A_AhkPath),!A_IsCompiled?A_ScriptFullPath:"")=TaskName){
Menu, TRAY,Check, 自启
}
}
}
}else{
if (TaskActionExecPaths[1,1]=A_AhkPath&&TaskActionExecPaths[1,2]=A_ScriptFullPath){
Menu, TRAY,Check, 自启
}Else{
if DisableAutorun(TaskName){
if (EnableAutoRun(TaskName,"这是一个演示自启动示例",(A_IsCompiled?A_ScriptFullPath:A_AhkPath),!A_IsCompiled?A_ScriptFullPath:"")=TaskName){
Menu, TRAY,Check, 自启
}
}
}
}
}
}Catch{
TargetPath:=IsExistShortcut(A_Startup,A_IsCompiled?A_ScriptFullPath:A_AhkPath,!A_IsCompiled?A_ScriptFullPath:"")
if !TargetPath&&FileExist(A_Startup "\" TaskName ".lnk") {
FileDelete,%A_Startup%\%TaskName%.lnk
if CreateShortcut(A_Startup "\" TaskName ".lnk",A_IsCompiled?A_ScriptFullPath:A_AhkPath,!A_IsCompiled?A_ScriptFullPath:"","这是一个演示自启动示例"){
Menu, Tray, Check, 自启
}Else{
Menu, Tray, Uncheck, 自启
Menu, Tray, Icon, 自启,shell32.dll,234
}
}Else if TargetPath {
Menu, Tray, Check, 自启
}
}
Menu, TRAY,Add,
Menu, TRAY,Add, 重启,OnReload
Menu, TRAY,Add, 退出,OnExits
Menu, TRAY,Tip, ahk模板示例
Return
AutoRunScript:
Try
{
if IsAutoRun:=EnableAutoRun(TaskName,"这是一个演示自启动示例",(A_IsCompiled?A_ScriptFullPath:A_AhkPath),!A_IsCompiled?A_ScriptFullPath:"") {
if (IsAutoRun=1){
Menu, Tray, Uncheck, 自启
Menu, Tray, Icon, 自启,shell32.dll,234
traytip,%TaskName%,已取消开机自启任务!,,1
}Else if (IsAutoRun<0){
MsgBox, 262160, Error,添加异常!,8
}Else if (IsAutoRun=TaskName){
Menu, Tray, Check, 自启
traytip,%TaskName%,已建立开机自启任务!,,1
}Else{
Menu, Tray, Uncheck, 自启
Menu, Tray, Icon, 自启,shell32.dll,234
traytip,%TaskName%,%IsAutoRun%,,2
}
}else{
Menu, Tray, Uncheck, 自启
Menu, Tray, Icon, 自启,shell32.dll,234
traytip,Error,建立开机自启任务失败!,,3
}
}Catch{
TargetPath:=IsExistShortcut(A_Startup,A_IsCompiled?A_ScriptFullPath:A_AhkPath,!A_IsCompiled?A_ScriptFullPath:"")
if !TargetPath {
FileDelete,%A_Startup%\%TaskName%.lnk
if CreateShortcut(A_Startup "\" TaskName ".lnk",A_IsCompiled?A_ScriptFullPath:A_AhkPath,!A_IsCompiled?A_ScriptFullPath:"","这是一个演示自启动示例"){
Menu, Tray, Check, 自启
traytip,%TaskName%,已建立自启快捷方式!,,1
}Else{
Menu, Tray, Uncheck, 自启
Menu, Tray, Icon, 自启,shell32.dll,234
traytip,Error,建立自启快捷方式失败!,,3
}
}Else{
FileDelete,%TargetPath%
Menu, Tray, Uncheck, 自启
Menu, Tray, Icon, 自启,shell32.dll,234
traytip,%TaskName%,已取消自启快捷方式!,,1
}
}
Return
OnReload:
Reload
Return
OnExits:
ExitApp
Return
;;;根据进程文件名获取托盘图标信息列表,以判断托盘图标是否正常显示
TrayIcon_GetInfo(sExeName := "")
{
d := A_DetectHiddenWindows
DetectHiddenWindows, On
oTrayInfo := []
For key,sTray in ["Shell_TrayWnd", "NotifyIconOverflowWindow"]
{
idxTB := TrayIcon_GetTrayBar(sTray)
WinGet, pidTaskbar, PID, ahk_class %sTray%
hProc := DllCall("OpenProcess", UInt,0x38, Int,0, UInt,pidTaskbar)
pRB := DllCall("VirtualAllocEx", Ptr,hProc, Ptr,0, UPtr,20, UInt,0x1000, UInt,0x04)
szBtn := VarSetCapacity(btn, (A_Is64bitOS ? 32 : 20), 0)
szNfo := VarSetCapacity(nfo, (A_Is64bitOS ? 32 : 24), 0)
szTip := VarSetCapacity(tip, 128 * 2, 0)
; TB_BUTTONCOUNT = 0x0418
SendMessage, 0x0418, 0, 0, ToolbarWindow32%idxTB%, ahk_class %sTray%
Loop, %ErrorLevel%
{
; TB_GETBUTTON 0x0417
SendMessage, 0x0417, A_Index-1, pRB, ToolbarWindow32%idxTB%, ahk_class %sTray%
DllCall("ReadProcessMemory", Ptr,hProc, Ptr,pRB, Ptr,&btn, UPtr,szBtn, UPtr,0)
iBitmap := NumGet(btn, 0, "Int")
idCmd := NumGet(btn, 4, "Int")
fsState := NumGet(btn, 8, "UChar")
fsStyle := NumGet(btn, 9, "UChar")
dwData := NumGet(btn, (A_Is64bitOS ? 16 : 12), "UPtr")
iString := NumGet(btn, (A_Is64bitOS ? 24 : 16), "Ptr")
DllCall("ReadProcessMemory", Ptr,hProc, Ptr,dwData, Ptr,&nfo, UPtr,szNfo, UPtr,0)
hWnd := NumGet(nfo, 0, "Ptr")
uId := NumGet(nfo, (A_Is64bitOS ? 8 : 4), "UInt")
msgId := NumGet(nfo, (A_Is64bitOS ? 12 : 8), "UPtr")
hIcon := NumGet(nfo, (A_Is64bitOS ? 24 : 20), "Ptr")
WinGet, nPid, PID, ahk_id %hWnd%
WinGet, sProcess, ProcessName, ahk_id %hWnd%
WinGetClass, sClass, ahk_id %hWnd%
If ( !sExeName || sExeName == sProcess || sExeName == nPid )
{
DllCall("ReadProcessMemory", Ptr,hProc, Ptr,iString, Ptr,&tip, UPtr,szTip, UPtr,0)
oTrayInfo.Push({ "idx" : A_Index-1
, "idcmd" : idCmd
, "pid" : nPid
, "uid" : uId
, "msgid" : msgId
, "hicon" : hIcon
, "hwnd" : hWnd
, "class" : sClass
, "process" : sProcess
, "tooltip" : StrGet(&tip, "UTF-16")
, "tray" : sTray })
}
}
DllCall("VirtualFreeEx", Ptr,hProc, Ptr,pRB, UPtr,0, UInt,0x8000)
DllCall("CloseHandle", Ptr,hProc)
}
DetectHiddenWindows, %d%
Return oTrayInfo
}
TrayIcon_GetTrayBar(sTray:="Shell_TrayWnd")
{
d := A_DetectHiddenWindows
DetectHiddenWindows, On
WinGet, ControlList, ControlList, ahk_class %sTray%
RegExMatch(ControlList, "(?<=ToolbarWindow32)\d+(?!.*ToolbarWindow32)", nTB)
Loop, %nTB%
{
ControlGet, hWnd, hWnd,, ToolbarWindow32%A_Index%, ahk_class %sTray%
hParent := DllCall( "GetParent", Ptr, hWnd )
WinGetClass, sClass, ahk_id %hParent%
If !(sClass == "SysPager" || sClass == "NotifyIconOverflowWindow" )
Continue
idxTB := A_Index
Break
}
DetectHiddenWindows, %d%
Return idxTB
}
AHK_NOTIFYICON(wParam, lParam, uMsg, hWnd)
{
;;脚本托盘图标单击与双击尽量不要同时启用
if (lParam = 0x201){ ;鼠标左键单击脚本托盘图标
MsgBox,你单击了鼠标左键
}
if (lParam = 0x203){ ;鼠标左键双击脚本托盘图标
MsgBox,你双击了鼠标左键
}
if (lParam = 0x204){ ;鼠标右键单击脚本托盘图标
MsgBox,你单击了鼠标右键
}
if (lParam = 0x206){ ;鼠标右键双击脚本托盘图标
MsgBox,你双击了鼠标右键
}
if (lParam = 0x207){ ;鼠标中键单击脚本托盘图标
MsgBox,你单击了鼠标中键
}
if (lParam = 0x209){ ;鼠标中键双击脚本托盘图标
MsgBox,你双击了鼠标中键
}
}
;获取系统计划任务自启列表
GetTaskInfos() {
objService := ComObjCreate("Schedule.Service")
objService.Connect()
rootFolder := objService.GetFolder("\")
taskCollection := rootFolder.GetTasks(0)
numberOfTasks := taskCollection.Count
; ?RegistrationInfo.Author
For registeredTask, state in taskCollection
{
if (registeredTask.state == 0)
state:= "Unknown"
else if (registeredTask.state == 1)
state:= "Disabled"
else if (registeredTask.state == 2)
state:= "Queued"
else if (registeredTask.state == 3)
state:= "Ready"
else if (registeredTask.state == 4)
state:= "Running"
tasklist .= registeredTask.Name "=" state "=" registeredTask.state "`n"
}
return RTrim(tasklist,"`n")
}
;判断是否自启
IsAutorunEnabled(TaskName)
{
objService := ComObjCreate("Schedule.Service")
objService.Connect()
objFolder := objService.GetFolder("\")
Try {
RunAsTask := objFolder.GetTask( TaskName )
return ! A_LastError
}Catch
Return ""
}
;取消自启
DisableAutorun(TaskName){
objService := ComObjCreate("Schedule.Service")
objService.Connect()
objFolder := objService.GetFolder("\")
Try {
objFolder.DeleteTask(TaskName, 0)
Return !A_LastError
}Catch
Return ""
}
;根据自启任务名获取自启文件长路径
GetTaskActionExecPaths(taskName, folderPath := "\") {
service := ComObjCreate("Schedule.Service")
service.Connect()
Try {
Paths:=[]
for action in service.GetFolder(folderPath).GetTask(taskName).Definition.Actions
if (action.Type ==0)
Paths.Push([RegExReplace(action.Path,"[\""""]"),RegExReplace(action.Arguments,"[\""""]")])
Return Paths
}Catch
Return []
}
;设置自启
EnableAutoRun(taskName:="",DescriptionInfo:="",ProcessPath="",ScriptPath="",TaskState=3)
{
if (!TaskName||!ProcessPath)
Return -1
TaskExists := IsAutorunEnabled(taskName)
if (A_IsAdmin and TaskExists) {
if DisableAutorun(TaskName)
Return 1
}else If ( not A_IsAdmin and TaskExists ) {
Return !A_IsAdmin?"建立失败,当前非管理员身份!":""
}else If ( not A_IsAdmin and not TaskExists ){
Return !A_IsAdmin?"建立失败,当前非管理员身份!":""
}else If ( A_IsAdmin and not TaskExists ) {
TriggerType = 9 ; trigger on logon.
ActionTypeExec = 0 ; specifies an executable action.
TaskCreateOrUpdate = 6
Task_Runlevel_Highest = 1
objService := ComObjCreate("Schedule.Service")
objService.Connect()
objFolder := objService.GetFolder("\")
objTaskDefinition := objService.NewTask(0)
principal := objTaskDefinition.Principal
principal.LogonType := 1 ; Set the logon type to TASK_LOGON_PASSWORD
principal.RunLevel := Task_Runlevel_Highest ; Tasks will be run with the highest privileges.
colTasks := objTaskDefinition.Triggers
objTrigger := colTasks.Create(TriggerType)
colActions := objTaskDefinition.Actions
objAction := colActions.Create(ActionTypeExec)
objAction.ID := "Autorun"
if(A_IsCompiled)
objAction.Path := """" Trim(ProcessPath) """"
else
{
objAction.Path := """" Trim(ProcessPath) """"
objAction.Arguments := """" Trim(ScriptPath) """"
}
objAction.WorkingDirectory := A_ScriptDir
objInfo := objTaskDefinition.RegistrationInfo
objInfo.Author := A_UserName
objInfo.Description := DescriptionInfo
objSettings := objTaskDefinition.Settings
objSettings.Enabled := True
objSettings.Hidden := False
objSettings.StartWhenAvailable := True
objSettings.ExecutionTimeLimit := "PT0S"
objSettings.DisallowStartIfOnBatteries := False
objSettings.StopIfGoingOnBatteries := False
objFolder.RegisterTaskDefinition(taskName, objTaskDefinition, TaskCreateOrUpdate , "", "", TaskState )
if IsAutorunEnabled(taskName)
Return taskName
}
}
GetShortcut(Path){
Local obj
obj:={}
FileGetShortcut, %Path% , TargetPath,WorkingDir,ArgsName,Description,IconPath,IconNum
if (!ErrorLevel&&TargetPath){
obj["Target"]:=TargetPath,obj["Args"]:=ArgsName,obj["Dir"]:=WorkingDir,obj["Description"]:=Description
,obj["IconPath"]:=Trim(IconPath,""""),obj["IconNum"]:=IconNum
}
Return obj
}
CreateShortcut(LinkFile,Target,Args:="",Description:="",WorkingDir:="",IconFile:="",IconNumber:="",ShortcutKey:="",RunState:=1){
IconFile:=IconFile?IconFile:A_IsCompiled?A_ScriptFullPath:A_AhkPath
WorkingDir:=WorkingDir?WorkingDir:RegExReplace(Target,"\\[^\\]+$")
Args:=FileExist(Trim(Trim(Args),""""))?"""" Trim(Trim(Args),"""") """":Args
FileCreateShortcut, %Target%, %LinkFile% , %WorkingDir%, %Args%, %Description%, %IconFile%, %ShortcutKey%, %IconNumber%, %RunState%
Return !ErrorLevel
}
IsExistShortcut(Dir,Target,Args:=""){
Loop, Files, %Dir%\*.lnk
{
FileGetShortcut, %A_LoopFileFullPath% , TargetPath,WorkingDir,ArgsName,Description,IconPath,IconNum, RunState
if (!ErrorLevel&&TargetPath){
Args:=Trim(Trim(Args),""""),ArgsName:=Trim(Trim(ArgsName),""""),Target:=Trim(Trim(Target),""""),TargetPath:=Trim(Trim(TargetPath),"""")
if !FileExist(TargetPath){
FileDelete,%A_LoopFileFullPath%
Continue
}
if (Target=TargetPath&&Args=ArgsName){
Return A_LoopFileFullPath
}
}
}
Return False
}
用代码框包起来,效果更好!