Tech ENABLE_REMOVE_ASSOCIATION_TO_FILE_FOR_WINDOWS_8_AND_LATER - Disable association to 3mf and stl files if the application is run on Windows 8 or later

This commit is contained in:
enricoturri1966 2022-05-17 13:19:33 +02:00
parent e6750a524f
commit 39cefdad89
5 changed files with 7865 additions and 7817 deletions

View File

@ -81,6 +81,8 @@
#define ENABLE_USED_FILAMENT_POST_PROCESS (1 && ENABLE_2_5_0_ALPHA1) #define ENABLE_USED_FILAMENT_POST_PROCESS (1 && ENABLE_2_5_0_ALPHA1)
// Enable gizmo grabbers to share common models // Enable gizmo grabbers to share common models
#define ENABLE_GIZMO_GRABBER_REFACTOR (1 && ENABLE_2_5_0_ALPHA1) #define ENABLE_GIZMO_GRABBER_REFACTOR (1 && ENABLE_2_5_0_ALPHA1)
// Disable association to 3mf and stl files if the application is run on Windows 8 or later
#define ENABLE_REMOVE_ASSOCIATION_TO_FILE_FOR_WINDOWS_8_AND_LATER (1 && ENABLE_2_5_0_ALPHA1)
#endif // _prusaslicer_technologies_h_ #endif // _prusaslicer_technologies_h_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,449 +1,449 @@
#ifdef HAS_WIN10SDK #ifdef HAS_WIN10SDK
#ifndef NOMINMAX #ifndef NOMINMAX
# define NOMINMAX # define NOMINMAX
#endif #endif
// Windows Runtime // Windows Runtime
#include <roapi.h> #include <roapi.h>
// for ComPtr // for ComPtr
#include <wrl/client.h> #include <wrl/client.h>
// from C:/Program Files (x86)/Windows Kits/10/Include/10.0.17134.0/ // from C:/Program Files (x86)/Windows Kits/10/Include/10.0.17134.0/
#include <winrt/robuffer.h> #include <winrt/robuffer.h>
#include <winrt/windows.storage.provider.h> #include <winrt/windows.storage.provider.h>
#include <winrt/windows.graphics.printing3d.h> #include <winrt/windows.graphics.printing3d.h>
#include "FixModelByWin10.hpp" #include "FixModelByWin10.hpp"
#include <atomic> #include <atomic>
#include <chrono> #include <chrono>
#include <cstdint> #include <cstdint>
#include <condition_variable> #include <condition_variable>
#include <exception> #include <exception>
#include <string> #include <string>
#include <thread> #include <thread>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/nowide/convert.hpp> #include <boost/nowide/convert.hpp>
#include <boost/nowide/cstdio.hpp> #include <boost/nowide/cstdio.hpp>
#include <boost/thread.hpp> #include <boost/thread.hpp>
#include "libslic3r/Model.hpp" #include "libslic3r/Model.hpp"
#include "libslic3r/Print.hpp" #include "libslic3r/Print.hpp"
#include "libslic3r/PresetBundle.hpp" #include "libslic3r/PresetBundle.hpp"
#include "libslic3r/Format/3mf.hpp" #include "libslic3r/Format/3mf.hpp"
#include "../GUI/GUI.hpp" #include "../GUI/GUI.hpp"
#include "../GUI/I18N.hpp" #include "../GUI/I18N.hpp"
#include "../GUI/MsgDialog.hpp" #include "../GUI/MsgDialog.hpp"
#include <wx/msgdlg.h> #include <wx/msgdlg.h>
#include <wx/progdlg.h> #include <wx/progdlg.h>
extern "C"{ extern "C"{
// from rapi.h // from rapi.h
typedef HRESULT (__stdcall* FunctionRoInitialize)(int); typedef HRESULT (__stdcall* FunctionRoInitialize)(int);
typedef HRESULT (__stdcall* FunctionRoUninitialize)(); typedef HRESULT (__stdcall* FunctionRoUninitialize)();
typedef HRESULT (__stdcall* FunctionRoActivateInstance)(HSTRING activatableClassId, IInspectable **instance); typedef HRESULT (__stdcall* FunctionRoActivateInstance)(HSTRING activatableClassId, IInspectable **instance);
typedef HRESULT (__stdcall* FunctionRoGetActivationFactory)(HSTRING activatableClassId, REFIID iid, void **factory); typedef HRESULT (__stdcall* FunctionRoGetActivationFactory)(HSTRING activatableClassId, REFIID iid, void **factory);
// from winstring.h // from winstring.h
typedef HRESULT (__stdcall* FunctionWindowsCreateString)(LPCWSTR sourceString, UINT32 length, HSTRING *string); typedef HRESULT (__stdcall* FunctionWindowsCreateString)(LPCWSTR sourceString, UINT32 length, HSTRING *string);
typedef HRESULT (__stdcall* FunctionWindowsDelteString)(HSTRING string); typedef HRESULT (__stdcall* FunctionWindowsDelteString)(HSTRING string);
} }
namespace Slic3r { namespace Slic3r {
HMODULE s_hRuntimeObjectLibrary = nullptr; HMODULE s_hRuntimeObjectLibrary = nullptr;
FunctionRoInitialize s_RoInitialize = nullptr; FunctionRoInitialize s_RoInitialize = nullptr;
FunctionRoUninitialize s_RoUninitialize = nullptr; FunctionRoUninitialize s_RoUninitialize = nullptr;
FunctionRoActivateInstance s_RoActivateInstance = nullptr; FunctionRoActivateInstance s_RoActivateInstance = nullptr;
FunctionRoGetActivationFactory s_RoGetActivationFactory = nullptr; FunctionRoGetActivationFactory s_RoGetActivationFactory = nullptr;
FunctionWindowsCreateString s_WindowsCreateString = nullptr; FunctionWindowsCreateString s_WindowsCreateString = nullptr;
FunctionWindowsDelteString s_WindowsDeleteString = nullptr; FunctionWindowsDelteString s_WindowsDeleteString = nullptr;
bool winrt_load_runtime_object_library() bool winrt_load_runtime_object_library()
{ {
if (s_hRuntimeObjectLibrary == nullptr) if (s_hRuntimeObjectLibrary == nullptr)
s_hRuntimeObjectLibrary = LoadLibrary(L"ComBase.dll"); s_hRuntimeObjectLibrary = LoadLibrary(L"ComBase.dll");
if (s_hRuntimeObjectLibrary != nullptr) { if (s_hRuntimeObjectLibrary != nullptr) {
s_RoInitialize = (FunctionRoInitialize) GetProcAddress(s_hRuntimeObjectLibrary, "RoInitialize"); s_RoInitialize = (FunctionRoInitialize) GetProcAddress(s_hRuntimeObjectLibrary, "RoInitialize");
s_RoUninitialize = (FunctionRoUninitialize) GetProcAddress(s_hRuntimeObjectLibrary, "RoUninitialize"); s_RoUninitialize = (FunctionRoUninitialize) GetProcAddress(s_hRuntimeObjectLibrary, "RoUninitialize");
s_RoActivateInstance = (FunctionRoActivateInstance) GetProcAddress(s_hRuntimeObjectLibrary, "RoActivateInstance"); s_RoActivateInstance = (FunctionRoActivateInstance) GetProcAddress(s_hRuntimeObjectLibrary, "RoActivateInstance");
s_RoGetActivationFactory = (FunctionRoGetActivationFactory) GetProcAddress(s_hRuntimeObjectLibrary, "RoGetActivationFactory"); s_RoGetActivationFactory = (FunctionRoGetActivationFactory) GetProcAddress(s_hRuntimeObjectLibrary, "RoGetActivationFactory");
s_WindowsCreateString = (FunctionWindowsCreateString) GetProcAddress(s_hRuntimeObjectLibrary, "WindowsCreateString"); s_WindowsCreateString = (FunctionWindowsCreateString) GetProcAddress(s_hRuntimeObjectLibrary, "WindowsCreateString");
s_WindowsDeleteString = (FunctionWindowsDelteString) GetProcAddress(s_hRuntimeObjectLibrary, "WindowsDeleteString"); s_WindowsDeleteString = (FunctionWindowsDelteString) GetProcAddress(s_hRuntimeObjectLibrary, "WindowsDeleteString");
} }
return s_RoInitialize && s_RoUninitialize && s_RoActivateInstance && s_WindowsCreateString && s_WindowsDeleteString; return s_RoInitialize && s_RoUninitialize && s_RoActivateInstance && s_WindowsCreateString && s_WindowsDeleteString;
} }
static HRESULT winrt_activate_instance(const std::wstring &class_name, IInspectable **pinst) static HRESULT winrt_activate_instance(const std::wstring &class_name, IInspectable **pinst)
{ {
HSTRING hClassName; HSTRING hClassName;
HRESULT hr = (*s_WindowsCreateString)(class_name.c_str(), class_name.size(), &hClassName); HRESULT hr = (*s_WindowsCreateString)(class_name.c_str(), class_name.size(), &hClassName);
if (S_OK != hr) if (S_OK != hr)
return hr; return hr;
hr = (*s_RoActivateInstance)(hClassName, pinst); hr = (*s_RoActivateInstance)(hClassName, pinst);
(*s_WindowsDeleteString)(hClassName); (*s_WindowsDeleteString)(hClassName);
return hr; return hr;
} }
template<typename TYPE> template<typename TYPE>
static HRESULT winrt_activate_instance(const std::wstring &class_name, TYPE **pinst) static HRESULT winrt_activate_instance(const std::wstring &class_name, TYPE **pinst)
{ {
IInspectable *pinspectable = nullptr; IInspectable *pinspectable = nullptr;
HRESULT hr = winrt_activate_instance(class_name, &pinspectable); HRESULT hr = winrt_activate_instance(class_name, &pinspectable);
if (S_OK != hr) if (S_OK != hr)
return hr; return hr;
hr = pinspectable->QueryInterface(__uuidof(TYPE), (void**)pinst); hr = pinspectable->QueryInterface(__uuidof(TYPE), (void**)pinst);
pinspectable->Release(); pinspectable->Release();
return hr; return hr;
} }
static HRESULT winrt_get_activation_factory(const std::wstring &class_name, REFIID iid, void **pinst) static HRESULT winrt_get_activation_factory(const std::wstring &class_name, REFIID iid, void **pinst)
{ {
HSTRING hClassName; HSTRING hClassName;
HRESULT hr = (*s_WindowsCreateString)(class_name.c_str(), class_name.size(), &hClassName); HRESULT hr = (*s_WindowsCreateString)(class_name.c_str(), class_name.size(), &hClassName);
if (S_OK != hr) if (S_OK != hr)
return hr; return hr;
hr = (*s_RoGetActivationFactory)(hClassName, iid, pinst); hr = (*s_RoGetActivationFactory)(hClassName, iid, pinst);
(*s_WindowsDeleteString)(hClassName); (*s_WindowsDeleteString)(hClassName);
return hr; return hr;
} }
template<typename TYPE> template<typename TYPE>
static HRESULT winrt_get_activation_factory(const std::wstring &class_name, TYPE **pinst) 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)); return winrt_get_activation_factory(class_name, __uuidof(TYPE), reinterpret_cast<void**>(pinst));
} }
// To be called often to test whether to cancel the operation. // To be called often to test whether to cancel the operation.
typedef std::function<void ()> ThrowOnCancelFn; typedef std::function<void ()> ThrowOnCancelFn;
template<typename T> template<typename T>
static AsyncStatus winrt_async_await(const Microsoft::WRL::ComPtr<T> &asyncAction, ThrowOnCancelFn throw_on_cancel, int blocking_tick_ms = 100) 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; Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> asyncInfo;
asyncAction.As(&asyncInfo); asyncAction.As(&asyncInfo);
AsyncStatus status; AsyncStatus status;
// Ugly blocking loop until the RepairAsync call finishes. // Ugly blocking loop until the RepairAsync call finishes.
//FIXME replace with a callback. //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 // 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 (;;) { for (;;) {
asyncInfo->get_Status(&status); asyncInfo->get_Status(&status);
if (status != AsyncStatus::Started) if (status != AsyncStatus::Started)
return status; return status;
throw_on_cancel(); throw_on_cancel();
::Sleep(blocking_tick_ms); ::Sleep(blocking_tick_ms);
} }
} }
static HRESULT winrt_open_file_stream( static HRESULT winrt_open_file_stream(
const std::wstring &path, const std::wstring &path,
ABI::Windows::Storage::FileAccessMode mode, ABI::Windows::Storage::FileAccessMode mode,
ABI::Windows::Storage::Streams::IRandomAccessStream **fileStream, ABI::Windows::Storage::Streams::IRandomAccessStream **fileStream,
ThrowOnCancelFn throw_on_cancel) ThrowOnCancelFn throw_on_cancel)
{ {
// Get the file factory. // Get the file factory.
Microsoft::WRL::ComPtr<ABI::Windows::Storage::IStorageFileStatics> fileFactory; Microsoft::WRL::ComPtr<ABI::Windows::Storage::IStorageFileStatics> fileFactory;
HRESULT hr = winrt_get_activation_factory(L"Windows.Storage.StorageFile", fileFactory.GetAddressOf()); HRESULT hr = winrt_get_activation_factory(L"Windows.Storage.StorageFile", fileFactory.GetAddressOf());
if (FAILED(hr)) return hr; if (FAILED(hr)) return hr;
// Open the file asynchronously. // Open the file asynchronously.
HSTRING hstr_path; HSTRING hstr_path;
hr = (*s_WindowsCreateString)(path.c_str(), path.size(), &hstr_path); hr = (*s_WindowsCreateString)(path.c_str(), path.size(), &hstr_path);
if (FAILED(hr)) return hr; if (FAILED(hr)) return hr;
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::StorageFile*>> fileOpenAsync; Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::StorageFile*>> fileOpenAsync;
hr = fileFactory->GetFileFromPathAsync(hstr_path, fileOpenAsync.GetAddressOf()); hr = fileFactory->GetFileFromPathAsync(hstr_path, fileOpenAsync.GetAddressOf());
if (FAILED(hr)) return hr; if (FAILED(hr)) return hr;
(*s_WindowsDeleteString)(hstr_path); (*s_WindowsDeleteString)(hstr_path);
// Wait until the file gets open, get the actual file. // Wait until the file gets open, get the actual file.
AsyncStatus status = winrt_async_await(fileOpenAsync, throw_on_cancel); AsyncStatus status = winrt_async_await(fileOpenAsync, throw_on_cancel);
Microsoft::WRL::ComPtr<ABI::Windows::Storage::IStorageFile> storageFile; Microsoft::WRL::ComPtr<ABI::Windows::Storage::IStorageFile> storageFile;
if (status == AsyncStatus::Completed) { if (status == AsyncStatus::Completed) {
hr = fileOpenAsync->GetResults(storageFile.GetAddressOf()); hr = fileOpenAsync->GetResults(storageFile.GetAddressOf());
} else { } else {
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> asyncInfo; Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> asyncInfo;
hr = fileOpenAsync.As(&asyncInfo); hr = fileOpenAsync.As(&asyncInfo);
if (FAILED(hr)) return hr; if (FAILED(hr)) return hr;
HRESULT err; HRESULT err;
hr = asyncInfo->get_ErrorCode(&err); hr = asyncInfo->get_ErrorCode(&err);
return FAILED(hr) ? hr : err; return FAILED(hr) ? hr : err;
} }
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::Streams::IRandomAccessStream*>> fileStreamAsync; Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::Streams::IRandomAccessStream*>> fileStreamAsync;
hr = storageFile->OpenAsync(mode, fileStreamAsync.GetAddressOf()); hr = storageFile->OpenAsync(mode, fileStreamAsync.GetAddressOf());
if (FAILED(hr)) return hr; if (FAILED(hr)) return hr;
status = winrt_async_await(fileStreamAsync, throw_on_cancel); status = winrt_async_await(fileStreamAsync, throw_on_cancel);
if (status == AsyncStatus::Completed) { if (status == AsyncStatus::Completed) {
hr = fileStreamAsync->GetResults(fileStream); hr = fileStreamAsync->GetResults(fileStream);
} else { } else {
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> asyncInfo; Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> asyncInfo;
hr = fileStreamAsync.As(&asyncInfo); hr = fileStreamAsync.As(&asyncInfo);
if (FAILED(hr)) return hr; if (FAILED(hr)) return hr;
HRESULT err; HRESULT err;
hr = asyncInfo->get_ErrorCode(&err); hr = asyncInfo->get_ErrorCode(&err);
if (!FAILED(hr)) if (!FAILED(hr))
hr = err; hr = err;
} }
return hr; return hr;
} }
bool is_windows10() bool is_windows10()
{ {
HKEY hKey; HKEY hKey;
LONG lRes = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_READ, &hKey); LONG lRes = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_READ, &hKey);
if (lRes == ERROR_SUCCESS) { if (lRes == ERROR_SUCCESS) {
WCHAR szBuffer[512]; WCHAR szBuffer[512];
DWORD dwBufferSize = sizeof(szBuffer); DWORD dwBufferSize = sizeof(szBuffer);
lRes = RegQueryValueExW(hKey, L"ProductName", 0, nullptr, (LPBYTE)szBuffer, &dwBufferSize); lRes = RegQueryValueExW(hKey, L"ProductName", 0, nullptr, (LPBYTE)szBuffer, &dwBufferSize);
if (lRes == ERROR_SUCCESS) if (lRes == ERROR_SUCCESS)
return wcsncmp(szBuffer, L"Windows 10", 10) == 0; return wcsncmp(szBuffer, L"Windows 10", 10) == 0;
RegCloseKey(hKey); RegCloseKey(hKey);
} }
return false; return false;
} }
// Progress function, to be called regularly to update the progress. // Progress function, to be called regularly to update the progress.
typedef std::function<void (const char * /* message */, unsigned /* progress */)> ProgressFn; typedef std::function<void (const char * /* message */, unsigned /* progress */)> ProgressFn;
void fix_model_by_win10_sdk(const std::string &path_src, const std::string &path_dst, ProgressFn on_progress, ThrowOnCancelFn throw_on_cancel) 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()) if (! is_windows10())
throw Slic3r::RuntimeError("fix_model_by_win10_sdk called on non Windows 10 system"); throw Slic3r::RuntimeError("fix_model_by_win10_sdk called on non Windows 10 system");
if (! winrt_load_runtime_object_library()) if (! winrt_load_runtime_object_library())
throw Slic3r::RuntimeError("Failed to initialize the WinRT library."); throw Slic3r::RuntimeError("Failed to initialize the WinRT library.");
HRESULT hr = (*s_RoInitialize)(RO_INIT_MULTITHREADED); HRESULT hr = (*s_RoInitialize)(RO_INIT_MULTITHREADED);
{ {
on_progress(L("Exporting source model"), 20); on_progress(L("Exporting source model"), 20);
Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IRandomAccessStream> fileStream; 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(), throw_on_cancel); 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; Microsoft::WRL::ComPtr<ABI::Windows::Graphics::Printing3D::IPrinting3D3MFPackage> printing3d3mfpackage;
hr = winrt_activate_instance(L"Windows.Graphics.Printing3D.Printing3D3MFPackage", printing3d3mfpackage.GetAddressOf()); hr = winrt_activate_instance(L"Windows.Graphics.Printing3D.Printing3D3MFPackage", printing3d3mfpackage.GetAddressOf());
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Graphics::Printing3D::Printing3DModel*>> modelAsync; Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Graphics::Printing3D::Printing3DModel*>> modelAsync;
hr = printing3d3mfpackage->LoadModelFromPackageAsync(fileStream.Get(), modelAsync.GetAddressOf()); hr = printing3d3mfpackage->LoadModelFromPackageAsync(fileStream.Get(), modelAsync.GetAddressOf());
AsyncStatus status = winrt_async_await(modelAsync, throw_on_cancel); AsyncStatus status = winrt_async_await(modelAsync, throw_on_cancel);
Microsoft::WRL::ComPtr<ABI::Windows::Graphics::Printing3D::IPrinting3DModel> model; Microsoft::WRL::ComPtr<ABI::Windows::Graphics::Printing3D::IPrinting3DModel> model;
if (status == AsyncStatus::Completed) if (status == AsyncStatus::Completed)
hr = modelAsync->GetResults(model.GetAddressOf()); hr = modelAsync->GetResults(model.GetAddressOf());
else else
throw Slic3r::RuntimeError(L("Failed loading the input model.")); throw Slic3r::RuntimeError(L("Failed loading the input model."));
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IVector<ABI::Windows::Graphics::Printing3D::Printing3DMesh*>> meshes; Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IVector<ABI::Windows::Graphics::Printing3D::Printing3DMesh*>> meshes;
hr = model->get_Meshes(meshes.GetAddressOf()); hr = model->get_Meshes(meshes.GetAddressOf());
unsigned num_meshes = 0; unsigned num_meshes = 0;
hr = meshes->get_Size(&num_meshes); hr = meshes->get_Size(&num_meshes);
on_progress(L("Repairing model by the Netfabb service"), 40); on_progress(L("Repairing model by the Netfabb service"), 40);
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncAction> repairAsync; Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncAction> repairAsync;
hr = model->RepairAsync(repairAsync.GetAddressOf()); hr = model->RepairAsync(repairAsync.GetAddressOf());
status = winrt_async_await(repairAsync, throw_on_cancel); status = winrt_async_await(repairAsync, throw_on_cancel);
if (status != AsyncStatus::Completed) if (status != AsyncStatus::Completed)
throw Slic3r::RuntimeError(L("Mesh repair failed.")); throw Slic3r::RuntimeError(L("Mesh repair failed."));
repairAsync->GetResults(); repairAsync->GetResults();
on_progress(L("Loading repaired model"), 60); on_progress(L("Loading repaired model"), 60);
// Verify the number of meshes returned after the repair action. // Verify the number of meshes returned after the repair action.
meshes.Reset(); meshes.Reset();
hr = model->get_Meshes(meshes.GetAddressOf()); hr = model->get_Meshes(meshes.GetAddressOf());
hr = meshes->get_Size(&num_meshes); hr = meshes->get_Size(&num_meshes);
// Save model to this class' Printing3D3MFPackage. // Save model to this class' Printing3D3MFPackage.
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncAction> saveToPackageAsync; Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncAction> saveToPackageAsync;
hr = printing3d3mfpackage->SaveModelToPackageAsync(model.Get(), saveToPackageAsync.GetAddressOf()); hr = printing3d3mfpackage->SaveModelToPackageAsync(model.Get(), saveToPackageAsync.GetAddressOf());
status = winrt_async_await(saveToPackageAsync, throw_on_cancel); status = winrt_async_await(saveToPackageAsync, throw_on_cancel);
if (status != AsyncStatus::Completed) if (status != AsyncStatus::Completed)
throw Slic3r::RuntimeError(L("Saving mesh into the 3MF container failed.")); throw Slic3r::RuntimeError(L("Saving mesh into the 3MF container failed."));
hr = saveToPackageAsync->GetResults(); hr = saveToPackageAsync->GetResults();
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::Streams::IRandomAccessStream*>> generatorStreamAsync; Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::Streams::IRandomAccessStream*>> generatorStreamAsync;
hr = printing3d3mfpackage->SaveAsync(generatorStreamAsync.GetAddressOf()); hr = printing3d3mfpackage->SaveAsync(generatorStreamAsync.GetAddressOf());
status = winrt_async_await(generatorStreamAsync, throw_on_cancel); status = winrt_async_await(generatorStreamAsync, throw_on_cancel);
if (status != AsyncStatus::Completed) if (status != AsyncStatus::Completed)
throw Slic3r::RuntimeError(L("Saving mesh into the 3MF container failed.")); throw Slic3r::RuntimeError(L("Saving mesh into the 3MF container failed."));
Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IRandomAccessStream> generatorStream; Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IRandomAccessStream> generatorStream;
hr = generatorStreamAsync->GetResults(generatorStream.GetAddressOf()); hr = generatorStreamAsync->GetResults(generatorStream.GetAddressOf());
// Go to the beginning of the stream. // Go to the beginning of the stream.
generatorStream->Seek(0); generatorStream->Seek(0);
Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IInputStream> inputStream; Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IInputStream> inputStream;
hr = generatorStream.As(&inputStream); hr = generatorStream.As(&inputStream);
// Get the buffer factory. // Get the buffer factory.
Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IBufferFactory> bufferFactory; Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IBufferFactory> bufferFactory;
hr = winrt_get_activation_factory(L"Windows.Storage.Streams.Buffer", bufferFactory.GetAddressOf()); hr = winrt_get_activation_factory(L"Windows.Storage.Streams.Buffer", bufferFactory.GetAddressOf());
// Open the destination file. // Open the destination file.
FILE *fout = boost::nowide::fopen(path_dst.c_str(), "wb"); FILE *fout = boost::nowide::fopen(path_dst.c_str(), "wb");
try { try {
Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IBuffer> buffer; Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IBuffer> buffer;
byte *buffer_ptr; byte *buffer_ptr;
bufferFactory->Create(65536 * 2048, buffer.GetAddressOf()); bufferFactory->Create(65536 * 2048, buffer.GetAddressOf());
{ {
Microsoft::WRL::ComPtr<Windows::Storage::Streams::IBufferByteAccess> bufferByteAccess; Microsoft::WRL::ComPtr<Windows::Storage::Streams::IBufferByteAccess> bufferByteAccess;
buffer.As(&bufferByteAccess); buffer.As(&bufferByteAccess);
hr = bufferByteAccess->Buffer(&buffer_ptr); hr = bufferByteAccess->Buffer(&buffer_ptr);
} }
uint32_t length; uint32_t length;
hr = buffer->get_Length(&length); hr = buffer->get_Length(&length);
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperationWithProgress<ABI::Windows::Storage::Streams::IBuffer*, UINT32>> asyncRead; Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperationWithProgress<ABI::Windows::Storage::Streams::IBuffer*, UINT32>> asyncRead;
for (;;) { for (;;) {
hr = inputStream->ReadAsync(buffer.Get(), 65536 * 2048, ABI::Windows::Storage::Streams::InputStreamOptions_ReadAhead, asyncRead.GetAddressOf()); hr = inputStream->ReadAsync(buffer.Get(), 65536 * 2048, ABI::Windows::Storage::Streams::InputStreamOptions_ReadAhead, asyncRead.GetAddressOf());
status = winrt_async_await(asyncRead, throw_on_cancel); status = winrt_async_await(asyncRead, throw_on_cancel);
if (status != AsyncStatus::Completed) if (status != AsyncStatus::Completed)
throw Slic3r::RuntimeError(L("Saving mesh into the 3MF container failed.")); throw Slic3r::RuntimeError(L("Saving mesh into the 3MF container failed."));
hr = buffer->get_Length(&length); hr = buffer->get_Length(&length);
if (length == 0) if (length == 0)
break; break;
fwrite(buffer_ptr, length, 1, fout); fwrite(buffer_ptr, length, 1, fout);
} }
} catch (...) { } catch (...) {
fclose(fout); fclose(fout);
throw; throw;
} }
fclose(fout); fclose(fout);
// Here all the COM objects will be released through the ComPtr destructors. // Here all the COM objects will be released through the ComPtr destructors.
} }
(*s_RoUninitialize)(); (*s_RoUninitialize)();
} }
class RepairCanceledException : public std::exception { class RepairCanceledException : public std::exception {
public: public:
const char* what() const throw() { return "Model repair has been canceled"; } const char* what() const throw() { return "Model repair has been canceled"; }
}; };
// returt FALSE, if fixing was canceled // returt FALSE, if fixing was canceled
// fix_result is empty, if fixing finished successfully // fix_result is empty, if fixing finished successfully
// fix_result containes a message if fixing failed // fix_result containes a message if fixing failed
bool fix_model_by_win10_sdk_gui(ModelObject &model_object, int volume_idx, wxProgressDialog& progress_dialog, const wxString& msg_header, std::string& fix_result) bool fix_model_by_win10_sdk_gui(ModelObject &model_object, int volume_idx, wxProgressDialog& progress_dialog, const wxString& msg_header, std::string& fix_result)
{ {
std::mutex mutex; std::mutex mutex;
std::condition_variable condition; std::condition_variable condition;
std::unique_lock<std::mutex> lock(mutex); std::unique_lock<std::mutex> lock(mutex);
struct Progress { struct Progress {
std::string message; std::string message;
int percent = 0; int percent = 0;
bool updated = false; bool updated = false;
} progress; } progress;
std::atomic<bool> canceled = false; std::atomic<bool> canceled = false;
std::atomic<bool> finished = false; std::atomic<bool> finished = false;
std::vector<ModelVolume*> volumes; std::vector<ModelVolume*> volumes;
if (volume_idx == -1) if (volume_idx == -1)
volumes = model_object.volumes; volumes = model_object.volumes;
else else
volumes.emplace_back(model_object.volumes[volume_idx]); volumes.emplace_back(model_object.volumes[volume_idx]);
// Executing the calculation in a background thread, so that the COM context could be created with its own threading model. // 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). // (It seems like wxWidgets initialize the COM contex as single threaded and we need a multi-threaded context).
bool success = false; bool success = false;
size_t ivolume = 0; size_t ivolume = 0;
auto on_progress = [&mutex, &condition, &ivolume, &volumes, &progress](const char *msg, unsigned prcnt) { auto on_progress = [&mutex, &condition, &ivolume, &volumes, &progress](const char *msg, unsigned prcnt) {
std::lock_guard<std::mutex> lk(mutex); std::lock_guard<std::mutex> lk(mutex);
progress.message = msg; progress.message = msg;
progress.percent = (int)floor((float(prcnt) + float(ivolume) * 100.f) / float(volumes.size())); progress.percent = (int)floor((float(prcnt) + float(ivolume) * 100.f) / float(volumes.size()));
progress.updated = true; progress.updated = true;
condition.notify_all(); condition.notify_all();
}; };
auto worker_thread = boost::thread([&model_object, &volumes, &ivolume, on_progress, &success, &canceled, &finished]() { auto worker_thread = boost::thread([&model_object, &volumes, &ivolume, on_progress, &success, &canceled, &finished]() {
try { try {
std::vector<TriangleMesh> meshes_repaired; std::vector<TriangleMesh> meshes_repaired;
meshes_repaired.reserve(volumes.size()); meshes_repaired.reserve(volumes.size());
for (; ivolume < volumes.size(); ++ ivolume) { for (; ivolume < volumes.size(); ++ ivolume) {
on_progress(L("Exporting source model"), 0); on_progress(L("Exporting source model"), 0);
boost::filesystem::path path_src = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); boost::filesystem::path path_src = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
path_src += ".3mf"; path_src += ".3mf";
Model model; Model model;
ModelObject *mo = model.add_object(); ModelObject *mo = model.add_object();
mo->add_volume(*volumes[ivolume]); mo->add_volume(*volumes[ivolume]);
// We are about to save a 3mf, fix it by netfabb and load the fixed 3mf back. // We are about to save a 3mf, fix it by netfabb and load the fixed 3mf back.
// store_3mf currently bakes the volume transformation into the mesh itself. // store_3mf currently bakes the volume transformation into the mesh itself.
// If we then loaded the repaired 3mf and pushed the mesh into the original ModelVolume // If we then loaded the repaired 3mf and pushed the mesh into the original ModelVolume
// (which remembers the matrix the whole time), the transformation would be used twice. // (which remembers the matrix the whole time), the transformation would be used twice.
// We will therefore set the volume transform on the dummy ModelVolume to identity. // We will therefore set the volume transform on the dummy ModelVolume to identity.
mo->volumes.back()->set_transformation(Geometry::Transformation()); mo->volumes.back()->set_transformation(Geometry::Transformation());
mo->add_instance(); mo->add_instance();
if (!Slic3r::store_3mf(path_src.string().c_str(), &model, nullptr, false, nullptr, false)) { if (!Slic3r::store_3mf(path_src.string().c_str(), &model, nullptr, false, nullptr, false)) {
boost::filesystem::remove(path_src); boost::filesystem::remove(path_src);
throw Slic3r::RuntimeError(L("Export of a temporary 3mf file failed")); throw Slic3r::RuntimeError(L("Export of a temporary 3mf file failed"));
} }
model.clear_objects(); model.clear_objects();
model.clear_materials(); model.clear_materials();
boost::filesystem::path path_dst = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); boost::filesystem::path path_dst = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
path_dst += ".3mf"; path_dst += ".3mf";
fix_model_by_win10_sdk(path_src.string().c_str(), path_dst.string(), on_progress, fix_model_by_win10_sdk(path_src.string().c_str(), path_dst.string(), on_progress,
[&canceled]() { if (canceled) throw RepairCanceledException(); }); [&canceled]() { if (canceled) throw RepairCanceledException(); });
boost::filesystem::remove(path_src); boost::filesystem::remove(path_src);
// PresetBundle bundle; // PresetBundle bundle;
on_progress(L("Loading repaired model"), 80); on_progress(L("Loading repaired model"), 80);
DynamicPrintConfig config; DynamicPrintConfig config;
ConfigSubstitutionContext config_substitutions{ ForwardCompatibilitySubstitutionRule::EnableSilent }; ConfigSubstitutionContext config_substitutions{ ForwardCompatibilitySubstitutionRule::EnableSilent };
bool loaded = Slic3r::load_3mf(path_dst.string().c_str(), config, config_substitutions, &model, false); bool loaded = Slic3r::load_3mf(path_dst.string().c_str(), config, config_substitutions, &model, false);
boost::filesystem::remove(path_dst); boost::filesystem::remove(path_dst);
if (! loaded) if (! loaded)
throw Slic3r::RuntimeError(L("Import of the repaired 3mf file failed")); throw Slic3r::RuntimeError(L("Import of the repaired 3mf file failed"));
if (model.objects.size() == 0) if (model.objects.size() == 0)
throw Slic3r::RuntimeError(L("Repaired 3MF file does not contain any object")); throw Slic3r::RuntimeError(L("Repaired 3MF file does not contain any object"));
if (model.objects.size() > 1) if (model.objects.size() > 1)
throw Slic3r::RuntimeError(L("Repaired 3MF file contains more than one object")); throw Slic3r::RuntimeError(L("Repaired 3MF file contains more than one object"));
if (model.objects.front()->volumes.size() == 0) if (model.objects.front()->volumes.size() == 0)
throw Slic3r::RuntimeError(L("Repaired 3MF file does not contain any volume")); throw Slic3r::RuntimeError(L("Repaired 3MF file does not contain any volume"));
if (model.objects.front()->volumes.size() > 1) if (model.objects.front()->volumes.size() > 1)
throw Slic3r::RuntimeError(L("Repaired 3MF file contains more than one volume")); throw Slic3r::RuntimeError(L("Repaired 3MF file contains more than one volume"));
meshes_repaired.emplace_back(std::move(model.objects.front()->volumes.front()->mesh())); meshes_repaired.emplace_back(std::move(model.objects.front()->volumes.front()->mesh()));
} }
for (size_t i = 0; i < volumes.size(); ++ i) { for (size_t i = 0; i < volumes.size(); ++ i) {
volumes[i]->set_mesh(std::move(meshes_repaired[i])); volumes[i]->set_mesh(std::move(meshes_repaired[i]));
volumes[i]->calculate_convex_hull(); volumes[i]->calculate_convex_hull();
volumes[i]->set_new_unique_id(); volumes[i]->set_new_unique_id();
} }
model_object.invalidate_bounding_box(); model_object.invalidate_bounding_box();
-- ivolume; -- ivolume;
on_progress(L("Model repair finished"), 100); on_progress(L("Model repair finished"), 100);
success = true; success = true;
finished = true; finished = true;
} catch (RepairCanceledException & /* ex */) { } catch (RepairCanceledException & /* ex */) {
canceled = true; canceled = true;
finished = true; finished = true;
on_progress(L("Model repair canceled"), 100); on_progress(L("Model repair canceled"), 100);
} catch (std::exception &ex) { } catch (std::exception &ex) {
success = false; success = false;
finished = true; finished = true;
on_progress(ex.what(), 100); on_progress(ex.what(), 100);
} }
}); });
while (! finished) { while (! finished) {
condition.wait_for(lock, std::chrono::milliseconds(250), [&progress]{ return progress.updated; }); condition.wait_for(lock, std::chrono::milliseconds(250), [&progress]{ return progress.updated; });
// decrease progress.percent value to avoid closing of the progress dialog // decrease progress.percent value to avoid closing of the progress dialog
if (!progress_dialog.Update(progress.percent-1, msg_header + _(progress.message))) if (!progress_dialog.Update(progress.percent-1, msg_header + _(progress.message)))
canceled = true; canceled = true;
else else
progress_dialog.Fit(); progress_dialog.Fit();
progress.updated = false; progress.updated = false;
} }
if (canceled) { if (canceled) {
// Nothing to show. // Nothing to show.
} else if (success) { } else if (success) {
fix_result = ""; fix_result = "";
} else { } else {
fix_result = progress.message; fix_result = progress.message;
} }
worker_thread.join(); worker_thread.join();
return !canceled; return !canceled;
} }
} // namespace Slic3r } // namespace Slic3r
#endif /* HAS_WIN10SDK */ #endif /* HAS_WIN10SDK */