Hello @ferdinand,
Thank you very much for your detailed guidance and for pointing out the necessary forum procedures.
Following your suggestion, I managed to implement the multi-file selection feature by utilizing a third-party GUI API, and I successfully outputted the selected file paths to the console.
Please note that this solution has only been tested on the Windows so far. I am sharing my example script below in the hope that it might help other developers facing the same requirement:
import ctypes
from ctypes import wintypes
# Flags used by the Windows file dialog.
OFN_EXPLORER = 0x00080000 # Use the Explorer-style dialog.
OFN_ALLOWMULTISELECT = 0x00000200 # Allow selecting multiple files.
OFN_FILEMUSTEXIST = 0x00001000 # Require selected files to exist.
OFN_PATHMUSTEXIST = 0x00000800 # Require the selected path to exist.
MAX_BUFFER = 65536 # Buffer size used to receive the result.
# OPENFILENAMEW structure used by the Windows API.
class OPENFILENAMEW(ctypes.Structure):
_fields_ = [
("lStructSize", wintypes.DWORD),
("hwndOwner", wintypes.HWND),
("hInstance", wintypes.HINSTANCE),
("lpstrFilter", wintypes.LPCWSTR),
("lpstrCustomFilter", ctypes.c_wchar_p),
("nMaxCustFilter", wintypes.DWORD),
("nFilterIndex", wintypes.DWORD),
("lpstrFile", ctypes.c_wchar_p),
("nMaxFile", wintypes.DWORD),
("lpstrFileTitle", ctypes.c_wchar_p),
("nMaxFileTitle", wintypes.DWORD),
("lpstrInitialDir", wintypes.LPCWSTR),
("lpstrTitle", wintypes.LPCWSTR),
("Flags", wintypes.DWORD),
("nFileOffset", wintypes.WORD),
("nFileExtension", wintypes.WORD),
("lpstrDefExt", wintypes.LPCWSTR),
("lCustData", wintypes.LPARAM),
("lpfnHook", wintypes.LPVOID),
("lpTemplateName", wintypes.LPCWSTR),
("pvReserved", wintypes.LPVOID),
("dwReserved", wintypes.DWORD),
("FlagsEx", wintypes.DWORD),
]
def open_multiple_files():
# Create a writable Unicode buffer to receive the file path data from Windows.
buffer = ctypes.create_unicode_buffer(MAX_BUFFER)
# Configure the parameters for the file-open dialog.
ofn = OPENFILENAMEW()
ofn.lStructSize = ctypes.sizeof(OPENFILENAMEW)
ofn.hwndOwner = None
ofn.lpstrFilter = "All Files\0*.*\0Text Files\0*.txt\0\0"
ofn.lpstrFile = ctypes.cast(buffer, ctypes.c_wchar_p)
ofn.nMaxFile = MAX_BUFFER
ofn.lpstrTitle = "Select Files"
ofn.Flags = (
OFN_EXPLORER
| OFN_ALLOWMULTISELECT
| OFN_FILEMUSTEXIST
| OFN_PATHMUSTEXIST
)
# Call the native Windows file selection dialog.
comdlg32 = ctypes.windll.comdlg32
result = comdlg32.GetOpenFileNameW(ctypes.byref(ofn))
# The user canceled the dialog, or the call failed.
if not result:
err = comdlg32.CommDlgExtendedError()
if err:
print("GetOpenFileNameW failed, error code:", err)
return []
# Read the returned content from the buffer.
# Single selection: returns a full file path.
# Multiple selection: returns [directory, file1, file2, ...].
raw = ctypes.wstring_at(ctypes.addressof(buffer), MAX_BUFFER)
parts = [p for p in raw.split("\0") if p]
if not parts:
return []
# If only one file was selected, return the full path directly.
if len(parts) == 1:
return [parts[0]]
# If multiple files were selected, combine the directory with each filename.
directory = parts[0]
filenames = parts[1:]
return [directory + "\\" + name for name in filenames]
def main():
paths = open_multiple_files()
if not paths:
print("No file selected.")
return
print("Selected files:")
for path in paths:
print(path)
if __name__ == "__main__":
main()
Best regards,
Anlv