@@ -6,6 +6,7 @@ import WinAppSDK
66import WinUI
77import WindowsFoundation
88import WinSDK
9+ import WinUIInterop
910
1011// Many force tries are required for the WinUI backend but we don't really want them
1112// anywhere else so just disable them for this file.
@@ -1005,8 +1006,14 @@ public final class WinUIBackend: AppBackend {
10051006 resultHandler handleResult: @escaping ( DialogResult < [ URL ] > ) -> Void
10061007 ) {
10071008 let picker = FileOpenPicker ( )
1008- // TODO: Associate the picker with a window. Requires some janky WinUI
1009- // Win32 interop kinda stuff I believe.
1009+
1010+ let window = window ?? windows [ 0 ]
1011+ let hwnd = window. getHWND ( ) !
1012+ let interface : SwiftIInitializeWithWindow = try ! picker. thisPtr. QueryInterface ( )
1013+ try ! interface. initialize ( with: hwnd)
1014+
1015+ picker. fileTypeFilter. append ( " * " )
1016+
10101017 if openDialogOptions. allowMultipleSelections {
10111018 let promise = try ! picker. pickMultipleFilesAsync ( ) !
10121019 promise. completed = { operation, status in
@@ -1015,9 +1022,14 @@ public final class WinUIBackend: AppBackend {
10151022 let operation,
10161023 let result = try ? operation. getResults ( )
10171024 else {
1025+ handleResult ( . cancelled)
10181026 return
10191027 }
1020- print ( result)
1028+
1029+ let files = Array ( result) . compactMap { $0 }
1030+ . map ( \. path)
1031+ . map ( URL . init ( fileURLWithPath: ) )
1032+ handleResult ( . success( files) )
10211033 }
10221034 } else {
10231035 let promise = try ! picker. pickSingleFileAsync ( ) !
@@ -1027,9 +1039,12 @@ public final class WinUIBackend: AppBackend {
10271039 let operation,
10281040 let result = try ? operation. getResults ( )
10291041 else {
1042+ handleResult ( . cancelled)
10301043 return
10311044 }
1032- print ( result)
1045+
1046+ let file = URL ( fileURLWithPath: result. path)
1047+ handleResult ( . success( [ file] ) )
10331048 }
10341049 }
10351050 }
@@ -1040,6 +1055,28 @@ public final class WinUIBackend: AppBackend {
10401055 window: Window ? ,
10411056 resultHandler handleResult: @escaping ( DialogResult < URL > ) -> Void
10421057 ) {
1058+ let picker = FileSavePicker ( )
1059+
1060+ let window = window ?? windows [ 0 ]
1061+ let hwnd = window. getHWND ( ) !
1062+ let interface : SwiftIInitializeWithWindow = try ! picker. thisPtr. QueryInterface ( )
1063+ try ! interface. initialize ( with: hwnd)
1064+
1065+ _ = picker. fileTypeChoices. insert ( " Text " , [ " .txt " ] . toVector ( ) )
1066+ let promise = try ! picker. pickSaveFileAsync ( ) !
1067+ promise. completed = { operation, status in
1068+ guard
1069+ status == . completed,
1070+ let operation,
1071+ let result = try ? operation. getResults ( )
1072+ else {
1073+ handleResult ( . cancelled)
1074+ return
1075+ }
1076+
1077+ let file = URL ( fileURLWithPath: result. path)
1078+ handleResult ( . success( file) )
1079+ }
10431080 }
10441081
10451082 public func createTapGestureTarget( wrapping child: Widget , gesture: TapGesture ) -> Widget {
@@ -1215,6 +1252,23 @@ final class TapGestureTarget: WinUI.Canvas {
12151252 var child : WinUI . FrameworkElement ?
12161253}
12171254
1255+ class SwiftIInitializeWithWindow : WindowsFoundation . IUnknown {
1256+ override class var IID : WindowsFoundation . IID {
1257+ WindowsFoundation . IID (
1258+ Data1: 0x3E68D4BD ,
1259+ Data2: 0x7135 ,
1260+ Data3: 0x4D10 ,
1261+ Data4: ( 0x80 , 0x18 , 0x9F , 0xB6 , 0xD9 , 0xF3 , 0x3F , 0xA1 )
1262+ )
1263+ }
1264+
1265+ func initialize( with hwnd: HWND ) throws {
1266+ _ = try perform ( as: IInitializeWithWindow . self) { pThis in
1267+ try CHECKED ( pThis. pointee. lpVtbl. pointee. Initialize ( pThis, hwnd) )
1268+ }
1269+ }
1270+ }
1271+
12181272public class CustomWindow : WinUI . Window {
12191273 /// Hardcoded menu bar height from MenuBar_themeresources.xaml in the
12201274 /// microsoft-ui-xaml repository.
0 commit comments