{"record":{"id":"08d6d68420e155f2","repo":"wailsapp/wails","slug":"invoke-dragqueryfile-error","errorCode":null,"errorMessage":"Invoke DragQueryFile error.","messagePattern":"Invoke DragQueryFile error\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/pkg/w32/shell32.go","lineNumber":284,"sourceCode":"\tret, _, _ := procDragQueryFile.Call(\n\t\thDrop,\n\t\tuintptr(iFile),\n\t\t0,\n\t\t0)\n\n\tfileCount = uint(ret)\n\n\tif iFile != 0xFFFFFFFF {\n\t\tbuf := make([]uint16, fileCount+1)\n\n\t\tret, _, _ := procDragQueryFile.Call(\n\t\t\thDrop,\n\t\t\tuintptr(iFile),\n\t\t\tuintptr(unsafe.Pointer(&buf[0])),\n\t\t\tuintptr(fileCount+1))\n\n\t\tif ret == 0 {\n\t\t\tpanic(\"Invoke DragQueryFile error.\")\n\t\t}\n\n\t\tfileName = syscall.UTF16ToString(buf)\n\t}\n\n\treturn\n}\n\nfunc DragQueryPoint(hDrop HDROP) (x, y int, isClientArea bool) {\n\tvar pt POINT\n\tret, _, _ := procDragQueryPoint.Call(\n\t\tuintptr(hDrop),\n\t\tuintptr(unsafe.Pointer(&pt)))\n\n\treturn int(pt.X), int(pt.Y), (ret == 1)\n}\n\nfunc DragFinish(hDrop HDROP) {","sourceCodeStart":266,"sourceCodeEnd":302,"githubUrl":"https://github.com/wailsapp/wails/blob/0e754b1b40ba9044c2a1460e23b7c3de20fc5cf3/v3/pkg/w32/shell32.go#L266-L302","documentation":"The DragQueryFile wrapper panicked because the second call (the one that copies the file name for a specific index) returned 0, meaning the call failed — most often the buffer was too small, iFile was out of range, or hDrop was invalid. The code sizes the buffer from the first DragQueryFile(0xFFFFFFFF) call, which returns the FILE COUNT, not the longest path length, so deep paths overflow the buffer and make the copy fail.","triggerScenarios":"Dropping files whose full path is longer than the number of dropped files (almost always true in practice — e.g. one file with a 120-char path gets a 2-uint16 buffer); calling with iFile >= the count returned by the enumeration pass; using hDrop after DragFinish.","commonSituations":"Wails drag-and-drop handlers on Windows processing files from long directory trees or with long Unicode names; re-reading the drop handle after it was finished; races where the drop list is queried twice.","solutions":["Fix the wrapper: size the buffer by calling DragQueryFile(hDrop, iFile, nil, 0) first — it returns the required character count — then allocate count+1","Validate iFile < fileCount before the copy call","Do not call DragFinish until all DragQueryFile/QueryPoint reads are done","Recover around the drop-handling loop so one bad entry does not crash the app"],"exampleFix":"// before\nret, _, _ := procDragQueryFile.Call(hDrop, uintptr(0xFFFFFFFF), 0, 0)\nfileCount = uint(ret)\nbuf := make([]uint16, fileCount+1) // WRONG: sizes by file count\n\n// after\n// pass iFile with null buffer to get needed length\nlenRet, _, _ := procDragQueryFile.Call(hDrop, uintptr(iFile), 0, 0)\nbuf := make([]uint16, lenRet+1)\nret, _, _ := procDragQueryFile.Call(hDrop, uintptr(iFile),\n    uintptr(unsafe.Pointer(&buf[0])), uintptr(lenRet+1))\nif ret == 0 { panic(\"Invoke DragQueryFile error.\") }","handlingStrategy":"validation","validationCode":"// fixed wrapper: query required length first\nl, _, _ := procDragQueryFile.Call(hDrop, uintptr(iFile), 0, 0)\nif l == 0 { return } // invalid index or handle\nbuf := make([]uint16, l+1)","typeGuard":null,"tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        log.Printf(\"DragQueryFile failed for index %d: %v\", iFile, r)\n    }\n}()","preventionTips":["Size the buffer from DragQueryFile(hDrop, iFile, nil, 0), not from the file count","Validate iFile against the count from the 0xFFFFFFFF query","Finish all queries before DragFinish"],"tags":["windows","drag-and-drop","shell32","buffer-size","panic","wrapper-bug"],"backgroundTag":null,"analyzedSha":"0e754b1b40ba9044c2a1460e23b7c3de20fc5cf3","analyzedAt":"2026-08-15T14:17:36.034Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}