changeset 4036:c6e82885f570

merge
author Alain Mazy <alain@mazy.be>
date Wed, 10 Jun 2020 10:28:15 +0200
parents cc6ed76bba27 (current diff) 78ee0155ec67 (diff)
children e072b4e33600
files Core/HttpServer/EmbeddedResourceHttpHandler.cpp Core/HttpServer/EmbeddedResourceHttpHandler.h OrthancServer/OrthancFindRequestHandler.cpp
diffstat 44 files changed, 552 insertions(+), 428 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Wed Jun 10 10:28:01 2020 +0200
+++ b/CMakeLists.txt	Wed Jun 10 10:28:15 2020 +0200
@@ -26,8 +26,6 @@
 set(ENABLE_WEB_SERVER ON)
 set(ENABLE_ZLIB ON)
 
-set(HAS_EMBEDDED_RESOURCES ON)
-
 
 #####################################################################
 ## CMake parameters tunable at the command line to configure the
@@ -35,6 +33,7 @@
 #####################################################################
 
 # Parameters of the build
+set(STANDALONE_BUILD ON CACHE BOOL "Standalone build (all the resources are embedded, necessary for releases)")
 SET(BUILD_MODALITY_WORKLISTS ON CACHE BOOL "Whether to build the sample plugin to serve modality worklists")
 SET(BUILD_RECOVER_COMPRESSED_FILE ON CACHE BOOL "Whether to build the companion tool to recover files compressed using Orthanc")
 SET(BUILD_SERVE_FOLDERS ON CACHE BOOL "Whether to build the ServeFolders plugin")
@@ -66,14 +65,15 @@
   OrthancServer/Database/SQLiteDatabaseWrapper.cpp
   OrthancServer/DicomInstanceOrigin.cpp
   OrthancServer/DicomInstanceToStore.cpp
+  OrthancServer/EmbeddedResourceHttpHandler.cpp
   OrthancServer/ExportedResource.cpp
   OrthancServer/LuaScripting.cpp
   OrthancServer/OrthancConfiguration.cpp
   OrthancServer/OrthancFindRequestHandler.cpp
+  OrthancServer/OrthancGetRequestHandler.cpp
   OrthancServer/OrthancHttpHandler.cpp
   OrthancServer/OrthancInitialization.cpp
   OrthancServer/OrthancMoveRequestHandler.cpp
-  OrthancServer/OrthancGetRequestHandler.cpp
   OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp
   OrthancServer/OrthancRestApi/OrthancRestApi.cpp
   OrthancServer/OrthancRestApi/OrthancRestArchive.cpp
@@ -166,6 +166,7 @@
     ${ORTHANC_DICOM_SOURCES_INTERNAL}
     ${ORTHANC_SERVER_SOURCES}
     ${ORTHANC_UNIT_TESTS_SOURCES}
+    ${ORTHANC_ROOT}/Core/HttpServer/EmbeddedResourceHttpHandler.cpp
     Plugins/Samples/ServeFolders/Plugin.cpp
     Plugins/Samples/ModalityWorklists/Plugin.cpp
     OrthancServer/main.cpp
@@ -196,24 +197,28 @@
 
 if (STANDALONE_BUILD)
   # We embed all the resources in the binaries for standalone builds
-  add_definitions(-DORTHANC_STANDALONE=1)
-  EmbedResources(
-    ${ORTHANC_EMBEDDED_FILES}
+  add_definitions(
+    -DORTHANC_STANDALONE=1
+    )
+
+  list(APPEND ORTHANC_EMBEDDED_FILES
     ORTHANC_EXPLORER ${CMAKE_CURRENT_SOURCE_DIR}/OrthancExplorer
-    ${DCMTK_DICTIONARIES}
-    ${LIBICU_RESOURCES}
     )
 else()
   add_definitions(
+    -DORTHANC_PATH=\"${CMAKE_SOURCE_DIR}\"
     -DORTHANC_STANDALONE=0
-    -DORTHANC_PATH=\"${CMAKE_SOURCE_DIR}\"
-    )
-  EmbedResources(
-    ${ORTHANC_EMBEDDED_FILES}
-    ${LIBICU_RESOURCES}
     )
 endif()
 
+EmbedResources(
+  --namespace=Orthanc.ServerResources
+  --target=OrthancServerResources
+  --framework-path=${CMAKE_SOURCE_DIR}/Core
+  ${ORTHANC_EMBEDDED_FILES}
+  )
+
+
 if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
   execute_process(
     COMMAND 
--- a/Core/Compression/HierarchicalZipWriter.h	Wed Jun 10 10:28:01 2020 +0200
+++ b/Core/Compression/HierarchicalZipWriter.h	Wed Jun 10 10:28:15 2020 +0200
@@ -53,7 +53,7 @@
 #endif
 
   private:
-    class Index
+    class ORTHANC_PUBLIC Index
     {
     private:
       struct Directory
--- a/Core/DicomParsing/FromDcmtkBridge.cpp	Wed Jun 10 10:28:01 2020 +0200
+++ b/Core/DicomParsing/FromDcmtkBridge.cpp	Wed Jun 10 10:28:15 2020 +0200
@@ -103,7 +103,7 @@
 #endif
 
 #if DCMTK_USE_EMBEDDED_DICTIONARIES == 1
-#  include <EmbeddedResources.h>
+#  include <OrthancFrameworkResources.h>
 #endif
 
 #if ORTHANC_ENABLE_DCMTK_JPEG == 1
@@ -142,10 +142,10 @@
 
 #if DCMTK_USE_EMBEDDED_DICTIONARIES == 1
   static void LoadEmbeddedDictionary(DcmDataDictionary& dictionary,
-                                     EmbeddedResources::FileResourceId resource)
+                                     FrameworkResources::FileResourceId resource)
   {
     std::string content;
-    EmbeddedResources::GetFileResource(content, resource);
+    FrameworkResources::GetFileResource(content, resource);
 
 #if ORTHANC_SANDBOXED == 0
     TemporaryFile tmp;
@@ -171,7 +171,7 @@
 
   namespace
   {
-    class DictionaryLocker
+    class DictionaryLocker : public boost::noncopyable
     {
     private:
       DcmDataDictionary& dictionary_;
@@ -269,14 +269,14 @@
        * command "strace storescu 2>&1 |grep dic" shows that DICONDE
        * dictionary is not loaded by storescu.
        **/
-      //LoadEmbeddedDictionary(*locker, EmbeddedResources::DICTIONARY_DICONDE);
-
-      LoadEmbeddedDictionary(*locker, EmbeddedResources::DICTIONARY_DICOM);
+      //LoadEmbeddedDictionary(*locker, FrameworkResources::DICTIONARY_DICONDE);
+
+      LoadEmbeddedDictionary(*locker, FrameworkResources::DICTIONARY_DICOM);
 
       if (loadPrivateDictionary)
       {
         LOG(INFO) << "Loading the embedded dictionary of private tags";
-        LoadEmbeddedDictionary(*locker, EmbeddedResources::DICTIONARY_PRIVATE);
+        LoadEmbeddedDictionary(*locker, FrameworkResources::DICTIONARY_PRIVATE);
       }
       else
       {
--- a/Core/FileStorage/FilesystemStorage.h	Wed Jun 10 10:28:01 2020 +0200
+++ b/Core/FileStorage/FilesystemStorage.h	Wed Jun 10 10:28:15 2020 +0200
@@ -33,6 +33,8 @@
 
 #pragma once
 
+#include "../OrthancFramework.h"
+
 #if !defined(ORTHANC_SANDBOXED)
 #  error The macro ORTHANC_SANDBOXED must be defined
 #endif
--- a/Core/HttpClient.h	Wed Jun 10 10:28:01 2020 +0200
+++ b/Core/HttpClient.h	Wed Jun 10 10:28:15 2020 +0200
@@ -42,6 +42,14 @@
 #include <boost/shared_ptr.hpp>
 #include <json/json.h>
 
+#if !defined(ORTHANC_ENABLE_CURL)
+#  error The macro ORTHANC_ENABLE_CURL must be defined
+#endif
+
+#if ORTHANC_ENABLE_CURL != 1
+#  error Support for curl is disabled, cannot use this file
+#endif
+
 #if !defined(ORTHANC_ENABLE_SSL)
 #  error The macro ORTHANC_ENABLE_SSL must be defined
 #endif
--- a/Core/HttpServer/EmbeddedResourceHttpHandler.cpp	Wed Jun 10 10:28:01 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,99 +0,0 @@
-/**
- * Orthanc - A Lightweight, RESTful DICOM Store
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * In addition, as a special exception, the copyright holders of this
- * program give permission to link the code of its release with the
- * OpenSSL project's "OpenSSL" library (or with modified versions of it
- * that use the same license as the "OpenSSL" library), and distribute
- * the linked executables. You must obey the GNU General Public License
- * in all respects for all of the code used other than "OpenSSL". If you
- * modify file(s) with this exception, you may extend this exception to
- * your version of the file(s), but you are not obligated to do so. If
- * you do not wish to do so, delete this exception statement from your
- * version. If you delete this exception statement from all source files
- * in the program, then also delete it here.
- * 
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#include "../PrecompiledHeaders.h"
-#include "EmbeddedResourceHttpHandler.h"
-
-#include "../Logging.h"
-#include "../OrthancException.h"
-#include "../SystemToolbox.h"
-#include "HttpOutput.h"
-
-#include <stdio.h>
-
-
-namespace Orthanc
-{
-  EmbeddedResourceHttpHandler::EmbeddedResourceHttpHandler(
-    const std::string& baseUri,
-    EmbeddedResources::DirectoryResourceId resourceId)
-  {
-    Toolbox::SplitUriComponents(baseUri_, baseUri);
-    resourceId_ = resourceId;
-  }
-
-
-  bool EmbeddedResourceHttpHandler::Handle(
-    HttpOutput& output,
-    RequestOrigin /*origin*/,
-    const char* /*remoteIp*/,
-    const char* /*username*/,
-    HttpMethod method,
-    const UriComponents& uri,
-    const Arguments& headers,
-    const GetArguments& arguments,
-    const void* /*bodyData*/,
-    size_t /*bodySize*/)
-  {
-    if (!Toolbox::IsChildUri(baseUri_, uri))
-    {
-      // This URI is not served by this handler
-      return false;
-    }
-
-    if (method != HttpMethod_Get)
-    {
-      output.SendMethodNotAllowed("GET");
-      return true;
-    }
-
-    std::string resourcePath = Toolbox::FlattenUri(uri, baseUri_.size());
-    MimeType contentType = SystemToolbox::AutodetectMimeType(resourcePath);
-
-    try
-    {
-      const void* buffer = EmbeddedResources::GetDirectoryResourceBuffer(resourceId_, resourcePath.c_str());
-      size_t size = EmbeddedResources::GetDirectoryResourceSize(resourceId_, resourcePath.c_str());
-
-      output.SetContentType(contentType);
-      output.Answer(buffer, size);
-    }
-    catch (OrthancException&)
-    {
-      LOG(WARNING) << "Unable to find HTTP resource: " << resourcePath;
-      output.SendStatus(HttpStatus_404_NotFound);
-    }
-
-    return true;
-  } 
-}
--- a/Core/HttpServer/EmbeddedResourceHttpHandler.h	Wed Jun 10 10:28:01 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/**
- * Orthanc - A Lightweight, RESTful DICOM Store
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * In addition, as a special exception, the copyright holders of this
- * program give permission to link the code of its release with the
- * OpenSSL project's "OpenSSL" library (or with modified versions of it
- * that use the same license as the "OpenSSL" library), and distribute
- * the linked executables. You must obey the GNU General Public License
- * in all respects for all of the code used other than "OpenSSL". If you
- * modify file(s) with this exception, you may extend this exception to
- * your version of the file(s), but you are not obligated to do so. If
- * you do not wish to do so, delete this exception statement from your
- * version. If you delete this exception statement from all source files
- * in the program, then also delete it here.
- * 
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "IHttpHandler.h"
-
-#include <EmbeddedResources.h>   // Autogenerated file
-#include <boost/shared_ptr.hpp>
-
-namespace Orthanc
-{
-  class EmbeddedResourceHttpHandler : public IHttpHandler
-  {
-  private:
-    UriComponents baseUri_;
-    EmbeddedResources::DirectoryResourceId resourceId_;
-
-  public:
-    EmbeddedResourceHttpHandler(
-      const std::string& baseUri,
-      EmbeddedResources::DirectoryResourceId resourceId);
-
-    virtual bool CreateChunkedRequestReader(std::unique_ptr<IChunkedRequestReader>& target,
-                                            RequestOrigin origin,
-                                            const char* remoteIp,
-                                            const char* username,
-                                            HttpMethod method,
-                                            const UriComponents& uri,
-                                            const Arguments& headers)
-    {
-      return false;
-    }
-
-    virtual bool Handle(HttpOutput& output,
-                        RequestOrigin origin,
-                        const char* remoteIp,
-                        const char* username,
-                        HttpMethod method,
-                        const UriComponents& uri,
-                        const Arguments& headers,
-                        const GetArguments& arguments,
-                        const void* /*bodyData*/,
-                        size_t /*bodySize*/);
-  };
-}
--- a/Core/Images/Font.cpp	Wed Jun 10 10:28:01 2020 +0200
+++ b/Core/Images/Font.cpp	Wed Jun 10 10:28:15 2020 +0200
@@ -153,16 +153,6 @@
 #endif
 
 
-#if ORTHANC_HAS_EMBEDDED_RESOURCES == 1
-  void Font::LoadFromResource(EmbeddedResources::FileResourceId resource)
-  {
-    std::string content;
-    EmbeddedResources::GetFileResource(content, resource);
-    LoadFromMemory(content);
-  }
-#endif
-
-
   static unsigned int MyMin(unsigned int a, 
                             unsigned int b)
   {
--- a/Core/Images/Font.h	Wed Jun 10 10:28:01 2020 +0200
+++ b/Core/Images/Font.h	Wed Jun 10 10:28:15 2020 +0200
@@ -33,17 +33,8 @@
 
 #pragma once
 
-// To have ORTHANC_HAS_EMBEDDED_RESOURCES defined if using the shared library
 #include "../OrthancFramework.h"
 
-#if !defined(ORTHANC_HAS_EMBEDDED_RESOURCES)
-#  error Macro ORTHANC_HAS_EMBEDDED_RESOURCES must be defined
-#endif
-
-#if ORTHANC_HAS_EMBEDDED_RESOURCES == 1
-#  include <EmbeddedResources.h>   // Autogenerated file
-#endif
-
 #include "ImageAccessor.h"
 
 #include <stdint.h>
@@ -99,10 +90,6 @@
     void LoadFromFile(const std::string& path);
 #endif
 
-#if ORTHANC_HAS_EMBEDDED_RESOURCES == 1
-    void LoadFromResource(EmbeddedResources::FileResourceId resource);
-#endif
-
     const std::string& GetName() const
     {
       return name_;
--- a/Core/Images/FontRegistry.cpp	Wed Jun 10 10:28:01 2020 +0200
+++ b/Core/Images/FontRegistry.cpp	Wed Jun 10 10:28:15 2020 +0200
@@ -67,16 +67,6 @@
 #endif
 
 
-#if ORTHANC_HAS_EMBEDDED_RESOURCES == 1
-  void FontRegistry::AddFromResource(EmbeddedResources::FileResourceId resource)
-  {
-    std::string content;
-    EmbeddedResources::GetFileResource(content, resource);
-    AddFromMemory(content);
-  }
-#endif
-
-
   const Font& FontRegistry::GetFont(size_t i) const
   {
     if (i >= fonts_.size())
--- a/Core/Images/FontRegistry.h	Wed Jun 10 10:28:01 2020 +0200
+++ b/Core/Images/FontRegistry.h	Wed Jun 10 10:28:15 2020 +0200
@@ -35,14 +35,6 @@
 
 #include "Font.h"
 
-#if !defined(ORTHANC_HAS_EMBEDDED_RESOURCES)
-#  error Macro ORTHANC_HAS_EMBEDDED_RESOURCES must be defined
-#endif
-
-#if ORTHANC_HAS_EMBEDDED_RESOURCES == 1
-#  include <EmbeddedResources.h>   // Autogenerated file
-#endif
-
 namespace Orthanc
 {
   class ORTHANC_PUBLIC FontRegistry : public boost::noncopyable
@@ -61,10 +53,6 @@
     void AddFromFile(const std::string& path);
 #endif
 
-#if ORTHANC_HAS_EMBEDDED_RESOURCES == 1
-    void AddFromResource(EmbeddedResources::FileResourceId resource);
-#endif
-
     size_t GetSize() const
     {
       return fonts_.size();
--- a/Core/Logging.cpp	Wed Jun 10 10:28:01 2020 +0200
+++ b/Core/Logging.cpp	Wed Jun 10 10:28:15 2020 +0200
@@ -537,7 +537,11 @@
     void Initialize()
     {
       boost::mutex::scoped_lock lock(loggingStreamsMutex_);
-      loggingStreamsContext_.reset(new LoggingStreamsContext);
+
+      if (loggingStreamsContext_.get() == NULL)
+      {
+        loggingStreamsContext_.reset(new LoggingStreamsContext);
+      }
     }
 
     void Finalize()
--- a/Core/Lua/LuaContext.cpp	Wed Jun 10 10:28:01 2020 +0200
+++ b/Core/Lua/LuaContext.cpp	Wed Jun 10 10:28:15 2020 +0200
@@ -167,6 +167,7 @@
   }
 
 
+#if ORTHANC_ENABLE_CURL == 1
   int LuaContext::SetHttpCredentials(lua_State *state)
   {
     LuaContext& that = GetLuaContext(state);
@@ -189,8 +190,10 @@
 
     return 0;
   }
+#endif
 
 
+#if ORTHANC_ENABLE_CURL == 1
   bool LuaContext::AnswerHttpQuery(lua_State* state)
   {
     std::string str;
@@ -209,8 +212,10 @@
 
     return true;
   }
+#endif
   
 
+#if ORTHANC_ENABLE_CURL == 1
   void LuaContext::SetHttpHeaders(int top)
   {
     std::map<std::string, std::string> headers;
@@ -223,9 +228,11 @@
     {
       httpClient_.AddHeader(it->first, it->second);
     }
-  }  
+  }
+#endif
 
 
+#if ORTHANC_ENABLE_CURL == 1
   int LuaContext::CallHttpGet(lua_State *state)
   {
     LuaContext& that = GetLuaContext(state);
@@ -256,8 +263,10 @@
 
     return 1;
   }
+#endif
 
 
+#if ORTHANC_ENABLE_CURL == 1
   int LuaContext::CallHttpPostOrPut(lua_State *state,
                                     HttpMethod method)
   {
@@ -308,20 +317,26 @@
 
     return 1;
   }
+#endif
+  
 
-
+#if ORTHANC_ENABLE_CURL == 1
   int LuaContext::CallHttpPost(lua_State *state)
   {
     return CallHttpPostOrPut(state, HttpMethod_Post);
   }
+#endif
 
 
+#if ORTHANC_ENABLE_CURL == 1
   int LuaContext::CallHttpPut(lua_State *state)
   {
     return CallHttpPostOrPut(state, HttpMethod_Put);
   }
+#endif
 
 
+#if ORTHANC_ENABLE_CURL == 1
   int LuaContext::CallHttpDelete(lua_State *state)
   {
     LuaContext& that = GetLuaContext(state);
@@ -356,6 +371,7 @@
 
     return 1;
   }
+#endif
 
 
   void LuaContext::PushJson(const Json::Value& value)
@@ -554,11 +570,14 @@
     lua_register(lua_, "print", PrintToLog);
     lua_register(lua_, "ParseJson", ParseJson);
     lua_register(lua_, "DumpJson", DumpJson);
+    
+#if ORTHANC_ENABLE_CURL == 1
     lua_register(lua_, "HttpGet", CallHttpGet);
     lua_register(lua_, "HttpPost", CallHttpPost);
     lua_register(lua_, "HttpPut", CallHttpPut);
     lua_register(lua_, "HttpDelete", CallHttpDelete);
     lua_register(lua_, "SetHttpCredentials", SetHttpCredentials);
+#endif
 
     SetGlobalVariable("_LuaContext", this);
   }
@@ -593,16 +612,6 @@
   }
 
 
-#if ORTHANC_HAS_EMBEDDED_RESOURCES == 1
-  void LuaContext::Execute(EmbeddedResources::FileResourceId resource)
-  {
-    std::string command;
-    EmbeddedResources::GetFileResource(command, resource);
-    ExecuteInternal(NULL, command);
-  }
-#endif
-
-
   bool LuaContext::IsExistingFunction(const char* name)
   {
     lua_settop(lua_, 0);
--- a/Core/Lua/LuaContext.h	Wed Jun 10 10:28:01 2020 +0200
+++ b/Core/Lua/LuaContext.h	Wed Jun 10 10:28:15 2020 +0200
@@ -40,26 +40,25 @@
 #  error The macro ORTHANC_ENABLE_LUA must be defined
 #endif
 
-#if !defined(ORTHANC_HAS_EMBEDDED_RESOURCES)
-#  error Macro ORTHANC_HAS_EMBEDDED_RESOURCES must be defined
+#if !defined(ORTHANC_ENABLE_CURL)
+#  error Macro ORTHANC_ENABLE_CURL must be defined
 #endif
 
 #if ORTHANC_ENABLE_LUA == 0
 #  error The Lua support is disabled, cannot include this file
 #endif
 
-#if ORTHANC_HAS_EMBEDDED_RESOURCES == 1
-#  include <EmbeddedResources.h>   // Autogenerated file
+#if ORTHANC_ENABLE_CURL == 1
+#  include "../HttpClient.h"
 #endif
 
-#include "../HttpClient.h"
-
 extern "C" 
 {
 #include <lua.h>
 }
 
 #include <boost/noncopyable.hpp>
+#include <json/value.h>
 
 namespace Orthanc
 {
@@ -70,20 +69,24 @@
 
     lua_State *lua_;
     std::string log_;
+
+#if ORTHANC_ENABLE_CURL == 1
     HttpClient httpClient_;
+#endif
 
     static int PrintToLog(lua_State *state);
     static int ParseJson(lua_State *state);
     static int DumpJson(lua_State *state);
 
+#if ORTHANC_ENABLE_CURL == 1
     static int SetHttpCredentials(lua_State *state);
-
     static int CallHttpPostOrPut(lua_State *state,
                                  HttpMethod method);
     static int CallHttpGet(lua_State *state);
     static int CallHttpPost(lua_State *state);
     static int CallHttpPut(lua_State *state);
     static int CallHttpDelete(lua_State *state);
+#endif
 
     bool AnswerHttpQuery(lua_State* state);
 
@@ -116,17 +119,15 @@
     void Execute(Json::Value& output,
                  const std::string& command);
 
-#if ORTHANC_HAS_EMBEDDED_RESOURCES == 1
-    void Execute(EmbeddedResources::FileResourceId resource);
-#endif
-
     bool IsExistingFunction(const char* name);
 
+#if ORTHANC_ENABLE_CURL == 1
     void SetHttpCredentials(const char* username,
                             const char* password)
     {
       httpClient_.SetCredentials(username, password);
     }
+#endif
 
     void RegisterFunction(const char* name,
                           lua_CFunction func);
--- a/Core/MetricsRegistry.h	Wed Jun 10 10:28:01 2020 +0200
+++ b/Core/MetricsRegistry.h	Wed Jun 10 10:28:15 2020 +0200
@@ -113,7 +113,7 @@
     void ExportPrometheusText(std::string& s);
 
 
-    class SharedMetrics : public boost::noncopyable
+    class ORTHANC_PUBLIC SharedMetrics : public boost::noncopyable
     {
     private:
       boost::mutex      mutex_;
@@ -135,7 +135,7 @@
     };
 
 
-    class ActiveCounter : public boost::noncopyable
+    class ORTHANC_PUBLIC ActiveCounter : public boost::noncopyable
     {
     private:
       SharedMetrics&   metrics_;
@@ -154,7 +154,7 @@
     };
 
 
-    class Timer : public boost::noncopyable
+    class ORTHANC_PUBLIC Timer : public boost::noncopyable
     {
     private:
       MetricsRegistry&          registry_;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/OrthancFramework.cpp	Wed Jun 10 10:28:15 2020 +0200
@@ -0,0 +1,123 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2020 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "PrecompiledHeaders.h"
+#include "OrthancFramework.h"
+
+#if !defined(ORTHANC_ENABLE_CURL)
+#  error Macro ORTHANC_ENABLE_CURL must be defined
+#endif
+
+#if !defined(ORTHANC_ENABLE_SSL)
+#  error Macro ORTHANC_ENABLE_SSL must be defined
+#endif
+
+#if !defined(ORTHANC_ENABLE_DCMTK)
+#  error Macro ORTHANC_ENABLE_DCMTK must be defined
+#endif
+
+#if !defined(ORTHANC_ENABLE_DCMTK_NETWORKING)
+#  error Macro ORTHANC_ENABLE_DCMTK_NETWORKING must be defined
+#endif
+
+#if ORTHANC_ENABLE_CURL == 1
+#  include "HttpClient.h"
+#endif
+
+#if ORTHANC_ENABLE_DCMTK == 1
+#  include "DicomParsing/FromDcmtkBridge.h"
+#  if ORTHANC_ENABLE_DCMTK_NETWORKING == 1
+#    include <dcmtk/dcmnet/dul.h>
+#  endif
+#endif
+
+#include "Logging.h"
+#include "Toolbox.h"
+
+
+namespace Orthanc
+{
+  void InitializeFramework(const std::string& locale,
+                           bool loadPrivateDictionary)
+  {
+    Logging::Initialize();
+
+#if (ORTHANC_ENABLE_LOCALE == 1) && !defined(__EMSCRIPTEN__)  // No global locale in wasm/asm.js
+    if (locale.empty())
+    {
+      Toolbox::InitializeGlobalLocale(NULL);
+    }
+    else
+    {
+      Toolbox::InitializeGlobalLocale(locale.c_str());
+    }
+#endif
+
+    Toolbox::InitializeOpenSsl();
+
+#if ORTHANC_ENABLE_CURL == 1
+    HttpClient::GlobalInitialize();
+#endif
+
+#if ORTHANC_ENABLE_DCMTK == 1
+    FromDcmtkBridge::InitializeDictionary(true);
+    FromDcmtkBridge::InitializeCodecs();
+#endif
+
+#if (ORTHANC_ENABLE_DCMTK == 1 &&               \
+     ORTHANC_ENABLE_DCMTK_NETWORKING == 1)
+    /* Disable "gethostbyaddr" (which results in memory leaks) and use raw IP addresses */
+    dcmDisableGethostbyaddr.set(OFTrue);
+#endif
+  }
+  
+
+  void FinalizeFramework()
+  {
+#if ORTHANC_ENABLE_DCMTK == 1
+    FromDcmtkBridge::FinalizeCodecs();
+#endif
+
+#if ORTHANC_ENABLE_CURL == 1
+    HttpClient::GlobalFinalize();
+#endif
+    
+    Toolbox::FinalizeOpenSsl();
+
+#if (ORTHANC_ENABLE_LOCALE == 1) && !defined(__EMSCRIPTEN__)
+    Toolbox::FinalizeGlobalLocale();
+#endif
+    
+    Logging::Finalize();
+  }
+}
--- a/Core/OrthancFramework.h	Wed Jun 10 10:28:01 2020 +0200
+++ b/Core/OrthancFramework.h	Wed Jun 10 10:28:15 2020 +0200
@@ -41,8 +41,8 @@
 #ifndef __ORTHANC_FRAMEWORK_H
 #define __ORTHANC_FRAMEWORK_H
 
-#if !defined(ORTHANC_FRAMEWORK_BUILDING_LIBRARY)
-#  define ORTHANC_FRAMEWORK_BUILDING_LIBRARY 0
+#if !defined(ORTHANC_BUILDING_FRAMEWORK_LIBRARY)
+#  error The macro ORTHANC_BUILDING_FRAMEWORK_LIBRARY must be defined
 #endif
 
 /**
@@ -51,7 +51,7 @@
  * common "BUILDING_DLL"
  * construction. https://gcc.gnu.org/wiki/Visibility
  **/
-#if ORTHANC_FRAMEWORK_BUILDING_LIBRARY == 1
+#if ORTHANC_BUILDING_FRAMEWORK_LIBRARY == 1
 #  if defined(_WIN32) || defined (__CYGWIN__)
 #    define ORTHANC_PUBLIC __declspec(dllexport)
 #    define ORTHANC_LOCAL
@@ -70,4 +70,16 @@
 #  define ORTHANC_LOCAL
 #endif
 
+
+#include <string>
+
+namespace Orthanc
+{
+  ORTHANC_PUBLIC void InitializeFramework(const std::string& locale,
+                                          bool loadPrivateDictionary);
+  
+  ORTHANC_PUBLIC void FinalizeFramework();
+}
+
+
 #endif /* __ORTHANC_FRAMEWORK_H */
--- a/Core/RestApi/RestApiHierarchy.h	Wed Jun 10 10:28:01 2020 +0200
+++ b/Core/RestApi/RestApiHierarchy.h	Wed Jun 10 10:28:15 2020 +0200
@@ -45,7 +45,7 @@
   class ORTHANC_PUBLIC RestApiHierarchy : public boost::noncopyable
   {
   public:
-    class Resource : public boost::noncopyable
+    class ORTHANC_PUBLIC Resource : public boost::noncopyable
     {
     private:
       RestApiGetCall::Handler     getHandler_;
--- a/Core/Toolbox.cpp	Wed Jun 10 10:28:01 2020 +0200
+++ b/Core/Toolbox.cpp	Wed Jun 10 10:28:15 2020 +0200
@@ -118,7 +118,7 @@
 
 #if defined(ORTHANC_STATIC_ICU)
 #  if (ORTHANC_STATIC_ICU == 1 && ORTHANC_ENABLE_LOCALE == 1)
-#    include <EmbeddedResources.h>
+#    include <OrthancFrameworkResources.h>
 #    include <unicode/udata.h>
 #    include <unicode/uloc.h>
 #    include "Compression/GzipCompressor.h"
@@ -1473,8 +1473,8 @@
 
       GzipCompressor compressor;
       compressor.Uncompress(globalIcuData_,
-                            EmbeddedResources::GetFileResourceBuffer(EmbeddedResources::LIBICU_DATA),
-                            EmbeddedResources::GetFileResourceSize(EmbeddedResources::LIBICU_DATA));
+                            FrameworkResources::GetFileResourceBuffer(FrameworkResources::LIBICU_DATA),
+                            FrameworkResources::GetFileResourceSize(FrameworkResources::LIBICU_DATA));
 
       std::string md5;
       Toolbox::ComputeMD5(md5, globalIcuData_);
@@ -2226,7 +2226,7 @@
 
 
 bool OrthancLinesIterator_GetLine(std::string& target,
-                                         const OrthancLinesIterator* iterator)
+                                  const OrthancLinesIterator* iterator)
 {
   if (iterator != NULL)
   {
--- a/Core/Toolbox.h	Wed Jun 10 10:28:01 2020 +0200
+++ b/Core/Toolbox.h	Wed Jun 10 10:28:15 2020 +0200
@@ -58,6 +58,10 @@
 #  error The macro ORTHANC_ENABLE_PUGIXML must be defined
 #endif
 
+#if !defined(ORTHANC_ENABLE_SSL)
+#  error The macro ORTHANC_ENABLE_SSL must be defined
+#endif
+
 
 /**
  * NOTE: GUID vs. UUID
@@ -85,7 +89,7 @@
   class ORTHANC_PUBLIC Toolbox
   {
   public:
-    class LinesIterator
+    class ORTHANC_PUBLIC LinesIterator
     {
     private:
       const std::string& content_;
@@ -243,7 +247,7 @@
 #endif
 
     static void InitializeOpenSsl();
-    
+
     static void FinalizeOpenSsl();
 
     static std::string GenerateUuid();
@@ -272,8 +276,8 @@
 /**
  * The plain C, opaque data structure "OrthancLinesIterator" is a thin
  * wrapper around Orthanc::Toolbox::LinesIterator, and is only used by
- * "../Resources/WebAssembly/dcdict.cc", in order to avoid code
- * duplication
+ * "../Resources/Patches/dcmtk-dcdict_orthanc.cc", in order to avoid
+ * code duplication
  **/
 
 struct OrthancLinesIterator;
--- a/OrthancServer/Database/SQLiteDatabaseWrapper.cpp	Wed Jun 10 10:28:01 2020 +0200
+++ b/OrthancServer/Database/SQLiteDatabaseWrapper.cpp	Wed Jun 10 10:28:15 2020 +0200
@@ -40,7 +40,7 @@
 #include "../Search/ISqlLookupFormatter.h"
 #include "../ServerToolbox.h"
 
-#include <EmbeddedResources.h>
+#include <OrthancServerResources.h>
 
 #include <stdio.h>
 #include <boost/lexical_cast.hpp>
@@ -394,7 +394,7 @@
       {
         LOG(INFO) << "Creating the database";
         std::string query;
-        EmbeddedResources::GetFileResource(query, EmbeddedResources::PREPARE_DATABASE);
+        ServerResources::GetFileResource(query, ServerResources::PREPARE_DATABASE);
         db_.Execute(query);
       }
 
@@ -430,7 +430,7 @@
         {
           LOG(INFO) << "Installing the SQLite triggers to track the size of the attachments";
           std::string query;
-          EmbeddedResources::GetFileResource(query, EmbeddedResources::INSTALL_TRACK_ATTACHMENTS_SIZE);
+          ServerResources::GetFileResource(query, ServerResources::INSTALL_TRACK_ATTACHMENTS_SIZE);
           db_.Execute(query);
         }
       }
@@ -444,10 +444,10 @@
 
 
   static void ExecuteUpgradeScript(SQLite::Connection& db,
-                                   EmbeddedResources::FileResourceId script)
+                                   ServerResources::FileResourceId script)
   {
     std::string upgrade;
-    EmbeddedResources::GetFileResource(upgrade, script);
+    ServerResources::GetFileResource(upgrade, script);
     db.BeginTransaction();
     db.Execute(upgrade);
     db.CommitTransaction();    
@@ -475,14 +475,14 @@
     if (version_ == 3)
     {
       LOG(WARNING) << "Upgrading database version from 3 to 4";
-      ExecuteUpgradeScript(db_, EmbeddedResources::UPGRADE_DATABASE_3_TO_4);
+      ExecuteUpgradeScript(db_, ServerResources::UPGRADE_DATABASE_3_TO_4);
       version_ = 4;
     }
 
     if (version_ == 4)
     {
       LOG(WARNING) << "Upgrading database version from 4 to 5";
-      ExecuteUpgradeScript(db_, EmbeddedResources::UPGRADE_DATABASE_4_TO_5);
+      ExecuteUpgradeScript(db_, ServerResources::UPGRADE_DATABASE_4_TO_5);
       version_ = 5;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancServer/EmbeddedResourceHttpHandler.cpp	Wed Jun 10 10:28:15 2020 +0200
@@ -0,0 +1,97 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2020 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "PrecompiledHeadersServer.h"
+#include "EmbeddedResourceHttpHandler.h"
+
+#include "../Core/HttpServer/HttpOutput.h"
+#include "../Core/Logging.h"
+#include "../Core/OrthancException.h"
+#include "../Core/SystemToolbox.h"
+
+
+namespace Orthanc
+{
+  EmbeddedResourceHttpHandler::EmbeddedResourceHttpHandler(
+    const std::string& baseUri,
+    ServerResources::DirectoryResourceId resourceId)
+  {
+    Toolbox::SplitUriComponents(baseUri_, baseUri);
+    resourceId_ = resourceId;
+  }
+
+
+  bool EmbeddedResourceHttpHandler::Handle(
+    HttpOutput& output,
+    RequestOrigin /*origin*/,
+    const char* /*remoteIp*/,
+    const char* /*username*/,
+    HttpMethod method,
+    const UriComponents& uri,
+    const Arguments& headers,
+    const GetArguments& arguments,
+    const void* /*bodyData*/,
+    size_t /*bodySize*/)
+  {
+    if (!Toolbox::IsChildUri(baseUri_, uri))
+    {
+      // This URI is not served by this handler
+      return false;
+    }
+
+    if (method != HttpMethod_Get)
+    {
+      output.SendMethodNotAllowed("GET");
+      return true;
+    }
+
+    std::string resourcePath = Toolbox::FlattenUri(uri, baseUri_.size());
+    MimeType contentType = SystemToolbox::AutodetectMimeType(resourcePath);
+
+    try
+    {
+      const void* buffer = ServerResources::GetDirectoryResourceBuffer(resourceId_, resourcePath.c_str());
+      size_t size = ServerResources::GetDirectoryResourceSize(resourceId_, resourcePath.c_str());
+
+      output.SetContentType(contentType);
+      output.Answer(buffer, size);
+    }
+    catch (OrthancException&)
+    {
+      LOG(WARNING) << "Unable to find HTTP resource: " << resourcePath;
+      output.SendStatus(HttpStatus_404_NotFound);
+    }
+
+    return true;
+  } 
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancServer/EmbeddedResourceHttpHandler.h	Wed Jun 10 10:28:15 2020 +0200
@@ -0,0 +1,76 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2020 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "../Core/HttpServer/IHttpHandler.h"
+
+#include <OrthancServerResources.h>   // Autogenerated file
+#include <boost/shared_ptr.hpp>
+
+namespace Orthanc
+{
+  class EmbeddedResourceHttpHandler : public IHttpHandler
+  {
+  private:
+    UriComponents baseUri_;
+    ServerResources::DirectoryResourceId resourceId_;
+
+  public:
+    EmbeddedResourceHttpHandler(
+      const std::string& baseUri,
+      ServerResources::DirectoryResourceId resourceId);
+
+    virtual bool CreateChunkedRequestReader(std::unique_ptr<IChunkedRequestReader>& target,
+                                            RequestOrigin origin,
+                                            const char* remoteIp,
+                                            const char* username,
+                                            HttpMethod method,
+                                            const UriComponents& uri,
+                                            const Arguments& headers)
+    {
+      return false;
+    }
+
+    virtual bool Handle(HttpOutput& output,
+                        RequestOrigin origin,
+                        const char* remoteIp,
+                        const char* username,
+                        HttpMethod method,
+                        const UriComponents& uri,
+                        const Arguments& headers,
+                        const GetArguments& arguments,
+                        const void* /*bodyData*/,
+                        size_t /*bodySize*/);
+  };
+}
--- a/OrthancServer/LuaScripting.cpp	Wed Jun 10 10:28:01 2020 +0200
+++ b/OrthancServer/LuaScripting.cpp	Wed Jun 10 10:28:15 2020 +0200
@@ -42,7 +42,7 @@
 #include "../Core/Logging.h"
 #include "../Core/Lua/LuaFunctionCall.h"
 
-#include <EmbeddedResources.h>
+#include <OrthancServerResources.h>
 
 
 namespace Orthanc
@@ -907,7 +907,11 @@
   {
     OrthancConfiguration::ReaderLock configLock;
 
-    lua_.Execute(Orthanc::EmbeddedResources::LUA_TOOLBOX);
+    {
+      std::string command;
+      Orthanc::ServerResources::GetFileResource(command, Orthanc::ServerResources::LUA_TOOLBOX);
+      lua_.Execute(command);
+    }    
 
     std::list<std::string> luaScripts;
     configLock.GetConfiguration().GetListOfStringsParameter(luaScripts, "LuaScripts");
--- a/OrthancServer/OrthancConfiguration.cpp	Wed Jun 10 10:28:01 2020 +0200
+++ b/OrthancServer/OrthancConfiguration.cpp	Wed Jun 10 10:28:15 2020 +0200
@@ -584,6 +584,14 @@
   }
 
 
+  void OrthancConfiguration::RegisterFont(ServerResources::FileResourceId resource)
+  {
+    std::string content;
+    ServerResources::GetFileResource(content, resource);
+    fontRegistry_.AddFromMemory(content);
+  }
+
+
   void OrthancConfiguration::GetDicomModalityUsingSymbolicName(
     RemoteModalityParameters& modality,
     const std::string& name) const
--- a/OrthancServer/OrthancConfiguration.h	Wed Jun 10 10:28:01 2020 +0200
+++ b/OrthancServer/OrthancConfiguration.h	Wed Jun 10 10:28:15 2020 +0200
@@ -37,7 +37,7 @@
 #include "../Core/WebServiceParameters.h"
 #include "../Core/DicomNetworking/RemoteModalityParameters.h"
 
-#include <EmbeddedResources.h>
+#include <OrthancServerResources.h>
 
 #include <boost/filesystem.hpp>
 #include <boost/thread/shared_mutex.hpp>
@@ -158,10 +158,7 @@
 
     void LoadModalitiesAndPeers();
     
-    void RegisterFont(EmbeddedResources::FileResourceId resource)
-    {
-      fontRegistry_.AddFromResource(resource);
-    }
+    void RegisterFont(ServerResources::FileResourceId resource);
 
     bool LookupStringParameter(std::string& target,
                                const std::string& parameter) const;
--- a/OrthancServer/OrthancFindRequestHandler.cpp	Wed Jun 10 10:28:01 2020 +0200
+++ b/OrthancServer/OrthancFindRequestHandler.cpp	Wed Jun 10 10:28:15 2020 +0200
@@ -399,9 +399,11 @@
 
           if (tag->IsPrivate())
           {
-            if (privateCreators.find(tag->GetGroup()) != privateCreators.end())
+            std::map<uint16_t, std::string>::const_iterator found = privateCreators.find(tag->GetGroup());
+            
+            if (found != privateCreators.end())
             {
-              dicom.Replace(*tag, content, false, DicomReplaceMode_InsertIfAbsent, privateCreators.at(tag->GetGroup()).c_str());
+              dicom.Replace(*tag, content, false, DicomReplaceMode_InsertIfAbsent, found->second.c_str());
             }
             else
             {
--- a/OrthancServer/OrthancInitialization.cpp	Wed Jun 10 10:28:01 2020 +0200
+++ b/OrthancServer/OrthancInitialization.cpp	Wed Jun 10 10:28:15 2020 +0200
@@ -48,6 +48,8 @@
 #include "Database/SQLiteDatabaseWrapper.h"
 #include "OrthancConfiguration.h"
 
+#include <OrthancServerResources.h>
+
 #include <dcmtk/dcmnet/dul.h>   // For dcmDisableGethostbyaddr()
 
 
@@ -225,22 +227,24 @@
   {
     OrthancConfiguration::WriterLock lock;
 
-    Toolbox::InitializeOpenSsl();
-
     InitializeServerEnumerations();
 
     // Read the user-provided configuration
     lock.GetConfiguration().Read(configurationFile);
 
-    if (lock.GetJson().isMember("Locale"))
     {
-      std::string locale = lock.GetConfiguration().GetStringParameter("Locale", "");
-      Toolbox::InitializeGlobalLocale(lock.GetJson()["Locale"].asCString());
+      std::string locale;
+      
+      if (lock.GetJson().isMember("Locale"))
+      {
+        locale = lock.GetConfiguration().GetStringParameter("Locale", "");
+      }
+      
+      bool loadPrivate = lock.GetConfiguration().GetBooleanParameter("LoadPrivateDictionary", true);
+      Orthanc::InitializeFramework(locale, loadPrivate);
     }
-    else
-    {
-      Toolbox::InitializeGlobalLocale(NULL);
-    }
+
+    // The Orthanc framework is now initialized
 
     if (lock.GetJson().isMember("DefaultEncoding"))
     {
@@ -257,21 +261,12 @@
       ConfigurePkcs11(lock.GetJson()["Pkcs11"]);
     }
 
-    HttpClient::GlobalInitialize();
-
     RegisterUserMetadata(lock.GetJson());
     RegisterUserContentType(lock.GetJson());
 
-    bool loadPrivate = lock.GetConfiguration().GetBooleanParameter("LoadPrivateDictionary", true);
-    FromDcmtkBridge::InitializeDictionary(loadPrivate);
     LoadCustomDictionary(lock.GetJson());
 
-    FromDcmtkBridge::InitializeCodecs();
-
-    lock.GetConfiguration().RegisterFont(EmbeddedResources::FONT_UBUNTU_MONO_BOLD_16);
-
-    /* Disable "gethostbyaddr" (which results in memory leaks) and use raw IP addresses */
-    dcmDisableGethostbyaddr.set(OFTrue);
+    lock.GetConfiguration().RegisterFont(ServerResources::FONT_UBUNTU_MONO_BOLD_16);
   }
 
 
@@ -279,11 +274,7 @@
   void OrthancFinalize()
   {
     OrthancConfiguration::WriterLock lock;
-
-    HttpClient::GlobalFinalize();
-    FromDcmtkBridge::FinalizeCodecs();
-    Toolbox::FinalizeOpenSsl();
-    Toolbox::FinalizeGlobalLocale();
+    Orthanc::FinalizeFramework();
   }
 
 
--- a/OrthancServer/OrthancRestApi/OrthancRestSystem.cpp	Wed Jun 10 10:28:01 2020 +0200
+++ b/OrthancServer/OrthancRestApi/OrthancRestSystem.cpp	Wed Jun 10 10:28:15 2020 +0200
@@ -176,7 +176,7 @@
   static void GetDicomConformanceStatement(RestApiGetCall& call)
   {
     std::string statement;
-    GetFileResource(statement, EmbeddedResources::DICOM_CONFORMANCE_STATEMENT);
+    GetFileResource(statement, ServerResources::DICOM_CONFORMANCE_STATEMENT);
     call.GetOutput().AnswerBuffer(statement, MimeType_PlainText);
   }
 
--- a/OrthancServer/ServerContext.cpp	Wed Jun 10 10:28:01 2020 +0200
+++ b/OrthancServer/ServerContext.cpp	Wed Jun 10 10:28:15 2020 +0200
@@ -53,7 +53,6 @@
 #include "ServerToolbox.h"
 #include "StorageCommitmentReports.h"
 
-#include <EmbeddedResources.h>
 #include <dcmtk/dcmdata/dcfilefo.h>
 
 
--- a/OrthancServer/ServerIndex.cpp	Wed Jun 10 10:28:01 2020 +0200
+++ b/OrthancServer/ServerIndex.cpp	Wed Jun 10 10:28:15 2020 +0200
@@ -46,7 +46,6 @@
 
 #include "Database/ResourcesContent.h"
 #include "DicomInstanceToStore.h"
-#include "EmbeddedResources.h"
 #include "OrthancConfiguration.h"
 #include "Search/DatabaseLookup.h"
 #include "Search/DicomTagConstraint.h"
--- a/OrthancServer/main.cpp	Wed Jun 10 10:28:01 2020 +0200
+++ b/OrthancServer/main.cpp	Wed Jun 10 10:28:15 2020 +0200
@@ -41,17 +41,17 @@
 #include "../Core/DicomNetworking/DicomAssociationParameters.h"
 #include "../Core/DicomNetworking/DicomServer.h"
 #include "../Core/DicomParsing/FromDcmtkBridge.h"
-#include "../Core/HttpServer/EmbeddedResourceHttpHandler.h"
 #include "../Core/HttpServer/FilesystemHttpHandler.h"
 #include "../Core/HttpServer/HttpServer.h"
 #include "../Core/Logging.h"
 #include "../Core/Lua/LuaFunctionCall.h"
 #include "../Plugins/Engine/OrthancPlugins.h"
+#include "EmbeddedResourceHttpHandler.h"
 #include "OrthancConfiguration.h"
 #include "OrthancFindRequestHandler.h"
+#include "OrthancGetRequestHandler.h"
 #include "OrthancInitialization.h"
 #include "OrthancMoveRequestHandler.h"
-#include "OrthancGetRequestHandler.h"
 #include "ServerContext.h"
 #include "ServerJobs/StorageCommitmentScpJob.h"
 #include "ServerToolbox.h"
@@ -1152,7 +1152,7 @@
   
   // Secondly, apply the "static resources" layer
 #if ORTHANC_STANDALONE == 1
-  EmbeddedResourceHttpHandler staticResources("/app", EmbeddedResources::ORTHANC_EXPLORER);
+  EmbeddedResourceHttpHandler staticResources("/app", ServerResources::ORTHANC_EXPLORER);
 #else
   FilesystemHttpHandler staticResources("/app", ORTHANC_PATH "/OrthancExplorer");
 #endif
@@ -1566,7 +1566,7 @@
     {
       // TODO WHAT IS THE ENCODING?
       std::string configurationSample;
-      GetFileResource(configurationSample, EmbeddedResources::CONFIGURATION_SAMPLE);
+      GetFileResource(configurationSample, ServerResources::CONFIGURATION_SAMPLE);
 
 #if defined(_WIN32)
       // Replace UNIX newlines with DOS newlines 
@@ -1710,11 +1710,9 @@
     status = -1;
   }
 
-  OrthancFinalize();
-
   LOG(WARNING) << "Orthanc has stopped";
 
-  Logging::Finalize();
+  OrthancFinalize();
 
   return status;
 }
--- a/Plugins/Samples/Common/OrthancPluginException.h	Wed Jun 10 10:28:01 2020 +0200
+++ b/Plugins/Samples/Common/OrthancPluginException.h	Wed Jun 10 10:28:15 2020 +0200
@@ -39,7 +39,7 @@
 
 
 #if HAS_ORTHANC_EXCEPTION == 1
-#  include "../../../Core/OrthancException.h"
+#  include <OrthancException.h>
 #  define ORTHANC_PLUGINS_ERROR_ENUMERATION     ::Orthanc::ErrorCode
 #  define ORTHANC_PLUGINS_EXCEPTION_CLASS       ::Orthanc::OrthancException
 #  define ORTHANC_PLUGINS_GET_ERROR_CODE(code)  ::Orthanc::ErrorCode_ ## code
--- a/Plugins/Samples/ConnectivityChecks/CMakeLists.txt	Wed Jun 10 10:28:01 2020 +0200
+++ b/Plugins/Samples/ConnectivityChecks/CMakeLists.txt	Wed Jun 10 10:28:15 2020 +0200
@@ -6,7 +6,6 @@
 SET(PLUGIN_VERSION "mainline" CACHE STRING "Version of the plugin")
 
 include(${CMAKE_CURRENT_SOURCE_DIR}/../../../Resources/CMake/OrthancFrameworkParameters.cmake)
-set(HAS_EMBEDDED_RESOURCES ON)
 include(${CMAKE_CURRENT_SOURCE_DIR}/../../../Resources/CMake/OrthancFrameworkConfiguration.cmake)
 
 include(JavaScriptLibraries.cmake)
--- a/Resources/CMake/AutoGeneratedCode.cmake	Wed Jun 10 10:28:01 2020 +0200
+++ b/Resources/CMake/AutoGeneratedCode.cmake	Wed Jun 10 10:28:15 2020 +0200
@@ -1,3 +1,5 @@
+set(EMBED_RESOURCES_PYTHON "${CMAKE_CURRENT_LIST_DIR}/../EmbedResources.py"
+  CACHE INTERNAL "Path to the EmbedResources.py script from Orthanc")
 set(AUTOGENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/AUTOGENERATED")
 set(AUTOGENERATED_SOURCES)
 
@@ -11,6 +13,8 @@
   set(DEPENDENCIES)
   set(IS_PATH_NAME false)
 
+  set(TARGET_BASE "${AUTOGENERATED_DIR}/EmbeddedResources")
+
   # Loop over the arguments of the function
   foreach(arg ${ARGN})
     # Extract the first character of the argument
@@ -18,7 +22,13 @@
     if (${FIRST_CHAR} STREQUAL "-")
       # If the argument starts with a dash "-", this is an option to
       # EmbedResources.py
-      list(APPEND SCRIPT_OPTIONS ${arg})
+      if (${arg} MATCHES "--target=.*")
+        # Does the argument starts with "--target="?
+        string(SUBSTRING "${arg}" 9 -1 TARGET)  # 9 is the length of "--target="
+        set(TARGET_BASE "${AUTOGENERATED_DIR}/${TARGET}")
+      else()
+        list(APPEND SCRIPT_OPTIONS ${arg})
+      endif()
     else()
       if (${IS_PATH_NAME})
         list(APPEND SCRIPT_ARGUMENTS "${arg}")
@@ -31,23 +41,18 @@
     endif()
   endforeach()
 
-  set(TARGET_BASE "${AUTOGENERATED_DIR}/EmbeddedResources")
   add_custom_command(
     OUTPUT
     "${TARGET_BASE}.h"
     "${TARGET_BASE}.cpp"
-    COMMAND 
-    ${PYTHON_EXECUTABLE}
-    "${ORTHANC_ROOT}/Resources/EmbedResources.py"
-    ${SCRIPT_OPTIONS}
-    "${AUTOGENERATED_DIR}/EmbeddedResources"
-    ${SCRIPT_ARGUMENTS}
+    COMMAND ${PYTHON_EXECUTABLE} ${EMBED_RESOURCES_PYTHON}
+            ${SCRIPT_OPTIONS} "${TARGET_BASE}" ${SCRIPT_ARGUMENTS}
     DEPENDS
-    "${ORTHANC_ROOT}/Resources/EmbedResources.py"
+    ${EMBED_RESOURCES_PYTHON}
     ${DEPENDENCIES}
     )
 
   list(APPEND AUTOGENERATED_SOURCES
-    "${AUTOGENERATED_DIR}/EmbeddedResources.cpp"
+    "${TARGET_BASE}.cpp"
     ) 
 endmacro()
--- a/Resources/CMake/BoostConfiguration.cmake	Wed Jun 10 10:28:01 2020 +0200
+++ b/Resources/CMake/BoostConfiguration.cmake	Wed Jun 10 10:28:15 2020 +0200
@@ -108,17 +108,29 @@
     BEFORE ${BOOST_SOURCES_DIR}
     )
 
+  if (ORTHANC_BUILDING_FRAMEWORK_LIBRARY)
+    add_definitions(
+      # Packaging Boost inside the Orthanc Framework DLL
+      -DBOOST_ALL_DYN_LINK
+      -DBOOST_THREAD_BUILD_DLL
+      #-DBOOST_REGEX_BUILD_DLL
+      )
+  else()
+    add_definitions(
+      # Static build of Boost (this was the only possibility in
+      # Orthanc <= 1.7.1)
+      -DBOOST_ALL_NO_LIB 
+      -DBOOST_ALL_NOLIB 
+      -DBOOST_DATE_TIME_NO_LIB 
+      -DBOOST_THREAD_BUILD_LIB
+      -DBOOST_PROGRAM_OPTIONS_NO_LIB
+      -DBOOST_REGEX_NO_LIB
+      -DBOOST_SYSTEM_NO_LIB
+      -DBOOST_LOCALE_NO_LIB
+      )
+  endif()
+
   add_definitions(
-    # Static build of Boost
-    -DBOOST_ALL_NO_LIB 
-    -DBOOST_ALL_NOLIB 
-    -DBOOST_DATE_TIME_NO_LIB 
-    -DBOOST_THREAD_BUILD_LIB
-    -DBOOST_PROGRAM_OPTIONS_NO_LIB
-    -DBOOST_REGEX_NO_LIB
-    -DBOOST_SYSTEM_NO_LIB
-    -DBOOST_LOCALE_NO_LIB
-
     # In static builds, explicitly prevent Boost from using the system
     # locale in lexical casts. This is notably important if
     # "boost::lexical_cast<double>()" is applied to strings containing
--- a/Resources/CMake/DcmtkConfigurationStatic-3.6.0.cmake	Wed Jun 10 10:28:01 2020 +0200
+++ b/Resources/CMake/DcmtkConfigurationStatic-3.6.0.cmake	Wed Jun 10 10:28:15 2020 +0200
@@ -173,9 +173,3 @@
     endif()
   endif()
 endif()
-
-
-list(REMOVE_ITEM DCMTK_SOURCES 
-  ${DCMTK_SOURCES_DIR}/dcmdata/libsrc/mkdictbi.cc
-  ${DCMTK_SOURCES_DIR}/dcmdata/libsrc/mkdeftag.cc
-  )
--- a/Resources/CMake/DcmtkConfigurationStatic-3.6.4.cmake	Wed Jun 10 10:28:01 2020 +0200
+++ b/Resources/CMake/DcmtkConfigurationStatic-3.6.4.cmake	Wed Jun 10 10:28:15 2020 +0200
@@ -166,12 +166,6 @@
 endif()
 
 
-list(REMOVE_ITEM DCMTK_SOURCES 
-  ${DCMTK_SOURCES_DIR}/dcmdata/libsrc/mkdictbi.cc
-  ${DCMTK_SOURCES_DIR}/dcmdata/libsrc/mkdeftag.cc
-  )
-
-
 # Starting with DCMTK 3.6.2, the Nagle algorithm is not disabled by
 # default since this does not seem to be appropriate (anymore) for
 # most modern operating systems. In order to change this default, the
--- a/Resources/CMake/DcmtkConfigurationStatic-3.6.5.cmake	Wed Jun 10 10:28:01 2020 +0200
+++ b/Resources/CMake/DcmtkConfigurationStatic-3.6.5.cmake	Wed Jun 10 10:28:15 2020 +0200
@@ -166,12 +166,6 @@
 endif()
 
 
-list(REMOVE_ITEM DCMTK_SOURCES 
-  ${DCMTK_SOURCES_DIR}/dcmdata/libsrc/mkdictbi.cc
-  ${DCMTK_SOURCES_DIR}/dcmdata/libsrc/mkdeftag.cc
-  )
-
-
 # Starting with DCMTK 3.6.2, the Nagle algorithm is not disabled by
 # default since this does not seem to be appropriate (anymore) for
 # most modern operating systems. In order to change this default, the
--- a/Resources/CMake/OrthancFrameworkConfiguration.cmake	Wed Jun 10 10:28:01 2020 +0200
+++ b/Resources/CMake/OrthancFrameworkConfiguration.cmake	Wed Jun 10 10:28:15 2020 +0200
@@ -137,6 +137,7 @@
   ${ORTHANC_ROOT}/Core/HttpServer/MultipartStreamReader.cpp
   ${ORTHANC_ROOT}/Core/HttpServer/StringMatcher.cpp
   ${ORTHANC_ROOT}/Core/Logging.cpp
+  ${ORTHANC_ROOT}/Core/OrthancFramework.cpp
   ${ORTHANC_ROOT}/Core/SerializationToolbox.cpp
   ${ORTHANC_ROOT}/Core/Toolbox.cpp
   ${ORTHANC_ROOT}/Core/WebServiceParameters.cpp
@@ -541,6 +542,13 @@
   )
 
 
+if (ORTHANC_BUILDING_FRAMEWORK_LIBRARY)
+  add_definitions(-DORTHANC_BUILDING_FRAMEWORK_LIBRARY=1)
+else()
+  add_definitions(-DORTHANC_BUILDING_FRAMEWORK_LIBRARY=0)
+endif()
+
+
 if (ORTHANC_SANDBOXED)
   add_definitions(
     -DORTHANC_SANDBOXED=1
@@ -596,36 +604,6 @@
   add_definitions(-DORTHANC_ENABLE_LOGGING_STDIO=0)
 endif()
 
-      
-if (HAS_EMBEDDED_RESOURCES)
-  add_definitions(-DORTHANC_HAS_EMBEDDED_RESOURCES=1)
-
-  if (ENABLE_WEB_SERVER)
-    list(APPEND ORTHANC_CORE_SOURCES_INTERNAL
-      ${ORTHANC_ROOT}/Core/HttpServer/EmbeddedResourceHttpHandler.cpp
-      )
-  endif()
-
-elseif (STANDALONE_BUILD)
-  # No embedded resources are provided by the external project, but
-  # some are required by the Orthanc framework (DCMTK and ICU)
-  add_definitions(-DORTHANC_HAS_EMBEDDED_RESOURCES=1)
-
-  EmbedResources(
-    ${DCMTK_DICTIONARIES}
-    ${LIBICU_RESOURCES}
-    )
-
-  list(APPEND ORTHANC_DICOM_SOURCES_DEPENDENCIES
-    ${AUTOGENERATED_SOURCES}
-    )
-  
-else()
-  # Neither the external project, nor the Orthanc framework have to
-  # embed external resources
-  add_definitions(-DORTHANC_HAS_EMBEDDED_RESOURCES=0)
-endif()
-
 
 
 #####################################################################
@@ -698,6 +676,15 @@
 endif()
 
 
+EmbedResources(
+  --namespace=Orthanc.FrameworkResources
+  --target=OrthancFrameworkResources
+  --framework-path=${ORTHANC_ROOT}/Core
+  ${LIBICU_RESOURCES}
+  ${DCMTK_DICTIONARIES}
+  )
+
+
 set(ORTHANC_CORE_SOURCES
   ${ORTHANC_CORE_SOURCES_INTERNAL}
   ${ORTHANC_CORE_SOURCES_DEPENDENCIES}
--- a/Resources/CMake/OrthancFrameworkParameters.cmake	Wed Jun 10 10:28:01 2020 +0200
+++ b/Resources/CMake/OrthancFrameworkParameters.cmake	Wed Jun 10 10:28:15 2020 +0200
@@ -27,7 +27,6 @@
 # Support of static compilation
 set(ALLOW_DOWNLOADS OFF CACHE BOOL "Allow CMake to download packages")
 set(STATIC_BUILD OFF CACHE BOOL "Static build of the third-party libraries (necessary for Windows)")
-set(STANDALONE_BUILD ON CACHE BOOL "Standalone build (all the resources are embedded, necessary for releases)")
 
 # Generic parameters of the build
 set(ENABLE_CIVETWEB ON CACHE BOOL "Use Civetweb instead of Mongoose (Mongoose was the default embedded HTTP server in Orthanc <= 1.5.1)")
@@ -106,12 +105,11 @@
 set(ENABLE_DCMTK_TRANSCODING OFF CACHE INTERNAL "Enable DICOM transcoding in DCMTK")
 set(ENABLE_OPENSSL_ENGINES OFF CACHE INTERNAL "Enable support of engines in OpenSSL")
 
-set(HAS_EMBEDDED_RESOURCES OFF CACHE INTERNAL
-  "Whether resources are auto-generated using EmbedResources.py")
-
 set(ORTHANC_SANDBOXED OFF CACHE INTERNAL
   "Whether Orthanc runs inside a sandboxed environment (such as Google NaCl or WebAssembly)")
 
+set(ORTHANC_BUILDING_FRAMEWORK_LIBRARY OFF CACHE INTERNAL
+  "Whether we are in the process of building the Orthanc Framework shared library")
 
 #
 # These options can be used to turn off some modules of the Orthanc
--- a/Resources/EmbedResources.py	Wed Jun 10 10:28:01 2020 +0200
+++ b/Resources/EmbedResources.py	Wed Jun 10 10:28:15 2020 +0200
@@ -42,7 +42,8 @@
 EXCEPTION_CLASS = 'OrthancException'
 OUT_OF_RANGE_EXCEPTION = '::Orthanc::OrthancException(::Orthanc::ErrorCode_ParameterOutOfRange)'
 INEXISTENT_PATH_EXCEPTION = '::Orthanc::OrthancException(::Orthanc::ErrorCode_InexistentItem)'
-NAMESPACE = 'Orthanc'
+NAMESPACE = 'Orthanc.EmbeddedResources'
+FRAMEWORK_PATH = None
 
 ARGS = []
 for i in range(len(sys.argv)):
@@ -57,6 +58,8 @@
         INEXISTENT_PATH_EXCEPTION = '%s("Unknown path in a directory resource")' % EXCEPTION_CLASS
     elif sys.argv[i].startswith('--namespace='):
         NAMESPACE = sys.argv[i][sys.argv[i].find('=') + 1 : ]
+    elif sys.argv[i].startswith('--framework-path='):
+        FRAMEWORK_PATH = sys.argv[i][sys.argv[i].find('=') + 1 : ]
 
 if len(ARGS) < 2 or len(ARGS) % 2 != 0:
     print ('Usage:')
@@ -166,13 +169,17 @@
 #  pragma warning(disable: 4065)  // "Switch statement contains 'default' but no 'case' labels"
 #endif
 
-namespace %s
-{
-  namespace EmbeddedResources
-  {
+""")
+
+
+for ns in NAMESPACE.split('.'):
+    header.write('namespace %s {\n' % ns)
+    
+
+header.write("""
     enum FileResourceId
     {
-""" % NAMESPACE)
+""")
 
 isFirst = True
 for name in resources:
@@ -211,9 +218,13 @@
     void GetDirectoryResource(std::string& result, DirectoryResourceId id, const char* path);
 
     void ListResources(std::list<std::string>& result, DirectoryResourceId id);
-  }
-}
+
 """)
+
+
+for ns in NAMESPACE.split('.'):
+    header.write('}\n')
+
 header.close()
 
 
@@ -272,18 +283,19 @@
 
 if USE_SYSTEM_EXCEPTION:
     cpp.write('#include <stdexcept>')
+elif FRAMEWORK_PATH != None:
+    cpp.write('#include "%s/OrthancException.h"' % FRAMEWORK_PATH)
 else:
-    cpp.write('#include "%s/Core/OrthancException.h"' % os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
+    cpp.write('#include <OrthancException.h>')
 
 cpp.write("""
 #include <stdint.h>
 #include <string.h>
 
-namespace %s
-{
-  namespace EmbeddedResources
-  {
-""" % NAMESPACE)
+""")
+
+for ns in NAMESPACE.split('.'):
+    cpp.write('namespace %s {\n' % ns)
 
 
 for name in resources:
@@ -434,7 +446,10 @@
       if (size > 0)
         memcpy(&result[0], GetDirectoryResourceBuffer(id, path), size);
     }
-  }
-}
 """)
+
+
+for ns in NAMESPACE.split('.'):
+    cpp.write('}\n')
+
 cpp.close()
--- a/UnitTestsSources/LuaTests.cpp	Wed Jun 10 10:28:01 2020 +0200
+++ b/UnitTestsSources/LuaTests.cpp	Wed Jun 10 10:28:15 2020 +0200
@@ -42,6 +42,8 @@
 #include "../Core/Toolbox.h"
 #include "../Core/Lua/LuaFunctionCall.h"
 
+#include <OrthancServerResources.h>
+
 #include <boost/lexical_cast.hpp>
 
 #if !defined(UNIT_TESTS_WITH_HTTP_CONNEXIONS)
@@ -54,9 +56,13 @@
   Orthanc::LuaContext lua;
 
 #if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK != 1
-  lua.Execute(Orthanc::EmbeddedResources::LUA_TOOLBOX);
+  {
+    std::string command;
+    Orthanc::ServerResources::GetFileResource(command, Orthanc::ServerResources::LUA_TOOLBOX);
+    lua.Execute(command);
+  }
 #endif
-  
+
   lua.Execute("a={}");
   lua.Execute("a['x'] = 10");
   lua.Execute("a['y'] = {}");
@@ -131,7 +137,12 @@
 TEST(Lua, Simple)
 {
   Orthanc::LuaContext lua;
-  lua.Execute(Orthanc::EmbeddedResources::LUA_TOOLBOX);
+
+  {
+    std::string command;
+    Orthanc::ServerResources::GetFileResource(command, Orthanc::ServerResources::LUA_TOOLBOX);
+    lua.Execute(command);
+  }
 
   {
     Orthanc::LuaFunctionCall f(lua, "PrintRecursive");
--- a/UnitTestsSources/VersionsTests.cpp	Wed Jun 10 10:28:01 2020 +0200
+++ b/UnitTestsSources/VersionsTests.cpp	Wed Jun 10 10:28:15 2020 +0200
@@ -31,10 +31,6 @@
  **/
 
 
-#if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK == 1
-#  include <OrthancFramework.h>
-#endif
-
 #include "PrecompiledHeadersUnitTests.h"
 #include "gtest/gtest.h"