仿DropIt拖拽文件归类整理demo示例

部分代码示例:

一个供新手入门的demo,规则配置窗口需要自己折腾。

/*
	author:oeasy(QQ:2880424)
	https://wwt.lanzoul.com/b07nzwd4f 密码:84bs
*/
;编译exe文件信息及版本号设置
ToolVersion:="1.4.0"					;设置版本号
;@Ahk2Exe-Obey U_bits, = "%A_PtrSize%>4" ? " - 64bit" : " - 32bit"	; 判断位数
;@Ahk2Exe-Let U_version = %A_PriorLine~U)^(.+"){1}(.+)".*$~$2%		; 读取版本号以编译
;@Ahk2Exe-AddResource Icon\Pause2.ico, 160			; 替换自带的'蓝色H'图标
;@Ahk2Exe-AddResource Icon\lock2.ico, 206			; 替换为 '绿色 S'
;@Ahk2Exe-AddResource Icon\Pause1.ico, 207			; 替换自带的'红色H'图标
;@Ahk2Exe-AddResource Icon\lock1.ico, 208			; 替换为 '红色 S'
;@Ahk2Exe-SetMainIcon Icon\tools.ico				; 指定托盘图标文件
;@Ahk2Exe-ExeName %A_ScriptDir%\DropIt文件归类.exe			; 打包后的exe文件路径
;@Ahk2Exe-SetCompanyName oeasy撸码客				; 企业信息
;@Ahk2Exe-SetCopyright Copyright (c) oeasy			; 版权信息
;@Ahk2Exe-SetLegalTrademarks DropIt-AHK			; 更改合法商标信息.
;@Ahk2Exe-SetDescription DropIt文件归类-AHK版			; 文件说明
;@Ahk2Exe-SetFileVersion %U_version%				; 文件版本
;@Ahk2Exe-SetInternalName DropIt-AHK				; 文件内部名
;@Ahk2Exe-SetLanguage 0x0804				; 区域语言
;@Ahk2Exe-SetName DropIt-AHK				; 名称
;@Ahk2Exe-SetProductName DropIt-AHK				; 产品名称
;@Ahk2Exe-SetOrigFilename DropIt-AHK.exe			; 原始文件名称
;@Ahk2Exe-SetProductVersion %U_version%			; 产品版本号
;@Ahk2Exe-SetVersion %U_version%				; 版本号

If A_IsCompiled {
	thisPID := DllCall("GetCurrentProcessId")
	if objCount(Processlist:=GetProcessNameList(A_ScriptName))>1
	{
		loop,% objCount(Processlist)
		{
			if (thisPID<>Processlist[A_Index,2]){
				process,Close,% Processlist[A_Index,2]
			}
		}
	}
}Else{
	DetectHiddenWindows, On
	thisPID := DllCall("GetCurrentProcessId")
	WinGet, List, List,%A_ScriptName%
	Loop % List
	{
		WinGet, PID, PID, % "ahk_id " List%A_Index%
		WinGetTitle, WinTitle , % "ahk_id " List%A_Index%
		If (PID != thisPID&&WinTitle=A_ScriptName){
			process,Close,% PID
		}
	}
	DetectHiddenWindows, Off
}

#NoEnv
#MaxMem 2048
#SingleInstance, Force
SetBatchLines, -1
#InstallKeybdHook
#InstallMouseHook
#MaxThreadsPerHotkey 100
#MaxHotkeysPerInterval 400
#Persistent
#WinActivateForce
#Include %A_ScriptDir%
#Include <gdip_all>
#Include <Class_EasyIni>
OnMessage(0x201,"WM_LBUTTONDOWN")
;OnMessage(0x200, "WM_MOUSEMOVE")
;=====================================环境检测==================================
if (A_AhkVersion<1.1.33){
	MsgBox,262160,Error,ahk主程序版本过低,要求1.1.33+,20
	ExitApp
}
if Not A_OSVersion~="i)^(WIN_7|WIN_8|\d+)"{
	MsgBox,262160,Error,仅支持Win7及Win7以上系统!,20
	ExitApp
}
;=====================================权限检测==================================
RunAsAdmin()
Loop 2  ; 解决管理员权限运行脚本时,文件无法拖拽的问题
	DllCall("ChangeWindowMessageFilter", "UInt", "0x" (i:=!i?49:233), "Uint", 1)
;=====================================临时目录检测==================================
if !FileExist(A_Temp "\DropFilesTool\")
	FileCreateDir,%A_Temp%\DropFilesTool
if !FileExist(A_Temp "\DropFilesTool\dll\x86"){
	FileCreateDir,%A_Temp%\DropFilesTool\dll\x86
	FileInstall,dll\x86\MinHook.dll,%A_Temp%\DropFilesTool\dll\x86\MinHook.dll,1
}
if !FileExist(A_Temp "\DropFilesTool\dll\x64"){
	FileCreateDir,%A_Temp%\DropFilesTool\dll\x64
	FileInstall,dll\x64\MinHook.dll,%A_Temp%\DropFilesTool\dll\x64\MinHook.dll,1
}
;=====================================logo文件处理==================================
; 自定义修改Gui窗口类名、不再是AutoHotkeyGUI
Global LogoClassName:="DropItToolUI"
try {
	CWHOOK := New MinHook("user32.dll", "CreateWindowExW", "CreateWindowExW_Hook")
	RCHOOK := New MinHook("user32.dll", "RegisterClassExW", "RegisterClassExW_Hook")
	MH_EnableHook()
}
FileInstall,logo.png,%A_Temp%\DropFilesTool\logo.png,1
ImageNumber:=1
,ImagePath:=A_IsCompiled
		?FileExist(A_ScriptDir "\logo.png")
			?A_ScriptDir "\logo.png"
			:A_Temp "\DropFilesTool\logo.png"
		:A_ScriptDir "\logo.png"
if !FileExist(ImagePath){
	ImagePath:="shell32.dll",ImageNumber:=87,ImageWidth:=128,ImageHeight:=128
}Else{
	;计算图片合适的缩放率
	logosize:=GetLogoInitialScale(ImagePath, ImageWidth, ImageHeight)
}

;=====================================配置读取及检测==================================
DefaultParam:={"Logo参数":{xpos:200,ypos:200,mode:"cut",AutoClassified:False,logosize:logosize}
	,"目标路径参数":[A_Desktop,A_AppData,A_Startup,A_MyDocuments]
	,"归类规则参数":["压缩文档=7z|zip|rar|gz|xz|cab"
		,"Win程序包=msi|exe|misx|AppX"
		,"办公文档=doc|docx|xls|xlsx|ppt|pptx|wps|rtf"
		,"PDF文档=pdf"
		,"阅读文档=chm|md"
		,"图标文件=icl|ico"
		,"字体文件=ttf|otf"
		,"文本文档=txt|ini"
		,"AHK脚本=ahk"
		,"音频文件=mp3|ape|flac|m4a|wav|wma|aac|mov|ogg|"
		,"视频文件=mp4|avi|rm|rmvb|mkv|flv|3gp|m4v"
		,"图片文件=jpg|jpeg|png|bmp|gif"]}
LocalConfig:=class_EasyIni(A_ScriptDir "\Settings.ini")
;LocalConfig:=class_EasyIni(A_IsCompiled?A_Temp "\DropFilesTool\Setting.ini":A_ScriptDir "\Settings.ini")
For Section, element In DefaultParam
{
	if (objlength(element)>0){
		if !objlength(LocalConfig[Section])
			LocalConfig[Section]:=DefaultParam[Section]
	}Else{
		For key,value In element
		{
			if (LocalConfig[Section,key]="")
				LocalConfig[Section,key]:=DefaultParam[Section,key]
		}
	}
}
;=====================================参数有效性检查==================================
For Section, element In LocalConfig["目标路径参数"]
{
	if !FileExist(element)
		LocalConfig["目标路径参数"].RemoveAt(Section)
}
LocalConfig["目标路径参数"]:=objlength(LocalConfig["目标路径参数"])?LocalConfig["目标路径参数"]:DefaultParam["目标路径参数"]

For Section, element In LocalConfig["归类规则参数"]
{
	if Not element~=".+\=[^\=]+$"
		LocalConfig["归类规则参数"].RemoveAt(Section)
}
;=====================================logo参数检查==================================
if (LocalConfig["Logo参数","ImageWidth"]<>ImageWidth&&LocalConfig["Logo参数","ImageHeight"]<>ImageHeight){
	LocalConfig["Logo参数","ImageWidth"]:=ImageWidth,LocalConfig["Logo参数","ImageHeight"]:=ImageHeight
	LocalConfig["Logo参数","logosize"]:=logosize
}
if (LocalConfig["Logo参数","xpos"]<0||LocalConfig["Logo参数","xpos"]>A_ScreenWidth-ImageWidth*LocalConfig["Logo参数","logosize"]/100||LocalConfig["Logo参数","ypos"]<0||LocalConfig["Logo参数","ypos"]>A_ScreenHeight-ImageHeight*LocalConfig["Logo参数","logosize"]/100){
	LocalConfig["Logo参数","xpos"]:=DefaultParam["Logo参数","xpos"],LocalConfig["Logo参数","ypos"]:=DefaultParam["Logo参数","ypos"]
}
LocalConfig.Save(),EmptyMem()
;=======================================配置文件实时监控==========================================
/*
	监控文件 —> 1
	监控目录 —> 2
	监控属性 —> 4
	监控大小 —> 8
	监控写入时间 —> 16
	监控访问时间 —> 32
	监控创建时间 —> 64
	监控加密 —> 256
*/
WatchFolder(RegExReplace(LocalConfig.EasyIni_ReservedFor_m_sFile,"[^\\]+$"), "WatchConfigDirFunc", False, 19)
;=====================================创建托盘菜单、载入logo==================================
Gosub CreateTrayMenu
load_logo_box(ImagePath,ImageNumber,LocalConfig["Logo参数","logosize"],LocalConfig["Logo参数","xpos"],LocalConfig["Logo参数","ypos"])
;=====================================注册滚轮事件==================================
IsModifyLogoSize:= Func("IsExistLogo")
Hotkey,if, % IsModifyLogoSize
Hotkey $WheelDown, ModifyLogoDownSize
Hotkey $WheelUp, ModifyLogoUpSize
;=====================================logo坐标监控==================================
SetTimer,GetLogoClientPos,On
EmptyMem()
Return
;===============================================================================
;===============================================================================
;===============================================================================

;计算图片初始化显示比例
GetLogoInitialScale(ImagePath,ByRef Width,ByRef Height){
	pToken := Gdip_Startup()
	if pBitmap := Gdip_CreateBitmapFromFile(ImagePath){
		Width:=Gdip_GetImageWidth(pBitmap),Height:=Gdip_GetImageHeight(pBitmap)
		MaxSize:=Max(Width,Height),Gdip_DisposeImage(pBitmap)
		if (MaxSize>=1000&&MaxSize<=2000){
			Return 20
		}Else if (MaxSize>=200&&MaxSize<1000){
			Return 50
		}Else if (MaxSize>0&&MaxSize<200){
			Return 100
		}Else if (MaxSize>2000){
			Return 10
		}Else
			Return 50
	}Else Return 50
}

;拖拽事件
logoGuiDropFiles:
	if A_EventInfo&&A_GuiEvent {
		AllFileList:=A_GuiEvent
		Gosub CreateLogoMenu
	}Else
		TrayTip,Error,GuiDropFiles事件无法执行!,,3
Return

;处理拖拽事件
HandlingFilelabels:
	if !FileExist(ThisFolderItem)&&ThisFolderItem
		FileCreateDir,%ThisFolderItem%
	if FileExist(ThisFolderItem){
		if (AllFileList<>""){
			DropCount:=""
			Loop, Parse, AllFileList, `n
			{
				loopfilepath:=A_LoopField,DestPattern:=""
				SplitPath, loopfilepath, filename, filedir, file_ext, name_no_ext, drive
				if InStr(LocalConfig["Logo参数","mode"],"cut"){
					if LocalConfig["Logo参数","AutoClassified"]{
						if (file_ext<>""&&name_no_ext<>"") {
							Loop,% objlength(LocalConfig["归类规则参数"])
							{
								LocalConfig["归类规则参数",A_Index]:=InStr(LocalConfig["归类规则参数",A_Index],"=")?LocalConfig["归类规则参数",A_Index]:"其它文件=" LocalConfig["归类规则参数",A_Index]
								tarr:=strsplit(LocalConfig["归类规则参数",A_Index],"=")
								DestPattern:=Trim(ThisFolderItem,"\") "\" name_no_ext "." file_ext
								if InStr("|" Trim(tarr[2],"|") "|",file_ext "|")&&tarr[2]{
									if !FileExist(Trim(ThisFolderItem,"\") "\" tarr[1] "\")
										FileCreateDir,% Trim(ThisFolderItem,"\") "\" tarr[1] "\"
									DestPattern:=Trim(ThisFolderItem,"\") "\" tarr[1] "\" name_no_ext "." file_ext
									FileMove, %loopfilepath%, %DestPattern%, 1
								}
							}
							if !FileExist(DestPattern){
								FileMove, %loopfilepath%, %DestPattern%, 1
							}
							DropCount.="[文件]" filename (InStr(LocalConfig["Logo参数","mode"],"cut")?"-移动完成!":"-复制完成!") "`n"
						}Else if (file_ext=""&&name_no_ext<>"") {
							Loop Files, %loopfilepath%\*.*, R
							{
								DestPattern:=""
								For key,value In LocalConfig["归类规则参数"]
								{
									LocalConfig["归类规则参数",key]:=InStr(LocalConfig["归类规则参数",key],"=")?LocalConfig["归类规则参数",key]:"其它文件=" LocalConfig["归类规则参数",key]
									tarr:=strsplit(LocalConfig["归类规则参数",key],"=")
									DestPattern:=Trim(ThisFolderItem,"\") "\" A_LoopFileName
									if InStr("|" Trim(tarr[2],"|") "|",A_LoopFileExt "|")&&tarr[2]{
										if !FileExist(Trim(ThisFolderItem,"\") "\" tarr[1] "\")
											FileCreateDir,% Trim(ThisFolderItem,"\") "\" tarr[1] "\"
										DestPattern:=Trim(ThisFolderItem,"\") "\" tarr[1] "\" A_LoopFileName
										FileMove, %A_LoopFileLongPath%, %DestPattern%, 1
										Break
									}
								}
								if !FileExist(DestPattern){
									FileMove, %A_LoopFileLongPath%, %DestPattern%, 1
								}
								DropCount.="[文件]" A_LoopFileName (InStr(LocalConfig["Logo参数","mode"],"cut")?"-移动完成!":"-复制完成!") "`n"
							}
						}Else{
							TrayTip,Error,目标路径不规范!,,3
						}
					}Else{
						if (file_ext<>""&&name_no_ext<>"") {
							DestPattern:=Trim(ThisFolderItem,"\") "\" name_no_ext "." file_ext
							FileMove, %loopfilepath%, %DestPattern%, 1
							DropCount.="[文件]" filename (InStr(LocalConfig["Logo参数","mode"],"cut")?"-移动完成!":"-复制完成!") "`n"
						}Else if (file_ext=""&&name_no_ext<>"") {
							if !FileExist(Trim(ThisFolderItem,"\") "\" name_no_ext)
								FileCreateDir,% Trim(ThisFolderItem,"\") "\" name_no_ext
							DestPattern:=Trim(ThisFolderItem,"\") "\" name_no_ext "\"
							FileMoveDir,%loopfilepath%, %DestPattern%,1
							DropCount.="[目录]" filename (InStr(LocalConfig["Logo参数","mode"],"cut")?"-移动完成!":"-复制完成!") "`n"
						}Else{
							TrayTip,Error,目标路径不规范!,,3
						}
					}
				}Else{
					if LocalConfig["Logo参数","AutoClassified"]{
						if (file_ext<>""&&name_no_ext<>"") {
							Loop,% objlength(LocalConfig["归类规则参数"])
							{
								LocalConfig["归类规则参数",A_Index]:=InStr(LocalConfig["归类规则参数",A_Index],"=")?LocalConfig["归类规则参数",A_Index]:"其它文件=" LocalConfig["归类规则参数",A_Index]
								tarr:=strsplit(LocalConfig["归类规则参数",A_Index],"=")
								DestPattern:=Trim(ThisFolderItem,"\") "\" name_no_ext "." file_ext
								if InStr("|" Trim(tarr[2],"|") "|",file_ext "|")&&tarr[2]{
									if !FileExist(Trim(ThisFolderItem,"\") "\" tarr[1] "\")
										FileCreateDir,% Trim(ThisFolderItem,"\") "\" tarr[1] "\"
									DestPattern:=Trim(ThisFolderItem,"\") "\" tarr[1] "\" name_no_ext "." file_ext
									FileCopy, %loopfilepath%, %DestPattern%, 1
									Break
								}
							}
							if !FileExist(DestPattern){
								FileCopy, %loopfilepath%, %DestPattern%, 1
							}
							DropCount.="[文件]" filename (InStr(LocalConfig["Logo参数","mode"],"cut")?"-移动完成!":"-复制完成!") "`n"
						}Else if (file_ext=""&&name_no_ext<>"") {
							Loop Files, %loopfilepath%\*.*, R
							{
								DestPattern:=""
								For key,value In LocalConfig["归类规则参数"]
								{
									LocalConfig["归类规则参数",key]:=InStr(LocalConfig["归类规则参数",key],"=")?LocalConfig["归类规则参数",key]:"其它文件=" LocalConfig["归类规则参数",key]
									tarr:=strsplit(LocalConfig["归类规则参数",key],"=")
									DestPattern:=Trim(ThisFolderItem,"\") "\" A_LoopFileName
									if InStr("|" Trim(tarr[2],"|") "|",A_LoopFileExt "|")&&tarr[2]{
										if !FileExist(Trim(ThisFolderItem,"\") "\" tarr[1] "\")
											FileCreateDir,% Trim(ThisFolderItem,"\") "\" tarr[1] "\"
										DestPattern:=Trim(ThisFolderItem,"\") "\" tarr[1] "\" A_LoopFileName
										FileCopy, %A_LoopFileLongPath%, %DestPattern%, 1
										Break
									}
								}
								if !FileExist(DestPattern){
									FileCopy, %A_LoopFileLongPath%, %DestPattern%, 1
								}
								DropCount.="[文件]" A_LoopFileName (InStr(LocalConfig["Logo参数","mode"],"cut")?"-移动完成!":"-复制完成!") "`n"
							}
						}Else{
							TrayTip,Error,目标路径不规范!,,3
						}
					}Else{
						if (file_ext<>""&&name_no_ext<>"") {
							DestPattern:=Trim(ThisFolderItem,"\") "\" name_no_ext "." file_ext
							FileCopy, %loopfilepath%, %DestPattern%, 1
							DropCount.="[文件]" filename (InStr(LocalConfig["Logo参数","mode"],"cut")?"-移动完成!":"-复制完成!") "`n"
						}Else if (file_ext=""&&name_no_ext<>"") {
							if !FileExist(Trim(ThisFolderItem,"\") "\" name_no_ext)
								FileCreateDir,% Trim(ThisFolderItem,"\") "\" name_no_ext
							DestPattern:=Trim(ThisFolderItem,"\") "\" name_no_ext "\"
							FileCopyDir,%loopfilepath%, %DestPattern%,1
							DropCount.="[目录]" filename (InStr(LocalConfig["Logo参数","mode"],"cut")?"-移动完成!":"-复制完成!") "`n"
						}Else{
							TrayTip,Error,目标路径不规范!,,3
						}
					}
				}
			}
			if (DropCount<>"")
				StrReplace(DropCount,"`n","`n",tCount)
				if tCount>20
					DropCount:=RegExReplace(DropCount,"(([^\r\n]+[`r`n]+){8})(([^\r\n]+[`r`n]+){1,})","$1······`r`n此处省略" tCount-8 "行......")
				ToolTipBox.ToolTip(Trim(DropCount,"`r`n"),,,5,True)
		}Else{
			TrayTip,Error,GuiDropFiles事件错误!,,3
		}
	}Else
		TrayTip,Error,目标路径不存在!,,3
	ThisFolderItem:="",AllFileList:="",EmptyMem()
Return

;创建右键菜单
CreateLogoMenu:
	ThisFolderItem:=""
	if MenuGetHandle("logo"){
		Menu, logo, DeleteAll
		Menu, logo, Delete
	}
	Menu, logo, NoStandard
	Menu, logo, UseErrorLevel
	if MenuGetHandle("OptionMode"){
		Menu, OptionMode, DeleteAll
		Menu, OptionMode, Delete
	}
	Menu, OptionMode, NoStandard
	Menu, OptionMode, UseErrorLevel
	Menu, OptionMode,Add, 复制模式,MenuItemLabel
	Menu, OptionMode,Add, 
	Menu, OptionMode,Add, 移动模式,MenuItemLabel
	if InStr(LocalConfig["Logo参数","mode"],"cut")
		Menu, OptionMode,Check, 移动模式
	Else
		Menu, OptionMode,Check, 复制模式
	Menu, logo,Add, 规则配置,MenuItemLabel
	Menu, logo,Add,
	if (AllFileList<>""){
		Menu, logo,Disable, 规则配置
	}
	Menu, logo,Add, 操作方式,:OptionMode
	Menu, logo,Add, 
	Menu, logo,Add, 按规则自动归类,MenuItemLabel
	if LocalConfig["Logo参数","AutoClassified"]
		Menu, logo,Check, 按规则自动归类
	if (AllFileList<>""){
		MenuItemList:=""
		if !objlength(LocalConfig["目标路径参数"]){
			LocalConfig["目标路径参数"]:=[],LocalConfig["目标路径参数",1]:=A_ScriptDir
			MenuItem:=InStr(LocalConfig["Logo参数","mode"],"cut")?"移动到" A_ScriptDir:"复制到" A_ScriptDir
			Menu, logo,Add
			Menu, logo,Add, %MenuItem%,MenuItemLabel
		}Else{
			IsExistFolder:=False
			For each,item In LocalConfig["目标路径参数"]
			{
				MenuItem:=InStr(LocalConfig["Logo参数","mode"],"cut")?"移动到" item:"复制到" item
				if FileExist(item)&&!InStr("`n" MenuItemList,"`n" MenuItem "`n"){
					Menu, logo,Add
					Menu, logo,Add, %MenuItem%,MenuItemLabel
					IsExistFolder:=True
				}
				MenuItemList.=InStr(LocalConfig["Logo参数","mode"],"cut")?"移动到" item "`n":"复制到" item "`n"
			}
			if !IsExistFolder {
				LocalConfig["目标路径参数"]:=[],LocalConfig["目标路径参数",1]:=A_ScriptDir
				MenuItem:=InStr(LocalConfig["Logo参数","mode"],"cut")?"移动到" A_ScriptDir:"复制到" A_ScriptDir
				Menu, logo,Add
				Menu, logo,Add, %MenuItem%,MenuItemLabel
			}
		}
	}Else{
		MenuItemList:=""
		if MenuGetHandle("folder"){
			Menu, folder, DeleteAll
			Menu, folder, Delete
		}
		if !objlength(LocalConfig["目标路径参数"]){
			LocalConfig["目标路径参数"]:=[],LocalConfig["目标路径参数",1]:=A_ScriptDir
			Menu, folder,Add, %A_ScriptDir%,MenuItemLabel
		}Else{
			IsExistFolder:=False,LoopCount:=0
			For each,item In LocalConfig["目标路径参数"]
			{
				if FileExist(item)&&!InStr("`n" MenuItemList,"`n" item "`n"){
					LoopCount++
					if (LoopCount>1)
						Menu, folder,Add
					Menu, folder,Add, %item%,MenuItemLabel
					IsExistFolder:=True
				}
				MenuItemList.=item "`n"
			}
			if !IsExistFolder {
				LocalConfig["目标路径参数"]:=[],LocalConfig["目标路径参数",1]:=A_ScriptDir
				Menu, folder,Add, %A_ScriptDir%,MenuItemLabel
			}
		}
		Menu, logo,Add, 
		Menu, logo,Add, 打开目录,:folder
		Menu, logo,Add, 
		Menu, logo,Add, 重载程序,MenuItemLabel
		Menu, logo,Add, 
		Menu, logo,Add, 退出程序,MenuItemLabel
	}
	Menu, logo,Show
	save_local_config()
Return

;创建托盘菜单
CreateTrayMenu:
	ThisFolderItem:="",AllFileList:=""
	if MenuGetHandle("Tray"){
		Menu, Tray, DeleteAll
	}
	Menu, TRAY, NoStandard
	Menu, Tray, UseErrorLevel
	Menu, Tray,Add, 规则配置,MenuItemLabel
	Menu, Tray,Add,
	if MenuGetHandle("Option"){
		Menu, Option, DeleteAll
		;Menu, Option, Delete
	}
	Menu, Option, UseErrorLevel
	Menu, Option,Add, 复制模式,MenuItemLabel
	Menu, Option,Add, 
	Menu, Option,Add, 移动模式,MenuItemLabel
	if InStr(LocalConfig["Logo参数","mode"],"cut")
		Menu, Option,Check, 移动模式
	Else
		Menu, Option,Check, 复制模式
	Menu, Tray,Add, 操作方式,:Option
	Menu, Tray,Add, 
	Menu, Tray,Add, 自动归类,MenuItemLabel
	if LocalConfig["Logo参数","AutoClassified"]
		Menu, Tray,Check, 自动归类
	Menu, Tray,Add, 
	Menu, Tray,Add, 重载程序,MenuItemLabel
	Menu, Tray,Add, 
	Menu, Tray,Add, 退出程序,MenuItemLabel
	if !A_IsCompiled {
		Menu, Tray,Icon, %A_ScriptDir%\Icon\tools.ico
	}
	Menu, Tray,Tip,DropIt文件归类-%ToolVersion%`n - logo定义:程序同目录下存在logo.png时自动调用
Return

;菜单项选择处理
MenuItemLabel:
	Switch A_ThisMenuItem
	{
		Case "规则配置":
			Gosub DrawRulesGui
		Case "复制模式":
			LocalConfig["Logo参数","mode"]:="copy",save_local_config()
		Case "移动模式":
			LocalConfig["Logo参数","mode"]:="cut",save_local_config()
		Case "按规则自动归类","自动归类":
			LocalConfig["Logo参数","AutoClassified"]:=!LocalConfig["Logo参数","AutoClassified"],save_local_config()
		Case "重载程序":
			Reload
		Case "退出程序":
			ExitApp
		Default:
			if A_ThisMenuItem~="^(移动到|复制到)"&&(A_ThisMenu<>"Tray") {
				ThisFolderItem:=RegExReplace(A_ThisMenuItem,"^(移动到|复制到)")
				Gosub HandlingFilelabels
			}Else if A_ThisMenuItem~="^[a-zA-Z]:(((\\(?! )[^/:*?<>\""|\\]+)+\\?)|(\\)?)\s*$"&&(A_ThisMenu<>"Tray"){
				if !FileExist(A_ThisMenuItem)
					FileCreateDir,%A_ThisMenuItem%
				OpenAndSelect(Trim(A_ThisMenuItem,"\") "\")
			}
	}
	Gosub CreateTrayMenu
Return

;绘制「规则配置」窗口
DrawRulesGui:
	GetRulesObject(LocalConfig["归类规则参数"],RulesName,Ruleslist)
	Gui,Rules:Destroy
	Gui,Rules:Default
	Gui,Rules:+HWNDhDropRules
	Gui,Rules:Font,s10
	Gui,Rules:Add,Tab3,vtabox w300,自定义规则|自定义路径
	Gui,Rules:Tab,1
	Gui,Rules:Add,ListBox,h200 Choose1 gGuiControl_Rules vChoiceRulesName HWNDhRulesName Section,% Trim(RulesName,"|")
	Gui,Rules:Add,ListBox,x+15 ys h200 w80 gGuiControl_Rules vShowRulesList HWNDhRulesList ,% Trim(Ruleslist[strsplit(RulesName,"|")[1]],"|")
	GuiControlGet,crnpos,Rules:Pos,ChoiceRulesName
	GuiControlGet,srlpos,Rules:Pos,ShowRulesList
	GuiControl,Rules:Move,tabox,% "w" srlposX+srlposW+5
	Gui,Rules:Tab,2
	Gui,Rules:Add,ListView,h200 gGuiControl_Rules vLVClickEvent AltSubmit Grid -LV0x10 -Multi NoSortHdr -WantF2 0x8 LV0x40 LV0x800 LV0x80 HwndLVClick,目标路径
	Loop,% objlength(LocalConfig["目标路径参数"])
	{
		if FileExist(LocalConfig["目标路径参数",A_Index])
			LV_Add("",LocalConfig["目标路径参数",A_Index]),LV_ModifyCol()
		Else
			LocalConfig["目标路径参数"].RemoveAt(A_Index)
	}
	Gui,Rules:Show,AutoSize,% (A_IsAdmin?"[管理员]":"") "规则配置窗口"
Return

GuiControl_Rules:
	Gui,Rules:Submit,NoHide
	Switch A_GuiControl
	{
		Case "ChoiceRulesName":
			GuiControl,Rules:,ShowRulesList,% "|" Trim(Ruleslist[%A_GuiControl%],"|")
		Case "ShowRulesList":
			
		Case "LVClickEvent":

	}
Return

RulesGuiClose:
	Gui,Rules:Destroy
	ThisFolderItem:="",AllFileList:=""
	,save_local_config(),EmptyMem()
Return

RulesGuiContextMenu(GuiHwnd, CtrlHwnd, EventInfo, IsRightClick, X, Y){
	Global ControlName,LocalConfig,RulesName,Ruleslist,hRulesName,hRulesList
	if (IsRightClick&&A_GuiControl){
		ControlName:=A_GuiControl
		Gui,Rules:Default
		LV_GetText(folder,EventInfo,1)
		if MenuGetHandle("Status")
			Menu,Status,Deleteall
		Menu,Status,Add,刷新,ReloadExtItem
		Menu,Status,Add,
		Menu,Status,Add,新增,AddExtItem
		Menu,Status,Add,
		Menu,Status,Add,删除,RemoveExtItem
		Menu,Status,Add,
		Menu,Status,Add,清空,DeleteallExtItem
		if (!LV_GetNext()&&ControlName="LVClickEvent"){
			Menu,Status,Disable,删除
			Menu,Status,Disable,清空
		}
		Menu,Status,Show
		Return
	}

	AddExtItem:
		Gui,Rules:Default
		Switch ControlName
		{
			Case "LVClickEvent":
				Gui +OwnDialogs
				FileSelectFolder, SelectFolderVar,, 3,请选择一个自定义目录
				if (SelectFolderVar<>""){
					LocalConfig["目标路径参数",objlength(LocalConfig["目标路径参数"])+1]:=SelectFolderVar,save_local_config()
					LV_Add("",SelectFolderVar),LV_ModifyCol()
				}
			Case "ChoiceRulesName":
				if NewRulesName:=MiniInputBox("分类目录名称添加窗口","格式:办公文档 或 办公文档=doc|docx|xls|xlsx|ppt|pptx|wps",1,400,"Rules"){
					if InStr(NewRulesName,"="){
						if RegExMatch(NewRulesName,"O)(.+)\=([^\=]+$)",match){
							if (Match.Value(1)<>""){
								VarSetCapacity(String,128),StrPut(Trim(Match.Value(1)), &String, "utf-16")
								DllCall("User32\SendMessage", "Ptr", hRulesName, "UInt", LB_ADDSTRING := 0x0180, "Ptr", 0, "Ptr", &String)+1
								Ruleslist[Trim(Match.Value(1))]:=Ruleslist[Trim(Match.Value(1))]?Ruleslist[Trim(Match.Value(1))]:""
							}
							if (Match.Value(2)<>""){
								Count:= DllCall("User32.dll\SendMessage", "Ptr", hRulesName, "UInt", LB_GETCOUNT := 0x018B, "Ptr", 0, "Ptr", 0, "Ptr")
								GuiControl,Rules:Choose,ChoiceRulesName,% Count
								GuiControl,Rules:,ShowRulesList,% "|" Trim(RegExReplace(Match.Value(2),"[\s\t\r\n]"),"|")
								Ruleslist[Trim(Match.Value(1))]:=Trim(RegExReplace(Match.Value(2),"[\s\t\r\n]"),"|")
								LocalConfig["归类规则参数"]:=SetRulesObject(Ruleslist),save_local_config()
							}
						}
					}Else{
						VarSetCapacity(String,128),StrPut(NewRulesName, &String, "utf-16")
						DllCall("User32\SendMessage", "Ptr", hRulesName, "UInt", LB_ADDSTRING := 0x0180, "Ptr", 0, "Ptr", &String)+1
						Ruleslist[Trim(NewRulesName)]:=Ruleslist[Trim(NewRulesName)]?Ruleslist[Trim(NewRulesName)]:""
					}
				}
			Case "ShowRulesList":
				if NewRulesList:=MiniInputBox("文件后缀名添加窗口","格式:doc|docx|xls|xlsx|ppt|pptx|wps",1,400,"Rules"){
					;VarSetCapacity(String,128),StrPut(NewRulesList, &String, "utf-16")
					;DllCall("User32\SendMessage", "Ptr", hRulesList, "UInt", LB_ADDSTRING := 0x0180, "Ptr", 0, "Ptr", &String)+1
					GuiControl,Rules:,ShowRulesList,% Trim(RegExReplace(NewRulesList,"[\s\t\r\n]"),"|")
					allRulesList:=CListBox.GetAllItem(hRulesList,"|")
					GuiControlGet, ChoiceRulesName ,, ChoiceRulesName, ListBox
					if ChoiceRulesName&&allRulesList {
						Ruleslist[ChoiceRulesName]:=Trim(allRulesList,"|")
						LocalConfig["归类规则参数"]:=SetRulesObject(Ruleslist),save_local_config()
					}
					
				}
		} 
	Return

	RemoveExtItem:
		Gui,Rules:Default
		Switch ControlName
		{
			Case "LVClickEvent":
				if EventInfo {
					LV_Delete(EventInfo),LocalConfig["目标路径参数"]:=[]
					Loop,% LV_GetCount()
					{
						LV_GetText(OutputVar, A_Index)
						if FileExist(OutputVar)
							LocalConfig["目标路径参数",objlength(LocalConfig["目标路径参数"])+1]:=OutputVar

					}
					save_local_config()
				}
			Case "ChoiceRulesName":
				GuiControlGet, ChoiceRulesName ,, ChoiceRulesName, ListBox
				if (ChoiceRulesName<>""){
					VarSetCapacity(String,128),StrPut(ChoiceRulesName, &String, "utf-16")
					Index:= DllCall("User32\SendMessage", "Ptr", hRulesName, "UInt", LB_FINDSTRINGEXACT := 0x01A2, "UInt", -1, "Ptr", &String)+1
					DllCall("User32\SendMessage", "Ptr", hRulesName, "UInt", LB_DELETESTRING := 0x0182, "UInt", Index-1, "Ptr", 0, "Ptr")
					Ruleslist.Delete(ChoiceRulesName),LocalConfig["归类规则参数"]:=SetRulesObject(Ruleslist),save_local_config()
					DllCall("User32\SendMessage", "Ptr", hRulesList, "UInt", LB_RESETCONTENT := 0x0184, "Ptr", 0, "Ptr", 0, "Ptr")
				}
			Case "ShowRulesList":
				GuiControlGet, ShowRulesList ,, ShowRulesList, ListBox
				if (ShowRulesList<>""){
					GuiControlGet, ChoiceRulesName ,, ChoiceRulesName, ListBox
					VarSetCapacity(String,128),StrPut(ShowRulesList, &String, "utf-16")
					Index:= DllCall("User32\SendMessage", "Ptr", hRulesList, "UInt", LB_FINDSTRINGEXACT := 0x01A2, "UInt", -1, "Ptr", &String)+1
					DllCall("User32\SendMessage", "Ptr", hRulesList, "UInt", LB_DELETESTRING := 0x0182, "UInt", Index-1, "Ptr", 0, "Ptr")
					ControlGet, OutputVar, List , Count, , ahk_id%hRulesList%
					if OutputVar:=Trim(OutputVar) {
						Ruleslist[ChoiceRulesName]:=StrReplace(OutputVar,"`n","|")
						LocalConfig["归类规则参数"]:=SetRulesObject(Ruleslist),save_local_config()
					}
				}
		} 
	Return

	DeleteallExtItem:
		Gui,Rules:Default
		Switch ControlName
		{
			Case "LVClickEvent":
				LocalConfig["目标路径参数"]:=[],save_local_config()
				LV_Delete()
			Case "ChoiceRulesName":
				DllCall("User32\SendMessage", "Ptr", hRulesName, "UInt", LB_RESETCONTENT := 0x0184, "Ptr", 0, "Ptr", 0, "Ptr")
				Ruleslist:={},LocalConfig["归类规则参数"]:=[],save_local_config()
			Case "ShowRulesList":
				GuiControlGet, ChoiceRulesName ,, ChoiceRulesName, ListBox
				DllCall("User32\SendMessage", "Ptr", hRulesList, "UInt", LB_RESETCONTENT := 0x0184, "Ptr", 0, "Ptr", 0, "Ptr")
				Ruleslist[ChoiceRulesName]:="",LocalConfig["归类规则参数"]:=SetRulesObject(Ruleslist),save_local_config()
		} 
	Return

	ReloadExtItem:
		reload_local_config()
		Gui,Rules:Default
		Switch ControlName
		{
			Case "LVClickEvent":
				LV_Delete()
				Loop,% objlength(LocalConfig["目标路径参数"])
				{
					if FileExist(LocalConfig["目标路径参数",A_Index])
						LV_Add("",LocalConfig["目标路径参数",A_Index]),LV_ModifyCol()
					Else
						LocalConfig["目标路径参数"].RemoveAt(A_Index)
				}
			Case "ChoiceRulesName":
				GetRulesObject(LocalConfig["归类规则参数"],RulesName,Ruleslist)
				GuiControl,Rules:,ChoiceRulesName,% "|" Trim(RulesName,"|")
				GuiControl,Rules:Choose,ChoiceRulesName,1
				GuiControl,Rules:,ShowRulesList,% "|" Trim(Ruleslist[strsplit(RulesName,"|")[1]],"|")
			Case "ShowRulesList":
				GuiControlGet, ChoiceRulesName ,, ChoiceRulesName, ListBox
				GetRulesObject(LocalConfig["归类规则参数"],RulesName,Ruleslist)
				GuiControl,Rules:,ShowRulesList,% "|" Trim(Ruleslist[strsplit(ChoiceRulesName,"|")[1]],"|")
				GuiControl,Rules:Choose,ShowRulesList,1
		} 
	Return
}

SetRulesObject(Array){
	tarr:=[]
	For each,item In Array
	{
		if (Trim(item)<>"")&&(Trim(each)<>""){
			tarr.push(Trim(each) "=" Trim(item,"|"))
		}
	}

	Return tarr
}

OpenAndSelect(sFullPath){
	SplitPath sFullPath, , sPath, ext, name_no_ext
	FolderPidl := DllCall("shell32\ILCreateFromPath", "Str", sPath)
	DllCall("shell32\SHParseDisplayName", "str", sFullPath, "Ptr", 0, "Ptr*", ItemPidl := 0, "Uint", 0, "Uint*", 0)
	DllCall("shell32\SHOpenFolderAndSelectItems", "Ptr", FolderPidl, "UInt", 1, "Ptr*", ItemPidl, "Int", 0)
	CoTaskMemFree(FolderPidl)
	if name_no_ext
		CoTaskMemFree(ItemPidl)
}

CoTaskMemFree(pv) {
	Return DllCall("ole32\CoTaskMemFree", "Ptr", pv)
}

MiniInputBox(title,PROMPT:="",row:=1,Width:=200,OwnerGuiNum:=""){
	Static IsSubmitText,hIBox
	IsSubmitText:=False
	Gui,InputBox:Destroy
	if OwnerGuiNum
		Gui,InputBox:+Owner%OwnerGuiNum% -MinimizeBox +HWNDhIBox
	Else
		Gui,InputBox:+AlwaysOnTop +HWNDhIBox
	Gui,InputBox:Font,s10
	Gui,InputBox:Add,Edit,r%row% w%Width% HWNDhedit,
	if (row=1&&PROMPT)
		DllCall("user32\SendMessage", "ptr", hedit, "uint", EM_SETCUEBANNER := 0x1501, "int", True, "str", PROMPT, "int")
	Gui,InputBox:Add,Button,% (row=1?"x+5 yp":"xp y+8") " gGuiControl_Mini",% row=1?"提交":"提交结果"
	Gui,InputBox:Show,AutoSize,%title%
	While !IsSubmitText
	{
		if (WinActive("A")<>hIBox&&!OwnerGuiNum)
			WinActivate,ahk_id%hIBox%
	}
	Gui,InputBox:Submit,NoHide
	ControlGetText, OutputVar , Edit1, ahk_id%hIBox%
	Gui,InputBox:Destroy
	Return Trim(OutputVar)

	GuiControl_Mini:
		IsSubmitText:=True
	Return

	InputBoxGuiClose:
		IsSubmitText:=False
		Gui,InputBox:Destroy
	Return
}

LV_GetClickColumNum(HLV) {
	Static LVM_SUBITEMHITTEST := 0x1039
	VarSetCapacity(POINT, 8, 0)
	DllCall("User32.dll\GetCursorPos", "Ptr", &POINT)
	DllCall("User32.dll\ScreenToClient", "Ptr", HLV, "Ptr", &POINT)
	VarSetCapacity(LVHITTESTINFO, 24, 0)
	NumPut(NumGet(POINT, 0, "Int"), LVHITTESTINFO, 0, "Int")
	NumPut(NumGet(POINT, 4, "Int"), LVHITTESTINFO, 4, "Int")
	SendMessage, LVM_SUBITEMHITTEST, 0, &LVHITTESTINFO, , ahk_id %HLV%
	If (ErrorLevel = -1)
		Return False

	Return NumGet(LVHITTESTINFO, 16, "Int") + 1
}

GetRulesObject(obj,ByRef NameList,ByRef Ruleslist){
	Ruleslist:={},NameList:=""
	Loop,% objlength(obj)
	{
		if (objlength(tarr:=strsplit(obj[A_Index],"="))>1){
			NameList.=tarr[1] "|",Ruleslist[tarr[1]]:=Trim(tarr[2],"|")
		}
	}

	Return Ruleslist
}

;实时监控logo坐标位置
GetLogoClientPos:
	;监控坐标同步记录
	if WinExist("ahk_id " hlogo){
		VarSetCapacity( size, 16, 0 )
		DllCall( "GetClientRect", "Ptr", hlogo, "Ptr", &size )
		DllCall( "ClientToScreen", "Ptr", hlogo, "Ptr", &size )
		LocalConfig["Logo参数","xpos"] := NumGet( size, 0, "Int")
		, LocalConfig["Logo参数","ypos"] := NumGet( size, 4, "Int")
	}
	;15秒内键鼠无操作自动保存坐标到本地配置
	if (Mod(A_TimeIdlePhysical,15000)<1000&&A_TimeIdlePhysical>1000){
		save_local_config()
	}
Return

ModifyLogoDownSize:
	LocalConfig["Logo参数","logosize"]--
	load_logo_box(ImagePath,ImageNumber,LocalConfig["Logo参数","logosize"],LocalConfig["Logo参数","xpos"],LocalConfig["Logo参数","ypos"])
	save_local_config()
Return

ModifyLogoUpSize:
	LocalConfig["Logo参数","logosize"]++
	load_logo_box(ImagePath,ImageNumber,LocalConfig["Logo参数","logosize"],LocalConfig["Logo参数","xpos"],LocalConfig["Logo参数","ypos"])
	save_local_config()
Return

WatchConfigDirFunc(Folder, Changes){
	/*
		Change.Name
		Change.Action
		1—>"新增"
		2—>"移除"
		3—>"修改"
		4—>"重命名"
	*/
	Global LocalConfig
	For Each, Change In Changes
	{
		if Change.Action&&FileExist(Folder) {  ;&&!A_IsSuspended
			if (Change.Name=LocalConfig.EasyIni_ReservedFor_m_sFile){
				if (Change.Action=2||Change.Action=4)
					save_local_config()
				Else
					reload_local_config()

			}
		}
	}
}

save_local_config(){
	Global LocalConfig
	WatchFolder(RegExReplace(LocalConfig.EasyIni_ReservedFor_m_sFile,"[^\\]+$"), "**DEL")
	LocalConfig.Save()
	WatchFolder(RegExReplace(LocalConfig.EasyIni_ReservedFor_m_sFile,"[^\\]+$"), "WatchConfigDirFunc", False, 19)
}

reload_local_config(){
	Global LocalConfig
	WatchFolder(RegExReplace(LocalConfig.EasyIni_ReservedFor_m_sFile,"[^\\]+$"), "**DEL")
	if FileExist(LocalConfig.EasyIni_ReservedFor_m_sFile){
		try TempConfig:=LocalConfig.Reload()
		LocalConfig:=TempConfig
	}Else
		LocalConfig.Save()
	WatchFolder(RegExReplace(LocalConfig.EasyIni_ReservedFor_m_sFile,"[^\\]+$"), "WatchConfigDirFunc", False, 19)
}

RunAsAdmin(){
	full_command_line := DllCall("GetCommandLine", "str")
	if not (A_IsAdmin or RegExMatch(full_command_line, " /restart(?!\S)")) {
		try {
			if A_IsCompiled {
				Run *RunAs "%A_ScriptFullPath%" /restart
			}else{
				if FileExist(AhkUPath:=RegExReplace(A_AhkPath,"i)(\.exe)$","_UIA$1"))&&!InStr(A_AhkPath,"_UIA.exe")&&InStr(AhkUPath,"_UIA"){
					Run *RunAs "%AhkUPath%" /restart "%A_ScriptFullPath%"
				}Else if FileExist(AhkUPath:=RegExReplace(A_AhkPath,"i)(U" A_PtrSize*8 ")(\.exe)$","$1_UIA$2"))&&!InStr(A_AhkPath,"U" A_PtrSize*8 "_UIA.exe")&&InStr(A_AhkPath,"U" A_PtrSize*8 ".exe")&&InStr(AhkUPath,"_UIA"){
					Run *RunAs "%AhkUPath%" /restart "%A_ScriptFullPath%"
				}Else if FileExist(AhkUPath:=RegExReplace(A_AhkPath,"i)(\.exe)$","U" A_PtrSize*8 "_UIA$1"))&&!InStr(A_AhkPath,"_UIA.exe")&&!InStr(A_AhkPath,"U" A_PtrSize*8 ".exe")&&InStr(AhkUPath,"_UIA"){
					Run *RunAs "%AhkUPath%" /restart "%A_ScriptFullPath%"
				}Else
					Run *RunAs "%A_AhkPath%" /restart "%A_ScriptFullPath%"
			}
		}Catch e{
			MsgBox, 262160,Error,% e.Extra?e.Extra:"以管理员身份运行失败!",15
			ExitApp
		}
	}
}

IsExistLogo(){
	Global hlogo
	CoordMode,Mouse,Screen
	MouseGetPos,,,MID

	Return (MID&&MID=hlogo?True:False)
}

load_logo_box(ImagePath,Number:=1,logosize:=50,xpos:=100,ypos:=100,logoAlpha:=255){
	Global hlogo
	pToken := Gdip_Startup()
	pBitmap := Gdip_CreateBitmapFromFile(ImagePath,Number)
	if !pBitmap
		Return
	Gui, logo: -Caption +E0x80000 +LastFound +AlwaysOnTop +ToolWindow +OwnDialogs +Hwndhlogo
	Gui, logo: Show, NA
	Ratio:=(logo_Width:=Gdip_GetImageWidth(pBitmap))/(logo_Height:=Gdip_GetImageHeight(pBitmap))
	, DisplayWidth:=Round(logo_Width*logosize/100), DisplayHeight:=DisplayWidth//Ratio
	pBitmap:=Gdip_ResizeBitmap(pBitmap, DisplayWidth, DisplayHeight, 0)
	hbm := CreateDIBSection(DisplayWidth, DisplayHeight),hdc := CreateCompatibleDC()
	obm := SelectObject(hdc, hbm),G := Gdip_GraphicsFromHDC(hdc)
	Gdip_SetInterpolationMode(G, 7),Gdip_DrawImageFast(G, pBitmap, 0, 0)
	UpdateLayeredWindow(hlogo, hdc,xpos , ypos, DisplayWidth, DisplayHeight,logoAlpha>0&&logoAlpha<=255?logoAlpha:255)
	SelectObject(hdc, obh), DeleteObject(hbm), DeleteDC(hdc),Gdip_DeleteGraphics(G),Gdip_DisposeImage(pBitmap)
	OnMessage(0x20, Func("WM_SETCURSOR").Bind(hlogo))

}

logoGuiContextMenu(GuiHwnd, CtrlHwnd, EventInfo, IsRightClick, X, Y){
	Global AllFileList
	if (IsRightClick){
		AllFileList:=""
		Gosub CreateLogoMenu
	}
}


WM_LBUTTONDOWN(wParam, lParam, uMsg, hWnd){
	if (A_Gui="logo"&&HWND)
		DllCall("user32.dll\PostMessage", "ptr", hWnd, "uint", 0x00A1, "ptr", 2, "ptr", 0)
	EmptyMem()
}

WM_MOUSEMOVE( p_w, p_l, p_m, p_hw){
	Global hlogo,hTTBox
	ControlComment:={}
	CurRControl := A_GuiControl
	if (CurRControl <> PrevControl && ControlComment[CurRControl]&&!GetKeyState("LButton","P"))||(p_hw&&p_hw=hlogo&&!GetKeyState("LButton","P"))
	{
		hTTBox:=ToolTipBox.ToolTip("把文件拖拽至此处进行批量整理",,,4,{auto_color:True},,1000)
	}Else if GetKeyState("LButton","P"){
		DllCall("DestroyWindow","Ptr",hTTBox.HWND)
	}
}

WM_SETCURSOR(hPic, wp) {
	static hCursor, flags := (LR_DEFAULTSIZE := 0x40) | (LR_SHARED := 0x8000)
		, params := [ "Ptr", 0, "UInt", OCR_HAND := 32649
			, "UInt", IMAGE_CURSOR := 2
			, "Int", 0, "Int", 0, "UInt", flags, "Ptr" ]
	(!hCursor && hCursor := DllCall("LoadImage", params*))
	if (wp = hPic)
		Return DllCall("SetCursor", "Ptr", hCursor)
}

EmptyMem(PID=""){
	pid:=!PID ? DllCall("GetCurrentProcessId") : pid
	h:=DllCall("OpenProcess", "UInt", 0x001F0FFF, "Int", 0, "Int", pid)
	DllCall("SetProcessWorkingSetSize", "UInt", h, "Int", -1, "Int", -1)
	DllCall("CloseHandle", "Int", h)
}

;;根据进程文件名获取进程信息列表
GetProcessNameList(ProcessName:=""){
	list:="",tarr:=[]
	s := 10240  ; 缓存和数组的大小(4 KB)

	Process, Exist  ; 设置 ErrorLevel 为这个正在运行脚本的 PID.
	; 使用 PROCESS_QUERY_INFORMATION(0x0400) 获取此脚本的句柄:
	h := DllCall("OpenProcess", "UInt", 0x0400, "Int", false, "UInt", ErrorLevel, "Ptr")
	; 打开此进程的可调整的访问令牌(TOKEN_ADJUST_PRIVILEGES = 32):
	DllCall("Advapi32.dll\OpenProcessToken", "Ptr", h, "UInt", 32, "PtrP", t)
	VarSetCapacity(ti, 16, 0)  ; 特权结构
	NumPut(1, ti, 0, "UInt")  ; 特权数组中的一个条目...
	; 获取调试特权的本地唯一标识符:
	DllCall("Advapi32.dll\LookupPrivilegeValue", "Ptr", 0, "Str", "SeDebugPrivilege", "Int64P", luid)
	NumPut(luid, ti, 4, "Int64")
	NumPut(2, ti, 12, "UInt")  ; 启用这个特权: SE_PRIVILEGE_ENABLED = 2
	; 使用新的访问令牌更新此进程的特权:
	r := DllCall("Advapi32.dll\AdjustTokenPrivileges", "Ptr", t, "Int", false, "Ptr", &ti, "UInt", 0, "Ptr", 0, "Ptr", 0)
	DllCall("CloseHandle", "Ptr", t)  ; 关闭此访问令牌句柄以节约内存.
	DllCall("CloseHandle", "Ptr", h)  ; 关闭此进程句柄以节约内存.

	hModule := DllCall("LoadLibrary", "Str", "Psapi.dll")  ; 通过预加载来提升性能.
	s := VarSetCapacity(a, s)  ; 接收进程列表标识符的数组:

	DllCall("Psapi.dll\EnumProcesses", "Ptr", &a, "UInt", s, "UIntP", r)
	Loop, % r // 4  ; 把数组解析为 DWORD(32 位) 的标识符:
	{
		id := NumGet(a, A_Index * 4, "UInt")
		; 打开进程: PROCESS_VM_READ(0x0010) | PROCESS_QUERY_INFORMATION(0x0400)
		h := DllCall("OpenProcess", "UInt", 0x0010 | 0x0400, "Int", false, "UInt", id, "Ptr")
		if !h
			continue
		VarSetCapacity(n, s, 0)  ; 接收模块基础名称的缓存:
		e := DllCall("Psapi.dll\GetModuleBaseName", "Ptr", h, "Ptr", 0, "Str", n, "UInt", A_IsUnicode ? s//2 : s)
		if !e    ;  用于 64 位进程在 32 位模式时的回退方法:
			if e := DllCall("Psapi.dll\GetProcessImageFileName", "Ptr", h, "Str", n, "UInt", A_IsUnicode ? s//2 : s)
				SplitPath n, n
		DllCall("CloseHandle", "Ptr", h)  ; 关闭进程句柄以节约内存
		if (n && e){  ; 如果映像不是空的, 则添加到列表:
			If (ProcessName&&ProcessName=n)
				tarr.push([n,id])
			else
				list.=n "/" id "|"
		}
	}
	DllCall("FreeLibrary", "Ptr", hModule)  ; 卸载库来释放内存.

	return !ProcessName?list:tarr
}

Class ToolTipBox
{
	/*
		Drawtooltip("自绘tooltip窗口5",,,{back_color:0x17ffff,text_color:0xffffff,font_weight:700,font_point:16,font_face:"宋体"})
		TT1:=Drawtooltip("自绘tooltip窗口1",600,100,True)
		TT2:=Drawtooltip("自绘tooltip窗口2",TT1.x,TT1.y+TT1.h+10,True)
		TT3:=Drawtooltip("自绘tooltip窗口3",TT2.x,TT2.y+TT2.h+10,True)
		TT4:=Drawtooltip("自绘tooltip窗口4",TT3.x,TT3.y+TT3.h+10,True)
		参数:
			Text: 文本字符
			xpos: x坐标,为空时跟随鼠标,例如Drawtooltip("Text")
			ypos: y坐标,为空时跟随鼠标
			Style:
				1、为true时自动随机颜色,其它默认。例如Drawtooltip("自绘tooltip窗口",,,True)
				2、为数组对象参数时:
					auto_color:为true时自动随机颜色,back_color与text_color定义无效
					back_color:背景色
					text_color:字体颜色
					font_face:字体名称
					font_point:字号
					font_weight:字体粗细
					Top:上边距
					Bottom:下边距
					Left:左边距
					Right:右边距
					,例如:Drawtooltip("自绘tooltip窗口",,,{back_color:0x17ffff,text_color:0xffffff,font_weight:700,font_point:16,font_face:"楷体"})
			Timeout: 限定时间自动销毁(毫秒)
		窗口ahk_class:tooltips_class32
	*/
	Drawtooltip(Text,xpos:="",ypos:="",Style:="",Timeout:=3500){
		MinLeft:=DllCall("GetSystemMetrics", "Int", 76), MinTop:=DllCall("GetSystemMetrics", "Int", 77)
		, MaxRight:=DllCall("GetSystemMetrics", "Int", 78), MaxBottom:=DllCall("GetSystemMetrics", "Int", 79)
		SysGet, MonCount, MonitorCount
		SysGet, Mon, Monitor
		if !(xpos>=0&&ypos>=0){
			static i:=VarSetCapacity(i,8,0)
			DllCall("GetCursorPos","Ptr",&i),xpos:=NumGet(i,0,"Int"),ypos:=NumGet(i,4,"Int")
		}
		xpos:=(xpos<MinLeft?MinLeft:xpos>MaxRight?MaxRight:xpos), ypos:=(ypos<MinTop?MinTop:ypos>MaxBottom?MaxBottom:ypos)
		If (MonCount>1){
			HMON:=DllCall("User32.dll\MonitorFromPoint", "Int64", (xpos & 0xFFFFFFFF) | (ypos << 32), "UInt", 0, "Ptr")
			NumPut(VarSetCapacity(MIEX, 40 + (32 << !!A_IsUnicode)), MIEX, 0, "UInt")
			if DllCall("User32.dll\GetMonitorInfo", "Ptr", HMON, "Ptr", &MIEX, "Int"){
				MonInfo:={Name: (Name := StrGet(&MIEX + 40, 32)), Num: RegExReplace(Name, ".*(\d+)$", "$1")
					, Left: NumGet(MIEX, 4, "Int"), Top: NumGet(MIEX, 8, "Int")
					, Right: NumGet(MIEX, 12, "Int"), Bottom: NumGet(MIEX, 16, "Int")
					, WALeft: NumGet(MIEX, 20, "Int"), WATop: NumGet(MIEX, 24, "Int")
					, WARight: NumGet(MIEX, 28, "Int"), WABottom: NumGet(MIEX, 32, "Int")
					, Primary: NumGet(MIEX, 36, "UInt")}
				MonLeft:=MonInfo.Left, MonTop:=MonInfo.Top, MonRight:=MonInfo.Right, MonBottom:=MonInfo.Bottom
			}Else
				SysGet, Mon, Monitor
		}
		VarSetCapacity(TOOLINFO, A_PtrSize=8?72:48, 0)
		NumPut(A_PtrSize=8?72:48, &TOOLINFO, 0, "UInt")
		NumPut(TTF_TRACK := 0x20, &TOOLINFO, 4, "UInt")
		NumPut(&Text, &TOOLINFO, A_PtrSize=8?48:36, "Ptr")
		hTT := DllCall("user32\CreateWindowEx", "UInt",0x8, "Str","tooltips_class32", "Ptr",0, "UInt",0x3, "Int",0, "Int",0, "Int",0, "Int",0, "Ptr",A_ScriptHwnd, "Ptr",0, "Ptr",0, "Ptr",0)
		if (!isObject(Style)&&hTT&&Style||isObject(Style)&&hTT&&Style.auto_color) {
			Random,backcolor,0x000000,0xffffff
			Style:=isObject(Style)?Style:{},Style.back_color:=Format("0x{:06X}",backcolor)
			tarr:= StrSplit(RegExReplace(SubStr(Style.back_color,3),"(..)","0x$1,"),",")
			Style.text_color:=Floor(tarr[1]*0.299+tarr[2]*0.587+tarr[3]*0.114)<192?"0xffffff":"0x333333"
		}Else{
			Style:=isObject(Style)?Style:{},Style.back_color :=Style.back_color~="i)^(0x[a-fA-F0-9]{5,6}|\d+)"?Style.back_color: 0xF0F0F0 ;RGB
			,Style.text_color :=Style.text_color~="i)^(0x[a-fA-F0-9]{5,6}|\d+)"?Style.text_color: 0x1F1F1F ;RGB
		}
		DllCall("uxtheme\SetWindowTheme", "Ptr",hTT, "Ptr",0, "Str","")
		VarSetCapacity(RECT, 16, 0),vRect := (Style.Left>0?Style.Left:8) "," (Style.Top>0?Style.Top:4) "," (Style.Right>0?Style.Right:8) "," (Style.Bottom>0?Style.Bottom:4)
		Loop, Parse, vRect, % ","
			NumPut(A_LoopField, &RECT, A_Index*4-4, "Int")
		DllCall("SendMessage", "Uint", hTT, "Uint", TTM_SETMARGIN := 0x41A, "Uint", 0, "Uint", &RECT)
		DllCall("SendMessage", "Ptr", hTT, "Uint", TTM_SETTIPBKCOLOR := 0x413, "Ptr", ((Style.back_color&255)<<16)+(((Style.back_color>>8)&255)<<8)+(Style.back_color>>16), "Ptr", 0)
		DllCall("SendMessage", "Ptr", hTT, "Uint", TTM_SETTIPTEXTCOLOR := 0x414, "Ptr", ((Style.text_color&255)<<16)+(((Style.text_color>>8)&255)<<8)+(Style.text_color>>16), "Ptr", 0)
		DllCall("SendMessage", "Uint", hTT, "Uint", TTM_SETMAXTIPWIDTH :=0x418, "Uint", 0, "Uint", A_ScreenWidth)
		NumPut(VarSetCapacity(info, A_IsUnicode ? 504 : 344, 0), info, 0, "UInt")
		DllCall("SystemParametersInfo", "UInt", 0x29, "UInt", 0, "Ptr", &info, "UInt", 0)
		SysDefaultFont:=StrGet(&info + 52)<>""?StrGet(&info + 52):"微软雅黑"
		,Style.font_face :=Style.font_face<>""?Style.font_face:SysDefaultFont
		,Style.font_point :=Style.font_point>0?Style.font_point:9
		,Style.font_weight :=Style.font_weight?Style.font_weight:400
		,Style.font_height := -Round(Style.font_point*A_ScreenDPI/72)
		hFont := DllCall("gdi32\CreateFont", "Int",Style.font_height, "Int",0, "Int",0, "Int",0, "Int",Style.font_weight, "UInt",0, "UInt",0 ,"UInt",0, "UInt",0, "UInt",0, "UInt",0, "UInt",0, "UInt",0, "Str",Style.font_face, "Ptr")
		DllCall("SendMessage", "Ptr", hTT, "Uint", WM_SETFONT := 0x30, "Ptr", hfont, "Ptr", 0)
		DllCall("SendMessage", "Uint", hTT, "Uint", TTM_ADDTOOL:=A_IsUnicode?0x432:0x404, "Uint", 0, "Uint", &TOOLINFO)
		DllCall("SendMessage", "Uint", hTT, "Uint", TTM_TRACKPOSITION := 0x412, "Uint", 0, "Uint", (xpos&0xFFFF)|(ypos<<16))
		DllCall("SendMessage", "Uint", hTT, "Uint", TTM_TRACKACTIVATE := 0x411, "Uint", 1, "Uint", &TOOLINFO)
		VarSetCapacity( size, 16, 0 ),DllCall( "GetClientRect", "Ptr", htt, "Ptr", &size )
		DllCall( "ClientToScreen", "Ptr", htt, "Ptr", &size )
		width := NumGet( size, 8, "Int" ), height := NumGet( size, 12, "Int" )
		if (Timeout>0){
			flag:=Func("DllCall").Bind("DestroyWindow", "ptr", hTT)
			SetTimer, % flag,% "-" Timeout
		}

		Return {HWND:hTT,w:width,h:height,x:xpos,y:ypos}
	}

	/*
		HWND1:=ToolTip("Text..1",600,100,1,True)
		HWND2:=ToolTip("Text..2",600,HWND1.y+HWND1.h+10,2,True)
		HWND3:=ToolTip("Text..3",600,HWND2.y+HWND2.h+10,3,True)
		HWND4:=ToolTip("Text..4",600,HWND3.y+HWND3.h+10,4,True)
		HWND5:=ToolTip("Text..5",,,5,True)

		ToolTip(Text,xpos:="",ypos:="",WhichToolTip:=1,Style:="",RelatedArea:="Screen",Timeout:=3000)
		参数:
			Text: 文本字符
			xpos: x坐标,为空时跟随鼠标,例如ToolTip("Text")
			ypos: y坐标,为空时跟随鼠标
			WhichToolTip: ToolTip编号1~20,例如ToolTip("Text",,,3)
			Style:
				1、为true时自动随机颜色,其它默认。例如ToolTip("Text..3",,,3,True)
				2、为数组对象参数时例如{back_color:0x17ffff,text_color:0xffffff}
					当auto_color:为true时自动随机颜色,back_color与text_color定义无效
					,例如ToolTip("Text..3",,,3,{back_color:0x17ffff,text_color:0xffffff})
			RelatedArea:为多个命令设置坐标模式, 相对于活动窗口还是屏幕,参数为Screen、Relative、Window、Client
			Timeout: 限定时间自动销毁(毫秒)
	*/
	ToolTip(Text,xpos:="",ypos:="",WhichToolTip:=1,Style:="",RelatedArea:="Screen",Timeout:=3000){
		if (WhichToolTip<1||WhichToolTip>20||Trim(Text)="")
			Return False
		if RelatedArea In Screen,Relative,Window,Client
			CoordMode,ToolTip,%RelatedArea%
		Gui +OwnDialogs
		ToolTip,%Text%,xpos,ypos,WhichToolTip
		HWND:=WinExist("ahk_class tooltips_class32")
		if (!isObject(Style)&&HWND&&Style||isObject(Style)&&HWND&&Style.auto_color) {
			Random,backcolor,0x000000,0xffffff
			Style:=isObject(Style)?Style:{},Style.back_color:=Format("0x{:06X}",backcolor)
			tarr:= StrSplit(RegExReplace(SubStr(Style.back_color,3),"(..)","0x$1,"),",")
			Style.text_color:=Floor(tarr[1]*0.299+tarr[2]*0.587+tarr[3]*0.114)<192?"0xffffff":"0x333333"
		}
		if (isObject(Style)&&HWND) {
			DllCall("UxTheme.dll\SetWindowTheme", "ptr", hwnd, "Ptr", 0, "UintP", 0)
			if Style.back_color~="i)^(0x[a-fA-F0-9]{5,6}|\d+)"
				DllCall("SendMessage", "Ptr", hwnd, "Uint", 1043, "Ptr", ((Style.back_color&255)<<16)+(((Style.back_color>>8)&255)<<8)+(Style.back_color>>16), "Ptr", 0)
			if Style.text_color~="i)^(0x[a-fA-F0-9]{5,6}|\d+)"
				DllCall("SendMessage", "Ptr", hwnd, "Uint", 1044, "Ptr", ((Style.text_color&255)<<16)+(((Style.text_color>>8)&255)<<8)+(Style.text_color>>16), "Ptr", 0)
		}
		;hfont:=DllCall("SendMessage", "Ptr", hwnd, "Uint", WM_GETFONT:= 0x31, "Ptr", 0, "Ptr", 0)
		;if hFont&&HWND
		;	DllCall("SendMessage", "Ptr", hwnd, "Uint", 0x30, "Ptr", hfont, "Ptr", 0)
		if !(xpos>=0&&ypos>=0){
			static i:=VarSetCapacity(i,8,0)
			DllCall("GetCursorPos","Ptr",&i),xpos:=NumGet(i,0,"Int"),ypos:=NumGet(i,4,"Int")
		}
		VarSetCapacity( size, 16, 0 ),DllCall( "GetClientRect", "Ptr", HWND, "Ptr", &size )
		DllCall( "ClientToScreen", "Ptr", HWND, "Ptr", &size )
		xpos := NumGet( size, 0, "Int"), ypos := NumGet( size, 4, "Int")
		width := NumGet( size, 8, "Int" ), height := NumGet( size, 12, "Int" )
		if (Timeout>0){
			flag:=Func("DllCall").Bind("DestroyWindow", "ptr", HWND)
			SetTimer, % flag,% "-" Timeout
		}

		Return {HWND:HWND,w:width,h:height,x:xpos,y:ypos}
	}
}

; ==================================================================================================================================
; Function:       Notifies about changes within folders.
;                 This is a rewrite of HotKeyIt's WatchDirectory() released at
;                    http://www.autohotkey.com/board/topic/60125-ahk-lv2-watchdirectory-report-directory-changes/
; Tested with:    AHK 1.1.23.01 (A32/U32/U64)
; Tested on:      Win 10 Pro x64
; Usage:          WatchFolder(Folder, UserFunc[, SubTree := False[, Watch := 3]])
; Parameters:
;     Folder      -  The full qualified path of the folder to be watched.
;                    Pass the string "**PAUSE" and set UserFunc to either True or False to pause respectively resume watching.
;                    Pass the string "**END" and an arbitrary value in UserFunc to completely stop watching anytime.
;                    If not, it will be done internally on exit.
;     UserFunc    -  The name of a user-defined function to call on changes. The function must accept at least two parameters:
;                    1: The path of the affected folder. The final backslash is not included even if it is a drive's root
;                       directory (e.g. C:).
;                    2: An array of change notifications containing the following keys:
;                       Action:  One of the integer values specified as FILE_ACTION_... (see below).
;                                In case of renaming Action is set to FILE_ACTION_RENAMED (4).
;                       Name:    The full path of the changed file or folder.
;                       OldName: The previous path in case of renaming, otherwise not used.
;                       IsDir:   True if Name is a directory; otherwise False. In case of Action 2 (removed) IsDir is always False.
;                    Pass the string "**DEL" to remove the directory from the list of watched folders.
;     SubTree     -  Set to true if you want the whole subtree to be watched (i.e. the contents of all sub-folders).
;                    Default: False - sub-folders aren't watched.
;     Watch       -  The kind of changes to watch for. This can be one or any combination of the FILE_NOTIFY_CHANGES_...
;                    values specified below.
;                    Default: 0x03 - FILE_NOTIFY_CHANGE_FILE_NAME + FILE_NOTIFY_CHANGE_DIR_NAME
; Return values:
;     Returns True on success; otherwise False.
; Change history:
;     1.0.03.00/2021-10-14/just me        -  bug-fix for addding, removing, or updating folders.
;     1.0.02.00/2016-11-30/just me        -  bug-fix for closing handles with the '**END' option.
;     1.0.01.00/2016-03-14/just me        -  bug-fix for multiple folders
;     1.0.00.00/2015-06-21/just me        -  initial release
; License:
;     The Unlicense -> http://unlicense.org/
; Remarks:
;     Due to the limits of the API function WaitForMultipleObjects() you cannot watch more than MAXIMUM_WAIT_OBJECTS (64)
;     folders simultaneously.
; MSDN:
;     ReadDirectoryChangesW          msdn.microsoft.com/en-us/library/aa365465(v=vs.85).aspx
;     FILE_NOTIFY_CHANGE_FILE_NAME   = 1   (0x00000001) : Notify about renaming, creating, or deleting a file.
;     FILE_NOTIFY_CHANGE_DIR_NAME    = 2   (0x00000002) : Notify about creating or deleting a directory.
;     FILE_NOTIFY_CHANGE_ATTRIBUTES  = 4   (0x00000004) : Notify about attribute changes.
;     FILE_NOTIFY_CHANGE_SIZE        = 8   (0x00000008) : Notify about any file-size change.
;     FILE_NOTIFY_CHANGE_LAST_WRITE  = 16  (0x00000010) : Notify about any change to the last write-time of files.
;     FILE_NOTIFY_CHANGE_LAST_ACCESS = 32  (0x00000020) : Notify about any change to the last access time of files.
;     FILE_NOTIFY_CHANGE_CREATION    = 64  (0x00000040) : Notify about any change to the creation time of files.
;     FILE_NOTIFY_CHANGE_SECURITY    = 256 (0x00000100) : Notify about any security-descriptor change.
;     FILE_NOTIFY_INFORMATION        msdn.microsoft.com/en-us/library/aa364391(v=vs.85).aspx
;     FILE_ACTION_ADDED              = 1   (0x00000001) : The file was added to the directory.
;     FILE_ACTION_REMOVED            = 2   (0x00000002) : The file was removed from the directory.
;     FILE_ACTION_MODIFIED           = 3   (0x00000003) : The file was modified.
;     FILE_ACTION_RENAMED            = 4   (0x00000004) : The file was renamed (not defined by Microsoft).
;     FILE_ACTION_RENAMED_OLD_NAME   = 4   (0x00000004) : The file was renamed and this is the old name.
;     FILE_ACTION_RENAMED_NEW_NAME   = 5   (0x00000005) : The file was renamed and this is the new name.
;     GetOverlappedResult            msdn.microsoft.com/en-us/library/ms683209(v=vs.85).aspx
;     CreateFile                     msdn.microsoft.com/en-us/library/aa363858(v=vs.85).aspx
;     FILE_FLAG_BACKUP_SEMANTICS     = 0x02000000
;     FILE_FLAG_OVERLAPPED           = 0x40000000
; ==================================================================================================================================
WatchFolder(Folder, UserFunc, SubTree := False, Watch := 0x03) {
   Static DummyObject := {Base: {__Delete: Func("WatchFolder").Bind("**END", "")
   Static TimerID := "**" . A_TickCount
   Static TimerFunc := Func("WatchFolder").Bind(TimerID, "")
   Static MAXIMUM_WAIT_OBJECTS := 64
   Static MAX_DIR_PATH := 260 - 12 + 1
   Static SizeOfLongPath := MAX_DIR_PATH << !!A_IsUnicode
   Static SizeOfFNI := 0xFFFF ; size of the FILE_NOTIFY_INFORMATION structure buffer (64 KB)
   Static SizeOfOVL := 32     ; size of the OVERLAPPED structure (64-bit)
   Static WatchedFolders := {}
   Static EventArray := []
   Static WaitObjects := 0
   Static BytesRead := 0
   Static Paused := False
   ; ===============================================================================================================================
   If (Folder = "")
      Return False
   SetTimer, % TimerFunc, Off
   RebuildWaitObjects := False
   ; ===============================================================================================================================
   If (Folder = TimerID) { ; called by timer
      If (ObjCount := EventArray.Count()) && !Paused {
         ObjIndex := DllCall("WaitForMultipleObjects", "UInt", ObjCount, "Ptr", &WaitObjects, "Int", 0, "UInt", 0, "UInt")
         While (ObjIndex >= 0) && (ObjIndex < ObjCount) {
            Event := NumGet(WaitObjects, ObjIndex * A_PtrSize, "UPtr")
            Folder := EventArray[Event]
            If DllCall("GetOverlappedResult", "Ptr", Folder.Handle, "Ptr", Folder.OVLAddr, "UIntP", BytesRead, "Int", True) {
               Changes := []
               FNIAddr := Folder.FNIAddr
               FNIMax := FNIAddr + BytesRead
               OffSet := 0
               PrevIndex := 0
               PrevAction := 0
               PrevName := ""
               Loop {
                  FNIAddr += Offset
                  OffSet := NumGet(FNIAddr + 0, "UInt")
                  Action := NumGet(FNIAddr + 4, "UInt")
                  Length := NumGet(FNIAddr + 8, "UInt") // 2
                  Name   := Folder.Name . "\" . StrGet(FNIAddr + 12, Length, "UTF-16")
                  IsDir  := InStr(FileExist(Name), "D") ? 1 : 0
                  If (Name = PrevName) {
                     If (Action = PrevAction)
                        Continue
                     If (Action = 1) && (PrevAction = 2) {
                        PrevAction := Action
                        Changes.RemoveAt(PrevIndex--)
                        Continue
                     }
                  }
                  If (Action = 4)
                     PrevIndex := Changes.Push({Action: Action, OldName: Name, IsDir: 0})
                  Else If (Action = 5) && (PrevAction = 4) {
                     Changes[PrevIndex, "Name"] := Name
                     Changes[PrevIndex, "IsDir"] := IsDir
                  }
                  Else
                     PrevIndex := Changes.Push({Action: Action, Name: Name, IsDir: IsDir})
                  PrevAction := Action
                  PrevName := Name
               } Until (Offset = 0) || ((FNIAddr + Offset) > FNIMax)
               If (Changes.Length() > 0)
                  Folder.Func.Call(Folder.Name, Changes)
               DllCall("ResetEvent", "Ptr", Event)
               DllCall("ReadDirectoryChangesW", "Ptr", Folder.Handle, "Ptr", Folder.FNIAddr, "UInt", SizeOfFNI
                                              , "Int", Folder.SubTree, "UInt", Folder.Watch, "UInt", 0
                                              , "Ptr", Folder.OVLAddr, "Ptr", 0)
            }
            ObjIndex := DllCall("WaitForMultipleObjects", "UInt", ObjCount, "Ptr", &WaitObjects, "Int", 0, "UInt", 0, "UInt")
            Sleep, 0
         }
      }
   }
   ; ===============================================================================================================================
   Else If (Folder = "**PAUSE") { ; called to pause/resume watching
      Paused := !!UserFunc
      RebuildObjects := Paused
   }
   ; ===============================================================================================================================
   Else If (Folder = "**END") { ; called to stop watching
      For Event, Folder In EventArray {
         DllCall("CloseHandle", "Ptr", Folder.Handle)
         DllCall("CloseHandle", "Ptr", Event)
      }
      WatchedFolders := {}
      EventArray := []
      Paused := False
      Return True
   }
   ; ===============================================================================================================================
   Else { ; called to add, update, or remove folders
      Folder := RTrim(Folder, "\")
      VarSetCapacity(LongPath, MAX_DIR_PATH << !!A_IsUnicode, 0)
      If !DllCall("GetLongPathName", "Str", Folder, "Ptr", &LongPath, "UInt", MAX_DIR_PATH)
         Return False
      VarSetCapacity(LongPath, -1)
      Folder := LongPath
      If (WatchedFolders.HasKey(Folder)) { ; update or remove
         Event :=  WatchedFolders[Folder]
         FolderObj := EventArray[Event]
         DllCall("CloseHandle", "Ptr", FolderObj.Handle)
         DllCall("CloseHandle", "Ptr", Event)
         EventArray.Delete(Event)
         WatchedFolders.Delete(Folder)
         RebuildWaitObjects := True
      }
      If InStr(FileExist(Folder), "D") && (UserFunc <> "**DEL") && (EventArray.Count() < MAXIMUM_WAIT_OBJECTS) {
         If (IsFunc(UserFunc) && (UserFunc := Func(UserFunc)) && (UserFunc.MinParams >= 2)) && (Watch &= 0x017F) {
            Handle := DllCall("CreateFile", "Str", Folder . "\", "UInt", 0x01, "UInt", 0x07, "Ptr",0, "UInt", 0x03
                                          , "UInt", 0x42000000, "Ptr", 0, "UPtr")
            If (Handle > 0) {
               Event := DllCall("CreateEvent", "Ptr", 0, "Int", 1, "Int", 0, "Ptr", 0)
               FolderObj := {Name: Folder, Func: UserFunc, Handle: Handle, SubTree: !!SubTree, Watch: Watch}
               FolderObj.SetCapacity("FNIBuff", SizeOfFNI)
               FNIAddr := FolderObj.GetAddress("FNIBuff")
               DllCall("RtlZeroMemory", "Ptr", FNIAddr, "Ptr", SizeOfFNI)
               FolderObj["FNIAddr"] := FNIAddr
               FolderObj.SetCapacity("OVLBuff", SizeOfOVL)
               OVLAddr := FolderObj.GetAddress("OVLBuff")
               DllCall("RtlZeroMemory", "Ptr", OVLAddr, "Ptr", SizeOfOVL)
               NumPut(Event, OVLAddr + 8, A_PtrSize * 2, "Ptr")
               FolderObj["OVLAddr"] := OVLAddr
               DllCall("ReadDirectoryChangesW", "Ptr", Handle, "Ptr", FNIAddr, "UInt", SizeOfFNI, "Int", SubTree
                                              , "UInt", Watch, "UInt", 0, "Ptr", OVLAddr, "Ptr", 0)
               EventArray[Event] := FolderObj
               WatchedFolders[Folder] := Event
               RebuildWaitObjects := True
            }
         }
      }
      If (RebuildWaitObjects) {
         VarSetCapacity(WaitObjects, MAXIMUM_WAIT_OBJECTS * A_PtrSize, 0)
         OffSet := &WaitObjects
         For Event In EventArray
            Offset := NumPut(Event, Offset + 0, 0, "Ptr")
      }
   }
   ; ===============================================================================================================================
   If (EventArray.Count() > 0)
      SetTimer, % TimerFunc, -100
   Return (RebuildWaitObjects) ; returns True on success, otherwise False
}

Class CListBox
{
	/*
		新增(追加)listbox项
		HWND:ListBox控件句柄
		Text:要追加字符
		成功返回总行数否则返回false
	*/
	Add(HWND,Text){
		Static LB_ADDSTRING := 0x0180

		VarSetCapacity(String,StrPut(Text,"utf-16")*4),StrPut(Text, &String, "utf-16")
		Index:=DllCall("User32\SendMessage", "Ptr", HWND, "UInt", LB_ADDSTRING, "Ptr", 0, "Ptr", &String)+1
		Count:=this.GetCount(HWND),this.SetCurSel(HWND, Count)
		Return Count=Index?Count:False
	}

	/*
		指定位置插入listbox项
		HWND:ListBox控件句柄
		Pos:指定插入的行号,Pos=0时追加插入
		Text:要追加字符
		成功返回行号否则返回false
	*/
	Insert(HWND,Text,Pos:=1){
		Static LB_INSERTSTRING := 0x0181

		VarSetCapacity(String,StrPut(Text,"utf-16")*4),StrPut(Text, &String, "utf-16")
		Index:=DllCall("User32\SendMessage", "Ptr", HWND, "UInt", LB_INSERTSTRING, "UInt", Pos-1, "Ptr", &String)+1
		if (Index>=Pos)
			this.SetCurSel(HWND, Index)
		Return Index>=Pos?Index:False
	}

	/*
		获取listbox总行数
		成功返回总行数
	*/
	GetCount(HWND){
		Static LB_GETCOUNT := 0x018B

		Return DllCall("User32.dll\SendMessage", "Ptr", HWND, "UInt", LB_GETCOUNT, "Ptr", 0, "Ptr", 0, "Ptr") 
	}

	/*
		删除listbox指定行
		HWND:ListBox控件句柄
		Pos:指定删除的行号
		成功返回True否则返回false
	*/
	Delete(HWND,Pos){
		Static LB_DELETESTRING := 0x0182

		i:=this.GetCount(HWND)
		Index:=DllCall("User32\SendMessage", "Ptr", HWND, "UInt", LB_DELETESTRING, "UInt", Pos-1, "Ptr", 0, "Ptr")
		Count:=this.GetCount(HWND)
		Return Index=Count&&Count<i?True:False
	}

	; 删除listbox所有项
	DeleteAll(HWND){
		Static LB_RESETCONTENT := 0x0184

		Return DllCall("User32\SendMessage", "Ptr", HWND, "UInt", LB_RESETCONTENT, "Ptr", 0, "Ptr", 0, "Ptr")
	}

	; 删除listbox指定条目,成功返回True否则返回false
	DeleteItem(HWND,Text){
		Pos:=this.GetItemPos(HWND, Text),Index:=this.Delete(HWND,Pos)

		Return Index?True:False
	}

	/*
		修改指定行的字符串,Pos=0时视为追加新字符串
		HWND:ListBox控件句柄
		Pos:要修改的指定行
		Text:要替换的新字符
		成功返回True否则返回false
	*/
	Modify(HWND,Pos,Text){
		Status:=this.Delete(HWND,Pos)
		Index:=this.Insert(HWND,Text,Pos)

		Return Index=Pos?True:False
	}

	/*
		获取listbox指定行的字符串
		HWND:ListBox控件句柄
		Pos:要修改的指定行
		成功返回字符串反之为空
	*/
	GetText(HWND,Pos){
		Static LB_GETTEXTLEN := 0x018A
		Static LB_GETTEXT := 0x0189

		len:=DllCall("User32\SendMessage", "Ptr", HWND, "UInt", LB_GETTEXTLEN, "UInt", Pos-1, "Ptr", 0, "Ptr")
		VarSetCapacity(Text, Len << !!A_IsUnicode, 0)
		DllCall("User32\SendMessage", "Ptr", HWND, "UInt", LB_GETTEXT, "UInt", Pos-1, "Ptr", &Text)
		Return StrGet(&Text, Len)
	}

	/*
		获取listbox全部字符串项
		HWND:ListBox控件句柄
		separator:指定分割符
		成功返回字符串反之为空
	*/
	GetAllItem(HWND,separator:="|"){
		ControlGet, GETALLTEXT, List , Count, , ahk_id%HWND%
		Return StrReplace(Trim(GETALLTEXT,"`r`n"),"`n",separator)
	}

	/*
		根据指定字符串项获取在listbox中的位置(在第几行)
		HWND:ListBox控件句柄
		Text:要匹配的字符
		成功返回位置(行号)
	*/
	GetItemPos(HWND, Text) {
		Static LB_FINDSTRINGEXACT := 0x01A2

		VarSetCapacity(String,StrPut(Text,"utf-16")*4),StrPut(Text, &String, "utf-16")
		Index:=DllCall("User32\SendMessage", "Ptr", HWND, "UInt", LB_FINDSTRINGEXACT, "UInt", -1, "Ptr", &String)+1
		Count:=this.GetCount(HWND)
		Return Count&&Index?Index:False
	}

	;返回选中的高亮项行号(单选)
	GetCurrentSel(HWND) {
		Static LB_GETCURSEL := 0x0188

		Return DllCall("User32\SendMessage", "Ptr", HWND, "UInt", LB_GETCURSEL, "UInt", 0, "Ptr")+1
	}

	;选中listbox列表中的指定条目,返回行号
	SelectString(HWND, Text) {
		;;Static LB_SELECTSTRING := 0x018C
		;;VarSetCapacity(String,StrPut(Text,"utf-16")*4),StrPut(Text, &String, "utf-16")
		;;Return DllCall("User32\SendMessage", "Ptr", HWND, "UInt", LB_SELECTSTRING, "UInt", -1, "Ptr", &String)+1

		if Index:=this.GetItemPos(HWND, Text){
			Return this.SetCurSel(HWND, Index)
		}Else
			Return False
	}

	SelectAllItem(HWND){
		Static LB_SETSEL := 0x0185
		PostMessage, 0x0185, 1, -1, , ahk_id%HWND%
		Return DllCall("User32\PostMessage", "Ptr", HWND, "UInt", LB_SETSEL, "UInt", 1, "UInt",-1)+1
	}

	;选中listbox列表中的指定行
	SetCurSel(HWND, Index){
		Static LB_SETCURSEL := 0x0186

		Return DllCall("User32\SendMessage", "Ptr", HWND, "UInt", LB_SETCURSEL, "UInt", Index-1, "Ptr", 0, "Ptr")+1
	}

	;设置listbox行高
	SetItemHeight(HWND, Height) {
		Static LB_SETITEMHEIGHT := 0x01A0
		
		Return DllCall("User32\SendMessage", "Ptr", HWND, "UInt", LB_SETITEMHEIGHT, "UInt", -1, "UInt", Height, "Ptr")+1
	}

	;获取listbox行高
	GetItemHeight(HWND) {
		Static LB_GETITEMHEIGHT := 0x01A1

		Return DllCall("User32\SendMessage", "Ptr", HWND, "UInt", LB_GETITEMHEIGHT, "UInt", 0, "UInt", 0, "Ptr")
	}

	;根据listbox项获取单行真实宽度
	CalcIdealWidth(HWND){
		Static WM_GETFONT := 0x0031
		hFont:=DllCall("User32\SendMessage", "Ptr", HWND, "UInt", WM_GETFONT, "UInt", 0, "UInt", 0, "Ptr")
		if !hFont
			Return False
		ControlGet, Content, List, , , ahk_id %HWND%
		Items := StrSplit(Content, "`n")
		HDC := DllCall("User32.dll\GetDC", "Ptr", HWND, "UPtr")
		DllCall("Gdi32.dll\SelectObject", "Ptr", HWND, "Ptr", HFONT)
		VarSetCapacity(SIZE, 8, 0)
		For Each, Item In Items
		{
			DllCall("Gdi32.dll\GetTextExtentPoint32", "Ptr", HDC, "Ptr", &Item, "Int", StrLen(Item), "UIntP", Width)
			If (Width > MaxW)
				MaxW := Width
		}
		DllCall("User32.dll\ReleaseDC", "Ptr", HLB, "Ptr", HDC)

		Return MaxW + 8
	}

	;获取listbox单行行高与宽度
	GetItemRect(HWND){
		Static LB_GETITEMRECT := 0x0198

		VarSetCapacity(RECT, 16, 0)
		DllCall("User32\SendMessage", "Ptr", HWND, "UInt", LB_GETITEMRECT, "Ptr", 0, "Ptr", &RECT, "Ptr")
		ItemWidth := NumGet(RECT, 8, "Int") - NumGet(RECT, 0, "Int")
		ItemHeight := NumGet(RECT, 12, "Int") - NumGet(RECT, 4, "Int")
		Return {Width:ItemWidth,Height:ItemHeight}
	}

}

RegisterClassExW_Hook(lpwcx) {
	Global LogoClassName

	lpszClassName := StrGet( NumGet(lpwcx+0, A_PtrSize == 8 ? 64 : 40, "Ptr") )
	if (lpszClassName = "AutoHotkeyGUI") {
		newClass := LogoClassName<>""?LogoClassName:"DropItToolUI"
		NumPut(&newClass, lpwcx+0, A_PtrSize == 8 ? 64 : 40, "Ptr")
	}

	return DllCall(Object(A_EventInfo).original, "ptr", lpwcx, "ushort")
}

CreateWindowExW_Hook(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam) {
	Global LogoClassName

	sClassName := StrGet(lpClassName)
	if (sClassName = "AutoHotkeyGUI") {
		newClass := LogoClassName<>""?LogoClassName:"DropItToolUI"
		lpClassName := &newClass
	}

	return DllCall(Object(A_EventInfo).original
		, "uint", dwExStyle
		, "ptr", lpClassName
		, "ptr", lpWindowName
		, "int", dwStyle
		, "int", X
		, "int", Y
		, "int", nWidth
		, "int", nHeight
		, "ptr", hWndParent
		, "ptr", hMenu
		, "ptr", hInstance
		, "ptr", lpParam
		, "ptr")
}

; v1.2.1 (2019-08-18)
; AHK version: U32/U64

class MinHook
{
	__New(ModuleName, ModuleFunction, CallbackFunction)
	{
		static init
		if !init
			init := this.__MinHook_Load_Unload()

		if !IsFunc(CallbackFunction)
			throw "Function <" CallbackFunction "> does not exist."

		this.cbAddr := RegisterCallback(CallbackFunction, "F",, &this)

		if (ModuleName = "")
		{
			if err := MH_CreateHook(ModuleFunction, this.cbAddr, pOriginal)
				throw MH_StatusToString(err)
		}
		else
		{
			if !(ModuleName ~= "i)^(User32|Kernel32|ComCtl32|Gdi32)(\.dll)?$")
			{
				if !this.hModule := DllCall("LoadLibrary", "str", ModuleName, "ptr")
					throw "Failed loading module: " ModuleName
			}
			
			if err := MH_CreateHookApiEx(ModuleName, ModuleFunction, this.cbAddr, pOriginal, pTarget)
				throw MH_StatusToString(err)
		}
		
		this.original := pOriginal
		this.target := pTarget
	}

	__Delete()
	{
		MH_RemoveHook(this.target)
		DllCall("GlobalFree", "ptr", this.cbAddr, "ptr")
		if this.hModule
			DllCall("FreeLibrary", "ptr", this.hModule)
	}

	Enable() {
		if err := MH_EnableHook(this.target)
			throw MH_StatusToString(err)
	}

	Disable() {
		if err := MH_DisableHook(this.target)
			throw MH_StatusToString(err)
	}

	QueueEnable() {
		if err := MH_QueueEnableHook(this.target)
			throw MH_StatusToString(err)
	}

	QueueDisable() {
		if err := MH_QueueDisableHook(this.target)
			throw MH_StatusToString(err)
	}

	__MinHook_Load_Unload()
	{
		static _ := { base: {__Delete: MinHook.__MinHook_Load_Unload} }
		static hModule

		if _
		{
			if !dllFile := this._findDll()
				throw "Unable to find MinHook.dll"
			if !hModule := DllCall("LoadLibrary", "str", dllFile, "ptr")
				throw "Failed loading " dllFile
			if err := MH_Initialize()
				throw MH_StatusToString(err)
			return true
		}

		if hModule
		{
			DllCall("MinHook\MH_Uninitialize")
			DllCall("FreeLibrary", "ptr", hModule)
		}
	}

	_findDll()
	{
		dirs := { 4: [".",A_Temp "\DropFilesTool\dll\x86",A_ScriptDir "\dll\x86", A_LineFile "\..", A_Temp "\DaDaInputMethod\dll\x86"]
			, 8: [".",A_Temp "\DropFilesTool\dll\x64", A_ScriptDir "\dll\x64", A_LineFile "\..", A_Temp "\DaDaInputMethod\dll\x64"] }
		for i, dir in dirs[A_PtrSize]
			if FileExist(dir "\MinHook.dll")
				return dir "\MinHook.dll"
	}
}


; Initialize the MinHook library. You must call this function EXACTLY ONCE
; at the beginning of your program.
MH_Initialize() {
	return DllCall("MinHook\MH_Initialize")
}

; Uninitialize the MinHook library. You must call this function EXACTLY
; ONCE at the end of your program.
MH_Uninitialize() {
	return DllCall("MinHook\MH_Uninitialize")
}

; Creates a Hook for the specified target function, in disabled state.
; Parameters:
;   pTarget    [in]  A pointer to the target function, which will be
;                    overridden by the detour function.
;   pDetour    [in]  A pointer to the detour function, which will override
;                    the target function.
;   ppOriginal [out] A pointer to the trampoline function, which will be
;                    used to call the original target function.
;                    This parameter can be NULL.
MH_CreateHook(pTarget, pDetour, ByRef ppOriginal := 0) {
	return DllCall("MinHook\MH_CreateHook"
	               , "ptr", pTarget
	               , "ptr", pDetour
	               , "uptr*", ppOriginal )
}

; Creates a Hook for the specified API function, in disabled state.
; Parameters:
;   pszModule  [in]  A pointer to the loaded module name which contains the
;                    target function.
;   pszTarget  [in]  A pointer to the target function name, which will be
;                    overridden by the detour function.
;   pDetour    [in]  A pointer to the detour function, which will override
;                    the target function.
;   ppOriginal [out] A pointer to the trampoline function, which will be
;                    used to call the original target function.
;                    This parameter can be NULL.
MH_CreateHookApi(pszModule, pszProcName, pDetour, ByRef ppOriginal := 0) {
	return DllCall("MinHook\MH_CreateHookApi"
	               , "str", pszModule
	               , "astr", pszProcName
	               , "ptr", pDetour
	               , "uptr*", ppOriginal )
}

; Creates a Hook for the specified API function, in disabled state.
; Parameters:
;   pszModule  [in]  A pointer to the loaded module name which contains the
;                    target function.
;   pszTarget  [in]  A pointer to the target function name, which will be
;                    overridden by the detour function.
;   pDetour    [in]  A pointer to the detour function, which will override
;                    the target function.
;   ppOriginal [out] A pointer to the trampoline function, which will be
;                    used to call the original target function.
;                    This parameter can be NULL.
;   ppTarget   [out] A pointer to the target function, which will be used
;                    with other functions.
;                    This parameter can be NULL.
MH_CreateHookApiEx(pszModule, pszProcName, pDetour, ByRef ppOriginal := 0, ByRef ppTarget := 0) {
	return DllCall("MinHook\MH_CreateHookApiEx"
	               , "str", pszModule
	               , "astr", pszProcName
	               , "ptr", pDetour
	               , "uptr*", ppOriginal
	               , "uptr*", ppTarget )
}

; Removes an already created hook.
; Parameters:
;   pTarget [in] A pointer to the target function.
MH_RemoveHook(pTarget) {
	return DllCall("MinHook\MH_RemoveHook", "ptr", pTarget)
}

/*
	#define MH_ALL_HOOKS NULL
*/

; Enables an already created hook.
; Parameters:
;   pTarget [in] A pointer to the target function.
;                If this parameter is MH_ALL_HOOKS, all created hooks are
;                enabled in one go.
MH_EnableHook(pTarget := 0) {
	return DllCall("MinHook\MH_EnableHook", "ptr", pTarget)
}

; Disables an already created hook.
; Parameters:
;   pTarget [in] A pointer to the target function.
;                If this parameter is MH_ALL_HOOKS, all created hooks are
;                disabled in one go.
MH_DisableHook(pTarget := 0) {
	return DllCall("MinHook\MH_DisableHook", "ptr", pTarget)
}

; Queues to enable an already created hook.
; Parameters:
;   pTarget [in] A pointer to the target function.
;                If this parameter is MH_ALL_HOOKS, all created hooks are
;                queued to be enabled.
MH_QueueEnableHook(pTarget := 0) {
	return DllCall("MinHook\MH_QueueEnableHook", "ptr", pTarget)
}

; Queues to disable an already created hook.
; Parameters:
;   pTarget [in] A pointer to the target function.
;                If this parameter is MH_ALL_HOOKS, all created hooks are
;                queued to be disabled.
MH_QueueDisableHook(pTarget := 0) {
	return DllCall("MinHook\MH_QueueDisableHook", "ptr", pTarget)
}

; Applies all queued changes in one go.
MH_ApplyQueued() {
	return DllCall("MinHook\MH_ApplyQueued")
}

; Translates the MH_STATUS to its name as a string.
MH_StatusToString(status) {
	return DllCall("MinHook\MH_StatusToString", "int", status, "astr")
}

完整版下载链接:

https://wwt.lanzoul.com/b07nzwd4f 密码:84bs

给TA捐赠
共{{data.count}}人
人已捐赠
其他社区推荐

飞鼠增强

2022-7-22 8:36:05

其他社区推荐

批量打印工具

2022-7-23 9:06:31

3 条回复 A文章作者 M管理员
  1. HoneyBadger

    最新的加了简单的设置窗口,代码所展示不完整请去链接下载源码进行改造完善。

  2. 1河许人

    在一个项目上持续更新,摸摸天花板

  3. 1河许人
    1河许人给您打赏了¥5
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索