Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions helper/WinDialog/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
'Button', 'DefaultButton', 'CheckBoxButton', 'GroupBox', 'CommandButton', 'RadioButton', 'RadioPushButton', 'SplitButton',
'Label', 'TruncatedLabel', 'BlackFramedLabel', 'CenteredLabel', 'RigthAlignedLabel',
'ComboBox', 'ComboBoxEx', 'ListBox', 'TextBox', 'ListView', 'ProgressBar', 'StatusBar', 'UpDown', 'TreeView',
'DirectoryPicker', 'FileOpenDialog'
'DirectoryPicker', 'FileOpenDialog', 'FileSaveDialog'
]
__version__ = '0.3'
__author__ = 'ekopalypse'
Expand Down Expand Up @@ -102,7 +102,7 @@
# from .controls.systabcontrol32 import ...
# from .controls.toolbarwindow32 import ...

from .com_dialogs import FileOpenDialog, DirectoryPicker
from .com_dialogs import FileOpenDialog, DirectoryPicker, FileSaveDialog

from .resource_parser import parser

Expand Down
48 changes: 39 additions & 9 deletions helper/WinDialog/__tests__/test_com_dialogs.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,43 @@
from WinDialog import FileOpenDialog, DirectoryPicker
from WinDialog import FileOpenDialog, DirectoryPicker, FileSaveDialog
from WinDialog.com_dialogs import FOS

dlg = FileOpenDialog()
dlg.setOptions(FOS.ALLOWMULTISELECT)
print(dlg.show())
def test_dlgs():

print(DirectoryPicker().show())
answer = notepad.messageBox('About to demo a file-open dialog where you can select multiple items -- proceed?', '', MESSAGEBOXFLAGS.YESNOCANCEL)
if answer == MESSAGEBOXFLAGS.RESULTCANCEL: return
if answer == MESSAGEBOXFLAGS.RESULTYES:
open_dlg = FileOpenDialog()
open_dlg.setOptions(FOS.ALLOWMULTISELECT)
result = open_dlg.show()
if len(result) > 0: notepad.messageBox(str(result), 'Result')

options = dlg.getOptions()
options &= ~FOS.ALLOWMULTISELECT
dlg.setOptions(options)
print(dlg.show())
answer = notepad.messageBox('About to demo a file-open dialog where you can only select 1 item -- proceed?', '', MESSAGEBOXFLAGS.YESNOCANCEL)
if answer == MESSAGEBOXFLAGS.RESULTCANCEL: return
if answer == MESSAGEBOXFLAGS.RESULTYES:
open_dlg = FileOpenDialog()
open_options = open_dlg.getOptions()
open_options &= ~FOS.ALLOWMULTISELECT
open_dlg.setOptions(open_options)
result = open_dlg.show()
if len(result) > 0: notepad.messageBox(str(result), 'Result')

answer = notepad.messageBox('About to demo a file-save dialog -- proceed?', '', MESSAGEBOXFLAGS.YESNOCANCEL)
if answer == MESSAGEBOXFLAGS.RESULTCANCEL: return
if answer == MESSAGEBOXFLAGS.RESULTYES:
save_dlg = FileSaveDialog()
save_dlg.setFolder(r'c:')
save_dlg.setFileTypes([['All files', '*.*'], ['Text Files', '*.txt'], ['Log Files', '*.log']])
save_options = save_dlg.getOptions()
save_options |= FOS.OVERWRITEPROMPT
save_dlg.setOptions(save_options)
result = save_dlg.show()
if len(result) > 0: notepad.messageBox(str(result), 'Result')

answer = notepad.messageBox('About to demo a directory-picker dialog -- proceed?', '', MESSAGEBOXFLAGS.YESNOCANCEL)
if answer == MESSAGEBOXFLAGS.RESULTCANCEL: return
if answer == MESSAGEBOXFLAGS.RESULTYES:
dir_pick_dlg = DirectoryPicker()
result = dir_pick_dlg.show()
if len(result) > 0: notepad.messageBox(str(result), 'Result')

test_dlgs()
91 changes: 58 additions & 33 deletions helper/WinDialog/com_dialogs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ def __post_init__(self, rclsid, riid, extend_vtable):
self._set_title = WINFUNCTYPE(HRESULT, c_void_p, LPCWSTR)(self._vtable[17])
self._set_ok_button_label = WINFUNCTYPE(HRESULT, c_void_p, LPCWSTR)(self._vtable[18])
self._set_file_name_label = WINFUNCTYPE(HRESULT, c_void_p, LPCWSTR)(self._vtable[19])
# self._get_result = WINFUNCTYPE(HRESULT, c_void_p, POINTER(c_void_p))(self._vtable[20])
self._get_result = WINFUNCTYPE(HRESULT, c_void_p, POINTER(c_void_p))(self._vtable[20])
self._add_place = WINFUNCTYPE(HRESULT, c_void_p, c_void_p, UINT)(self._vtable[21])
self._set_default_extension = WINFUNCTYPE(HRESULT, c_void_p, LPCWSTR)(self._vtable[22])
# self._close = WINFUNCTYPE(HRESULT, c_void_p, HRESULT)(self._vtable[23])
Expand Down Expand Up @@ -492,43 +492,68 @@ def setOptions(self, options):
self._set_options(self.this, default_options.value | options)


# @dataclass
# class FileSaveDialog(FileDialog):
# # https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nn-shobjidl_core-ifilesavedialog
# '''
# FileSaveDialog Class
@dataclass
class FileSaveDialog(FileDialog):
# https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nn-shobjidl_core-ifilesavedialog
'''
FileSaveDialog Class

# Represents the standard COM-based file open dialog window.
Represents the standard COM-based file save dialog window.

# The FileSaveDialog class provides a template for creating and managing dialog windows.
# It encapsulates properties and behaviors common to dialog windows, such as
# title, size, position, styles, and controls.
The FileSaveDialog class provides a template for creating and managing dialog windows.
It encapsulates properties and behaviors common to dialog windows, such as
title, size, position, styles, and controls.

# Attributes:
# title (str): The title of the dialog window.
# parent (int): The handle of the parent window for the dialog.
# '''
Attributes:
title (str): The title of the dialog window.
parent (int): The handle of the parent window for the dialog.
'''

# def __post_init__(self):
# """
# Perform post-initialization tasks for the FileSaveDialog object.
selectedItem: List = field(default_factory=list)
parent: int = notepad.hwnd

# This method is automatically called after the initialization of the FileSaveDialog object.
# It creates the com object and its vtable (object methods).
def __post_init__(self):
"""
Perform post-initialization tasks for the FileSaveDialog object.

# Args:
# None.
This method is automatically called after the initialization of the FileSaveDialog object.
It creates the com object and its vtable (object methods).

# Returns:
# None.
# """
# super().__post_init__(GUID('C0B4E2F3-BA21-4773-8DBA-335EC946EB8B'), GUID('84BCCD23-5FDE-4CDB-AEA4-AF64B83D78AB'), 5)
Args:
None.

# def show(self, hwnd=None):
# try:
# self._show(self.this, hwnd)
# except OSError as e:
# if len(e.args) > 3 and e.args[3] == -2147023673:
# pass # User cancelled dialog
# else:
# raise
Returns:
None.
"""
super().__post_init__(GUID('C0B4E2F3-BA21-4773-8DBA-335EC946EB8B'), GUID('84BCCD23-5FDE-4CDB-AEA4-AF64B83D78AB'), 5)
# self._set_saveas_item = WINFUNCTYPE(HRESULT, c_void_p, POINTER(c_void_p))(self._vtable[27])
# self._set_properties = WINFUNCTYPE(HRESULT, c_void_p, POINTER(c_void_p))(self._vtable[28])
# self._set_collected_properties = WINFUNCTYPE(HRESULT, c_void_p, POINTER(c_void_p))(self._vtable[29])
# self._get_properties = WINFUNCTYPE(HRESULT, c_void_p, POINTER(c_void_p))(self._vtable[30])
# self._apply_properties = WINFUNCTYPE(HRESULT, c_void_p, POINTER(c_void_p))(self._vtable[30])

def show(self, hwnd=None):
'''
This method displays the dialog on the screen.
The method blocks until the dialog is closed.

Args:
None

Returns:
list: A single-element list containing the selected item (or empty list if cancelled or some error)
'''
try:
self.selectedItem.clear()
self._show(self.this, self.parent)
ishell_object = c_void_p()
if self._get_result(self.this, byref(ishell_object)) == 0:
ishell_item = IShellItem(ishell_object)
self.selectedItem.append(ishell_item.get_display_name())
ishell_item.release()
except OSError as e:
if len(e.args) > 3 and e.args[3] == -2147023673: # see, e.g., https://knowledge.broadcom.com/external/article/152212/error-codes-list-for-microsoft-technolog.html
pass # User cancelled dialog
else:
raise
return self.selectedItem