Тема: AHK: Эмулирование drag and drop в стороннее приложение через инжект
Не во все приложения можно передать файлы с помощью сообщения WM_DROPFILES.
Такие приложения испльзуют IDropTarget interface.
https://docs.microsoft.com/en-us/window … droptarget
Чтобы узнать его адрес и использовать его методы нужен инжект.
Файлы должны быть разделены с "|".
Позиция для перетаскивания определяется тут:
WinGetPos, x, y, width, height, ahk_id %Hwnd%
x += Round((Width*96/A_ScreenDPI)*2/3)
y += Round((Height*96/A_ScreenDPI)/2)
Для каждого приложения должна определяться по разному алгоритму.
Битность автохотки и приложения должны совпадать.
AutoHotkeyMiniDll скачать тут
https://raw.githubusercontent.com/HotKe … eyMini.dll
https://raw.githubusercontent.com/HotKe … eyMini.dll
Переименовать в AutoHotkeyMini_32.dll и в AutoHotkeyMini_64.dll соответственно, сделать им unlock и положить в папку со скриптом.
AutoHotkeyMiniDll := A_ScriptDir "\AutoHotkeyMini_" A_PtrSize*8 ".dll"
WindowTitle := "ahk_exe Adobe Premiere Pro.exe"
Filenames := "D:\test1.mp4|D:\test2.mp4"
f1::
WinActivate, %WindowTitle%
WinWaitActive, %WindowTitle%,, 2
if ErrorLevel
{
MsgBox, 274336,, WinWaitActive timed out.
return
}
WinGet, Hwnd, ID, %WindowTitle%
WinGet, PID, PID, ahk_id %Hwnd%
if (pid != pidPrev)
{
if !pidPrev
{
if !DllCall("user32\GetProp", "ptr", Hwnd, "str", "OleDropTargetInterface", "ptr")
{
msgbox no OleDropTargetInterface
return
}
Proc := DllCall("kernel32\OpenProcess", "uint", PROCESS_QUERY_INFORMATION := 0x400, "int", 0, "uint", PID, "ptr")
DllCall("kernel32\IsWow64Process", "ptr", Proc, "int*", IsWow64Process)
DllCall("kernel32\CloseHandle", "ptr", Proc)
if ((IsWow64Process = 0) and (A_PtrSize = 4)) or ((IsWow64Process = 1) and (A_PtrSize = 8))
{
msgbox process bitness mismatch
ExitApp
}
}
rThread := ""
rThread := InjectAhkDll(PID, AutoHotkeyMiniDll)
pidPrev := pid
}
WinGetPos, x, y, width, height, ahk_id %Hwnd%
x += Round((Width*96/A_ScreenDPI)*2/3)
y += Round((Height*96/A_ScreenDPI)/2)
DragAndDropScript1 := "Hwnd := " Hwnd ", filenames := """ Filenames """, x := " x ", y := " y "`r`n"
if !DragAndDropScript2
{
DragAndDropScript2 =
(% ` Join`r`n
SetBatchLines -1
filenames := StrSplit(filenames, "|")
path := filenames.1
SplitPath, path,, dir
for key, path in filenames
{
SplitPath, path, name
filenames[key] := name
}
if (!IsObject(filenames) || !filenames.MaxIndex() || !filenames[1])
return
if (!(pUnk := DllCall("GetProp", "Ptr", hWnd, "Str", "OleDropTargetInterface", "Ptr")))
return
if (!VarSetCapacity(IID_IDataObject))
{
VarSetCapacity(IID_IDataObject, 16)
DllCall("ole32\CLSIDFromString", "WStr", "{0000010e-0000-0000-C000-000000000046}", "Ptr", &IID_IDataObject)
}
if (!VarSetCapacity(IID_IShellFolder))
{
VarSetCapacity(IID_IShellFolder, 16)
DllCall("ole32\CLSIDFromString", "WStr", "{000214E6-0000-0000-C000-000000000046}", "Ptr", &IID_IShellFolder)
}
DllCall("shell32\SHGetDesktopFolder", "Ptr*", pDesktop)
if (dir = A_Desktop)
pISF := pDesktop
else
{
DllCall("shell32\SHParseDisplayName", "WStr", dir, "Ptr", 0, "Ptr*", pidl_dir, UInt, 0, Ptr, 0)
DllCall(NumGet(NumGet(pDesktop+0)+5*A_PtrSize), "Ptr", pDesktop, "Ptr", pidl_dir, "UInt", 0, "Ptr", &IID_IShellFolder, "Ptr*", pISF) ; BindToObject
}
if (pISF)
{
pDropTarget := ComObjQuery(pUnk, "{00000122-0000-0000-C000-000000000046}")
VarSetCapacity(pidl_list, filenames.MaxIndex() * A_PtrSize)
filenameCount := 0, ParseDisplayName := NumGet(NumGet(pISF+0)+3*A_PtrSize)
for _, filename in filenames
{
DllCall(ParseDisplayName, "Ptr", pISF, "Ptr", 0, Ptr, 0, "WStr", filename, "Ptr", 0, "Ptr", &pidl_list+(filenameCount * A_PtrSize), "Ptr", 0)
filenameCount++
}
if (filenameCount)
{
DllCall(NumGet(NumGet(pISF+0)+10*A_PtrSize), "Ptr", pISF, "Ptr", 0, "UInt", filenameCount, "Ptr", &pidl_list, "Ptr", &IID_IDataObject, "Ptr", 0, "Ptr*", pDataObject) ; GetUIObjectOf
if (pDataObject)
{
DllCall(NumGet(NumGet(pDropTarget+0)+3*A_PtrSize), "Ptr", pDropTarget, "Ptr", pDataObject, "UInt", 0, "Int64", x | y << 32, "UInt*", DragEnter := 1) ; DragEnter
if (DragEnter = 0)
msgbox Coordinates Error: %x%-%y%
DllCall(NumGet(NumGet(pDropTarget+0)+6*A_PtrSize), "Ptr", pDropTarget, "Ptr", pDataObject, "UInt", 0, "Int64", x | y << 32, "UInt*", 1) ; Drop
ObjRelease(pDataObject)
}
Loop, % filenameCount
{
if ((pidl := NumGet(pidl_list, (A_Index - 1) * A_PtrSize, "Ptr")))
DllCall("ole32\CoTaskMemFree", "Ptr", pidl)
}
}
DllCall("ole32\CoTaskMemFree", "Ptr", pidl_dir)
for _, obj in [pDropTarget, pISF]
ObjRelease(obj)
if !(dir = A_Desktop)
ObjRelease(pDesktop)
}
)
}
rThread.Exec(DragAndDropScript1 DragAndDropScript2)
return
InjectAhkDll(PID,dll:="AutoHotkey64.dll",script:=0, deleteThread := false)
{
static PROCESS_ALL_ACCESS:=0x1F0FFF,MEM_COMMIT := 0x1000,MEM_RELEASE:=0x8000,PAGE_EXECUTE_READWRITE:=64
,hKernel32:=DllCall("LoadLibrary","Str","kernel32.dll","PTR"),LoadLibraryA:=DllCall("GetProcAddress","PTR",hKernel32,"AStr","LoadLibraryA","PTR")
,FreeLibrary:=DllCall("GetProcAddress","PTR",hKernel32,"AStr","FreeLibrary","PTR")
,TH32CS_SNAPMODULE:=0x00000008,INVALID_HANDLE_VALUE:=-1
,MAX_PATH:=260,MAX_MODULE_NAME32:=255,ModuleName:="",init:=VarSetCapacity(ModuleName,MAX_PATH*(A_IsUnicode?2:1))
base:= deleteThread ? {__Call:"InjectAhkDll",__Delete:"InjectAhkDll"} : {__Call:"InjectAhkDll"}
if IsObject(PID)
{
if (dll!="Exec" && script)
return "Only Exec method can be used here!"
hProc := DllCall("OpenProcess", "UInt", PROCESS_ALL_ACCESS, "Int",0, "UInt", PID.PID,"PTR")
if !hProc
return "Could not open process for PID: " PID.PID
if (!script) ; Free Library in remote process (object is being deleted)
{
; Terminate the thread in ahkdll
hThread := DllCall("CreateRemoteThread", "PTR", hProc, "PTR", 0, "PTR", 0, "PTR", PID.ahkTerminate, "PTR", 0, "UInt", 0, "PTR", 0,"PTR")
DllCall("WaitForSingleObject", "PTR", hThread, "UInt", 0xFFFFFFFF)
,DllCall("CloseHandle", "PTR", hThread)
; Free library in remote process
hThread := DllCall("CreateRemoteThread", "PTR", hProc, "UInt", 0, "UInt", 0, "PTR", FreeLibrary, "PTR", PID.hModule, "UInt", 0, "UInt", 0,"PTR")
DllCall("WaitForSingleObject", "PTR", hThread, "UInt", 0xFFFFFFFF)
,DllCall("CloseHandle", "PTR", hThread),DllCall("CloseHandle", "PTR", hProc)
return
}
nScriptLength := VarSetCapacity(nScript, (StrLen(script)+1)*(A_IsUnicode?2:1), 0)
,StrPut(script,&nScript)
; Reserve memory in remote process where our script will be saved
if !pBufferRemote := DllCall("VirtualAllocEx", "Ptr", hProc, "Ptr", 0, "PTR", nScriptLength, "UInt", MEM_COMMIT, "UInt", PAGE_EXECUTE_READWRITE, "Ptr")
return "Could not reseve memory for process"
,DllCall("CloseHandle", "PTR", hProc)
; Write script to remote process memory
DllCall("WriteProcessMemory", "Ptr", hProc, "Ptr", pBufferRemote, "Ptr", &nScript, "PTR", nScriptLength, "Ptr", 0)
; Start execution of code
hThread := DllCall("CreateRemoteThread", "PTR", hProc, "PTR", 0, "PTR", 0, "PTR", PID.ahkExec, "PTR", pBufferRemote, "UInt", 0, "PTR", 0,"PTR")
if !hThread
{
DllCall("VirtualFreeEx","PTR",hProc,"PTR",pBufferRemote,"PTR",nScriptLength,MEM_RELEASE)
,DllCall("CloseHandle", "PTR", hProc)
return "Could not execute script in remote process"
}
; Wait for thread to finish
DllCall("WaitForSingleObject", "PTR", hThread, "UInt", 0xFFFFFFFF)
; Get Exit code returned by ahkExec (1 = script could be executed / 0 = script could not be executed)
DllCall("GetExitCodeThread", "PTR", hThread, "UIntP", lpExitCode)
if !lpExitCode
return "Could not execute script in remote process"
DllCall("CloseHandle", "PTR", hThread)
,DllCall("VirtualFreeEx","PTR",hProc,"PTR",pBufferRemote,"PTR",nScriptLength,MEM_RELEASE)
,DllCall("CloseHandle", "PTR", hProc)
return
}
else if !hDll:=DllCall("LoadLibrary","Str",dll,"PTR")
return "Could not find " dll " library", DllCall("CloseHandle", "PTR", hProc)
else
{
hProc := DllCall("OpenProcess","UInt", PROCESS_ALL_ACCESS, "Int",0,"UInt", DllCall("GetCurrentProcessId"),"PTR")
DllCall("GetModuleFileName","PTR",hDll,"PTR",&ModuleName,"UInt",MAX_PATH)
DllCall("CloseHandle","PTR",hProc)
}
; Open Process to PID
hProc := DllCall("OpenProcess", "UInt", PROCESS_ALL_ACCESS, "Int",0, "UInt", PID,"PTR")
if !hProc
return "Could not open process for PID: " PID
Loop, Files, %dll%, F
dll := A_LoopFileLongPath
; Reserve some memory and write dll path (ANSI)
nDirLength := VarSetCapacity(nDir, StrLen(dll)+1, 0)
,StrPut(dll,&nDir,"CP0")
; Reserve memory in remote process
if !pBufferRemote := DllCall("VirtualAllocEx", "Ptr", hProc, "Ptr", 0, "PTR", nDirLength, "UInt", MEM_COMMIT, "UInt", PAGE_EXECUTE_READWRITE, "Ptr")
return "Could not reseve memory for process", DllCall("CloseHandle", "PTR", hProc)
; Write dll path to remote process memory
DllCall("WriteProcessMemory", "Ptr", hProc, "Ptr", pBufferRemote, "Ptr", &nDir, "PTR", nDirLength, "Ptr", 0)
; Start new thread loading our dll
hThread:=DllCall("CreateRemoteThread","PTR",hProc,"PTR",0,"PTR",0,"PTR",LoadLibraryA,"PTR",pBufferRemote,"UInt",0,"PTR",0,"PTR")
if !hThread
{
DllCall("VirtualFreeEx","PTR",hProc,"PTR",pBufferRemote,"PTR",nDirLength,"Uint",MEM_RELEASE)
,DllCall("CloseHandle", "PTR", hProc)
return "Could not load " dll " in remote process"
}
; Wait for thread to finish
DllCall("WaitForSingleObject", "PTR", hThread, "UInt", 0xFFFFFFFF)
; Get Exit code returned by thread (HMODULE for our dll)
DllCall("GetExitCodeThread", "PTR", hThread, "UInt*", hModule)
; Close Thread
DllCall("CloseHandle", "PTR", hThread)
if (A_PtrSize=8)
{ ; use different method to retrieve base address because GetExitCodeThread returns DWORD only
hModule:=0,VarSetCapacity(me32, (A_PtrSize=8?48:32)+(A_IsUnicode?1032:516), 0) ;W:1080:1064, A:564:548
; Take a snapshot of all modules in the specified process.
hModuleSnap := DllCall("CreateToolhelp32Snapshot","UInt", TH32CS_SNAPMODULE,"UInt", PID, "PTR" )
if ( hModuleSnap != INVALID_HANDLE_VALUE )
{
; reset hModule and set the size of the structure before using it.
NumPut((A_PtrSize=8?48:32)+(A_IsUnicode?1032:516), &me32, 0, "UInt") ;dwSize ;W:1080:1064, A:564:548
; Retrieve information about the first module,
; and exit if unsuccessful
if ( !DllCall("Module32First" (A_IsUnicode?"W":""),"PTR", hModuleSnap,"PTR", &me32 ) )
{
; Free memory used for passing dll path to remote thread
DllCall("VirtualFreeEx","PTR",hProc,"PTR",pBufferRemote,"PTR",nDirLength,MEM_RELEASE)
,DllCall("CloseHandle","PTR", hModuleSnap ) ; Must clean up the snapshot object!
return false
}
; Now walk the module list of the process,and display information about each module
while(A_Index=1 || DllCall("Module32Next" (A_IsUnicode?"W":""),"PTR",hModuleSnap,"PTR", &me32 ) )
if (StrGet(&me32+(A_PtrSize=8?48:32)+(A_IsUnicode?512:256))=dll) ;szExePath ;W:560:544, A:304:288
{
hModule := NumGet(me32, A_PtrSize=8?40:28, "Ptr") ;hModule
break
}
DllCall("CloseHandle","PTR",hModuleSnap) ; clean up
}
}
hDll:=DllCall("LoadLibrary","Str",dll,"PTR")
; Calculate pointer to ahkdll and ahkExec functions
ahktextdll:=hModule+DllCall("GetProcAddress","PTR",hDll,"AStr","ahktextdll","PTR")-hDll
ahkExec:=hModule+DllCall("GetProcAddress","PTR",hDll,"AStr","ahkExec","PTR")-hDll
ahkTerminate:=hModule+DllCall("GetProcAddress","PTR",hDll,"AStr","ahkTerminate","PTR")-hDll
if script
{
nScriptLength := VarSetCapacity(nScript, (StrLen(script)+1)*(A_IsUnicode?2:1), 0)
,StrPut(script,&nScript)
; Reserve memory in remote process where our script will be saved
if !pBufferScript := DllCall("VirtualAllocEx", "Ptr", hProc, "Ptr", 0, "PTR", nScriptLength, "UInt", MEM_COMMIT, "UInt", PAGE_EXECUTE_READWRITE, "Ptr")
return "Could not reseve memory for process"
,DllCall("CloseHandle", "PTR", hProc)
; Write script to remote process memory
DllCall("WriteProcessMemory", "Ptr", hProc, "Ptr", pBufferScript, "Ptr", &nScript, "PTR", nScriptLength, "Ptr", 0)
}
else
pBufferScript:=0
; Run ahkdll function in remote thread
hThread := DllCall("CreateRemoteThread","PTR",hProc,"PTR",0,"PTR",0,"PTR",ahktextdll,"PTR",pBufferScript,"PTR",0,"UInt",0,"PTR")
if !hThread
{ ; could not start ahkdll in remote process
; Free memory used for passing dll path to remote thread
DllCall("VirtualFreeEx","PTR",hProc,"PTR",pBufferRemote,"PTR",nDirLength,MEM_RELEASE)
DllCall("CloseHandle", "PTR", hProc)
return "Could not start ahkdll in remote process"
}
DllCall("WaitForSingleObject", "PTR", hThread, "UInt", 0xFFFFFFFF)
DllCall("GetExitCodeThread", "PTR", hThread, "UIntP", lpExitCode)
; Release memory and handles
DllCall("VirtualFreeEx","PTR",hProc,"PTR",pBufferRemote,"PTR",nDirLength,MEM_RELEASE)
DllCall("CloseHandle", "PTR", hThread)
DllCall("CloseHandle", "PTR", hProc)
if !lpExitCode ; thread could not be created.
return "Could not create a thread in remote process"
return {PID:PID,hModule:hModule,ahkExec:ahkExec,ahkTerminate:ahkTerminate,base:base}
}