@@ -6,6 +6,7 @@ import WinAppSDK
6
6
import WinUI
7
7
import WindowsFoundation
8
8
import WinSDK
9
+ import WinUIInterop
9
10
10
11
// Many force tries are required for the WinUI backend but we don't really want them
11
12
// anywhere else so just disable them for this file.
@@ -1005,8 +1006,14 @@ public final class WinUIBackend: AppBackend {
1005
1006
resultHandler handleResult: @escaping ( DialogResult < [ URL ] > ) -> Void
1006
1007
) {
1007
1008
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
+
1010
1017
if openDialogOptions. allowMultipleSelections {
1011
1018
let promise = try ! picker. pickMultipleFilesAsync ( ) !
1012
1019
promise. completed = { operation, status in
@@ -1015,9 +1022,14 @@ public final class WinUIBackend: AppBackend {
1015
1022
let operation,
1016
1023
let result = try ? operation. getResults ( )
1017
1024
else {
1025
+ handleResult ( . cancelled)
1018
1026
return
1019
1027
}
1020
- print ( result)
1028
+
1029
+ let files = Array ( result) . compactMap { $0 }
1030
+ . map ( \. path)
1031
+ . map ( URL . init ( fileURLWithPath: ) )
1032
+ handleResult ( . success( files) )
1021
1033
}
1022
1034
} else {
1023
1035
let promise = try ! picker. pickSingleFileAsync ( ) !
@@ -1027,9 +1039,12 @@ public final class WinUIBackend: AppBackend {
1027
1039
let operation,
1028
1040
let result = try ? operation. getResults ( )
1029
1041
else {
1042
+ handleResult ( . cancelled)
1030
1043
return
1031
1044
}
1032
- print ( result)
1045
+
1046
+ let file = URL ( fileURLWithPath: result. path)
1047
+ handleResult ( . success( [ file] ) )
1033
1048
}
1034
1049
}
1035
1050
}
@@ -1040,6 +1055,28 @@ public final class WinUIBackend: AppBackend {
1040
1055
window: Window ? ,
1041
1056
resultHandler handleResult: @escaping ( DialogResult < URL > ) -> Void
1042
1057
) {
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
+ }
1043
1080
}
1044
1081
1045
1082
public func createTapGestureTarget( wrapping child: Widget , gesture: TapGesture ) -> Widget {
@@ -1215,6 +1252,23 @@ final class TapGestureTarget: WinUI.Canvas {
1215
1252
var child : WinUI . FrameworkElement ?
1216
1253
}
1217
1254
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
+
1218
1272
public class CustomWindow : WinUI . Window {
1219
1273
/// Hardcoded menu bar height from MenuBar_themeresources.xaml in the
1220
1274
/// microsoft-ui-xaml repository.
0 commit comments