GifCam增强版6.5 动图快速录制

GifCam6.5功能扩展辅助

在学习AHK的过程中,对这款GifCam进行不断的增强扩展。方便大家平时交流录制Gif动图来说明问题。

感谢AHK中文社区QQ群里平日大家的帮助,这个辅助示例分类注释了各个部分的功能,也方便学习和使用。

主要功能有:自定义快捷键录制、一键保存到剪贴板、添加了录制鼠标提示功能等等

 

GifCam增强版6.5

蓝奏云单文件exe下载地址:

提取码:无
解压码:无

百度网盘单文件exe下载地址:

提取码:6666复制
解压码:无

GifCam增强版6.5 动图快速录制

整合了生成ini配置文件、对exe程序修改图标、对exe程序界面添加按钮、对exe程序选项注入菜单、AHK托盘菜单和图标自定义、热键自定义设置UI等技术示例

源代码:

#NoEnv
#SingleInstance Force
SetBatchLines, -1
Process, Priority,, High
SetWorkingDir %A_ScriptDir%

if not A_IsAdmin
Run *RunAs "%A_AhkPath%" /r "%A_ScriptFullPath%"

; 检测ini配置文件,并决定是否隐藏托盘图标和后续
IniRead, NoIconScript, GifCam.ini, key, NoIconScript
if (NoIconScript=1)
Menu, Tray, NoIcon

Menu, Tray, Icon, shell32.dll, 175

Gosub, CurPromptToggle ; 启动时停用鼠标录制提示功能
WinClose, ahk_class TGifCamForm

if FileExist(A_ScriptDir "\GifCam.exe") {
if !FileExist(A_ScriptDir "\GifCam.ini") {
FileAppend,
(
[FPS Options]
FPSOptionOne=10
FPSOptionTwo=16
FPSOptionThree=33
[Memory]
UseMemory=1
MemoryUsage=1024000000
[Preferences]
WindowWidth=442
WindowHeight=385
AlwaysCaptureCursor=1
SaveSettingsOnGifCamPath=1
[key]
REC=F3
SaveClip=F4
StopREC=!c
Frame=!d
EditGif=!e 
SaveGif=!s
NoIconScript=0
CurPrompt=1
GifSavePath=%A_Temp%
), %A_ScriptDir%\GifCam.ini
	}
Run %A_ScriptDir%\GifCam.exe
} else {
MsgBox, 16, 找不到GifCam主程序, 脚本同目录不存在GifCam主程序`n请将GifCam主程序的名称改为"GifCam.exe"
ExitApp
}
IniRead, REC, GifCam.ini, key, REC
if (REC = "ERROR") {
FileDelete, %A_ScriptDir%\GifCam.ini
Reload
	}
IniRead, SaveClip, GifCam.ini, key, SaveClip
IniRead, StopREC, GifCam.ini, key, StopREC
IniRead, Frame, GifCam.ini, key, Frame
IniRead, EditGif, GifCam.ini, key, EditGif
IniRead, SaveGif, GifCam.ini, key, SaveGif
IniRead, GifSavePath, GifCam.ini, key, GifSavePath
Hotkey, % REC, REC
Hotkey, % SaveClip, SaveClip
Hotkey, % StopREC, StopREC
Hotkey, % Frame, Frame
Hotkey, % EditGif, EditGif
Hotkey, % SaveGif, SaveGif

; 载入"保存至剪贴板"按钮,并跟随
WinWaitActive ahk_class TGifCamForm
Hosthwnd:=WinExist("ahk_class TGifCamForm")
if objCount(ButtonGuiPos:=GetButtonGuiPos(Hosthwnd)) {
Gui, TGifCam:Destroy
Gui, TGifCam:+hwndTGifCam -Caption -DPIScale +Owner +AlwaysOnTop
Gui, TGifCam:Font, s9
Gui, TGifCam:Add, Button,% ("x0 y0 w" ButtonGuiPos.w " h" ButtonGuiPos.h " gSaveClip"), 保存至`n剪切板
Gui, TGifCam:Show,% ("x" ButtonGuiPos.x " y" ButtonGuiPos.y " w" ButtonGuiPos.w " h" ButtonGuiPos.h)
	}
Instance := new Dock(TGifCam, Hosthwnd)
Instance.Position("C")

; 读取自定义的热键机器码,并转换显示
REC_Tile := StrReplace(StrReplace(StrReplace(Format("{:U}", REC),"+","Shift+"),"!","Alt+"),"^","Ctrl+")
SaveClip_Tile := StrReplace(StrReplace(StrReplace(Format("{:U}", SaveClip),"+","Shift+"),"!","Alt+"),"^","Ctrl+")
StopREC_Tile := StrReplace(StrReplace(StrReplace(Format("{:U}", StopREC),"+","Shift+"),"!","Alt+"),"^","Ctrl+")
Frame_Tile := StrReplace(StrReplace(StrReplace(Format("{:U}", Frame),"+","Shift+"),"!","Alt+"),"^","Ctrl+")
EditGif_Tile := StrReplace(StrReplace(StrReplace(Format("{:U}", EditGif),"+","Shift+"),"!","Alt+"),"^","Ctrl+")
SaveGif_Tile := StrReplace(StrReplace(StrReplace(Format("{:U}", SaveGif),"+","Shift+"),"!","Alt+"),"^","Ctrl+")
WinSetTitle, ahk_class TGifCamForm, ,GifCam〔%REC_Tile%:录制/暂停,%SaveClip_Tile%:保存至剪贴板〕
ChangeWindowIcon("shell32.dll",WinExist("ahk_class TGifCamForm"),204)
WinSet, AlwaysOnTop, On, ahk_class TGifCamForm
WinActivate ahk_class TGifCamForm

; 托盘菜单+图标
Menu, Tray, NoStandard
Menu, Tray, DeleteAll
Menu, Tray, UseErrorLevel
Menu, Tray, Add, 快捷键设置(&W)..., SetHey
Menu, Tray, Icon, 快捷键设置(&W)..., shell32.dll, 317, 16
Menu, Tray, Add,
Menu, Tray, Add, 隐藏图标(&N), NoIconScript
Menu, Tray, Icon, 隐藏图标(&N), wmploc.dll, 43, 16
Menu, Tray, Add,
Menu, Tray, Add, 退出辅助(&D), ExitScript
Menu, Tray, Icon, 退出辅助(&D), wmploc.dll, 136, 16
Menu, Tray, Add,
Menu, Tray, Add, 关闭GifCam(&X), ExitGifCam
Menu, Tray, Icon, 关闭GifCam(&X), shell32.dll, 132, 16
Menu, Tray, Color, ffffff
Menu, Tray, Default, 关闭GifCam(&X)
Menu, Tray, Tip,- 双击托盘图标关闭GifCam`n- %REC_Tile%:录制/暂停`n- %SaveClip_Tile%:保存至剪切板`n- %StopREC_Tile%:停止录制`n- %Frame_Tile%:单帧`n- %EditGif_Tile%:编辑`n- %SaveGif_Tile%:保存

; 窗口消息钩子,用于同步关闭脚本。激活窗口时反馈
Gui +LastFound
DllCall( "RegisterShellHookWindow", UInt,WinExist() )
OnMessage( DllCall( "RegisterWindowMessage", Str,"SHELLHOOK" ), "ShellIMEMessage")
ShellIMEMessage( wParam,lParam ) {
		if !WinExist("ahk_class TGifCamForm")
		ExitApp
	}

; 预加载鼠标提示
IniRead, CurPrompt, GifCam.ini, key, CurPrompt
CoordMode, Mouse, Screen
Gui, +LastFound -Caption +AlwaysOnTop +hwndMouseTS +Owner
Gui, Color, fffc00
Gui, Font, s100 cfffc00
Gui, Margin,-18,-18
Gui, Add, Text, vTextColor, ■
Gui, Show, x8888 y8888
WinSet, ExStyle, +0x20, ahk_id %MouseTS%
WinSet, Region, 27-27 w37 h37 E, ahk_id %MouseTS%
WinSet, Transparent, 110, ahk_id %MouseTS%
Gui, Show, Hide
Return
;----------------------------- 托盘菜单 -----------------------------
NoIconScript:
Menu, Tray, NoIcon
WinActivate ahk_class TGifCamForm
Iniwrite, 1, GifCam.ini, key, NoIconScript
Return

ExitGifCam:
WinClose, ahk_class TGifCamForm
Return

ExitScript:
ExitApp
;--------------------------- 二级菜单 ---------------------------
SetHey:
Gosub, SetHeyGuiClose
IniRead, NoIconScript, GifCam.ini, key, NoIconScript
GifSavePathJump:
Gui, SetHey:Font, s9, 微软雅黑
Gui, SetHey:-MinimizeBox -MaximizeBox +AlwaysOnTop
Gui, SetHey:Add, text, x26 y32 w76 h21, 录制/暂停 :
Gui, SetHey:Add, Hotkey, vREC x106 y30 w94 h20
Gui, SetHey:Add, text, x42 y56 w60 h20, 停 止 :
Gui, SetHey:Add, Hotkey, vStopREC x106 y54 w94 h20
Gui, SetHey:Add, text, x42 y80 w60 h20, 单 帧 :
Gui, SetHey:Add, Hotkey, vFrame x106 y78 w94 h20
Gui, SetHey:Add, text, x42 y104 w60 h20, 编 辑 :
Gui, SetHey:Add, Hotkey, vEditGif x106 y102 w94 h20
Gui, SetHey:Add, text, x42 y128 w60 h20, 保 存 :
Gui, SetHey:Add, Hotkey, vSaveGif x106 y126 w94 h20
Gui, SetHey:Add, text, x22 y187 w88 h18, 保存至剪贴板:
Gui, SetHey:Add, Hotkey, vSaveClip x106 y185 w94 h20
Gui, SetHey:Add, GroupBox, x10 y8 w212 h149, % " GifCam 快捷键 "
Gui, SetHey:Add, GroupBox, x10 y164 w212 h124, % "    辅助选项  "
Gui, SetHey:Add, Text, x22 y212 w138 h20, 默认存储路径:
Gui, SetHey:Add, Button, gGifSavePathSelect x111 y209 w86 h22, % " 更改路径..."
Gui, SetHey:Add, CheckBox, vNoIconScript x20 y261 w100 h22 Checked%NoIconScript%, 隐藏托盘图标
Gui, SetHey:Add, CheckBox, vCurPrompt x124 y261 w96 h22 Checked%CurPrompt%, 录制鼠标提示
Gui, SetHey:Add, Button, gSubset x136 y293 w80 h24, 应用
Gui, SetHey:Add, Button, gRestoreDefault x16 y293 w80 h24, 恢复默认
Gui, SetHey:Font, s8
Gui, SetHey:Add, Edit, gGifSavePathSelect x18 y235 w196 h22, % GifSavePath
GuiControl, SetHey:, StopREC, % StopREC
GuiControl, SetHey:, REC, % REC
GuiControl, SetHey:, SaveClip, % SaveClip
GuiControl, SetHey:, Frame, % Frame
GuiControl, SetHey:, EditGif, % EditGif
GuiControl, SetHey:, SaveGif, % SaveGif
Gui, SetHey: Show, w232 h325, 全局快捷键
ChangeWindowIcon("shell32.dll",WinExist("ahk_class AutoHotkeyGUI"),317)
Return

SetHeyGuiClose:
Hotkey, % REC, Toggle
Hotkey, % SaveClip, Toggle
Hotkey, % StopREC, Toggle
Hotkey, % Frame, Toggle
Hotkey, % EditGif, Toggle
Hotkey, % SaveGif, Toggle
Gui, SetHey:Destroy
Return

Subset:
Gui, SetHey:Submit, NoHide
Iniwrite, % REC, GifCam.ini, key, REC
Iniwrite, % SaveClip, GifCam.ini, key, SaveClip
Iniwrite, % StopREC, GifCam.ini, key, StopREC
Iniwrite, % Frame, GifCam.ini, key, Frame
Iniwrite, % EditGif, GifCam.ini, key, EditGif
Iniwrite, % SaveGif, GifCam.ini, key, SaveGif
Iniwrite, % NoIconScript, GifCam.ini, key, NoIconScript
Iniwrite, % CurPrompt, GifCam.ini, key, CurPrompt
Reload

GifSavePathSelect:
Gui, -AlwaysOnTop
GifSavePathCache := GifSavePath
SetTimer, Recursive2, -100
GifSavePath := SelectFolderEx( A_Desktop, "请选择需要自动储存Gif的保存路径" , 0, "选择文件夹" )
if (GifSavePath = "")
GifSavePath := GifSavePathCache

Iniwrite, % GifSavePath, GifCam.ini, key, GifSavePath
Gui, SetHey:Destroy
Goto, GifSavePathJump
Return

Recursive2:
ChangeWindowIcon("shell32.dll",WinExist("ahk_class #32770"),4)
if WinExist("ahk_class #32770")
Goto ClearToolTip
;ToolTip, 递归调用异步等待窗口加图标
SetTimer, Recursive2, -1
Return

RestoreDefault:
FileDelete, %A_ScriptDir%\GifCam.ini
Reload
;------------------------------ 快捷键 ------------------------------
REC: ;录制/暂停
WinActivate, ahk_class TGifCamForm
Control, Check, ,TButton4, ahk_class TGifCamForm
if (CurPrompt=1)
Goto, CurPromptToggle
Return
 
StopREC: ;停止录制判断
WinGetTitle, TGifCamForm_Title, ahk_class TGifCamForm
Sleep 110
Goto, JudgeREC
Return

Frame: ;单帧
WinActivate, ahk_class TGifCamForm
Control, Check, ,TButton3, ahk_class TGifCamForm
Return

EditGif: ;编辑Gif
WinActivate, ahk_class TGifCamForm
Control, Check, ,TButton1, ahk_class TGifCamForm
Return

SaveGif: ;保存Gif
WinActivate, ahk_class TGifCamForm
Control, Check, ,TButton2, ahk_class TGifCamForm
Return

JudgeREC:
WinGetTitle, TGifCamForm_Title2, ahk_class TGifCamForm ; 停止录制
if (TGifCamForm_Title != TGifCamForm_Title2) {
		WinActivate, ahk_class TGifCamForm
		Control, Check, ,TButton4, ahk_class TGifCamForm
	if (CurPrompt=1)
	Goto, CurPromptToggle
} Return
;----------------------------- 修改图标和生成按钮相关 -----------------------------
; 启动时计算生成按钮和坐标
GetButtonGuiPos(HWND) {
	if !WinExist("ahk_id " . hwnd)
		Return {}
	WinGetPos, hX, hY, hW, hH, % "ahk_id " . hwnd
	ControlGetPos , TPanel1_X, TPanel1_Y, TPanel1_Width, TPanel1_Height, TPanel1, % "ahk_id " . hwnd
	ControlGetPos , TButton4_X, TButton4_Y, TButton4_Width, TButton4_Height, TButton4, % "ahk_id " . hwnd
	ControlGetPos , TButton2_X, TButton2_Y, TButton2_Width, TButton2_Height, TButton2, % "ahk_id " . hwnd
	Return {x:Hx+TPanel1_Width+13*(A_ScreenDPI/96),y:hY+(hH-TPanel1_Height)+(TPanel1_Y-TButton4_Y)+TButton2_Height*4+11*(A_ScreenDPI/96),w:TButton2_Width,h:TButton2_Height}
}

; 修改窗口标题图标的函数
ChangeWindowIcon(IconFile, hWnd:="", IconNumber:=1, IconSize:=128) {    ;ico图标文件IconNumber和IconSize不用填,如果是icl图标库需要填
	hWnd :=hWnd?hWnd:WinExist("A")
	if (!hWnd)
		Return "窗口不存在!"
	if not IconFile~="\.ico$"
		hIcon := LoadIcon(IconFile, IconNumber, IconSize)
	else
		hIcon := DllCall("LoadImage", uint, 0, str, IconFile, uint, 1, int, 0, int, 0, uint, LR_LOADFROMFILE:=0x10)
	if (!hIcon)
		Return "图标文件不存在!"
	SendMessage, WM_SETICON:=0x80, ICON_SMALL2:=0, hIcon,, ahk_id %hWnd%  ; 设置窗口的小图标
	;;SendMessage, STM_SETICON:=0x0170, hIcon, 0,, Ahk_ID %hWnd%
	SendMessage, WM_SETICON:=0x80, ICON_BIG:=1   , hIcon,, ahk_id %hWnd%  ; 将窗口的大图标设置为同一个
}
; 获取exe/dll/icl文件中指定图标找返回
LoadIcon(Filename, IconNumber, IconSize) {
	if DllCall("PrivateExtractIcons"
		, "str", Filename, "int", IconNumber-1, "int", IconSize, "int", IconSize
		, "ptr*", hIcon, "uint*", 0, "uint", 1, "uint", 0, "ptr")
		Return hIcon
}
;-------------------- 自判断隐藏窗口将Gif存入剪贴板 --------------------
SaveClip:
WinGetTitle, TGifCamForm_Title, ahk_class TGifCamForm ; 判断有没有录制内容
if !InStr(TGifCamForm_Title,"区域"){
	ToolTip, 未录制,请录制后再操作, -42*(A_ScreenDPI/96),45*(A_ScreenDPI/96)
	SetTimer, ClearToolTip, -400
	Return
}
Sleep 110
Gosub, JudgeREC
Name_gif := "GIF " A_YYYY "-" A_MM "-" A_DD " " A_Hour "-" A_Min "-" A_Sec ".gif"
SetControlDelay,-1
SetWinDelay,-1
WinMove, ahk_class TGifCamForm,,6666,6666
Control, Check, ,TButton2, ahk_class TGifCamForm
SetTimer, Recursive, -1
WinWait,另存为,,2
WinActivate, ahk_class #32770
ControlSetText, Edit1, % GifSavePath "\" Name_gif
	if A_OSVersion in WIN_7,WIN_VISTA,WIN_2003,WIN_XP,WIN_2000
		AnNiuHao=1
	else
		AnNiuHao=2
Control, Check, ,button%AnNiuHao%, 另存为
WinWait, ahk_class TProgressForm, , 3
WinActivate, ahk_class TProgressForm
	if WinActive("ahk_class TProgressForm")
	  WinWaitClose, ahk_class TProgressForm
		if FileExist(GifSavePath "\" Name_gif) {
			Gosub, GiftoClip
			ClipWait, 3, 1
			ToolTip, 动图已同步到剪贴板
		} else
			ToolTip, 等待超时 或者 未知错误
Sleep 1500
WinClose, ahk_class TGifCamForm
Return

Recursive:
WinMove, ahk_class #32770,,6666,6666
if WinExist("ahk_class #32770")
Goto ClearToolTip
;ToolTip, 递归调用异步执行
SetTimer, Recursive, -1
Return

ClearToolTip:
ToolTip
Return
;------------------------- WinClip函数将Gif存入剪贴板 -------------------------
GiftoClip:
ImageFile = % GifSavePath "\" Name_gif
if !RegExMatch(ImageFile, "i)^(https?|ftp)://") {
Loop, %ImageFile%
ImageFile := A_LoopFileLongPath
}
html =
(
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD></HEAD>
<BODY><!--StartFragment--><IMG src="%ImageFile%"><!--EndFragment--></BODY>
</HTML>
)
WinClip.Clear()
WinClip.SetHTML( html )
if RegExMatch(ImageFile, "i)^(https?|ftp)://")
Return
WinClip.SetFiles( ImageFile )
WinClip.SetBitmap( ImageFile )
Return
;---------------------------- 录制鼠标提示功能 ----------------------------
~LButton::
~RButton::
~MButton::
t:=-Round(oldt)+(oldt:=A_TickCount)
if (t<100 || t>300) {
	SetTimer, ShuaXin, 1
	Return
} else {oldt:=0
	GUi, Font, cFF5F5F
	GuiControl, Font, TextColor
	SetTimer, ShuaXin, 20
	SetTimer, GuiHide, -200
} Return

~LButton Up::
~RButton Up::
~MButton Up::
SetTimer, GuiHide, -200
Return

ShuaXin:
MouseGetPos, MouseGuiX, MouseGuiY
GuiX := MouseGuiX - 45
GuiY := MouseGuiY - 45
Gui, Show, x%GuiX% y%GuiY% NA
Return

GuiHide:
SetTimer, ShuaXin, Off
GUi, Font, cfffc00
GuiControl, Font, TextColor
Gui, Show, Hide
Return

CurPromptToggle:
Hotkey, ~LButton, Toggle
Hotkey, ~RButton, Toggle
Hotkey, ~MButton, Toggle
Hotkey, ~LButton Up, Toggle
Hotkey, ~RButton Up, Toggle
Hotkey, ~MButton Up, Toggle
Return
;--------------------- 只能用鼠标识别解决点击标题栏按钮丢失Bug ---------------------
#IfWinActive ahk_class TGifCamForm
~LButton Up::
;CoordMode, Mouse, Screen
MouseGetPos, x, y,, Control
SendMessage, 0x84,, (x & 0xFFFF) | (y & 0xFFFF) << 16
if Control in TButton2,TButton4
{
Goto Label_MenuContext_Explorer
} Else if (ErrorLevel = 2) {
	Winset, Top, , ahk_class TGifCamForm
	Gui, TGifCam:+AlwaysOnTop
} Return
#IfWinActive
;=============== 下面是鼠标左键添加一级菜单的函数 ===============
Label_MenuContext_Explorer: 
If not WinExist( "ahk_class #32768" )
	Return

Global MenuContext_NoClicked_AddedItem := "-> MenuContext: Added items have not been clicked <-"
Global MenuContext_Separator := "-> MenuContext: Separator <-" 
Global MenuContext_Item := "-> MenuContext: Standard Item <-"

InsertItemsAtPosition := 14
ArrayToAddItems := { }
ArrayToAddItems.Push( Fct_MenuContext_Separator() )
ArrayToAddItems.Push( Fct_MenuContext_Item( "快捷键设置" ) )
TargetProgram_Classes := [ "TGifCamForm" ]
ClickedItem := Fct_Get_ClickedItem_MenuContext_AddedItems( TargetProgram_Classes, InsertItemsAtPosition, ArrayToAddItems* )

if ( ClickedItem = "快捷键设置" )
Goto SetHey
Return 

Fct_MenuContext_Separator() {
	Return { Type: MenuContext_Separator }
}
Fct_MenuContext_Item( Name ) {
	Return { Type: MenuContext_Item, Name: Name }
}
; Writed by  Nico.Godvician  /  Code Opensource - CC: BY-NC-SA 2.0  –> Copy thsee lines
; Pubished:  2019/09/21 –>     ;被改成了鼠标左键添加一级菜单  https://www.autohotkey.com/boards/viewtopic.php?f=76&t=38579&p=291014#p290862
Fct_Get_ClickedItem_MenuContext_AddedItems( TargetProgram_Classes, InsertItemsAt_Position, ArrayOf_Items* ) {
For each, ProgramClass in TargetProgram_Classes 
	{
		If Program_Handle := WinActive( "ahk_class " ProgramClass )
			Break
	}
	If not Program_Handle
		Return "-> Not into the right program <-"

	WinWait, ahk_class #32768
	SendMessage, 0x1E1, False, False 
	MenuContext_Handle := ErrorLevel

	Static MF_SEPARATOR := 0x800
	Static MF_STRING := 0x0
	Static MF_POPUP := 0x10
	Static MF_BYPOSITION := 0x400 

	For each, ItemToAdd in ArrayToAdd_Items :=  ArrayOf_Items
	{
		ItemToAdd.Position := InsertItemsAt_Position-1 + A_Index-1
		If ( ItemToAdd.Type == MenuContext_Separator ) {
			DllCall( "User32\InsertMenu"
					,"UPtr", MenuContext_Handle
					,"UInt", ItemToAdd.Position
					,"UInt", MF_SEPARATOR + MF_BYPOSITION
					,"UPtr", False
					,"UInt", False )
		} Else If ( ItemToAdd.Type == MenuContext_Item ) {
			DllCall( "User32\InsertMenu" 
					,"UPtr", MenuContext_Handle
					,"UInt", ItemToAdd.Position
					,"UInt", MF_STRING + MF_BYPOSITION
					,"UPtr", False 
					,"Str", ItemToAdd.Name )
			For each, ItemOfSubmenu in AddSubmenu.Items 
			{
				If ( ItemOfSubmenu == MenuContext_Separator ) 
					DllCall( "User32\AppendMenu"
							,"UPtr", AddSubmenu.Handle
							,"UInt", MF_SEPARATOR
							,"UPtr", False, "UInt", False )
				Else
					DllCall( "User32\AppendMenu"
							,"UPtr", AddSubmenu.Handle
							,"UInt", MF_STRING
							,"UPtr", False
							,"Str", ItemOfSubmenu )
			}
		}
	}
	KeyWait, LButton, D
	While not GetKeyState( "LButton" ) 
	CoordMode, Mouse, Screen
	MouseGetPos, MouseScreenX, MouseScreenY
	MousePointScreen := x := MouseScreenX  | y := ( MouseScreenY << 32 ) 
	WinDPIMultiplicator := A_ScreenDPI/96
	For each, AddedItemInMenu in ArrayOfAdded_Items := ArrayOf_Items 
	{
		If ( AddedItemInMenu.Type == MenuContext_Separator ) {
			VarSetCapacity( ItemRectangle, 16, 0 )
			isFilledRectangle := DLLCall( "User32\GetMenuItemRect"
									,"UPtr", Program_Handle
									,"UPtr", MenuContext_Handle
									,"UInt", AddedItemInMenu.Position
									,"UPtr", &ItemRectangle )
		} Else If ( AddedItemInMenu.Type == MenuContext_Item ) {
			VarSetCapacity( ItemRectangle, 16, 0 )
			isFilledRectangle := DLLCall( "User32\GetMenuItemRect"  
									,"UPtr", Program_Handle
									,"UPtr", MenuContext_Handle
									,"UInt", AddedItemInMenu.Position 
									,"UPtr", &ItemRectangle )
			If isFilledRectangle 
			and isPointIntoRectangle := DllCall( "User32\PtInRect", "UPtr", &ItemRectangle, "Int64", MousePointScreen )
			Return AddedItemInMenu.Name
		} 
	}
  Return MenuContext_NoClicked_AddedItem
}
;=============== 下面是Class Dock的类与函数 ===============
/*
Class Dock
Attach a window to another
Author
Soft (visionary1 예지력)
version
0.1 (2017.04.20)
0.2 (2017.05.06)
0.2.1 (2017.05.07)
0.2.1.1 bug fixed (2017.05.09)
0.2.2 testing multiple docks... (2017.05.09)
0.2.3 adding relative (2018.12.16)
License
WTFPL (http://wtfpl.net/)
Dev env
Windows 10 pro x64
AutoHotKey H v1.1.25.01 32bit
To Do...
Multiple Dock, group windows...
thanks to
Helgef for overall coding advices
*/
class Dock
{
	static EVENT_OBJECT_LOCATIONCHANGE := 0x800B
		, EVENT_OBJECT_FOCUS := 0x8005, EVENT_OBJECT_DESTROY := 0x8001
		, EVENT_MIN := 0x00000001, EVENT_MAX := 0x7FFFFFFF ;for debug
		, EVENT_SYSTEM_FOREGROUND := 0x0003
/*
Instance := new Dock(Host hwnd, Client hwnd, [Callback], [CloseCallback])
Host hwnd
hwnd of a Host window
Client hwnd
hwnd of a window that follows Host window (window that'll be attached to a Host window)
[Callback]
a func object, or a bound func object
if omitted, default EventsHandler will be used, which is hard-coded in 'Dock.EventsHandler'
To construct your own events handler, I advise you to see Dock.EventsHandler first
[CloseCallback]
a func object, or a bound func object
called when Host window is destroyed, see 'Dock Example.ahk' for practical usuage
*/
	__New(Host, Client, Callback := "", CloseCallback := ""){
	this.hwnd := []
	this.hwnd.Host := Host
	this.hwnd.Client := Client
	WinSet, ExStyle, +0x80, % "ahk_id " this.hwnd.Host

	this.Bound := []

	this.Callback := IsObject(Callback) ? Callback : ObjBindMethod(Dock.EventsHandler, "Calls")
	this.CloseCallback := IsFunc(CloseCallback) || IsObject(CloseCallback) ? CloseCallback

	this.hookProcAdr := RegisterCallback("_DockHookProcAdr",,, &this)

/*
idProcess
*/
	;WinGet, idProcess, PID, % "ahk_id " . this.hwnd.Host
	idProcess := 0

/*
idThread
*/
	;idThread := DllCall("GetWindowThreadProcessId", "Ptr", this.hwnd.Host, "Int", 0)
	idThRead := 0

	DllCall("CoInitialize", "Int", 0)

	this.Hook := DllCall("SetWinEventHook"
		, "UInt", Dock.EVENT_SYSTEM_FOREGROUND ;eventMin
		, "UInt", Dock.EVENT_OBJECT_LOCATIONCHANGE ;eventMax
		, "Ptr", 0 ;hmodWinEventProc
		, "Ptr", this.hookProcAdr ;lpfnWinEventProc
		, "UInt", idProcess ;idProcess
		, "UInt", idThread ;idThread
		, "UInt", 0) ;dwFlags
}

/*
Instance.Unhook()
unhooks Dock and frees memory
*/
Unhook(){
	DllCall("UnhookWinEvent", "Ptr", this.Hook)
	DllCall("CoUninitialize")
	DllCall("GlobalFree", "Ptr", this.hookProcAdr)
	this.Hook := ""
	this.hookProcAdr := ""
	this.Callback := ""
	WinSet, ExStyle, -0x80, % "ahk_id " this.hwnd.Host
}

__Delete(){
	this.Delete("Bound")

	if (this.Hook)
		this.Unhook()

	this.CloseCallback := ""
}

/*
provisional
*/
Add(hwnd, pos := ""){
	static last_hwnd := 0

	this.Bound.Push( new this( !NumGet(&this.Bound, 4*A_PtrSize) ? this.hwnd.Client : last_hwnd, hwnd ) )

	if pos Contains Top,Bottom,R,Right,L,Left,Relative
		this.Bound[NumGet(&this.Bound, 4*A_PtrSize)].Position(pos)

	last_hwnd := hwnd
}

/*
Instance.Position(pos)
pos - sets position to dock client window
Top - sets to Top side of the host window
Bottom - sets to bottom side of the host window
R or Right - right side
L or Left - left side
*/
Position(pos){
	this.pos := pos
	return this.EventsHandler.EVENT_OBJECT_LOCATIONCHANGE(this, "host")
}

/*
Default EventsHandler
*/
class EventsHandler extends Dock.HelperFunc
{
	Calls(self, hWinEventHook, event, hwnd){
	Critical
	if (hwnd = self.hwnd.Host){
		return this.Host(self, event)
	}

	if (hwnd = self.hwnd.Client){
		return this.Client(self, event)
	}
}

Host(self, event){
	if (event = Dock.EVENT_SYSTEM_FOREGROUND){
		return this.EVENT_SYSTEM_FOREGROUND(self.hwnd.Client)
	}

	if (event = Dock.EVENT_OBJECT_LOCATIONCHANGE){
		return this.EVENT_OBJECT_LOCATIONCHANGE(self, "host")
	}

	if (event = Dock.EVENT_OBJECT_DESTROY){
		self.Unhook()
		if (IsFunc(self.CloseCallback) || IsObject(self.CloseCallback))
			return self.CloseCallback()
	}
}

Client(self, event){
	if (event = Dock.EVENT_SYSTEM_FOREGROUND){
		return this.EVENT_SYSTEM_FOREGROUND(self.hwnd.Host)
	}

	if (event = Dock.EVENT_OBJECT_LOCATIONCHANGE){
		return this.EVENT_OBJECT_LOCATIONCHANGE(self, "client")
	}
}

/*
Called when host window got focus
without this, client window can't be showed (can't set to top)
*/
EVENT_SYSTEM_FOREGROUND(hwnd){
	return this.WinSetTop(hwnd)
}

/*
Called when host window is moved
*/
EVENT_OBJECT_LOCATIONCHANGE(self, via){
	Host := this.WinGetPos(self.hwnd.Host)
	Client := this.WinGetPos(self.hwnd.Client)
	TButtonHost := this.GetTButton2Pos(self.hwnd.Client) ; 追加
	TPanelClient := this.GetTPanel1Pos(self.hwnd.Client) ; 追加

	if InStr(self.pos, "Relative"){
		if (via = "host"){
			return this.MoveWindow(self.hwnd.Client ;hwnd
				, Host.x + StrSplit(self.pos,A_Space).2 ;x
				, Host.y + StrSplit(self.pos,A_Space).3 ;y
				, Client.w ;width
				, Client.h) ;height
		}

		if (via = "client"){
			return this.MoveWindow(self.hwnd.Host ;hwnd
				, Host.x ;x
				, Host.y ;y
				, Host.w ;width
				, Host.h) ;height
		}
	}

	if InStr(self.pos, "Top"){
		if (via = "host"){
			return this.MoveWindow(self.hwnd.Client ;hwnd
				, Host.x ;x
				, Host.y - Client.h ;y
				, Client.w ;width
				, Client.h) ;height
		}

		if (via = "client"){
			return this.MoveWindow(self.hwnd.Host ;hwnd
				, Client.x ;x
				, Client.y + Client.h ;y
				, Host.w ;width
				, Host.h) ;height
		}
	}

	if InStr(self.pos, "Bottom"){
		if (via = "host"){
			return this.MoveWindow(self.hwnd.Client ;hwnd
				, Host.x ;x
				, Host.y + Host.h ;y
				, Client.w ;width
				, Client.h) ;height
		}

		if (via = "client"){
			return this.MoveWindow(self.hwnd.Host ;hwnd
				, Client.x ;x
				, Client.y - Host.h ;y
				, Host.w ;width
				, Host.h) ;height
		}
	}

	if InStr(self.pos, "R"){
		if (via = "host"){
			return this.MoveWindow(self.hwnd.Client ;hwnd
				, Host.x + Host.w ;x
				, Host.y ;y
				, Client.w ;width
				, Client.h) ;height
		}

		if (via = "client"){
			return this.MoveWindow(self.hwnd.Host ;hwnd
				, Client.x - Host.w ;x
				, Client.y ;y
				, Host.w ;width
				, Host.h) ;height
		}
	}

	if InStr(self.pos, "L"){
		if (via = "host"){
			return this.MoveWindow(self.hwnd.Client ;hwnd
				, Host.x - Client.w ;x
				, Host.y ;y
				, Client.w ;width
				, Client.h) ;height
		}

		if (via = "client"){
			return this.MoveWindow(self.hwnd.Host ;hwnd
				, Client.x + Client.w ;x
				, Client.y ;y
				, Host.w ;width
				, Host.h) ;height
		}
	}


	if InStr(self.pos, "C"){   ;自定义,计算按钮大小并生成
		if (via = "client"){
			return this.MoveWindow(self.hwnd.Host	   	;hwnd
				, Client.h<(TButtonHost.h+Client.h-TPanelClient.h)?Client.x + Client.w:Client.h<(TButtonHost.h*6+14*(A_ScreenDPI/96))?Client.x+TPanelClient.w-TButtonHost.w:Client.x+TPanelClient.w+13*(A_ScreenDPI/96)   ;x
				, Client.h<(TButtonHost.h+Client.h-TPanelClient.h)?Client.y:Client.h<(TButtonHost.h*6+14*(A_ScreenDPI/96))?Client.y+Client.h-TPanelClient.h:Client.y+Client.h-TPanelClient.h+TButtonHost.h*4+4*(A_ScreenDPI/96)  	;y
				, TButtonHost.w		;width
				, TButtonHost.h)	   	;height
		}
	}

}
}

class HelperFunc
{
	WinGetPos(hwnd){
	WinGetPos, hX, hY, hW, hH, % "ahk_id " . hwnd
	return {x: hX, y: hY, w: hW, h: hH}
}

GetTPanel1Pos(hwnd){
	ControlGetPos , TPanel1_X, TPanel1_Y, TPanel1_Width, TPanel1_Height, TPanel1, % "ahk_id " . hwnd
	return {x: TPanel1_X, y: TPanel1_Y, w: TPanel1_Width, h: TPanel1_Height}
}

GetTButton2Pos(hwnd){
	ControlGetPos , TButton4_X, TButton4_Y, TButton4_Width, TButton4_Height, TButton4, % "ahk_id " . hwnd
	ControlGetPos , TPanel_X, TPanel_Y, TPanel_Width, TPanel_Height, TButton2, % "ahk_id " . hwnd
	return {x: TPanel_X, y: TPanel_Y, w: TPanel_Width, h: TPanel_Height,d:TPanel_Y-TButton4_Y}
}

WinSetTop(hwnd){
	WinSet, AlwaysOnTop, On, % "ahk_id " . hwnd
	;WinSet, AlwaysOnTop, Off, % "ahk_id " . hwnd
	Gui, TGifCam:+AlwaysOnTop
}

MoveWindow(hwnd, x, y, w, h){
	return DllCall("MoveWindow", "Ptr", hwnd, "Int", x, "Int", y, "Int", w, "Int", h, "Int", 1)
}

Run(Target){
	Try Run, % Target,,, OutputVarPID
	catch,
		throw, "Couldn't Run " Target
	WinWait, % "ahk_pid " OutputVarPID
	return WinExist("ahk_pid " OutputVarPID)
		}
	}
}

_DockHookProcAdr(hWinEventHook, event, hwnd, idObject, idChild, dwEventThread, dwmsEventTime){
	this := Object(A_EventInfo)
	this.Callback.Call(this, hWinEventHook, event, hwnd)
}
;================= 下面是WinClip的类和函数 =================

class WinClip_base{
__Call( aTarget, aParams* ) {
if ObjHasKey( WinClip_base, aTarget )
return WinClip_base[ aTarget ].( this, aParams* )
throw Exception( "Unknown function '" aTarget "' requested from object '" this.__Class "'", -1 )
}Err( msg ){
throw Exception( this.__Class " : " msg ( A_LastError != 0 ? "`n" this.ErrorFormat( A_LastError ) : "" ), -2 )
}ErrorFormat( error_id ){
VarSetCapacity(msg,1000,0)
if !len := DllCall("FormatMessageW"
,"UInt",FORMAT_MESSAGE_FROM_SYSTEM := 0x00001000 | FORMAT_MESSAGE_IGNORE_INSERTS := 0x00000200
,"Ptr",0
,"UInt",error_id
,"UInt",0
,"Ptr",&msg
,"UInt",500)
return
return 	strget(&msg,len)
}
}class WinClipAPI_base extends WinClip_base{
__Get( name ){
if !ObjHasKey( this, initialized )
this.Init()
else
throw Exception( "Unknown field '" name "' requested from object '" this.__Class "'", -1 )
}
}class WinClipAPI extends WinClip_base{
memcopy( dest, src, size ){
return DllCall( "msvcrt\memcpy", "ptr", dest, "ptr", src, "uint", size )
}GlobalSize( hObj ){
return DllCall( "GlobalSize", "Ptr", hObj )
}GlobalLock( hMem ){
return DllCall( "GlobalLock", "Ptr", hMem )
}GlobalUnlock( hMem ){
return DllCall( "GlobalUnlock", "Ptr", hMem )
}GlobalAlloc( flags, size ){
return DllCall( "GlobalAlloc", "Uint", flags, "Uint", size )
}OpenClipboard(){
return DllCall( "OpenClipboard", "Ptr", 0 )
}CloseClipboard(){
return DllCall( "CloseClipboard" )
}SetClipboardData( format, hMem ){
return DllCall( "SetClipboardData", "Uint", format, "Ptr", hMem )
}GetClipboardData( format ){
return DllCall( "GetClipboardData", "Uint", format ) 
}EmptyClipboard(){
return DllCall( "EmptyClipboard" )
}EnumClipboardFormats( format ){
return DllCall( "EnumClipboardFormats", "UInt", format )
}CountClipboardFormats(){
return DllCall( "CountClipboardFormats" )
}GetClipboardFormatName( iFormat ){
size := VarSetCapacity( bufName, 255*( A_IsUnicode ? 2 : 1 ), 0 )
DllCall( "GetClipboardFormatName", "Uint", iFormat, "str", bufName, "Uint", size )
return bufName
}GetEnhMetaFileBits( hemf, ByRef buf ){
if !( bufSize := DllCall( "GetEnhMetaFileBits", "Ptr", hemf, "Uint", 0, "Ptr", 0 ) )
return 0
VarSetCapacity( buf, bufSize, 0 )
if !( bytesCopied := DllCall( "GetEnhMetaFileBits", "Ptr", hemf, "Uint", bufSize, "Ptr", &buf ) )
return 0
return bytesCopied
}SetEnhMetaFileBits( pBuf, bufSize ){
return DllCall( "SetEnhMetaFileBits", "Uint", bufSize, "Ptr", pBuf )
}DeleteEnhMetaFile( hemf ){
return DllCall( "DeleteEnhMetaFile", "Ptr", hemf )
}ErrorFormat(error_id){
VarSetCapacity(msg,1000,0)
if !len := DllCall("FormatMessageW"
,"UInt",FORMAT_MESSAGE_FROM_SYSTEM := 0x00001000 | FORMAT_MESSAGE_IGNORE_INSERTS := 0x00000200
,"Ptr",0
,"UInt",error_id
,"UInt",0
,"Ptr",&msg
,"UInt",500)
return
return 	strget(&msg,len)
}IsInteger( var ){
if var is integer
return True
else 
return False
}LoadDllFunction( file, function ){
if !hModule := DllCall( "GetModuleHandleW", "Wstr", file, "UPtr" )
hModule := DllCall( "LoadLibraryW", "Wstr", file, "UPtr" )
ret := DllCall("GetProcAddress", "Ptr", hModule, "AStr", function, "UPtr")
return ret
}SendMessage( hWnd, Msg, wParam, lParam ){
static SendMessageW
If not SendMessageW
SendMessageW := this.LoadDllFunction( "user32.dll", "SendMessageW" )
ret := DllCall( SendMessageW, "UPtr", hWnd, "UInt", Msg, "UPtr", wParam, "UPtr", lParam )
return ret
}GetWindowThreadProcessId( hwnd ){
return DllCall( "GetWindowThreadProcessId", "Ptr", hwnd, "Ptr", 0 )
}WinGetFocus( hwnd ){
GUITHREADINFO_cbsize := 24 + A_PtrSize*6
VarSetCapacity( GuiThreadInfo, GUITHREADINFO_cbsize, 0 )
NumPut(GUITHREADINFO_cbsize, GuiThreadInfo, 0, "UInt")
threadWnd := this.GetWindowThreadProcessId( hwnd )
if not DllCall( "GetGUIThreadInfo", "uint", threadWnd, "UPtr", &GuiThreadInfo )
return 0
return NumGet( GuiThreadInfo, 8+A_PtrSize,"UPtr")
}GetPixelInfo( ByRef DIB ){
bmi := &DIB
biSize := numget( bmi+0, 0, "UInt" )
biSizeImage := numget( bmi+0, 20, "UInt" )
biBitCount := numget( bmi+0, 14, "UShort" )
if ( biSizeImage == 0 ){
biWidth := numget( bmi+0, 4, "UInt" )
biHeight := numget( bmi+0, 8, "UInt" )
biSizeImage := (((( biWidth * biBitCount + 31 ) & ~31 ) >> 3 ) * biHeight )
numput( biSizeImage, bmi+0, 20, "UInt" )
}p := numget( bmi+0, 32, "UInt" )
if ( p == 0 && biBitCount <= 8 )
p := 1 << biBitCount
p := p * 4 + biSize + bmi
return p
}Gdip_Startup(){
if !DllCall( "GetModuleHandleW", "Wstr", "gdiplus", "UPtr" )
DllCall( "LoadLibraryW", "Wstr", "gdiplus", "UPtr" )
VarSetCapacity(GdiplusStartupInput , 3*A_PtrSize, 0), NumPut(1,GdiplusStartupInput ,0,"UInt")
DllCall("gdiplus\GdiplusStartup", "Ptr*", pToken, "Ptr", &GdiplusStartupInput, "Ptr", 0)
return pToken
}Gdip_Shutdown(pToken){
DllCall("gdiplus\GdiplusShutdown", "Ptr", pToken)
if hModule := DllCall( "GetModuleHandleW", "Wstr", "gdiplus", "UPtr" )
DllCall("FreeLibrary", "Ptr", hModule)
return 0
}StrSplit(str,delim,omit = ""){
if (strlen(delim) > 1){
StringReplace,str,str,% delim,ƒ,1
delim = ƒ
}ra := Array()
loop, parse,str,% delim,% omit
if (A_LoopField != "")
ra.Insert(A_LoopField)
return ra
}RemoveDubls( objArray ){
while True
{
nodubls := 1
tempArr := Object()
for i,val in objArray
{
if tempArr.haskey( val ){
nodubls := 0
objArray.Remove( i )
break
}tempArr[ val ] := 1
}if nodubls
break
}return objArray
}RegisterClipboardFormat( fmtName ){
return DllCall( "RegisterClipboardFormat", "ptr", &fmtName )
}GetOpenClipboardWindow(){
return DllCall( "GetOpenClipboardWindow" )
}IsClipboardFormatAvailable( iFmt ){
return DllCall( "IsClipboardFormatAvailable", "UInt", iFmt )
}GetImageEncodersSize( ByRef numEncoders, ByRef size ){
return DllCall( "gdiplus\GdipGetImageEncodersSize", "Uint*", numEncoders, "UInt*", size )
}GetImageEncoders( numEncoders, size, pImageCodecInfo ){
return DllCall( "gdiplus\GdipGetImageEncoders", "Uint", numEncoders, "UInt", size, "Ptr", pImageCodecInfo )
}GetEncoderClsid( format, ByRef CLSID ){
if !format
return 0
format := "image/" format
this.GetImageEncodersSize( num, size )
if ( size = 0 )
return 0
VarSetCapacity( ImageCodecInfo, size, 0 )
this.GetImageEncoders( num, size, &ImageCodecInfo )
loop,% num
{
pici := &ImageCodecInfo + ( 48+7*A_PtrSize )*(A_Index-1)
pMime := NumGet( pici+0, 32+4*A_PtrSize, "UPtr" )
MimeType := StrGet( pMime, "UTF-16")
if ( MimeType = format ){
VarSetCapacity( CLSID, 16, 0 )
this.memcopy( &CLSID, pici, 16 )
return 1
}
}return 0
}
}
class WinClip extends WinClip_base
{
__New(){
this.isinstance := 1
this.allData := ""
}_toclipboard( ByRef data, size ){
if !WinClipAPI.OpenClipboard()
return 0
offset := 0
lastPartOffset := 0
WinClipAPI.EmptyClipboard()
while ( offset < size ){
if !( fmt := NumGet( data, offset, "UInt" ) )
break
offset += 4
if !( dataSize := NumGet( data, offset, "UInt" ) )
break
offset += 4
if ( ( offset + dataSize ) > size )
break
if !( pData := WinClipAPI.GlobalLock( WinClipAPI.GlobalAlloc( 0x0042, dataSize ) ) ){
offset += dataSize
continue
}
WinClipAPI.memcopy( pData, &data + offset, dataSize )
if ( fmt == this.ClipboardFormats.CF_ENHMETAFILE )
pClipData := WinClipAPI.SetEnhMetaFileBits( pData, dataSize )
else
pClipData := pData
if !pClipData
continue
WinClipAPI.SetClipboardData( fmt, pClipData )
if ( fmt == this.ClipboardFormats.CF_ENHMETAFILE )
WinClipAPI.DeleteEnhMetaFile( pClipData )
WinClipAPI.GlobalUnlock( pData )
offset += dataSize
lastPartOffset := offset
}WinClipAPI.CloseClipboard()
return lastPartOffset
}

_fromclipboard( ByRef clipData ){
if !WinClipAPI.OpenClipboard()
return 0
nextformat := 0
objFormats := object()
clipSize := 0
formatsNum := 0
while ( nextformat := WinClipAPI.EnumClipboardFormats( nextformat ) ){
if this.skipFormats.hasKey( nextformat )
continue
if ( dataHandle := WinClipAPI.GetClipboardData( nextformat ) ){
pObjPtr := 0, nObjSize := 0
if ( nextFormat == this.ClipboardFormats.CF_ENHMETAFILE ){
if ( bufSize := WinClipAPI.GetEnhMetaFileBits( dataHandle, hemfBuf ) )
pObjPtr := &hemfBuf, nObjSize := bufSize
}else if ( nSize := WinClipAPI.GlobalSize( WinClipAPI.GlobalLock( dataHandle ) ) )
pObjPtr := dataHandle, nObjSize := nSize
else
continue
if !( pObjPtr && nObjSize )
continue
objFormats[ nextformat ] := { handle : pObjPtr, size : nObjSize }
clipSize += nObjSize
formatsNum++
}
}
structSize := formatsNum*( 4 + 4 ) + clipSize
if !structSize
return 0
VarSetCapacity( clipData, structSize, 0 )
offset := 0
for fmt, params in objFormats
{
NumPut( fmt, &clipData, offset, "UInt" )
offset += 4
NumPut( params.size, &clipData, offset, "UInt" )
offset += 4
WinClipAPI.memcopy( &clipData + offset, params.handle, params.size )
offset += params.size
WinClipAPI.GlobalUnlock( params.handle )
}WinClipAPI.CloseClipboard()
return structSize
}_IsInstance( funcName ){
if !this.isinstance
{
throw Exception( "Error in '" funcName "':`nInstantiate the object first to use this method!", -1 )
return 0
}return 1
}_loadFile( filePath, ByRef Data ){
f := FileOpen( filePath, "r","CP0" )
if !IsObject( f )
return 0
f.Pos := 0
dataSize := f.RawRead( Data, f.Length )
f.close()
return dataSize
}_saveFile( filepath, byRef data, size ){
f := FileOpen( filepath, "w","CP0" )
bytes := f.RawWrite( &data, size )
f.close()
return bytes
}_setClipData( ByRef data, size ){
if !size
return 0
if !ObjSetCapacity( this, "allData", size )
return 0
if !( pData := ObjGetAddress( this, "allData" ) )
return 0
WinClipAPI.memcopy( pData, &data, size )
return size
}_getClipData( ByRef data ){
if !( clipSize := ObjGetCapacity( this, "allData" ) )
return 0
if !( pData := ObjGetAddress( this, "allData" ) )
return 0
VarSetCapacity( data, clipSize, 0 )
WinClipAPI.memcopy( &data, pData, clipSize )
return clipSize
}__Delete(){
ObjSetCapacity( this, "allData", 0 )
return
}

_parseClipboardData( ByRef data, size ){
offset := 0
formats := object()
while ( offset < size ){
if !( fmt := NumGet( data, offset, "UInt" ) )
break
offset += 4
if !( dataSize := NumGet( data, offset, "UInt" ) )
break
offset += 4
if ( ( offset + dataSize ) > size )
break
params := { name : this._getFormatName( fmt ), size : dataSize }
ObjSetCapacity( params, "buffer", dataSize )
pBuf := ObjGetAddress( params, "buffer" )
WinClipAPI.memcopy( pBuf, &data + offset, dataSize )
formats[ fmt ] := params
offset += dataSize
}return formats
}_compileClipData( ByRef out_data, objClip ){
if !IsObject( objClip )
return 0
;calculating required data size
clipSize := 0
for fmt, params in objClip
clipSize += 8 + params.size
VarSetCapacity( out_data, clipSize, 0 )
offset := 0
for fmt, params in objClip
{
NumPut( fmt, out_data, offset, "UInt" )
offset += 4
NumPut( params.size, out_data, offset, "UInt" )
offset += 4
WinClipAPI.memcopy( &out_data + offset, ObjGetAddress( params, "buffer" ), params.size )
offset += params.size
}return clipSize
}
GetFormats(){
if !( clipSize := this._fromclipboard( clipData ) )
return 0
return this._parseClipboardData( clipData, clipSize )
}iGetFormats(){
this._IsInstance( A_ThisFunc )
if !( clipSize := this._getClipData( clipData ) )
return 0
return this._parseClipboardData( clipData, clipSize )
}Snap( ByRef data ){
return this._fromclipboard( data )
}iSnap(){
this._IsInstance( A_ThisFunc )
if !( dataSize := this._fromclipboard( clipData ) )
return 0
return this._setClipData( clipData, dataSize )
}Restore( ByRef clipData ){
clipSize := VarSetCapacity( clipData )
return this._toclipboard( clipData, clipSize )
}iRestore(){
this._IsInstance( A_ThisFunc )
if !( clipSize := this._getClipData( clipData ) )
return 0
return this._toclipboard( clipData, clipSize )
}Save( filePath ){
if !( size := this._fromclipboard( data ) )
return 0
return this._saveFile( filePath, data, size )
}iSave( filePath ){
this._IsInstance( A_ThisFunc )
if !( clipSize := this._getClipData( clipData ) )
return 0
return this._saveFile( filePath, clipData, clipSize )
}Load( filePath ){
if !( dataSize := this._loadFile( filePath, dataBuf ) )
return 0
return this._toclipboard( dataBuf, dataSize )
}iLoad( filePath ){
this._IsInstance( A_ThisFunc )
if !( dataSize := this._loadFile( filePath, dataBuf ) )
return 0
return this._setClipData( dataBuf, dataSize )
}Clear(){
if !WinClipAPI.OpenClipboard()
return 0
WinClipAPI.EmptyClipboard()
WinClipAPI.CloseClipboard()
return 1
}iClear(){
this._IsInstance( A_ThisFunc )
ObjSetCapacity( this, "allData", 0 )
}Copy( timeout = 1, method = 1 ){
this.Snap( data )
this.Clear()    ;clearing the clipboard
if( method = 1 )
SendInput, ^{Ins}
else
SendInput, ^{vk43sc02E} ;ctrl+c
ClipWait,% timeout, 1
if ( ret := this._isClipEmpty() )
this.Restore( data )
return !ret
}iCopy( timeout = 1, method = 1 ){
this._IsInstance( A_ThisFunc )
this.Snap( data )
this.Clear()    ;clearing the clipboard
if( method = 1 )
SendInput, ^{Ins}
else
SendInput, ^{vk43sc02E} ;ctrl+c
ClipWait,% timeout, 1
bytesCopied := 0
if !this._isClipEmpty(){
this.iClear()   ;clearing the variable containing the clipboard data
bytesCopied := this.iSnap()
}this.Restore( data )
return bytesCopied
}Paste( plainText = "", method = 1 ){
ret := 0
if ( plainText != "" ){
this.Snap( data )
this.Clear()
ret := this.SetText( plainText )
}if( method = 1 )
SendInput, +{Ins}
else
SendInput, ^{vk56sc02F} ;ctrl+v
this._waitClipReady( 3000 )
if ( plainText != "" ){
this.Restore( data )
}else
ret := !this._isClipEmpty()
return ret
}
iPaste( method = 1 ){
this._IsInstance( A_ThisFunc )
this.Snap( data )
if !( bytesRestored := this.iRestore() )
return 0
if( method = 1 )
SendInput, +{Ins}
else
SendInput, ^{vk56sc02F}
this._waitClipReady( 3000 )
this.Restore( data )
return bytesRestored
}IsEmpty(){
return this._isClipEmpty()
}iIsEmpty(){
return !this.iGetSize()
}_isClipEmpty(){
return !WinClipAPI.CountClipboardFormats()
}_waitClipReady( timeout = 10000 ){
start_time := A_TickCount
sleep 100
while ( WinClipAPI.GetOpenClipboardWindow() && ( A_TickCount - start_time < timeout ) )
sleep 100
}iSetText( textData ){
if ( textData = "" )
return 0
this._IsInstance( A_ThisFunc )
clipSize := this._getClipData( clipData )
if !( clipSize := this._appendText( clipData, clipSize, textData, 1 ) )
return 0
return this._setClipData( clipData, clipSize )
}SetText( textData ){
if ( textData = "" )
return 0
clipSize :=  this._fromclipboard( clipData )
if !( clipSize := this._appendText( clipData, clipSize, textData, 1 ) )
return 0
return this._toclipboard( clipData, clipSize )
}GetRTF(){
if !( clipSize := this._fromclipboard( clipData ) )
return ""
if !( out_size := this._getFormatData( out_data, clipData, clipSize, "Rich Text Format" ) )
return ""
return strget( &out_data, out_size, "CP0" )
}iGetRTF(){
this._IsInstance( A_ThisFunc )
if !( clipSize := this._getClipData( clipData ) )
return ""
if !( out_size := this._getFormatData( out_data, clipData, clipSize, "Rich Text Format" ) )
return ""
return strget( &out_data, out_size, "CP0" )
}SetRTF( textData ){
if ( textData = "" )
return 0
clipSize :=  this._fromclipboard( clipData )
if !( clipSize := this._setRTF( clipData, clipSize, textData ) )
return 0
return this._toclipboard( clipData, clipSize )
}iSetRTF( textData ){
if ( textData = "" )
return 0
this._IsInstance( A_ThisFunc )
clipSize :=  this._getClipData( clipData )
if !( clipSize := this._setRTF( clipData, clipSize, textData ) )
return 0
return this._setClipData( clipData, clipSize )
}_setRTF( ByRef clipData, clipSize, textData ){
objFormats := this._parseClipboardData( clipData, clipSize )
uFmt := WinClipAPI.RegisterClipboardFormat( "Rich Text Format" )
objFormats[ uFmt ] := object()
sLen := StrLen( textData )
ObjSetCapacity( objFormats[ uFmt ], "buffer", sLen )
StrPut( textData, ObjGetAddress( objFormats[ uFmt ], "buffer" ), sLen, "CP0" )
objFormats[ uFmt ].size := sLen
return this._compileClipData( clipData, objFormats )
}iAppendText( textData ){
if ( textData = "" )
return 0
this._IsInstance( A_ThisFunc )
clipSize := this._getClipData( clipData )
if !( clipSize := this._appendText( clipData, clipSize, textData ) )
return 0
return this._setClipData( clipData, clipSize )
}AppendText( textData ){
if ( textData = "" )
return 0
clipSize :=  this._fromclipboard( clipData )
if !( clipSize := this._appendText( clipData, clipSize, textData ) )
return 0
return this._toclipboard( clipData, clipSize )
}SetHTML( html, source = "" ){
if ( html = "" )
return 0
clipSize :=  this._fromclipboard( clipData )
if !( clipSize := this._setHTML( clipData, clipSize, html, source ) )
return 0
return this._toclipboard( clipData, clipSize )
}iSetHTML( html, source = "" ){
if ( html = "" )
return 0
this._IsInstance( A_ThisFunc )
clipSize := this._getClipData( clipData )
if !( clipSize := this._setHTML( clipData, clipSize, html, source ) )
return 0
return this._setClipData( clipData, clipSize )
}_calcHTMLLen( num ){
while ( StrLen( num ) < 10 )
num := "0" . num
return num
}_setHTML( ByRef clipData, clipSize, htmlData, source ){
objFormats := this._parseClipboardData( clipData, clipSize )
uFmt := WinClipAPI.RegisterClipboardFormat( "HTML Format" )
objFormats[ uFmt ] := object()
encoding := "UTF-8"
htmlLen := StrPut( htmlData, encoding ) - 1   ;substract null
srcLen := 2 + 10 + StrPut( source, encoding ) - 1      ;substract null
StartHTML := this._calcHTMLLen( 105 + srcLen )
EndHTML := this._calcHTMLLen( StartHTML + htmlLen + 76 )
StartFragment := this._calcHTMLLen( StartHTML + 38 )
EndFragment := this._calcHTMLLen( StartFragment + htmlLen )
html =
( Join`r`n
Version:0.9
StartHTML:%StartHTML%
EndHTML:%EndHTML%
StartFragment:%StartFragment%
EndFragment:%EndFragment%
SourceURL:%source%
<html>
<body>
<!--StartFragment-->
%htmlData%
<!--EndFragment-->
</body>
</html>
)
sLen := StrPut( html, encoding )
ObjSetCapacity( objFormats[ uFmt ], "buffer", sLen )
StrPut( html, ObjGetAddress( objFormats[ uFmt ], "buffer" ), sLen, encoding )
objFormats[ uFmt ].size := sLen
return this._compileClipData( clipData, objFormats )
}_appendText( ByRef clipData, clipSize, textData, IsSet = 0 ){
objFormats := this._parseClipboardData( clipData, clipSize )
uFmt := this.ClipboardFormats.CF_UNICODETEXT
str := ""
if ( objFormats.haskey( uFmt ) && !IsSet )
str := strget( ObjGetAddress( objFormats[ uFmt ],  "buffer" ), "UTF-16" )
else
objFormats[ uFmt ] := object()
str .= textData
sLen := ( StrLen( str ) + 1 ) * 2
ObjSetCapacity( objFormats[ uFmt ], "buffer", sLen )
StrPut( str, ObjGetAddress( objFormats[ uFmt ], "buffer" ), sLen, "UTF-16" )
objFormats[ uFmt ].size := sLen
return this._compileClipData( clipData, objFormats )
}_getFiles( pDROPFILES ){
fWide := numget( pDROPFILES + 0, 16, "uchar" )
pFiles := numget( pDROPFILES + 0, 0, "UInt" ) + pDROPFILES
list := ""
while numget( pFiles + 0, 0, fWide ? "UShort" : "UChar" ){
lastPath := strget( pFiles+0, fWide ? "UTF-16" : "CP0" )
list .= ( list ? "`n" : "" ) lastPath
pFiles += ( StrLen( lastPath ) + 1 ) * ( fWide ? 2 : 1 )
}return list
}_setFiles( ByRef clipData, clipSize, files, append = 0, isCut = 0 ){
objFormats := this._parseClipboardData( clipData, clipSize )
uFmt := this.ClipboardFormats.CF_HDROP
if ( append && objFormats.haskey( uFmt ) )
prevList := this._getFiles( ObjGetAddress( objFormats[ uFmt ], "buffer" ) ) "`n"
objFiles := WinClipAPI.StrSplit( prevList . files, "`n", A_Space A_Tab )
objFiles := WinClipAPI.RemoveDubls( objFiles )
if !objFiles.MaxIndex()
return 0
objFormats[ uFmt ] := object()
DROP_size := 20 + 2
for i,str in objFiles
DROP_size += ( StrLen( str ) + 1 ) * 2
VarSetCapacity( DROPFILES, DROP_size, 0 )
NumPut( 20, DROPFILES, 0, "UInt" )  ;offset
NumPut( 1, DROPFILES, 16, "uchar" ) ;NumPut( 20, DROPFILES, 0, "UInt" )
offset := &DROPFILES + 20
for i,str in objFiles
{
StrPut( str, offset, "UTF-16" )
offset += ( StrLen( str ) + 1 ) * 2
}ObjSetCapacity( objFormats[ uFmt ], "buffer", DROP_size )
WinClipAPI.memcopy( ObjGetAddress( objFormats[ uFmt ], "buffer" ), &DROPFILES, DROP_size )
objFormats[ uFmt ].size := DROP_size
prefFmt := WinClipAPI.RegisterClipboardFormat( "Preferred DropEffect" )
objFormats[ prefFmt ] := { size : 4 }
ObjSetCapacity( objFormats[ prefFmt ], "buffer", 4 )
NumPut( isCut ? 2 : 5, ObjGetAddress( objFormats[ prefFmt ], "buffer" ), 0 "UInt" )
return this._compileClipData( clipData, objFormats )
}SetFiles( files, isCut = 0 ){
if ( files = "" )
return 0
clipSize := this._fromclipboard( clipData )
if !( clipSize := this._setFiles( clipData, clipSize, files, 0, isCut ) )
return 0
return this._toclipboard( clipData, clipSize )
}iSetFiles( files, isCut = 0 ){
this._IsInstance( A_ThisFunc )
if ( files = "" )
return 0
clipSize := this._getClipData( clipData )
if !( clipSize := this._setFiles( clipData, clipSize, files, 0, isCut ) )
return 0
return this._setClipData( clipData, clipSize )
}AppendFiles( files, isCut = 0 ){
if ( files = "" )
return 0
clipSize := this._fromclipboard( clipData )
if !( clipSize := this._setFiles( clipData, clipSize, files, 1, isCut ) )
return 0
return this._toclipboard( clipData, clipSize )
}iAppendFiles( files, isCut = 0 ){
this._IsInstance( A_ThisFunc )
if ( files = "" )
return 0
clipSize := this._getClipData( clipData )
if !( clipSize := this._setFiles( clipData, clipSize, files, 1, isCut ) )
return 0
return this._setClipData( clipData, clipSize )
}GetFiles(){
if !( clipSize := this._fromclipboard( clipData ) )
return ""
if !( out_size := this._getFormatData( out_data, clipData, clipSize, this.ClipboardFormats.CF_HDROP ) )
return ""
return this._getFiles( &out_data )
}iGetFiles(){
this._IsInstance( A_ThisFunc )
if !( clipSize := this._getClipData( clipData ) )
return ""
if !( out_size := this._getFormatData( out_data, clipData, clipSize, this.ClipboardFormats.CF_HDROP ) )
return ""
return this._getFiles( &out_data )
}_getFormatData( ByRef out_data, ByRef data, size, needleFormat ){
needleFormat := WinClipAPI.IsInteger( needleFormat ) ? needleFormat : WinClipAPI.RegisterClipboardFormat( needleFormat )
if !needleFormat
return 0
offset := 0
while ( offset < size ){
if !( fmt := NumGet( data, offset, "UInt" ) )
break
offset += 4
if !( dataSize := NumGet( data, offset, "UInt" ) )
break
offset += 4
if ( fmt == needleFormat ){
VarSetCapacity( out_data, dataSize, 0 )
WinClipAPI.memcopy( &out_data, &data + offset, dataSize )
return dataSize
}offset += dataSize
}return 0
}
_DIBtoHBITMAP( ByRef dibData )
{
pPix := WinClipAPI.GetPixelInfo( dibData )
gdip_token := WinClipAPI.Gdip_Startup()
DllCall("gdiplus\GdipCreateBitmapFromGdiDib", "Ptr", &dibData, "Ptr", pPix, "Ptr*", pBitmap )
DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", "Ptr", pBitmap, "Ptr*", hBitmap, "int", 0xffffffff )
DllCall("gdiplus\GdipDisposeImage", "Ptr", pBitmap)
WinClipAPI.Gdip_Shutdown( gdip_token )
return hBitmap
}GetBitmap(){
if !( clipSize := this._fromclipboard( clipData ) )
return ""
if !( out_size := this._getFormatData( out_data, clipData, clipSize, this.ClipboardFormats.CF_DIB ) )
return ""
return this._DIBtoHBITMAP( out_data )
}iGetBitmap(){
this._IsInstance( A_ThisFunc )
if !( clipSize := this._getClipData( clipData ) )
return ""
if !( out_size := this._getFormatData( out_data, clipData, clipSize, this.ClipboardFormats.CF_DIB ) )
return ""
return this._DIBtoHBITMAP( out_data )
}_BITMAPtoDIB( bitmap, ByRef DIB ){
if !bitmap
return 0
if !WinClipAPI.IsInteger( bitmap ){
gdip_token := WinClipAPI.Gdip_Startup()
DllCall("gdiplus\GdipCreateBitmapFromFileICM", "wstr", bitmap, "Ptr*", pBitmap )
DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", "Ptr", pBitmap, "Ptr*", hBitmap, "int", 0xffffffff )
DllCall("gdiplus\GdipDisposeImage", "Ptr", pBitmap)
WinClipAPI.Gdip_Shutdown( gdip_token )
bmMade := 1
}else
hBitmap := bitmap, bmMade := 0
if !hBitmap
return 0
if !( hdc := DllCall( "GetDC", "Ptr", 0 ) )
goto, _BITMAPtoDIB_cleanup
hPal := DllCall( "GetStockObject", "UInt", 15 ) ;DEFAULT_PALLETE
hPal := DllCall( "SelectPalette", "ptr", hdc, "ptr", hPal, "Uint", 0 )
DllCall( "RealizePalette", "ptr", hdc )
size := DllCall( "GetObject", "Ptr", hBitmap, "Uint", 0, "ptr", 0 )
VarSetCapacity( bm, size, 0 )
DllCall( "GetObject", "Ptr", hBitmap, "Uint", size, "ptr", &bm )
biBitCount := NumGet( bm, 16, "UShort" )*NumGet( bm, 18, "UShort" )
nColors := (1 << biBitCount)
if ( nColors > 256 ) 
nColors := 0
bmiLen  := 40 + nColors * 4
VarSetCapacity( bmi, bmiLen, 0 )
NumPut( 40, bmi, 0, "Uint" )
NumPut( NumGet( bm, 4, "Uint" ), bmi, 4, "Uint" )
NumPut( biHeight := NumGet( bm, 8, "Uint" ), bmi, 8, "Uint" )
NumPut( 1, bmi, 12, "UShort" )
NumPut( biBitCount, bmi, 14, "UShort" )
NumPut( 0, bmi, 16, "UInt" )
if !DllCall("GetDIBits"
,"ptr",hdc
,"ptr",hBitmap
,"uint",0 
,"uint",biHeight
,"ptr",0
,"ptr",&bmi
,"uint",0)
goto, _BITMAPtoDIB_cleanup
biSizeImage := NumGet( &bmi, 20, "UInt" )
if ( biSizeImage = 0 ){
biBitCount := numget( &bmi, 14, "UShort" )
biWidth := numget( &bmi, 4, "UInt" )
biHeight := numget( &bmi, 8, "UInt" )
biSizeImage := (((( biWidth * biBitCount + 31 ) & ~31 ) >> 3 ) * biHeight )
numput( biSizeImage, &bmi, 20, "UInt" )
}DIBLen := bmiLen + biSizeImage
VarSetCapacity( DIB, DIBLen, 0 )
WinClipAPI.memcopy( &DIB, &bmi, bmiLen )
if !DllCall("GetDIBits"
,"ptr",hdc
,"ptr",hBitmap
,"uint",0 
,"uint",biHeight
,"ptr",&DIB + bmiLen
,"ptr",&DIB
,"uint",0)
goto, _BITMAPtoDIB_cleanup
_BITMAPtoDIB_cleanup:
if bmMade
DllCall( "DeleteObject", "ptr", hBitmap )
DllCall( "SelectPalette", "ptr", hdc, "ptr", hPal, "Uint", 0 )
DllCall( "RealizePalette", "ptr", hdc )
DllCall("ReleaseDC","ptr",hdc)
if ( A_ThisLabel = "_BITMAPtoDIB_cleanup" )
return 0
return DIBLen
}_setBitmap( ByRef DIB, DIBSize, ByRef clipData, clipSize ){
objFormats := this._parseClipboardData( clipData, clipSize )
uFmt := this.ClipboardFormats.CF_DIB
objFormats[ uFmt ] := { size : DIBSize }
ObjSetCapacity( objFormats[ uFmt ], "buffer", DIBSize )
WinClipAPI.memcopy( ObjGetAddress( objFormats[ uFmt ], "buffer" ), &DIB, DIBSize )
return this._compileClipData( clipData, objFormats )
}SetBitmap( bitmap ){
if ( DIBSize := this._BITMAPtoDIB( bitmap, DIB ) ){
clipSize := this._fromclipboard( clipData )
if ( clipSize := this._setBitmap( DIB, DIBSize, clipData, clipSize ) )
return this._toclipboard( clipData, clipSize )
}return 0
}iSetBitmap( bitmap ){
this._IsInstance( A_ThisFunc )
if ( DIBSize := this._BITMAPtoDIB( bitmap, DIB ) ){
clipSize := this._getClipData( clipData )
if ( clipSize := this._setBitmap( DIB, DIBSize, clipData, clipSize ) )
return this._setClipData( clipData, clipSize )
}return 0
}GetText(){
if !( clipSize := this._fromclipboard( clipData ) )
return ""
if !( out_size := this._getFormatData( out_data, clipData, clipSize, this.ClipboardFormats.CF_UNICODETEXT ) )
return ""
return strget( &out_data, out_size, "UTF-16" )
}iGetText(){
this._IsInstance( A_ThisFunc )
if !( clipSize := this._getClipData( clipData ) )
return ""
if !( out_size := this._getFormatData( out_data, clipData, clipSize, this.ClipboardFormats.CF_UNICODETEXT ) )
return ""
return strget( &out_data, out_size, "UTF-16" )
}GetHtml(){
if !( clipSize := this._fromclipboard( clipData ) )
return ""
if !( out_size := this._getFormatData( out_data, clipData, clipSize, "HTML Format" ) )
return ""
return strget( &out_data, out_size, "CP0" )
}iGetHtml(){
this._IsInstance( A_ThisFunc )
if !( clipSize := this._getClipData( clipData ) )
return ""
if !( out_size := this._getFormatData( out_data, clipData, clipSize, "HTML Format" ) )
return ""
return strget( &out_data, out_size, "CP0" )
}_getFormatName( iformat ){
if this.formatByValue.HasKey( iformat )
return this.formatByValue[ iformat ]
else
return WinClipAPI.GetClipboardFormatName( iformat )
}iGetData( ByRef Data ){
this._IsInstance( A_ThisFunc )
return this._getClipData( Data )
}iSetData( ByRef data ){
this._IsInstance( A_ThisFunc )
return this._setClipData( data, VarSetCapacity( data ) )
}iGetSize(){
this._IsInstance( A_ThisFunc )
return ObjGetCapacity( this, "alldata" )
}HasFormat( fmt ){
if !fmt
return 0
return WinClipAPI.IsClipboardFormatAvailable( WinClipAPI.IsInteger( fmt ) ? fmt 
: WinClipAPI.RegisterClipboardFormat( fmt )  )
}iHasFormat( fmt ){
this._IsInstance( A_ThisFunc )
if !( clipSize := this._getClipData( clipData ) )
return 0
return this._hasFormat( clipData, clipSize, fmt )
}_hasFormat( ByRef data, size, needleFormat ){
needleFormat := WinClipAPI.IsInteger( needleFormat ) ? needleFormat 
: WinClipAPI.RegisterClipboardFormat( needleFormat )
if !needleFormat
return 0
offset := 0
while ( offset < size ){
if !( fmt := NumGet( data, offset, "UInt" ) )
break
if ( fmt == needleFormat )
return 1
offset += 4
if !( dataSize := NumGet( data, offset, "UInt" ) )
break
offset += 4 + dataSize
}return 0
}iSaveBitmap( filePath, format ){
this._IsInstance( A_ThisFunc )
if ( filePath = "" || format = "" )
return 0
if !( clipSize := this._getClipData( clipData ) )
return 0
if !( DIBsize := this._getFormatData( DIB, clipData, clipSize, this.ClipboardFormats.CF_DIB ) )
return 0
gdip_token := WinClipAPI.Gdip_Startup()
if !WinClipAPI.GetEncoderClsid( format, CLSID )
return 0
DllCall("gdiplus\GdipCreateBitmapFromGdiDib", "Ptr", &DIB, "Ptr", WinClipAPI.GetPixelInfo( DIB ), "Ptr*", pBitmap )
DllCall("gdiplus\GdipSaveImageToFile", "Ptr", pBitmap, "wstr", filePath, "Ptr", &CLSID, "Ptr", 0 )
DllCall("gdiplus\GdipDisposeImage", "Ptr", pBitmap)
WinClipAPI.Gdip_Shutdown( gdip_token )
return 1
}SaveBitmap( filePath, format ){
if ( filePath = "" || format = "" )
return 0
if !( clipSize := this._fromclipboard( clipData ) )
return 0
if !( DIBsize := this._getFormatData( DIB, clipData, clipSize, this.ClipboardFormats.CF_DIB ) )
return 0
gdip_token := WinClipAPI.Gdip_Startup()
if !WinClipAPI.GetEncoderClsid( format, CLSID )
return 0
DllCall("gdiplus\GdipCreateBitmapFromGdiDib", "Ptr", &DIB, "Ptr", WinClipAPI.GetPixelInfo( DIB ), "Ptr*", pBitmap )
DllCall("gdiplus\GdipSaveImageToFile", "Ptr", pBitmap, "wstr", filePath, "Ptr", &CLSID, "Ptr", 0 )
DllCall("gdiplus\GdipDisposeImage", "Ptr", pBitmap)
WinClipAPI.Gdip_Shutdown( gdip_token )
return 1
}static ClipboardFormats := { CF_BITMAP : 2
,CF_DIB : 8
,CF_DIBV5 : 17
,CF_DIF : 5
,CF_DSPBITMAP : 0x0082
,CF_DSPENHMETAFILE : 0x008E
,CF_DSPMETAFILEPICT : 0x0083
,CF_DSPTEXT : 0x0081
,CF_ENHMETAFILE : 14
,CF_GDIOBJFIRST : 0x0300
,CF_GDIOBJLAST : 0x03FF
,CF_HDROP : 15
,CF_LOCALE : 16
,CF_METAFILEPICT : 3
,CF_OEMTEXT : 7
,CF_OWNERDISPLAY : 0x0080
,CF_PALETTE : 9
,CF_PENDATA : 10
,CF_PRIVATEFIRST : 0x0200
,CF_PRIVATELAST : 0x02FF
,CF_RIFF : 11
,CF_SYLK : 4
,CF_TEXT : 1
,CF_TIFF : 6
,CF_UNICODETEXT : 13
,CF_WAVE : 12 }

static WM_COPY := 0x301
,WM_CLEAR := 0x0303
,WM_CUT := 0x0300
,WM_PASTE := 0x0302

static skipFormats := {   2      : 0
,17     : 0
,0x0082 : 0
,0x008E : 0
,0x0083 : 0
,0x0081 : 0
,0x0080 : 0
,3      : 0
,7      : 0
,1      : 0 }
static formatByValue := { 2 : "CF_BITMAP"
,8 : "CF_DIB"
,17 : "CF_DIBV5"
,5 : "CF_DIF"
,0x0082 : "CF_DSPBITMAP"
,0x008E : "CF_DSPENHMETAFILE"
,0x0083 : "CF_DSPMETAFILEPICT"
,0x0081 : "CF_DSPTEXT"
,14 : "CF_ENHMETAFILE"
,0x0300 : "CF_GDIOBJFIRST"
,0x03FF : "CF_GDIOBJLAST"
,15 : "CF_HDROP"
,16 : "CF_LOCALE"
,3 : "CF_METAFILEPICT"
,7 : "CF_OEMTEXT"
,0x0080 : "CF_OWNERDISPLAY"
,9 : "CF_PALETTE"
,10 : "CF_PENDATA"
,0x0200 : "CF_PRIVATEFIRST"
,0x02FF : "CF_PRIVATELAST"
,11 : "CF_RIFF"
,4 : "CF_SYLK"
,1 : "CF_TEXT"
,6 : "CF_TIFF"
,13 : "CF_UNICODETEXT"
,12 : "CF_WAVE" }
}
;================= 下面是文件夹选择返回的函数 =================

SelectFolderEx(StartingFolder := "", Prompt := "", OwnerHwnd := 0, OkBtnLabel := "") {
   Static OsVersion := DllCall("GetVersion", "UChar")
        , IID_IShellItem := 0
        , InitIID := VarSetCapacity(IID_IShellItem, 16, 0)
                  & DllCall("Ole32.dll\IIDFromString", "WStr", "{43826d1e-e718-42ee-bc55-a1e261c37bfe}", "Ptr", &IID_IShellItem)
        , Show := A_PtrSize * 3
        , SetOptions := A_PtrSize * 9
        , SetFolder := A_PtrSize * 12
        , SetTitle := A_PtrSize * 17
        , SetOkButtonLabel := A_PtrSize * 18
        , GetResult := A_PtrSize * 20
   SelectedFolder := ""
   If (OsVersion < 6) { ; Vista+系统以下, 则恢复使用FileSelectFolder
      FileSelectFolder, SelectedFolder, *%StartingFolder%, 3, %Prompt%
      Return SelectedFolder
   }
   OwnerHwnd := DllCall("IsWindow", "Ptr", OwnerHwnd, "UInt") ? OwnerHwnd : 0
   If !(FileDialog := ComObjCreate("{DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7}", "{42f85136-db7e-439c-85f1-e4075d135fc8}"))
      Return ""
   VTBL := NumGet(FileDialog + 0, "UPtr")
   ; FOS_CREATEPROMPT | FOS_NOCHANGEDIR | FOS_PICKFOLDERS
   DllCall(NumGet(VTBL + SetOptions, "UPtr"), "Ptr", FileDialog, "UInt", 0x00002028, "UInt")
   If (StartingFolder <> "")
      If !DllCall("Shell32.dll\SHCreateItemFromParsingName", "WStr", StartingFolder, "Ptr", 0, "Ptr", &IID_IShellItem, "PtrP", FolderItem)
         DllCall(NumGet(VTBL + SetFolder, "UPtr"), "Ptr", FileDialog, "Ptr", FolderItem, "UInt")
   If (Prompt <> "")
      DllCall(NumGet(VTBL + SetTitle, "UPtr"), "Ptr", FileDialog, "WStr", Prompt, "UInt")
   If (OkBtnLabel <> "")
      DllCall(NumGet(VTBL + SetOkButtonLabel, "UPtr"), "Ptr", FileDialog, "WStr", OkBtnLabel, "UInt")
   If !DllCall(NumGet(VTBL + Show, "UPtr"), "Ptr", FileDialog, "Ptr", OwnerHwnd, "UInt") {
      If !DllCall(NumGet(VTBL + GetResult, "UPtr"), "Ptr", FileDialog, "PtrP", ShellItem, "UInt") {
         GetDisplayName := NumGet(NumGet(ShellItem + 0, "UPtr"), A_PtrSize * 5, "UPtr")
         If !DllCall(GetDisplayName, "Ptr", ShellItem, "UInt", 0x80028000, "PtrP", StrPtr) ; SIGDN_DESKTOPABSOLUTEPARSING
            SelectedFolder := StrGet(StrPtr, "UTF-16"), DllCall("Ole32.dll\CoTaskMemFree", "Ptr", StrPtr)
         ObjRelease(ShellItem)
   }  }
   If (FolderItem)
      ObjRelease(FolderItem)
   ObjRelease(FileDialog)
   Return SelectedFolder
}

给TA捐赠
共{{data.count}}人
人已捐赠
案例

自动登陆钉钉,并在发送消息后,退出钉钉

2021-5-11 9:01:48

其他函数

[func] htmlClip:剪贴板放入文字和图片

2021-5-12 22:52:29

7 条回复 A文章作者 M管理员
  1. 蜜獾哥

    链接无效

    • dbgba

      收到,又另传了一份到百度云。??
      链接:https://pan.baidu.com/s/1x5dW6pKYiMHNSeWDcXHNTA
      提取码:11qq

  2. 蜜獾哥

    bug一个 动图中标题栏快捷键提示与实际快捷键没同步 不一致

  3. MrLiu

    看起来不错,试试看

个人中心
购物车
优惠劵
有新私信 私信列表
搜索