Display And Use A File's Icon When Dragging Over Window

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
ToonyTom
Posts: 9
Joined: 04 Mar 2015, 04:41

Display And Use A File's Icon When Dragging Over Window

04 Mar 2015, 07:48

I've been working on building a dock completely in AHK. The reson is because I'm very unsatisfied with ObjectDock. The only peice of the puzzle that's causing me major problems is grabbing the image for what's being dragged over. You'll notice that if you drag anything on your desktop or from explorer it will create an image to represent whatever it is being dragged. I noticed that ObjectDock seems to use this same image whenever you drag something onto it. It doesn't matter if it's the "my computer" shortcut, or something from your control panel, or a file. It uses the exact same icon that you see when it's dragged over ObjectDock's window.

Now I've tried the usual ways of grabbing a file's icon:
Shell32\SHGetFileInfo: only returns 32x32 sized icons and I cannot make it return the path of a file's icon using SHGFI_ICONLOCATION
ExtractAssociatedIcon: only returns 32x32 sized icons
Gdip_CreateBitmapFromFile(): doesn't read every format
AssocQueryApp(sExt): only returns the exe path, not the icon number
reading the registry: isn't reliable

But all of those ways usually fail to get the right icon or it's the wrong size, especially with those oddball shell shortcuts. So the best I could see is to use that image that appears over your cursor while dragging. From what I've found in this script, what's required is way over my head:

Code: Select all

#SingleInstance	Force

GuiOpen:
Gui, +LastFound
Gui, Add, ListView, R20 W600, #|Format|Size|Data
Gui, Show, X10 Y10
hGui := WinExist()

VarSetCapacity(IDropTarget,32,0)
NumPut(&IDropTarget+4,IDropTarget)
nParams=3116516

Loop,	Parse,	nParams
	NumPut( RegisterCallback("IDropTarget","",A_LoopField,A_Index-1) ,IDropTarget,4*A_Index)

DllCall("ole32\OleInitialize","Uint",0)
DllCall("ole32\RegisterDragDrop","Uint",hGui,"Uint",&IDropTarget)
Return


GuiClose:
Gui, Destroy
DllCall("ole32\RevokeDragDrop","Uint",hGui)
DllCall("ole32\OleUninitialize")
ExitApp

IDropTarget(this, pdata=0, key=0, x=0, y=0, peffect=0)
{
	If	A_EventInfo = 4 ; dragging loop over window
	{
		NumPut(NumGet(y+0)&5,y+0)
		tooltip DragOver
	}
	Else If	A_EventInfo = 3 ;dragging to window
	{
		NumPut(NumGet(peffect+0)&5,peffect+0)
		tooltip DragEnter
	}
	Else If	A_EventInfo = 6 ;item dropped
	{
		NumPut(NumGet(peffect+0)&5,peffect+0), IEnumFormatEtc(pdata)
		tooltip Drop
	}
	Else If	A_EventInfo = 0
	{
		NumPut(this,key+0)
		tooltip some4
	}
if A_EventInfo = 5      ;leaving window
tooltip DragLeave
	Return	0
}

IEnumFormatEtc(this)
{
	LV_Delete()
	DllCall(NumGet(NumGet(1*this)+32),"Uint",this,"Uint",1,"UintP",penum) ; DATADIR_GET=1, DATADIR_SET=2
	Loop
	{
		VarSetCapacity(FormatEtc,20,0)
		If  DllCall(NumGet(NumGet(1*penum)+12), "Uint", penum, "Uint",1, "Uint", &FormatEtc, "Uint",0)
		    Break
		0+(nFormat:=NumGet(FormatEtc,0,"Ushort"))<18 ? RegExMatch("CF_TEXT CF_BITMAP CF_METAFILEPICT CF_SYLK CF_DIF CF_TIFF CF_OEMTEXT CF_DIB CF_PALETTE CF_PENDATA CF_RIFF CF_WAVE CF_UNICODETEXT CF_ENHMETAFILE CF_HDROP CF_LOCALE CF_DIBV5", "(?:\w+\s+){" . nFormat-1 . "}(?<FORMAT>\w+\b)", CF_) : nFormat>=0x80&&nFormat<=0x83 ? RegExMatch("CF_OWNERDISPLAY CF_DSPTEXT CF_DSPBITMAP CF_DSPMETAFILEPICT", "(?:\w+\s+){" . nFormat-0x80 . "}(?<FORMAT>\w+\b)", CF_) : nFormat=0x8E ? CF_FORMAT:="CF_DSPENHMETAFILE" : CF_FORMAT:=GetClipboardFormatName(nFormat)
		VarSetCapacity(StgMedium,12,0)
		If  DllCall(NumGet(NumGet(1*this)+12), "Uint", this, "Uint", &FormatEtc, "Uint", &StgMedium)
		    Continue
		If	NumGet(StgMedium,0)=1	; TYMED_HGLOBAL=1
		{
			hData:=NumGet(StgMedium,4)
			pData:=DllCall("GlobalLock", "Uint", hData)
			nSize:=DllCall("GlobalSize", "Uint", hData)
			VarSetCapacity(sData,1023), DllCall("wsprintf", "str", sData, "str", DllCall("advapi32\IsTextUnicode", "Uint", pData, "Uint", nSize, "Uint", 0) ? "%S" : "%s", "Uint", pData, "Cdecl")
			DllCall("GlobalUnlock", "Uint", hData)
;~ 			if (CF_FORMAT = "FileName")      ;here we can get file name of dropped file
				LV_Add("", A_Index, CF_FORMAT, nSize, sData)
	
		}
		Else	RegExMatch("TYMED_NULL TYMED_FILE TYMED_ISTREAM TYMED_ISTORAGE TYMED_GDI TYMED_MFPICT TYMED_ENHMF", "(?:\w+\s+){" . Floor(ln(NumGet(StgMedium)+1)/ln(2)) . "}(?<STGMEDIUM>\w+\b)", TYMED_), LV_Add("", A_Index, CF_FORMAT, "?", TYMED_STGMEDIUM)
		DllCall("ole32\ReleaseStgMedium","Uint",&StgMedium)
	}
	DllCall(NumGet(NumGet(1*penum)+8), "Uint", penum)
	LV_ModifyCol()
}

GetClipboardFormatName(nFormat)
{
	VarSetCapacity(sFormat, 255)
	DllCall("GetClipboardFormatName", "Uint", nFormat, "str", sFormat, "Uint", 256)
	Return	sFormat
}
I found that code around the old autohotkey forums. It will display a tooltip depending on what's going on and spit out some info into a listview, but that's it. I thought "DragImageBits" might be the data of the drag image, so I tried using a couple of GDIP functions to make it display in a GUI, but it was useless. I have absolutely no clue how the coder found nParams=3116516 and knew how to do all this NumPut stuff to get all this working. :headwall:

Over on MSDN I found this, which explains:
Drop targets that have a window can register a DI_GETDRAGIMAGE window message for it by initializing the drag-and-drop helper object with IDragSourceHelper::InitializeFromWindow. When the target receives a DI_GETDRAGIMAGE message, the handler puts the drag image bitmap information in the SHDRAGIMAGE structure that is passed as the message's lParam value.
I just have no idea how to translate that into something I can do with AHK. Would it be possible to use DLL_Struct() to make all of this easier? All I really want to do is use a file's large icon to make a bitmap with GDIP.

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Billykid, filipemb, haomingchen1998, Oblomov228, RussF and 260 guests