I'm trying to integrate the functionality of the Windows.Graphics.Printing3D
API into a WiseJ VB.Net app to create .3mf files.
The Printing3D methods depend on UWP, so I created a sub-domain that allows the methods to function. All is well until it hits my SaveTo3mf()
method, which utilizes FileSavePicker
. At this point I get an InvalidWindowHandle
exception and the method fails on this line:
Dim storageFile = Await savePicker.PickSaveFileAsync()
I've researched the problem and I understand or think I understand the problem is the sub-domain is operating outside the main domain, so it can't retrieve a window handle. My attempt to solve this is shown below by using IInitializeWithWindow
. I used Invoke()
believing it would return the method in question to the main domain, but the error persists.
I cobbled the code together and can't claim any expertise whatsoever in manipulating domains or threading. Is an alternate approach, or is there is a mistake in my implementation? The code compiles fine with the required references.
<ComImport>
<Guid("3E68D4BD-7135-4D10-8018-9FB6D9F33FA1")>
<InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
Interface IInitializeWithWindow
Sub Initialize(ByVal hwnd As IntPtr)
End Interface
Delegate Sub Invoker(localPackage As Printing3D3MFPackage)
Public Async Sub Build3MF()
Dim packages = Await CreatePackageAsync()'method not shown, it seems to work properly once I added the sub-domain
Dim c1 As New FilePicker
Dim msd As Invoker = AddressOf c1.SaveTo3mf
msd.Invoke(packages)
End Sub
Private Class FilePicker
Inherits Page
Public Async Sub SaveTo3mf(localPackage As Printing3D3MFPackage)
Dim savePicker As FileSavePicker = New FileSavePicker()
savePicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary
savePicker.DefaultFileExtension = ".3mf"
savePicker.FileTypeChoices.Add("3MF File", {".3mf"})
Dim hWnd = Me.Handle'I added this to see if it produced a result; it does
Dim initWindow As IInitializeWithWindow = CType(CObj(savePicker), IInitializeWithWindow)
initWindow.Initialize(System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle)
Dim storageFile = Await savePicker.PickSaveFileAsync()'Fail point
If storageFile Is Nothing Then
Else
Using stream = Await localPackage.SaveAsync()
stream.Seek(0)
Using dataReader = New DataReader(stream)
Await dataReader.LoadAsync(CUInt(stream.Size))
Dim buffer = dataReader.ReadBuffer(CUInt(stream.Size))
Await FileIO.WriteBufferAsync(storageFile, buffer)
End Using
End Using
End If
End Sub
End Class
As it happens for me programming is another word for learning the hard way. My vb.net understanding is being augmented by learning WiseJ. They have a simple function Application.Download(File,"FileName"). This allowed me to take the stream directly and download it applying a file name in the process. It doesn't have the elegance of allowing the user to select a location but the file is downloaded to the "Downloads" folder for the user to access.