Win32 Splitter Control

2020-03-26 08:37发布

问题:

Of all the different controls that there are for Win32, is there any basic, lightweight Splitter/Splitcontainer control available (meaning one or two C/C++ files max)?

I can't seem to find any in the default controls shown in Visual Studio, and everything I find online seems to be for MFC, which I'm not using in my project...

回答1:

No there is no native win32 splitter, you have to use a framework or write your own. Codeproject even has its own splitter category.

If you write your own you basically have two options:

  • The parent of window A and B is the splitter (The splitter border comes from WS_EX_CLIENTEDGE on windows A and B)
  • A and B are separated by a third window; the splitter


回答2:

I found this while googling, and although it had some issues with drawing, I'm sure it could be fixed or used for learning at least.



回答3:

There's a native splitter in Win32, it's basically just transform mouse icon to IDC_SIZENS in this example, and tracking mouse movement and then resizing the control based on mouse movement.

See here: Split Window using Win32 API



回答4:

There is no native win32 splitter, I made one using pure win32 api in one cpp file.

    // Win32test2.cpp : 定义应用程序的入口点。
//

#include "stdafx.h"
#include "Win32test2.h"

LRESULT CALLBACK windowprocessforwindow1(HWND handleforwindow1, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK windowprocessforwindow2(HWND handleforwindow2, UINT message, WPARAM wParam, LPARAM lParam);

bool window1closed = false;
bool window2closed = false;

//child hwnd 小子窗口,非弹出式子窗口,是CreateWindowEx设置了parent
HWND cHwnd[5]; //0 左窗口 1 右窗口或右上窗口  2 竖分隔符窗口 spiltter 3 右下窗口  4 横分隔符窗口 spiltter
//main hwnd
HWND mHwnd;

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nShowCmd)
{
    bool endprogram = false;

    //create window 1

    WNDCLASSEX windowclassforwindow1;
    ZeroMemory(&windowclassforwindow1, sizeof(WNDCLASSEX));
    windowclassforwindow1.cbClsExtra = NULL;
    windowclassforwindow1.cbSize = sizeof(WNDCLASSEX);
    windowclassforwindow1.cbWndExtra = NULL;
    windowclassforwindow1.hbrBackground = (HBRUSH)COLOR_WINDOW;
    windowclassforwindow1.hCursor = LoadCursor(NULL, IDC_ARROW);
    windowclassforwindow1.hIcon = NULL;
    windowclassforwindow1.hIconSm = NULL;
    windowclassforwindow1.hInstance = hInst;
    windowclassforwindow1.lpfnWndProc = (WNDPROC)windowprocessforwindow1;
    windowclassforwindow1.lpszClassName = L"windowclass 1";
    windowclassforwindow1.lpszMenuName = NULL;
    windowclassforwindow1.style = CS_HREDRAW | CS_VREDRAW;

    if (!RegisterClassEx(&windowclassforwindow1))
    {
        int nResult = GetLastError();
        MessageBox(NULL,
            L"Window class creation failed",
            L"Window Class Failed",
            MB_ICONERROR);
    }

    HWND handleforwindow1 = CreateWindowEx(NULL,
        windowclassforwindow1.lpszClassName,
        L"Parent Window",
        WS_OVERLAPPEDWINDOW,
        200,
        200,
        640,
        480,
        NULL,
        NULL,
        hInst,
        NULL                /* No Window Creation data */
    );

    if (!handleforwindow1)
    {
        int nResult = GetLastError();

        MessageBox(NULL,
            L"Window creation failed",
            L"Window Creation Failed",
            MB_ICONERROR);
    }

    ShowWindow(handleforwindow1, nShowCmd);
    mHwnd = handleforwindow1;


    // create window 2

    WNDCLASSEX windowclassforwindow2;
    ZeroMemory(&windowclassforwindow2, sizeof(WNDCLASSEX));
    windowclassforwindow2.cbClsExtra = NULL;
    windowclassforwindow2.cbSize = sizeof(WNDCLASSEX);
    windowclassforwindow2.cbWndExtra = NULL;
    windowclassforwindow2.hbrBackground = (HBRUSH)COLOR_WINDOW;
    windowclassforwindow2.hCursor = LoadCursor(NULL, IDC_ARROW);
    windowclassforwindow2.hIcon = NULL;
    windowclassforwindow2.hIconSm = NULL;
    windowclassforwindow2.hInstance = hInst;
    windowclassforwindow2.lpfnWndProc = (WNDPROC)windowprocessforwindow2;
    windowclassforwindow2.lpszClassName = L"window class2";
    windowclassforwindow2.lpszMenuName = NULL;
    windowclassforwindow2.style = CS_HREDRAW | CS_VREDRAW;

    if (!RegisterClassEx(&windowclassforwindow2))
    {
        int nResult = GetLastError();
        MessageBox(NULL,
            L"Window class creation failed for window 2",
            L"Window Class Failed",
            MB_ICONERROR);
    }

    HWND handleforwindow2 = CreateWindowEx(NULL,
        windowclassforwindow2.lpszClassName,
        L"Child Window",
        WS_CHILD 
        ,
        0,
        0,
        195,
        480,
        handleforwindow1,
        NULL,
        hInst,
        NULL);

    if (!handleforwindow2)
    {
        int nResult = GetLastError();

        MessageBox(NULL,
            L"Window creation failed",
            L"Window Creation Failed",
            MB_ICONERROR);
    }

    ShowWindow(handleforwindow2, nShowCmd);
    cHwnd[0] = handleforwindow2;

    // create window 3

    HWND handleforwindow3 = CreateWindowEx(NULL,
        windowclassforwindow2.lpszClassName,
        L"Child Window",
        WS_CHILD 
        ,
        200,
        0,
        440,
        275,
        handleforwindow1,
        NULL,
        hInst,
        NULL);

    if (!handleforwindow3)
    {
        int nResult = GetLastError();

        MessageBox(NULL,
            L"Window creation failed",
            L"Window Creation Failed",
            MB_ICONERROR);
    }

    ShowWindow(handleforwindow3, nShowCmd);
    cHwnd[1] = handleforwindow3;

    // create window 4 spiltter

    WNDCLASSEX windowclassforwindow4;
    ZeroMemory(&windowclassforwindow4, sizeof(WNDCLASSEX));
    windowclassforwindow4.cbClsExtra = NULL;
    windowclassforwindow4.cbSize = sizeof(WNDCLASSEX);
    windowclassforwindow4.cbWndExtra = NULL;
    windowclassforwindow4.hbrBackground = (HBRUSH)COLOR_WINDOW;
    windowclassforwindow4.hCursor = LoadCursor(NULL, IDC_SIZEWE);
    windowclassforwindow4.hIcon = NULL;
    windowclassforwindow4.hIconSm = NULL;
    windowclassforwindow4.hInstance = hInst;
    windowclassforwindow4.lpfnWndProc = (WNDPROC)windowprocessforwindow2;
    windowclassforwindow4.lpszClassName = L"window class4";
    windowclassforwindow4.lpszMenuName = NULL;
    windowclassforwindow4.style = CS_HREDRAW | CS_VREDRAW;

    if (!RegisterClassEx(&windowclassforwindow4))
    {
        int nResult = GetLastError();
        MessageBox(NULL,
            L"Window class creation failed for window 2",
            L"Window Class Failed",
            MB_ICONERROR);
    }

    HWND handleforwindow4 = CreateWindowEx(NULL,
        windowclassforwindow4.lpszClassName,
        L"Child Window",
        WS_CHILD \
        | WS_BORDER
        ,
        195,
        0,
        5,
        480,
        handleforwindow1,
        NULL,
        hInst,
        NULL);

    if (!handleforwindow4)
    {
        int nResult = GetLastError();

        MessageBox(NULL,
            L"Window creation failed",
            L"Window Creation Failed",
            MB_ICONERROR);
    }

    ShowWindow(handleforwindow4, nShowCmd);
    cHwnd[2] = handleforwindow4;

    // create window 5 有窗口下面窗口

    HWND handleforwindow5 = CreateWindowEx(NULL,
        windowclassforwindow2.lpszClassName,
        L"Child Window",
        WS_CHILD
        ,
        200,
        280,
        440,
        200,
        handleforwindow1,
        NULL,
        hInst,
        NULL);

    if (!handleforwindow5)
    {
        int nResult = GetLastError();

        MessageBox(NULL,
            L"Window creation failed",
            L"Window Creation Failed",
            MB_ICONERROR);
    }
    ShowWindow(handleforwindow5, nShowCmd);
    cHwnd[3] = handleforwindow5;

    // create window 6 spiltter 右窗口spiltter

    WNDCLASSEX windowclassforwindow6;
    ZeroMemory(&windowclassforwindow6, sizeof(WNDCLASSEX));
    windowclassforwindow6.cbClsExtra = NULL;
    windowclassforwindow6.cbSize = sizeof(WNDCLASSEX);
    windowclassforwindow6.cbWndExtra = NULL;
    windowclassforwindow6.hbrBackground = (HBRUSH)COLOR_WINDOW;
    windowclassforwindow6.hCursor = LoadCursor(NULL, IDC_SIZENS);
    windowclassforwindow6.hIcon = NULL;
    windowclassforwindow6.hIconSm = NULL;
    windowclassforwindow6.hInstance = hInst;
    windowclassforwindow6.lpfnWndProc = (WNDPROC)windowprocessforwindow2;
    windowclassforwindow6.lpszClassName = L"window class6";
    windowclassforwindow6.lpszMenuName = NULL;
    windowclassforwindow6.style = CS_HREDRAW | CS_VREDRAW;

    if (!RegisterClassEx(&windowclassforwindow6))
    {
        int nResult = GetLastError();
        MessageBox(NULL,
            L"Window class creation failed for window 2",
            L"Window Class Failed",
            MB_ICONERROR);
    }

    HWND handleforwindow6 = CreateWindowEx(NULL,
        windowclassforwindow6.lpszClassName,
        L"Child Window",
        WS_CHILD \
        | WS_BORDER
        ,
        200,
        275,
        480,
        5,
        handleforwindow1,
        NULL,
        hInst,
        NULL);

    if (!handleforwindow6)
    {
        int nResult = GetLastError();

        MessageBox(NULL,
            L"Window creation failed",
            L"Window Creation Failed",
            MB_ICONERROR);
    }

    ShowWindow(handleforwindow6, nShowCmd);
    cHwnd[4] = handleforwindow6;

    MSG msg;
    ZeroMemory(&msg, sizeof(MSG));
    while (endprogram == false) {
        if (GetMessage(&msg, NULL, 0, 0));
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        if (window1closed == true && window2closed == true) {
            endprogram = true;
        }
    }

    return 0;
}

LRESULT CALLBACK windowprocessforwindow1(HWND handleforwindow, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_DESTROY: {

        window1closed = true;
        return 0;
    }
                     break;
    }

    return DefWindowProc(handleforwindow, msg, wParam, lParam);
}

//子窗口处理
LRESULT CALLBACK windowprocessforwindow2(HWND handleforwindow, UINT msg, WPARAM wParam, LPARAM lParam)
{
    //鼠标拖动spiltter时,相对于主窗口的x
    int spos,border;
    //鼠标左键单击spiltter时,在spiltter内部的偏移长度
    int posinspiltter = 0;
    static BOOL bSplitterMoving;

    RECT rectMain,rectSpiltterH,rectRightUp;

    switch (msg)
    {
    case WM_DESTROY: {


        window2closed = true;
        return 0;
    }
    case WM_LBUTTONDOWN:

        if (handleforwindow == cHwnd[0])
        {
            MessageBox(NULL, TEXT("1鼠标左键点击"), TEXT("Win32_Mouse"), MB_OK);
        }else if (handleforwindow == cHwnd[1])
        {
            MessageBox(NULL, TEXT("2鼠标左键点击"), TEXT("Win32_Mouse"), MB_OK);
        }
        else if (handleforwindow == cHwnd[3])
        {
            MessageBox(NULL, TEXT("3鼠标左键点击"), TEXT("Win32_Mouse"), MB_OK);
        }
        else if (handleforwindow == cHwnd[2])
        {
            //MessageBox(NULL, TEXT("3鼠标左键点击"), TEXT("Win32_Mouse"), MB_OK);
            bSplitterMoving = TRUE;
            //抓住左窗口,WM_MOUSEMOVE得到的就是鼠标相对于左窗口移动距离
            SetCapture(cHwnd[0]);
            posinspiltter = GET_X_LPARAM(lParam);
            return 0;
        }
        else if (handleforwindow == cHwnd[4])
        {
            //MessageBox(NULL, TEXT("3鼠标左键点击"), TEXT("Win32_Mouse"), MB_OK);
            bSplitterMoving = TRUE;
            //抓住右上窗口
            SetCapture(cHwnd[1]);
            posinspiltter = GET_Y_LPARAM(lParam);
            return 0;
        }

        break;
    case WM_LBUTTONUP:
        ReleaseCapture();
        bSplitterMoving = FALSE;
        return 0;
    case WM_MOUSEMOVE:
        if ((wParam == MK_LBUTTON) && bSplitterMoving && (handleforwindow == cHwnd[0]))
        {
            spos = GET_X_LPARAM(lParam);
            //spos- posinspiltter  鼠标的相对于主窗口的x - 在spiltter内的偏移 就是左窗口的宽度
            MoveWindow(cHwnd[0], 0, 0, spos- posinspiltter, 480, TRUE); //左窗口
            //spos+(5- posinspiltter)  5- posinspiltter是点击位置到spiltter有边框的距离, 鼠标的相对于主窗口的x + 点击位置到spiltter有边框的距离就是 有窗口的x起始位置
            //640-(spos + (5 - posinspiltter))  640是主窗口宽度 - 有窗口的起始位置,就是宽度

            MoveWindow(cHwnd[2], spos, 0, 5, 480, TRUE); //spiltter

            GetWindowRect(mHwnd, &rectMain);
            GetWindowRect(cHwnd[1], &rectRightUp);

            MoveWindow(cHwnd[1], spos + (5 - posinspiltter), 0, 640 - (spos + (5 - posinspiltter)), rectRightUp.bottom - rectMain.top - 31, TRUE); //右窗口

            MoveWindow(cHwnd[3], spos + (5 - posinspiltter), rectRightUp.bottom- rectMain.top-31+5, 640 - (spos + (5 - posinspiltter)), 480 - (rectRightUp.bottom -     rectMain.top - 31 + 5), TRUE); //右下
            MoveWindow(cHwnd[4], spos + (5 - posinspiltter), rectRightUp.bottom - rectMain.top - 31, 640 - (spos + (5 - posinspiltter)), 5, TRUE); //spiltter
        }
        else if ((wParam == MK_LBUTTON) && bSplitterMoving && (handleforwindow == cHwnd[1]))
        {
            border = GetSystemMetrics(SM_CXBORDER);
            spos = GET_Y_LPARAM(lParam);

            GetWindowRect(mHwnd, &rectMain);
            GetWindowRect(cHwnd[2], &rectSpiltterH);
            GetWindowRect(cHwnd[1], &rectRightUp);

            MoveWindow(cHwnd[1], rectRightUp.left - rectMain.left-8, 0, rectRightUp.right-rectRightUp.left, spos - posinspiltter, TRUE); //右上
            MoveWindow(cHwnd[3], rectRightUp.left - rectMain.left-8, spos + (5-posinspiltter), rectRightUp.right - rectRightUp.left, 480-(spos + (5 -     posinspiltter)), TRUE); //右下
            MoveWindow(cHwnd[4], rectRightUp.left - rectMain.left-8, spos - posinspiltter, rectRightUp.right - rectRightUp.left, 5, TRUE); //spiltter

        }
        return 0;
    }

    return DefWindowProc(handleforwindow, msg, wParam, lParam);
}


回答5:

Try this one, it's a native win32 splitter control with just 2 files.

// Splitter.h

#pragma once

#include <windows.h>

constexpr WCHAR UC_SPLITTER[]{ L"UserControl_Splitter" };

constexpr DWORD SPS_HORZ{ 0b1u };
constexpr DWORD SPS_VERT{ 0b10u };
constexpr DWORD SPS_PARENTWIDTH{ 0b100u };
constexpr DWORD SPS_PARENTHEIGHT{ 0b1000u };
constexpr DWORD SPS_AUTODRAG{ 0b10000u };
constexpr DWORD SPS_NOCAPTURE{ 0b100000u };
constexpr DWORD SPS_NONOTIFY{ 0b1000000u };

enum SPLITTERMESSAGE : UINT { SPM_ROTATE = WM_USER + 1, SPM_SETRANGE, SPM_GETRANGE, SPM_SETMARGIN, SPM_GETMARGIN, SPM_SETLINKEDCTL, SPM_GETLINKEDCTL, SPM_ADDLINKEDCTL, SPM_REMOVELINKEDCTL };
enum SETLINKEDCONTROL : WORD { SLC_TOP = 1, SLC_BOTTOM, SLC_LEFT, SLC_RIGHT };

typedef struct tagNMSPLITTER
{
    NMHDR hdr;
    POINT ptCursor;
    POINT ptCursorOffset;
} NMSPLITTER, *PNMSPLITTER, *LPNMSPLITTER;

ATOM InitSplitter();
// Splitter.cpp

#include <windows.h>
#include <windowsx.h>
#include <vector>
#include <array>
#include <algorithm>
#include <cassert>
#include "Splitter.h"

LRESULT CALLBACK SplitterProc(HWND hWndSplitter, UINT Message, WPARAM wParam, LPARAM lParam);

ATOM InitSplitter()
{
    WNDCLASS wc{ 0, SplitterProc, 0, 0, static_cast<HINSTANCE>(GetModuleHandle(NULL)), NULL, NULL, NULL, NULL, UC_SPLITTER };

    return RegisterClass(&wc);
}

LRESULT CALLBACK SplitterProc(HWND hWndSplitter, UINT Message, WPARAM wParam, LPARAM lParam)
{
    LRESULT ret{};

    static DWORD dwSplitterStyle{};
    static WORD idSplitter{};
    static POINT ptSplitterRange{};
    static DWORD dwLineMargin{};
    static POINT ptCursorOffset{};
    static std::array<std::vector<HWND>, 2> LinkedControl;

    switch (Message)
    {
    case SPM_ROTATE:
        {
            DWORD dwSplitterStyleNew{ (dwSplitterStyle & (~(SPS_HORZ | SPS_VERT))) | ((dwSplitterStyle & (SPS_HORZ | SPS_VERT)) ^ (SPS_HORZ | SPS_VERT)) };
            if (dwSplitterStyleNew & SPS_PARENTWIDTH)
            {
                dwSplitterStyle = (dwSplitterStyleNew & (~SPS_PARENTWIDTH)) | SPS_PARENTHEIGHT;
            }
            if (dwSplitterStyleNew & SPS_PARENTHEIGHT)
            {
                dwSplitterStyle = (dwSplitterStyleNew & (~SPS_PARENTHEIGHT)) | SPS_PARENTWIDTH;
            }
            SetWindowLongPtr(hWndSplitter, GWL_STYLE, static_cast<LONG>(dwSplitterStyleNew));

            InvalidateRect(hWndSplitter, NULL, FALSE);
        }
        break;
    case SPM_SETRANGE:
        {
            if (wParam)
            {
                HWND hWndSplitterParent{ GetAncestor(hWndSplitter, GA_PARENT) };
                RECT rcSplitter{};
                GetWindowRect(hWndSplitter, &rcSplitter);
                MapWindowRect(HWND_DESKTOP, hWndSplitterParent, &rcSplitter);
                if (dwSplitterStyle & SPS_HORZ)
                {
                    ptSplitterRange = { LOWORD(wParam), HIWORD(wParam) - (rcSplitter.bottom - rcSplitter.top) };
                }
                else if (dwSplitterStyle & SPS_VERT)
                {
                    ptSplitterRange = { LOWORD(wParam), HIWORD(wParam) - (rcSplitter.right - rcSplitter.left) };
                }
                if (ptSplitterRange.y >= ptSplitterRange.x)
                {
                    ret = static_cast<LRESULT>(TRUE);
                }
                else
                {
                    ptSplitterRange = {};

                    ret = static_cast<LRESULT>(FALSE);
                }
            }
            else
            {
                ptSplitterRange = {};

                ret = static_cast<LRESULT>(TRUE);
            }
        }
        break;
    case SPM_GETRANGE:
        {
            ret = MAKELRESULT(ptSplitterRange.x, ptSplitterRange.y);
        }
        break;
    case SPM_SETMARGIN:
        {
            dwLineMargin = static_cast<DWORD>(wParam);
            RECT rcSplitterClient{};
            GetClientRect(hWndSplitter, &rcSplitterClient);
            if (dwSplitterStyle & SPS_HORZ)
            {
                POINT ptLineStart{ rcSplitterClient.left + static_cast<LONG>(dwLineMargin), rcSplitterClient.top + (rcSplitterClient.bottom - rcSplitterClient.top) / 2 };
                RECT rcSplitterClientLeftPart{ rcSplitterClient.left, rcSplitterClient.top, rcSplitterClient.left + (rcSplitterClient.right - rcSplitterClient.left) / 2, rcSplitterClient.bottom };
                if (!PtInRect(&rcSplitterClientLeftPart, ptLineStart))
                {
                    dwLineMargin = 0;

                    ret = static_cast<LRESULT>(FALSE);
                    break;
                }
            }
            else if (dwSplitterStyle & SPS_VERT)
            {
                POINT ptLineStart{ rcSplitterClient.left + (rcSplitterClient.right - rcSplitterClient.left) / 2, rcSplitterClient.top + static_cast<LONG>(dwLineMargin) };
                RECT rcSplitterClientUpperPart{ rcSplitterClient.left, rcSplitterClient.top, rcSplitterClient.right, rcSplitterClient.top + (rcSplitterClient.bottom - rcSplitterClient.top) / 2 };
                if (!PtInRect(&rcSplitterClientUpperPart, ptLineStart))
                {
                    dwLineMargin = 0;

                    ret = static_cast<LRESULT>(FALSE);
                    break;
                }
            }
            else
            {
                dwLineMargin = 0;

                ret = static_cast<LRESULT>(FALSE);
                break;
            }

            InvalidateRect(hWndSplitter, NULL, FALSE);

            ret = static_cast<LRESULT>(TRUE);
        }
        break;
    case SPM_GETMARGIN:
        {
            ret = static_cast<LRESULT>(dwLineMargin);
        }
        break;
    case SPM_SETLINKEDCTL:
        {
            switch (HIWORD(wParam))
            {
            case SLC_TOP:
                {
                    if (dwSplitterStyle & SPS_HORZ)
                    {
                        LinkedControl[0].clear();
                        try
                        {
                            for (WORD i = 0; i < LOWORD(wParam); i++)
                            {
                                if (IsWindow(reinterpret_cast<HWND*>(lParam)[i]) && (GetAncestor(reinterpret_cast<HWND*>(lParam)[i], GA_PARENT) == GetAncestor(hWndSplitter, GA_PARENT)))
                                {
                                    LinkedControl[0].push_back(reinterpret_cast<HWND*>(lParam)[i]);
                                }
                            }
                            std::sort(LinkedControl[0].begin(), LinkedControl[0].end());
                            LinkedControl[0].erase(std::unique(LinkedControl[0].begin(), LinkedControl[0].end()), LinkedControl[0].end());
                        }
                        catch (...)
                        {
                            LinkedControl[0].clear();

                            ret = 0;
                            break;
                        }

                        ret = static_cast<LRESULT>(LinkedControl[0].size());
                    }
                    else
                    {
                        ret = 0;
                    }
                }
                break;
            case SLC_BOTTOM:
                {
                    if (dwSplitterStyle & SPS_HORZ)
                    {
                        LinkedControl[1].clear();
                        try
                        {
                            for (WORD i = 0; i < LOWORD(wParam); i++)
                            {
                                if (IsWindow(reinterpret_cast<HWND*>(lParam)[i]) && (GetAncestor(reinterpret_cast<HWND*>(lParam)[i], GA_PARENT) == GetAncestor(hWndSplitter, GA_PARENT)))
                                {
                                    LinkedControl[1].push_back(reinterpret_cast<HWND*>(lParam)[i]);
                                }
                            }
                            std::sort(LinkedControl[1].begin(), LinkedControl[1].end());
                                                        LinkedControl[1].erase(std::unique(LinkedControl[1].begin(), LinkedControl[1].end()), LinkedControl[1].end());
                        }
                        catch (...)
                        {
                            LinkedControl[1].clear();

                            ret = 0;
                            break;
                        }

                        ret = static_cast<LRESULT>(LinkedControl[1].size());
                    }
                    else
                    {
                        ret = 0;
                    }
                }
                break;
            case SLC_LEFT:
                {
                    if (dwSplitterStyle & SPS_VERT)
                    {
                        LinkedControl[0].clear();
                        try
                        {
                            for (WORD i = 0; i < LOWORD(wParam); i++)
                            {
                                if (IsWindow(reinterpret_cast<HWND*>(lParam)[i]) && (GetAncestor(reinterpret_cast<HWND*>(lParam)[i], GA_PARENT) == GetAncestor(hWndSplitter, GA_PARENT)))
                                {
                                    LinkedControl[0].push_back(reinterpret_cast<HWND*>(lParam)[i]);
                                }
                            }
                            std::sort(LinkedControl[0].begin(), LinkedControl[0].end());
                            LinkedControl[0].erase(std::unique(LinkedControl[0].begin(), LinkedControl[0].end()), LinkedControl[0].end());
                        }
                        catch (...)
                        {
                            LinkedControl[0].clear();

                            ret = 0;
                            break;
                        }

                        ret = static_cast<LRESULT>(LinkedControl[0].size());
                    }
                    else
                    {
                        ret = 0;
                    }
                }
                break;
            case SLC_RIGHT:
                {
                    if (dwSplitterStyle & SPS_VERT)
                    {
                        LinkedControl[1].clear();
                        try
                        {
                            for (WORD i = 0; i < LOWORD(wParam); i++)
                            {
                                if (IsWindow(reinterpret_cast<HWND*>(lParam)[i]) && (GetAncestor(reinterpret_cast<HWND*>(lParam)[i], GA_PARENT) == GetAncestor(hWndSplitter, GA_PARENT)))
                                {
                                    LinkedControl[1].push_back(reinterpret_cast<HWND*>(lParam)[i]);
                                }
                            }
                            std::sort(LinkedControl[1].begin(), LinkedControl[1].end());
                            LinkedControl[1].erase(std::unique(LinkedControl[1].begin(), LinkedControl[1].end()), LinkedControl[1].end());
                        }
                        catch (...)
                        {
                            LinkedControl[1].clear();

                            ret = 0;
                            break;
                        }

                        ret = static_cast<LRESULT>(LinkedControl[1].size());
                    }
                    else
                    {
                        ret = 0;
                    }
                }
                break;
            default:
                {
                    ret = 0;
                }
                break;
            }
        }
        break;
    case SPM_GETLINKEDCTL:
        {
            switch (HIWORD(wParam))
            {
            case SLC_TOP:
                {
                    if (dwSplitterStyle & SPS_HORZ)
                    {
                        if (lParam)
                        {
                            for (WORD i = 0; i < static_cast<WORD>(LinkedControl[0].size()); i++)
                            {
                                reinterpret_cast<HWND*>(lParam)[i] = LinkedControl[0][i];
                            }
                        }

                        ret = static_cast<LRESULT>(LinkedControl[0].size());
                    }
                    else
                    {
                        ret = 0;
                    }
                }
                break;
            case SLC_BOTTOM:
                {
                    if (dwSplitterStyle & SPS_HORZ)
                    {
                        if (lParam)
                        {
                            for (WORD i = 0; i < static_cast<WORD>(LinkedControl[1].size()); i++)
                            {
                                reinterpret_cast<HWND*>(lParam)[i] = LinkedControl[1][i];
                            }
                        }

                        ret = static_cast<LRESULT>(LinkedControl[1].size());
                    }
                    else
                    {
                        ret = 0;
                    }
                }
                break;
            case SLC_LEFT:
                {
                    if (dwSplitterStyle & SPS_VERT)
                    {
                        if (lParam)
                        {
                            for (WORD i = 0; i < static_cast<WORD>(LinkedControl[0].size()); i++)
                            {
                                reinterpret_cast<HWND*>(lParam)[i] = LinkedControl[0][i];
                            }
                        }

                        ret = static_cast<LRESULT>(LinkedControl[0].size());
                    }
                    else
                    {
                        ret = 0;
                    }
                }
                break;
            case SLC_RIGHT:
                {
                    if (dwSplitterStyle & SPS_VERT)
                    {
                        if (lParam)
                        {
                            for (WORD i = 0; i < static_cast<WORD>(LinkedControl[1].size()); i++)
                            {
                                reinterpret_cast<HWND*>(lParam)[i] = LinkedControl[1][i];
                            }
                        }

                        ret = static_cast<LRESULT>(LinkedControl[1].size());
                    }
                    else
                    {
                        ret = 0;
                    }
                }
                break;
            default:
                {
                    ret = 0;
                }
                break;
            }
        }
        break;
    case SPM_ADDLINKEDCTL:
        {
            std::vector<HWND> LinkedControlTemp{};

            switch (HIWORD(wParam))
            {
            case SLC_TOP:
                {
                    if (dwSplitterStyle & SPS_HORZ)
                    {
                        try
                        {
                            for (WORD i = 0; i < LOWORD(wParam); i++)
                            {
                                if (IsWindow(reinterpret_cast<HWND*>(lParam)[i]) && (GetAncestor(reinterpret_cast<HWND*>(lParam)[i], GA_PARENT) == GetAncestor(hWndSplitter, GA_PARENT)))
                                {
                                    LinkedControlTemp.push_back(reinterpret_cast<HWND*>(lParam)[i]);
                                }
                            }
                            std::sort(LinkedControlTemp.begin(), LinkedControlTemp.end());
                            LinkedControlTemp.erase(std::unique(LinkedControlTemp.begin(), LinkedControlTemp.end()), LinkedControlTemp.end());
                            LinkedControl[0].reserve(LinkedControl[0].size() + LinkedControlTemp.size());
                        }
                        catch (...)
                        {
                            ret = 0;
                            break;
                        }
                        LinkedControl[0].insert(LinkedControl[0].end(), LinkedControlTemp.begin(), LinkedControlTemp.end());

                        ret = static_cast<LRESULT>(LinkedControlTemp.size());
                    }
                    else
                    {
                        ret = 0;
                    }
                }
                break;
            case SLC_BOTTOM:
                {
                    if (dwSplitterStyle & SPS_HORZ)
                    {
                        try
                        {
                            for (WORD i = 0; i < LOWORD(wParam); i++)
                            {
                                if (IsWindow(reinterpret_cast<HWND*>(lParam)[i]) && (GetAncestor(reinterpret_cast<HWND*>(lParam)[i], GA_PARENT) == GetAncestor(hWndSplitter, GA_PARENT)))
                                {
                                    LinkedControlTemp.push_back(reinterpret_cast<HWND*>(lParam)[i]);
                                }
                            }
                            std::sort(LinkedControlTemp.begin(), LinkedControlTemp.end());
                            LinkedControlTemp.erase(std::unique(LinkedControlTemp.begin(), LinkedControlTemp.end()), LinkedControlTemp.end());
                            LinkedControl[1].reserve(LinkedControl[1].size() + LinkedControlTemp.size());
                        }
                        catch (...)
                        {
                            ret = 0;
                            break;
                        }
                        LinkedControl[1].insert(LinkedControl[1].end(), LinkedControlTemp.begin(), LinkedControlTemp.end());

                        ret = static_cast<LRESULT>(LinkedControlTemp.size());
                    }
                    else
                    {
                        ret = 0;
                    }
                }
                break;
            case SLC_LEFT:
                {
                    if (dwSplitterStyle & SPS_VERT)
                    {
                        try
                        {
                            for (WORD i = 0; i < LOWORD(wParam); i++)
                            {
                                if (IsWindow(reinterpret_cast<HWND*>(lParam)[i]) && (GetAncestor(reinterpret_cast<HWND*>(lParam)[i], GA_PARENT) == GetAncestor(hWndSplitter, GA_PARENT)))
                                {
                                    LinkedControlTemp.push_back(reinterpret_cast<HWND*>(lParam)[i]);
                                }
                            }
                            std::sort(LinkedControlTemp.begin(), LinkedControlTemp.end());
                            LinkedControlTemp.erase(std::unique(LinkedControlTemp.begin(), LinkedControlTemp.end()), LinkedControlTemp.end());
                            LinkedControl[0].reserve(LinkedControl[0].size() + LinkedControlTemp.size());
                        }
                        catch (...)
                        {
                            ret = 0;
                            break;
                        }
                        LinkedControl[0].insert(LinkedControl[0].end(), LinkedControlTemp.begin(), LinkedControlTemp.end());

                        ret = static_cast<LRESULT>(LinkedControlTemp.size());
                    }
                    else
                    {
                        ret = 0;
                    }
                }
                break;
            case SLC_RIGHT:
                {
                    if (dwSplitterStyle & SPS_VERT)
                    {
                        try
                        {
                            for (WORD i = 0; i < LOWORD(wParam); i++)
                            {
                                if (IsWindow(reinterpret_cast<HWND*>(lParam)[i]) && (GetAncestor(reinterpret_cast<HWND*>(lParam)[i], GA_PARENT) == GetAncestor(hWndSplitter, GA_PARENT)))
                                {
                                    LinkedControlTemp.push_back(reinterpret_cast<HWND*>(lParam)[i]);
                                }
                            }
                            std::sort(LinkedControlTemp.begin(), LinkedControlTemp.end());
                            LinkedControlTemp.erase(std::unique(LinkedControlTemp.begin(), LinkedControlTemp.end()), LinkedControlTemp.end());
                            LinkedControl[1].reserve(LinkedControl[1].size() + LinkedControlTemp.size());
                        }
                        catch (...)
                        {
                            ret = 0;
                            break;
                        }
                        LinkedControl[1].insert(LinkedControl[1].end(), LinkedControlTemp.begin(), LinkedControlTemp.end());

                        ret = static_cast<LRESULT>(LinkedControlTemp.size());
                    }
                }
                break;
            default:
                {
                    ret = 0;
                }
                break;
            }
        }
        break;
    case SPM_REMOVELINKEDCTL:
        {
            switch (HIWORD(wParam))
            {
            case SLC_TOP:
                {
                    if (dwSplitterStyle & SPS_HORZ)
                    {
                        std::size_t LinkedControlOriginalSize{ LinkedControl[0].size() };
                        for (WORD i = 0; i < LOWORD(wParam); i++)
                        {
                            LinkedControl[0].erase(std::find(LinkedControl[0].begin(), LinkedControl[0].end(), reinterpret_cast<HWND*>(lParam)[i]));
                        }

                        ret = static_cast<LRESULT>(LinkedControlOriginalSize - LinkedControl[0].size());
                    }
                    else
                    {
                        ret = 0;
                    }
                }
                break;
            case SLC_BOTTOM:
                {
                    if (dwSplitterStyle & SPS_HORZ)
                    {
                        std::size_t LinkedControlOriginalSize{ LinkedControl[1].size() };
                        for (WORD i = 0; i < LOWORD(wParam); i++)
                        {
                            LinkedControl[1].erase(std::find(LinkedControl[1].begin(), LinkedControl[1].end(), reinterpret_cast<HWND*>(lParam)[i]));
                        }

                        ret = static_cast<LRESULT>(LinkedControlOriginalSize - LinkedControl[1].size());
                    }
                    else
                    {
                        ret = 0;
                    }
                }
                break;
            case SLC_LEFT:
                {
                    if (dwSplitterStyle & SPS_VERT)
                    {
                        std::size_t LinkedControlOriginalSize{ LinkedControl[0].size() };
                        for (WORD i = 0; i < LOWORD(wParam); i++)
                        {
                            LinkedControl[0].erase(std::find(LinkedControl[0].begin(), LinkedControl[0].end(), reinterpret_cast<HWND*>(lParam)[i]));
                        }

                        ret = static_cast<LRESULT>(LinkedControlOriginalSize - LinkedControl[0].size());
                    }
                    else
                    {
                        ret = 0;
                    }
                }
                break;
            case SLC_RIGHT:
                {
                    if (dwSplitterStyle & SPS_VERT)
                    {
                        std::size_t LinkedControlOriginalSize{ LinkedControl[1].size() };
                        for (WORD i = 0; i < LOWORD(wParam); i++)
                        {
                            LinkedControl[1].erase(std::find(LinkedControl[1].begin(), LinkedControl[1].end(), reinterpret_cast<HWND*>(lParam)[i]));
                        }

                        ret = static_cast<LRESULT>(LinkedControlOriginalSize - LinkedControl[1].size());
                    }
                    else
                    {
                        ret = 0;
                    }
                }
                break;
            default:
                {
                    ret = 0;
                }
                break;
            }
        }
        break;
    case WM_CREATE:
        {
            dwSplitterStyle = static_cast<DWORD>(reinterpret_cast<LPCREATESTRUCT>(lParam)->style);
            idSplitter = static_cast<WORD>(reinterpret_cast<UINT_PTR>(reinterpret_cast<LPCREATESTRUCT>(lParam)->hMenu) & 0xFFFF);

            if (static_cast<bool>(dwSplitterStyle & SPS_HORZ) == static_cast<bool>(dwSplitterStyle & SPS_VERT))
            {
                dwSplitterStyle = dwSplitterStyle & (~(SPS_HORZ | SPS_VERT));
            }
            if ((dwSplitterStyle & SPS_PARENTWIDTH) && (dwSplitterStyle & SPS_PARENTHEIGHT))
            {
                dwSplitterStyle = dwSplitterStyle & (~(SPS_PARENTWIDTH | SPS_PARENTHEIGHT));
            }
            if ((dwSplitterStyle & SPS_HORZ) && (dwSplitterStyle & SPS_PARENTHEIGHT))
            {
                dwSplitterStyle = dwSplitterStyle & (~(SPS_PARENTHEIGHT));
            }
            if ((dwSplitterStyle & SPS_VERT) && (dwSplitterStyle & SPS_PARENTWIDTH))
            {
                dwSplitterStyle = dwSplitterStyle & (~(SPS_PARENTWIDTH));
            }
            SetWindowLongPtr(hWndSplitter, GWL_STYLE, static_cast<LONG>(dwSplitterStyle));

            ret = 0;
        }
        break;
    case WM_ERASEBKGND:
        {
            ret = static_cast<LRESULT>(TRUE);
        }
        break;
    case WM_PAINT:
        {
            PAINTSTRUCT ps{};
            HDC hDCSplitter{ BeginPaint(hWndSplitter, &ps) };

            HWND hWndSplitterParent{ GetAncestor(hWndSplitter, GA_PARENT) };
            HBRUSH hBrSplitterBackground{ FORWARD_WM_CTLCOLORSTATIC(hWndSplitterParent, hDCSplitter, hWndSplitter, SendMessage) };

            RECT rcSplitterClient{};
            GetClientRect(hWndSplitter, &rcSplitterClient);
            if (!hBrSplitterBackground)
            {
                hBrSplitterBackground = GetSysColorBrush(COLOR_3DFACE);
            }
            FillRect(hDCSplitter, &rcSplitterClient, hBrSplitterBackground);

            if (dwSplitterStyle & SPS_HORZ)
            {
                MoveToEx(hDCSplitter, rcSplitterClient.left + dwLineMargin, rcSplitterClient.top + (rcSplitterClient.bottom - rcSplitterClient.top) / 2, NULL);
                LineTo(hDCSplitter, rcSplitterClient.right - dwLineMargin, rcSplitterClient.top + (rcSplitterClient.bottom - rcSplitterClient.top) / 2);
            }
            else if (dwSplitterStyle & SPS_VERT)
            {
                MoveToEx(hDCSplitter, rcSplitterClient.left + (rcSplitterClient.right - rcSplitterClient.left) / 2, rcSplitterClient.top + dwLineMargin, NULL);
                LineTo(hDCSplitter, rcSplitterClient.left + (rcSplitterClient.right - rcSplitterClient.left) / 2, rcSplitterClient.bottom - dwLineMargin);
            }

            EndPaint(hWndSplitter, &ps);
        }
        break;
    case WM_LBUTTONDOWN:
        {
            if (!(dwSplitterStyle & SPS_NOCAPTURE))
            {
                SetCapture(hWndSplitter);
            }

            if (!(dwSplitterStyle & SPS_NONOTIFY))
            {
                HWND hWndSplitterParent{ GetAncestor(hWndSplitter, GA_PARENT) };
                RECT rcSplitter{}, rcSplitterClient{};
                GetWindowRect(hWndSplitter, &rcSplitter);
                GetClientRect(hWndSplitter, &rcSplitterClient);
                MapWindowRect(hWndSplitter, HWND_DESKTOP, &rcSplitterClient);
                POINT ptCursor{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
                ptCursorOffset = { ptCursor.x + (rcSplitterClient.left - rcSplitter.left), ptCursor.y + (rcSplitterClient.top - rcSplitter.top) };
                MapWindowPoints(hWndSplitter, hWndSplitterParent, &ptCursor, 1);
                NMSPLITTER nms{ { hWndSplitter, static_cast<UINT_PTR>(idSplitter), static_cast<UINT>(SPN_DRAGBEGIN) }, ptCursor, ptCursorOffset };
                SendMessage(hWndSplitterParent, WM_NOTIFY, static_cast<WPARAM>(idSplitter), reinterpret_cast<LPARAM>(&nms));
            }
        }
        break;
    case WM_MOUSEMOVE:
        {
            if ((wParam == MK_LBUTTON))
            {
                HWND hWndSplitterParent{ GetAncestor(hWndSplitter, GA_PARENT) };
                POINT ptCursor{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }, ptSplitter{}, ptCursorOffsetNew{ ptCursorOffset };
                MapWindowPoints(hWndSplitter, hWndSplitterParent, &ptCursor, 1);
                ptSplitter = { ptCursor.x - ptCursorOffsetNew.x, ptCursor.y - ptCursorOffsetNew.y };
                if ((ptSplitterRange.x != 0) || (ptSplitterRange.y != 0))
                {
                    if (dwSplitterStyle & SPS_HORZ)
                    {
                        if (ptSplitter.y < ptSplitterRange.x)
                        {
                            ptSplitter.y = ptSplitterRange.x;
                            ptCursorOffsetNew.y = ptCursor.y - ptSplitterRange.x;
                        }
                        if (ptSplitter.y > ptSplitterRange.y)
                        {
                            ptSplitter.y = ptSplitterRange.y;
                            ptCursorOffsetNew.y = ptCursor.y - ptSplitterRange.y;
                        }
                    }
                    if (dwSplitterStyle & SPS_VERT)
                    {
                        if (ptSplitter.x < ptSplitterRange.x)
                        {
                            ptSplitter.x = ptSplitterRange.x;
                            ptCursorOffsetNew.x = ptCursor.x - ptSplitterRange.x;
                        }
                        if (ptSplitter.x > ptSplitterRange.y)
                        {
                            ptSplitter.x = ptSplitterRange.y;
                            ptCursorOffsetNew.x = ptCursor.x - ptSplitterRange.y;
                        }
                    }
                }

                if (dwSplitterStyle & SPS_AUTODRAG)
                {
                    FORWARD_WM_MOVE(hWndSplitter, ptSplitter.x, ptSplitter.y, SendMessage);
                }

                if (!(dwSplitterStyle & SPS_NONOTIFY))
                {
                    NMSPLITTER nms{ { hWndSplitter, static_cast<UINT_PTR>(idSplitter), static_cast<UINT>(SPN_DRAGGING) }, ptCursor, ptCursorOffsetNew };
                    SendMessage(hWndSplitterParent, WM_NOTIFY, static_cast<WPARAM>(idSplitter), reinterpret_cast<LPARAM>(&nms));
                }
            }
        }
        break;
    case WM_LBUTTONUP:
        {
            if (!(dwSplitterStyle & SPS_NOCAPTURE))
            {
                ReleaseCapture();
            }

            if (!(dwSplitterStyle & SPS_NONOTIFY))
            {
                HWND hWndSplitterParent{ GetAncestor(hWndSplitter, GA_PARENT) };
                POINT ptCursor{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
                MapWindowPoints(hWndSplitter, hWndSplitterParent, &ptCursor, 1);
                NMSPLITTER nms{ { hWndSplitter, static_cast<UINT_PTR>(idSplitter), static_cast<UINT>(SPN_DRAGEND) }, ptCursor, ptCursorOffset };
                SendMessage(hWndSplitterParent, WM_NOTIFY, static_cast<WPARAM>(idSplitter), reinterpret_cast<LPARAM>(&nms));
            }
        }
        break;
    case WM_SETCURSOR:
        {
            if (reinterpret_cast<HWND>(wParam) == hWndSplitter)
            {
                if (dwSplitterStyle & SPS_HORZ)
                {
                    SetCursor(LoadCursor(NULL, IDC_SIZENS));

                    ret = static_cast<LRESULT>(TRUE);
                }
                else if (dwSplitterStyle & SPS_VERT)
                {
                    SetCursor(LoadCursor(NULL, IDC_SIZEWE));

                    ret = static_cast<LRESULT>(TRUE);
                }
                else
                {
                    ret = static_cast<LRESULT>(FALSE);
                }
            }
        }
        break;
    case WM_MOVE:
        {
            HWND hWndSplitterParent{ GetAncestor(hWndSplitter, GA_PARENT) };
            RECT rcSplitter{}, rcSplitterParentClient{};
            GetWindowRect(hWndSplitter, &rcSplitter);
            GetClientRect(hWndSplitterParent, &rcSplitterParentClient);
            int xPosSplitter{}, yPosSplitter{}, cxSplitter{}, cySplitter{};
            UINT uFlags{ SWP_NOZORDER | SWP_NOACTIVATE };
            if (dwSplitterStyle & SPS_PARENTWIDTH)
            {
                xPosSplitter = rcSplitterParentClient.left;
                yPosSplitter = GET_Y_LPARAM(lParam);
                cxSplitter = rcSplitterParentClient.right - rcSplitterParentClient.left;
                cySplitter = rcSplitter.bottom - rcSplitter.top;
            }
            else if (dwSplitterStyle & SPS_PARENTHEIGHT)
            {
                xPosSplitter = GET_X_LPARAM(lParam);
                yPosSplitter = rcSplitterParentClient.top;
                cxSplitter = rcSplitter.right - rcSplitter.left;
                cySplitter = rcSplitterParentClient.bottom - rcSplitterParentClient.top;
            }
            else
            {
                xPosSplitter = GET_X_LPARAM(lParam);
                yPosSplitter = GET_Y_LPARAM(lParam);
                uFlags |= SWP_NOSIZE;
            }
            SetWindowPos(hWndSplitter, NULL, xPosSplitter, yPosSplitter, cxSplitter, cySplitter, uFlags);

            MapWindowRect(HWND_DESKTOP, hWndSplitterParent, &rcSplitter);
            for (const auto& i : LinkedControl[0])
            {
                RECT rcLinkedWindow{};
                GetWindowRect(i, &rcLinkedWindow);
                MapWindowRect(HWND_DESKTOP, hWndSplitterParent, &rcLinkedWindow);
                if (dwSplitterStyle & SPS_HORZ)
                {
                    SetWindowPos(i, NULL, 0, 0, rcLinkedWindow.right - rcLinkedWindow.left, yPosSplitter - rcLinkedWindow.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE | SWP_ASYNCWINDOWPOS);
                }
                else if (dwSplitterStyle & SPS_VERT)
                {
                    SetWindowPos(i, NULL, 0, 0, xPosSplitter - rcLinkedWindow.left, rcLinkedWindow.bottom - rcLinkedWindow.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE | SWP_ASYNCWINDOWPOS);
                }
            }
            for (const auto& i : LinkedControl[1])
            {
                RECT rcLinkedWindow{};
                GetWindowRect(i, &rcLinkedWindow);
                MapWindowRect(HWND_DESKTOP, hWndSplitterParent, &rcLinkedWindow);
                if (dwSplitterStyle & SPS_HORZ)
                {
                    SetWindowPos(i, NULL, rcLinkedWindow.left, yPosSplitter + cySplitter, rcLinkedWindow.right - rcLinkedWindow.left, rcLinkedWindow.bottom - (yPosSplitter + cySplitter), SWP_NOZORDER | SWP_NOACTIVATE | SWP_ASYNCWINDOWPOS);
                }
                else if (dwSplitterStyle & SPS_VERT)
                {
                    SetWindowPos(i, NULL, xPosSplitter + cxSplitter, rcLinkedWindow.top, rcLinkedWindow.right - (xPosSplitter + cxSplitter), rcLinkedWindow.bottom - rcLinkedWindow.top, SWP_NOZORDER | SWP_NOACTIVATE | SWP_ASYNCWINDOWPOS);
                }
            }
        }
        break;
    case WM_SIZE:
        {
            HWND hWndSplitterParent{ GetAncestor(hWndSplitter, GA_PARENT) };
            RECT rcSplitter{}, rcSplitterParentClient{};
            GetWindowRect(hWndSplitter, &rcSplitter);
            MapWindowRect(HWND_DESKTOP, hWndSplitterParent, &rcSplitter);
            GetClientRect(hWndSplitterParent, &rcSplitterParentClient);
            int xPosSplitter{}, yPosSplitter{}, cxSplitter{}, cySplitter{};
            UINT uFlags{ SWP_NOZORDER | SWP_NOACTIVATE };
            if (dwSplitterStyle & SPS_PARENTWIDTH)
            {
                xPosSplitter = rcSplitterParentClient.left;
                yPosSplitter = rcSplitter.top;
                cxSplitter = rcSplitterParentClient.right - rcSplitterParentClient.left;
                cySplitter = HIWORD(lParam);
            }
            else if (dwSplitterStyle & SPS_PARENTHEIGHT)
            {
                xPosSplitter = rcSplitter.left;
                yPosSplitter = rcSplitterParentClient.top;
                cxSplitter = LOWORD(lParam);
                cySplitter = rcSplitterParentClient.bottom - rcSplitterParentClient.top;
            }
            else
            {
                cxSplitter = LOWORD(lParam);
                cySplitter = HIWORD(lParam);
                uFlags |= SWP_NOMOVE;
            }
            SetWindowPos(hWndSplitter, NULL, xPosSplitter, yPosSplitter, cxSplitter, cySplitter, uFlags);

            MapWindowRect(HWND_DESKTOP, hWndSplitterParent, &rcSplitter);
            for (const auto& i : LinkedControl[0])
            {
                RECT rcLinkedWindow{};
                GetWindowRect(i, &rcLinkedWindow);
                MapWindowRect(HWND_DESKTOP, hWndSplitterParent, &rcLinkedWindow);
                if (dwSplitterStyle & SPS_HORZ)
                {
                    SetWindowPos(i, NULL, 0, 0, rcLinkedWindow.right - rcLinkedWindow.left, yPosSplitter - rcLinkedWindow.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE | SWP_ASYNCWINDOWPOS);
                }
                else if (dwSplitterStyle & SPS_VERT)
                {
                    SetWindowPos(i, NULL, 0, 0, xPosSplitter - rcLinkedWindow.left, rcLinkedWindow.bottom - rcLinkedWindow.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE | SWP_ASYNCWINDOWPOS);
                }
            }
            for (const auto& i : LinkedControl[1])
            {
                RECT rcLinkedWindow{};
                GetWindowRect(i, &rcLinkedWindow);
                MapWindowRect(HWND_DESKTOP, hWndSplitterParent, &rcLinkedWindow);
                if (dwSplitterStyle & SPS_HORZ)
                {
                    SetWindowPos(i, NULL, rcLinkedWindow.left, yPosSplitter + cySplitter, rcLinkedWindow.right - rcLinkedWindow.left, rcLinkedWindow.bottom - (yPosSplitter + cySplitter), SWP_NOZORDER | SWP_NOACTIVATE | SWP_ASYNCWINDOWPOS);
                }
                else if (dwSplitterStyle & SPS_VERT)
                {
                    SetWindowPos(i, NULL, xPosSplitter + cxSplitter, rcLinkedWindow.top, rcLinkedWindow.right - (xPosSplitter + cxSplitter), rcLinkedWindow.bottom - rcLinkedWindow.top, SWP_NOZORDER | SWP_NOACTIVATE | SWP_ASYNCWINDOWPOS);
                }
            }
        }
        break;
    case WM_STYLECHANGING:
        {
            if (wParam == GWL_STYLE)
            {
                if (static_cast<bool>(reinterpret_cast<LPSTYLESTRUCT>(lParam)->styleNew & SPS_HORZ) == static_cast<bool>(reinterpret_cast<LPSTYLESTRUCT>(lParam)->styleNew & SPS_VERT))
                {
                    reinterpret_cast<LPSTYLESTRUCT>(lParam)->styleNew = reinterpret_cast<LPSTYLESTRUCT>(lParam)->styleNew & (~(SPS_HORZ | SPS_VERT));
                }
                if ((reinterpret_cast<LPSTYLESTRUCT>(lParam)->styleNew & SPS_PARENTWIDTH) && (reinterpret_cast<LPSTYLESTRUCT>(lParam)->styleNew & SPS_PARENTHEIGHT))
                {
                    reinterpret_cast<LPSTYLESTRUCT>(lParam)->styleNew = reinterpret_cast<LPSTYLESTRUCT>(lParam)->styleNew & (~(SPS_PARENTWIDTH | SPS_PARENTHEIGHT));
                }
                if ((reinterpret_cast<LPSTYLESTRUCT>(lParam)->styleNew & SPS_HORZ) && (reinterpret_cast<LPSTYLESTRUCT>(lParam)->styleNew & SPS_PARENTHEIGHT))
                {
                    reinterpret_cast<LPSTYLESTRUCT>(lParam)->styleNew = reinterpret_cast<LPSTYLESTRUCT>(lParam)->styleNew & (~(SPS_PARENTHEIGHT));
                }
                if ((reinterpret_cast<LPSTYLESTRUCT>(lParam)->styleNew & SPS_VERT) && (reinterpret_cast<LPSTYLESTRUCT>(lParam)->styleNew & SPS_PARENTWIDTH))
                {
                    reinterpret_cast<LPSTYLESTRUCT>(lParam)->styleNew = reinterpret_cast<LPSTYLESTRUCT>(lParam)->styleNew & (~(SPS_PARENTWIDTH));
                }

                if (reinterpret_cast<LPSTYLESTRUCT>(lParam)->styleNew != reinterpret_cast<LPSTYLESTRUCT>(lParam)->styleOld)
                {
                    InvalidateRect(hWndSplitter, NULL, FALSE);
                }
            }
        }
        break;
    default:
        {
            ret = DefWindowProc(hWndSplitter, Message, wParam, lParam);
        }
        break;
    }

    return ret;
}