DirectX Texture Warping - winapi

I am writing a WIN32 DirectX 9 program in which I load a few textures (a person and a background) and display them on the screen. However, they become warped (stretched), not being a one-to-one representation of what I drew in Paint. I tried different window sizes and different screen resolutions, but it still doesn't work.
I can force a very close imitation of the original thing by calling D3DXMatrixTransformation2D before drawing the sprite. However, that doesn't fix the problem. My program relies on me knowing exactly where the person is in relevence to the background (in reality, the background moves and the person stays in the middle of the screen).
Is there something simple I am missing or is it that I just can't do that for some reason? I can give code if it more than a simple fix, but I hope not. For the record, I recieve no errors or warnings; it's just a visual and movement-tracking issue. Thank you.
EDIT: Here's some code:
//start of program
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
//Define and register the Windows Class ***Function
createWindowClass(hInstance);
//Create the window (still not shown)
HWND hWnd = CreateWindow("Sample Window Class", "Person With Ship", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, hInstance, NULL);
//Define and create the DirectX9 object ***Function
HRESULT hr = createDirectX(hWnd);
D3DXCreateSprite(d3dDevice, &sprite);
D3DXCreateTextureFromFile(d3dDevice, "landingPad2.png", &texture);
D3DXCreateTextureFromFile(d3dDevice, "person.png", &person);
//D3DXCreateTextureFromFile(d3dDevice, "secondRoom.png", &secondRoom);
//Set up text
LPD3DXFONT mFont;
D3DXCreateFont(d3dDevice, 20, 0, FW_BOLD, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, TEXT("Arial"), &mFont );
//Finally show window
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
//setup keyboard
RAWINPUTDEVICE Rid[1]; // array of structs for input devices
Rid[0].usUsagePage = 1; // use 1 for most inputs
Rid[0].usUsage = 6; //2-mouse, 4-joystick, 6-keyboard
Rid[0].dwFlags = 0; //use 0
Rid[0].hwndTarget=NULL; //use NULL
RegisterRawInputDevices(Rid,1,sizeof(RAWINPUTDEVICE)); // registers all of the input devices
//MAIN LOOP!!
MSG msg;
ZeroMemory(&msg, sizeof(msg));
while (msg.message!=WM_QUIT)
{
while(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
updateGraphics(hr, mFont);
updatePosition();
}
mFont->Release();
texture->Release();
return msg.wParam;
}
void createWindowClass(HINSTANCE hInstance)
{
const LPCSTR CLASS_NAME = "Sample Window Class";
//create windows object
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style= CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc= (WNDPROC)WndProc;
wcex.cbClsExtra= 0;
wcex.cbWndExtra= 0;
wcex.hInstance= hInstance;
wcex.hIcon= 0;
wcex.hCursor= LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground= (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName= 0;
wcex.lpszClassName= CLASS_NAME;
wcex.hIconSm= 0;
//register windows class
RegisterClassEx(&wcex);
}
HRESULT createDirectX(HWND hWnd)
{
//create directx object
d3dObject = Direct3DCreate9(D3D_SDK_VERSION);
if (d3dObject==NULL)
{
exit(1);
}
//Present Parameters struct
D3DPRESENT_PARAMETERS presParams;
//Sets everything to 0
ZeroMemory(&presParams, sizeof(presParams));
presParams.Windowed = TRUE;
presParams.SwapEffect = D3DSWAPEFFECT_DISCARD;
presParams.BackBufferFormat = D3DFMT_UNKNOWN;
presParams.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
//DIRECT3D Stuff (not used currently)
//presParams.EnableAutoDepthStencil = TRUE;
//presParams.AutoDepthStencilFormat = D3DFMT_D16;
//d3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
//D3DXMatrixIdentity( &worldMatrix );
HRESULT hr = d3dObject->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &presParams, &d3dDevice);
return hr;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INPUT:
{
UINT bufferSize;
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &bufferSize, sizeof (RAWINPUTHEADER));
// Create a buffer of the correct size
BYTE *buffer=new BYTE[bufferSize];
// Call the function again, this time with the buffer to get the data
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, (LPVOID)buffer, &bufferSize, sizeof (RAWINPUTHEADER));
PRAWINPUT raw = (RAWINPUT*) buffer;
getInput(raw);
break;
}
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
int wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_EXIT:
DestroyWindow(hWnd);
break;
}
break;
}
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
void getInput(PRAWINPUT raw)
{
if (raw->header.dwType== RIM_TYPEKEYBOARD)
{
USHORT keyCode = raw->data.keyboard.VKey;
switch(keyCode)
{
case VK_LEFT:
keyUp=raw->data.keyboard.Flags & RI_KEY_BREAK;
if (keyUp == false)
counterTrue = true;
else
counterTrue = false;
break;
case VK_RIGHT:
keyUp=raw->data.keyboard.Flags & RI_KEY_BREAK;
if (keyUp == false)
clockwiseTrue = true;
else
clockwiseTrue = false;
break;
case VK_UP:
keyUp=raw->data.keyboard.Flags & RI_KEY_BREAK;
if (keyUp == false)
upTrue = true;
else
upTrue = false;
break;
case VK_DOWN:
keyUp=raw->data.keyboard.Flags & RI_KEY_BREAK;
if (keyUp == false)
downTrue = true;
else
downTrue = false;
break;
default:
break;
}
if (keyCode == 'A')
{
keyUp=raw->data.keyboard.Flags & RI_KEY_BREAK;
if (keyUp == false)
leftTrue = true;
else
leftTrue = false;
}
if (keyCode == 'D')
{
keyUp=raw->data.keyboard.Flags & RI_KEY_BREAK;
if (keyUp == false)
rightTrue = true;
else
rightTrue = false;
}
if (keyCode == 'W')
{
keyUp=raw->data.keyboard.Flags & RI_KEY_BREAK;
if (keyUp == false)
upTrue = true;
else
upTrue = false;
}
if (keyCode == 'S')
{
keyUp=raw->data.keyboard.Flags & RI_KEY_BREAK;
if (keyUp == false)
downTrue = true;
else
downTrue = false;
}
}
}
void updateGraphics(HRESULT hr, LPD3DXFONT mFont)
{
hr = d3dDevice->Clear(0, NULL, D3DCLEAR_TARGET| D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1.0f, 0);
hr = d3dDevice->BeginScene();
sprite->Begin(D3DXSPRITE_ALPHABLEND);
// Texture being used is 64 by 64:
D3DXVECTOR2 spriteCentre=D3DXVECTOR2(rotationCenter.x, rotationCenter.y);
// Screen position of the sprite
D3DXVECTOR2 trans=D3DXVECTOR2(pos.x, pos.y);
// Build our matrix to rotate, scale and position our sprite
D3DXMATRIX mat;
D3DXVECTOR2 scaling(0.5798f, 0.784f);
// out, scaling centre, scaling rotation, scaling, rotation centre, rotation, translation
D3DXMatrixTransformation2D(&mat,NULL, NULL, &scaling,&spriteCentre,rotation,NULL/*&trans*/);
// Tell the sprite about the matrix
sprite->SetTransform(&mat);
sprite->Draw(texture, NULL, &rotationCenter, &pos, 0xFFFFFFFF);
scaling.x = 0.53;
scaling.y = 0.57f;
D3DXMatrixTransformation2D(&mat,NULL,0.0, &scaling,&spriteCentre, 0,NULL/*&trans*/);
sprite->SetTransform(&mat);
sprite->Draw(person, NULL, NULL, &personPos, 0xFFFFFFFF);
sprite->End();
DisplaySomeText(mFont);
d3dDevice->EndScene();
d3dDevice->Present(NULL, NULL, NULL, NULL);
}
void updatePosition()
{
if (clockwiseTrue == true)
{
rotation -= (float)0.03;
}
else if (counterTrue == true)
{
rotation += (float)0.03;
}
if (rotation >(PI))
{
rotation -= (float)(2*PI);
}
if (rotation <= -(PI))
{
rotation += (float)(2*PI);
}
if (upTrue == true)
{
pos.y += (3*cos(rotation));
pos.x += (3*sin(rotation));
}
else if (downTrue == true)
{
pos.y -= (3*cos(rotation));
pos.x -= (3*sin(rotation));
}
if (leftTrue == true)
{
pos.x += (3*cos(rotation));
pos.y -= (3*sin(rotation));
}
else if (rightTrue == true)
{
pos.x -= (3*cos(rotation));
pos.y += (3*sin(rotation));
}
//collision detection
if (rotation >=0 && rotation < (PI/2))
{
if (pos.y - (30*cos(rotation)) - (30*sin(rotation)) < -138 && pos.x < 350 && pos.x > -550)
{
pos.y = -142 + (30*cos(rotation)) + (30*sin(rotation));
}
}
if (rotation < 0 && rotation > -(PI/2))
{
if (pos.y - (51*cos(rotation)) + (14*sin(rotation)) < -142 && pos.x < 350 && pos.x > -550)
{
pos.y = -142 + (51*cos(rotation)) - (14*sin(rotation));
}
}
if (rotation < -(PI/2) && rotation > -(PI))
{
if (pos.y + (51*cos(rotation)) + (14*sin(rotation)) < -142 && pos.x < 350 && pos.x > -550)
{
pos.y = -142 - (51*cos(rotation)) - (14*sin(rotation));
}
}
if (rotation > (PI/2) && rotation <= (PI))
{
if (pos.y + (51*cos(rotation)) - (14*sin(rotation)) < -142 && pos.x < 350 && pos.x > -550)
{
pos.y = -142 - (51*cos(rotation)) + (14*sin(rotation));
}
}
}
void DisplaySomeText(LPD3DXFONT mFont)
{
// Create a colour for the text - in this case blue
D3DCOLOR fontColor = D3DCOLOR_ARGB(255,0,0,255);
// Create a rectangle to indicate where on the screen it should be drawn
RECT rct;
rct.left=200;
rct.right=780;
rct.top=10;
rct.bottom=rct.top+20;
TCHAR cX[30] = "x";
TCHAR cY[30] = "y";
TCHAR cR[30] = "r";
TCHAR cQ[30] = "q";
size_t cchDest = 30;
LPCTSTR pszFormat = TEXT("%f");
HRESULT har = StringCchPrintf(cX, cchDest, pszFormat, pos.x);
HRESULT her = StringCchPrintf(cY, cchDest, pszFormat, pos.y);
HRESULT hir = StringCchPrintf(cR, cchDest, pszFormat, rotation);
HRESULT hur = StringCchPrintf(cQ, cchDest, pszFormat, (pos.y - (43*cos(rotation))));
mFont->DrawText(NULL, cX, -1, &rct, 0, fontColor);
rct.left += 100;
mFont->DrawText(NULL, cY, -1, &rct, 0, fontColor);
rct.left += 100;
mFont->DrawText(NULL, cR, -1, &rct, 0, fontColor);
rct.left += 100;
mFont->DrawText(NULL, cQ, -1, &rct, 0, fontColor);
}

So, finally: the issue was due to the texture dimensions not being powers of two :) This behaviour is quite usual, but it is still hardware-dependent: in theory there may exist some videocards which handle arbitrary texture sizes the same way as power-of-two-sized ones. To know that they do we'd have to check their capabilities via IDirect3DDevice9::GetDeviceCaps.

Related

How to get windows folder display order by C + +

I need to get the pictures in the windows folder and sort them according to the order in which they are displayed. Now there is a method to traverse the entire folder display items through the handle by getting the folder window handle. However, this method has a drawback: it can't get the order of the unopened folder, because there is no open file and no window handle.
Qt is used.
Please forgive my grammatical mistakes.
//Find out the current folder window according to the mouse click position
HWND findOpenFileWindow(const QString& path)
{
Sleep(3 * 1000);
POINT pNow = { 0, 0 };
if (!GetCursorPos(&pNow))
return NULL;
TCHAR szClass[255] = {0};
HWND pMouseChooseHandle = WindowFromPoint(pNow);
HWND pParent = ::GetParent(pMouseChooseHandle);
GetClassName(pParent, szClass, 255);
if (_tcscmp(szClass, L"SHELLDLL_DefView") == 0 || _tcscmp(szClass, L"NSEViewClass") == 0 )
{
bool bQingDisk = _tcscmp(szClass, L"NSEViewClass") == 0;
pParent = ::GetParent(pParent);
GetClassName(pParent, szClass, 255);
if (_tcscmp(szClass, L"WorkerW"))
{
pParent = pMouseChooseHandle;
for (int i = 0; i < 6; i++)
{
if(pParent != NULL)
pParent = ::GetParent(pParent);
}
HWND pChild = ::GetWindow(pParent, GW_CHILD);
GetClassName(pChild, szClass, 255);
while (pChild != NULL)
{
GetClassName(pChild, szClass, 255);
if (_tcscmp(szClass, TEXT("ShellTabWindowClass")) == 0)
{
pParent = pChild;
break;
}
pChild = ::GetNextWindow(pChild, GW_HWNDNEXT);
}
TCHAR exploreWndName[MAX_PATH] = {0};
::GetWindowText(pParent, exploreWndName, MAX_PATH);
if(QFileInfo(path).fileName() == QString().fromWCharArray(exploreWndName))
return pParent;
}
}
return NULL;
}
//Traverse window display items, get them
QStringList listNormalFolderFile( const QString& path, const QStringList& filter )
{
HWND folderWnd = findOpenFileWindow(path);
HWND hwnd;
IDispatch *pDispatch;
CComPtr<IShellWindows> pShellWindows;
CoInitialize(NULL);
HRESULT hr = CoCreateInstance(CLSID_ShellWindows, NULL, CLSCTX_ALL, IID_PPV_ARGS(&pShellWindows));
if (FAILED(hr))
{
CoUninitialize();
return QStringList();
}
LONG lCount = 0;
pShellWindows->get_Count(&lCount);
QStringList fileList;
for (LONG i = 0; i < lCount; i++)
{
CComPtr<IShellBrowser> pShellBrowser;
VARIANT var;
var.vt = VT_I4;
var.lVal = i;
if(SUCCEEDED(pShellWindows->Item(var, &pDispatch)))
{
if(SUCCEEDED(IUnknown_QueryService(pDispatch, SID_STopLevelBrowser, IID_PPV_ARGS(&pShellBrowser))))
{
if (SUCCEEDED(IUnknown_GetWindow(pShellBrowser, &hwnd)))
{
TCHAR szBuf[256];
GetWindowText(hwnd, szBuf, sizeof(szBuf) / sizeof(TCHAR));
if(QFileInfo(path).fileName() != QString().fromWCharArray(szBuf))
continue;
CComPtr<IShellView> pShellView;
if(FAILED(pShellBrowser->QueryActiveShellView(&pShellView)))
continue;
CComPtr<IFolderView> pFv = NULL;
/*
do something here
*/
CComPtr<IPersistFolder2 > pFolder;
if( FAILED(pFv->GetFolder(IID_IPersistFolder2, (void**) &pFolder)))
continue;
LPITEMIDLIST pidl = nullptr;
if( SUCCEEDED(pFolder->GetCurFolder(&pidl)))
{
wchar_t cPath[32767];
if( ::SHGetPathFromIDList(pidl, cPath))
{
QString filePath;
QFileInfo fileInfo(filePath.fromWCharArray(cPath));
if(fileInfo.absoluteFilePath() == QFileInfo(path).absoluteFilePath())
{
if(folderWnd == NULL || folderWnd == hwnd)
{
fileList = listFileInBrowser(pShellBrowser, filter);
break;
}
}
}
}
}
}
}
}
CoUninitialize();
return fileList;

How do I implement double buffering in the winapi?

I can't stop the flickering. I got the advice to add dubbel-buffering. How do I do that?
#include <iostream>
#include <windows.h>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
namespace {
const int ID_NEW = 1;
const int ID_QUIT = 2;
const int ID_ABOUT = 3;
const int NORTH_BUTTON_ID = 4;
const int SOUTH_BUTTON_ID = 5;
const int WEST_BUTTON_ID = 6;
const int EAST_BUTTON_ID = 7;
const int ID_FINISHED_GAME = 8;
int x = 0;
int y = 0;
int xStart = 0;
int yStart = 0;
int windowHeight = 400;
int windowWidth = 500;
char level1[20][21];
int noOfMoves = 0;
}
void readLevel(string fileName, char level[20][21]) {
char character{};
ifstream file(fileName);
int i = 0;
int j = 0;
if (file.is_open()) {
while (file >> character) {
level[j][i] = character;
if (level[j][i] == 's') {
y = yStart = j;
x = xStart = i;
}
if (++i % 20 == 0) {
i = 0;
j++;
}
}
file.close();
}
}
void restart(){
x = xStart;
y = yStart;
noOfMoves = 0;
}
LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
HDC hdc{ 0 };
PAINTSTRUCT ps{ 0 };
switch (msg) {
case WM_CLOSE:
PostQuitMessage(0);
return 0;
case WM_COMMAND:
switch (LOWORD(wParam)){
case ID_ABOUT:
MessageBox(hwnd, L"About this program!", L"About", MB_OK);
return 0;
case ID_NEW:
restart();
return 0;
case ID_QUIT:
if (MessageBox(0, L"Do you really want to quit?", L"Are you sure?", MB_YESNO) == IDYES) {
PostQuitMessage(0);
return 0;
}
case NORTH_BUTTON_ID:
if (level1[y - 1][x] != '1') {
y -= 1;
noOfMoves++;
}
break;
case SOUTH_BUTTON_ID:
if (level1[y + 1][x] != '1'){
y += 1;
noOfMoves++;
}
break;
case WEST_BUTTON_ID:
if (level1[y][x - 1] != '1'){
x -= 1;
noOfMoves++;
}
break;
case EAST_BUTTON_ID:
if (level1[y][x + 1] != '1') {
x += 1;
noOfMoves++;
}
break;
}
if (level1[y][x] == 'e') {
wstring moves = L"Congratulations, you finished the game with " + to_wstring(noOfMoves);
MessageBox(hwnd, moves.c_str(), L"Finished game", MB_OK);
}
case WM_PAINT: {
char wall[2] = { "W" };
char floor[2] = { 'W' };
char current[2] = { "X" };
char goal[2] = { "G" };
wstring position = L"Position = [" + to_wstring(x) + L", " + to_wstring(y) + L"]";
wstring moves = L"Move = " + to_wstring(noOfMoves);
hdc = BeginPaint(hwnd, &ps);
TextOut(hdc, 20, 200, position.c_str(), position.size());
TextOut(hdc, 20, 220, moves.c_str(), moves.size());
for (int i = 0; i < 20; i++) {
for (int j = 0; j < 20; j++) {
if (level1[j][i] == '1') {
SetTextColor(hdc, RGB(0, 0, 0));
SetBkColor(hdc, RGB(0, 0, 0));
TextOut(hdc, 14 * i + 190, 14 * j + 20, LPCTSTR(wall), strlen(wall));
}
SetBkColor(hdc, RGB(255, 255, 255));
if (level1[j][i] == '0') {
SetTextColor(hdc, RGB(255, 255, 255));
TextOut(hdc, 14 * i + 190, 14 * j + 20, LPCTSTR(floor), strlen(floor));
}
SetTextColor(hdc, RGB(0, 0, 0));
if (i == x && j == y)
TextOut(hdc, 14 * i + 190, 14 * j + 20, LPCTSTR(current), strlen(current));
if (level1[j][i] == 'e')
TextOut(hdc, 14 * i + 190, 14 * j + 20, LPCTSTR(goal), strlen(goal));
}
}
EndPaint(hwnd, &ps);
break;
}
case WM_ERASEBKGND:
return true;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
HMENU CreateMainMenu() {
HMENU main = CreateMenu();
HMENU file = CreateMenu();
AppendMenu(file, MF_STRING, ID_NEW, L"&New");
AppendMenu(file, MF_SEPARATOR, 0, 0);
AppendMenu(file, MF_STRING, ID_QUIT, L"&Quit");
AppendMenu(main, MF_POPUP, (UINT_PTR)file, L"&File");
HMENU help = CreateMenu();
AppendMenu(help, MF_STRING, ID_ABOUT, L"&About");
AppendMenu(main, MF_POPUP, (UINT_PTR)help, L"&Help");
return main;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow) {
readLevel("level1.txt", level1);
WNDCLASS wc = { 0 };
wc.hbrBackground = NULL;
wc.lpfnWndProc = WinProc;
wc.hInstance = hInstance;
wc.lpszClassName = L"MyWindowClass";
RegisterClass(&wc);
HWND hwnd = CreateWindow(L"MyWindowClass", L"The Maze",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
windowWidth, windowHeight, 0, CreateMainMenu(), hInstance, 0);
HWND buttonNorth = CreateWindow(L"BUTTON", L"NORTH", WS_CHILD | WS_VISIBLE,
10, 20, 150, 40, hwnd, (HMENU)NORTH_BUTTON_ID, hInstance, 0);
HWND buttonSouth = CreateWindow(L"BUTTON", L"SOUTH", WS_CHILD | WS_VISIBLE,
10, 60, 150, 40, hwnd, (HMENU)SOUTH_BUTTON_ID, hInstance, 0);
HWND buttonEast = CreateWindow(L"BUTTON", L"EAST", WS_CHILD | WS_VISIBLE,
10, 140, 150, 40, hwnd, (HMENU)EAST_BUTTON_ID, hInstance, 0);
HWND buttonWest = CreateWindow(L"BUTTON", L"WEST", WS_CHILD | WS_VISIBLE,
10, 100, 150, 40, hwnd, (HMENU)WEST_BUTTON_ID, hInstance, 0);
UpdateWindow(hwnd);
ShowWindow(hwnd, nCmdShow);
MSG msg = { 0 };
BOOL isRunning = true;
while (isRunning) {
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT)
isRunning = false;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
wc.hbrBackground = NULL;
InvalidateRect(hwnd, NULL, FALSE);
Sleep(10);
}
return 0;
}
As member Retired Ninja said, you make compatible device context with the original one ( hdc in your case ), and create a bitmap compatible with your original device context ( bitmap size is equal to the size of your rectangle where you paint your stuff ).
Then select this newly created bitmap into compatible device context you just created and draw everything on it.
Then you just BitBlt(...) the compatible device context into original one.
Do not forget to perform proper cleanup in order to avoid GDI leaks.
Your code should look like this:
case WM_PAINT:
{
// skipped the initialization part to preserve space
// just copy those, they are irrelevant for your problem
hdc = BeginPaint(hwnd, &ps);
// create memory DC and memory bitmap where we shall do our drawing
HDC memDC = CreateCompatibleDC( hdc );
// get window's client rectangle. We need this for bitmap creation.
RECT rcClientRectangle;
GetClientRect( hwnd, &rcClientRect );
// now we can create bitmap where we shall do our drawing
HBITMAP bmp = CreateCompatibleBitmap( hdc,
rcClientRect.right - rcClientRect.left,
rcClientRect.bottom - rcClientRect.top );
// we need to save original bitmap, and select it back when we are done,
// in order to avoid GDI leaks!
HBITMAP oldBmp = (HBITMAP)SelectObject( memDC, bmp );
// now you draw your stuff in memory dc;
// just substitute hdc with memDC in your drawing code,
// like I did below:
TextOut( memDC, //...
TextOut( memDC, //...
for (int i = 0; i < 20; i++)
{
for (int j = 0; j < 20; j++)
{
if (level1[j][i] == '1')
{
SetTextColor( memDC, //...
SetBkColor( memDC, //...
TextOut( memDC, //...
}
SetBkColor( memDC, //...
if (level1[j][i] == '0')
{
SetTextColor( memDC, //...
TextOut( memDC, //...
}
SetTextColor( memDC, //...
if (i == x && j == y)
TextOut( memDC, //...
if (level1[j][i] == 'e')
TextOut( memDC, //...
}
}
// OK, everything is drawn into memory DC,
// now is the time to draw that final result into our target DC
BitBlt( hdc, 0, 0, rcClientRect.right - rcClientRect.left,
rcClientRect.bottom - rcClientRect.top, memDC, 0, 0, SRCCOPY );
// all done, now we need to cleanup
SelectObject( memDC, oldBmp ); // select back original bitmap
DeleteObject( bmp ); // delete bitmap since it is no longer required
DeleteDC( memDC ); // delete memory DC since it is no longer required
EndPaint(hwnd, &ps);
break;
}

How can I reinitialize my code

Hi I am currently working on a project where we are creating a UDP server to communicate with a KUKA robot. We are able to establish the connection with the robot and exchange the data back and forth but when an event occurs such as the robot faulting out due to motor over torque. So to detect this fault we have added a timeout to the code so that the main dialog box will close and reopen so that all the variables will be reinitialized and we can set the connection to reestablish.
Heres the server code:
#include "stdafx.h"
#include "HapticRobot.h"
#include "CMaths.h"
using namespace chai3d;
#include <winsock.h>
using namespace std;
#pragma comment(lib, "Ws2.lib")
#include <fstream>
#include <string>
#include <sstream>
DWORD WINAPI DoGravity(LPVOID lpParameter);
#define REFRESH_INTERVAL 0 // sec
const int kBufferSize = 1024;
int nTempHold;
extern HapticDevice hd;
extern HWND g_hWndHapticBox;
extern bool bRobotInMotion, bRobotConnectInit, bRobotConnected;
extern Handles hc;
bool err;
std::string stSend, stSendXML, stLine;
std::string stRobotStatus , stAppend;
TCHAR *chRobotStatus;
//variables for timeout
fd_set fds;
int n;
struct timeval tv;
//// Prototypes ////////////////////////////////////////////////////////
SOCKET SetUpListener(const char* pcAddress, int nPort);
bool EchoIncomingPackets(SOCKET sd);
//// DoWinsock /////////////////////////////////////////////////////////
// The module's driver function -- we just call other functions and
// interpret their results.
int DoWinsock(const char* pcAddress, int nPort)
{
int nRetval = 0;
ifstream inFile("HardDisk/ExternalData.xml");
if (inFile.is_open())
{
while ( inFile.good() )
{
getline ( inFile, stLine);
stSendXML.append(stLine);
}
inFile.close();
}
SendDlgItemMessage(g_hWndHapticBox, IDC_LIST_Server, LB_INSERTSTRING, 0, (LPARAM)L"Establishing the listener...");
SOCKET ListeningSocket = SetUpListener(pcAddress, htons(nPort));
SendDlgItemMessage(g_hWndHapticBox, IDC_LIST_Server, LB_INSERTSTRING, 0, (LPARAM)L"Waiting for connections...");
bRobotConnectInit = true;
SetDlgItemText(g_hWndHapticBox, IDC_STATIC_RobotStatus, _T("Waiting for robot"));
while (1)
{
EchoIncomingPackets(ListeningSocket);
bRobotConnected = false;
bRobotConnectInit = true;
SendDlgItemMessage(g_hWndHapticBox, IDC_LIST_Server, LB_INSERTSTRING, 0, (LPARAM)L"Acceptor restarting...");
}
}
//// SetUpListener /////////////////////////////////////////////////////
// Sets up a listener on the given interface and port, returning the
// listening socket if successful; if not, returns INVALID_SOCKET.
SOCKET SetUpListener(const char* pcAddress, int nPort)
{
u_long nInterfaceAddr = inet_addr(pcAddress);
if (nInterfaceAddr != INADDR_NONE)
{
SOCKET sd = socket(AF_INET, SOCK_DGRAM, 0);
sockaddr_in sinInterface;
sinInterface.sin_family = AF_INET;
sinInterface.sin_addr.s_addr = nInterfaceAddr;
sinInterface.sin_port = nPort;
if (bind(sd, (sockaddr*)&sinInterface,
sizeof(sockaddr_in)) != SOCKET_ERROR)
{
return sd;
}
}
return INVALID_SOCKET;
}
//// EchoIncomingPackets ///////////////////////////////////////////////
// Bounces any incoming packets back to the client. We return false
// on errors, or true if the client closed the socket normally.
bool EchoIncomingPackets(SOCKET sd)
{
// Read data from client
std::string stReceive;
std::string stIPOC;
std::wstring stTime;
int nStartPos, nEndPos;
char acReadBuffer[kBufferSize], acWriteBuffer[512];
int nReadBytes;
struct sockaddr_in clientAddr;
int sockAddrSize = sizeof(struct sockaddr_in);
//declarations for the low pass filter
int CURRENT_VALUE = 2;
double T = .004, w_co, OMEGA_co, f_co;
hd.bFirstRunRobot = true;
do
{
//This will be to timeout the socket connection
FD_ZERO(&fds);
FD_SET(sd, &fds);
tv.tv_sec = 5;
tv.tv_usec = 0;
n = select (sd, &fds, NULL, NULL, &tv );
if (n == 0)
{
PostMessage(g_hWndHapticBox,WM_CLOSE, 0, 0);
Sleep(5000);
PostMessage(g_hWndHapticBox, WM_INITDIALOG, 0, 0);
Sleep(1000);
//printf("Timeout..\n");
//HapticBox(HWND, UINT, WPARAM, LPARAM);
//return 0;
}
else if (n == -1)
{
printf("Error..\n");
return 1;
}
// end timeout
nReadBytes = recvfrom(sd, acReadBuffer, sizeof(acReadBuffer), 0, (struct sockaddr*)&clientAddr, &sockAddrSize);
//nReadBytes = recvfrom(sd, acReadBuffer, sizeof(acReadBuffer), MSG_PEEK, (struct sockaddr*)&clientAddr, &sockAddrSize);
//if (nReadBytes == SOCKET_ERROR)
//{
// SetDlgItemText(g_hWndHapticBox, IDC_STATIC_RobotStatus, _T("ERROR"));
//}
if (nReadBytes < 0 || nReadBytes == 0)
{
SetDlgItemText(g_hWndHapticBox, IDC_STATIC_RobotStatus, _T("ERROR 1"));
return true;
}
if (nReadBytes > 0)
{
if (bRobotConnectInit)
{
bRobotConnectInit = false;
bRobotConnected = true;
SetDlgItemText(g_hWndHapticBox, IDC_STATIC_RobotStatus, _T("Connected to Robot"));
}
}
stSend = stSendXML;
stReceive = acReadBuffer;
nStartPos = stReceive.find ("<IPOC>") + 6;
nEndPos = stReceive.find ("</IPOC>");
stIPOC = stReceive.substr (nStartPos, nEndPos - nStartPos);
nStartPos = stSend.find ("<IPOC>") + 6;
nEndPos = stSend.find ("</IPOC>");
stSend.replace(nStartPos, nEndPos - nStartPos, stIPOC);
//Raw sensor data
nStartPos = stReceive.find ("RFx=") + 5;
nEndPos = stReceive.find ("RFy=") - 2;
hd.stRFx = stReceive.substr (nStartPos, nEndPos - nStartPos);
hd.szRFx = hd.stRFx.c_str();
hd.RFx = strtod(hd.szRFx, NULL);
hd.RFx = hd.RFx * 0.22;
nStartPos = stReceive.find ("RFy=") + 5;
nEndPos = stReceive.find ("RFz=") - 2;
hd.stRFy = stReceive.substr (nStartPos, nEndPos - nStartPos);
hd.szRFy = hd.stRFy.c_str();
hd.RFy = strtod(hd.szRFy, NULL);
hd.RFy = hd.RFy * 0.22;
**//...more XML stuff...//**
//data the is to be sent to the robot
if (hd.FirstTimePosition)
{
hd.RobotXStartPosition = hd.RobotXPosition;
hd.RobotYStartPosition = hd.RobotYPosition;
hd.RobotZStartPosition = hd.RobotZPosition;
hd.FirstTimePosition = false;
}
if(hd.LinearScale == 4)
{
f_co = 0.5;
}
else if (hd.LinearScale == 3)
{
f_co = 0.5;
}
else if (hd.LinearScale == 2)
{
f_co = 1;
}
else if (hd.LinearScale == 1)
{
f_co = 2;
}
else if (hd.LinearScale == 0.5)
{
f_co = 2;
}
else
{
f_co = 0.5;
}
if (hd.Fz < hd.MaxForcePos)
{
hd.ForceLimitPosZ = false;
}
if (hd.Fz > hd.MaxForceNeg)
{
hd.ForceLimitNegZ = false;
}
if (hd.Fz > hd.MaxForcePos || hd.ForceLimitPosZ)
{
if (!hd.ForceLimitPosZ)
{
hd.CurrentZtoRobotPosition = hd.ZtoRobot;
}
if (hd.CurrentZtoRobotPosition >= hd.ZtoRobot)
{
hd.NewZtoRobot = hd.PreviousZtoRobot;
hd.ForceLimitPosZ = true;
}
else
{
hd.ForceLimitPosZ = false;
}
}
if (hd.ForceLimitPosZ)
{
hd.ForceZtoRobot = hd.NewZtoRobot;
}
else
{
hd.ForceZtoRobot = hd.ZtoRobot;
}
w_co = f_co * C_TWO_PI;
OMEGA_co = (2/T) * cTanRad((w_co * T) / 2);
hd.raw_x[CURRENT_VALUE] = hd.XtoRobot;
hd.raw_y[CURRENT_VALUE] = hd.YtoRobot;
hd.raw_z[CURRENT_VALUE] = hd.ForceZtoRobot;
hd.filtered_x[CURRENT_VALUE] = (pow(((OMEGA_co) / ((2 / T) + OMEGA_co)), 2)) *
((hd.raw_x[CURRENT_VALUE]) + (2 * hd.raw_x[CURRENT_VALUE - 1] + hd.raw_x[CURRENT_VALUE - 2]))
- (((2 * (OMEGA_co - (2 / T))) / ((2 / T) + OMEGA_co)) * hd.filtered_x[CURRENT_VALUE - 1])
- ((pow(((OMEGA_co - (2 / T)) / ((2 / T) + OMEGA_co)),2)) * hd.filtered_x[CURRENT_VALUE - 2]);
**//more digital filter stuff//**
hd.raw_x[CURRENT_VALUE - 2] = hd.raw_x[CURRENT_VALUE - 1];
hd.raw_y[CURRENT_VALUE - 2] = hd.raw_y[CURRENT_VALUE - 1];
hd.raw_z[CURRENT_VALUE - 2] = hd.raw_z[CURRENT_VALUE - 1];
hd.raw_x[CURRENT_VALUE - 1] = hd.raw_x[CURRENT_VALUE];
hd.raw_y[CURRENT_VALUE - 1] = hd.raw_y[CURRENT_VALUE];
hd.raw_z[CURRENT_VALUE - 1] = hd.raw_z[CURRENT_VALUE];
hd.filtered_x[CURRENT_VALUE - 2] = hd.filtered_x[CURRENT_VALUE - 1];
hd.filtered_y[CURRENT_VALUE - 2] = hd.filtered_y[CURRENT_VALUE - 1];
hd.filtered_z[CURRENT_VALUE - 2] = hd.filtered_z[CURRENT_VALUE - 1];
hd.filtered_x[CURRENT_VALUE - 1] = hd.filtered_x[CURRENT_VALUE];
hd.filtered_y[CURRENT_VALUE - 1] = hd.filtered_y[CURRENT_VALUE];
hd.filtered_z[CURRENT_VALUE - 1] = hd.filtered_z[CURRENT_VALUE];
hd.stXtoRobot = dtostr(hd.filtered_x[CURRENT_VALUE]);
nStartPos = stSend.find ("X=") + 3;
stSend.replace(nStartPos, 6, hd.stXtoRobot);
hd.stYtoRobot = dtostr(hd.filtered_y[CURRENT_VALUE]);
nStartPos = stSend.find ("Y=") + 3;
stSend.replace(nStartPos, 6, hd.stYtoRobot);
hd.stZtoRobot = dtostr(hd.filtered_z[CURRENT_VALUE]);
nStartPos = stSend.find ("Z=") + 3;
stSend.replace(nStartPos, 6, hd.stZtoRobot);
if (hd.ForceLimitPosZ)
{
hd.PreviousZtoRobot = hd.NewZtoRobot;
}
else
{
hd.PreviousZtoRobot = hd.ZtoRobot;
}
strcpy( static_cast<char*>( &acWriteBuffer[0] ), stSend.c_str() );
if (nReadBytes > 0)
{
int nSentBytes = 0;
int SendLength = strlen(acWriteBuffer);
while (nSentBytes < SendLength)
{
int nTemp = sendto(sd, acWriteBuffer, SendLength, 0, (const sockaddr*)&clientAddr, sockAddrSize);
nTempHold = nTemp;
if (nTemp > 0)
{
nSentBytes += nTemp;
}
else if (nTemp == SOCKET_ERROR)
{
return false;
}
else
{
// Client closed connection before we could reply to
// all the data it sent, so bomb out early.
SendDlgItemMessage(g_hWndHapticBox, IDC_LIST_Server, LB_INSERTSTRING, 0, (LPARAM)L"Peer unexpectedly dropped connection!");
return true;
}
}
}
else if (nReadBytes == SOCKET_ERROR)
{
return false;
}
hd.bFirstRunRobot = false;
}while (nReadBytes != 0);
SendDlgItemMessage(g_hWndHapticBox, IDC_LIST_Server, LB_INSERTSTRING, 0, (LPARAM)L"Connection closed by peer.");
bRobotConnected = false;
bRobotConnectInit = true;
SetDlgItemText(g_hWndHapticBox, IDC_STATIC_RobotStatus, _T("Waiting for robot"));
SetDlgItemText(g_hWndHapticBox, IDC_STATIC_RobotInMotion, _T("Robot not in motion"));
return true;
//}
}
And here is the code for the GUI:
// HapticRobot.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "HapticRobot.h"
#include <sstream>
#include <string>
using namespace std;
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE g_hInst; // current instance
HWND g_hWndCommandBar; // command bar handle
HWND g_hWndHapticBox; // haptic dialog handle
bool bRobotInMotion, bRobotConnectInit, bRobotConnected;
extern HapticDevice hd;
HDC hdc;
Handles hc;
DWORD WINAPI DoGravity(LPVOID lpParameter);
DWORD WINAPI DoConnectRobot(LPVOID lpParameter);
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE, LPTSTR);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK HapticBox(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
// Perform application initialization:
if (!InitInstance(hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable;
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_HAPTICROBOT));
DialogBox(hInstance, (LPCTSTR)IDD_HAPTIC, NULL, HapticBox);
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
ATOM MyRegisterClass(HINSTANCE hInstance, LPTSTR szWindowClass)
{
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_HAPTICROBOT));
wc.hCursor = 0;
wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = 0;
wc.lpszClassName = szWindowClass;
return RegisterClass(&wc);
}
//FUNCTION: InitInstance(HINSTANCE, int)
//PURPOSE: Saves instance handle and creates main window
//COMMENTS:
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
TCHAR szTitle[MAX_LOADSTRING]; // title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // main window class name
g_hInst = hInstance; // Store instance handle in our global variable
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_HAPTICROBOT, szWindowClass, MAX_LOADSTRING);
if (!MyRegisterClass(hInstance, szWindowClass))
{
return FALSE;
}
hWnd = CreateWindow(szWindowClass, szTitle, WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
if (g_hWndCommandBar)
{
CommandBar_Show(g_hWndCommandBar, TRUE);
}
return TRUE;
}
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_HELP_ABOUT:
DialogBox(g_hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, About);
break;
case IDM_FILE_EXIT:
dhdClose ();
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_CREATE:
g_hWndCommandBar = CommandBar_Create(g_hInst, hWnd, 1);
CommandBar_InsertMenubar(g_hWndCommandBar, g_hInst, IDR_MENU, 0);
CommandBar_AddAdornments(g_hWndCommandBar, 0, 0);
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
dhdClose ();
CommandBar_Destroy(g_hWndCommandBar);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
RECT rectChild, rectParent;
int DlgWidth, DlgHeight; // dialog width and height in pixel units
int NewPosX, NewPosY;
// trying to center the About dialog
if (GetWindowRect(hDlg, &rectChild))
{
GetClientRect(GetParent(hDlg), &rectParent);
DlgWidth = rectChild.right - rectChild.left;
DlgHeight = rectChild.bottom - rectChild.top ;
NewPosX = (rectParent.right - rectParent.left - DlgWidth) / 2;
NewPosY = (rectParent.bottom - rectParent.top - DlgHeight) / 2;
// if the About box is larger than the physical screen
if (NewPosX < 0) NewPosX = 0;
if (NewPosY < 0) NewPosY = 0;
SetWindowPos(hDlg, 0, NewPosX, NewPosY,
0, 0, SWP_NOZORDER | SWP_NOSIZE);
}
return (INT_PTR)TRUE;
case WM_COMMAND:
if ((LOWORD(wParam) == IDOK) || (LOWORD(wParam) == IDCANCEL))
{
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
break;
case WM_CLOSE:
EndDialog(hDlg, message);
return TRUE;
}
return (INT_PTR)FALSE;
}
// Message handler for haptic box.
BOOL CALLBACK HapticBox(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
SetWindowPos(hDlg, 0, 130, 200,
0, 0, SWP_NOZORDER | SWP_NOSIZE);
hd.Done = 1;
bRobotInMotion = false;
bRobotConnectInit = false;
g_hWndHapticBox = hDlg;
hd.HapticScaleX = 100;
hd.HapticScaleY = 100;
hd.HapticScaleZ = 100;
hd.MaxForcePos = 160;
hd.MaxForceNeg = -160;
hd.EnableForces = true;
hd.ForceLimitPosX = false;
hd.ForceLimitPosY = false;
hd.ForceLimitPosZ = false;
hd.ForceLimitNegX = false;
hd.ForceLimitNegY = false;
hd.ForceLimitNegZ = false;
hd.filtered_x[0,1,2] = 0; //low pass output for x
hd.filtered_y[0,1,2] = 0; //low pass output for y
hd.filtered_z[0,1,2] = 0; //low pass output for z
hd.raw_x[0,1,2] = 0; //raw haptic data for low pass x
hd.raw_y[0,1,2] = 0; //raw haptic data for low pass y
hd.raw_z[0,1,2] = 0; //raw haptic data for low pass z
hc.Xmm = GetDlgItem(g_hWndHapticBox, IDC_STATIC_X);
hc.Ymm = GetDlgItem(g_hWndHapticBox, IDC_STATIC_Y);
hc.Zmm = GetDlgItem(g_hWndHapticBox, IDC_STATIC_Z);
hc.XtoRobot = GetDlgItem(g_hWndHapticBox, IDC_STATIC_XtoRobot);
hc.YtoRobot = GetDlgItem(g_hWndHapticBox, IDC_STATIC_YtoRobot);
hc.ZtoRobot = GetDlgItem(g_hWndHapticBox, IDC_STATIC_ZtoRobot);
hc.Fx = GetDlgItem(g_hWndHapticBox, IDC_STATIC_Fx);
hc.Fy = GetDlgItem(g_hWndHapticBox, IDC_STATIC_Fy);
hc.Fz = GetDlgItem(g_hWndHapticBox, IDC_STATIC_Fz);
hc.rHz = GetDlgItem(g_hWndHapticBox, IDC_STATIC_Rate);
hc.HapticStatus = GetDlgItem(g_hWndHapticBox, IDC_STATIC_HapticStatus);
hc.RobotInMotion = GetDlgItem(g_hWndHapticBox, IDC_STATIC_RobotInMotion);
hc.RobotStatus = GetDlgItem(g_hWndHapticBox, IDC_STATIC_RobotStatus);
///////////////////////////////////////////////////////////////////////////////////////
hd.HapticConnected = false;
if (hd.HapticConnected == false)
{
DWORD nThreadID;
CreateThread(0, 0, DoConnectRobot, 0, 0, &nThreadID);
Sleep(100);
CreateThread(0, 0, DoGravity, 0, 0, &nThreadID);
hd.HapticConnected = true;
}
return (INT_PTR)TRUE;
case WM_CTLCOLORSTATIC:
if(IDC_STATIC_HapticStatus == ::GetDlgCtrlID((HWND)lParam))
{
hdc = (HDC)wParam;
if (hd.Done == 1)
{
SetBkColor(hdc, RGB(255,0,0)); //red
return (BOOL)::CreateSolidBrush(RGB(255,0,0)); //red
}
else
{
SetBkColor(hdc, RGB(0,255,0)); //green
return (BOOL)::CreateSolidBrush(RGB(0,255,0)); //green
}
}
if(IDC_STATIC_RobotStatus == ::GetDlgCtrlID((HWND)lParam))
{
hdc = (HDC)wParam;
if (bRobotConnectInit)
{
SetBkColor(hdc, RGB(250, 255, 5)); //yellow
return (BOOL)::CreateSolidBrush(RGB(250, 255, 5));
}
else if (bRobotConnected)
{
SetBkColor(hdc, RGB(0,255,0)); //green
return (BOOL)::CreateSolidBrush(RGB(0,255,0));
}
else
{
SetBkColor(hdc, RGB(255,0,0)); //red
return (BOOL)::CreateSolidBrush(RGB(255,0,0));
}
}
if(IDC_STATIC_RobotInMotion == ::GetDlgCtrlID((HWND)lParam))
{
hdc = (HDC)wParam;
if (bRobotInMotion)
{
SetBkColor(hdc, RGB(0,255,0)); //green
return (BOOL)::CreateSolidBrush(RGB(0,255,0));
}
else
{
SetBkColor(hdc, RGB(255,0,0)); //red
return (BOOL)::CreateSolidBrush(RGB(255,0,0));
}
}
break;
case WM_CLOSE:
hd.Done = 1;
EndDialog(hDlg, message);
return TRUE;
}
return (INT_PTR)FALSE;
}
There is more code associated with the solution that if it is need I can attach. My thougt was thought to just call the WM_INITDIALOG case so that basically it would be the same as closing the program out and re opening it. Any suggestions would be appericated.
Callign WM_INITDIALOG definitely won't do what you think it will. Don't send random Windows messages unless you understand them exactly.
My suggestion, given your design, would be to have your program launch another instance of itself and have the old instance exit. Look into CreateProcess on MSDN for the details on how to launch another process. I think that this will be the most maintainable and easy-to-code solution given what you already have.
I would suggest making repeated calls to DialogBox like this:
do
{
DialogBox(hInstance, (LPCTSTR)IDD_HAPTIC, NULL, HapticBox);
} while (ReOpenDialog);
Where ReOpenDialog is a global you set according to the success of your operation (or, to avoid a global, you could use the dialog return result from DialogBox via EndDialog).
Also, you don't need a message loop because DialogBox calls have their own one inside, thus creating a blocking call (which is why my above loop will work, in fact!).

Using GetRawInputBuffer correctly

I'm attempting to use the Win32 Raw Input API to collect raw mouse data with higher precision, but I can't seem to make sense of the documentation and samples at all for GetRawInputBuffer.
While my mouse is hovering over the window, nothing seems to happen. I only seem to get buffered data when I click or release on the title bar of the window and even then I mostly get 0 movement values and never receive mouse button changes. I've followed samples as closely as possible and have had little luck searching online.
Below is the the Window Procedure and Main for a heavily simplified example bearing the issue.
LRESULT CALLBACK MessageHandler(HWND WindowHandle, UINT Message, WPARAM wParameter, LPARAM lParameter)
{
switch(Message)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
break;
case WM_CLOSE:
{
DestroyWindow(WindowHandle);
return 0;
}
break;
case WM_INPUT:
{
UINT RawInputSize;
UINT Result;
Result = GetRawInputBuffer(NULL, &(RawInputSize), sizeof(RAWINPUTHEADER));
if(Result == -1)
{
DWORD ErrorCode = GetLastError();
std::cout << "GetRawInputBuffer returned error code" << ErrorCode << std::endl;
}
else if(Result == 0 && RawInputSize != 0)
{
UINT AllocatedBufferByteCount = RawInputSize * 16;
RAWINPUT* RawInputBuffer = reinterpret_cast<RAWINPUT*>(malloc(AllocatedBufferByteCount));
UINT AllocatedBufferByteCountTwo = AllocatedBufferByteCount;
Result = GetRawInputBuffer(RawInputBuffer, &(AllocatedBufferByteCountTwo), sizeof(RAWINPUTHEADER));
if(Result == -1)
{
DWORD ErrorCode = GetLastError();
std::cout << "GetRawInputBuffer returned error code" << ErrorCode << std::endl;
}
else if(Result != 0)
{
UINT RawInputCount = Result;
DWORD MouseDeltaX = 0;
DWORD MouseDeltaY = 0;
bool ButtonsPressed[2] = {false, false};
RAWINPUT* RawInput = RawInputBuffer;
for(unsigned int i = 0; i < RawInputCount; ++i)
{
switch(RawInput->header.dwType)
{
// Raw mouse movement data for high-resolution mice.
case RIM_TYPEMOUSE:
{
MouseDeltaX += RawInput->data.mouse.lLastX;
MouseDeltaY += RawInput->data.mouse.lLastY;
ButtonsPressed[0] = ((RawInput->data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN) == RI_MOUSE_LEFT_BUTTON_DOWN);
ButtonsPressed[1] = ((RawInput->data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN) == RI_MOUSE_RIGHT_BUTTON_DOWN);
}
break;
}
RawInput = NEXTRAWINPUTBLOCK(RawInput);
}
DefRawInputProc(&(RawInputBuffer), RawInputCount, sizeof(RAWINPUTHEADER));
std::cout << "Mouse moved (" << MouseDeltaX << ", " << MouseDeltaY << ")." << std::endl;
if(ButtonsPressed[0])
{
std::cout << "LMB pressed." << std::endl;
}
if(ButtonsPressed[1])
{
std::cout << "RMB pressed." << std::endl;
}
}
free(RawInputBuffer);
}
return 0;
}
break;
default:
{
return DefWindowProc(WindowHandle, Message, wParameter, lParameter);
}
break;
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
// Initialize window strings.
wchar_t WindowClassName[] = L"DominionWindowClass";
wchar_t WindowCaption[] = L"Test Window";
// Create the window class.
WNDCLASSEX WindowClass;
WindowClass.cbSize = sizeof(WindowClass);
WindowClass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
WindowClass.lpfnWndProc = &(MessageHandler);
WindowClass.cbClsExtra = 0;
WindowClass.cbWndExtra = 0;
WindowClass.hInstance = hInstance;
WindowClass.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
WindowClass.hIconSm = LoadIcon(hInstance, IDI_APPLICATION);
WindowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WindowClass.hbrBackground = NULL;
WindowClass.lpszMenuName = NULL;
WindowClass.lpszClassName = WindowClassName;
// Register window class.
RegisterClassEx(&WindowClass);
// Setup window style flags.
DWORD WindowStyles = WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU;
DWORD ExWindowStyles = WS_EX_APPWINDOW;
// Setup window rectangle area.
RECT WindowArea;
WindowArea.left = 0;
WindowArea.top = 0;
WindowArea.right = 1024;
WindowArea.bottom = 768;
AdjustWindowRectEx(&(WindowArea), WindowStyles, false, ExWindowStyles);
// Window creation.
HWND WindowHandle = CreateWindowEx(ExWindowStyles, WindowClass.lpszClassName, WindowCaption, WindowStyles, CW_USEDEFAULT, CW_USEDEFAULT, (WindowArea.right - WindowArea.left), (WindowArea.bottom - WindowArea.top), NULL, NULL, hInstance, NULL);
// Display the window.
ShowWindow(WindowHandle, SW_SHOWDEFAULT);
UpdateWindow(WindowHandle);
// Register devices for raw input.
const unsigned int RawInputDeviceCount = 1;
RAWINPUTDEVICE RawInputDevices[RawInputDeviceCount];
memset(RawInputDevices, 0, RawInputDeviceCount * sizeof(RAWINPUTDEVICE));
RAWINPUTDEVICE* MouseRawInputDevice;
MouseRawInputDevice = RawInputDevices;
MouseRawInputDevice->usUsagePage = 1;
MouseRawInputDevice->usUsage = 2;
MouseRawInputDevice->hwndTarget = WindowHandle;
BOOL SuccessfullyRegisteredInput = RegisterRawInputDevices(RawInputDevices, RawInputDeviceCount, sizeof(RAWINPUTDEVICE));
// Core loop.
MSG Message;
for(;;)
{
while(PeekMessage(&Message, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&Message);
DispatchMessage(&Message);
if(Message.message == WM_QUIT)
{
break;
}
}
if(Message.message == WM_QUIT)
{
break;
}
}
// Unregister devices for raw input.
memset(RawInputDevices, 0, RawInputDeviceCount * sizeof(RAWINPUTDEVICE));
MouseRawInputDevice = RawInputDevices;
MouseRawInputDevice->usUsagePage = 1;
MouseRawInputDevice->usUsage = 2;
MouseRawInputDevice->dwFlags = RIDEV_REMOVE;
MouseRawInputDevice->hwndTarget = NULL;
BOOL SuccessfullyUnregisteredInput = RegisterRawInputDevices(RawInputDevices, RawInputDeviceCount, sizeof(RAWINPUTDEVICE));
return Message.wParam;
}
I can't think of a simpler way to experiment with the Raw Input API. Thoughts?
Long late answer, but GetRawInputBuffer seems to be used for polling outside of the message processing loop. Use GetRawInputData within WM_INPUT handling or use GetRawInputBuffer outside the message processing loop.
I guess with GetRawInputBuffer() you can only read HID data. That means only the hid structure in the data part of the RAWINPUT structure is filled with input data. I was able to read input from my keyboard using the bRawData member of RAWHID but i think thats useless because that values vary from keyboard to keyboard. So I switched back to GetRawInputData....

Win32 Splitter Control

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;
}

Resources