|
27 | 27 | clr.AddReference('System.Collections') |
28 | 28 | clr.AddReference('System.Threading') |
29 | 29 | clr.AddReference('System.Reflection') |
| 30 | +if os.environ.get('PYTHONNET_RUNTIME') == 'coreclr': |
| 31 | + clr.AddReference('Microsoft.Win32.SystemEvents') |
30 | 32 |
|
31 | 33 | import System.Windows.Forms as WinForms # noqa: E402 |
32 | 34 | from Microsoft.Win32 import SystemEvents # noqa: E402 |
@@ -84,14 +86,17 @@ def edge_build(key_type, key, description=''): |
84 | 86 |
|
85 | 87 | return '0' |
86 | 88 |
|
| 89 | + is_coreclr = os.environ.get('PYTHONNET_RUNTIME') == 'coreclr' |
| 90 | + net_key = None |
87 | 91 | try: |
88 | | - net_key = winreg.OpenKey( |
89 | | - winreg.HKEY_LOCAL_MACHINE, r'SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full' |
90 | | - ) |
91 | | - version, _ = winreg.QueryValueEx(net_key, 'Release') |
| 92 | + if not is_coreclr: |
| 93 | + net_key = winreg.OpenKey( |
| 94 | + winreg.HKEY_LOCAL_MACHINE, r'SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full' |
| 95 | + ) |
| 96 | + version, _ = winreg.QueryValueEx(net_key, 'Release') |
92 | 97 |
|
93 | | - if version < 394802: # .NET 4.6.2 |
94 | | - return False |
| 98 | + if version < 394802: # .NET 4.6.2 |
| 99 | + return False |
95 | 100 |
|
96 | 101 | build_versions = [ |
97 | 102 | { |
@@ -121,7 +126,8 @@ def edge_build(key_type, key, description=''): |
121 | 126 | except Exception as e: |
122 | 127 | logger.exception(e) |
123 | 128 | finally: |
124 | | - winreg.CloseKey(net_key) |
| 129 | + if net_key is not None: |
| 130 | + winreg.CloseKey(net_key) |
125 | 131 |
|
126 | 132 | return False |
127 | 133 |
|
@@ -487,10 +493,8 @@ def _set_window_menu(): |
487 | 493 | def create_action_item(menu_line_item): |
488 | 494 | action_item = WinForms.ToolStripMenuItem(menu_line_item.title) |
489 | 495 | # Don't run action function on main thread |
490 | | - action_item.Click += ( |
491 | | - lambda _, __, menu_line_item=menu_line_item: threading.Thread( |
492 | | - target=menu_line_item.function |
493 | | - ).start() |
| 496 | + action_item.Click += lambda _, __, menu_line_item=menu_line_item: ( |
| 497 | + threading.Thread(target=menu_line_item.function).start() |
494 | 498 | ) |
495 | 499 | return action_item |
496 | 500 |
|
@@ -641,70 +645,103 @@ def alert(message): |
641 | 645 | WinForms.MessageBox.Show(str(message)) |
642 | 646 |
|
643 | 647 |
|
644 | | -class OpenFolderDialog: |
645 | | - foldersFilter = 'Folders|\n' |
646 | | - flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic |
647 | | - windowsFormsAssembly = Assembly.LoadWithPartialName('System.Windows.Forms') |
648 | | - iFileDialogType = windowsFormsAssembly.GetType( |
649 | | - 'System.Windows.Forms.FileDialogNative+IFileDialog' |
650 | | - ) |
651 | | - OpenFileDialogType = windowsFormsAssembly.GetType('System.Windows.Forms.OpenFileDialog') |
652 | | - FileDialogType = windowsFormsAssembly.GetType('System.Windows.Forms.FileDialog') |
653 | | - createVistaDialogMethodInfo = OpenFileDialogType.GetMethod('CreateVistaDialog', flags) |
654 | | - onBeforeVistaDialogMethodInfo = OpenFileDialogType.GetMethod('OnBeforeVistaDialog', flags) |
655 | | - getOptionsMethodInfo = FileDialogType.GetMethod('GetOptions', flags) |
656 | | - setOptionsMethodInfo = iFileDialogType.GetMethod('SetOptions', flags) |
657 | | - fosPickFoldersBitFlag = ( |
658 | | - windowsFormsAssembly.GetType('System.Windows.Forms.FileDialogNative+FOS') |
659 | | - .GetField('FOS_PICKFOLDERS') |
660 | | - .GetValue(None) |
661 | | - ) |
| 648 | +if os.environ.get('PYTHONNET_RUNTIME') != 'coreclr': |
| 649 | + |
| 650 | + class OpenFolderDialog: |
| 651 | + """Folder picker dialog using FileDialogNative reflection. |
| 652 | +
|
| 653 | + Used on .NET Framework where the internal FileDialogNative types |
| 654 | + are available. Supports multiple folder selection. |
| 655 | + """ |
662 | 656 |
|
663 | | - vistaDialogEventsConstructorInfo = windowsFormsAssembly.GetType( |
664 | | - 'System.Windows.Forms.FileDialog+VistaDialogEvents' |
665 | | - ).GetConstructor(flags, None, [FileDialogType], []) |
666 | | - adviseMethodInfo = iFileDialogType.GetMethod('Advise') |
667 | | - unadviseMethodInfo = iFileDialogType.GetMethod('Unadvise') |
668 | | - showMethodInfo = iFileDialogType.GetMethod('Show') |
669 | | - |
670 | | - @classmethod |
671 | | - def show(cls, parent=None, initialDirectory=None, allow_multiple=False, title=None): |
672 | | - openFileDialog = WinForms.OpenFileDialog() |
673 | | - openFileDialog.InitialDirectory = initialDirectory |
674 | | - openFileDialog.Title = title |
675 | | - openFileDialog.Filter = OpenFolderDialog.foldersFilter |
676 | | - openFileDialog.AddExtension = False |
677 | | - openFileDialog.CheckFileExists = False |
678 | | - openFileDialog.DereferenceLinks = True |
679 | | - openFileDialog.Multiselect = allow_multiple |
680 | | - openFileDialog.RestoreDirectory = True |
681 | | - |
682 | | - iFileDialog = OpenFolderDialog.createVistaDialogMethodInfo.Invoke(openFileDialog, []) |
683 | | - OpenFolderDialog.onBeforeVistaDialogMethodInfo.Invoke(openFileDialog, [iFileDialog]) |
684 | | - options = OpenFolderDialog.getOptionsMethodInfo.Invoke(openFileDialog, []) |
685 | | - options = options.op_BitwiseOr(OpenFolderDialog.fosPickFoldersBitFlag) |
686 | | - OpenFolderDialog.setOptionsMethodInfo.Invoke(iFileDialog, [options]) |
687 | | - adviseParametersWithOutputConnectionToken = Array[Object]( |
688 | | - [ |
689 | | - OpenFolderDialog.vistaDialogEventsConstructorInfo.Invoke([openFileDialog]), |
690 | | - UInt32(0), |
691 | | - ] |
| 657 | + foldersFilter = 'Folders|\n' |
| 658 | + flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic |
| 659 | + windowsFormsAssembly = Assembly.LoadWithPartialName('System.Windows.Forms') |
| 660 | + iFileDialogType = windowsFormsAssembly.GetType( |
| 661 | + 'System.Windows.Forms.FileDialogNative+IFileDialog' |
692 | 662 | ) |
693 | | - OpenFolderDialog.adviseMethodInfo.Invoke( |
694 | | - iFileDialog, adviseParametersWithOutputConnectionToken |
| 663 | + OpenFileDialogType = windowsFormsAssembly.GetType('System.Windows.Forms.OpenFileDialog') |
| 664 | + FileDialogType = windowsFormsAssembly.GetType('System.Windows.Forms.FileDialog') |
| 665 | + createVistaDialogMethodInfo = OpenFileDialogType.GetMethod('CreateVistaDialog', flags) |
| 666 | + onBeforeVistaDialogMethodInfo = OpenFileDialogType.GetMethod('OnBeforeVistaDialog', flags) |
| 667 | + getOptionsMethodInfo = FileDialogType.GetMethod('GetOptions', flags) |
| 668 | + setOptionsMethodInfo = iFileDialogType.GetMethod('SetOptions', flags) |
| 669 | + fosPickFoldersBitFlag = ( |
| 670 | + windowsFormsAssembly.GetType('System.Windows.Forms.FileDialogNative+FOS') |
| 671 | + .GetField('FOS_PICKFOLDERS') |
| 672 | + .GetValue(None) |
695 | 673 | ) |
696 | | - dwCookie = adviseParametersWithOutputConnectionToken.GetValue(1) |
697 | | - try: |
698 | | - result = OpenFolderDialog.showMethodInfo.Invoke( |
699 | | - iFileDialog, [parent.Handle if parent else None] |
| 674 | + |
| 675 | + vistaDialogEventsConstructorInfo = windowsFormsAssembly.GetType( |
| 676 | + 'System.Windows.Forms.FileDialog+VistaDialogEvents' |
| 677 | + ).GetConstructor(flags, None, [FileDialogType], []) |
| 678 | + adviseMethodInfo = iFileDialogType.GetMethod('Advise') |
| 679 | + unadviseMethodInfo = iFileDialogType.GetMethod('Unadvise') |
| 680 | + showMethodInfo = iFileDialogType.GetMethod('Show') |
| 681 | + |
| 682 | + @classmethod |
| 683 | + def show(cls, parent=None, initialDirectory=None, allow_multiple=False, title=None): |
| 684 | + openFileDialog = WinForms.OpenFileDialog() |
| 685 | + openFileDialog.InitialDirectory = initialDirectory |
| 686 | + openFileDialog.Title = title |
| 687 | + openFileDialog.Filter = OpenFolderDialog.foldersFilter |
| 688 | + openFileDialog.AddExtension = False |
| 689 | + openFileDialog.CheckFileExists = False |
| 690 | + openFileDialog.DereferenceLinks = True |
| 691 | + openFileDialog.Multiselect = allow_multiple |
| 692 | + openFileDialog.RestoreDirectory = True |
| 693 | + |
| 694 | + iFileDialog = OpenFolderDialog.createVistaDialogMethodInfo.Invoke(openFileDialog, []) |
| 695 | + OpenFolderDialog.onBeforeVistaDialogMethodInfo.Invoke(openFileDialog, [iFileDialog]) |
| 696 | + options = OpenFolderDialog.getOptionsMethodInfo.Invoke(openFileDialog, []) |
| 697 | + options = options.op_BitwiseOr(OpenFolderDialog.fosPickFoldersBitFlag) |
| 698 | + OpenFolderDialog.setOptionsMethodInfo.Invoke(iFileDialog, [options]) |
| 699 | + adviseParametersWithOutputConnectionToken = Array[Object]( |
| 700 | + [ |
| 701 | + OpenFolderDialog.vistaDialogEventsConstructorInfo.Invoke([openFileDialog]), |
| 702 | + UInt32(0), |
| 703 | + ] |
| 704 | + ) |
| 705 | + OpenFolderDialog.adviseMethodInfo.Invoke( |
| 706 | + iFileDialog, adviseParametersWithOutputConnectionToken |
700 | 707 | ) |
701 | | - if result == 0: |
702 | | - return tuple(openFileDialog.FileNames) |
| 708 | + dwCookie = adviseParametersWithOutputConnectionToken.GetValue(1) |
| 709 | + try: |
| 710 | + result = OpenFolderDialog.showMethodInfo.Invoke( |
| 711 | + iFileDialog, [parent.Handle if parent else None] |
| 712 | + ) |
| 713 | + if result == 0: |
| 714 | + return tuple(openFileDialog.FileNames) |
703 | 715 |
|
704 | | - return None |
| 716 | + return None |
| 717 | + |
| 718 | + finally: |
| 719 | + OpenFolderDialog.unadviseMethodInfo.Invoke(iFileDialog, [UInt32(dwCookie)]) |
| 720 | + |
| 721 | +else: |
| 722 | + |
| 723 | + class OpenFolderDialog: |
| 724 | + """Folder picker dialog using FolderBrowserDialog. |
705 | 725 |
|
706 | | - finally: |
707 | | - OpenFolderDialog.unadviseMethodInfo.Invoke(iFileDialog, [UInt32(dwCookie)]) |
| 726 | + Used on coreclr (.NET 8) where the internal FileDialogNative types |
| 727 | + don't exist. FolderBrowserDialog does not support multiple folder |
| 728 | + selection; the allow_multiple parameter is accepted but ignored. |
| 729 | + """ |
| 730 | + |
| 731 | + @classmethod |
| 732 | + def show(cls, parent=None, initialDirectory=None, allow_multiple=False, title=None): |
| 733 | + dlg = WinForms.FolderBrowserDialog() |
| 734 | + if title: |
| 735 | + dlg.Description = title |
| 736 | + dlg.UseDescriptionForTitle = True |
| 737 | + if initialDirectory: |
| 738 | + dlg.SelectedPath = initialDirectory |
| 739 | + |
| 740 | + result = dlg.ShowDialog() |
| 741 | + if result == WinForms.DialogResult.OK: |
| 742 | + return (dlg.SelectedPath,) |
| 743 | + |
| 744 | + return None |
708 | 745 |
|
709 | 746 |
|
710 | 747 | _main_window_created = Event() |
|
0 commit comments