improve open folder logic in windows

This commit is contained in:
AmirHossein Abdolmotallebi 2024-11-27 19:24:09 +03:30
parent a654bb846b
commit b27fc4ec8f
2 changed files with 70 additions and 0 deletions

View File

@ -10,4 +10,5 @@ dependencies {
api(libs.semver)
api(libs.arrow.optics)
api("ir.amirab.util:platform:1")
implementation(libs.jna.platform)
}

View File

@ -1,5 +1,10 @@
package ir.amirab.util.osfileutil
import com.sun.jna.Native
import com.sun.jna.Pointer
import com.sun.jna.platform.win32.*
import com.sun.jna.win32.StdCallLibrary
import com.sun.jna.win32.W32APIOptions
import ir.amirab.util.execAndWait
import java.io.File
@ -9,10 +14,74 @@ internal class WindowsFileUtils : FileUtilsBase() {
}
override fun openFolderOfFileInternal(file: File): Boolean {
val nativeSuccess = showFileInFolderViaNative(file.path)
if (nativeSuccess) {
return true
}
//fallback to use explorer
return execAndWait(arrayOf("cmd", "/c", "explorer.exe", "/select,", file.path))
}
override fun openFolderInternal(folder: File): Boolean {
val nativeSuccess = openFolderViaNative(folder.path)
if (nativeSuccess) {
return true
}
//fallback to use explorer
return execAndWait(arrayOf("cmd", "/c", "explorer.exe", folder.path))
}
private fun showFileInFolderViaNative(
file: String,
): Boolean {
Ole32.INSTANCE.CoInitializeEx(null, Ole32.COINIT_APARTMENTTHREADED)
val path = Shell32Ex.INSTANCE.ILCreateFromPath(File(file).parent)
val selectedFiles = arrayOf(Shell32Ex.INSTANCE.ILCreateFromPath(file))
val cidl = WinDef.UINT(selectedFiles.size.toLong())
try {
val res = Shell32Ex.INSTANCE.SHOpenFolderAndSelectItems(
pIdlFolder = path,
cIdl = cidl,
apIdl = selectedFiles,
dwFlags = WinDef.DWORD(0)
)
return WinError.S_OK == res
} catch (e: Exception) {
e.printStackTrace()
return false
} finally {
Shell32Ex.INSTANCE.ILFree(path)
selectedFiles.forEach {
Shell32Ex.INSTANCE.ILFree(it)
}
}
}
private fun openFolderViaNative(folder: String): Boolean {
try {
val result = Shell32.INSTANCE.ShellExecute(
null, "explore", folder, null, null, WinUser.SW_NORMAL,
).toInt()
return result > 32
} catch (e: Exception) {
e.printStackTrace()
return false
}
}
}
private interface Shell32Ex : StdCallLibrary {
fun ILCreateFromPath(path: String?): Pointer?
fun ILFree(pIdl: Pointer?)
fun SHOpenFolderAndSelectItems(
pIdlFolder: Pointer?,
cIdl: WinDef.UINT?,
apIdl: Array<Pointer?>?,
dwFlags: WinDef.DWORD?,
): WinNT.HRESULT?
companion object {
val INSTANCE: Shell32Ex = Native.load("shell32", Shell32Ex::class.java, W32APIOptions.DEFAULT_OPTIONS)
}
}