highgui: win32ui plugin
authorAlexander Alekhin <alexander.a.alekhin@gmail.com>
Sat, 19 Jun 2021 09:16:23 +0000 (09:16 +0000)
committerAlexander Alekhin <alexander.a.alekhin@gmail.com>
Sat, 19 Jun 2021 13:15:46 +0000 (13:15 +0000)
13 files changed:
cmake/OpenCVFindLibsGUI.cmake
cmake/templates/cvconfig.h.in
modules/highgui/CMakeLists.txt
modules/highgui/cmake/detect_win32ui.cmake [new file with mode: 0644]
modules/highgui/cmake/init.cmake
modules/highgui/src/backend.hpp
modules/highgui/src/precomp.hpp
modules/highgui/src/registry.impl.hpp
modules/highgui/src/window.cpp
modules/highgui/src/window_QT.cpp
modules/highgui/src/window_cocoa.mm
modules/highgui/src/window_gtk.cpp
modules/highgui/src/window_w32.cpp

index 8030e8b0c0fca4a4ef9004bdf04d1e566a282c88..c8ec55b58864f032a2401af5a9e192cb11505801 100644 (file)
@@ -2,15 +2,6 @@
 #  Detect 3rd-party GUI libraries
 # ----------------------------------------------------------------------------
 
-#--- Win32 UI ---
-ocv_clear_vars(HAVE_WIN32UI)
-if(WITH_WIN32UI)
-  try_compile(HAVE_WIN32UI
-    "${OpenCV_BINARY_DIR}"
-    "${OpenCV_SOURCE_DIR}/cmake/checks/win32uitest.cpp"
-    CMAKE_FLAGS "-DLINK_LIBRARIES:STRING=user32;gdi32")
-endif()
-
 # --- QT4/5 ---
 ocv_clear_vars(HAVE_QT HAVE_QT5)
 if(WITH_QT)
index e79e1ec0a1bc93d7e00732ef3bcd58acb38f6bd8..6439d8b43f067979324248d31f8432d1e8a42fe6 100644 (file)
 /* TIFF codec */
 #cmakedefine HAVE_TIFF
 
-/* Win32 UI */
-#cmakedefine HAVE_WIN32UI
-
 /* Define if your processor stores words with the most significant byte
    first (like Motorola and SPARC, unlike Intel and VAX). */
 #cmakedefine WORDS_BIGENDIAN
index b4d4b9f50384715caeb6001206195f2253038e0c..5eb9f5ab5e6ba411747fc4f83e3d9051bf45821b 100644 (file)
@@ -131,12 +131,6 @@ elseif(WINRT)
     message(STATUS "  ${name}:   Removing 'comctl32.lib, gdi32.lib, ole32.lib, setupapi.lib'")
     message(STATUS "  ${name}:   Leaving '${HIGHGUI_LIBRARIES}'")
   endif()
-elseif(HAVE_WIN32UI)
-  set(OPENCV_HIGHGUI_BUILTIN_BACKEND "WIN32UI")
-  list(APPEND highgui_srcs ${CMAKE_CURRENT_LIST_DIR}/src/window_w32.cpp)
-  if(OpenCV_ARCH STREQUAL "ARM64")
-    list(APPEND HIGHGUI_LIBRARIES "comdlg32" "advapi32")
-  endif()
 elseif(HAVE_COCOA)
   set(OPENCV_HIGHGUI_BUILTIN_BACKEND "COCOA")
   add_definitions(-DHAVE_COCOA)
@@ -144,6 +138,16 @@ elseif(HAVE_COCOA)
   list(APPEND HIGHGUI_LIBRARIES "-framework Cocoa")
 endif()
 
+if(TARGET ocv.3rdparty.win32ui)
+  if("win32ui" IN_LIST HIGHGUI_PLUGIN_LIST OR HIGHGUI_PLUGIN_LIST STREQUAL "all")
+    ocv_create_builtin_highgui_plugin(opencv_highgui_win32 ocv.3rdparty.win32ui "window_w32.cpp")
+  else()
+    set(OPENCV_HIGHGUI_BUILTIN_BACKEND "WIN32UI")
+    list(APPEND highgui_srcs ${CMAKE_CURRENT_LIST_DIR}/src/window_w32.cpp)
+    list(APPEND tgts ocv.3rdparty.win32ui)
+  endif()
+endif()
+
 if(TARGET ocv.3rdparty.gtk3 OR TARGET ocv.3rdparty.gtk2)
   if(TARGET ocv.3rdparty.gtk3 AND NOT WITH_GTK_2_X)
     set(__gtk_dependency "ocv.3rdparty.gtk3")
diff --git a/modules/highgui/cmake/detect_win32ui.cmake b/modules/highgui/cmake/detect_win32ui.cmake
new file mode 100644 (file)
index 0000000..1d2fdc5
--- /dev/null
@@ -0,0 +1,17 @@
+#--- Win32 UI ---
+ocv_clear_vars(HAVE_WIN32UI)
+if(WITH_WIN32UI)
+  try_compile(HAVE_WIN32UI
+    "${CMAKE_CURRENT_BINARY_DIR}"
+    "${OpenCV_SOURCE_DIR}/cmake/checks/win32uitest.cpp"
+    CMAKE_FLAGS "-DLINK_LIBRARIES:STRING=user32;gdi32")
+  if(HAVE_WIN32UI)
+    set(__libs "user32" "gdi32")
+    if(OpenCV_ARCH STREQUAL "ARM64")
+      list(APPEND __libs "comdlg32" "advapi32")
+    endif()
+    ocv_add_external_target(win32ui "" "${__libs}" "HAVE_WIN32UI")
+  endif()
+endif()
+
+set(HAVE_WIN32UI "${HAVE_WIN32UI}" PARENT_SCOPE)  # informational
index 3b766b3758c02d0714c0c1a371d48fbbc74a5fc2..1626d254daf9e755ca3070b6a94614b04a72282e 100644 (file)
@@ -43,8 +43,7 @@ else()
 endif()
 
 add_backend("gtk" WITH_GTK)
-
-# TODO win32
+add_backend("win32ui" WITH_WIN32UI)
 # TODO cocoa
 # TODO qt
 # TODO opengl
index 14c88b238761c8f1d0a803a9a926470af0d028e7..7c32846ce4a37578a6b1eaa769e5169c69e8423c 100644 (file)
@@ -114,6 +114,10 @@ bool setUIBackend(const std::string& backendName);
 
 #ifndef BUILD_PLUGIN
 
+#ifdef HAVE_WIN32UI
+std::shared_ptr<UIBackend> createUIBackendWin32UI();
+#endif
+
 #ifdef HAVE_GTK
 std::shared_ptr<UIBackend> createUIBackendGTK();
 #endif
index 6ad5bce8b4657718af1850490e81e74d86d88286..0d26b957ad71fbbce9dbee56736899aee4c3a7cf 100644 (file)
@@ -67,7 +67,6 @@
 #include <string.h>
 #include <limits.h>
 #include <ctype.h>
-#include <assert.h>
 
 #if defined _WIN32 || defined WINCE
     #include <windows.h>
@@ -127,6 +126,13 @@ void cvSetPropTopmost_COCOA(const char* name, const bool topmost);
 double cvGetPropVsync_W32(const char* name);
 void cvSetPropVsync_W32(const char* name, const bool enabled);
 
+void setWindowTitle_W32(const cv::String& name, const cv::String& title);
+void setWindowTitle_GTK(const cv::String& name, const cv::String& title);
+void setWindowTitle_QT(const cv::String& name, const cv::String& title);
+void setWindowTitle_COCOA(const cv::String& name, const cv::String& title);
+
+int pollKey_W32();
+
 //for QT
 #if defined (HAVE_QT)
 CvRect cvGetWindowRect_QT(const char* name);
index ccf81f928002ea9af6392b1632a803290315de2b..66693f1b07e0347e5d3a63e33a187c44021b938e 100644 (file)
@@ -50,6 +50,14 @@ std::vector<BackendInfo>& getBuiltinBackendsInfo()
 #elif defined(ENABLE_PLUGINS)
         DECLARE_DYNAMIC_BACKEND("QT")
 #endif
+#endif
+
+#ifdef _WIN32
+#ifdef HAVE_WIN32UI
+        DECLARE_STATIC_BACKEND("WIN32", createUIBackendWin32UI)
+#elif defined(ENABLE_PLUGINS)
+        DECLARE_DYNAMIC_BACKEND("WIN32")
+#endif
 #endif
     };
     return g_backends;
index 56c1456a5d95935e569fedf688056843733b4c0c..d1ccd1dbc3a93eb21790be2ab001b1028cb2922d 100644 (file)
@@ -586,6 +586,46 @@ void cv::moveWindow( const String& winname, int x, int y )
 #endif
 }
 
+void cv::setWindowTitle(const String& winname, const String& title)
+{
+    CV_TRACE_FUNCTION();
+
+    {
+        cv::AutoLock lock(cv::getWindowMutex());
+        auto window = findWindow_(winname);
+        if (window)
+        {
+            return window->setTitle(title);
+        }
+    }
+
+#if defined(OPENCV_HIGHGUI_WITHOUT_BUILTIN_BACKEND) && defined(ENABLE_PLUGINS)
+    auto backend = getCurrentUIBackend();
+    if (backend)
+    {
+        CV_LOG_WARNING(NULL, "Can't find window with name: '" << winname << "'. Do nothing");
+        CV_NOT_FOUND_DEPRECATION;
+    }
+    else
+    {
+        CV_LOG_WARNING(NULL, "No UI backends available. Use OPENCV_LOG_LEVEL=DEBUG for investigation");
+    }
+    return;
+#elif defined(HAVE_WIN32UI)
+    return setWindowTitle_W32(winname, title);
+#elif defined (HAVE_GTK)
+    return setWindowTitle_GTK(winname, title);
+#elif defined (HAVE_QT)
+    return setWindowTitle_QT(winname, title);
+#elif defined (HAVE_COCOA)
+    return setWindowTitle_COCOA(winname, title);
+#else
+    CV_Error(Error::StsNotImplemented, "The function is not implemented. "
+        "Rebuild the library with Windows, GTK+ 2.x or Cocoa support. "
+        "If you are on Ubuntu or Debian, install libgtk2.0-dev and pkg-config, then re-run cmake or configure script");
+#endif
+}
+
 void cv::setWindowProperty(const String& winname, int prop_id, double prop_value)
 {
     CV_TRACE_FUNCTION();
@@ -630,9 +670,9 @@ int cv::waitKey(int delay)
     return (code != -1) ? (code & 0xff) : -1;
 }
 
-#if defined(HAVE_QT) || (defined (WINRT) && !defined (WINRT_8_0)) || \
-    !defined(HAVE_WIN32UI) && (defined(HAVE_GTK) || defined(HAVE_COCOA))
-// pollKey() fallback implementation
+/*
+ * process until queue is empty but don't wait.
+ */
 int cv::pollKey()
 {
     CV_TRACE_FUNCTION();
@@ -646,12 +686,13 @@ int cv::pollKey()
         }
     }
 
+#if defined(HAVE_WIN32UI)
+    return pollKey_W32();
+#else
     // fallback. please implement a proper polling function
     return cvWaitKey(1);
-}
-#elif defined(HAVE_WIN32UI)
-// pollKey() implemented in window_w32.cpp
 #endif
+}
 
 int cv::createTrackbar(const String& trackbarName, const String& winName,
                    int* value, int count, TrackbarCallback callback,
@@ -1203,13 +1244,6 @@ int cv::createButton(const String&, ButtonCallback, void*, int , bool )
 // version with a more capable one without a need to recompile dependent
 // applications or libraries.
 
-void cv::setWindowTitle(const String&, const String&)
-{
-    CV_Error(Error::StsNotImplemented, "The function is not implemented. "
-        "Rebuild the library with Windows, GTK+ 2.x or Cocoa support. "
-        "If you are on Ubuntu or Debian, install libgtk2.0-dev and pkg-config, then re-run cmake or configure script");
-}
-
 #define CV_NO_GUI_ERROR(funcname) \
     cv::error(cv::Error::StsError, \
     "The function is not implemented. " \
@@ -1360,11 +1394,6 @@ CV_IMPL int cvCreateButton(const char*, void (*)(int, void*), void*, int, int)
     CV_NO_GUI_ERROR("cvCreateButton");
 }
 
-int cv::pollKey()
-{
-    CV_NO_GUI_ERROR("cv::pollKey()");
-}
-
 #endif
 
 /* End of file. */
index 60d7d69a597927ddc3b4233ba9bbe94dc1ac4ac5..9899dfdcf0f1567875f08a85718baa0087749223 100644 (file)
@@ -63,6 +63,7 @@
     #endif
 #endif
 
+using namespace cv;
 
 //Static and global first
 static GuiReceiver *guiMainThread = NULL;
@@ -197,7 +198,7 @@ void cvSetPropWindow_QT(const char* name,double prop_value)
         Q_ARG(double, prop_value));
 }
 
-void cv::setWindowTitle(const String& winname, const String& title)
+void setWindowTitle_QT(const String& winname, const String& title)
 {
     if (!guiMainThread)
         CV_Error(Error::StsNullPtr, "NULL guiReceiver (please create a window)");
index 29a0278c982e100ac3579917c469d3ebe615ca2f..e8e903440675855df326c60d2b5649c2e604063e 100644 (file)
@@ -795,18 +795,18 @@ void cvSetPropTopmost_COCOA( const char* name, const bool topmost )
     __END__;
 }
 
-void cv::setWindowTitle(const String& winname, const String& title)
+void setWindowTitle_COCOA(const cv::String& winname, const cv::String& title)
 {
     CVWindow *window = cvGetWindow(winname.c_str());
 
     if (window == NULL)
     {
-        namedWindow(winname);
+        cv::namedWindow(winname);
         window = cvGetWindow(winname.c_str());
     }
 
     if (window == NULL)
-        CV_Error(Error::StsNullPtr, "NULL window");
+        CV_Error(cv::Error::StsNullPtr, "NULL window");
 
     NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
 
index efa3fbd96f56e3b59d2dc498b91a9890c9632943..8eaf98fb36121bb1fdab1fcb5437b85db09da121 100644 (file)
@@ -364,7 +364,7 @@ static void cvImageWidget_set_size(GtkWidget * widget, int max_width, int max_he
 
 
     }
-    assert( image_widget->scaled_image );
+    CV_Assert(image_widget->scaled_image);
 }
 
 static void
@@ -849,7 +849,7 @@ static bool setModeWindow_(const std::shared_ptr<CvWindow>& window, int mode)
     return false;
 }
 
-void cv::setWindowTitle(const String& winname, const String& title)
+void setWindowTitle_GTK(const String& winname, const String& title)
 {
     CV_LOCK_MUTEX();
 
index c4f2ddd2a603ea89c27efce6bdf6070d8b61fe35..d9a9d732227a08506c726b86b865c1ac2ec8fad4 100644 (file)
 
 #include "precomp.hpp"
 
+#ifdef HAVE_WIN32UI
+
+#include <opencv2/core/utils/logger.hpp>
+#include <opencv2/core/utils/trace.hpp>
+
+#include "backend.hpp"
+
 using namespace cv;
 
 #include <windowsx.h> // required for GET_X_LPARAM() and GET_Y_LPARAM() macros
 
-#if defined _WIN32
-
 #ifdef __GNUC__
 #  pragma GCC diagnostic ignored "-Wmissing-declarations"
 #endif
@@ -60,14 +65,12 @@ using namespace cv;
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
-#include <assert.h>
 
 #ifdef HAVE_OPENGL
 #include <memory>
 #include <algorithm>
 #include <vector>
 #include <functional>
-#include "opencv2/highgui.hpp"
 #include <GL/gl.h>
 #include "opencv2/core/opengl.hpp"
 #endif
@@ -78,7 +81,7 @@ static const char* trackbar_text =
 #if defined _M_X64 || defined __x86_64 || defined _M_ARM64
 
 #define icvGetWindowLongPtr GetWindowLongPtr
-#define icvSetWindowLongPtr( hwnd, id, ptr ) SetWindowLongPtr( hwnd, id, (LONG_PTR)(ptr) )
+#define icvSetWindowLongPtr(hwnd, id, ptr) SetWindowLongPtr(hwnd, id, (LONG_PTR)(ptr))
 #define icvGetClassLongPtr  GetClassLongPtr
 
 #define CV_USERDATA GWLP_USERDATA
@@ -89,7 +92,7 @@ static const char* trackbar_text =
 #else
 
 #define icvGetWindowLongPtr GetWindowLong
-#define icvSetWindowLongPtr( hwnd, id, ptr ) SetWindowLong( hwnd, id, (size_t)ptr )
+#define icvSetWindowLongPtr(hwnd, id, ptr) SetWindowLong(hwnd, id, (size_t)ptr)
 #define icvGetClassLongPtr GetClassLong
 
 #define CV_USERDATA GWL_USERDATA
@@ -116,13 +119,13 @@ static inline void mingw_strcat_s(char *dest, size_t destsz, const char *src){
 #define strcat_s mingw_strcat_s
 #endif
 
-static void FillBitmapInfo( BITMAPINFO* bmi, int width, int height, int bpp, int origin )
+static void FillBitmapInfo(BITMAPINFO* bmi, int width, int height, int bpp, int origin)
 {
-    assert( bmi && width >= 0 && height >= 0 && (bpp == 8 || bpp == 24 || bpp == 32));
+    CV_Assert(bmi && width >= 0 && height >= 0 && (bpp == 8 || bpp == 24 || bpp == 32));
 
     BITMAPINFOHEADER* bmih = &(bmi->bmiHeader);
 
-    memset( bmih, 0, sizeof(*bmih));
+    memset(bmih, 0, sizeof(*bmih));
     bmih->biSize = sizeof(BITMAPINFOHEADER);
     bmih->biWidth = width;
     bmih->biHeight = origin ? abs(height) : -abs(height);
@@ -130,11 +133,11 @@ static void FillBitmapInfo( BITMAPINFO* bmi, int width, int height, int bpp, int
     bmih->biBitCount = (unsigned short)bpp;
     bmih->biCompression = BI_RGB;
 
-    if( bpp == 8 )
+    if (bpp == 8)
     {
         RGBQUAD* palette = bmi->bmiColors;
         int i;
-        for( i = 0; i < 256; i++ )
+        for (i = 0; i < 256; i++)
         {
             palette[i].rgbBlue = palette[i].rgbGreen = palette[i].rgbRed = (BYTE)i;
             palette[i].rgbReserved = 0;
@@ -144,68 +147,91 @@ static void FillBitmapInfo( BITMAPINFO* bmi, int width, int height, int bpp, int
 
 struct CvWindow;
 
-typedef struct CvTrackbar
+struct CvTrackbar : public std::enable_shared_from_this<CvTrackbar>
 {
+    CvTrackbar(CvWindow& window, const std::string& name_)
+        : signature(CV_TRACKBAR_MAGIC_VAL)
+        , name(name_)
+        , parent(&window)
+    {
+        // nothing
+    }
+    ~CvTrackbar()
+    {
+        signature = -1;
+    }
+
     int signature;
-    HWND hwnd;
-    char* name;
-    CvTrackbar* next;
-    CvWindow* parent;
-    HWND buddy;
-    int* data;
-    int pos;
-    int maxval;
-    int minval;
-    void (*notify)(int);
-    void (*notify2)(int, void*);
-    void* userdata;
-    int id;
-}
-CvTrackbar;
+    HWND hwnd = 0;
+    std::string name;
+    CvWindow* parent;  // TODO weak_ptr
+    HWND buddy = 0;
+    int* data = nullptr;
+    int pos = 0;
+    int maxval = 0;
+    int minval = 0;
+    void (*notify)(int) = nullptr;  // deprecated
+    void (*notify2)(int, void*) = nullptr;  // deprecated
+    TrackbarCallback onChangeCallback = nullptr;
+    void* userdata = nullptr;
+    int id = -1;
+};
 
 
-typedef struct CvWindow
+struct CvWindow : public std::enable_shared_from_this<CvWindow>
 {
+    CvWindow(const std::string& name_)
+        : signature(CV_WINDOW_MAGIC_VAL)
+        , name(name_)
+    {
+        // nothing
+    }
+
+    ~CvWindow()
+    {
+        signature = -1;
+    }
+
+    void destroy();
+
     int signature;
-    HWND hwnd;
-    char* name;
-    CvWindow* prev;
-    CvWindow* next;
-    HWND frame;
+    cv::Mutex mutex;
+    HWND hwnd = 0;
+    std::string name;
+    HWND frame = 0;
 
-    HDC dc;
-    HGDIOBJ image;
-    int last_key;
-    int flags;
-    int status;//0 normal, 1 fullscreen (YV)
+    HDC dc = 0;
+    HGDIOBJ image = 0;
+    int last_key = 0;
+    int flags = 0;
+    int status = 0;//0 normal, 1 fullscreen (YV)
 
-    CvMouseCallback on_mouse;
-    void* on_mouse_param;
+    CvMouseCallback on_mouse = nullptr;
+    void* on_mouse_param = nullptr;
 
     struct
     {
-        HWND toolbar;
-        int pos;
-        int rows;
-        WNDPROC toolBarProc;
-        CvTrackbar* first;
+        HWND toolbar = 0;
+        int pos = 0;
+        int rows = 0;
+        WNDPROC toolBarProc = nullptr;
+        std::vector< std::shared_ptr<CvTrackbar> > trackbars;
     }
     toolbar;
 
-    int width;
-    int height;
+    int width = -1;
+    int height = -1;
 
     // OpenGL support
 
 #ifdef HAVE_OPENGL
-    bool useGl;
-    HGLRC hGLRC;
+    bool useGl = false;
+    HGLRC hGLRC = 0;
 
-    CvOpenGlDrawCallback glDrawCallback;
-    void* glDrawData;
+    CvOpenGlDrawCallback glDrawCallback = nullptr;
+    void* glDrawData = nullptr;
 #endif
-}
-CvWindow;
+};
 
 #define HG_BUDDY_WIDTH  130
 
@@ -221,19 +247,50 @@ CvWindow;
     #define TBM_GETTOOLTIPS  (WM_USER + 30)
 #endif
 
-static LRESULT CALLBACK HighGUIProc(  HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
-static LRESULT CALLBACK WindowProc(  HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
-static LRESULT CALLBACK MainWindowProc(  HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
-static void icvUpdateWindowPos( CvWindow* window );
+static
+std::vector< std::shared_ptr<CvWindow> >& getWindowsList()
+{
+    static std::vector< std::shared_ptr<CvWindow> > g_windows;
+    return g_windows;
+}
 
-static CvWindow* hg_windows = 0;
+
+// Mutex must be locked
+static
+std::shared_ptr<CvWindow> icvFindWindowByName(const std::string& name)
+{
+    auto& g_windows = getWindowsList();
+    for (auto it = g_windows.begin(); it != g_windows.end(); ++it)
+    {
+        auto window = *it;
+        if (!window)
+            continue;
+        if (window->name == name)
+            return window;
+    }
+    return std::shared_ptr<CvWindow>();
+}
+
+static inline
+std::shared_ptr<CvWindow> icvFindWindowByName(const char* name)
+{
+    CV_Assert(name);
+    return icvFindWindowByName(std::string(name));
+}
+
+
+
+static LRESULT CALLBACK HighGUIProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static LRESULT CALLBACK MainWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static void icvUpdateWindowPos(CvWindow& window);
 
 typedef int (CV_CDECL * CvWin32WindowCallback)(HWND, UINT, WPARAM, LPARAM, int*);
 static CvWin32WindowCallback hg_on_preprocess = 0, hg_on_postprocess = 0;
 static HINSTANCE hg_hinstance = 0;
 
-static const char* highGUIclassName = "HighGUI class";
-static const char* mainHighGUIclassName = "Main HighGUI class";
+static const char* const highGUIclassName = "HighGUI class";
+static const char* const mainHighGUIclassName = "Main HighGUI class";
 
 static void icvCleanupHighgui()
 {
@@ -242,15 +299,15 @@ static void icvCleanupHighgui()
     UnregisterClass(mainHighGUIclassName, hg_hinstance);
 }
 
-CV_IMPL int cvInitSystem( int, char** )
+CV_IMPL int cvInitSystem(int, char**)
 {
     static int wasInitialized = 0;
 
     // check initialization status
-    if( !wasInitialized )
+    if (!wasInitialized)
     {
-        // Initialize the storage
-        hg_windows = 0;
+        (void)getWindowMutex();  // force mutex initialization
+        (void)getWindowsList();  // Initialize the storage
 
         // Register the class
         WNDCLASS wndc;
@@ -262,7 +319,7 @@ CV_IMPL int cvInitSystem( int, char** )
         wndc.lpszClassName = highGUIclassName;
         wndc.lpszMenuName = highGUIclassName;
         wndc.hIcon = LoadIcon(0, IDI_APPLICATION);
-        wndc.hCursor = (HCURSOR)LoadCursor(0, (LPSTR)(size_t)IDC_CROSS );
+        wndc.hCursor = (HCURSOR)LoadCursor(0, (LPSTR)(size_t)IDC_CROSS);
         wndc.hbrBackground = (HBRUSH)GetStockObject(DKGRAY_BRUSH);
 
         RegisterClass(&wndc);
@@ -273,12 +330,12 @@ CV_IMPL int cvInitSystem( int, char** )
         wndc.lpfnWndProc = MainWindowProc;
 
         RegisterClass(&wndc);
-        atexit( icvCleanupHighgui );
+        atexit(icvCleanupHighgui);
 
         wasInitialized = 1;
     }
 
-    setlocale(LC_NUMERIC,"C");
+    setlocale(LC_NUMERIC,"C");  // FIXIT must be removed
 
     return 0;
 }
@@ -287,50 +344,58 @@ CV_IMPL int cvStartWindowThread(){
     return 0;
 }
 
-static CvWindow* icvFindWindowByName( const char* name )
-{
-    CvWindow* window = hg_windows;
-
-    for( ; window != 0 && strcmp( name, window->name) != 0; window = window->next )
-        ;
 
-    return window;
-}
-
-
-static CvWindow* icvWindowByHWND( HWND hwnd )
+static std::shared_ptr<CvWindow> icvWindowByHWND(HWND hwnd)
 {
-    CvWindow* window = (CvWindow*)icvGetWindowLongPtr( hwnd, CV_USERDATA );
-    return window != 0 && hg_windows != 0 &&
+    AutoLock lock(getWindowMutex());
+    CvWindow* window = (CvWindow*)icvGetWindowLongPtr(hwnd, CV_USERDATA);
+    window = window != 0 &&
            window->signature == CV_WINDOW_MAGIC_VAL ? window : 0;
+    if (window)
+    {
+        return window->shared_from_this();
+    }
+    else
+    {
+        return std::shared_ptr<CvWindow>();
+    }
 }
 
 
-static CvTrackbar* icvTrackbarByHWND( HWND hwnd )
+static std::shared_ptr<CvTrackbar> icvTrackbarByHWND(HWND hwnd)
 {
-    CvTrackbar* trackbar = (CvTrackbar*)icvGetWindowLongPtr( hwnd, CV_USERDATA );
-    return trackbar != 0 && trackbar->signature == CV_TRACKBAR_MAGIC_VAL &&
+    AutoLock lock(getWindowMutex());
+    CvTrackbar* trackbar = (CvTrackbar*)icvGetWindowLongPtr(hwnd, CV_USERDATA);
+    trackbar = trackbar != 0 && trackbar->signature == CV_TRACKBAR_MAGIC_VAL &&
            trackbar->hwnd == hwnd ? trackbar : 0;
+    if (trackbar)
+    {
+        return trackbar->shared_from_this();
+    }
+    else
+    {
+        return std::shared_ptr<CvTrackbar>();
+    }
 }
 
 
-static const char* icvWindowPosRootKey = "Software\\OpenCV\\HighGUI\\Windows\\";
+static const char* const icvWindowPosRootKey = "Software\\OpenCV\\HighGUI\\Windows\\";
 
 // Window positions saving/loading added by Philip Gruebele.
 //<a href="mailto:pgruebele@cox.net">pgruebele@cox.net</a>
 // Restores the window position from the registry saved position.
 static void
-icvLoadWindowPos( const char* name, CvRect& rect )
+icvLoadWindowPos(const char* name, CvRect& rect)
 {
     HKEY hkey;
     char szKey[1024];
-    strcpy_s( szKey, 1024, icvWindowPosRootKey );
-    strcat_s( szKey, 1024, name );
+    strcpy_s(szKey, 1024, icvWindowPosRootKey);
+    strcat_s(szKey, 1024, name);
 
     rect.x = rect.y = CW_USEDEFAULT;
     rect.width = rect.height = 320;
 
-    if( RegOpenKeyEx(HKEY_CURRENT_USER,szKey,0,KEY_QUERY_VALUE,&hkey) == ERROR_SUCCESS )
+    if (RegOpenKeyEx(HKEY_CURRENT_USER,szKey,0,KEY_QUERY_VALUE,&hkey) == ERROR_SUCCESS)
     {
         // Yes we are installed.
         DWORD dwType = 0;
@@ -379,16 +444,16 @@ icvLoadWindowPos( const char* name, CvRect& rect )
 //<a href="mailto:pgruebele@cox.net">pgruebele@cox.net</a>
 // philipg.  Saves the window position in the registry
 static void
-icvSaveWindowPos( const char* name, CvRect rect )
+icvSaveWindowPos(const char* name, CvRect rect)
 {
     static const DWORD MAX_RECORD_COUNT = 100;
     HKEY hkey;
     char szKey[1024];
     char rootKey[1024];
-    strcpy_s( szKey, 1024, icvWindowPosRootKey );
-    strcat_s( szKey, 1024, name );
+    strcpy_s(szKey, 1024, icvWindowPosRootKey);
+    strcat_s(szKey, 1024, name);
 
-    if( RegOpenKeyEx( HKEY_CURRENT_USER,szKey,0,KEY_READ,&hkey) != ERROR_SUCCESS )
+    if (RegOpenKeyEx(HKEY_CURRENT_USER,szKey,0,KEY_READ,&hkey) != ERROR_SUCCESS)
     {
         HKEY hroot;
         DWORD count = 0;
@@ -396,40 +461,40 @@ icvSaveWindowPos( const char* name, CvRect rect )
         char oldestKey[1024];
         char currentKey[1024];
 
-        strcpy_s( rootKey, 1024, icvWindowPosRootKey );
+        strcpy_s(rootKey, 1024, icvWindowPosRootKey);
         rootKey[strlen(rootKey)-1] = '\0';
-        if( RegCreateKeyEx(HKEY_CURRENT_USER, rootKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ+KEY_WRITE, 0, &hroot, NULL) != ERROR_SUCCESS )
-            //RegOpenKeyEx( HKEY_CURRENT_USER,rootKey,0,KEY_READ,&hroot) != ERROR_SUCCESS )
+        if (RegCreateKeyEx(HKEY_CURRENT_USER, rootKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ+KEY_WRITE, 0, &hroot, NULL) != ERROR_SUCCESS)
+            //RegOpenKeyEx(HKEY_CURRENT_USER,rootKey,0,KEY_READ,&hroot) != ERROR_SUCCESS)
             return;
 
         for(;;)
         {
             DWORD csize = sizeof(currentKey);
             FILETIME accesstime = { 0, 0 };
-            LONG code = RegEnumKeyEx( hroot, count, currentKey, &csize, NULL, NULL, NULL, &accesstime );
-            if( code != ERROR_SUCCESS && code != ERROR_MORE_DATA )
+            LONG code = RegEnumKeyEx(hroot, count, currentKey, &csize, NULL, NULL, NULL, &accesstime);
+            if (code != ERROR_SUCCESS && code != ERROR_MORE_DATA)
                 break;
             count++;
-            ifoldestTime.dwHighDateTime > accesstime.dwHighDateTime ||
+            if (oldestTime.dwHighDateTime > accesstime.dwHighDateTime ||
                 (oldestTime.dwHighDateTime == accesstime.dwHighDateTime &&
-                oldestTime.dwLowDateTime > accesstime.dwLowDateTime) )
+                oldestTime.dwLowDateTime > accesstime.dwLowDateTime))
             {
                 oldestTime = accesstime;
-                strcpy_s( oldestKey, 1024, currentKey );
+                strcpy_s(oldestKey, 1024, currentKey);
             }
         }
 
-        if( count >= MAX_RECORD_COUNT )
-            RegDeleteKey( hroot, oldestKey );
-        RegCloseKey( hroot );
+        if (count >= MAX_RECORD_COUNT)
+            RegDeleteKey(hroot, oldestKey);
+        RegCloseKey(hroot);
 
-        if( RegCreateKeyEx(HKEY_CURRENT_USER,szKey,0,NULL,REG_OPTION_NON_VOLATILE, KEY_WRITE, 0, &hkey, NULL) != ERROR_SUCCESS )
+        if (RegCreateKeyEx(HKEY_CURRENT_USER,szKey,0,NULL,REG_OPTION_NON_VOLATILE, KEY_WRITE, 0, &hkey, NULL) != ERROR_SUCCESS)
             return;
     }
     else
     {
-        RegCloseKey( hkey );
-        if( RegOpenKeyEx( HKEY_CURRENT_USER,szKey,0,KEY_WRITE,&hkey) != ERROR_SUCCESS )
+        RegCloseKey(hkey);
+        if (RegOpenKeyEx(HKEY_CURRENT_USER,szKey,0,KEY_WRITE,&hkey) != ERROR_SUCCESS)
             return;
     }
 
@@ -440,96 +505,101 @@ icvSaveWindowPos( const char* name, CvRect rect )
     RegCloseKey(hkey);
 }
 
+static Rect getImageRect_(CvWindow& window);
+
 CvRect cvGetWindowRect_W32(const char* name)
 {
-    RECT rect = { 0 };
-    CvRect result = cvRect(-1, -1, -1, -1);
-
-    CV_FUNCNAME( "cvGetWindowRect_W32" );
+    CV_FUNCNAME("cvGetWindowRect_W32");
 
-    __BEGIN__;
-
-    CvWindow* window;
+    AutoLock lock(getWindowMutex());
 
     if (!name)
-        CV_ERROR( CV_StsNullPtr, "NULL name string" );
-    window = icvFindWindowByName( name );
+        CV_Error(Error::StsNullPtr, "NULL name string");
+
+    auto window = icvFindWindowByName(name);
     if (!window)
-        EXIT; // keep silence here
+        CV_Error_(Error::StsNullPtr, ("NULL window: '%s'", name));
 
-    GetClientRect(window->hwnd, &rect);
-    {
+    Rect r = getImageRect_(*window);
+
+    CvRect result = cvRect(r.x, r.y, r.width, r.height);
+    return result;
+}
+
+static Rect getImageRect_(CvWindow& window)
+{
+    RECT rect = { 0 };
+    GetClientRect(window.hwnd, &rect);
     POINT pt = {rect.left, rect.top};
-    ClientToScreen(window->hwnd, &pt);
-    result = cvRect(pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top);
-    }
-    __END__;
+    ClientToScreen(window.hwnd, &pt);
+    Rect result(pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top);
     return result;
 }
 
 double cvGetModeWindow_W32(const char* name)//YV
 {
-    double result = -1;
-
-    CV_FUNCNAME( "cvGetModeWindow_W32" );
-
-    __BEGIN__;
+    CV_FUNCNAME("cvGetModeWindow_W32");
 
-    CvWindow* window;
+    AutoLock lock(getWindowMutex());
 
     if (!name)
-        CV_ERROR( CV_StsNullPtr, "NULL name string" );
+        CV_Error(Error::StsNullPtr, "NULL name string");
 
-    window = icvFindWindowByName( name );
+    auto window = icvFindWindowByName(name);
     if (!window)
-        EXIT; // keep silence here
+        CV_Error_(Error::StsNullPtr, ("NULL window: '%s'", name));
 
-    result = window->status;
-
-    __END__;
-    return result;
+    return window->status;
 }
 
-void cvSetModeWindow_W32( const char* name, double prop_value)//Yannick Verdie
+static bool setModeWindow_(CvWindow& window, int mode);
+
+void cvSetModeWindow_W32(const char* name, double prop_value)//Yannick Verdie
 {
-    CV_FUNCNAME( "cvSetModeWindow_W32" );
+    CV_FUNCNAME("cvSetModeWindow_W32");
 
-    __BEGIN__;
+    AutoLock lock(getWindowMutex());
 
-    CvWindow* window;
+    if (!name)
+        CV_Error(Error::StsNullPtr, "NULL name string");
 
-    if(!name)
-        CV_ERROR( CV_StsNullPtr, "NULL name string" );
+    auto window = icvFindWindowByName(name);
+    if (!window)
+         CV_Error_(Error::StsNullPtr, ("NULL window: '%s'", name));
 
-    window = icvFindWindowByName( name );
-    if( !window )
-        CV_ERROR( CV_StsNullPtr, "NULL window" );
+    (void)setModeWindow_(*window, (int)prop_value);
+}
 
-    if(window->flags & CV_WINDOW_AUTOSIZE)//if the flag CV_WINDOW_AUTOSIZE is set
-        EXIT;
+static bool setModeWindow_(CvWindow& window, int mode)
+{
+    if (window.flags & CV_WINDOW_AUTOSIZE)//if the flag CV_WINDOW_AUTOSIZE is set
+        return false;
+
+    if (window.status == mode)
+        return true;
 
     {
-        DWORD dwStyle = (DWORD)GetWindowLongPtr(window->frame, GWL_STYLE);
+        DWORD dwStyle = (DWORD)GetWindowLongPtr(window.frame, GWL_STYLE);
         CvRect position;
 
-        if (window->status==CV_WINDOW_FULLSCREEN && prop_value==CV_WINDOW_NORMAL)
+        if (window.status == CV_WINDOW_FULLSCREEN && mode == CV_WINDOW_NORMAL)
         {
-            icvLoadWindowPos(window->name,position );
-            SetWindowLongPtr(window->frame, GWL_STYLE, dwStyle | WS_CAPTION | WS_THICKFRAME);
+            icvLoadWindowPos(window.name.c_str(), position);
+            SetWindowLongPtr(window.frame, GWL_STYLE, dwStyle | WS_CAPTION | WS_THICKFRAME);
 
-            SetWindowPos(window->frame, HWND_TOP, position.x, position.y , position.width,position.height, SWP_NOZORDER | SWP_FRAMECHANGED);
-            window->status=CV_WINDOW_NORMAL;
+            SetWindowPos(window.frame, HWND_TOP, position.x, position.y , position.width,position.height, SWP_NOZORDER | SWP_FRAMECHANGED);
+            window.status=CV_WINDOW_NORMAL;
 
-            EXIT;
+            return true;
         }
 
-        if (window->status==CV_WINDOW_NORMAL && prop_value==CV_WINDOW_FULLSCREEN)
+        if (window.status == CV_WINDOW_NORMAL && mode == CV_WINDOW_FULLSCREEN)
         {
             //save dimension
             RECT rect = { 0 };
-            GetWindowRect(window->frame, &rect);
-            CvRect RectCV = cvRect(rect.left, rect.top,rect.right - rect.left, rect.bottom - rect.top);
-            icvSaveWindowPos(window->name,RectCV );
+            GetWindowRect(window.frame, &rect);
+            CvRect rectCV = cvRect(rect.left, rect.top,rect.right - rect.left, rect.bottom - rect.top);
+            icvSaveWindowPos(window.name.c_str(), rectCV);
 
             //Look at coordinate for fullscreen
             HMONITOR hMonitor;
@@ -542,60 +612,75 @@ void cvSetModeWindow_W32( const char* name, double prop_value)//Yannick Verdie
             //fullscreen
             position.x=mi.rcMonitor.left;position.y=mi.rcMonitor.top;
             position.width=mi.rcMonitor.right - mi.rcMonitor.left;position.height=mi.rcMonitor.bottom - mi.rcMonitor.top;
-            SetWindowLongPtr(window->frame, GWL_STYLE, dwStyle & ~WS_CAPTION & ~WS_THICKFRAME);
+            SetWindowLongPtr(window.frame, GWL_STYLE, dwStyle & ~WS_CAPTION & ~WS_THICKFRAME);
 
-            SetWindowPos(window->frame, HWND_TOP, position.x, position.y , position.width,position.height, SWP_NOZORDER | SWP_FRAMECHANGED);
-            window->status=CV_WINDOW_FULLSCREEN;
+            SetWindowPos(window.frame, HWND_TOP, position.x, position.y , position.width,position.height, SWP_NOZORDER | SWP_FRAMECHANGED);
+            window.status=CV_WINDOW_FULLSCREEN;
 
-            EXIT;
+            return true;
         }
     }
 
-    __END__;
+    return false;
 }
 
+static double getPropTopmost_(CvWindow& window);
+
 double cvGetPropTopmost_W32(const char* name)
 {
-    double result = -1;
-
     CV_Assert(name);
 
-    CvWindow* window = icvFindWindowByName(name);
+    auto window = icvFindWindowByName(name);
     if (!window)
         CV_Error(Error::StsNullPtr, "NULL window");
 
-    LONG style = GetWindowLongA(window->frame, GWL_EXSTYLE); // -20
+    return getPropTopmost_(*window);
+}
+
+static double getPropTopmost_(CvWindow& window)
+{
+    LONG style = GetWindowLongA(window.frame, GWL_EXSTYLE); // -20
     if (!style)
     {
         std::ostringstream errorMsg;
-        errorMsg << "window(" << name << "): failed to retrieve extended window style using GetWindowLongA(); error code: " << GetLastError();
-        CV_Error(Error::StsError, errorMsg.str().c_str());
+        errorMsg << "window(" << window.name << "): failed to retrieve extended window style using GetWindowLongA(); error code: " << GetLastError();
+        CV_Error(Error::StsError, errorMsg.str());
     }
 
-    result = (style & WS_EX_TOPMOST) == WS_EX_TOPMOST;
-
-    return result;
+    bool result = (style & WS_EX_TOPMOST) == WS_EX_TOPMOST;
+    return result ? 1.0 : 0.0;
 }
 
+static bool setPropTopmost_(CvWindow& window, bool topmost);
+
 void cvSetPropTopmost_W32(const char* name, const bool topmost)
 {
     CV_Assert(name);
 
-    CvWindow* window = icvFindWindowByName(name);
+    auto window = icvFindWindowByName(name);
     if (!window)
         CV_Error(Error::StsNullPtr, "NULL window");
 
+    (void)setPropTopmost_(*window, topmost);
+}
+
+static bool setPropTopmost_(CvWindow& window, bool topmost)
+{
     HWND flag    = topmost ? HWND_TOPMOST : HWND_TOP;
-    BOOL success = SetWindowPos(window->frame, flag, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+    BOOL success = SetWindowPos(window.frame, flag, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
 
     if (!success)
     {
         std::ostringstream errorMsg;
-        errorMsg << "window(" << name << "): error reported by SetWindowPos(" << (topmost ? "HWND_TOPMOST" : "HWND_TOP") << "), error code:  " << GetLastError();
-        CV_Error(Error::StsError, errorMsg.str().c_str());
+        errorMsg << "window(" << window.name << "): error reported by SetWindowPos(" << (topmost ? "HWND_TOPMOST" : "HWND_TOP") << "), error code:  " << GetLastError();
+        CV_Error(Error::StsError, errorMsg.str());
+        return false;
     }
+    return true;
 }
 
+static double getPropVsync_(CvWindow& window);
+
 double cvGetPropVsync_W32(const char* name)
 {
 #ifndef HAVE_OPENGL
@@ -605,40 +690,53 @@ double cvGetPropVsync_W32(const char* name)
     if (!name)
         CV_Error(Error::StsNullPtr, "'name' argument must not be NULL");
 
-    CvWindow* window = icvFindWindowByName(name);
+    auto window = icvFindWindowByName(name);
     if (!window)
         CV_Error_(Error::StsBadArg, ("there is no window named '%s'", name));
 
+    double result = getPropVsync_(*window);
+    return cvIsNaN(result) ? -1.0 : result;
+#endif
+}
+
+static double getPropVsync_(CvWindow& window)
+{
+#ifndef HAVE_OPENGL
+    CV_UNUSED(window);
+    CV_Error(Error::OpenGlNotSupported, "Library was built without OpenGL support");
+#else
     // https://www.khronos.org/opengl/wiki/Swap_Interval
     // https://www.khronos.org/registry/OpenGL/extensions/EXT/WGL_EXT_extensions_string.txt
     // https://www.khronos.org/registry/OpenGL/extensions/EXT/WGL_EXT_swap_control.txt
 
-    if (!wglMakeCurrent(window->dc, window->hGLRC))
+    if (!wglMakeCurrent(window.dc, window.hGLRC))
         CV_Error(Error::OpenGlApiCallError, "Can't Activate The GL Rendering Context");
 
     typedef const char* (APIENTRY* PFNWGLGETEXTENSIONSSTRINGEXTPROC)(void);
     PFNWGLGETEXTENSIONSSTRINGEXTPROC wglGetExtensionsString = NULL;
     wglGetExtensionsString = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)wglGetProcAddress("wglGetExtensionsStringEXT");
     if (wglGetExtensionsString == NULL)
-        return -1; // wglGetProcAddress failed to get wglGetExtensionsStringEXT
+        return std::numeric_limits<double>::quiet_NaN(); // wglGetProcAddress failed to get wglGetExtensionsStringEXT
 
     const char* wgl_extensions = wglGetExtensionsString();
     if (wgl_extensions == NULL)
-        return -1; // Can't get WGL extensions string
+        return std::numeric_limits<double>::quiet_NaN(); // Can't get WGL extensions string
 
     if (strstr(wgl_extensions, "WGL_EXT_swap_control") == NULL)
-        return -1; // WGL extensions don't contain WGL_EXT_swap_control
+        return std::numeric_limits<double>::quiet_NaN(); // WGL extensions don't contain WGL_EXT_swap_control
 
     typedef int (APIENTRY* PFNWGLGETSWAPINTERVALPROC)(void);
     PFNWGLGETSWAPINTERVALPROC wglGetSwapInterval = 0;
     wglGetSwapInterval = (PFNWGLGETSWAPINTERVALPROC)wglGetProcAddress("wglGetSwapIntervalEXT");
     if (wglGetSwapInterval == NULL)
-        return -1; // wglGetProcAddress failed to get wglGetSwapIntervalEXT
+        return std::numeric_limits<double>::quiet_NaN(); // wglGetProcAddress failed to get wglGetSwapIntervalEXT
 
     return wglGetSwapInterval();
 #endif
 }
 
+static bool setPropVsync_(CvWindow& window, bool enable_vsync);
+
 void cvSetPropVsync_W32(const char* name, const bool enable_vsync)
 {
 #ifndef HAVE_OPENGL
@@ -649,11 +747,22 @@ void cvSetPropVsync_W32(const char* name, const bool enable_vsync)
     if (!name)
         CV_Error(Error::StsNullPtr, "'name' argument must not be NULL");
 
-    CvWindow* window = icvFindWindowByName(name);
+    auto window = icvFindWindowByName(name);
     if (!window)
         CV_Error_(Error::StsBadArg, ("there is no window named '%s'", name));
 
-    if (!wglMakeCurrent(window->dc, window->hGLRC))
+    (void)setPropVsync_(*window, enable_vsync);
+#endif
+}
+
+static bool setPropVsync_(CvWindow& window, bool enable_vsync)
+{
+#ifndef HAVE_OPENGL
+    CV_UNUSED(window);
+    CV_UNUSED(enable_vsync);
+    CV_Error(Error::OpenGlNotSupported, "Library was built without OpenGL support");
+#else
+    if (!wglMakeCurrent(window.dc, window.hGLRC))
         CV_Error(Error::OpenGlApiCallError, "Can't Activate The GL Rendering Context");
 
     typedef const char* (APIENTRY* PFNWGLGETEXTENSIONSSTRINGEXTPROC)(void);
@@ -676,47 +785,44 @@ void cvSetPropVsync_W32(const char* name, const bool enable_vsync)
         CV_Error(Error::OpenGlApiCallError, "wglGetProcAddress failed to get wglSwapIntervalEXT");
 
     wglSwapInterval(enable_vsync);
+    return true;
 #endif
 }
 
-void cv::setWindowTitle(const String& winname, const String& title)
+void setWindowTitle_W32(const std::string& name, const std::string& title)
 {
-    CvWindow* window = icvFindWindowByName(winname.c_str());
+    auto window = icvFindWindowByName(name);
 
     if (!window)
     {
-        namedWindow(winname);
-        window = icvFindWindowByName(winname.c_str());
+        namedWindow(name);
+        window = icvFindWindowByName(name);
     }
 
     if (!window)
         CV_Error(Error::StsNullPtr, "NULL window");
 
     if (!SetWindowText(window->frame, title.c_str()))
-        CV_Error_(Error::StsError, ("Failed to set \"%s\" window title to \"%s\"", winname.c_str(), title.c_str()));
+        CV_Error_(Error::StsError, ("Failed to set \"%s\" window title to \"%s\"", name.c_str(), title.c_str()));
 }
 
 double cvGetPropWindowAutoSize_W32(const char* name)
 {
     double result = -1;
 
-    CV_FUNCNAME( "cvSetCloseCallback" );
+    CV_FUNCNAME("cvSetCloseCallback");
 
-    __BEGIN__;
-
-    CvWindow* window;
+    AutoLock lock(getWindowMutex());
 
     if (!name)
-        CV_ERROR( CV_StsNullPtr, "NULL name string" );
+        CV_Error(Error::StsNullPtr, "NULL name string");
 
-    window = icvFindWindowByName( name );
+    auto window = icvFindWindowByName(name);
     if (!window)
-        EXIT; // keep silence here
+        CV_Error_(Error::StsNullPtr, ("NULL window: '%s'", name));
 
     result = window->flags & CV_WINDOW_AUTOSIZE;
 
-    __END__;
-
     return result;
 }
 
@@ -724,23 +830,19 @@ double cvGetRatioWindow_W32(const char* name)
 {
     double result = -1;
 
-    CV_FUNCNAME( "cvGetRatioWindow_W32" );
+    CV_FUNCNAME("cvGetRatioWindow_W32");
 
-    __BEGIN__;
-
-    CvWindow* window;
+    AutoLock lock(getWindowMutex());
 
     if (!name)
-        CV_ERROR( CV_StsNullPtr, "NULL name string" );
+        CV_Error(Error::StsNullPtr, "NULL name string");
 
-    window = icvFindWindowByName( name );
+    auto window = icvFindWindowByName(name);
     if (!window)
-        EXIT; // keep silence here
+        CV_Error_(Error::StsNullPtr, ("NULL window: '%s'", name));
 
     result = static_cast<double>(window->width) / window->height;
 
-    __END__;
-
     return result;
 }
 
@@ -749,23 +851,20 @@ double cvGetOpenGlProp_W32(const char* name)
     double result = -1;
 
 #ifdef HAVE_OPENGL
-    CV_FUNCNAME( "cvGetOpenGlProp_W32" );
+    CV_FUNCNAME("cvGetOpenGlProp_W32");
 
-    __BEGIN__;
-
-    CvWindow* window;
+    AutoLock lock(getWindowMutex());
 
     if (!name)
-        CV_ERROR( CV_StsNullPtr, "NULL name string" );
+        CV_Error(Error::StsNullPtr, "NULL name string");
 
-    window = icvFindWindowByName( name );
+    auto window = icvFindWindowByName(name);
     if (!window)
-        EXIT; // keep silence here
+        return -1;
 
     result = window->useGl;
-
-    __END__;
 #endif
+
     CV_UNUSED(name);
 
     return result;
@@ -775,16 +874,15 @@ double cvGetPropVisible_W32(const char* name)
 {
     double result = -1;
 
-    CV_FUNCNAME( "cvGetPropVisible_W32" );
+    CV_FUNCNAME("cvGetPropVisible_W32");
 
-    __BEGIN__;
+    AutoLock lock(getWindowMutex());
 
     if (!name)
-        CV_ERROR( CV_StsNullPtr, "NULL name string" );
-
-    result = (icvFindWindowByName( name ) != NULL);
+        CV_Error(Error::StsNullPtr, "NULL name string");
 
-    __END__;
+    auto window = icvFindWindowByName(name);
+    result = (bool)window ? 1.0 : 0.0;
 
     return result;
 }
@@ -798,9 +896,9 @@ namespace
 {
     void createGlContext(HWND hWnd, HDC& hGLDC, HGLRC& hGLRC, bool& useGl)
     {
-        CV_FUNCNAME( "createGlContext" );
+        CV_FUNCNAME("createGlContext");
 
-        __BEGIN__;
+        AutoLock lock(getWindowMutex());
 
         useGl = false;
 
@@ -830,120 +928,119 @@ namespace
 
         hGLDC = GetDC(hWnd);
         if (!hGLDC)
-            CV_ERROR( CV_OpenGlApiCallError, "Can't Create A GL Device Context" );
+            CV_Error(Error::OpenGlApiCallError, "Can't Create A GL Device Context");
 
         PixelFormat = ChoosePixelFormat(hGLDC, &pfd);
         if (!PixelFormat)
-            CV_ERROR( CV_OpenGlApiCallError, "Can't Find A Suitable PixelFormat" );
+            CV_Error(Error::OpenGlApiCallError, "Can't Find A Suitable PixelFormat");
 
         if (!SetPixelFormat(hGLDC, PixelFormat, &pfd))
-            CV_ERROR( CV_OpenGlApiCallError, "Can't Set The PixelFormat" );
+            CV_Error(Error::OpenGlApiCallError, "Can't Set The PixelFormat");
 
         hGLRC = wglCreateContext(hGLDC);
         if (!hGLRC)
-            CV_ERROR( CV_OpenGlApiCallError, "Can't Create A GL Rendering Context" );
+            CV_Error(Error::OpenGlApiCallError, "Can't Create A GL Rendering Context");
 
         if (!wglMakeCurrent(hGLDC, hGLRC))
-            CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );
+            CV_Error(Error::OpenGlApiCallError, "Can't Activate The GL Rendering Context");
 
         useGl = true;
-
-        __END__;
     }
 
-    void releaseGlContext(CvWindow* window)
+    void releaseGlContext(CvWindow& window)
     {
-        //CV_FUNCNAME( "releaseGlContext" );
+        //CV_FUNCNAME("releaseGlContext");
 
-        __BEGIN__;
+        AutoLock lock(getWindowMutex());
 
-        if (window->hGLRC)
+        if (window.hGLRC)
         {
-            wglDeleteContext(window->hGLRC);
-            window->hGLRC = NULL;
+            wglDeleteContext(window.hGLRC);
+            window.hGLRC = NULL;
         }
 
-        if (window->dc)
+        if (window.dc)
         {
-            ReleaseDC(window->hwnd, window->dc);
-            window->dc = NULL;
+            ReleaseDC(window.hwnd, window.dc);
+            window.dc = NULL;
         }
 
-        window->useGl = false;
-
-        __END__;
+        window.useGl = false;
     }
 
-    void drawGl(CvWindow* window)
+    void drawGl(CvWindow& window)
     {
-        CV_FUNCNAME( "drawGl" );
+        CV_FUNCNAME("drawGl");
 
-        __BEGIN__;
+        AutoLock lock(getWindowMutex());
 
-        if (!wglMakeCurrent(window->dc, window->hGLRC))
-            CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );
+        if (!wglMakeCurrent(window.dc, window.hGLRC))
+            CV_Error(Error::OpenGlApiCallError, "Can't Activate The GL Rendering Context");
 
         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
-        if (window->glDrawCallback)
-            window->glDrawCallback(window->glDrawData);
+        if (window.glDrawCallback)
+            window.glDrawCallback(window.glDrawData);
 
-        if (!SwapBuffers(window->dc))
-            CV_ERROR( CV_OpenGlApiCallError, "Can't swap OpenGL buffers" );
-
-        __END__;
+        if (!SwapBuffers(window.dc))
+            CV_Error(Error::OpenGlApiCallError, "Can't swap OpenGL buffers");
     }
 
-    void resizeGl(CvWindow* window)
+    void resizeGl(CvWindow& window)
     {
-        CV_FUNCNAME( "resizeGl" );
-
-        __BEGIN__;
+        CV_FUNCNAME("resizeGl");
 
-        if (!wglMakeCurrent(window->dc, window->hGLRC))
-            CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );
+        AutoLock lock(getWindowMutex());
 
-        glViewport(0, 0, window->width, window->height);
+        if (!wglMakeCurrent(window.dc, window.hGLRC))
+            CV_Error(Error::OpenGlApiCallError, "Can't Activate The GL Rendering Context");
 
-        __END__;
+        glViewport(0, 0, window.width, window.height);
     }
 }
 
 #endif // HAVE_OPENGL
 
+static std::shared_ptr<CvWindow> namedWindow_(const std::string& name, int flags);
+
+CV_IMPL int cvNamedWindow(const char* name, int flags)
+{
+    CV_FUNCNAME("cvNamedWindow");
+
+    AutoLock lock(getWindowMutex());
+
+    if (!name)
+        CV_Error(Error::StsNullPtr, "NULL name string");
+
+    // Check the name in the storage
+    auto window = icvFindWindowByName(name);
+    if (window)
+    {
+        return 1;
+    }
 
-CV_IMPL int cvNamedWindow( const char* name, int flags )
+    window = namedWindow_(name, flags);
+    return (bool)window;
+}
+
+static std::shared_ptr<CvWindow> namedWindow_(const std::string& name, int flags)
 {
-    int result = 0;
-    CV_FUNCNAME( "cvNamedWindow" );
+    AutoLock lock(getWindowMutex());
 
-    __BEGIN__;
+    cvInitSystem(0,0);
 
     HWND hWnd, mainhWnd;
-    CvWindow* window;
     DWORD defStyle = WS_VISIBLE | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU;
-    int len;
-    CvRect rect;
 #ifdef HAVE_OPENGL
     bool useGl;
     HDC hGLDC;
     HGLRC hGLRC;
 #endif
 
-    cvInitSystem(0,0);
-
-    if( !name )
-        CV_ERROR( CV_StsNullPtr, "NULL name string" );
-
-    // Check the name in the storage
-    window = icvFindWindowByName( name );
-    if (window != 0)
-    {
-        result = 1;
-        EXIT;
-    }
+    CvRect rect;
+    icvLoadWindowPos(name.c_str(), rect);
 
-    if!(flags & CV_WINDOW_AUTOSIZE))//YV add border in order to resize the window
+    if (!(flags & CV_WINDOW_AUTOSIZE))//YV add border in order to resize the window
        defStyle |= WS_SIZEBOX;
 
 #ifdef HAVE_OPENGL
@@ -951,23 +1048,21 @@ CV_IMPL int cvNamedWindow( const char* name, int flags )
         defStyle |= WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
 #endif
 
-    icvLoadWindowPos( name, rect );
-
-    mainhWnd = CreateWindow( "Main HighGUI class", name, defStyle | WS_OVERLAPPED,
-                             rect.x, rect.y, rect.width, rect.height, 0, 0, hg_hinstance, 0 );
-    if( !mainhWnd )
-        CV_ERROR( CV_StsError, "Frame window can not be created" );
+    mainhWnd = CreateWindow(mainHighGUIclassName, name.c_str(), defStyle | WS_OVERLAPPED,
+                             rect.x, rect.y, rect.width, rect.height, 0, 0, hg_hinstance, 0);
+    if (!mainhWnd)
+        CV_Error_(Error::StsError, ("Frame window can not be created: '%s'", name.c_str()));
 
     ShowWindow(mainhWnd, SW_SHOW);
 
     //YV- remove one border by changing the style
-    hWnd = CreateWindow("HighGUI class", "", (defStyle & ~WS_SIZEBOX) | WS_CHILD, CW_USEDEFAULT, 0, rect.width, rect.height, mainhWnd, 0, hg_hinstance, 0);
-    if( !hWnd )
-        CV_ERROR( CV_StsError, "Frame window can not be created" );
+    hWnd = CreateWindow(highGUIclassName, "", (defStyle & ~WS_SIZEBOX) | WS_CHILD, CW_USEDEFAULT, 0, rect.width, rect.height, mainhWnd, 0, hg_hinstance, 0);
+    if (!hWnd)
+        CV_Error(Error::StsError, "Frame window can not be created");
 
 #ifndef HAVE_OPENGL
     if (flags & CV_WINDOW_OPENGL)
-        CV_ERROR( CV_OpenGlNotSupported, "Library was built without OpenGL support" );
+        CV_Error(Error::OpenGlNotSupported, "Library was built without OpenGL support");
 #else
     useGl = false;
     hGLDC = 0;
@@ -979,14 +1074,10 @@ CV_IMPL int cvNamedWindow( const char* name, int flags )
 
     ShowWindow(hWnd, SW_SHOW);
 
-    len = (int)strlen(name);
-    CV_CALL( window = (CvWindow*)cvAlloc(sizeof(CvWindow) + len + 1));
+    auto window = std::make_shared<CvWindow>(name);
 
-    window->signature = CV_WINDOW_MAGIC_VAL;
     window->hwnd = hWnd;
     window->frame = mainhWnd;
-    window->name = (char*)(window + 1);
-    memcpy( window->name, name, len + 1 );
     window->flags = flags;
     window->image = 0;
 
@@ -1016,200 +1107,175 @@ CV_IMPL int cvNamedWindow( const char* name, int flags )
     window->on_mouse = 0;
     window->on_mouse_param = 0;
 
-    memset( &window->toolbar, 0, sizeof(window->toolbar));
+    icvSetWindowLongPtr(hWnd, CV_USERDATA, window.get());
+    icvSetWindowLongPtr(mainhWnd, CV_USERDATA, window.get());
 
-    window->next = hg_windows;
-    window->prev = 0;
-    if( hg_windows )
-        hg_windows->prev = window;
-    hg_windows = window;
-    icvSetWindowLongPtr( hWnd, CV_USERDATA, window );
-    icvSetWindowLongPtr( mainhWnd, CV_USERDATA, window );
+    auto& g_windows = getWindowsList();
+    g_windows.push_back(window);
 
     // Recalculate window pos
-    icvUpdateWindowPos( window );
+    icvUpdateWindowPos(*window);
 
-    result = 1;
-    __END__;
-
-    return result;
+    return window;
 }
 
 #ifdef HAVE_OPENGL
 
 CV_IMPL void cvSetOpenGlContext(const char* name)
 {
-    CV_FUNCNAME( "cvSetOpenGlContext" );
-
-    __BEGIN__;
+    CV_FUNCNAME("cvSetOpenGlContext");
 
-    CvWindow* window;
+    AutoLock lock(getWindowMutex());
 
-    if(!name)
-        CV_ERROR( CV_StsNullPtr, "NULL name string" );
+    if (!name)
+        CV_Error(Error::StsNullPtr, "NULL name string");
 
-    window = icvFindWindowByName( name );
+    auto window = icvFindWindowByName(name);
     if (!window)
-        CV_ERROR( CV_StsNullPtr, "NULL window" );
+        CV_Error_(Error::StsNullPtr, ("NULL window: '%s'", name));
 
     if (!window->useGl)
-        CV_ERROR( CV_OpenGlNotSupported, "Window doesn't support OpenGL" );
+        CV_Error(Error::OpenGlNotSupported, "Window doesn't support OpenGL");
 
     if (!wglMakeCurrent(window->dc, window->hGLRC))
-        CV_ERROR( CV_OpenGlApiCallError, "Can't Activate The GL Rendering Context" );
-
-    __END__;
+        CV_Error(Error::OpenGlApiCallError, "Can't Activate The GL Rendering Context");
 }
 
 CV_IMPL void cvUpdateWindow(const char* name)
 {
-    CV_FUNCNAME( "cvUpdateWindow" );
+    CV_FUNCNAME("cvUpdateWindow");
 
-    __BEGIN__;
-
-    CvWindow* window;
+    AutoLock lock(getWindowMutex());
 
     if (!name)
-        CV_ERROR( CV_StsNullPtr, "NULL name string" );
+        CV_Error(Error::StsNullPtr, "NULL name string");
 
-    window = icvFindWindowByName( name );
+    auto window = icvFindWindowByName(name);
     if (!window)
-        EXIT;
+        CV_Error_(Error::StsNullPtr, ("NULL window: '%s'", name));
 
     InvalidateRect(window->hwnd, 0, 0);
-
-    __END__;
 }
 
 CV_IMPL void cvSetOpenGlDrawCallback(const char* name, CvOpenGlDrawCallback callback, void* userdata)
 {
-    CV_FUNCNAME( "cvCreateOpenGLCallback" );
+    CV_FUNCNAME("cvCreateOpenGLCallback");
 
-    __BEGIN__;
+    AutoLock lock(getWindowMutex());
 
-    CvWindow* window;
-
-    if(!name)
-        CV_ERROR( CV_StsNullPtr, "NULL name string" );
+    if (!name)
+        CV_Error(Error::StsNullPtr, "NULL name string");
 
-    window = icvFindWindowByName( name );
-    if( !window )
-        EXIT;
+    auto window = icvFindWindowByName(name);
+    if (!window)
+        CV_Error_(Error::StsNullPtr, ("NULL window: '%s'", name));
 
     if (!window->useGl)
-        CV_ERROR( CV_OpenGlNotSupported, "Window was created without OpenGL context" );
+        CV_Error(Error::OpenGlNotSupported, "Window was created without OpenGL context");
 
     window->glDrawCallback = callback;
     window->glDrawData = userdata;
-
-    __END__;
 }
 
 #endif // HAVE_OPENGL
 
-static void icvRemoveWindow( CvWindow* window )
+static void icvRemoveWindow(const std::shared_ptr<CvWindow>& window_)
 {
-    CvTrackbar* trackbar = NULL;
+    CV_Assert(window_);
+    AutoLock lock(getWindowMutex());
+    CvWindow& window = *window_;
+
     RECT wrect={0,0,0,0};
 
+    auto& g_windows = getWindowsList();
+    for (auto it = g_windows.begin(); it != g_windows.end(); ++it)
+    {
+        const std::shared_ptr<CvWindow>& w = *it;
+        if (w.get() == &window)
+        {
+            g_windows.erase(it);
+            break;
+        }
+    }
+
 #ifdef HAVE_OPENGL
-    if (window->useGl)
+    if (window.useGl)
         releaseGlContext(window);
 #endif
 
-    if( window->frame )
-        GetWindowRect( window->frame, &wrect );
-    if( window->name )
-        icvSaveWindowPos( window->name, cvRect(wrect.left, wrect.top,
-            wrect.right-wrect.left, wrect.bottom-wrect.top) );
-
-    if( window->hwnd )
-        icvSetWindowLongPtr( window->hwnd, CV_USERDATA, 0 );
-    if( window->frame )
-        icvSetWindowLongPtr( window->frame, CV_USERDATA, 0 );
+    if (window.frame)
+        GetWindowRect(window.frame, &wrect);
+    icvSaveWindowPos(window.name.c_str(), cvRect(wrect.left, wrect.top, wrect.right-wrect.left, wrect.bottom-wrect.top));
 
-    if( window->toolbar.toolbar )
-        icvSetWindowLongPtr(window->toolbar.toolbar, CV_USERDATA, 0);
+    if (window.hwnd)
+        icvSetWindowLongPtr(window.hwnd, CV_USERDATA, 0);
+    if (window.frame)
+        icvSetWindowLongPtr(window.frame, CV_USERDATA, 0);
 
-    if( window->prev )
-        window->prev->next = window->next;
-    else
-        hg_windows = window->next;
-
-    if( window->next )
-        window->next->prev = window->prev;
+    if (window.toolbar.toolbar)
+        icvSetWindowLongPtr(window.toolbar.toolbar, CV_USERDATA, 0);
 
-    window->prev = window->next = 0;
+    if (window.dc && window.image)
+        DeleteObject(SelectObject(window.dc, window.image));
 
-    if( window->dc && window->image )
-        DeleteObject(SelectObject(window->dc,window->image));
+    if (window.dc)
+        DeleteDC(window.dc);
 
-    if( window->dc )
-        DeleteDC(window->dc);
-
-    for( trackbar = window->toolbar.first; trackbar != 0; )
+    for (auto it = window.toolbar.trackbars.begin(); it != window.toolbar.trackbars.end(); ++it)
     {
-        CvTrackbar* next = trackbar->next;
-        if( trackbar->hwnd )
+        auto trackbar = (*it).get();
+        if (trackbar && trackbar->hwnd)
         {
-            icvSetWindowLongPtr( trackbar->hwnd, CV_USERDATA, 0 );
-            cvFree( &trackbar );
+            icvSetWindowLongPtr(trackbar->hwnd, CV_USERDATA, 0);
         }
-        trackbar = next;
     }
-
-    cvFree( &window );
 }
 
 
-CV_IMPL void cvDestroyWindow( const char* name )
+CV_IMPL void cvDestroyWindow(const char* name)
 {
-    CV_FUNCNAME( "cvDestroyWindow" );
+    CV_FUNCNAME("cvDestroyWindow");
 
-    __BEGIN__;
+    AutoLock lock(getWindowMutex());
 
-    CvWindow* window;
-    HWND mainhWnd;
+    if (!name)
+        CV_Error(Error::StsNullPtr, "NULL name string");
 
-    if(!name)
-        CV_ERROR( CV_StsNullPtr, "NULL name string" );
+    auto window = icvFindWindowByName(name);
+    if (!window)
+        CV_Error_(Error::StsNullPtr, ("NULL window: '%s'", name));
 
-    window = icvFindWindowByName( name );
-    if( !window )
-        EXIT;
+    window->destroy();
+}
 
-    mainhWnd = window->frame;
 
-    SendMessage(window->hwnd, WM_CLOSE, 0, 0);
-    SendMessage( mainhWnd, WM_CLOSE, 0, 0);
+void CvWindow::destroy()
+{
+    SendMessage(hwnd, WM_CLOSE, 0, 0);
+    SendMessage(frame, WM_CLOSE, 0, 0);
     // Do NOT call _remove_window -- CvWindow list will be updated automatically ...
-
-    __END__;
 }
 
-
-static void icvScreenToClient( HWND hwnd, RECT* rect )
+static void icvScreenToClient(HWND hwnd, RECT* rect)
 {
     POINT p;
     p.x = rect->left;
     p.y = rect->top;
     ScreenToClient(hwnd, &p);
-    OffsetRect( rect, p.x - rect->left, p.y - rect->top );
+    OffsetRect(rect, p.x - rect->left, p.y - rect->top);
 }
 
 
 /* Calculatess the window coordinates relative to the upper left corner of the mainhWnd window */
-static RECT icvCalcWindowRect( CvWindow* window )
+static RECT icvCalcWindowRect(CvWindow& window)
 {
     RECT crect = { 0 }, trect = { 0 }, rect = { 0 };
 
-    assert(window);
-
-    GetClientRect(window->frame, &crect);
-    if (window->toolbar.toolbar)
+    GetClientRect(window.frame, &crect);
+    if (window.toolbar.toolbar)
     {
-        GetWindowRect(window->toolbar.toolbar, &trect);
-        icvScreenToClient(window->frame, &trect);
+        GetWindowRect(window.toolbar.toolbar, &trect);
+        icvScreenToClient(window.frame, &trect);
         SubtractRect(&rect, &crect, &trect);
     }
     else
@@ -1217,138 +1283,153 @@ static RECT icvCalcWindowRect( CvWindow* window )
 
     return rect;
 }
+static inline RECT icvCalcWindowRect(CvWindow* window) { CV_Assert(window); return icvCalcWindowRect(*window); }
+
 
-// returns TRUE if there is a problem such as ERROR_IO_PENDING.
-static bool icvGetBitmapData( CvWindow* window, SIZE* size, int* channels, void** data )
+// returns FALSE if there is a problem such as ERROR_IO_PENDING.
+static bool icvGetBitmapData(CvWindow& window, SIZE& size, int& channels, void*& data)
 {
-    BITMAP bmp;
     GdiFlush();
-    HGDIOBJ h = GetCurrentObject( window->dc, OBJ_BITMAP );
-    if( size )
-        size->cx = size->cy = 0;
-    if( data )
-        *data = 0;
+
+    HGDIOBJ h = GetCurrentObject(window.dc, OBJ_BITMAP);
+    size.cx = size.cy = 0;
+    data = 0;
 
     if (h == NULL)
-        return true;
+        return false;
+
+    BITMAP bmp = {};
     if (GetObject(h, sizeof(bmp), &bmp) == 0)
-        return true;
+        return false;
 
-    if( size )
-    {
-        size->cx = abs(bmp.bmWidth);
-        size->cy = abs(bmp.bmHeight);
-    }
+    size.cx = abs(bmp.bmWidth);
+    size.cy = abs(bmp.bmHeight);
 
-    if( channels )
-        *channels = bmp.bmBitsPixel/8;
+    channels = bmp.bmBitsPixel/8;
 
-    if( data )
-        *data = bmp.bmBits;
+    data = bmp.bmBits;
 
-    return false;
+    return true;
+}
+static bool icvGetBitmapData(CvWindow& window, SIZE& size)
+{
+    int channels = 0;
+    void* data = nullptr;
+    return icvGetBitmapData(window, size, channels, data);
 }
 
 
-static void icvUpdateWindowPos( CvWindow* window )
+static void icvUpdateWindowPos(CvWindow& window)
 {
     RECT rect = { 0 };
-    assert(window);
 
-    if( (window->flags & CV_WINDOW_AUTOSIZE) && window->image )
+    if ((window.flags & CV_WINDOW_AUTOSIZE) && window.image)
     {
         int i;
         SIZE size = {0,0};
-        icvGetBitmapData( window, &size, 0, 0 );
+        icvGetBitmapData(window, size);  // TODO check return value?
 
         // Repeat two times because after the first resizing of the mainhWnd window
         // toolbar may resize too
-        for(i = 0; i < (window->toolbar.toolbar ? 2 : 1); i++)
+        for(i = 0; i < (window.toolbar.toolbar ? 2 : 1); i++)
         {
-            RECT rmw = { 0 }, rw = icvCalcWindowRect(window );
-            MoveWindow(window->hwnd, rw.left, rw.top,
+            RECT rmw = { 0 }, rw = icvCalcWindowRect(&window);
+            MoveWindow(window.hwnd, rw.left, rw.top,
                 rw.right - rw.left, rw.bottom - rw.top, FALSE);
-            GetClientRect(window->hwnd, &rw);
-            GetWindowRect(window->frame, &rmw);
+            GetClientRect(window.hwnd, &rw);
+            GetWindowRect(window.frame, &rmw);
             // Resize the mainhWnd window in order to make the bitmap fit into the child window
-            MoveWindow(window->frame, rmw.left, rmw.top,
+            MoveWindow(window.frame, rmw.left, rmw.top,
                 size.cx + (rmw.right - rmw.left) - (rw.right - rw.left),
-                size.cy + (rmw.bottom - rmw.top) - (rw.bottom - rw.top), TRUE );
+                size.cy + (rmw.bottom - rmw.top) - (rw.bottom - rw.top), TRUE);
         }
     }
 
     rect = icvCalcWindowRect(window);
-    MoveWindow(window->hwnd, rect.left, rect.top,
+    MoveWindow(window.hwnd, rect.left, rect.top,
                rect.right - rect.left,
-               rect.bottom - rect.top, TRUE );
+               rect.bottom - rect.top, TRUE);
 }
 
+static void showImage_(CvWindow& window, const Mat& image);
+
 CV_IMPL void
-cvShowImage( const char* name, const CvArr* arr )
+cvShowImage(const char* name, const CvArr* arr)
 {
-    CV_FUNCNAME( "cvShowImage" );
-
-    __BEGIN__;
-
-    CvWindow* window;
-    SIZE size = { 0, 0 };
-    int channels = 0;
-    void* dst_ptr = 0;
-    const int channels0 = 3;
-    CvMat stub, *image;
-    bool changed_size = false; // philipg
+    CV_FUNCNAME("cvShowImage");
 
-    if( !name )
-        CV_ERROR( CV_StsNullPtr, "NULL name" );
+    if (!name)
+        CV_Error(Error::StsNullPtr, "NULL name");
 
-    window = icvFindWindowByName(name);
-    if(!window)
+    std::shared_ptr<CvWindow> window;
     {
-        cvNamedWindow(name, CV_WINDOW_AUTOSIZE);
+        AutoLock lock(getWindowMutex());
+
         window = icvFindWindowByName(name);
+        if (!window)
+        {
+            cvNamedWindow(name, CV_WINDOW_AUTOSIZE);
+            window = icvFindWindowByName(name);
+        }
     }
 
-    if( !window || !arr )
-        EXIT; // keep silence here.
-
-    CV_CALL( image = cvGetMat( arr, &stub ));
+    if (!window || !arr)
+        return; // keep silence here.
 
+    CvMat stub = {};
+    CvMat* image_c = cvGetMat(arr, &stub);
+    Mat image = cv::cvarrToMat(image_c);
 #ifdef HAVE_OPENGL
     if (window->useGl)
     {
-        cv::imshow(name, cv::cvarrToMat(image));
+        cv::imshow(name, image);
         return;
     }
 #endif
+    return showImage_(*window, image);
+}
+
+static void showImage_(CvWindow& window, const Mat& image)
+{
+    AutoLock lock(window.mutex);
 
-    if (window->image)
+    SIZE size = { 0, 0 };
+    int channels = 0;
+    void* dst_ptr = 0;
+    const int channels0 = 3;
+    bool changed_size = false; // philipg
+
+    if (window.image)
+    {
         // if there is something wrong with these system calls, we cannot display image...
-        if (icvGetBitmapData( window, &size, &channels, &dst_ptr ))
+        if (!icvGetBitmapData(window, size, channels, dst_ptr))
             return;
+    }
 
-    if( size.cx != image->width || size.cy != image->height || channels != channels0 )
+    if (size.cx != image.cols || size.cy != image.rows || channels != channels0)
     {
         changed_size = true;
 
         uchar buffer[sizeof(BITMAPINFO) + 255*sizeof(RGBQUAD)];
         BITMAPINFO* binfo = (BITMAPINFO*)buffer;
 
-        DeleteObject( SelectObject( window->dc, window->image ));
-        window->image = 0;
+        DeleteObject(SelectObject(window.dc, window.image));
+        window.image = 0;
 
-        size.cx = image->width;
-        size.cy = image->height;
+        size.cx = image.cols;
+        size.cy = image.rows;
         channels = channels0;
 
-        FillBitmapInfo( binfo, size.cx, size.cy, channels*8, 1 );
+        FillBitmapInfo(binfo, size.cx, size.cy, channels*8, 1);
 
-        window->image = SelectObject( window->dc, CreateDIBSection(window->dc, binfo,
-                                      DIB_RGB_COLORS, &dst_ptr, 0, 0));
+        window.image = SelectObject(window.dc,
+                CreateDIBSection(window.dc, binfo, DIB_RGB_COLORS, &dst_ptr, 0, 0)
+            );
     }
 
     {
         cv::Mat dst(size.cy, size.cx, CV_8UC3, dst_ptr, (size.cx * channels + 3) & -4);
-        convertToShow(cv::cvarrToMat(image), dst, false);
+        convertToShow(image, dst, false);
         CV_Assert(dst.data == (uchar*)dst_ptr);
         cv::flip(dst, dst, 0);
     }
@@ -1356,98 +1437,103 @@ cvShowImage( const char* name, const CvArr* arr )
     // only resize window if needed
     if (changed_size)
         icvUpdateWindowPos(window);
-    InvalidateRect(window->hwnd, 0, 0);
+    InvalidateRect(window.hwnd, 0, 0);
     // philipg: this is not needed and just slows things down
     //    UpdateWindow(window->hwnd);
-
-    __END__;
 }
 
-CV_IMPL void cvResizeWindow(const char* name, int width, int height )
+static void resizeWindow_(CvWindow& window, const Size& size);
+
+CV_IMPL void cvResizeWindow(const char* name, int width, int height)
 {
-    CV_FUNCNAME( "cvResizeWindow" );
+    CV_FUNCNAME("cvResizeWindow");
 
-    __BEGIN__;
+    AutoLock lock(getWindowMutex());
 
-    int i;
-    CvWindow* window;
-    RECT rmw = { 0 }, rw = { 0 }, rect = { 0 };
+    if (!name)
+        CV_Error(Error::StsNullPtr, "NULL name");
 
-    if( !name )
-        CV_ERROR( CV_StsNullPtr, "NULL name" );
+    auto window = icvFindWindowByName(name);
+    if (!window)
+        CV_Error_(Error::StsNullPtr, ("NULL window: '%s'", name));
 
-    window = icvFindWindowByName(name);
-    if(!window)
-        EXIT;
+    return resizeWindow_(*window, Size(width, height));
+}
+
+static void resizeWindow_(CvWindow& window, const Size& size)
+{
+    RECT rmw = { 0 }, rw = { 0 }, rect = { 0 };
 
     // Repeat two times because after the first resizing of the mainhWnd window
     // toolbar may resize too
-    for(i = 0; i < (window->toolbar.toolbar ? 2 : 1); i++)
+    for (int i = 0; i < (window.toolbar.toolbar ? 2 : 1); i++)
     {
         rw = icvCalcWindowRect(window);
-        MoveWindow(window->hwnd, rw.left, rw.top,
+        MoveWindow(window.hwnd, rw.left, rw.top,
             rw.right - rw.left, rw.bottom - rw.top, FALSE);
-        GetClientRect(window->hwnd, &rw);
-        GetWindowRect(window->frame, &rmw);
+        GetClientRect(window.hwnd, &rw);
+        GetWindowRect(window.frame, &rmw);
         // Resize the mainhWnd window in order to make the bitmap fit into the child window
-        MoveWindow(window->frame, rmw.left, rmw.top,
-            width  + (rmw.right - rmw.left) - (rw.right - rw.left),
-            height + (rmw.bottom - rmw.top) - (rw.bottom - rw.top), TRUE);
+        MoveWindow(window.frame, rmw.left, rmw.top,
+            size.width  + (rmw.right - rmw.left) - (rw.right - rw.left),
+            size.height + (rmw.bottom - rmw.top) - (rw.bottom - rw.top), TRUE);
     }
 
     rect = icvCalcWindowRect(window);
-    MoveWindow(window->hwnd, rect.left, rect.top,
+    MoveWindow(window.hwnd, rect.left, rect.top,
         rect.right - rect.left, rect.bottom - rect.top, TRUE);
-
-    __END__;
 }
 
+static void moveWindow_(CvWindow& window, const Point& pt);
 
-CV_IMPL void cvMoveWindow( const char* name, int x, int y )
+CV_IMPL void cvMoveWindow(const char* name, int x, int y)
 {
-    CV_FUNCNAME( "cvMoveWindow" );
+    CV_FUNCNAME("cvMoveWindow");
 
-    __BEGIN__;
+    AutoLock lock(getWindowMutex());
 
-    CvWindow* window;
-    RECT rect = { 0 };
-
-    if( !name )
-        CV_ERROR( CV_StsNullPtr, "NULL name" );
+    if (!name)
+        CV_Error(Error::StsNullPtr, "NULL name");
 
-    window = icvFindWindowByName(name);
-    if(!window)
-        EXIT;
+    auto window = icvFindWindowByName(name);
+    if (!window)
+        CV_Error_(Error::StsNullPtr, ("NULL window: '%s'", name));
 
-    GetWindowRect( window->frame, &rect );
-    MoveWindow( window->frame, x, y, rect.right - rect.left, rect.bottom - rect.top, TRUE);
+    (void)moveWindow_(*window, Point(x, y));
+}
 
-    __END__;
+static void moveWindow_(CvWindow& window, const Point& pt)
+{
+    RECT rect = { 0 };
+    GetWindowRect(window.frame, &rect);  // TODO check return value
+    MoveWindow(window.frame, pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, TRUE);
 }
 
 
 static LRESULT CALLBACK
-MainWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
+MainWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
-    CvWindow* window = icvWindowByHWND( hwnd );
-    if( !window )
+    auto window_ = icvWindowByHWND(hwnd);
+    if (!window_)
         return DefWindowProc(hwnd, uMsg, wParam, lParam);
 
+    CvWindow& window = *window_;
+
     switch(uMsg)
     {
     case WM_COPY:
-        ::SendMessage(window->hwnd, uMsg, wParam, lParam);
+        ::SendMessage(window.hwnd, uMsg, wParam, lParam);
         break;
 
     case WM_DESTROY:
 
-        icvRemoveWindow(window);
+        icvRemoveWindow(window_);
         // Do nothing!!!
         //PostQuitMessage(0);
         break;
 
     case WM_GETMINMAXINFO:
-        if( !(window->flags & CV_WINDOW_AUTOSIZE) )
+        if (!(window.flags & CV_WINDOW_AUTOSIZE))
         {
             MINMAXINFO* minmax = (MINMAXINFO*)lParam;
             RECT rect = { 0 };
@@ -1456,10 +1542,10 @@ MainWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
             minmax->ptMinTrackSize.y = 100;
             minmax->ptMinTrackSize.x = 100;
 
-            if( window->toolbar.first )
+            if (!window.toolbar.trackbars.empty())
             {
-                GetWindowRect( window->toolbar.first->hwnd, &rect );
-                minmax->ptMinTrackSize.y += window->toolbar.rows*(rect.bottom - rect.top);
+                GetWindowRect(window.toolbar.trackbars[0]->hwnd, &rect);
+                minmax->ptMinTrackSize.y += window.toolbar.rows*(rect.bottom - rect.top);
                 minmax->ptMinTrackSize.x = MAX(rect.right - rect.left + HG_BUDDY_WIDTH, HG_BUDDY_WIDTH*2);
             }
             return retval;
@@ -1471,14 +1557,14 @@ MainWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
             WINDOWPOS* pos = (WINDOWPOS*)lParam;
 
             // Update the toolbar pos/size
-            if(window->toolbar.toolbar)
+            if (window.toolbar.toolbar)
             {
                 RECT rect = { 0 };
-                GetWindowRect(window->toolbar.toolbar, &rect);
-                MoveWindow(window->toolbar.toolbar, 0, 0, pos->cx, rect.bottom - rect.top, TRUE);
+                GetWindowRect(window.toolbar.toolbar, &rect);
+                MoveWindow(window.toolbar.toolbar, 0, 0, pos->cx, rect.bottom - rect.top, TRUE);
             }
 
-            if(!(window->flags & CV_WINDOW_AUTOSIZE))
+            if (!(window.flags & CV_WINDOW_AUTOSIZE))
                 icvUpdateWindowPos(window);
 
             break;
@@ -1490,7 +1576,7 @@ MainWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
           LPWINDOWPOS pos = (LPWINDOWPOS)lParam;
 
           RECT rect = { 0 };
-          GetWindowRect(window->frame, &rect);
+          GetWindowRect(window.frame, &rect);
 
           HMONITOR hMonitor;
           hMonitor = MonitorFromRect(&rect, MONITOR_DEFAULTTONEAREST);
@@ -1515,13 +1601,13 @@ MainWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
        }
 
     case WM_ACTIVATE:
-        if(LOWORD(wParam) == WA_ACTIVE || LOWORD(wParam) == WA_CLICKACTIVE)
-            SetFocus(window->hwnd);
+        if (LOWORD(wParam) == WA_ACTIVE || LOWORD(wParam) == WA_CLICKACTIVE)
+            SetFocus(window.hwnd);
         break;
 
     case WM_MOUSEWHEEL:
     case WM_MOUSEHWHEEL:
-       if( window->on_mouse )
+       if (window.on_mouse)
        {
           int flags = (wParam & MK_LBUTTON      ? CV_EVENT_FLAG_LBUTTON  : 0)|
                       (wParam & MK_RBUTTON      ? CV_EVENT_FLAG_RBUTTON  : 0)|
@@ -1536,32 +1622,32 @@ MainWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
           flags |= (delta << 16);
 
           POINT pt;
-          pt.x = GET_X_LPARAM( lParam );
-          pt.y = GET_Y_LPARAM( lParam );
+          pt.x = GET_X_LPARAM(lParam);
+          pt.y = GET_Y_LPARAM(lParam);
           ::ScreenToClient(hwnd, &pt); // Convert screen coordinates to client coordinates.
 
           RECT rect = { 0 };
-          GetClientRect( window->hwnd, &rect );
+          GetClientRect(window.hwnd, &rect);
 
           SIZE size = {0,0};
 #ifdef HAVE_OPENGL
-          if (window->useGl)
+          if (window.useGl)
           {
-              cv::ogl::Texture2D* texObj = static_cast<cv::ogl::Texture2D*>(window->glDrawData);
+              cv::ogl::Texture2D* texObj = static_cast<cv::ogl::Texture2D*>(window.glDrawData);
               size.cx = texObj->cols();
               size.cy = texObj->rows();
           }
           else
           {
-              icvGetBitmapData(window, &size, 0, 0);
+              icvGetBitmapData(window, size);
           }
 #else
-          icvGetBitmapData(window, &size, 0, 0);
+          icvGetBitmapData(window, size);
 #endif
 
-          window->on_mouse( event, pt.x*size.cx/MAX(rect.right - rect.left,1),
-                                   pt.y*size.cy/MAX(rect.bottom - rect.top,1), flags,
-                                   window->on_mouse_param );
+          int x = cvRound((float)pt.x*size.cx/MAX(rect.right - rect.left,1));
+          int y = cvRound((float)pt.y*size.cy/MAX(rect.bottom - rect.top,1));
+          window.on_mouse(event, x, y, flags, window.on_mouse_param);
        }
        break;
 
@@ -1571,17 +1657,17 @@ MainWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
             HRGN rgn, rgn1, rgn2;
             int ret;
             HDC hdc = (HDC)wParam;
-            GetWindowRect(window->hwnd, &cr);
-            icvScreenToClient(window->frame, &cr);
-            if(window->toolbar.toolbar)
+            GetWindowRect(window.hwnd, &cr);
+            icvScreenToClient(window.frame, &cr);
+            if (window.toolbar.toolbar)
             {
-                GetWindowRect(window->toolbar.toolbar, &tr);
-                icvScreenToClient(window->frame, &tr);
+                GetWindowRect(window.toolbar.toolbar, &tr);
+                icvScreenToClient(window.frame, &tr);
             }
             else
                 tr.left = tr.top = tr.right = tr.bottom = 0;
 
-            GetClientRect(window->frame, &wrc);
+            GetClientRect(window.frame, &wrc);
 
             rgn = CreateRectRgn(0, 0, wrc.right, wrc.bottom);
             rgn1 = CreateRectRgn(cr.left, cr.top, cr.right, cr.bottom);
@@ -1591,7 +1677,7 @@ MainWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
             ret = CombineRgn(rgn, rgn, rgn1, RGN_DIFF);
             ret = CombineRgn(rgn, rgn, rgn2, RGN_DIFF);
 
-            if(ret != NULLREGION && ret != ERROR)
+            if (ret != NULLREGION && ret != ERROR)
                 FillRgn(hdc, rgn, (HBRUSH)icvGetClassLongPtr(hwnd, CV_HBRBACKGROUND));
 
             DeleteObject(rgn);
@@ -1605,20 +1691,24 @@ MainWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
 }
 
 
-static LRESULT CALLBACK HighGUIProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
+static LRESULT CALLBACK HighGUIProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
-    CvWindow* window = icvWindowByHWND(hwnd);
-    if( !window )
+    auto window_ = icvWindowByHWND(hwnd);
+    if (!window_)
+    {
         // This window is not mentioned in HighGUI storage
         // Actually, this should be error except for the case of calls to CreateWindow
         return DefWindowProc(hwnd, uMsg, wParam, lParam);
+    }
+
+    CvWindow& window = *window_;
 
     // Process the message
     switch(uMsg)
     {
     case WM_COPY:
         {
-            if (!::OpenClipboard(hwnd) )
+            if (!::OpenClipboard(hwnd))
                 break;
 
             HDC hDC       = 0;
@@ -1632,7 +1722,7 @@ static LRESULT CALLBACK HighGUIProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
                 if (!::EmptyClipboard())
                     break;
 
-                if(!window->image)
+                if (!window.image)
                     break;
 
                 // Get window device context
@@ -1640,19 +1730,20 @@ static LRESULT CALLBACK HighGUIProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
                     break;
 
                 // Create another DC compatible with hDC
-                if (0 == (memDC = ::CreateCompatibleDC( hDC )))
+                if (0 == (memDC = ::CreateCompatibleDC(hDC)))
                     break;
 
                 // Determine the bitmap's dimensions
-                int nchannels = 3;
                 SIZE size = {0,0};
-                icvGetBitmapData( window, &size, &nchannels, 0 );
+                int nchannels = 3;
+                void* data = NULL;  // unused
+                icvGetBitmapData(window, size, nchannels, data);
 
                 // Create bitmap to draw on and it in the new DC
-                if (0 == (memBM = ::CreateCompatibleBitmap ( hDC, size.cx, size.cy)))
+                if (0 == (memBM = ::CreateCompatibleBitmap(hDC, size.cx, size.cy)))
                     break;
 
-                if (!::SelectObject( memDC, memBM ))
+                if (!::SelectObject(memDC, memBM))
                     break;
 
                 // Begin drawing to DC
@@ -1660,7 +1751,7 @@ static LRESULT CALLBACK HighGUIProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
                     break;
 
                 RGBQUAD table[256];
-                if( 1 == nchannels )
+                if (1 == nchannels)
                 {
                     for(int i = 0; i < 256; ++i)
                     {
@@ -1668,14 +1759,14 @@ static LRESULT CALLBACK HighGUIProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
                         table[i].rgbGreen = (unsigned char)i;
                         table[i].rgbRed = (unsigned char)i;
                     }
-                    if (!::SetDIBColorTable(window->dc, 0, 255, table))
+                    if (!::SetDIBColorTable(window.dc, 0, 255, table))
                         break;
                 }
 
                 // The image copied to the clipboard will be in its original size, regardless if the window itself was resized.
 
                 // Render the image to the dc/bitmap (at original size).
-                if (!::BitBlt( memDC, 0, 0, size.cx, size.cy, window->dc, 0, 0, SRCCOPY ))
+                if (!::BitBlt(memDC, 0, 0, size.cx, size.cy, window.dc, 0, 0, SRCCOPY))
                     break;
 
                 // Finally, set bitmap to clipboard
@@ -1712,7 +1803,7 @@ static LRESULT CALLBACK HighGUIProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
     case WM_RBUTTONUP:
     case WM_MBUTTONUP:
     case WM_MOUSEMOVE:
-        if( window->on_mouse )
+        if (window.on_mouse)
         {
             POINT pt;
 
@@ -1732,50 +1823,50 @@ static LRESULT CALLBACK HighGUIProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
                         uMsg == WM_RBUTTONDBLCLK ? CV_EVENT_RBUTTONDBLCLK :
                         uMsg == WM_MBUTTONDBLCLK ? CV_EVENT_MBUTTONDBLCLK :
                                                    CV_EVENT_MOUSEMOVE;
-            if( uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONDOWN || uMsg == WM_MBUTTONDOWN )
-                SetCapture( hwnd );
-            if( uMsg == WM_LBUTTONUP || uMsg == WM_RBUTTONUP || uMsg == WM_MBUTTONUP )
+            if (uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONDOWN || uMsg == WM_MBUTTONDOWN)
+                SetCapture(hwnd);
+            if (uMsg == WM_LBUTTONUP || uMsg == WM_RBUTTONUP || uMsg == WM_MBUTTONUP)
                 ReleaseCapture();
 
-            pt.x = GET_X_LPARAM( lParam );
-            pt.y = GET_Y_LPARAM( lParam );
+            pt.x = GET_X_LPARAM(lParam);
+            pt.y = GET_Y_LPARAM(lParam);
 
-            if (window->flags & CV_WINDOW_AUTOSIZE)
+            if (window.flags & CV_WINDOW_AUTOSIZE)
             {
                 // As user can't change window size, do not scale window coordinates. Underlying windowing system
                 // may prevent full window from being displayed and in this case coordinates should not be scaled.
-                window->on_mouse( event, pt.x, pt.y, flags, window->on_mouse_param );
+                window.on_mouse(event, pt.x, pt.y, flags, window.on_mouse_param);
             } else {
                 // Full window is displayed using different size. Scale coordinates to match underlying positions.
                 RECT rect = { 0 };
                 SIZE size = {0, 0};
 
-                GetClientRect( window->hwnd, &rect );
+                GetClientRect(window.hwnd, &rect);
 
 #ifdef HAVE_OPENGL
-                if (window->useGl)
+                if (window.useGl)
                 {
-                    cv::ogl::Texture2D* texObj = static_cast<cv::ogl::Texture2D*>(window->glDrawData);
+                    cv::ogl::Texture2D* texObj = static_cast<cv::ogl::Texture2D*>(window.glDrawData);
                     size.cx = texObj->cols();
                     size.cy = texObj->rows();
                 }
                 else
                 {
-                    icvGetBitmapData(window, &size, 0, 0);
+                    icvGetBitmapData(window, size);
                 }
 #else
-                icvGetBitmapData( window, &size, 0, 0 );
+                icvGetBitmapData(window, size);
 #endif
 
-                window->on_mouse( event, pt.x*size.cx/MAX(rect.right - rect.left,1),
-                                         pt.y*size.cy/MAX(rect.bottom - rect.top,1), flags,
-                                         window->on_mouse_param );
+                int x = cvRound((float)pt.x*size.cx/MAX(rect.right - rect.left,1));
+                int y = cvRound((float)pt.y*size.cy/MAX(rect.bottom - rect.top,1));
+                window.on_mouse(event, x, y, flags, window.on_mouse_param);
             }
         }
         break;
 
     case WM_PAINT:
-        if(window->image != 0)
+        if (window.image != 0)
         {
             int nchannels = 3;
             SIZE size = {0,0};
@@ -1784,12 +1875,13 @@ static LRESULT CALLBACK HighGUIProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
             RGBQUAD table[256];
 
             // Determine the bitmap's dimensions
-            icvGetBitmapData( window, &size, &nchannels, 0 );
+            void* data = 0;  // unused
+            icvGetBitmapData(window, size, nchannels, data);
 
             hdc = BeginPaint(hwnd, &paint);
             SetStretchBltMode(hdc, COLORONCOLOR);
 
-            if( nchannels == 1 )
+            if (nchannels == 1)
             {
                 int i;
                 for(i = 0; i < 256; i++)
@@ -1798,25 +1890,25 @@ static LRESULT CALLBACK HighGUIProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
                     table[i].rgbGreen = (unsigned char)i;
                     table[i].rgbRed = (unsigned char)i;
                 }
-                SetDIBColorTable(window->dc, 0, 255, table);
+                SetDIBColorTable(window.dc, 0, 255, table);
             }
 
-            if(window->flags & CV_WINDOW_AUTOSIZE)
+            if (window.flags & CV_WINDOW_AUTOSIZE)
             {
-                BitBlt( hdc, 0, 0, size.cx, size.cy, window->dc, 0, 0, SRCCOPY );
+                BitBlt(hdc, 0, 0, size.cx, size.cy, window.dc, 0, 0, SRCCOPY);
             }
             else
             {
                 RECT rect = { 0 };
-                GetClientRect(window->hwnd, &rect);
-                StretchBlt( hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top,
-                            window->dc, 0, 0, size.cx, size.cy, SRCCOPY );
+                GetClientRect(window.hwnd, &rect);
+                StretchBlt(hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top,
+                            window.dc, 0, 0, size.cx, size.cy, SRCCOPY);
             }
             //DeleteDC(hdc);
             EndPaint(hwnd, &paint);
         }
 #ifdef HAVE_OPENGL
-        else if(window->useGl)
+        else if (window.useGl)
         {
             drawGl(window);
             return DefWindowProc(hwnd, uMsg, wParam, lParam);
@@ -1829,13 +1921,13 @@ static LRESULT CALLBACK HighGUIProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
         return 0;
 
     case WM_ERASEBKGND:
-        if(window->image)
+        if (window.image)
             return 0;
         break;
 
     case WM_DESTROY:
 
-        icvRemoveWindow(window);
+        icvRemoveWindow(window_);
         // Do nothing!!!
         //PostQuitMessage(0);
         break;
@@ -1845,15 +1937,15 @@ static LRESULT CALLBACK HighGUIProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
         return 0;
 
     case WM_KEYDOWN:
-        window->last_key = (int)wParam;
+        window.last_key = (int)wParam;
         return 0;
 
     case WM_SIZE:
-        window->width = LOWORD(lParam);
-        window->height = HIWORD(lParam);
+        window.width = LOWORD(lParam);
+        window.height = HIWORD(lParam);
 
 #ifdef HAVE_OPENGL
-        if (window->useGl)
+        if (window.useGl)
             resizeGl(window);
 #endif
     }
@@ -1862,24 +1954,24 @@ static LRESULT CALLBACK HighGUIProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
 }
 
 
-static LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
+static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
     LRESULT ret;
 
-    if( hg_on_preprocess )
+    if (hg_on_preprocess)
     {
         int was_processed = 0;
         int rethg = hg_on_preprocess(hwnd, uMsg, wParam, lParam, &was_processed);
-        if( was_processed )
+        if (was_processed)
             return rethg;
     }
     ret = HighGUIProc(hwnd, uMsg, wParam, lParam);
 
-    if(hg_on_postprocess)
+    if (hg_on_postprocess)
     {
         int was_processed = 0;
         int rethg = hg_on_postprocess(hwnd, uMsg, wParam, lParam, &was_processed);
-        if( was_processed )
+        if (was_processed)
             return rethg;
     }
 
@@ -1887,51 +1979,56 @@ static LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
 }
 
 
-static void icvUpdateTrackbar( CvTrackbar* trackbar, int pos )
+static void icvUpdateTrackbar(CvTrackbar& trackbar, int pos)
 {
     const int max_name_len = 10;
     const char* suffix = "";
     char pos_text[32];
     int name_len;
 
-    if( trackbar->data )
-        *trackbar->data = pos;
+    if (trackbar.data)
+        *trackbar.data = pos;
 
-    if( trackbar->pos != pos )
+    if (trackbar.pos != pos)
     {
-        trackbar->pos = pos;
-        if( trackbar->notify2 )
-            trackbar->notify2(pos, trackbar->userdata);
-        if( trackbar->notify )
-            trackbar->notify(pos);
-
-        name_len = (int)strlen(trackbar->name);
-
-        if( name_len > max_name_len )
+        trackbar.pos = pos;
+        if (trackbar.onChangeCallback)
+            trackbar.onChangeCallback(pos, trackbar.userdata);
+        if (trackbar.notify2)
+            trackbar.notify2(pos, trackbar.userdata);
+        if (trackbar.notify)
+            trackbar.notify(pos);
+
+        name_len = (int)trackbar.name.size();
+
+        // TODO replace C strings manipulation
+        if (name_len > max_name_len)
         {
             int start_len = max_name_len*2/3;
             int end_len = max_name_len - start_len - 2;
-            memcpy( pos_text, trackbar->name, start_len );
-            memcpy( pos_text + start_len, "...", 3 );
-            memcpy( pos_text + start_len + 3, trackbar->name + name_len - end_len, end_len + 1 );
+            memcpy(pos_text, trackbar.name.c_str(), start_len);
+            memcpy(pos_text + start_len, "...", 3);
+            memcpy(pos_text + start_len + 3, trackbar.name.c_str() + name_len - end_len, end_len + 1);
         }
         else
         {
-            memcpy( pos_text, trackbar->name, name_len + 1);
+            memcpy(pos_text, trackbar.name.c_str(), name_len + 1);
         }
 
-        sprintf( pos_text + strlen(pos_text), "%s: %d\n", suffix, pos );
-        SetWindowText( trackbar->buddy, pos_text );
+        sprintf(pos_text + strlen(pos_text), "%s: %d\n", suffix, pos);
+        SetWindowText(trackbar.buddy, pos_text);
     }
 }
 
 
-static LRESULT CALLBACK HGToolbarProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
+static LRESULT CALLBACK HGToolbarProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
-    CvWindow* window = icvWindowByHWND( hwnd );
-    if(!window)
+    auto window_ = icvWindowByHWND(hwnd);
+    if (!window_)
         return DefWindowProc(hwnd, uMsg, wParam, lParam);
 
+    CvWindow& window = *window_;
+
     // Control messages processing
     switch(uMsg)
     {
@@ -1940,32 +2037,34 @@ static LRESULT CALLBACK HGToolbarProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPAR
         {
             HWND slider = (HWND)lParam;
             int pos = (int)SendMessage(slider, TBM_GETPOS, 0, 0);
-            CvTrackbar* trackbar = icvTrackbarByHWND( slider );
+            auto trackbar = icvTrackbarByHWND(slider);
 
-            if( trackbar )
+            if (trackbar)
             {
-                if( trackbar->pos != pos )
-                    icvUpdateTrackbar( trackbar, pos );
+                if (trackbar->pos != pos)
+                    icvUpdateTrackbar(*trackbar, pos);
             }
 
-            SetFocus( window->hwnd );
+            SetFocus(window.hwnd);
             return 0;
         }
 
     case WM_NCCALCSIZE:
         {
-            LRESULT ret = CallWindowProc(window->toolbar.toolBarProc, hwnd, uMsg, wParam, lParam);
+            LRESULT ret = CallWindowProc(window.toolbar.toolBarProc, hwnd, uMsg, wParam, lParam);
             int rows = (int)SendMessage(hwnd, TB_GETROWS, 0, 0);
 
-            if(window->toolbar.rows != rows)
+            if (window.toolbar.rows != rows)
             {
-                SendMessage(window->toolbar.toolbar, TB_BUTTONCOUNT, 0, 0);
-                CvTrackbar* trackbar = window->toolbar.first;
+                SendMessage(window.toolbar.toolbar, TB_BUTTONCOUNT, 0, 0);
+                auto& trakbars = window.toolbar.trackbars;
 
-                for( ; trackbar != 0; trackbar = trackbar->next )
+                for (auto it = trakbars.begin(); it != trakbars.end(); ++it)
                 {
+                    auto trackbar = *it;
+                    CV_Assert(trackbar);
                     RECT rect = { 0 };
-                    SendMessage(window->toolbar.toolbar, TB_GETITEMRECT,
+                    SendMessage(window.toolbar.toolbar, TB_GETITEMRECT,
                                (WPARAM)trackbar->id, (LPARAM)&rect);
                     MoveWindow(trackbar->hwnd, rect.left + HG_BUDDY_WIDTH, rect.top,
                                rect.right - rect.left - HG_BUDDY_WIDTH,
@@ -1973,46 +2072,63 @@ static LRESULT CALLBACK HGToolbarProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPAR
                     MoveWindow(trackbar->buddy, rect.left, rect.top,
                                HG_BUDDY_WIDTH, rect.bottom - rect.top, FALSE);
                 }
-                window->toolbar.rows = rows;
+                window.toolbar.rows = rows;
             }
             return ret;
         }
     }
 
-    return CallWindowProc(window->toolbar.toolBarProc, hwnd, uMsg, wParam, lParam);
+    return CallWindowProc(window.toolbar.toolBarProc, hwnd, uMsg, wParam, lParam);
 }
 
 
 CV_IMPL void
 cvDestroyAllWindows(void)
 {
-    CvWindow* window = hg_windows;
-
-    while( window )
+    std::vector< std::shared_ptr<CvWindow> > g_windows;
     {
-        HWND mainhWnd = window->frame;
-        HWND hwnd = window->hwnd;
-        window = window->next;
+        AutoLock lock(getWindowMutex());
+        g_windows = getWindowsList();  // copy
+    }
+    for (auto it = g_windows.begin(); it != g_windows.end(); ++it)
+    {
+        auto window_ = *it;
+        if (!window_)
+            continue;
+
+        {
+            CvWindow& window = *window_;
+
+            HWND mainhWnd = window.frame;
+            HWND hwnd = window.hwnd;
+
+            SendMessage(hwnd, WM_CLOSE, 0, 0);
+            SendMessage(mainhWnd, WM_CLOSE, 0, 0);
+        }
 
-        SendMessage( hwnd, WM_CLOSE, 0, 0 );
-        SendMessage( mainhWnd, WM_CLOSE, 0, 0 );
+        window_.reset();
+    }
+    // TODO needed?
+    {
+        AutoLock lock(getWindowMutex());
+        getWindowsList().clear();
     }
 }
 
-static void showSaveDialog(CvWindow* window)
+static void showSaveDialog(CvWindow& window)
 {
-    if (!window || !window->image)
+    if (!window.image)
         return;
 
     SIZE sz;
     int channels;
     void* data;
-    if (icvGetBitmapData(window, &sz, &channels, &data))
+    if (icvGetBitmapData(window, sz, channels, data))
         return; // nothing to save
 
     char szFileName[MAX_PATH] = "";
     // try to use window title as file name
-    GetWindowText(window->frame, szFileName, MAX_PATH);
+    GetWindowText(window.frame, szFileName, MAX_PATH);
 
     OPENFILENAME ofn;
     ZeroMemory(&ofn, sizeof(ofn));
@@ -2022,7 +2138,7 @@ static void showSaveDialog(CvWindow* window)
 #else
     ofn.lStructSize = sizeof(ofn);
 #endif
-    ofn.hwndOwner = window->hwnd;
+    ofn.hwndOwner = window.hwnd;
     ofn.lpstrFilter =
 #ifdef HAVE_PNG
                       "Portable Network Graphics files (*.png)\0*.png\0"
@@ -2075,9 +2191,15 @@ static bool handleMessage(MSG& message, int& keyCode)
     // otherwise the message was handled specifically
     bool is_processed = false;
 
-    for (CvWindow* window = hg_windows; window != 0 && is_processed == 0; window = window->next)
+    AutoLock lock(getWindowMutex());
+    auto& g_windows = getWindowsList();
+    for (auto it = g_windows.begin(); it != g_windows.end() && !is_processed; ++it)
     {
-        if (!(window->hwnd == message.hwnd || window->frame == message.hwnd))
+        auto window_ = *it;
+        if (!window_)
+            continue;
+        CvWindow& window = *window_;
+        if (!(window.hwnd == message.hwnd || window.frame == message.hwnd))
             continue;
 
         is_processed = true;
@@ -2140,7 +2262,7 @@ static bool handleMessage(MSG& message, int& keyCode)
 /*
  * process until queue is empty but don't wait.
  */
-int cv::pollKey()
+int pollKey_W32()
 {
     CV_TRACE_FUNCTION();
     for(;;)
@@ -2156,7 +2278,7 @@ int cv::pollKey()
 }
 
 CV_IMPL int
-cvWaitKey( int delay )
+cvWaitKey(int delay)
 {
     int64 time0 = cv::getTickCount();
     int64 timeEnd = time0 + (int64)(delay * 0.001f * cv::getTickFrequency());
@@ -2165,9 +2287,9 @@ cvWaitKey( int delay )
     {
         MSG message;
 
-        if( (delay <= 0) && hg_windows)
+        if ((delay <= 0) && !getWindowsList().empty())
             GetMessage(&message, 0, 0, 0);
-        else if( PeekMessage(&message, 0, 0, 0, PM_REMOVE) == FALSE )
+        else if (PeekMessage(&message, 0, 0, 0, PM_REMOVE) == FALSE)
         {
             int64 t = cv::getTickCount();
             if (t - timeEnd >= 0)
@@ -2183,110 +2305,135 @@ cvWaitKey( int delay )
 }
 
 
-static CvTrackbar*
-icvFindTrackbarByName( const CvWindow* window, const char* name )
+static
+std::shared_ptr<CvTrackbar> icvFindTrackbarByName(CvWindow& window, const std::string& name)
 {
-    CvTrackbar* trackbar = window->toolbar.first;
-
-    for( ; trackbar != 0 && strcmp( trackbar->name, name ) != 0; trackbar = trackbar->next )
-        ;
-
-    return trackbar;
+    auto trackbars = window.toolbar.trackbars;
+    for (auto it = trackbars.begin(); it != trackbars.end(); ++it)
+    {
+        auto& trackbar = *it;
+        CV_Assert(trackbar);
+        if (trackbar->name == name)
+            return trackbar;
+    }
+    return std::shared_ptr<CvTrackbar>();
+}
+static inline
+std::shared_ptr<CvTrackbar> icvFindTrackbarByName(const std::shared_ptr<CvWindow>& window, const std::string& name)
+{
+    CV_Assert(window);
+    return icvFindTrackbarByName(window, name);
 }
 
+static
+std::shared_ptr<CvTrackbar> createTrackbar_(CvWindow& window, const std::string& trackbar_name,
+    int count,
+    TrackbarCallback onChange, void* userdata);
 
 static int
-icvCreateTrackbar( const char* trackbar_name, const char* window_name,
-                   int* val, int count, CvTrackbarCallback on_notify,
-                   CvTrackbarCallback2 on_notify2, void* userdata )
+icvCreateTrackbar(const char* trackbar_name, const char* window_name,
+                  int* val, int count, CvTrackbarCallback on_notify,
+                  CvTrackbarCallback2 on_notify2, void* userdata)
 {
-    int result = 0;
+    CV_FUNCNAME("icvCreateTrackbar");
 
-    CV_FUNCNAME( "icvCreateTrackbar" );
+    AutoLock lock(getWindowMutex());
 
-    __BEGIN__;
+    if (!window_name || !trackbar_name)
+        CV_Error(Error::StsNullPtr, "NULL window or trackbar name");
 
-    char slider_name[32];
-    CvWindow* window = 0;
-    CvTrackbar* trackbar = 0;
-    int pos = 0;
+    if (count < 0)
+        CV_Error(Error::StsOutOfRange, "Bad trackbar maximal value");
 
-    if( !window_name || !trackbar_name )
-        CV_ERROR( CV_StsNullPtr, "NULL window or trackbar name" );
+    auto window = icvFindWindowByName(window_name);
+    if (!window)
+        CV_Error_(Error::StsNullPtr, ("NULL window: '%s'", window_name));
 
-    if( count < 0 )
-        CV_ERROR( CV_StsOutOfRange, "Bad trackbar maximal value" );
+    auto trackbar = icvFindTrackbarByName(*window, trackbar_name);
+    if (!trackbar)
+        trackbar = createTrackbar_(*window, trackbar_name, count, nullptr, userdata);
+    CV_Assert(trackbar);
 
-    window = icvFindWindowByName(window_name);
-    if( !window )
-        EXIT;
+    trackbar->notify = on_notify;
+    trackbar->notify2 = on_notify2;
+    trackbar->userdata = userdata;
+    trackbar->data = val;
 
-    trackbar = icvFindTrackbarByName(window,trackbar_name);
-    if( !trackbar )
-    {
-        TBBUTTON tbs = {};
-        TBBUTTONINFO tbis = {};
-        RECT rect = { 0 };
-        int bcount;
-        int len = (int)strlen( trackbar_name );
+    return 1;
+}
 
-        // create toolbar if it is not created yet
-        if( !window->toolbar.toolbar )
-        {
-            const int default_height = 30;
-
-            // CreateToolbarEx is deprecated and forces linking against Comctl32.lib.
-            window->toolbar.toolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
-                                        WS_CHILD | CCS_TOP | TBSTYLE_WRAPABLE | BTNS_AUTOSIZE | BTNS_BUTTON,
-                                        0, 0, 0, 0,
-                                        window->frame, NULL, GetModuleHandle(NULL), NULL);
-            // CreateToolbarEx automatically sends this but CreateWindowEx doesn't.
-            SendMessage(window->toolbar.toolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
-
-            GetClientRect(window->frame, &rect);
-            MoveWindow( window->toolbar.toolbar, 0, 0,
-                        rect.right - rect.left, default_height, TRUE);
-            SendMessage(window->toolbar.toolbar, TB_AUTOSIZE, 0, 0);
-            ShowWindow(window->toolbar.toolbar, SW_SHOW);
-
-            window->toolbar.first = 0;
-            window->toolbar.pos = 0;
-            window->toolbar.rows = 0;
-            window->toolbar.toolBarProc =
-                (WNDPROC)icvGetWindowLongPtr(window->toolbar.toolbar, CV_WNDPROC);
-
-            icvUpdateWindowPos(window);
-
-            // Subclassing from toolbar
-            icvSetWindowLongPtr(window->toolbar.toolbar, CV_WNDPROC, HGToolbarProc);
-            icvSetWindowLongPtr(window->toolbar.toolbar, CV_USERDATA, window);
-        }
+static void createToolbar_(CvWindow& window)
+{
+    CV_Assert(!window.toolbar.toolbar);
+
+    const int default_height = 30;
+
+    // CreateToolbarEx is deprecated and forces linking against Comctl32.lib.
+    window.toolbar.toolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
+                                WS_CHILD | CCS_TOP | TBSTYLE_WRAPABLE | BTNS_AUTOSIZE | BTNS_BUTTON,
+                                0, 0, 0, 0,
+                                window.frame, NULL, GetModuleHandle(NULL), NULL);
+    // CreateToolbarEx automatically sends this but CreateWindowEx doesn't.
+    SendMessage(window.toolbar.toolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
+
+    RECT rect;
+    GetClientRect(window.frame, &rect);
+    MoveWindow(window.toolbar.toolbar, 0, 0,
+               rect.right - rect.left, default_height, TRUE);
+    SendMessage(window.toolbar.toolbar, TB_AUTOSIZE, 0, 0);
+    ShowWindow(window.toolbar.toolbar, SW_SHOW);
+
+    window.toolbar.pos = 0;
+    window.toolbar.rows = 0;
+    window.toolbar.toolBarProc =
+        (WNDPROC)icvGetWindowLongPtr(window.toolbar.toolbar, CV_WNDPROC);
 
-        /* Retrieve current buttons count */
-        bcount = (int)SendMessage(window->toolbar.toolbar, TB_BUTTONCOUNT, 0, 0);
+    icvUpdateWindowPos(window);
 
-        if(bcount > 1)
-        {
-            /* If this is not the first button then we need to
-            separate it from the previous one */
-            tbs.iBitmap = 0;
-            tbs.idCommand = bcount; // Set button id to it's number
-            tbs.iString = 0;
-            tbs.fsStyle = TBSTYLE_SEP;
-            tbs.fsState = TBSTATE_ENABLED;
-            SendMessage(window->toolbar.toolbar, TB_ADDBUTTONS, 1, (LPARAM)&tbs);
-
-            // Retrieve current buttons count
-            bcount = (int)SendMessage(window->toolbar.toolbar, TB_BUTTONCOUNT, 0, 0);
-        }
+    // Subclassing from toolbar
+    icvSetWindowLongPtr(window.toolbar.toolbar, CV_WNDPROC, HGToolbarProc);
+    icvSetWindowLongPtr(window.toolbar.toolbar, CV_USERDATA, (void*)&window);
+
+}
+
+static
+std::shared_ptr<CvTrackbar> createTrackbar_(CvWindow& window, const std::string& trackbar_name,
+    int count,
+    TrackbarCallback onChange, void* userdata)
+{
+    // create toolbar if it is not created yet
+    if (!window.toolbar.toolbar)
+    {
+        createToolbar_(window);
+    }
+
+    TBBUTTON tbs = {};
 
-        /* Add a button which we're going to cover with the slider */
+    /* Retrieve current buttons count */
+    int bcount = (int)SendMessage(window.toolbar.toolbar, TB_BUTTONCOUNT, 0, 0);
+
+    if (bcount > 1)
+    {
+        /* If this is not the first button then we need to
+        separate it from the previous one */
         tbs.iBitmap = 0;
         tbs.idCommand = bcount; // Set button id to it's number
+        tbs.iString = 0;
+        tbs.fsStyle = TBSTYLE_SEP;
         tbs.fsState = TBSTATE_ENABLED;
+        SendMessage(window.toolbar.toolbar, TB_ADDBUTTONS, 1, (LPARAM)&tbs);
+
+        // Retrieve current buttons count
+        bcount = (int)SendMessage(window.toolbar.toolbar, TB_BUTTONCOUNT, 0, 0);
+    }
+
+    /* Add a button which we're going to cover with the slider */
+    tbs.iBitmap = 0;
+    tbs.idCommand = bcount; // Set button id to it's number
+    tbs.fsState = TBSTATE_ENABLED;
 #if 0/*!defined WIN64 && !defined EM64T*/
-        tbs.fsStyle = 0;
-        tbs.iString = 0;
+    tbs.fsStyle = 0;
+    tbs.iString = 0;
 #else
 
 #ifndef TBSTYLE_AUTOSIZE
@@ -2296,320 +2443,640 @@ icvCreateTrackbar( const char* trackbar_name, const char* window_name,
 #ifndef TBSTYLE_GROUP
 #define TBSTYLE_GROUP           0x0004
 #endif
-        //tbs.fsStyle = TBSTYLE_AUTOSIZE;
-        tbs.fsStyle = TBSTYLE_GROUP;
-        tbs.iString = (INT_PTR)trackbar_text;
+    //tbs.fsStyle = TBSTYLE_AUTOSIZE;
+    tbs.fsStyle = TBSTYLE_GROUP;
+    tbs.iString = (INT_PTR)trackbar_text;
 #endif
-        SendMessage(window->toolbar.toolbar, TB_ADDBUTTONS, 1, (LPARAM)&tbs);
-
-        /* Adjust button size to the slider */
-        tbis.cbSize = sizeof(tbis);
-        tbis.dwMask = TBIF_SIZE;
-
-        GetClientRect(window->hwnd, &rect);
-        tbis.cx = (unsigned short)(rect.right - rect.left);
-
-        SendMessage(window->toolbar.toolbar, TB_SETBUTTONINFO,
-            (WPARAM)tbs.idCommand, (LPARAM)&tbis);
-
-        /* Get button pos */
-        SendMessage(window->toolbar.toolbar, TB_GETITEMRECT,
-            (WPARAM)tbs.idCommand, (LPARAM)&rect);
-
-        /* Create a slider */
-        trackbar = (CvTrackbar*)cvAlloc( sizeof(CvTrackbar) + len + 1 );
-        trackbar->signature = CV_TRACKBAR_MAGIC_VAL;
-        trackbar->notify = 0;
-        trackbar->notify2 = 0;
-        trackbar->parent = window;
-        trackbar->pos = 0;
-        trackbar->data = 0;
-        trackbar->id = bcount;
-        trackbar->next = window->toolbar.first;
-        trackbar->name = (char*)(trackbar + 1);
-        memcpy( trackbar->name, trackbar_name, len + 1 );
-        window->toolbar.first = trackbar;
-
-        sprintf(slider_name, "Trackbar%p", val);
-        trackbar->hwnd = CreateWindowEx(0, TRACKBAR_CLASS, slider_name,
-                            WS_CHILD | WS_VISIBLE | TBS_AUTOTICKS |
-                            TBS_FIXEDLENGTH | TBS_HORZ | TBS_BOTTOM,
-                            rect.left + HG_BUDDY_WIDTH, rect.top,
-                            rect.right - rect.left - HG_BUDDY_WIDTH,
-                            rect.bottom - rect.top, window->toolbar.toolbar,
-                            (HMENU)(size_t)bcount, hg_hinstance, 0);
-
-        sprintf(slider_name,"Buddy%p", val);
-        trackbar->buddy = CreateWindowEx(0, "STATIC", slider_name,
-                            WS_CHILD | SS_RIGHT,
-                            rect.left, rect.top,
-                            HG_BUDDY_WIDTH, rect.bottom - rect.top,
-                            window->toolbar.toolbar, 0, hg_hinstance, 0);
-
-        icvSetWindowLongPtr( trackbar->hwnd, CV_USERDATA, trackbar );
-
-        /* Minimize the number of rows */
-        SendMessage( window->toolbar.toolbar, TB_SETROWS,
-                     MAKEWPARAM(1, FALSE), (LPARAM)&rect );
-    }
-    else
-    {
-        trackbar->data = 0;
-        trackbar->notify = 0;
-        trackbar->notify2 = 0;
-    }
+    SendMessage(window.toolbar.toolbar, TB_ADDBUTTONS, 1, (LPARAM)&tbs);
+
+    TBBUTTONINFO tbis = {};
+
+    /* Adjust button size to the slider */
+    tbis.cbSize = sizeof(tbis);
+    tbis.dwMask = TBIF_SIZE;
+
+    RECT rect = { 0 };
+    GetClientRect(window.hwnd, &rect);
+    tbis.cx = (unsigned short)(rect.right - rect.left);
+
+    SendMessage(window.toolbar.toolbar, TB_SETBUTTONINFO,
+        (WPARAM)tbs.idCommand, (LPARAM)&tbis);
+
+    /* Get button pos */
+    SendMessage(window.toolbar.toolbar, TB_GETITEMRECT,
+        (WPARAM)tbs.idCommand, (LPARAM)&rect);
+
+    /* Create a slider */
+    auto trackbar = std::make_shared<CvTrackbar>(window, trackbar_name);
+    trackbar->id = bcount;
+    window.toolbar.trackbars.push_back(trackbar);
+
+    auto slider_name = cv::format("Trackbar%p", trackbar.get());
+    trackbar->hwnd = CreateWindowEx(0, TRACKBAR_CLASS, slider_name.c_str(),
+                        WS_CHILD | WS_VISIBLE | TBS_AUTOTICKS |
+                        TBS_FIXEDLENGTH | TBS_HORZ | TBS_BOTTOM,
+                        rect.left + HG_BUDDY_WIDTH, rect.top,
+                        rect.right - rect.left - HG_BUDDY_WIDTH,
+                        rect.bottom - rect.top, window.toolbar.toolbar,
+                        (HMENU)(size_t)bcount, hg_hinstance, 0);
+
+    slider_name = cv::format("Buddy%p", trackbar.get());
+    trackbar->buddy = CreateWindowEx(0, "STATIC", slider_name.c_str(),
+                        WS_CHILD | SS_RIGHT,
+                        rect.left, rect.top,
+                        HG_BUDDY_WIDTH, rect.bottom - rect.top,
+                        window.toolbar.toolbar, 0, hg_hinstance, 0);
+
+    icvSetWindowLongPtr(trackbar->hwnd, CV_USERDATA, (void*)trackbar.get());
+
+    /* Minimize the number of rows */
+    SendMessage(window.toolbar.toolbar, TB_SETROWS,
+                MAKEWPARAM(1, FALSE), (LPARAM)&rect);
 
     trackbar->maxval = count;
 
     /* Adjust slider parameters */
     SendMessage(trackbar->hwnd, TBM_SETRANGEMIN, (WPARAM)TRUE, (LPARAM)0);
     SendMessage(trackbar->hwnd, TBM_SETRANGEMAX, (WPARAM)TRUE, (LPARAM)count);
-    SendMessage(trackbar->hwnd, TBM_SETTICFREQ, (WPARAM)1, (LPARAM)0 );
-    if( val )
-        pos = *val;
+    SendMessage(trackbar->hwnd, TBM_SETTICFREQ, (WPARAM)1, (LPARAM)0);
 
-    SendMessage(trackbar->hwnd, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos );
-    SendMessage(window->toolbar.toolbar, TB_AUTOSIZE, 0, 0);
+    int pos = 0;
+    SendMessage(trackbar->hwnd, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos);
+    SendMessage(window.toolbar.toolbar, TB_AUTOSIZE, 0, 0);
 
     trackbar->pos = -1;
-    icvUpdateTrackbar( trackbar, pos );
-    ShowWindow( trackbar->buddy, SW_SHOW );
-    ShowWindow( trackbar->hwnd, SW_SHOW );
-
-    trackbar->notify = on_notify;
-    trackbar->notify2 = on_notify2;
-    trackbar->userdata = userdata;
-    trackbar->data = val;
+    icvUpdateTrackbar(*trackbar, pos);
+    ShowWindow(trackbar->buddy, SW_SHOW);
+    ShowWindow(trackbar->hwnd, SW_SHOW);
 
     /* Resize the window to reflect the toolbar resizing*/
     icvUpdateWindowPos(window);
 
-    result = 1;
-
-    __END__;
+    trackbar->onChangeCallback = onChange;
+    trackbar->userdata = userdata;
 
-    return result;
+    return trackbar;
 }
 
 CV_IMPL int
-cvCreateTrackbar( const char* trackbar_name, const char* window_name,
-                  int* val, int count, CvTrackbarCallback on_notify )
+cvCreateTrackbar(const char* trackbar_name, const char* window_name,
+                 int* val, int count, CvTrackbarCallback on_notify)
 {
-    return icvCreateTrackbar( trackbar_name, window_name, val, count,
-        on_notify, 0, 0 );
+    return icvCreateTrackbar(trackbar_name, window_name, val, count,
+        on_notify, 0, 0);
 }
 
 CV_IMPL int
-cvCreateTrackbar2( const char* trackbar_name, const char* window_name,
-                   int* val, int count, CvTrackbarCallback2 on_notify2,
-                   void* userdata )
+cvCreateTrackbar2(const char* trackbar_name, const char* window_name,
+                  int* val, int count, CvTrackbarCallback2 on_notify2,
+                  void* userdata)
 {
-    return icvCreateTrackbar( trackbar_name, window_name, val, count,
-        0, on_notify2, userdata );
+    return icvCreateTrackbar(trackbar_name, window_name, val, count,
+        0, on_notify2, userdata);
 }
 
 CV_IMPL void
-cvSetMouseCallback( const char* window_name, CvMouseCallback on_mouse, void* param )
+cvSetMouseCallback(const char* name, CvMouseCallback on_mouse, void* param)
 {
-    CV_FUNCNAME( "cvSetMouseCallback" );
-
-    __BEGIN__;
+    CV_FUNCNAME("cvSetMouseCallback");
 
-    CvWindow* window = 0;
+    if (!name)
+        CV_Error(Error::StsNullPtr, "NULL window name");
 
-    if( !window_name )
-        CV_ERROR( CV_StsNullPtr, "NULL window name" );
+    AutoLock lock(getWindowMutex());
 
-    window = icvFindWindowByName(window_name);
-    if( !window )
-        EXIT;
+    auto window = icvFindWindowByName(name);
+    if (!window)
+        CV_Error_(Error::StsNullPtr, ("NULL window: '%s'", name));
 
     window->on_mouse = on_mouse;
     window->on_mouse_param = param;
-
-    __END__;
 }
 
 
-CV_IMPL int cvGetTrackbarPos( const char* trackbar_name, const char* window_name )
+CV_IMPL int cvGetTrackbarPos(const char* trackbar_name, const char* window_name)
 {
-    int pos = -1;
-
-    CV_FUNCNAME( "cvGetTrackbarPos" );
+    CV_FUNCNAME("cvGetTrackbarPos");
 
-    __BEGIN__;
+    AutoLock lock(getWindowMutex());
 
-    CvWindow* window;
-    CvTrackbar* trackbar = 0;
+    if (trackbar_name == 0 || window_name == 0)
+        CV_Error(Error::StsNullPtr, "NULL trackbar or window name");
 
-    if( trackbar_name == 0 || window_name == 0 )
-        CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
-
-    window = icvFindWindowByName( window_name );
-    if( window )
-        trackbar = icvFindTrackbarByName( window, trackbar_name );
-
-    if( trackbar )
-        pos = trackbar->pos;
+    auto window = icvFindWindowByName(window_name);
+    if (!window)
+        CV_Error_(Error::StsNullPtr, ("NULL window: '%s'", window_name));
 
-    __END__;
+    auto trackbar = icvFindTrackbarByName(window, trackbar_name);
+    if (!trackbar)
+        CV_Error_(Error::StsNullPtr, ("NULL trackbar: '%s'", trackbar_name));
 
-    return pos;
+    return trackbar->pos;
 }
 
 
-CV_IMPL void cvSetTrackbarPos( const char* trackbar_name, const char* window_name, int pos )
+CV_IMPL void cvSetTrackbarPos(const char* trackbar_name, const char* window_name, int pos)
 {
-    CV_FUNCNAME( "cvSetTrackbarPos" );
+    CV_FUNCNAME("cvSetTrackbarPos");
 
-    __BEGIN__;
+    AutoLock lock(getWindowMutex());
 
-    CvWindow* window;
-    CvTrackbar* trackbar = 0;
+    if (trackbar_name == 0 || window_name == 0)
+        CV_Error(Error::StsNullPtr, "NULL trackbar or window name");
 
-    if( trackbar_name == 0 || window_name == 0 )
-        CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
+    auto window = icvFindWindowByName(window_name);
+    if (!window)
+        CV_Error_(Error::StsNullPtr, ("NULL window: '%s'", window_name));
 
-    window = icvFindWindowByName( window_name );
-    if( window )
-        trackbar = icvFindTrackbarByName( window, trackbar_name );
+    auto trackbar = icvFindTrackbarByName(window, trackbar_name);
+    if (!trackbar)
+        CV_Error_(Error::StsNullPtr, ("NULL trackbar: '%s'", trackbar_name));
 
-    if( trackbar )
     {
-        if( pos < 0 )
+        if (pos < 0)
             pos = 0;
 
-        if( pos > trackbar->maxval )
+        if (pos > trackbar->maxval)
             pos = trackbar->maxval;
 
-        SendMessage( trackbar->hwnd, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos );
-        icvUpdateTrackbar( trackbar, pos );
+        SendMessage(trackbar->hwnd, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos);
+        icvUpdateTrackbar(*trackbar, pos);
     }
-
-    __END__;
 }
 
 
 CV_IMPL void cvSetTrackbarMax(const char* trackbar_name, const char* window_name, int maxval)
 {
-    CV_FUNCNAME( "cvSetTrackbarMax" );
+    CV_FUNCNAME("cvSetTrackbarMax");
+
+    if (trackbar_name == 0 || window_name == 0)
+    {
+        CV_Error(Error::StsNullPtr, "NULL trackbar or window name");
+    }
+
+    AutoLock lock(getWindowMutex());
+
+    auto window = icvFindWindowByName(window_name);
+    if (!window)
+        CV_Error_(Error::StsNullPtr, ("NULL window: '%s'", window_name));
 
-    __BEGIN__;
+    auto trackbar = icvFindTrackbarByName(window, trackbar_name);
+    if (!trackbar)
+        CV_Error_(Error::StsNullPtr, ("NULL trackbar: '%s'", trackbar_name));
 
+    // FIXIT
     if (maxval >= 0)
     {
-        CvWindow* window = 0;
-        CvTrackbar* trackbar = 0;
-        if (trackbar_name == 0 || window_name == 0)
+        // The position will be min(pos, maxval).
+        trackbar->maxval = (trackbar->minval>maxval)?trackbar->minval:maxval;
+        SendMessage(trackbar->hwnd, TBM_SETRANGEMAX, (WPARAM)TRUE, (LPARAM)maxval);
+    }
+}
+
+
+CV_IMPL void cvSetTrackbarMin(const char* trackbar_name, const char* window_name, int minval)
+{
+    CV_FUNCNAME("cvSetTrackbarMin");
+
+    if (trackbar_name == 0 || window_name == 0)
+    {
+        CV_Error(Error::StsNullPtr, "NULL trackbar or window name");
+    }
+
+    AutoLock lock(getWindowMutex());
+
+    auto window = icvFindWindowByName(window_name);
+    if (!window)
+        CV_Error_(Error::StsNullPtr, ("NULL window: '%s'", window_name));
+
+    auto trackbar = icvFindTrackbarByName(window, trackbar_name);
+    if (!trackbar)
+        CV_Error_(Error::StsNullPtr, ("NULL trackbar: '%s'", trackbar_name));
+
+    // FIXIT
+    if (minval >= 0)
+    {
+        // The position will be min(pos, maxval).
+        trackbar->minval = (minval<trackbar->maxval)?minval:trackbar->maxval;
+        SendMessage(trackbar->hwnd, TBM_SETRANGEMIN, (WPARAM)TRUE, (LPARAM)minval);
+    }
+}
+
+
+CV_IMPL void* cvGetWindowHandle(const char* window_name)
+{
+    CV_FUNCNAME("cvGetWindowHandle");
+
+    AutoLock lock(getWindowMutex());
+
+    if (window_name == 0)
+        CV_Error(Error::StsNullPtr, "NULL window name");
+
+    auto window = icvFindWindowByName(window_name);
+    if (!window)
+        CV_Error_(Error::StsNullPtr, ("NULL window: '%s'", window_name));
+
+    return (void*)window->hwnd;
+}
+
+// FIXIT: result is not safe to use
+CV_IMPL const char* cvGetWindowName(void* window_handle)
+{
+    CV_FUNCNAME("cvGetWindowName");
+
+    AutoLock lock(getWindowMutex());
+
+    if (window_handle == 0)
+        CV_Error(Error::StsNullPtr, "NULL window handle");
+
+    auto window = icvWindowByHWND((HWND)window_handle);
+    if (!window)
+        CV_Error_(Error::StsNullPtr, ("NULL window: '%p'", window_handle));
+
+    return window->name.c_str();
+}
+
+
+CV_IMPL void
+cvSetPreprocessFuncWin32_(const void* callback)
+{
+    hg_on_preprocess = (CvWin32WindowCallback)callback;
+}
+
+CV_IMPL void
+cvSetPostprocessFuncWin32_(const void* callback)
+{
+    hg_on_postprocess = (CvWin32WindowCallback)callback;
+}
+
+
+
+namespace cv { namespace impl {
+
+using namespace cv::highgui_backend;
+
+class Win32UITrackbar;
+
+class Win32UIWindow
+        : public UIWindow
+        , public std::enable_shared_from_this<Win32UIWindow>
+{
+protected:
+    const std::string name_;
+    std::weak_ptr<CvWindow> window_;
+    std::map<std::string, std::shared_ptr<Win32UITrackbar> > trackbars_;
+public:
+    Win32UIWindow(const std::string& name, const std::shared_ptr<CvWindow>& window)
+        : name_(name)
+        , window_(window)
+    {
+        // nothing
+    }
+
+    ~Win32UIWindow() CV_OVERRIDE
+    {
+        if (!window_.expired())
+            destroy();
+        CV_LOG_DEBUG(NULL, "OpenCV/UI/Win32UI: Win32UIWindow(" << name_ << ") is disposed");
+    }
+
+    const std::string& getID() const CV_OVERRIDE { return name_; }
+
+    bool isActive() const CV_OVERRIDE { return !window_.expired(); }
+
+    void destroy() CV_OVERRIDE
+    {
+        cv::AutoLock lock(getWindowMutex());
+        if (!window_.expired())
         {
-            CV_ERROR(CV_StsNullPtr, "NULL trackbar or window name");
+            auto window = window_.lock();
+            if (window)
+                window->destroy();
+            window_.reset();
         }
+    }
 
-        window = icvFindWindowByName(window_name);
-        if (window)
+    void imshow(InputArray image) CV_OVERRIDE
+    {
+        auto window_ptr = window_.lock();
+        CV_Assert(window_ptr);
+        CvWindow& window = *window_ptr;
+        Mat image_mat = image.getMat();
+        showImage_(window, image_mat);
+    }
+
+    double getProperty(int prop) const CV_OVERRIDE
+    {
+        auto window_ptr = window_.lock();
+        CV_Assert(window_ptr);
+        CvWindow& window = *window_ptr;
+        // see cvGetWindowProperty
+        switch ((WindowPropertyFlags)prop)
         {
-            trackbar = icvFindTrackbarByName(window, trackbar_name);
-            if (trackbar)
-            {
-                // The position will be min(pos, maxval).
-                trackbar->maxval = (trackbar->minval>maxval)?trackbar->minval:maxval;
-                SendMessage(trackbar->hwnd, TBM_SETRANGEMAX, (WPARAM)TRUE, (LPARAM)maxval);
-            }
+        case WND_PROP_FULLSCREEN:
+            return (double)window.status;
+
+        case WND_PROP_AUTOSIZE:
+            return (window.flags & WINDOW_AUTOSIZE) ? 1.0 : 0.0;
+
+        case WND_PROP_ASPECT_RATIO:
+            return static_cast<double>(window.width) / window.height;
+
+#ifdef HAVE_OPENGL
+        case WND_PROP_OPENGL:
+            return window.useGl ? 1.0 : 0.0;
+#endif
+
+        case WND_PROP_VISIBLE:
+            return 1.0;
+
+        case WND_PROP_TOPMOST:
+            return getPropTopmost_(window);
+
+        case WND_PROP_VSYNC:
+            return getPropVsync_(window);
+
+        // don't use default, add unsupported cases below:
+        // case WND_PROP_UNSUPPORTED:  // fallthru
+        //    break;
         }
+        return std::numeric_limits<double>::quiet_NaN();
     }
 
-    __END__;
-}
+    bool setProperty(int prop, double value) CV_OVERRIDE
+    {
+        auto window_ptr = window_.lock();
+        CV_Assert(window_ptr);
+        CvWindow& window = *window_ptr;
+        // see cvSetWindowProperty
+        switch ((WindowPropertyFlags)prop)
+        {
+        case WND_PROP_FULLSCREEN:
+            if (value != WINDOW_NORMAL && value != WINDOW_FULLSCREEN)  // bad arg
+                break;
+            setModeWindow_(window, (int)value);
+            return true;
 
+        case WND_PROP_TOPMOST:
+            return setPropTopmost_(window, value != 0.0);
 
-CV_IMPL void cvSetTrackbarMin(const char* trackbar_name, const char* window_name, int minval)
-{
-    CV_FUNCNAME( "cvSetTrackbarMin" );
+        case WND_PROP_VSYNC:
+            return setPropVsync_(window, value != 0.0);
 
-    __BEGIN__;
+        // don't use default, add unsupported cases below:
+        // case WND_PROP_UNSUPPORTED:  // fallthru
+        case WND_PROP_AUTOSIZE:  // fallthru
+        case WND_PROP_ASPECT_RATIO:  // fallthru
+        case WND_PROP_OPENGL:  // fallthru
+        case WND_PROP_VISIBLE:  // fallthru
+            break;
+        }
+        return false;
+    }
 
-    if (minval >= 0)
+    void resize(int width, int height) CV_OVERRIDE
     {
-        CvWindow* window = 0;
-        CvTrackbar* trackbar = 0;
-        if (trackbar_name == 0 || window_name == 0)
+        auto window_ptr = window_.lock();
+        CV_Assert(window_ptr);
+        CvWindow& window = *window_ptr;
+        resizeWindow_(window, Size(width, height));
+    }
+
+    void move(int x, int y) CV_OVERRIDE
+    {
+        auto window_ptr = window_.lock();
+        CV_Assert(window_ptr);
+        CvWindow& window = *window_ptr;
+        moveWindow_(window, Point(x, y));
+    }
+
+    Rect getImageRect() const CV_OVERRIDE
+    {
+        auto window_ptr = window_.lock();
+        CV_Assert(window_ptr);
+        CvWindow& window = *window_ptr;
+        return getImageRect_(window);
+    }
+
+    void setTitle(const std::string& title) CV_OVERRIDE
+    {
+        auto window_ptr = window_.lock();
+        CV_Assert(window_ptr);
+        CvWindow& window = *window_ptr;
+        if (!SetWindowText(window.frame, title.c_str()))
+            CV_Error_(Error::StsError, ("Failed to set \"%s\" window title to \"%s\"", window.name.c_str(), title.c_str()));
+    }
+
+    void setMouseCallback(MouseCallback onMouse, void* userdata /*= 0*/) CV_OVERRIDE
+    {
+        auto window_ptr = window_.lock();
+        CV_Assert(window_ptr);
+        CvWindow& window = *window_ptr;
+        window.on_mouse = onMouse;
+        window.on_mouse_param = userdata;
+    }
+
+    std::shared_ptr<UITrackbar> createTrackbar(
+        const std::string& name,
+        int count,
+        TrackbarCallback onChange /*= 0*/,
+        void* userdata /*= 0*/
+    ) CV_OVERRIDE
+    {
+        auto window_ptr = window_.lock();
+        CV_Assert(window_ptr);
+        CvWindow& window = *window_ptr;
+        CV_LOG_INFO(NULL, "OpenCV/UI: Creating Win32UI trackbar at '" << name_ << "': '" << name << "'");
+        auto trackbar = createTrackbar_(window, name, count, onChange, userdata);
+        auto ui_trackbar = std::make_shared<Win32UITrackbar>(name, trackbar, shared_from_this());
         {
-            CV_ERROR(CV_StsNullPtr, "NULL trackbar or window name");
+            cv::AutoLock lock(getWindowMutex());
+            trackbars_.emplace(name, ui_trackbar);
         }
+        return std::static_pointer_cast<UITrackbar>(ui_trackbar);
+    }
 
-        window = icvFindWindowByName(window_name);
-        if (window)
+    std::shared_ptr<UITrackbar> findTrackbar(const std::string& name) CV_OVERRIDE
+    {
+        cv::AutoLock lock(getWindowMutex());
+        auto i = trackbars_.find(name);
+        if (i != trackbars_.end())
         {
-            trackbar = icvFindTrackbarByName(window, trackbar_name);
-            if (trackbar)
-            {
-                // The position will be min(pos, maxval).
-                trackbar->minval = (minval<trackbar->maxval)?minval:trackbar->maxval;
-                SendMessage(trackbar->hwnd, TBM_SETRANGEMIN, (WPARAM)TRUE, (LPARAM)minval);
-            }
+            return std::static_pointer_cast<UITrackbar>(i->second);
         }
+        return std::shared_ptr<UITrackbar>();
     }
-
-    __END__;
-}
+};  // Win32UIWindow
 
 
-CV_IMPL void* cvGetWindowHandle( const char* window_name )
+class Win32UITrackbar : public UITrackbar
 {
-    void* hwnd = 0;
+protected:
+    /*const*/ std::string name_;
+    std::weak_ptr<CvTrackbar> trackbar_;
+    std::weak_ptr<Win32UIWindow> parent_;
+    std::map<std::string, std::shared_ptr<Win32UITrackbar> > trackbars_;
+public:
+    Win32UITrackbar(const std::string& name, const std::shared_ptr<CvTrackbar>& trackbar, const std::shared_ptr<Win32UIWindow>& parent)
+        : trackbar_(trackbar)
+        , parent_(parent)
+    {
+        name_ = std::string("<") + name + ">@" + parent->getID();
+    }
 
-    CV_FUNCNAME( "cvGetWindowHandle" );
+    ~Win32UITrackbar() CV_OVERRIDE
+    {
+        if (!trackbar_.expired())
+            destroy();
+        CV_LOG_DEBUG(NULL, "OpenCV/UI/Win32UI: Win32UITrackbar(" << name_ << ") is disposed");
+    }
 
-    __BEGIN__;
+    const std::string& getID() const CV_OVERRIDE { return name_; }
 
-    CvWindow* window;
+    bool isActive() const CV_OVERRIDE { return !trackbar_.expired(); }
 
-    if( window_name == 0 )
-        CV_ERROR( CV_StsNullPtr, "NULL window name" );
+    void destroy() CV_OVERRIDE
+    {
+        // nothing (destroyed with parent window, dedicated trackbar removal is not supported)
+    }
 
-    window = icvFindWindowByName( window_name );
-    if( window )
-        hwnd = (void*)window->hwnd;
+    int getPos() const CV_OVERRIDE
+    {
+        auto trackbar_ptr = trackbar_.lock();
+        CV_Assert(trackbar_ptr);
+        CvTrackbar& trackbar = *trackbar_ptr;
+        return trackbar.pos;
+    }
+    void setPos(int pos) CV_OVERRIDE
+    {
+        auto trackbar_ptr = trackbar_.lock();
+        CV_Assert(trackbar_ptr);
+        CvTrackbar& trackbar = *trackbar_ptr;
+        SendMessage(trackbar.hwnd, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos);
+        icvUpdateTrackbar(trackbar, pos);
+    }
 
-    __END__;
+    cv::Range getRange() const CV_OVERRIDE
+    {
+        auto trackbar_ptr = trackbar_.lock();
+        CV_Assert(trackbar_ptr);
+        CvTrackbar& trackbar = *trackbar_ptr;
+        return cv::Range(trackbar.minval, trackbar.maxval);
+    }
 
-    return hwnd;
-}
+    void setRange(const cv::Range& range) CV_OVERRIDE
+    {
+        auto trackbar_ptr = trackbar_.lock();
+        CV_Assert(trackbar_ptr);
+        CvTrackbar& trackbar = *trackbar_ptr;
+        CV_CheckLE(range.start, range.end, "Invalid trackbar range");
+        trackbar.minval = range.start;
+        trackbar.maxval = range.start;
+        SendMessage(trackbar.hwnd, TBM_SETRANGEMIN, (WPARAM)TRUE, (LPARAM)trackbar.minval);
+        SendMessage(trackbar.hwnd, TBM_SETRANGEMAX, (WPARAM)TRUE, (LPARAM)trackbar.maxval);
+    }
+};  // Win32UITrackbar
 
 
-CV_IMPL const char* cvGetWindowName( void* window_handle )
+class Win32BackendUI : public UIBackend
 {
-    const char* window_name = "";
+public:
+    ~Win32BackendUI() CV_OVERRIDE
+    {
+        destroyAllWindows();
+    }
 
-    CV_FUNCNAME( "cvGetWindowName" );
+    void destroyAllWindows() CV_OVERRIDE
+    {
+        cvDestroyAllWindows();
+    }
 
-    __BEGIN__;
+    // namedWindow
+    virtual std::shared_ptr<UIWindow> createWindow(
+        const std::string& winname,
+        int flags
+    ) CV_OVERRIDE
+    {
+        CV_LOG_INFO(NULL, "OpenCV/UI: Creating Win32UI window: " << winname << " (" << flags << ")");
+        auto window = namedWindow_(winname, flags);
+        auto ui_window = std::make_shared<Win32UIWindow>(winname, window);
+        return ui_window;
+    }
 
-    CvWindow* window;
+    int waitKeyEx(int delay) CV_OVERRIDE
+    {
+        return cvWaitKey(delay);
+    }
+    int pollKey() CV_OVERRIDE
+    {
+        return pollKey_W32();
+    }
+};  // Win32BackendUI
 
-    if( window_handle == 0 )
-        CV_ERROR( CV_StsNullPtr, "NULL window" );
+static
+std::shared_ptr<Win32BackendUI>& getInstance()
+{
+    static std::shared_ptr<Win32BackendUI> g_instance = std::make_shared<Win32BackendUI>();
+    return g_instance;
+}
 
-    window = icvWindowByHWND( (HWND)window_handle );
-    if( window )
-        window_name = window->name;
+} // namespace impl
 
-    __END__;
+#ifndef BUILD_PLUGIN
+namespace highgui_backend {
 
-    return window_name;
+std::shared_ptr<UIBackend> createUIBackendWin32UI()
+{
+    return impl::getInstance();
 }
 
+}  // namespace highgui_backend
+#endif
 
-CV_IMPL void
-cvSetPreprocessFuncWin32_(const void* callback)
+}  // namespace
+
+
+#ifdef BUILD_PLUGIN
+
+#define ABI_VERSION 0
+#define API_VERSION 0
+#include "plugin_api.hpp"
+
+static
+CvResult cv_getInstance(CV_OUT CvPluginUIBackend* handle) CV_NOEXCEPT
 {
-    hg_on_preprocess = (CvWin32WindowCallback)callback;
+    try
+    {
+        if (!handle)
+            return CV_ERROR_FAIL;
+        *handle = cv::impl::getInstance().get();
+        return CV_ERROR_OK;
+    }
+    catch (...)
+    {
+        return CV_ERROR_FAIL;
+    }
 }
 
-CV_IMPL void
-cvSetPostprocessFuncWin32_(const void* callback)
+static const OpenCV_UI_Plugin_API plugin_api =
 {
-    hg_on_postprocess = (CvWin32WindowCallback)callback;
+    {
+        sizeof(OpenCV_UI_Plugin_API), ABI_VERSION, API_VERSION,
+        CV_VERSION_MAJOR, CV_VERSION_MINOR, CV_VERSION_REVISION, CV_VERSION_STATUS,
+        "Win32 OpenCV UI plugin"
+    },
+    {
+        /*  1*/cv_getInstance
+    }
+};
+
+const OpenCV_UI_Plugin_API* CV_API_CALL opencv_ui_plugin_init_v0(int requested_abi_version, int requested_api_version, void* /*reserved=NULL*/) CV_NOEXCEPT
+{
+    if (requested_abi_version == ABI_VERSION && requested_api_version <= API_VERSION)
+        return &plugin_api;
+    return NULL;
 }
 
-#endif //_WIN32
+#endif  // BUILD_PLUGIN
+
+#endif  // HAVE_WIN32UI