From 21caa9de48ec1da7862fe5912f4bd895127e0681 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Fri, 26 Oct 2018 11:57:52 +0200
Subject: [PATCH 1/2] Slic3r was split to a Slic3r.dll / Slic3r.exe /
 Slic3r-console.exe / Slic3r-noconsole.exe on Windows.

---
 src/CMakeLists.txt                | 39 ++++++++++++++++++++++++++-----
 src/libslic3r/GCode/WipeTower.hpp |  1 +
 src/slic3r.cpp                    | 27 ++++++++++++++++-----
 3 files changed, 55 insertions(+), 12 deletions(-)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index dbc4ecd21..621bce4ad 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -57,12 +57,18 @@ add_subdirectory(slic3r)
 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/platform/msw/slic3r.rc.in ${CMAKE_CURRENT_BINARY_DIR}/slic3r.rc @ONLY)
 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/platform/msw/slic3r.manifest.in ${CMAKE_CURRENT_BINARY_DIR}/slic3r.manifest @ONLY)
 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/platform/osx/Info.plist.in ${CMAKE_CURRENT_BINARY_DIR}/Info.plist @ONLY)
-add_executable(slic3r slic3r.cpp ${CMAKE_CURRENT_BINARY_DIR}/slic3r.rc)
-if(SLIC3R_GUI)
-    set_target_properties(slic3r PROPERTIES OUTPUT_NAME "slic3r-gui")
-else()
-    set_target_properties(slic3r PROPERTIES OUTPUT_NAME "slic3r-console")
-endif()
+if (MSVC)
+    add_library(slic3r SHARED slic3r.cpp)
+else ()
+    add_executable(slic3r slic3r.cpp)
+endif ()
+if (NOT MSVC)
+    if(SLIC3R_GUI)
+        set_target_properties(slic3r PROPERTIES OUTPUT_NAME "slic3r-gui")
+    else()
+        set_target_properties(slic3r PROPERTIES OUTPUT_NAME "slic3r-console")
+    endif()
+endif ()
 
 target_link_libraries(slic3r libslic3r)
 if (APPLE)
@@ -113,6 +119,27 @@ if (SLIC3R_GUI)
     endif ()
 endif ()
 
+# On Windows, a shim application is required to produce a console / non console version of the Slic3r application.
+# Also the shim may load the Mesa software OpenGL renderer if the default renderer does not support OpenGL 2.0 and higher.
+if (MSVC)
+    add_executable(slic3r_app_gui WIN32 slic3r_app_msvc.cpp ${CMAKE_CURRENT_BINARY_DIR}/slic3r.rc)
+    target_compile_definitions(slic3r_app_gui PRIVATE -DSLIC3R_WRAPPER_NOCONSOLE -DSLIC3R_WRAPPER_GUI)
+    add_dependencies(slic3r_app_gui slic3r)
+    target_link_libraries(slic3r_app_gui "-lShell32.lib")
+    set_target_properties(slic3r_app_gui PROPERTIES OUTPUT_NAME "slic3r")
+
+    add_executable(slic3r_app_console slic3r_app_msvc.cpp ${CMAKE_CURRENT_BINARY_DIR}/slic3r.rc)
+    target_compile_definitions(slic3r_app_console PRIVATE -DSLIC3R_WRAPPER_CONSOLE -DSLIC3R_WRAPPER_NOGUI)
+    add_dependencies(slic3r_app_console slic3r)
+    set_target_properties(slic3r_app_console PROPERTIES OUTPUT_NAME "slic3r-console")
+
+    add_executable(slic3r_app_noconsole WIN32 slic3r_app_msvc.cpp ${CMAKE_CURRENT_BINARY_DIR}/slic3r.rc)
+    target_compile_definitions(slic3r_app_noconsole PRIVATE -DSLIC3R_WRAPPER_NOCONSOLE -DSLIC3R_WRAPPER_NOGUI)
+    add_dependencies(slic3r_app_noconsole slic3r)
+    target_link_libraries(slic3r_app_gui "-lShell32.lib")
+    set_target_properties(slic3r_app_noconsole PROPERTIES OUTPUT_NAME "slic3r-noconsole")
+endif ()
+
 # Link the resources dir to where Slic3r GUI expects it
 if (MSVC)
     if (CMAKE_CONFIGURATION_TYPES)
diff --git a/src/libslic3r/GCode/WipeTower.hpp b/src/libslic3r/GCode/WipeTower.hpp
index 5cbbc1ca9..8ea3abd93 100644
--- a/src/libslic3r/GCode/WipeTower.hpp
+++ b/src/libslic3r/GCode/WipeTower.hpp
@@ -1,6 +1,7 @@
 #ifndef slic3r_WipeTower_hpp_
 #define slic3r_WipeTower_hpp_
 
+#include <math.h>
 #include <utility>
 #include <string>
 #include <vector>
diff --git a/src/slic3r.cpp b/src/slic3r.cpp
index 03e337db5..cf86c40ed 100644
--- a/src/slic3r.cpp
+++ b/src/slic3r.cpp
@@ -42,14 +42,12 @@ using namespace Slic3r;
 /// utility function for displaying CLI usage
 void printUsage();
 
-using namespace Slic3r;
-
+#ifdef _MSC_VER
+int slic3r_main_(int argc, char **argv)
+#else
 int main(int argc, char **argv)
+#endif
 {
-    // Convert arguments to UTF-8 (needed on Windows). argv then points to memory owned by a.
-    //FIXME On Windows, we want to receive the arguments as 16bit characters!
-    boost::nowide::args a(argc, argv);
-
     {
         const char *loglevel = boost::nowide::getenv("SLIC3R_LOGLEVEL");
         if (loglevel != nullptr) {
@@ -253,3 +251,20 @@ void printUsage()
     print_print_options(boost::nowide::cout);
     std::cout << "****\n";
 }
+
+#ifdef _MSC_VER
+extern "C" {
+	__declspec(dllexport) int __stdcall slic3r_main(int argc, wchar_t **argv)
+	{
+		// Convert wchar_t arguments to UTF8.
+		std::vector<std::string> 	argv_narrow;
+		std::vector<char*>			argv_ptrs(argc + 1, nullptr);
+		for (size_t i = 0; i < argc; ++ i)
+			argv_narrow.emplace_back(boost::nowide::narrow(argv[i]));
+		for (size_t i = 0; i < argc; ++ i)
+			argv_ptrs[i] = const_cast<char*>(argv_narrow[i].data());
+		// Call the UTF8 main.
+		return slic3r_main_(argc, argv_ptrs.data());
+	}
+}
+#endif /* _MSC_VER */

From cf18ba0bbdd2819604a282fd5a17c346b1368f7e Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Fri, 26 Oct 2018 12:07:25 +0200
Subject: [PATCH 2/2] Added a new file missing from the previous commit.

---
 src/slic3r_app_msvc.cpp | 79 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)
 create mode 100644 src/slic3r_app_msvc.cpp

diff --git a/src/slic3r_app_msvc.cpp b/src/slic3r_app_msvc.cpp
new file mode 100644
index 000000000..702e49b45
--- /dev/null
+++ b/src/slic3r_app_msvc.cpp
@@ -0,0 +1,79 @@
+// Why?
+#define _WIN32_WINNT 0x0502
+// The standard Windows includes.
+#define WIN32_LEAN_AND_MEAN
+#define NOMINMAX
+#include <Windows.h>
+#include <shellapi.h>
+#include <wchar.h>
+// Let the NVIDIA and AMD know we want to use their graphics card
+// on a dual graphics card system.
+__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
+__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <string>
+#include <vector>
+
+typedef int (__stdcall *Slic3rMainFunc)(int argc, wchar_t **argv);
+
+#ifdef SLIC3R_WRAPPER_NOCONSOLE
+int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, wchar_t *lpCmdLine, int nCmdShow)
+{
+	int 	  argc;
+	wchar_t **argv = CommandLineToArgvW(lpCmdLine, &argc);
+#else
+int wmain(int argc, wchar_t **argv)
+{
+#endif
+	wchar_t path_to_exe[MAX_PATH + 1] = { 0 };
+	::GetModuleFileNameW(nullptr, path_to_exe, MAX_PATH);
+	wchar_t drive[_MAX_DRIVE];
+	wchar_t dir[_MAX_DIR];
+	wchar_t fname[_MAX_FNAME];
+	wchar_t ext[_MAX_EXT];
+	_wsplitpath(path_to_exe, drive, dir, fname, ext);
+	_wmakepath(path_to_exe, drive, dir, nullptr, nullptr);
+
+// https://wiki.qt.io/Cross_compiling_Mesa_for_Windows
+// http://download.qt.io/development_releases/prebuilt/llvmpipe/windows/
+	wchar_t path_to_mesa[MAX_PATH + 1] = { 0 };
+	wcscpy(path_to_mesa, path_to_exe);
+	wcscat(path_to_mesa, L"mesa\\opengl32.dll");
+	printf("Loading MESA OpenGL library: %S\n", path_to_mesa);
+	HINSTANCE hInstance_OpenGL = LoadLibraryExW(path_to_mesa, nullptr, 0);
+	if (hInstance_OpenGL == nullptr) {
+		printf("MESA OpenGL library was not loaded\n");
+	}
+
+	wchar_t path_to_slic3r[MAX_PATH + 1] = { 0 };
+//	wcscpy(path_to_slic3r, path_to_exe);
+	wcscat(path_to_slic3r, L"slic3r.dll");
+	printf("Loading Slic3r library: %S\n", path_to_slic3r);
+	HINSTANCE hInstance_Slic3r = LoadLibraryExW(path_to_slic3r, nullptr, 0);
+//	if (hInstance_OpenGL == nullptr || hInstance_Slic3r == nullptr) {
+	if (hInstance_Slic3r == nullptr) {
+			printf("slic3r.dll was not loaded\n");
+		return -1;
+	}
+
+	// resolve function address here
+	Slic3rMainFunc slic3r_main = (Slic3rMainFunc)GetProcAddress(hInstance_Slic3r, "slic3r_main");
+	if (slic3r_main == nullptr) {
+		printf("could not locate the function slic3r_main in slic3r.dll\n");
+		return -1;
+	}
+
+	std::vector<wchar_t*> argv_extended;
+	argv_extended.emplace_back(argv[0]);
+#ifdef SLIC3R_WRAPPER_GUI
+	std::wstring cmd_gui = L"--gui";
+	argv_extended.emplace_back(const_cast<wchar_t*>(cmd_gui.data()));
+#endif
+	for (int i = 1; i < argc; ++ i)
+		argv_extended.emplace_back(argv[i]);
+	argv_extended.emplace_back(nullptr);
+	return slic3r_main(argc, argv_extended.data());
+}