From e65fac5e8484b7737f90948d40dfd05a49a35969 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Mon, 4 Jun 2018 17:27:33 +0200
Subject: [PATCH 1/3] Added initial implementation of fixing 3MFs through the
 Netfabb API provided through the Windows 10 Universal Windows Platform API.

---
 xs/CMakeLists.txt                       |   2 +
 xs/src/slic3r/Utils/FixModelByWin10.cpp | 287 ++++++++++++++++++++++++
 xs/src/slic3r/Utils/FixModelByWin10.hpp |  18 ++
 3 files changed, 307 insertions(+)
 create mode 100644 xs/src/slic3r/Utils/FixModelByWin10.cpp
 create mode 100644 xs/src/slic3r/Utils/FixModelByWin10.hpp

diff --git a/xs/CMakeLists.txt b/xs/CMakeLists.txt
index 77747cd07..64f4b9274 100644
--- a/xs/CMakeLists.txt
+++ b/xs/CMakeLists.txt
@@ -232,6 +232,8 @@ add_library(libslic3r_gui STATIC
     ${LIBDIR}/slic3r/GUI/FirmwareDialog.hpp
     ${LIBDIR}/slic3r/Utils/Http.cpp
     ${LIBDIR}/slic3r/Utils/Http.hpp
+    ${LIBDIR}/slic3r/Utils/FixModelByWin10.cpp
+    ${LIBDIR}/slic3r/Utils/FixModelByWin10.hpp
     ${LIBDIR}/slic3r/Utils/OctoPrint.cpp
     ${LIBDIR}/slic3r/Utils/OctoPrint.hpp
     ${LIBDIR}/slic3r/Utils/Bonjour.cpp
diff --git a/xs/src/slic3r/Utils/FixModelByWin10.cpp b/xs/src/slic3r/Utils/FixModelByWin10.cpp
new file mode 100644
index 000000000..e4b1952a4
--- /dev/null
+++ b/xs/src/slic3r/Utils/FixModelByWin10.cpp
@@ -0,0 +1,287 @@
+#ifdef HAS_WIN10SDK
+
+#include "FixModelByWin10.hpp"
+
+#include <roapi.h>
+#include <string>
+#include <cstdint>
+// for ComPtr
+#include <wrl/client.h>
+// from C:/Program Files (x86)/Windows Kits/10/Include/10.0.17134.0/
+#include <winrt/robuffer.h>
+#include <winrt/windows.storage.provider.h>
+#include <winrt/windows.graphics.printing3d.h>
+
+extern "C"{
+	// from rapi.h
+	typedef HRESULT (__stdcall* FunctionRoInitialize)(int);
+	typedef HRESULT (__stdcall* FunctionRoUninitialize)();
+	typedef HRESULT	(__stdcall* FunctionRoActivateInstance)(HSTRING activatableClassId, IInspectable **instance);
+	typedef HRESULT (__stdcall* FunctionRoGetActivationFactory)(HSTRING activatableClassId, REFIID iid, void **factory);
+	// from winstring.h
+	typedef HRESULT	(__stdcall* FunctionWindowsCreateString)(LPCWSTR sourceString, UINT32  length, HSTRING *string);
+	typedef HRESULT	(__stdcall* FunctionWindowsDelteString)(HSTRING string);
+}
+
+HMODULE							s_hRuntimeObjectLibrary  = nullptr;
+FunctionRoInitialize			s_RoInitialize			 = nullptr;
+FunctionRoUninitialize			s_RoUninitialize		 = nullptr;
+FunctionRoActivateInstance		s_RoActivateInstance     = nullptr;
+FunctionRoGetActivationFactory	s_RoGetActivationFactory = nullptr;
+FunctionWindowsCreateString		s_WindowsCreateString    = nullptr;
+FunctionWindowsDelteString		s_WindowsDeleteString    = nullptr;
+
+bool winrt_load_runtime_object_library()
+{
+	if (s_hRuntimeObjectLibrary == nullptr)
+		s_hRuntimeObjectLibrary = LoadLibrary(L"ComBase.dll");
+	if (s_hRuntimeObjectLibrary != nullptr) {
+		s_RoInitialize			 = (FunctionRoInitialize)			GetProcAddress(s_hRuntimeObjectLibrary, "RoInitialize");
+		s_RoUninitialize		 = (FunctionRoUninitialize)			GetProcAddress(s_hRuntimeObjectLibrary, "RoUninitialize");
+		s_RoActivateInstance	 = (FunctionRoActivateInstance)		GetProcAddress(s_hRuntimeObjectLibrary, "RoActivateInstance");
+		s_RoGetActivationFactory = (FunctionRoGetActivationFactory)	GetProcAddress(s_hRuntimeObjectLibrary, "RoGetActivationFactory");
+		s_WindowsCreateString	 = (FunctionWindowsCreateString)	GetProcAddress(s_hRuntimeObjectLibrary, "WindowsCreateString");
+		s_WindowsDeleteString	 = (FunctionWindowsDelteString)		GetProcAddress(s_hRuntimeObjectLibrary, "WindowsDeleteString");
+	}
+	return s_RoInitialize && s_RoUninitialize && s_RoActivateInstance && s_WindowsCreateString && s_WindowsDeleteString;
+}
+
+static HRESULT winrt_activate_instance(const std::wstring &class_name, IInspectable **pinst)
+{
+	HSTRING hClassName;
+	HRESULT hr = (*s_WindowsCreateString)(class_name.c_str(), class_name.size(), &hClassName);
+	if (S_OK != hr) 
+		return hr;
+	hr = (*s_RoActivateInstance)(hClassName, pinst);
+	(*s_WindowsDeleteString)(hClassName);
+	return hr;
+}
+
+template<typename TYPE>
+static HRESULT winrt_activate_instance(const std::wstring &class_name, TYPE **pinst)
+{
+	IInspectable *pinspectable = nullptr;
+	HRESULT hr = winrt_activate_instance(class_name, &pinspectable);
+	if (S_OK != hr)
+		return hr;
+	hr = pinspectable->QueryInterface(__uuidof(TYPE), (void**)pinst);
+	pinspectable->Release();
+	return hr;
+}
+
+static HRESULT winrt_get_activation_factory(const std::wstring &class_name, REFIID iid, void **pinst)
+{
+	HSTRING hClassName;
+	HRESULT hr = (*s_WindowsCreateString)(class_name.c_str(), class_name.size(), &hClassName);
+	if (S_OK != hr)
+		return hr;
+	hr = (*s_RoGetActivationFactory)(hClassName, iid, pinst);
+	(*s_WindowsDeleteString)(hClassName);
+	return hr;
+}
+
+template<typename TYPE>
+static HRESULT winrt_get_activation_factory(const std::wstring &class_name, TYPE **pinst)
+{
+	return winrt_get_activation_factory(class_name, __uuidof(TYPE), reinterpret_cast<void**>(pinst));
+}
+
+template<typename T>
+static AsyncStatus winrt_async_await(const Microsoft::WRL::ComPtr<T> &asyncAction, int blocking_tick_ms = 300)
+{
+	Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> asyncInfo;
+	asyncAction.As(&asyncInfo);
+	AsyncStatus status;
+	// Ugly blocking loop until the RepairAsync call finishes.
+//FIXME replace with a callback.
+// https://social.msdn.microsoft.com/Forums/en-US/a5038fb4-b7b7-4504-969d-c102faa389fb/trying-to-block-an-async-operation-and-wait-for-a-particular-time?forum=vclanguage
+	for (;;) {
+		asyncInfo->get_Status(&status);
+		if (status != AsyncStatus::Started)
+			return status;
+		::Sleep(blocking_tick_ms);
+	}
+}
+
+static HRESULT winrt_open_file_stream(
+	const std::wstring									 &path,
+	ABI::Windows::Storage::FileAccessMode				  mode,
+	ABI::Windows::Storage::Streams::IRandomAccessStream **fileStream)
+{
+	// Get the file factory.
+	Microsoft::WRL::ComPtr<ABI::Windows::Storage::IStorageFileStatics> fileFactory;
+	HRESULT hr = winrt_get_activation_factory(L"Windows.Storage.StorageFile", fileFactory.GetAddressOf());
+	if (FAILED(hr)) return hr;
+
+	// Open the file asynchronously.
+	HSTRING hstr_path;
+	hr = (*s_WindowsCreateString)(path.c_str(), path.size(), &hstr_path);
+	if (FAILED(hr)) return hr;
+	Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::StorageFile*>> fileOpenAsync;
+	hr = fileFactory->GetFileFromPathAsync(hstr_path, fileOpenAsync.GetAddressOf());
+	if (FAILED(hr)) return hr;
+	(*s_WindowsDeleteString)(hstr_path);
+
+	// Wait until the file gets open, get the actual file.
+	AsyncStatus status = winrt_async_await(fileOpenAsync);
+	Microsoft::WRL::ComPtr<ABI::Windows::Storage::IStorageFile> storageFile;
+	if (status == AsyncStatus::Completed) {
+		hr = fileOpenAsync->GetResults(storageFile.GetAddressOf());
+	} else {
+		Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> asyncInfo;
+		hr = fileOpenAsync.As(&asyncInfo);
+		if (FAILED(hr)) return hr;
+		HRESULT err;
+		hr = asyncInfo->get_ErrorCode(&err);
+		return FAILED(hr) ? hr : err;
+	}
+
+	Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::Streams::IRandomAccessStream*>> fileStreamAsync;
+	hr = storageFile->OpenAsync(mode, fileStreamAsync.GetAddressOf());
+	if (FAILED(hr)) return hr;
+
+	status = winrt_async_await(fileStreamAsync);
+	if (status == AsyncStatus::Completed) {
+		hr = fileStreamAsync->GetResults(fileStream);
+	} else {
+		Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> asyncInfo;
+		hr = fileStreamAsync.As(&asyncInfo);
+		if (FAILED(hr)) return hr;
+		HRESULT err;
+		hr = asyncInfo->get_ErrorCode(&err);
+		if (!FAILED(hr))
+			hr = err;
+	}
+	return hr;
+}
+
+bool is_windows10()
+{
+	HKEY hKey;
+	LONG lRes = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_READ, &hKey);
+	if (lRes == ERROR_SUCCESS) {
+		WCHAR szBuffer[512];
+		DWORD dwBufferSize = sizeof(szBuffer);
+		lRes = RegQueryValueExW(hKey, L"ProductName", 0, nullptr, (LPBYTE)szBuffer, &dwBufferSize);
+		if (lRes == ERROR_SUCCESS)
+			return wcsncmp(szBuffer, L"Windows 10", 10) == 0;
+		RegCloseKey(hKey);
+	}
+	return false;
+}
+
+bool fix_model_by_win10_sdk(const std::string &path_src, const std::string &path_dst)
+{
+	if (! is_windows10()) {
+		return false;
+	}
+
+	if (! winrt_load_runtime_object_library()) {
+		printf("Failed to initialize the WinRT library. This should not happen on Windows 10. Exiting.\n");
+		return -1;
+	}
+
+	(*s_RoInitialize)(RO_INIT_MULTITHREADED);
+	{
+		Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IRandomAccessStream>       fileStream;
+		HRESULT hr = winrt_open_file_stream(L"D:\\3dprint\\bug.3mf", ABI::Windows::Storage::FileAccessMode::FileAccessMode_Read, fileStream.GetAddressOf());
+
+		Microsoft::WRL::ComPtr<ABI::Windows::Graphics::Printing3D::IPrinting3D3MFPackage> printing3d3mfpackage;
+		hr = winrt_activate_instance(L"Windows.Graphics.Printing3D.Printing3D3MFPackage", printing3d3mfpackage.GetAddressOf());
+
+		Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Graphics::Printing3D::Printing3DModel*>> modelAsync;
+		hr = printing3d3mfpackage->LoadModelFromPackageAsync(fileStream.Get(), modelAsync.GetAddressOf());
+
+		AsyncStatus status = winrt_async_await(modelAsync);
+		Microsoft::WRL::ComPtr<ABI::Windows::Graphics::Printing3D::IPrinting3DModel>	  model;
+		if (status == AsyncStatus::Completed) {
+			hr = modelAsync->GetResults(model.GetAddressOf());
+		} else {
+			printf("Failed loading the input model. Exiting.\n");
+			return -1;
+		}
+
+		Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IVector<ABI::Windows::Graphics::Printing3D::Printing3DMesh*>> meshes;
+		hr = model->get_Meshes(meshes.GetAddressOf());
+		unsigned num_meshes = 0;
+		hr = meshes->get_Size(&num_meshes);
+		
+		Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncAction>					  repairAsync;
+		hr = model->RepairAsync(repairAsync.GetAddressOf());
+		status = winrt_async_await(repairAsync);
+		if (status != AsyncStatus::Completed) {
+			printf("Mesh repair failed. Exiting.\n");
+			return -1;
+		}
+		printf("Mesh repair finished successfully.\n");
+		repairAsync->GetResults();
+
+		// Verify the number of meshes returned after the repair action.
+		meshes.Reset();
+		hr = model->get_Meshes(meshes.GetAddressOf());
+		hr = meshes->get_Size(&num_meshes);
+
+		// Save model to this class' Printing3D3MFPackage.
+		Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncAction>					  saveToPackageAsync;
+		hr = printing3d3mfpackage->SaveModelToPackageAsync(model.Get(), saveToPackageAsync.GetAddressOf());
+		status = winrt_async_await(saveToPackageAsync);
+		if (status != AsyncStatus::Completed) {
+			printf("Saving mesh into the 3MF container failed. Exiting.\n");
+			return -1;
+		}
+		hr = saveToPackageAsync->GetResults();
+
+		Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::Streams::IRandomAccessStream*>> generatorStreamAsync;
+		hr = printing3d3mfpackage->SaveAsync(generatorStreamAsync.GetAddressOf());
+		status = winrt_async_await(generatorStreamAsync);
+		if (status != AsyncStatus::Completed) {
+			printf("Saving mesh into the 3MF container failed. Exiting.\n");
+			return -1;
+		}
+		Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IRandomAccessStream> generatorStream;
+		hr = generatorStreamAsync->GetResults(generatorStream.GetAddressOf());
+
+		// Go to the beginning of the stream.
+		generatorStream->Seek(0);
+		Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IInputStream> inputStream;
+		hr = generatorStream.As(&inputStream);
+
+		// Get the buffer factory.
+		Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IBufferFactory> bufferFactory;
+		hr = winrt_get_activation_factory(L"Windows.Storage.Streams.Buffer", bufferFactory.GetAddressOf());
+
+		// Open the destination file.
+		FILE *fout = ::fopen("D:\\3dprint\\bug-repaired.3mf", "wb");
+
+		Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IBuffer> buffer;
+		byte														   *buffer_ptr;
+		bufferFactory->Create(65536 * 2048, buffer.GetAddressOf());
+		{
+			Microsoft::WRL::ComPtr<Windows::Storage::Streams::IBufferByteAccess> bufferByteAccess;
+			buffer.As(&bufferByteAccess);
+			hr = bufferByteAccess->Buffer(&buffer_ptr);
+		}
+		uint32_t length;
+		hr = buffer->get_Length(&length);
+
+		Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperationWithProgress<ABI::Windows::Storage::Streams::IBuffer*, UINT32>> asyncRead;
+		for (;;) {
+			hr = inputStream->ReadAsync(buffer.Get(), 65536 * 2048, ABI::Windows::Storage::Streams::InputStreamOptions_ReadAhead, asyncRead.GetAddressOf());
+			status = winrt_async_await(asyncRead);
+			if (status != AsyncStatus::Completed) {
+				printf("Saving mesh into the 3MF container failed. Exiting.\n");
+				return -1;
+			}
+			hr = buffer->get_Length(&length);
+			if (length == 0)
+				break;
+			fwrite(buffer_ptr, length, 1, fout);
+		}
+		fclose(fout);
+		// Here all the COM objects will be released through the ComPtr destructors.
+	}
+	(*s_RoUninitialize)();
+	return 0;
+}
+
+#endif /* HAS_WIN10SDK */
diff --git a/xs/src/slic3r/Utils/FixModelByWin10.hpp b/xs/src/slic3r/Utils/FixModelByWin10.hpp
new file mode 100644
index 000000000..268b614ef
--- /dev/null
+++ b/xs/src/slic3r/Utils/FixModelByWin10.hpp
@@ -0,0 +1,18 @@
+#ifndef slic3r_GUI_Utils_FixModelByWin10_hpp_
+#define slic3r_GUI_Utils_FixModelByWin10_hpp_
+
+#include <string>
+
+#ifdef HAS_WIN10SDK
+
+extern bool is_windows10();
+extern bool fix_model_by_win10_sdk(const std::string &path_src, const std::string &path_dst);
+
+#else /* HAS_WIN10SDK */
+
+inline bool is_windows10() { return false; }
+inline bool fix_model_by_win10_sdk(const std::string &, const std::string &) { return false; }
+
+#endif /* HAS_WIN10SDK *
+
+#endif /* slic3r_GUI_Utils_FixModelByWin10_hpp_ */

From d05d3cb652de8dfc156b62e940aaf8a7422dee20 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Mon, 4 Jun 2018 21:22:42 +0200
Subject: [PATCH 2/3] Initial working implementation of the "Fix by Netfabb"
 function.

---
 CMakeLists.txt                          | 16 ++++++
 lib/Slic3r/GUI/Plater.pm                | 33 ++++++++++++
 xs/CMakeLists.txt                       |  7 +++
 xs/src/slic3r/Utils/FixModelByWin10.cpp | 72 +++++++++++++++++++++----
 xs/src/slic3r/Utils/FixModelByWin10.hpp | 12 ++++-
 xs/xsp/GUI.xsp                          |  7 +++
 6 files changed, 136 insertions(+), 11 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index e8b2a6faa..60d67553b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -49,6 +49,22 @@ if(NOT DEFINED CMAKE_PREFIX_PATH)
 	endif()
 endif()
 
+# WIN10SDK_PATH is used to point CMake to the WIN10 SDK installation directory.
+# We pick it from environment if it is not defined in another way
+if(WIN32)
+	if(NOT DEFINED WIN10SDK_PATH)
+		if(DEFINED ENV{WIN10SDK_PATH})
+			set(WIN10SDK_PATH "$ENV{WIN10SDK_PATH}")
+		endif()
+	endif()
+	if(DEFINED WIN10SDK_PATH AND NOT EXISTS "${WIN10SDK_PATH}/include/winrt/windows.graphics.printing3d.h")
+		message("WIN10SDK_PATH is invalid: ${WIN10SDK_PATH}")
+		message("${WIN10SDK_PATH}/include/winrt/windows.graphics.printing3d.h was not found")
+		message("STL fixing by the Netfabb service will not be compiled")
+		unset(WIN10SDK_PATH)
+	endif()
+endif()
+
 add_subdirectory(xs)
 
 get_filename_component(PERL_BIN_PATH "${PERL_EXECUTABLE}" DIRECTORY)
diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm
index d27be785c..40c2a1351 100644
--- a/lib/Slic3r/GUI/Plater.pm
+++ b/lib/Slic3r/GUI/Plater.pm
@@ -1620,6 +1620,34 @@ sub export_object_stl {
     $self->statusbar->SetStatusText(L("STL file exported to ").$output_file);
 }
 
+sub fix_through_netfabb {
+    my ($self) = @_;
+    my ($obj_idx, $object) = $self->selected_object;
+    return if !defined $obj_idx;
+    my $model_object = $self->{model}->objects->[$obj_idx];
+    my $model_fixed = Slic3r::Model->new;
+    Slic3r::GUI::fix_model_by_win10_sdk_gui($model_object, $self->{print}, $model_fixed);
+
+    my @new_obj_idx = $self->load_model_objects(@{$model_fixed->objects});
+    return if !@new_obj_idx;
+    
+    foreach my $new_obj_idx (@new_obj_idx) {
+        my $o = $self->{model}->objects->[$new_obj_idx];
+        $o->clear_instances;
+        $o->add_instance($_) for @{$model_object->instances};
+        #$o->invalidate_bounding_box;
+        
+        if ($o->volumes_count == $model_object->volumes_count) {
+            for my $i (0..($o->volumes_count-1)) {
+                $o->get_volume($i)->config->apply($model_object->get_volume($i)->config);
+            }
+        }
+        #FIXME restore volumes and their configs, layer_height_ranges, layer_height_profile, layer_height_profile_valid,
+    }
+    
+    $self->remove($obj_idx);
+}
+
 sub export_amf {
     my ($self) = @_;
     return if !@{$self->{objects}};
@@ -2178,6 +2206,11 @@ sub object_menu {
     $frame->_append_menu_item($menu, L("Export object as STL…"), L('Export this single object as STL file'), sub {
         $self->export_object_stl;
     }, undef, 'brick_go.png');
+    if (Slic3r::GUI::is_windows10) {
+        $frame->_append_menu_item($menu, L("Fix STL through Netfabb"), L('Fix the model by sending it to a Netfabb cloud service through Windows 10 API'), sub {
+            $self->fix_through_netfabb;
+        }, undef, 'brick_go.png');
+    }
     
     return $menu;
 }
diff --git a/xs/CMakeLists.txt b/xs/CMakeLists.txt
index 64f4b9274..866374584 100644
--- a/xs/CMakeLists.txt
+++ b/xs/CMakeLists.txt
@@ -27,6 +27,13 @@ if(WIN32)
     # BOOST_ALL_NO_LIB: Avoid the automatic linking of Boost libraries on Windows. Rather rely on explicit linking.
     add_definitions(-D_USE_MATH_DEFINES -D_WIN32 -DBOOST_ALL_NO_LIB)
     # -D_ITERATOR_DEBUG_LEVEL)
+    if(WIN10SDK_PATH)
+        message("Building with Win10 Netfabb STL fixing service support")
+        add_definitions(-DHAS_WIN10SDK)
+        include_directories("${WIN10SDK_PATH}/Include")
+    else()
+        message("Building without Win10 Netfabb STL fixing service support")
+    endif()
 endif()
 
 add_definitions(-DwxUSE_UNICODE -D_UNICODE -DUNICODE)
diff --git a/xs/src/slic3r/Utils/FixModelByWin10.cpp b/xs/src/slic3r/Utils/FixModelByWin10.cpp
index e4b1952a4..27a79f84e 100644
--- a/xs/src/slic3r/Utils/FixModelByWin10.cpp
+++ b/xs/src/slic3r/Utils/FixModelByWin10.cpp
@@ -1,10 +1,15 @@
 #ifdef HAS_WIN10SDK
 
+#ifndef NOMINMAX
+# define NOMINMAX
+#endif
+
 #include "FixModelByWin10.hpp"
 
 #include <roapi.h>
 #include <string>
 #include <cstdint>
+#include <thread>
 // for ComPtr
 #include <wrl/client.h>
 // from C:/Program Files (x86)/Windows Kits/10/Include/10.0.17134.0/
@@ -12,6 +17,18 @@
 #include <winrt/windows.storage.provider.h>
 #include <winrt/windows.graphics.printing3d.h>
 
+#include <boost/filesystem.hpp>
+#include <boost/nowide/convert.hpp>
+#include <boost/nowide/cstdio.hpp>
+
+#include "libslic3r/Model.hpp"
+#include "libslic3r/Print.hpp"
+#include "libslic3r/Format/3mf.hpp"
+#include "../GUI/GUI.hpp"
+#include "../GUI/PresetBundle.hpp"
+
+#include <wx/progdlg.h>
+
 extern "C"{
 	// from rapi.h
 	typedef HRESULT (__stdcall* FunctionRoInitialize)(int);
@@ -23,6 +40,8 @@ extern "C"{
 	typedef HRESULT	(__stdcall* FunctionWindowsDelteString)(HSTRING string);
 }
 
+namespace Slic3r {
+
 HMODULE							s_hRuntimeObjectLibrary  = nullptr;
 FunctionRoInitialize			s_RoInitialize			 = nullptr;
 FunctionRoUninitialize			s_RoUninitialize		 = nullptr;
@@ -178,13 +197,13 @@ bool fix_model_by_win10_sdk(const std::string &path_src, const std::string &path
 
 	if (! winrt_load_runtime_object_library()) {
 		printf("Failed to initialize the WinRT library. This should not happen on Windows 10. Exiting.\n");
-		return -1;
+		return false;
 	}
 
-	(*s_RoInitialize)(RO_INIT_MULTITHREADED);
+	HRESULT hr = (*s_RoInitialize)(RO_INIT_MULTITHREADED);
 	{
 		Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IRandomAccessStream>       fileStream;
-		HRESULT hr = winrt_open_file_stream(L"D:\\3dprint\\bug.3mf", ABI::Windows::Storage::FileAccessMode::FileAccessMode_Read, fileStream.GetAddressOf());
+		hr = winrt_open_file_stream(boost::nowide::widen(path_src), ABI::Windows::Storage::FileAccessMode::FileAccessMode_Read, fileStream.GetAddressOf());
 
 		Microsoft::WRL::ComPtr<ABI::Windows::Graphics::Printing3D::IPrinting3D3MFPackage> printing3d3mfpackage;
 		hr = winrt_activate_instance(L"Windows.Graphics.Printing3D.Printing3D3MFPackage", printing3d3mfpackage.GetAddressOf());
@@ -198,7 +217,7 @@ bool fix_model_by_win10_sdk(const std::string &path_src, const std::string &path
 			hr = modelAsync->GetResults(model.GetAddressOf());
 		} else {
 			printf("Failed loading the input model. Exiting.\n");
-			return -1;
+			return false;
 		}
 
 		Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IVector<ABI::Windows::Graphics::Printing3D::Printing3DMesh*>> meshes;
@@ -211,7 +230,7 @@ bool fix_model_by_win10_sdk(const std::string &path_src, const std::string &path
 		status = winrt_async_await(repairAsync);
 		if (status != AsyncStatus::Completed) {
 			printf("Mesh repair failed. Exiting.\n");
-			return -1;
+			return false;
 		}
 		printf("Mesh repair finished successfully.\n");
 		repairAsync->GetResults();
@@ -227,7 +246,7 @@ bool fix_model_by_win10_sdk(const std::string &path_src, const std::string &path
 		status = winrt_async_await(saveToPackageAsync);
 		if (status != AsyncStatus::Completed) {
 			printf("Saving mesh into the 3MF container failed. Exiting.\n");
-			return -1;
+			return false;
 		}
 		hr = saveToPackageAsync->GetResults();
 
@@ -236,7 +255,7 @@ bool fix_model_by_win10_sdk(const std::string &path_src, const std::string &path
 		status = winrt_async_await(generatorStreamAsync);
 		if (status != AsyncStatus::Completed) {
 			printf("Saving mesh into the 3MF container failed. Exiting.\n");
-			return -1;
+			return false;
 		}
 		Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IRandomAccessStream> generatorStream;
 		hr = generatorStreamAsync->GetResults(generatorStream.GetAddressOf());
@@ -251,7 +270,7 @@ bool fix_model_by_win10_sdk(const std::string &path_src, const std::string &path
 		hr = winrt_get_activation_factory(L"Windows.Storage.Streams.Buffer", bufferFactory.GetAddressOf());
 
 		// Open the destination file.
-		FILE *fout = ::fopen("D:\\3dprint\\bug-repaired.3mf", "wb");
+		FILE *fout = boost::nowide::fopen(path_dst.c_str(), "wb");
 
 		Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IBuffer> buffer;
 		byte														   *buffer_ptr;
@@ -270,7 +289,7 @@ bool fix_model_by_win10_sdk(const std::string &path_src, const std::string &path
 			status = winrt_async_await(asyncRead);
 			if (status != AsyncStatus::Completed) {
 				printf("Saving mesh into the 3MF container failed. Exiting.\n");
-				return -1;
+				return false;
 			}
 			hr = buffer->get_Length(&length);
 			if (length == 0)
@@ -281,7 +300,40 @@ bool fix_model_by_win10_sdk(const std::string &path_src, const std::string &path
 		// Here all the COM objects will be released through the ComPtr destructors.
 	}
 	(*s_RoUninitialize)();
-	return 0;
+	return true;
 }
 
+void fix_model_by_win10_sdk_gui(const ModelObject &model_object, const Print &print, Model &result)
+{
+	enum { PROGRESS_RANGE = 1000 };
+	wxProgressDialog progress_dialog(
+		_(L("Model fixing")),
+		_(L("Exporting model...")),
+		PROGRESS_RANGE, nullptr, wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT);
+	progress_dialog.Pulse();
+
+	// Executing the calculation in a background thread, so that the COM context could be created with its own threading model.
+	// (It seems like wxWidgets initialize the COM contex as single threaded and we need a multi-threaded context).
+	auto worker = std::thread([&model_object, &print, &result, &progress_dialog](){
+		boost::filesystem::path path_src = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
+		path_src += ".3mf";
+		Model model;
+		model.add_object(model_object);
+		bool res = Slic3r::store_3mf(path_src.string().c_str(), &model, const_cast<Print*>(&print), false);
+		model.clear_objects(); 
+		model.clear_materials();
+
+		boost::filesystem::path path_dst = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
+		path_dst += ".3mf";
+		res = fix_model_by_win10_sdk(path_src.string().c_str(), path_dst.string());
+		boost::filesystem::remove(path_src);
+		PresetBundle bundle;
+	    res = Slic3r::load_3mf(path_dst.string().c_str(), &bundle, &result);
+		boost::filesystem::remove(path_dst);
+	});
+	worker.join();
+}
+
+} // namespace Slic3r
+
 #endif /* HAS_WIN10SDK */
diff --git a/xs/src/slic3r/Utils/FixModelByWin10.hpp b/xs/src/slic3r/Utils/FixModelByWin10.hpp
index 268b614ef..299c9b75b 100644
--- a/xs/src/slic3r/Utils/FixModelByWin10.hpp
+++ b/xs/src/slic3r/Utils/FixModelByWin10.hpp
@@ -3,16 +3,26 @@
 
 #include <string>
 
+namespace Slic3r {
+
+class Model;
+class ModelObject;
+class Print;
+
 #ifdef HAS_WIN10SDK
 
 extern bool is_windows10();
 extern bool fix_model_by_win10_sdk(const std::string &path_src, const std::string &path_dst);
+extern void fix_model_by_win10_sdk_gui(const ModelObject &model_object, const Print &print, Model &result);
 
 #else /* HAS_WIN10SDK */
 
 inline bool is_windows10() { return false; }
 inline bool fix_model_by_win10_sdk(const std::string &, const std::string &) { return false; }
+inline void fix_model_by_win10_sdk_gui(const ModelObject &, const Print &, Model &) {}
 
-#endif /* HAS_WIN10SDK *
+#endif /* HAS_WIN10SDK */
+
+} // namespace Slic3r
 
 #endif /* slic3r_GUI_Utils_FixModelByWin10_hpp_ */
diff --git a/xs/xsp/GUI.xsp b/xs/xsp/GUI.xsp
index 897e63693..1d860d284 100644
--- a/xs/xsp/GUI.xsp
+++ b/xs/xsp/GUI.xsp
@@ -4,6 +4,7 @@
 #include <xsinit.h>
 #include "slic3r/GUI/GUI.hpp"
 #include "slic3r/Utils/ASCIIFolding.hpp"
+#include "slic3r/Utils/FixModelByWin10.hpp"
 #include "slic3r/Utils/Serial.hpp"
 %}
 
@@ -28,6 +29,9 @@ bool debugged()
 void break_to_debugger()
     %code{% Slic3r::GUI::break_to_debugger(); %};
 
+bool is_windows10()
+    %code{% RETVAL=Slic3r::is_windows10(); %};
+
 void set_wxapp(SV *ui)
     %code%{ Slic3r::GUI::set_wxapp((wxApp*)wxPli_sv_2_object(aTHX_ ui, "Wx::App")); %};
 
@@ -98,3 +102,6 @@ int get_export_option(SV *ui)
     
 void desktop_open_datadir_folder()
     %code%{ Slic3r::GUI::desktop_open_datadir_folder(); %};
+
+void fix_model_by_win10_sdk_gui(ModelObject *model_object_src, Print *print, Model *model_dst)
+    %code%{ Slic3r::fix_model_by_win10_sdk_gui(*model_object_src, *print, *model_dst); %};

From ce6a23ef3bc0e0caefdc96efc002a9a98339d50f Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Wed, 6 Jun 2018 15:19:06 +0200
Subject: [PATCH 3/3] Repair by the netfabb service: Implemented progress
 dialog and cancelation.

---
 xs/src/slic3r/Utils/FixModelByWin10.cpp | 201 ++++++++++++++++--------
 xs/src/slic3r/Utils/FixModelByWin10.hpp |   2 -
 2 files changed, 132 insertions(+), 71 deletions(-)

diff --git a/xs/src/slic3r/Utils/FixModelByWin10.cpp b/xs/src/slic3r/Utils/FixModelByWin10.cpp
index 27a79f84e..556035a5b 100644
--- a/xs/src/slic3r/Utils/FixModelByWin10.cpp
+++ b/xs/src/slic3r/Utils/FixModelByWin10.cpp
@@ -6,10 +6,19 @@
 
 #include "FixModelByWin10.hpp"
 
-#include <roapi.h>
-#include <string>
+#include <atomic>
+#include <chrono>
 #include <cstdint>
+#include <condition_variable>
+#include <exception>
+#include <string>
 #include <thread>
+
+#include <boost/filesystem.hpp>
+#include <boost/nowide/convert.hpp>
+#include <boost/nowide/cstdio.hpp>
+
+#include <roapi.h>
 // for ComPtr
 #include <wrl/client.h>
 // from C:/Program Files (x86)/Windows Kits/10/Include/10.0.17134.0/
@@ -17,16 +26,13 @@
 #include <winrt/windows.storage.provider.h>
 #include <winrt/windows.graphics.printing3d.h>
 
-#include <boost/filesystem.hpp>
-#include <boost/nowide/convert.hpp>
-#include <boost/nowide/cstdio.hpp>
-
 #include "libslic3r/Model.hpp"
 #include "libslic3r/Print.hpp"
 #include "libslic3r/Format/3mf.hpp"
 #include "../GUI/GUI.hpp"
 #include "../GUI/PresetBundle.hpp"
 
+#include <wx/msgdlg.h>
 #include <wx/progdlg.h>
 
 extern "C"{
@@ -105,8 +111,11 @@ static HRESULT winrt_get_activation_factory(const std::wstring &class_name, TYPE
 	return winrt_get_activation_factory(class_name, __uuidof(TYPE), reinterpret_cast<void**>(pinst));
 }
 
+// To be called often to test whether to cancel the operation.
+typedef std::function<void ()> ThrowOnCancelFn;
+
 template<typename T>
-static AsyncStatus winrt_async_await(const Microsoft::WRL::ComPtr<T> &asyncAction, int blocking_tick_ms = 300)
+static AsyncStatus winrt_async_await(const Microsoft::WRL::ComPtr<T> &asyncAction, ThrowOnCancelFn throw_on_cancel, int blocking_tick_ms = 100)
 {
 	Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> asyncInfo;
 	asyncAction.As(&asyncInfo);
@@ -118,6 +127,7 @@ static AsyncStatus winrt_async_await(const Microsoft::WRL::ComPtr<T> &asyncActio
 		asyncInfo->get_Status(&status);
 		if (status != AsyncStatus::Started)
 			return status;
+		throw_on_cancel();
 		::Sleep(blocking_tick_ms);
 	}
 }
@@ -125,7 +135,8 @@ static AsyncStatus winrt_async_await(const Microsoft::WRL::ComPtr<T> &asyncActio
 static HRESULT winrt_open_file_stream(
 	const std::wstring									 &path,
 	ABI::Windows::Storage::FileAccessMode				  mode,
-	ABI::Windows::Storage::Streams::IRandomAccessStream **fileStream)
+	ABI::Windows::Storage::Streams::IRandomAccessStream **fileStream,
+	ThrowOnCancelFn										  throw_on_cancel)
 {
 	// Get the file factory.
 	Microsoft::WRL::ComPtr<ABI::Windows::Storage::IStorageFileStatics> fileFactory;
@@ -142,7 +153,7 @@ static HRESULT winrt_open_file_stream(
 	(*s_WindowsDeleteString)(hstr_path);
 
 	// Wait until the file gets open, get the actual file.
-	AsyncStatus status = winrt_async_await(fileOpenAsync);
+	AsyncStatus status = winrt_async_await(fileOpenAsync, throw_on_cancel);
 	Microsoft::WRL::ComPtr<ABI::Windows::Storage::IStorageFile> storageFile;
 	if (status == AsyncStatus::Completed) {
 		hr = fileOpenAsync->GetResults(storageFile.GetAddressOf());
@@ -159,7 +170,7 @@ static HRESULT winrt_open_file_stream(
 	hr = storageFile->OpenAsync(mode, fileStreamAsync.GetAddressOf());
 	if (FAILED(hr)) return hr;
 
-	status = winrt_async_await(fileStreamAsync);
+	status = winrt_async_await(fileStreamAsync, throw_on_cancel);
 	if (status == AsyncStatus::Completed) {
 		hr = fileStreamAsync->GetResults(fileStream);
 	} else {
@@ -189,21 +200,23 @@ bool is_windows10()
 	return false;
 }
 
-bool fix_model_by_win10_sdk(const std::string &path_src, const std::string &path_dst)
-{
-	if (! is_windows10()) {
-		return false;
-	}
+// Progress function, to be called regularly to update the progress.
+typedef std::function<void (const char * /* message */, unsigned /* progress */)> ProgressFn;
 
-	if (! winrt_load_runtime_object_library()) {
-		printf("Failed to initialize the WinRT library. This should not happen on Windows 10. Exiting.\n");
-		return false;
-	}
+void fix_model_by_win10_sdk(const std::string &path_src, const std::string &path_dst, ProgressFn on_progress, ThrowOnCancelFn throw_on_cancel)
+{
+	if (! is_windows10())
+		throw std::runtime_error("fix_model_by_win10_sdk called on non Windows 10 system");
+
+	if (! winrt_load_runtime_object_library())
+		throw std::runtime_error("Failed to initialize the WinRT library.");
 
 	HRESULT hr = (*s_RoInitialize)(RO_INIT_MULTITHREADED);
 	{
+		on_progress(L("Exporting the source model"), 20);
+
 		Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IRandomAccessStream>       fileStream;
-		hr = winrt_open_file_stream(boost::nowide::widen(path_src), ABI::Windows::Storage::FileAccessMode::FileAccessMode_Read, fileStream.GetAddressOf());
+		hr = winrt_open_file_stream(boost::nowide::widen(path_src), ABI::Windows::Storage::FileAccessMode::FileAccessMode_Read, fileStream.GetAddressOf(), throw_on_cancel);
 
 		Microsoft::WRL::ComPtr<ABI::Windows::Graphics::Printing3D::IPrinting3D3MFPackage> printing3d3mfpackage;
 		hr = winrt_activate_instance(L"Windows.Graphics.Printing3D.Printing3D3MFPackage", printing3d3mfpackage.GetAddressOf());
@@ -211,30 +224,29 @@ bool fix_model_by_win10_sdk(const std::string &path_src, const std::string &path
 		Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Graphics::Printing3D::Printing3DModel*>> modelAsync;
 		hr = printing3d3mfpackage->LoadModelFromPackageAsync(fileStream.Get(), modelAsync.GetAddressOf());
 
-		AsyncStatus status = winrt_async_await(modelAsync);
+		AsyncStatus status = winrt_async_await(modelAsync, throw_on_cancel);
 		Microsoft::WRL::ComPtr<ABI::Windows::Graphics::Printing3D::IPrinting3DModel>	  model;
-		if (status == AsyncStatus::Completed) {
+		if (status == AsyncStatus::Completed)
 			hr = modelAsync->GetResults(model.GetAddressOf());
-		} else {
-			printf("Failed loading the input model. Exiting.\n");
-			return false;
-		}
+		else
+			throw std::runtime_error(L("Failed loading the input model."));
 
 		Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IVector<ABI::Windows::Graphics::Printing3D::Printing3DMesh*>> meshes;
 		hr = model->get_Meshes(meshes.GetAddressOf());
 		unsigned num_meshes = 0;
 		hr = meshes->get_Size(&num_meshes);
 		
+		on_progress(L("Repairing the model by the Netfabb service"), 40);
+		
 		Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncAction>					  repairAsync;
 		hr = model->RepairAsync(repairAsync.GetAddressOf());
-		status = winrt_async_await(repairAsync);
-		if (status != AsyncStatus::Completed) {
-			printf("Mesh repair failed. Exiting.\n");
-			return false;
-		}
-		printf("Mesh repair finished successfully.\n");
+		status = winrt_async_await(repairAsync, throw_on_cancel);
+		if (status != AsyncStatus::Completed)
+			throw std::runtime_error(L("Mesh repair failed."));
 		repairAsync->GetResults();
 
+		on_progress(L("Loading the repaired model"), 60);
+
 		// Verify the number of meshes returned after the repair action.
 		meshes.Reset();
 		hr = model->get_Meshes(meshes.GetAddressOf());
@@ -243,20 +255,16 @@ bool fix_model_by_win10_sdk(const std::string &path_src, const std::string &path
 		// Save model to this class' Printing3D3MFPackage.
 		Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncAction>					  saveToPackageAsync;
 		hr = printing3d3mfpackage->SaveModelToPackageAsync(model.Get(), saveToPackageAsync.GetAddressOf());
-		status = winrt_async_await(saveToPackageAsync);
-		if (status != AsyncStatus::Completed) {
-			printf("Saving mesh into the 3MF container failed. Exiting.\n");
-			return false;
-		}
+		status = winrt_async_await(saveToPackageAsync, throw_on_cancel);
+		if (status != AsyncStatus::Completed)
+			throw std::runtime_error(L("Saving mesh into the 3MF container failed."));
 		hr = saveToPackageAsync->GetResults();
 
 		Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::Streams::IRandomAccessStream*>> generatorStreamAsync;
 		hr = printing3d3mfpackage->SaveAsync(generatorStreamAsync.GetAddressOf());
-		status = winrt_async_await(generatorStreamAsync);
-		if (status != AsyncStatus::Completed) {
-			printf("Saving mesh into the 3MF container failed. Exiting.\n");
-			return false;
-		}
+		status = winrt_async_await(generatorStreamAsync, throw_on_cancel);
+		if (status != AsyncStatus::Completed)
+			throw std::runtime_error(L("Saving mesh into the 3MF container failed."));
 		Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IRandomAccessStream> generatorStream;
 		hr = generatorStreamAsync->GetResults(generatorStream.GetAddressOf());
 
@@ -286,11 +294,9 @@ bool fix_model_by_win10_sdk(const std::string &path_src, const std::string &path
 		Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperationWithProgress<ABI::Windows::Storage::Streams::IBuffer*, UINT32>> asyncRead;
 		for (;;) {
 			hr = inputStream->ReadAsync(buffer.Get(), 65536 * 2048, ABI::Windows::Storage::Streams::InputStreamOptions_ReadAhead, asyncRead.GetAddressOf());
-			status = winrt_async_await(asyncRead);
-			if (status != AsyncStatus::Completed) {
-				printf("Saving mesh into the 3MF container failed. Exiting.\n");
-				return false;
-			}
+			status = winrt_async_await(asyncRead, throw_on_cancel);
+			if (status != AsyncStatus::Completed)
+				throw std::runtime_error(L("Saving mesh into the 3MF container failed."));
 			hr = buffer->get_Length(&length);
 			if (length == 0)
 				break;
@@ -300,38 +306,95 @@ bool fix_model_by_win10_sdk(const std::string &path_src, const std::string &path
 		// Here all the COM objects will be released through the ComPtr destructors.
 	}
 	(*s_RoUninitialize)();
-	return true;
 }
 
+class RepairCanceledException : public std::exception {
+public:
+   const char* what() const throw() { return "Model repair has been canceled"; }
+};
+
 void fix_model_by_win10_sdk_gui(const ModelObject &model_object, const Print &print, Model &result)
 {
-	enum { PROGRESS_RANGE = 1000 };
+	std::mutex 						mutex;
+	std::condition_variable			condition;
+	std::unique_lock<std::mutex>	lock(mutex);
+	struct Progress {
+		std::string 				message;
+		int 						percent  = 0;
+		bool						updated = false;
+	} progress;
+	std::atomic<bool>				canceled = false;
+	std::atomic<bool>				finished = false;
+
+	// Open a progress dialog.
 	wxProgressDialog progress_dialog(
 		_(L("Model fixing")),
 		_(L("Exporting model...")),
-		PROGRESS_RANGE, nullptr, wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT);
-	progress_dialog.Pulse();
-
+		100, nullptr, wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT);
 	// Executing the calculation in a background thread, so that the COM context could be created with its own threading model.
 	// (It seems like wxWidgets initialize the COM contex as single threaded and we need a multi-threaded context).
-	auto worker = std::thread([&model_object, &print, &result, &progress_dialog](){
-		boost::filesystem::path path_src = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
-		path_src += ".3mf";
-		Model model;
-		model.add_object(model_object);
-		bool res = Slic3r::store_3mf(path_src.string().c_str(), &model, const_cast<Print*>(&print), false);
-		model.clear_objects(); 
-		model.clear_materials();
-
-		boost::filesystem::path path_dst = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
-		path_dst += ".3mf";
-		res = fix_model_by_win10_sdk(path_src.string().c_str(), path_dst.string());
-		boost::filesystem::remove(path_src);
-		PresetBundle bundle;
-	    res = Slic3r::load_3mf(path_dst.string().c_str(), &bundle, &result);
-		boost::filesystem::remove(path_dst);
+	bool success  = false;
+	auto on_progress = [&mutex, &condition, &progress](const char *msg, unsigned prcnt) {
+        std::lock_guard<std::mutex> lk(mutex);
+		progress.message = msg;
+		progress.percent = prcnt;
+		progress.updated = true;
+	    condition.notify_all();
+	};
+	auto worker_thread = boost::thread([&model_object, &print, &result, on_progress, &success, &canceled, &finished]() {
+		try {
+			on_progress(L("Exporting the source model"), 0);
+			boost::filesystem::path path_src = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
+			path_src += ".3mf";
+			Model model;
+			model.add_object(model_object);
+			if (! Slic3r::store_3mf(path_src.string().c_str(), &model, const_cast<Print*>(&print), false)) {
+				boost::filesystem::remove(path_src);
+				throw std::runtime_error(L("Export of a temporary 3mf file failed"));
+			}
+			model.clear_objects(); 
+			model.clear_materials();
+			boost::filesystem::path path_dst = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
+			path_dst += ".3mf";
+			fix_model_by_win10_sdk(path_src.string().c_str(), path_dst.string(), on_progress, 
+				[&canceled]() { if (canceled) throw RepairCanceledException(); });
+			boost::filesystem::remove(path_src);
+			PresetBundle bundle;
+			on_progress(L("Loading the repaired model"), 80);
+		    bool loaded = Slic3r::load_3mf(path_dst.string().c_str(), &bundle, &result);
+			boost::filesystem::remove(path_dst);
+			if (! loaded)
+ 				throw std::runtime_error(L("Import of the repaired 3mf file failed"));
+			success  = true;
+			finished = true;
+			on_progress(L("Model repair finished"), 100);
+		} catch (RepairCanceledException &ex) {
+			canceled = true;
+			finished = true;
+			on_progress(L("Model repair canceled"), 100);
+		} catch (std::exception &ex) {
+			success = false;
+			finished = true;
+			on_progress(ex.what(), 100);
+		}
 	});
-	worker.join();
+    while (! finished) {
+		condition.wait_for(lock, std::chrono::milliseconds(500), [&progress]{ return progress.updated; });
+		if (! progress_dialog.Update(progress.percent, _(progress.message)))
+			canceled = true;
+		progress.updated = false;
+    }
+
+	if (canceled) {
+		// Nothing to show.
+	} else if (success) {
+		wxMessageDialog dlg(nullptr, _(L("Model repaired successfully")), _(L("Model Repair by the Netfabb service")), wxICON_INFORMATION | wxOK_DEFAULT);
+		dlg.ShowModal();
+	} else {
+		wxMessageDialog dlg(nullptr, _(L("Model repair failed: \n")) + _(progress.message), _(L("Model Repair by the Netfabb service")), wxICON_ERROR | wxOK_DEFAULT);
+		dlg.ShowModal();
+	}
+	worker_thread.join();
 }
 
 } // namespace Slic3r
diff --git a/xs/src/slic3r/Utils/FixModelByWin10.hpp b/xs/src/slic3r/Utils/FixModelByWin10.hpp
index 299c9b75b..c148a6970 100644
--- a/xs/src/slic3r/Utils/FixModelByWin10.hpp
+++ b/xs/src/slic3r/Utils/FixModelByWin10.hpp
@@ -12,13 +12,11 @@ class Print;
 #ifdef HAS_WIN10SDK
 
 extern bool is_windows10();
-extern bool fix_model_by_win10_sdk(const std::string &path_src, const std::string &path_dst);
 extern void fix_model_by_win10_sdk_gui(const ModelObject &model_object, const Print &print, Model &result);
 
 #else /* HAS_WIN10SDK */
 
 inline bool is_windows10() { return false; }
-inline bool fix_model_by_win10_sdk(const std::string &, const std::string &) { return false; }
 inline void fix_model_by_win10_sdk_gui(const ModelObject &, const Print &, Model &) {}
 
 #endif /* HAS_WIN10SDK */