1

Тема: 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}
}

Тема для обсуждения