I have a client application written in C++, and a server written in Python. This application has several functions, including getting a screenshot of the client's desktop and getting this file on the server.
When I run these programs without any add-ons, everything works. I need to upload my client to the service, and I do it through CreateProcess[client file] inside of my service. All other functions besides the screenshot work with this approach.
Server code, getting a screenshot:
if (cState == State.GETTING_SCREENSHOT):
message = "SCREENSHOT".encode('utf-8')
MySend(client_sock , message)
curr_number = 0
with open("settings.txt" , 'r') as settings:
curr_number_str = settings.readline()
curr_number = int(curr_number_str)
with open("settings.txt" , 'w') as settings:
settings.write(str(curr_number + 1))
screenshot_file = str(curr_number) + ".png"
with open(screenshot_file , 'wb') as file:
while True:
data = MyRecv(client_sock , 40000)
data_arr = bytearray(data)
if (data_arr[:10] == b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'):
continue
if (b'ENDOFF' in data):
break
file.write(data)
cState = State.INPUT_COMMAND
Client code:
case SENDING_SCREENSHOT_IN_PROGRESS:
{
wchar_t PathToLocalAppDataFolder[MAX_PATH];
if (FAILED(SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, PathToLocalAppDataFolder))) {
LoadMessage("Error in ShGetFolderPathW");
break;
}
std::wstring PathToScreenshot = std::wstring(PathToLocalAppDataFolder) + L"\\1.png";
if (!SaveScreen(PathToScreenshot.c_str())) {
LoadMessage("SaveScreen api-func failed");
break;
}
HANDLE hFile = CreateFile(PathToScreenshot.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
LoadMessage("Can not open screenshot file");
break;
}
DWORD dwRead = 1;
BYTE buffSend[BIG_BUFFLEN];
while (dwRead) {
ZeroMemory(buffSend, BIG_BUFFLEN);
dwRead = 0;
ReadFile(hFile, buffSend, BIG_BUFFLEN, &dwRead, NULL);
MySend(ClientSoc, (char*)buffSend, dwRead, 0);
}
CloseHandle(hFile);
char message[SMALL_BUFFLEN] = "ENDOFFILE";
MySend(ClientSoc, message, BIG_BUFFLEN, 0);
DeleteFile(PathToScreenshot.c_str());
cState = WAITING_FOR_INCOMING_COMMAND;
break;
}
Service code:
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <iostream>
#include <shlobj_core.h>
#include <string>
#include "api.h"
#include <fstream>
#pragma comment(lib , "API.lib")
#pragma warning(disable:4996)
wchar_t SERVICE_NAME[] = L"RemoteController";
bool isCreate = FALSE;
SERVICE_STATUS ServiceStatus = { 0 };
SERVICE_STATUS_HANDLE hServiceStatus; //StatusHandle
HANDLE ServiceStopEvent = INVALID_HANDLE_VALUE;
VOID WINAPI ServiceMain(DWORD argc, LPTSTR* argv);
VOID WINAPI ServiceCtrlHandler(DWORD CtrlCode);
DWORD WINAPI ServiceWorkerThreadEntry(LPVOID lpParam);
VOID Install(VOID);
BOOL dirExists(const wchar_t* dir_path);
int main(int argc, char* argv[]) {
FreeConsole();
Install();
SERVICE_TABLE_ENTRY ServiceTable[] = {
{SERVICE_NAME , (LPSERVICE_MAIN_FUNCTION)ServiceMain} ,
{NULL , NULL}
};
if (StartServiceCtrlDispatcher(ServiceTable) == FALSE) {
LoadMessage("Service.exe : StartServiceCtrlDIspathcer error");
return GetLastError();
}
return 0;
}
VOID WINAPI ServiceMain(DWORD argc, LPTSTR* argv) {
DWORD Status = E_FAIL;
hServiceStatus = RegisterServiceCtrlHandler(
SERVICE_NAME,
ServiceCtrlHandler
);
if (hServiceStatus == NULL) {
LoadMessage("Service.exe : RegisterServiceCtrlHandler failed");
return;
}
ZeroMemory(&ServiceStatus, sizeof(ServiceStatus));
ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS;
ServiceStatus.dwControlsAccepted = 0;
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwServiceSpecificExitCode = 0;
ServiceStatus.dwCheckPoint = 0;
if (SetServiceStatus(hServiceStatus, &ServiceStatus) == FALSE) {
LoadMessage("Service.exe : SetServiceStatus failed");
}
ServiceStopEvent = CreateEventW(NULL, TRUE, FALSE, L"RemoteControllerEvent");
if (ServiceStopEvent == NULL) {
ServiceStatus.dwControlsAccepted = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = GetLastError();
ServiceStatus.dwCheckPoint = 1;
if (SetServiceStatus(hServiceStatus, &ServiceStatus) == FALSE) {
LoadMessage("Service.exe : SetServiceStatus failed");
return;
}
}
//start
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCheckPoint = 0;
if (SetServiceStatus(hServiceStatus, &ServiceStatus) == FALSE) {
LoadMessage("Service.exe : SetServiceStatus failed");
}
HANDLE hThread = CreateThread(NULL, 0, ServiceWorkerThreadEntry, NULL, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(ServiceStopEvent);
ServiceStatus.dwControlsAccepted = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCheckPoint = 3;
if (!SetServiceStatus(hServiceStatus, &ServiceStatus) == FALSE) {
LoadMessage("Service.exe : SetServiceStatus failed");
}
return;
}
VOID WINAPI ServiceCtrlHandler(DWORD CtrlCode) {
switch (CtrlCode) {
case SERVICE_CONTROL_STOP:
if (ServiceStatus.dwCurrentState != SERVICE_RUNNING) break;
ServiceStatus.dwControlsAccepted = 0;
ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCheckPoint = 4;
if (SetServiceStatus(hServiceStatus, &ServiceStatus) == FALSE) {
LoadMessage("Service.exe : SetServiceStatus failed");
return;
}
SetEvent(ServiceStopEvent);
default:
break;
}
}
BOOL dirExists(const wchar_t* dir_path) {
DWORD dwAttributes = GetFileAttributes(dir_path);
if (dwAttributes == INVALID_FILE_ATTRIBUTES) return FALSE;
if (dwAttributes & FILE_ATTRIBUTE_DIRECTORY) return TRUE;
return FALSE;
}
VOID Install(VOID) {
SC_HANDLE schSCManager;
SC_HANDLE schService;
wchar_t curr_path[MAX_PATH];
if (!GetModuleFileName(NULL, curr_path, MAX_PATH)) {
LoadMessage("Service.exe : GetModuleFilename failed");
return;
}
schSCManager = OpenSCManager(
NULL, NULL, SC_MANAGER_ALL_ACCESS
);
if (schSCManager == NULL) {
LoadMessage("Service.exe : OpenSCManager failed[with SC_MANAGER_ALL_ACCESS]");
return;
}
schService = CreateService(
schSCManager, SERVICE_NAME, SERVICE_NAME, SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
curr_path, NULL, NULL, NULL, NULL, NULL);
if (schService == NULL) {
LoadMessage("Service.exe : CreateService failed");
CloseServiceHandle(schSCManager);
return;
}
if (StartService(schService , 0 , NULL) == 0){
LoadMessage("Service.exe : Start service failed");
CloseServiceHandle(schSCManager);
CloseServiceHandle(schService);
return;
}
LoadMessage("\tService instaled");
CloseServiceHandle(schSCManager);
CloseServiceHandle(schService);
}
DWORD WINAPI ServiceWorkerThreadEntry(LPVOID lpParam) {
if (isCreate) {
return ERROR_SUCCESS;
}
isCreate = TRUE;
wchar_t ProgramToRun[MAX_PATH];
ZeroMemory(ProgramToRun , sizeof(ProgramToRun));
SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL, 0, ProgramToRun);
std::wstring tmp = std::wstring(ProgramToRun) + L"\\RemoteController\\MainClient.exe";
STARTUPINFO si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
PROCESS_INFORMATION pi;
CreateProcess(tmp.c_str(), NULL, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
return ERROR_SUCCESS;
}
I am trying to run 6 tasks parallel and all the tasks run for infinite time. But when the task starts running this error comes:
Guru Meditation Error: Core 0 panic'ed (LoadProhibited). Exception was unhandled.
Core 0 register dump:
PC : 0x400868b4 PS : 0x00060033 A0 : 0x80085442 A1 : 0x3ffb0b50
0x400868b4: xTaskIncrementTick at C:/Users/preet/esp/esp-idf/components/freertos/tasks.c:3157
A2 : 0x00000001 A3 : 0x80059301 A4 : 0x00000000 A5 : 0x00000132
A6 : 0x00000003 A7 : 0x00060023 A8 : 0x00000000 A9 : 0x3ffb0b30
A10 : 0x3ffb26b8 A11 : 0x00000003 A12 : 0x00060b20 A13 : 0x00060b23
A14 : 0x3ffb6300 A15 : 0x3ffb53fc SAR : 0x00000016 EXCCAUSE: 0x0000001c
EXCVADDR: 0x80059309 LBEG : 0x00000000 LEND : 0x00000000 LCOUNT : 0x00000000
Backtrace:0x400868b1:0x3ffb0b500x4008543f:0x3ffb0b70 0x40085199:0x3ffb0b90 0x400826e9:0x3ffb0ba0 0x400e4b6b:0x3ffb6210 0x400d18ef:0x3ffb6230 0x40086462:0x3ffb6250 0x40087991:0x3ffb6270
0x400868b1: xTaskIncrementTick at C:/Users/preet/esp/esp-idf/components/freertos/tasks.c:3156
0x4008543f: xPortSysTickHandler at C:/Users/preet/esp/esp-idf/components/freertos/port/port_systick.c:167
0x40085199: _frxt_timer_int at C:/Users/preet/esp/esp-idf/components/freertos/port/xtensa/portasm.S:329
0x400826e9: _xt_lowint1 at C:/Users/preet/esp/esp-idf/components/freertos/port/xtensa/xtensa_vectors.S:1111
0x400e4b6b: cpu_ll_waiti at C:/Users/preet/esp/esp-idf/components/hal/esp32/include/hal/cpu_ll.h:183
(inlined by) esp_pm_impl_waiti at C:/Users/preet/esp/esp-idf/components/esp_pm/pm_impl.c:837
0x400d18ef: esp_vApplicationIdleHook at C:/Users/preet/esp/esp-idf/components/esp_system/freertos_hooks.c:63
0x40086462: prvIdleTask at C:/Users/preet/esp/esp-idf/components/freertos/tasks.c:3973 (discriminator 1)
0x40087991: vPortTaskWrapper at C:/Users/preet/esp/esp-idf/components/freertos/port/xtensa/port.c:131
ELF file SHA256: 142fe637d0302132
Rebooting...
My code is:
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "sdkconfig.h"
#define TAG "Smart Sliding Gate"
#define PUSH_BUTTON 25
#define FORCE_STOP_BUTTON 26
#define IR_PIN 14
#define RELAY_1_PIN 22
#define RELAY_2_PIN 21
#define MAGNET_1_PIN 12
#define MAGNET_2_PIN 13
TaskHandle_t FFO_xHandle = NULL;
TaskHandle_t FRO_xHandle = NULL;
TaskHandle_t MS_xHandle = NULL;
TaskHandle_t MFS_xHandle = NULL;
TaskHandle_t MRS_xHandle = NULL;
TaskHandle_t IR_xHandle = NULL;
TaskHandle_t MAGNET_xHandle = NULL;
int MOTOR_STATE = 0;
xSemaphoreHandle I_F_F_O_SIGNAL = 0;
xSemaphoreHandle M_F_F_O_SIGNAL = 0;
xSemaphoreHandle M_F_R_O_SIGNAL = 0;
void MOTOR_FORWARD_START(void * pvParameters)
{
gpio_pad_select_gpio(RELAY_1_PIN);
gpio_pad_select_gpio(RELAY_2_PIN);
gpio_set_direction(RELAY_1_PIN, GPIO_MODE_OUTPUT);
gpio_set_direction(RELAY_2_PIN, GPIO_MODE_OUTPUT);
gpio_set_level(RELAY_1_PIN, 1);
gpio_set_level(RELAY_2_PIN, 0);
ESP_LOGW(TAG, "Motor working in forward direction.");
vTaskDelete(MFS_xHandle);
}
void MOTOR_REVERSE_START(void * pvParameters)
{
gpio_pad_select_gpio(RELAY_1_PIN);
gpio_pad_select_gpio(RELAY_2_PIN);
gpio_set_direction(RELAY_1_PIN, GPIO_MODE_OUTPUT);
gpio_set_direction(RELAY_2_PIN, GPIO_MODE_OUTPUT);
gpio_set_level(RELAY_1_PIN, 0);
gpio_set_level(RELAY_2_PIN, 1);
ESP_LOGW(TAG, "Motor working in reverse direction.");
vTaskDelete(MRS_xHandle);
}
void MOTOR_STOP(void * pvParameters)
{
gpio_pad_select_gpio(RELAY_1_PIN);
gpio_pad_select_gpio(RELAY_2_PIN);
gpio_set_direction(RELAY_1_PIN, GPIO_MODE_OUTPUT);
gpio_set_direction(RELAY_2_PIN, GPIO_MODE_OUTPUT);
gpio_set_level(RELAY_1_PIN, 0);
gpio_set_level(RELAY_2_PIN, 0);
ESP_LOGW(TAG, "Motor Stopped.");
vTaskDelete(MS_xHandle);
}
void MAGNETIC_END_SENSOR()
{
gpio_pad_select_gpio(MAGNET_1_PIN);
gpio_pad_select_gpio(MAGNET_2_PIN);
gpio_set_direction(MAGNET_1_PIN, GPIO_MODE_INPUT);
gpio_set_direction(MAGNET_2_PIN, GPIO_MODE_INPUT);
while (1)
{
if (gpio_get_level(MAGNET_1_PIN) == 1 || gpio_get_level(MAGNET_2_PIN) == 1){
if (MOTOR_STATE == 0){
xSemaphoreGive(M_F_F_O_SIGNAL);
ESP_LOGW(TAG, "F Signal sent.");
}
else if (MOTOR_STATE == 1){
xSemaphoreGive(M_F_R_O_SIGNAL);
ESP_LOGW(TAG, "R Signal sent.");
}
ESP_LOGW(TAG, "Gate reached to the destination, Stopping the motor.");
xTaskCreate(&MOTOR_STOP, "MOTOR_STOP", 512, NULL, 1, MS_xHandle);
MOTOR_STATE =! MOTOR_STATE;
ESP_LOGW(TAG, "Motor stopped and Motor State changed.");
vTaskDelete(MAGNET_xHandle);
}
}
}
void FULL_REVERSE_OPERATION(void * pvParameters)
{
xTaskCreate(&MOTOR_REVERSE_START, "MOTOR_REVERSE_START", 512, NULL, 1, MRS_xHandle);
vTaskDelay( 500 / portTICK_PERIOD_MS );
xTaskCreate(&MAGNETIC_END_SENSOR, "MAGNETIC_END_SENSOR", 1024, NULL, 1, MAGNET_xHandle);
while (1)
{
if (xSemaphoreTake(M_F_R_O_SIGNAL, portMAX_DELAY)){
vTaskDelete(FRO_xHandle);
}
}
}
void IR_INTERRUPT_SENSOR(void * pvParameters)
{
gpio_pad_select_gpio(IR_PIN);
gpio_set_direction(IR_PIN, GPIO_MODE_INPUT);
while (1)
{
if (gpio_get_level(IR_PIN) == 0){
ESP_LOGW(TAG, "IR Rays Intreupted.");
xSemaphoreGive(I_F_F_O_SIGNAL);
xTaskCreate(&MOTOR_STOP, "MOTOR_STOP", 512, NULL, 1, MS_xHandle);
ESP_LOGW(TAG, "Motor Stopped.");
MOTOR_STATE =! MOTOR_STATE;
xTaskCreate(&FULL_REVERSE_OPERATION, "FULL_REVERSE_OPERATION", 1536, NULL, 1, MRS_xHandle);
ESP_LOGW(TAG, "Motor State changed and working in reverse direction.");
vTaskDelete(IR_xHandle);
}
}
}
void FULL_FORWARD_OPERTAION(void * pvParameters)
{
xTaskCreate(&MOTOR_FORWARD_START, "MOTOR_FORWARD_START", 1024, NULL, 1, MFS_xHandle);
xTaskCreate(&IR_INTERRUPT_SENSOR, "IR_INTERRUPT_SENSOR", 2048, NULL, 1, IR_xHandle);
vTaskDelay( 500 / portTICK_PERIOD_MS );
xTaskCreate(&MAGNETIC_END_SENSOR, "MAGNETIC_END_SENSOR", 1536, NULL, 1, MAGNET_xHandle);
while (1)
{
if (xSemaphoreTake(I_F_F_O_SIGNAL, portMAX_DELAY)){
vTaskDelete(MAGNET_xHandle);
vTaskDelete(FFO_xHandle);
}
else if (xSemaphoreTake(M_F_F_O_SIGNAL, portMAX_DELAY)){
vTaskDelete(IR_xHandle);
vTaskDelete(FFO_xHandle);
}
}
}
void BUTTON_OPERATION(void * pvParameters)
{
gpio_pad_select_gpio(PUSH_BUTTON);
gpio_pad_select_gpio(FORCE_STOP_BUTTON);
gpio_set_direction(PUSH_BUTTON, GPIO_MODE_INPUT);
gpio_set_direction(FORCE_STOP_BUTTON, GPIO_MODE_INPUT);
while (1)
{
if (gpio_get_level(PUSH_BUTTON) == 1){
if (MOTOR_STATE == 0){
xTaskCreate(&FULL_FORWARD_OPERTAION, "FULL_FORWARD_OPERTAION", 4096, NULL, 1, FFO_xHandle);
}
else if (MOTOR_STATE == 1){
xTaskCreate(&FULL_REVERSE_OPERATION, "FULL_REVERSE_OPERATION", 1536, NULL, 1, FRO_xHandle);
}
}
else if (gpio_get_level(FORCE_STOP_BUTTON) == 1){
xTaskCreate(&MOTOR_STOP, "MOTOR_STOP", 512, NULL, 1, MS_xHandle);
}
vTaskDelay( 500 / portTICK_PERIOD_MS );
}
}
void app_main(void)
{
vSemaphoreCreateBinary(I_F_F_O_SIGNAL);
vSemaphoreCreateBinary(M_F_F_O_SIGNAL);
vSemaphoreCreateBinary(M_F_R_O_SIGNAL);
xTaskCreate(&BUTTON_OPERATION, "BUTTON_OPERATION", 4096, NULL, tskIDLE_PRIORITY, NULL);
}
I started developing a Firefox add-on, however I could not find any IDE specifically for Firefox. For most part it doesn't really matter because I can just open Javascript files and edit them (I use VS2013 and Web Essentials (I think)).
Up to this point everything is acceptable, but when I have to use cmd every time to run this plugin and then read console logs from cmd, it becomes a nightmare.
So my is - is there some way to launch, develop and log Firefox plugin just like any code in Visual Studio 2013? Other IDEs are welcome too.
Well I think it would be possible to create Visual Studio add-on, but it just too much work. However, I managed to partly integrate Firefox add-on creation into VS2013 with c++ code. It redirects cmd window so that means, that you'll output from cmd in "Output" window while debugging.
I'm leaving complete code with steps in case someone else needs this (C++11 is required):
Create Win32 C++ project (not cmd one).
Paste code (below) into cpp file.
Change YOUR_EXTENSION_NAME to your add-on name.
Run code once, it should throw message box with info where to put Add-on SDK.
Copy SDK files to that folder.
Run code again and exit (you may exit however you want, it should terminate remaining windows).
Now there are 3 options for file (.js, .css, etc.) linking:
Create files manually in SDK folder and add them manually to project.
Create files via VS2013 menu and then uncomment and modify, add, delete lines in do while loop.
Create files via VS2013 menu, but choose SDK folders.
Code:
#include <windows.h>
#include <tchar.h>
#include <thread>
#include <chrono>
#include <typeinfo>
#include <Shlwapi.h>
#pragma comment(lib,"Shlwapi.lib")
// Timer code start
/*
//
//Credit goes to James Daughtry for this piece of code
//
*/
class Timer {
typedef std::chrono::high_resolution_clock high_resolution_clock;
typedef std::chrono::milliseconds milliseconds;
public:
Timer(bool run = false)
{
if (run) Reset();
}
void Reset()
{
_start = high_resolution_clock::now();
}
milliseconds Elapsed() const
{
return std::chrono::duration_cast<milliseconds>(high_resolution_clock::now() - _start);
}
private:
high_resolution_clock::time_point _start;
};
// Timer code end
// Cmd redirection code start
/*
//
//Credit goes to some guys from StackOverflow for directions and Randor from CodeProject for base code
//
*/
struct _JOBWRAPPER
{
HANDLE hJob;
_JOBWRAPPER() : hJob(NULL) {}
~_JOBWRAPPER() { if (this->hJob != NULL) CloseHandle(hJob); }
operator HANDLE() const { return this->hJob; }
}hJob;
typedef void(*TextOutFunction)(LPCSTR);
struct _THREADARGUMENTS
{
HANDLE hOutRead;
clock_t stTimeout;
LPCSTR pchBreakText;
TextOutFunction Function;
bool bGotInfo;
_THREADARGUMENTS() : bGotInfo(false), hOutRead(NULL), stTimeout(NULL), pchBreakText(nullptr), Function(nullptr) {}
};
void ReadCMDThread(_THREADARGUMENTS* Arguments)
{
if (Arguments->hOutRead != NULL)
{
UINT CheckForAnyResponseOnLoop = 5, CurrentLoop = 0;
clock_t ScanInterval = 50;
DWORD dwAvailable = 0;
DWORD bytesRead = 0;
CHAR szOut[4096] = { 0 };
if (Arguments->stTimeout == 0)
{
while (true)
{
CurrentLoop++;
PeekNamedPipe(Arguments->hOutRead, szOut, sizeof(szOut), &bytesRead, &dwAvailable, NULL);
if (0 != bytesRead)
{
if (ReadFile(Arguments->hOutRead, szOut, sizeof(szOut), &bytesRead, NULL))
Arguments->bGotInfo = true;
Arguments->Function(szOut);
if (Arguments->pchBreakText != nullptr && Arguments->pchBreakText != "" && strstr(szOut, Arguments->pchBreakText) != nullptr)
break;
memset(szOut, '\0', sizeof(char) * 4096);
}
if (CheckForAnyResponseOnLoop == CurrentLoop && Arguments->pchBreakText == "")
break;
std::this_thread::sleep_for((std::chrono::milliseconds)ScanInterval);
}
}
else
{
Timer timer(true);
while (timer.Elapsed() < (std::chrono::milliseconds)Arguments->stTimeout)
{
CurrentLoop++;
PeekNamedPipe(Arguments->hOutRead, szOut, sizeof(szOut), &bytesRead, &dwAvailable, NULL);
if (0 != bytesRead)
{
if (ReadFile(Arguments->hOutRead, szOut, sizeof(szOut), &bytesRead, NULL))
Arguments->bGotInfo = true;
Arguments->Function(szOut);
timer.Reset();
if (Arguments->pchBreakText != nullptr && Arguments->pchBreakText != "" && strstr(szOut, Arguments->pchBreakText) != nullptr)
break;
memset(szOut, '\0', sizeof(char) * 4096);
}
if (CheckForAnyResponseOnLoop == CurrentLoop && Arguments->pchBreakText == "")
break;
std::this_thread::sleep_for((std::chrono::milliseconds)ScanInterval);
}
}
}
}
class CMDREDIRECTION{
private:
HANDLE hInRead, hInWrite, hOutRead, hOutWrite;
PROCESS_INFORMATION pi;
STARTUPINFO si;
SECURITY_ATTRIBUTES sa;
TextOutFunction CustomFunction;
public:
CMDREDIRECTION(TextOutFunction Function) : hInRead(NULL), hInWrite(NULL), hOutRead(NULL),
hOutWrite(NULL), CustomFunction(Function) {}
~CMDREDIRECTION(){
if (hInRead != NULL)
CloseHandle(hInRead);
if (hInWrite != NULL)
CloseHandle(hInWrite);
if (hOutRead != NULL)
CloseHandle(hOutRead);
if (hOutWrite != NULL)
CloseHandle(hOutWrite);
}
DWORD WriteToCmd(LPSTR pchString, bool PressEnter = false)
{
DWORD dwWritten = 0;
size_t GivenStringLength = strlen(pchString);
LPSTR TemporaryString = pchString;
bool bSuccess = false;
if (GivenStringLength != 0)
{
if (PressEnter)
{
size_t StringSize = GivenStringLength + 2;
TemporaryString = new CHAR[StringSize];
for (size_t i = 0; i < GivenStringLength; i++)
TemporaryString[i] = pchString[i];
TemporaryString[StringSize - 2] = '\n';
TemporaryString[StringSize - 1] = '\0';
bSuccess = (WriteFile(hInWrite, TemporaryString, strlen(TemporaryString), &dwWritten, NULL) && dwWritten);
delete[] TemporaryString;
}
else
bSuccess = (WriteFile(hInWrite, TemporaryString, strlen(TemporaryString), &dwWritten, NULL) && dwWritten);
}
return bSuccess;
}
bool GetAnswer(clock_t stTimeout, LPCSTR pchBreakText)
{
_THREADARGUMENTS Arguments;
Arguments.hOutRead = hOutRead;
Arguments.pchBreakText = pchBreakText;
Arguments.stTimeout = stTimeout;
Arguments.Function = CustomFunction;
std::thread CMDWatcher(ReadCMDThread, &Arguments);
CMDWatcher.join();
return Arguments.bGotInfo;
}
bool WriteToCmdAndWaitForAnswer(LPSTR pchString, clock_t stTimeout, LPCSTR pchBreakText, bool PressEnter = false)
{
if (WriteToCmd(pchString, PressEnter))
{
return (GetAnswer(stTimeout, pchBreakText));
}
else
{
return false;
}
}
bool Start()
{
if (hJob.hJob == NULL)
{
hJob.hJob = CreateJobObject(NULL, NULL);
if (hJob.hJob != NULL)
{
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
if (!SetInformationJobObject((HANDLE)hJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)))
{
return false;
}
}
else
{
return false;
}
}
ZeroMemory(&sa, sizeof(sa));
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = TRUE;
CreatePipe(&hInRead, &hInWrite, &sa, 0);
CreatePipe(&hOutRead, &hOutWrite, &sa, 0);
ZeroMemory(&si, sizeof(si));
GetStartupInfo(&si);
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
si.hStdOutput = hOutWrite;
si.hStdError = hOutWrite;
si.hStdInput = hInRead;
si.wShowWindow = SW_HIDE;
TCHAR Path[MAX_PATH] = { 0 };
GetSystemDirectory(Path, MAX_PATH);
_tcscat_s(Path, TEXT("\\cmd.exe"));
if (CreateProcess(Path, NULL, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi))
{
BOOL bResult = AssignProcessToJobObject(hJob, pi.hProcess);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return (bResult != 0);
}
else
{
return false;
}
}
};
// Cmd redirection code end
// TString code start
#ifdef UNICODE
#define TCat TCatW
#define TString _TString<WCHAR>
#else
#define TCat TCatA
#define TString _TString<CHAR>
#endif
struct AnyString
{
PVOID String;
bool bWide;
AnyString(LPSTR String)
{
this->String = String;
bWide = false;
}
AnyString(LPWSTR String)
{
this->String = String;
bWide = true;
}
operator LPSTR() { return (LPSTR)String; }
operator LPSTR() const { return (LPSTR)String; }
operator LPWSTR() { return (LPWSTR)String; }
operator LPWSTR() const { return (LPWSTR)String; }
};
template<class T>
class _TString
{
friend void SeAnyString(LPSTR String, _TString<CHAR> &TempString);
T *String;
size_t size;
void free()
{
if (String != nullptr && size != 0)
{
delete[] String;
String = nullptr;
size = 0;
}
}
_TString<CHAR> ToCHAR(LPWSTR wch)
{
_TString<CHAR> TempString;
LPSTR Buffer = nullptr;
size_t size = wcslen(wch),
realsize = size + 1;
if (size != 0)
{
Buffer = new CHAR[realsize];
wcstombs_s(nullptr, Buffer, realsize, wch, size);
TempString.SetAllocatedString(Buffer, size);
}
return TempString;
}
_TString<WCHAR> ToWCHAR(LPSTR ch)
{
_TString<WCHAR> TempString;
LPWSTR Buffer = nullptr;
size_t size = strlen(ch),
realsize = size + 1;
if (size != 0)
{
Buffer = new WCHAR[realsize];
mbstowcs_s(nullptr, Buffer, realsize, ch, size);
TempString.SetAllocatedString(Buffer, size);
}
return TempString;
}
public:
_TString(T *String)
{
free();
if (typeid(T) == typeid(CHAR))
{
size = strlen(String);
if (size != 0)
{
this->String = new T[size + 1];
for (size_t i = 0; i < size; i++)
this->String[i] = String[i];
this->String[size] = '\0';
}
}
else if (typeid(T) == typeid(WCHAR))
{
size = wcslen(String);
if (size != 0)
{
this->String = new T[size + 1];
for (size_t i = 0; i < size; i++)
this->String[i] = String[i];
this->String[size] = L'\0';
}
}
}
_TString() : String(nullptr), size(0) {}
~_TString() { free(); }
_TString(_TString&& OldTempStr)
{
this->String = OldTempStr.String;
this->size = OldTempStr.size;
OldTempStr.size = 0;
OldTempStr.String = nullptr;
}
_TString& operator=(_TString&& OldTempStr)
{
this->String = OldTempStr.String;
this->size = OldTempStr.size;
OldTempStr.size = 0;
OldTempStr.String = nullptr;
return *this;
}
operator T*() const { return String; }
operator T*() { return String; }
T& operator[] (size_t i) { return String[i]; }
void SetAllocatedString(T *String, size_t size)
{
free();
this->String = String;
this->size = size;
}
void join(LPWSTR StringToJoin)
{
join(AnyString(StringToJoin));
}
void join(LPSTR StringToJoin)
{
join(AnyString(StringToJoin));
}
void join(AnyString StringToJoin)
{
if (typeid(T) == typeid(CHAR))
{
size_t length = 0;
_TString<CHAR> TempString;
LPSTR StringLiteral = nullptr;
if (StringToJoin.bWide)
{
TempString = ToCHAR(StringToJoin);
StringLiteral = TempString;
}
else
{
StringLiteral = StringToJoin;
}
if (StringLiteral != nullptr)
length = strlen(StringLiteral);
if (length != 0)
{
size_t newsize = size + length, realsize = newsize + 1;
T *Buffer = new T[realsize];
for (size_t i = 0; i < size; i++)
Buffer[i] = String[i];
for (size_t i = size, j = 0; i < newsize; i++, j++)
Buffer[i] = StringLiteral[j];
Buffer[newsize] = '\0';
free();
size = newsize;
String = Buffer;
}
}
else if (typeid(T) == typeid(WCHAR))
{
size_t length = 0;
_TString<WCHAR> TempString;
LPWSTR StringLiteral = nullptr;
if (StringToJoin.bWide)
{
StringLiteral = StringToJoin;
}
else
{
TempString = ToWCHAR(StringToJoin);
StringLiteral = TempString;
}
if (StringLiteral != nullptr)
length = wcslen(StringLiteral);
if (length != 0)
{
size_t newsize = size + length, realsize = newsize + 1;
T *Buffer = new T[realsize];
for (size_t i = 0; i < size; i++)
Buffer[i] = String[i];
for (size_t i = size, j = 0; i < newsize; i++, j++)
Buffer[i] = StringLiteral[j];
Buffer[newsize] = L'\0';
free();
size = newsize;
String = Buffer;
}
}
}
size_t GetSize() { return size; }
T* GetString() { return String; }
};
_TString<CHAR> TCatA(std::initializer_list<AnyString> list)
{
_TString<CHAR> String;
for (auto iterator = list.begin(), end = list.end(); iterator != end; ++iterator)
String.join(*iterator);
return String;
}
_TString<WCHAR> TCatW(std::initializer_list<AnyString> list)
{
_TString<WCHAR> String;
for (auto iterator = list.begin(), end = list.end(); iterator != end; ++iterator)
String.join(*iterator);
return String;
}
// TString code end
// Main code start
#define EXTENSION_NAME YOUR_EXTENSION_NAME //"my-extension" in ANSI
void WriteToOutputWindow(LPCSTR Text) { OutputDebugStringA(Text); }
void GetProjectDirectory(TString &Path)
{
TCHAR MaxPath[MAX_PATH] = { 0 };
GetModuleFileName(NULL, MaxPath, MAX_PATH);
for (int i = _tcslen(MaxPath), ch = 0; i > 0; i--)
{
if (MaxPath[i] == TEXT('\\') && ++ch == 2)
break;
else
MaxPath[i] = TEXT('\0');
}
Path.join(MaxPath);
}
void GetDataDirectory(TString &Path)
{
GetProjectDirectory(Path);
TCHAR TempBuffer[MAX_PATH] = { 0 }, FinalBuffer[MAX_PATH] = { 0 };
for (size_t i = Path.GetSize() - 1, ch = 0, j = 0; i > 0; i--, j++)
{
if (Path[i] == TEXT('\\') && ++ch == 2)
break;
else
TempBuffer[j] = Path[i];
}
for (size_t i = _tcslen(TempBuffer), j = 0; i > 0; i--, j++)
FinalBuffer[j] = TempBuffer[i - 1];
Path.join(FinalBuffer);
}
bool Restart()
{
int msgboxID = MessageBox(NULL, TEXT("Firefox has been closed. Save changes and press \"Yes\" to run again."), TEXT("Run again?"), MB_YESNO | MB_ICONQUESTION);
switch (msgboxID)
{
case IDYES:
return true;
case IDNO:
return false;
}
}
int WINAPI _tWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrev, _In_ LPTSTR lpCmdLine, _In_ int nCmdShow)
{
CMDREDIRECTION Window(WriteToOutputWindow);
TString ExtensionDir;
TString DataDir;
if (Window.Start())
{
GetProjectDirectory(ExtensionDir);
GetDataDirectory(DataDir);
ExtensionDir.join(TEXT("Firefox SDK\\"));
if (!PathIsDirectory(ExtensionDir))
Window.WriteToCmdAndWaitForAnswer(TCatA({ "mkdir \"", ExtensionDir.GetString(), "\"" }), 0, "", true);
if (PathIsDirectoryEmpty(ExtensionDir))
{
MessageBox(NULL, TCat({ TEXT("Firefox SDK directory is empty, please copy SDK files to this directory: "), ExtensionDir.GetString() }), TEXT("Failure!"), MB_ICONINFORMATION);
return EXIT_FAILURE;
}
Window.WriteToCmdAndWaitForAnswer(TCatA({ "cd ", ExtensionDir.GetString() }), 0, "", true);
Window.WriteToCmdAndWaitForAnswer("bin\\activate", 0, "", true);
ExtensionDir.join(TCat({ TEXT(EXTENSION_NAME), TEXT("\\") }));
if (!PathIsDirectory(ExtensionDir))
Window.WriteToCmdAndWaitForAnswer(TCatA({ "mkdir ", EXTENSION_NAME }), 0, "", true);
Window.WriteToCmdAndWaitForAnswer(TCatA({ "cd ", EXTENSION_NAME }), 0, "", true);
if (PathIsDirectoryEmpty(ExtensionDir))
Window.WriteToCmdAndWaitForAnswer("cfx init", 0, "", true);
do
{
/*
Window.WriteToCmdAndWaitForAnswer(TCatA({ "cd ", DataDir.GetString() }), 0, "", true);
Window.WriteToCmdAndWaitForAnswer(TCatA({ "XCOPY \"main.js\" \"", ExtensionDir.GetString(), TEXT(EXTENSION_NAME), "\\lib\\\" /Y" }), 0, "", true);
Window.WriteToCmdAndWaitForAnswer(TCatA({ "XCOPY \"*.js\" \"", ExtensionDir.GetString(), TEXT(EXTENSION_NAME), "\\data\\\" /Y /EXCLUDE:exclude.txt" }), 0, "", true);
Window.WriteToCmdAndWaitForAnswer(TCatA({ "XCOPY \"*.html\" \"", ExtensionDir.GetString(), TEXT(EXTENSION_NAME), "\\data\\\" /Y" }), 0, "", true);
Window.WriteToCmdAndWaitForAnswer(TCatA({ "XCOPY \"*.png\" \"", ExtensionDir.GetString(), TEXT(EXTENSION_NAME), "\\data\\\" /Y" }), 0, "", true);
Window.WriteToCmdAndWaitForAnswer(TCatA({ "XCOPY \"*.css\" \"", ExtensionDir.GetString(), TEXT(EXTENSION_NAME), "\\data\\\" /Y" }), 0, "", true);
*/
Window.WriteToCmdAndWaitForAnswer("cfx run --profiledir=\"./dir\"", 0, "Program terminated successfully.", true);
} while (Restart());
}
return EXIT_SUCCESS;
}
// Main code end
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...
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
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
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);
}
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;
}