Related
I need to get the whole window's display area size, including controls that are hidden. In order to do that, I get the value from top from the very first window and the value of bottom from very last control. However, I'm getting a gap/white are in the end of the display area. See what's like in the below image. The display area is supposed to be until the Edit control's borders is seen. What am I missing?
I'm getting this size by:
int scrollHeight(void)
{
int minTop = 0;
int maxBottom = 0;
RECT rt = {0};
if(allControls_indx == 0) {
return 0;
}
#if 0
assert(allControls[0] == hMainWindow);
assert(allControls[allControls_indx - 1] == hEdit1);
#endif
if(!GetWindowRect(allControls[0], &rt)) {
ErrorExit(NAMEOF(scrollHeight), __LINE__, __FILENAME__);
}
minTop = rt.top;
if(!GetWindowRect(allControls[allControls_indx - 1], &rt)) {
ErrorExit(NAMEOF(scrollHeight), __LINE__, __FILENAME__);
}
maxBottom = rt.bottom;
return maxBottom - minTop;
}
set as scrollbar's page size like this:
setUpScrollBar(hwnd, scrollHeight());
where setUpScrollBar is defined as:
void setUpScrollBar(HWND hwnd, int h)
{
RECT rc = { 0 };
GetClientRect(hwnd, &rc);
SCROLLINFO si = { 0 };
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_ALL;
si.nMin = 0;
si.nMax = h;
si.nPage = (rc.bottom - rc.top);
si.nPos = 0;
si.nTrackPos = 0;
SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
}
full code:
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "Comctl32.lib")
#pragma comment(lib, "Gdi32.lib")
#define WIN32_LEAN_AND_MEAN
#define UNICODE
#define _UNICODE
#include <windows.h>
#include <Commctrl.h>
#include <crtdbg.h>
#include <strsafe.h>
#include <string.h>
#include <assert.h>
#ifdef UNICODE
#define STRSPLIT wcsrchr
#else
#define STRSPLIT strrchr
#endif
#define __FILENAME__ (STRSPLIT(TEXT(__FILE__), '/') ? STRSPLIT(TEXT(__FILE__), '/') + 1 : TEXT(__FILE__))
#define NAMEOF(s) TEXT(#s)
#define COUNTOF(a) (sizeof(a)/sizeof(a[0]))
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK CreateTabProc(HWND, UINT, WPARAM, LPARAM);
void ErrorExit(LPWSTR lpszFunction, int line, LPWSTR filename);
void InitComControls();
void ErrorExit(LPWSTR lpszFunction, int line, LPWSTR filename);
DWORD ShowLastError(LPWSTR lpszFunction, int line, LPWSTR filename);
void InitComControls();
void CreateTab(HWND hwnd);
void InsertTabItem(HWND tabHwnd, UINT id, LPWSTR text);
void CreateButtons(HWND hwnd);
RECT GetLocalCoordinates(HWND hWnd);
int scrollHeight(void);
int getHeight(HWND control);
void setUpScrollBar(HWND hwnd, int);
void pushControl(HWND);
int displayArea(void);
void setScrollBarSize(HWND hwnd, int s);
inline int my_max(int a, int b);
inline int my_min(int a, int b);
void displayText(HWND h);
HINSTANCE ghInstance;
HWND hTab;
HWND hLabel1, hLabel2;
HWND hEdit1;
HWND hRemoveButton;
enum
{
IDBUTTON_REMOVE = 50
};
#define MAX_CONTROLS 8
static const wchar_t *title[] = { L"Button A1", L"Button B2", L"Button C3",
L"Button D4", L"Button E5", L"Button F6",
L"Button G" , L"Button 001", L"Button 002",
L"Button 003", L"Button 004",
L"Button 005", L"Button 006" };
HWND hButton[sizeof(title)/sizeof(title[0])] = {0};
HWND allControls[MAX_CONTROLS];
HWND hMainWindow;
int allControls_indx = 0;
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PWSTR pCmdLine, int nCmdShow)
{
MSG msg = {0};
HWND hwnd;
WNDCLASSW wc = {0};
wc.lpszClassName = L"Window";
wc.hInstance = hInstance;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpfnWndProc = WndProc;
wc.hCursor = LoadCursor(0, IDC_ARROW);
InitComControls();
if(!RegisterClass(&wc)) {
ErrorExit(NAMEOF(RegisterClass), __LINE__, __FILENAME__);
}
int width = 500;
int height = 350/2; // half than the usual size, so that the scrollbar show up and we can test it
int screenWidth = GetSystemMetrics(SM_CXSCREEN);
int screenHeight = GetSystemMetrics(SM_CYSCREEN);
int cx = (screenWidth - width) / 2;
int cy = (screenHeight - height) / 2;
hwnd = CreateWindowW(wc.lpszClassName, L"main window",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
cx, cy, width, height, NULL, NULL,
hInstance, NULL);
ghInstance = hInstance;
while (GetMessage(&msg, NULL, 0, 0))
{
if (!IsDialogMessage(hwnd, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static int g_scrollY;
switch(msg)
{
case WM_CREATE:
hMainWindow = hwnd;
pushControl(hwnd); // push main window too
hLabel1 = CreateWindowW(L"Static", L"This is label 1...",
WS_VISIBLE | WS_CHILD | WS_TABSTOP,
50, 10, 130, 25, hwnd, (HMENU) 18, NULL, NULL);
pushControl(hLabel1);
hLabel2 = CreateWindowW(L"Static", L"This is label 2...",
WS_VISIBLE | WS_CHILD | WS_TABSTOP,
50, 40, 130, 25, hwnd, (HMENU) 19, NULL, NULL);
hRemoveButton = CreateWindow(L"Button", L"Remove",
WS_VISIBLE | WS_CHILD | WS_TABSTOP,
200, 40, 80, 25,
hwnd,
(HMENU) IDBUTTON_REMOVE,
NULL,
NULL);
pushControl(hLabel2);
CreateTab(hwnd);
CreateButtons(hwnd);
setUpScrollBar(hwnd, scrollHeight());
break;
case WM_VSCROLL:
{
int action = LOWORD(wParam);
//HWND hScroll = (HWND)lParam;
int pos = -1;
if (action == SB_THUMBPOSITION || action == SB_THUMBTRACK) {
pos = HIWORD(wParam);
} else if (action == SB_LINEDOWN) {
pos = g_scrollY + 30;
} else if (action == SB_LINEUP) {
pos = g_scrollY - 30;
}
if (pos == -1)
break;
SCROLLINFO si = { 0 };
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_POS;
si.nPos = pos;
si.nTrackPos = 0;
SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
GetScrollInfo(hwnd, SB_VERT, &si);
pos = si.nPos;
POINT pt;
pt.x = 0;
pt.y = pos - g_scrollY;
HDC hdc = GetDC(hwnd);
LPtoDP(hdc, &pt, 1);
ReleaseDC(hwnd, hdc);
ScrollWindow(hwnd, 0, -pt.y, NULL, NULL);
g_scrollY = pos;
return 0;
}
break;
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
case IDBUTTON_REMOVE:
ShowWindow(hEdit1, SW_HIDE);
SetScrollRange(hwnd, SB_VERT, 0, displayArea(), TRUE);
break;
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
// this is like scrollHeight but control that are hidden
// aren't considered part of the display area.
int displayArea(void)
{
int size = scrollHeight();
// start i with 1 so we skip the mainwindow.
// we are interested in the "children controls"
for(int i = 1; i < MAX_CONTROLS && allControls[i]; i++)
{
HWND h = allControls[i];
// if it not visible, remove it from display area
if(!IsWindowVisible(h)) {
size -= getHeight(h);
}
}
return size;
}
void pushControl(HWND hwnd)
{
if(allControls_indx > MAX_CONTROLS) {
assert(!"no room for extra controls");
}
allControls[allControls_indx++] = hwnd;
}
void CreateTab(HWND hwnd)
{
hTab =
CreateWindow(WC_TABCONTROLW, NULL,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_TABSTOP,
100, 80, 400, 250,
hwnd,
(HMENU) 1,
NULL,
NULL);
InsertTabItem(hTab, 2, L"Tab 1");
InsertTabItem(hTab, 3, L"Tab b");
pushControl(hTab);
}
void CreateButtons(HWND hwnd)
{
RECT rt = GetLocalCoordinates(hTab);
TabCtrl_AdjustRect(hTab, FALSE, &rt);
RECT rt2 = {0};
GetWindowRect(hTab, &rt2);
int tab_width = rt2.right - rt2.left;
int tab_height = rt2.bottom - rt2.top;
int id = 4;
const int cy_breakSize = 25;
int cx_initPos = rt.left;
int cy_initPos = rt.top;
int cx = cx_initPos;
int cy = cy_initPos;
const int button_width = 80;
const int button_height = 25;
const int cx_margin = 10;
int nMaxButtonPerRow = tab_width / (button_width + cx_margin);
for(int i = 0; i < sizeof(title)/sizeof(title[0]); ++i)
{
if(i != 0 && (i % nMaxButtonPerRow) == 0) {
cy += cy_breakSize;
cx = cx_initPos;
}
hButton[i] =
CreateWindow(L"button", title[i],
WS_VISIBLE | WS_CHILD | WS_TABSTOP,
cx,
cy,
button_width,
button_height,
hwnd, (HMENU) id++, NULL, NULL);
cx += button_width;
}
const int edit_width = 180;
const int edit_height = 25;
hEdit1 = CreateWindow(L"Edit", L"Hello, world!",
WS_VISIBLE | WS_CHILD | WS_BORDER,
cx,
// put below tab control's display area
getHeight(hTab) + cx,
edit_width,
edit_height,
hwnd,
(HMENU) id++,
NULL, NULL);
pushControl(hEdit1);
cx += edit_width;
}
void setUpScrollBar(HWND hwnd, int h)
{
RECT rc = { 0 };
GetClientRect(hwnd, &rc);
SCROLLINFO si = { 0 };
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_ALL;
si.nMin = 0;
si.nMax = h;
si.nPage = (rc.bottom - rc.top);
si.nPos = 0;
si.nTrackPos = 0;
SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
}
void setScrollBarSize(HWND hwnd, int s)
{
SCROLLINFO si = { 0 };
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_RANGE;
si.nMin = 0;
si.nMax = s;
SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
}
int getHeight(HWND control)
{
RECT rt;
if(!GetWindowRect(control, &rt)) {
ErrorExit(NAMEOF(getHeight), __LINE__, __FILENAME__);
}
return rt.bottom - rt.top;
}
void displayText(HWND h)
{
int len = GetWindowTextLength(h);
if(len == 0) {
return;
}
wchar_t buffer[len + 1];
memset(buffer, 0, sizeof(buffer));
GetWindowText(h, buffer, len+1);
MessageBox(NULL, buffer, L"control text = ", MB_OK);
}
int scrollHeight(void)
{
int minTop = 0;
int maxBottom = 0;
RECT rt = {0};
if(allControls_indx == 0) {
return 0;
}
#if 0
assert(allControls[0] == hMainWindow);
assert(allControls[allControls_indx - 1] == hEdit1);
#endif
if(!GetWindowRect(allControls[0], &rt)) {
ErrorExit(NAMEOF(scrollHeight), __LINE__, __FILENAME__);
}
minTop = rt.top;
if(!GetWindowRect(allControls[allControls_indx - 1], &rt)) {
ErrorExit(NAMEOF(scrollHeight), __LINE__, __FILENAME__);
}
maxBottom = rt.bottom;
return maxBottom - minTop;
}
RECT GetLocalCoordinates(HWND hWnd)
{
RECT Rect;
GetWindowRect(hWnd, &Rect);
MapWindowPoints(HWND_DESKTOP, GetParent(hWnd), (LPPOINT) &Rect, 2);
return Rect;
}
void InsertTabItem(HWND tabHwnd, UINT id, LPWSTR text)
{
TCITEMW tci = {0};
tci.mask = TCIF_TEXT;
tci.pszText = text;
tci.cchTextMax = lstrlenW(text);
SendMessage(tabHwnd, TCM_INSERTITEM, id, (LPARAM) &tci);
}
void InitComControls()
{
INITCOMMONCONTROLSEX icex;
/* initialize this component is required to use tab control,
it seems.
*/
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_TAB_CLASSES;
InitCommonControlsEx(&icex);
}
// display the error message from last error seen then
// exit the application, with that last error code seen.
// to test function, do something like:
// if(!GetProcessId(NULL))
// errorExit(TEXT("GetProcessId"));
// not quite a unittest but yeah.
void ErrorExit(LPWSTR lpszFunction, int line, LPWSTR filename)
{
DWORD dw = ShowLastError(lpszFunction, line, filename);
ExitProcess(dw);
}
DWORD ShowLastError(LPWSTR lpszFunction, int line, LPWSTR filename)
{
#define MAX_DIGITS 16
/*
* NOTE!!: calling GetLastError() must be done before calling
* any other function, that would reset the GetLastError(), making
* this function report error about the wrong function.
*/
DWORD dw = GetLastError();
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0,
NULL
);
lpDisplayBuf = (LPVOID) LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR)lpMsgBuf) +
lstrlen((LPCTSTR)lpszFunction) + 40 +
(line > 0 ? MAX_DIGITS : 0) +
(filename != NULL ? lstrlen(filename) : 0)) *
sizeof(TCHAR)
);
StringCchPrintf((LPTSTR)lpDisplayBuf,
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
TEXT("%s failed with %d: %s"),
lpszFunction, dw, lpMsgBuf
);
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
return dw;
}
I think there is no problem with your calculation method. But you added the handle of the main window hwnd for the first time, which leads to the fact that the minTop you get in GetWindowRect(allControls[0], &rt) is the top coordinate of the main window, which caused a gap at the end of the display area.
However, you should actually get the coordinates of minTop from hLabel1 so that you won't attend the question.
In addition, you forgot to add hRemoveButton to the allControls array.
Solution: You can choose not to add the main window to the allControls array, or use GetWindowRect(allControls[1], &rt) to get the coordinates of minTop.
if (!GetWindowRect(allControls[1], &rt)) {
ErrorExit((LPWSTR)NAMEOF(scrollHeight), __LINE__, (LPWSTR)__FILENAME__);
}
minTop = rt.top;
Edit:
The reason why part of the edit box is cropped is that your hLabel1 is set to a height of 10 compared to the top, so when the top of hLabel1 is used as minTop, the length of the bottom is reduced by 10 units.
You need to add the y size of the topmost control:
return maxBottom - minTop + y; //The y size of the topmost control.
I draw most of my UI using ID2D1HwndRenderTarget, but I want some classic window controls: button, edit. How to
ID2D1HwndRenderTarget * canvas = nullptr; // it's global object
HWND button = nullptr; // it's global object
HWND edit = nullptr; // it's global object
HWND custom = nullptr; // it's global object
// mainWindow WinPproc
case WM_CREATE:
button = CreateWindowExW(0, L"button", L"Send", WS_CHILD | WS_VISIBLE, 10, 10, 120, 30, hWnd, BUTTON_ID, hInstance, 0); // win32 control
edit = CreateWindowExW(0, L"edit", L"Edit", WS_CHILD | WS_VISIBLE, 10, 50, 120, 30, hWnd, BUTTON_ID, hInstance, 0); // win32 control
custom = CreateWindowExW(0, L"custom", L"Custom", WS_CHILD | WS_VISIBLE, 10, 90, 120, 30, hWnd, BUTTON_ID, hInstance, 0); // it's my custom class
break;
case WM_PAINT:
BeginPaint(hWnd, nullptr);
render_target->BeginPaint();
... GUI rendering stuff ....
HRESULT result = render_target->EndDraw();
if(result != S_OK)
{
// Error handling
...
}
EndPaint(hWnd, nullptr);
break;
// custom WinProc
case WM_PAINT:
BeginPaint(hWnd, nullptr);
render_target->BeginPaint();
... rendering stuff ....
HRESULT result = render_target->EndDraw();
if(result != S_OK)
{
// Error handling
...
}
EndPaint(hWnd, nullptr);
break;
Only things painted with render_target are visible. I understand why: becausebutton and edit are default win32 controls, internally drawn using PAINTSTRUCT->HDC context. I read Direct2D and GDI Interoperability Overview and get the concept, but still don't know where this HDC intrecpet should take place? I don't want touch default control WM_PAINT. I have to supclass all default win32 controls?
How to force those Win32 controls to draw onto my render_target?
If you want to share a device context (HDC) between GDI and Direct2D, you can use a ID2D1DCRenderTarget and Bind to this HDC when you want to render on it.
This is demonstrated in this official sample : GDI/Direct2D Interoperability Sample
Note, as is, it doesn't compile/work with today's Visual Studio. So, here is a similar code here with a simple button and textbox:
#include <windows.h>
#include <stdlib.h>
#include <math.h>
#include <d2d1.h>
template<class Interface>
inline void
SafeRelease(Interface** ppInterfaceToRelease)
{
if (*ppInterfaceToRelease != NULL)
{
(*ppInterfaceToRelease)->Release();
(*ppInterfaceToRelease) = NULL;
}
}
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
class DemoApp
{
public:
DemoApp();
~DemoApp();
HRESULT Initialize();
private:
HRESULT CreateDeviceIndependentResources();
HRESULT CreateDeviceResources();
void DiscardDeviceResources();
HRESULT OnRender(const PAINTSTRUCT& ps);
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
private:
HWND m_hwnd;
ID2D1Factory* m_pD2DFactory;
ID2D1DCRenderTarget* m_pDCRT;
ID2D1SolidColorBrush* m_pBlackBrush;
};
int WINAPI WinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int /*nCmdShow*/)
{
if (SUCCEEDED(CoInitialize(NULL)))
{
DemoApp app;
if (SUCCEEDED(app.Initialize()))
{
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
CoUninitialize();
}
return 0;
}
DemoApp::DemoApp() :
m_hwnd(NULL),
m_pD2DFactory(NULL),
m_pDCRT(NULL),
m_pBlackBrush(NULL)
{
}
DemoApp::~DemoApp()
{
SafeRelease(&m_pD2DFactory);
SafeRelease(&m_pDCRT);
SafeRelease(&m_pBlackBrush);
}
HRESULT DemoApp::Initialize()
{
HRESULT hr;
hr = CreateDeviceIndependentResources();
if (SUCCEEDED(hr))
{
// Register the window class.
WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = DemoApp::WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = sizeof(LONG_PTR);
wcex.hInstance = (HINSTANCE)&__ImageBase;
wcex.hbrBackground = NULL;
wcex.lpszMenuName = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.lpszClassName = L"D2DDemoApp";
RegisterClassEx(&wcex);
// Create the application window.
// Because the CreateWindow function takes its size in pixels, we obtain the system DPI and use it to scale the window size.
FLOAT dpiX, dpiY;
m_pD2DFactory->GetDesktopDpi(&dpiX, &dpiY);
m_hwnd = CreateWindow(
L"D2DDemoApp",
L"Direct2D Demo App",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
static_cast<UINT>(ceil(640.f * dpiX / 96.f)),
static_cast<UINT>(ceil(480.f * dpiY / 96.f)),
NULL,
NULL,
(HINSTANCE)&__ImageBase,
this
);
hr = m_hwnd ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
{
ShowWindow(m_hwnd, SW_SHOWNORMAL);
UpdateWindow(m_hwnd);
}
}
return hr;
}
HRESULT DemoApp::CreateDeviceIndependentResources()
{
// Create D2D factory
return D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_pD2DFactory);
}
HRESULT DemoApp::CreateDeviceResources()
{
HRESULT hr = S_OK;
if (!m_pDCRT)
{
// Create a DC render target.
D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(
D2D1_RENDER_TARGET_TYPE_DEFAULT,
D2D1::PixelFormat(
DXGI_FORMAT_B8G8R8A8_UNORM,
D2D1_ALPHA_MODE_IGNORE),
0,
0,
D2D1_RENDER_TARGET_USAGE_NONE,
D2D1_FEATURE_LEVEL_DEFAULT
);
hr = m_pD2DFactory->CreateDCRenderTarget(&props, &m_pDCRT);
if (SUCCEEDED(hr))
{
// Create a black brush.
hr = m_pDCRT->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black), &m_pBlackBrush);
}
}
return hr;
}
void DemoApp::DiscardDeviceResources()
{
SafeRelease(&m_pDCRT);
SafeRelease(&m_pBlackBrush);
}
HRESULT DemoApp::OnRender(const PAINTSTRUCT& ps)
{
HRESULT hr;
RECT rc;
// Get the dimensions of the client drawing area.
GetClientRect(m_hwnd, &rc);
// Draw the pie chart with Direct2D.
// Create the DC render target.
hr = CreateDeviceResources();
if (SUCCEEDED(hr))
{
// Bind the DC to the DC render target.
hr = m_pDCRT->BindDC(ps.hdc, &rc);
m_pDCRT->BeginDraw();
m_pDCRT->SetTransform(D2D1::Matrix3x2F::Identity());
m_pDCRT->Clear(D2D1::ColorF(D2D1::ColorF::White));
m_pDCRT->DrawEllipse(D2D1::Ellipse(D2D1::Point2F(150.0f, 150.0f), 100.0f, 100.0f), m_pBlackBrush, 3.0);
m_pDCRT->DrawLine(
D2D1::Point2F(150.0f, 150.0f),
D2D1::Point2F((150.0f + 100.0f * 0.15425f), (150.0f - 100.0f * 0.988f)), m_pBlackBrush, 3.0
);
m_pDCRT->DrawLine(
D2D1::Point2F(150.0f, 150.0f),
D2D1::Point2F((150.0f + 100.0f * 0.525f), (150.0f + 100.0f * 0.8509f)), m_pBlackBrush, 3.0
);
m_pDCRT->DrawLine(
D2D1::Point2F(150.0f, 150.0f),
D2D1::Point2F((150.0f - 100.0f * 0.988f), (150.0f - 100.0f * 0.15425f)), m_pBlackBrush, 3.0
);
hr = m_pDCRT->EndDraw();
if (SUCCEEDED(hr))
{
// Draw the pie chart with GDI.
// Save the original object.
HGDIOBJ original = NULL;
original = SelectObject(ps.hdc, GetStockObject(DC_PEN));
HPEN blackPen = CreatePen(PS_SOLID, 3, 0);
SelectObject(ps.hdc, blackPen);
Ellipse(ps.hdc, 300, 50, 500, 250);
POINT pntArray1[2];
pntArray1[0].x = 400;
pntArray1[0].y = 150;
pntArray1[1].x = static_cast<LONG>(400 + 100 * 0.15425);
pntArray1[1].y = static_cast<LONG>(150 - 100 * 0.9885);
POINT pntArray2[2];
pntArray2[0].x = 400;
pntArray2[0].y = 150;
pntArray2[1].x = static_cast<LONG>(400 + 100 * 0.525);
pntArray2[1].y = static_cast<LONG>(150 + 100 * 0.8509);
POINT pntArray3[2];
pntArray3[0].x = 400;
pntArray3[0].y = 150;
pntArray3[1].x = static_cast<LONG>(400 - 100 * 0.988);
pntArray3[1].y = static_cast<LONG>(150 - 100 * 0.15425);
Polyline(ps.hdc, pntArray1, 2);
Polyline(ps.hdc, pntArray2, 2);
Polyline(ps.hdc, pntArray3, 2);
DeleteObject(blackPen);
// Restore the original object.
SelectObject(ps.hdc, original);
}
}
if (hr == D2DERR_RECREATE_TARGET)
{
hr = S_OK;
DiscardDeviceResources();
}
return hr;
}
LRESULT CALLBACK DemoApp::WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_CREATE)
{
LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam;
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pcs->lpCreateParams);
auto button = CreateWindowExW(0, L"button", L"Send", WS_CHILD | WS_VISIBLE, 10, 10, 120, 30, hwnd, (HMENU)1, (HINSTANCE)&__ImageBase, 0); // win32 control
auto edit = CreateWindowExW(0, L"edit", L"Edit", WS_CHILD | WS_VISIBLE, 10, 50, 120, 30, hwnd, (HMENU)2, (HINSTANCE)&__ImageBase, 0); // win32 control
return 1;
}
LRESULT result = 0;
DemoApp* pDemoApp = (DemoApp*)(GetWindowLongPtr(hwnd, GWLP_USERDATA));
bool wasHandled = false;
if (pDemoApp)
{
switch (message)
{
case WM_PAINT:
case WM_DISPLAYCHANGE:
{
PAINTSTRUCT ps;
BeginPaint(hwnd, &ps);
pDemoApp->OnRender(ps);
EndPaint(hwnd, &ps);
}
result = 0;
wasHandled = true;
break;
case WM_DESTROY:
{
PostQuitMessage(0);
}
result = 1;
wasHandled = true;
break;
}
}
if (!wasHandled)
{
result = DefWindowProc(hwnd, message, wParam, lParam);
}
return result;
}
And here is how it renders (left circle is Direct2D, right is aliased GDI):
How to force Win32 controls to draw onto my ID2D1Bitmap1? Is that even possible?
Yes. You can write GDI content to a Direct2D GDI-compatible render target. This approach is useful for applications that primarily render with Direct2D but have an extensibility model or other legacy content that requires the ability to render with GDI.
Step:
To render GDI content to a Direct2D GDI-compatible render target, use
an ID2D1GdiInteropRenderTarget, which provides access to a device
context that can accept GDI draw calls. Unlike other interfaces, an
ID2D1GdiInteropRenderTarget object is not created directly. Instead,
use the QueryInterface method of an existing render target instance.
Refer: Draw GDI Content to a Direct2D GDI-Compatible Render Target
i was trying to create a win32 that could handle openGl ( the new version). It doesnt seem to be mutch info about win32/opengl(new version, most examples are in the old version ) on the net.
The few info that i found lead me to this code. But it doesnt display the square.
Does any one know if this is the proper way to do it, and if so what is wrong with it(it doesnt display square).
Ps. i know that the part of the vbo, vao ,shader.. are working cause i already did that with sdl.
Thank a lot.... :)
Here is the Code:
#include <iostream>
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
#include <glew.h>
#include <wglew.h>
using namespace std;
void display(){
// display square
}
bool progRun = false;
//-------------------------------------------------------------------
//#####################################################################
//-------------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int CALLBACK WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow
){
WNDCLASSEX wcex;
///////////////////////////LOAD GLEW///////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS ;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = NULL;
if (!RegisterClassEx(&wcex))
{
MessageBox(NULL,"RegisterClassEx","ERROR",MB_OK|MB_ICONSTOP);
return 0;
}
HWND hWnd = CreateWindow(
szWindowClass,
szTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
500, 500,
NULL,
NULL,
hInstance,
NULL
);
if (!hWnd)
{
MessageBox(NULL,"hWnd","ERROR",MB_OK|MB_ICONSTOP);
return -1;
}
HDC hdc = GetDC(hWnd);
PIXELFORMATDESCRIPTOR pfd;
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
pfd.nSize= sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cDepthBits = 32;
pfd.iLayerType = PFD_MAIN_PLANE;
int pf = ChoosePixelFormat(hdc, &pfd);
if(pf == 0){
MessageBox(NULL,"pf == 0","ERROR",MB_OK|MB_ICONSTOP);
return -1;
}
if(SetPixelFormat(hdc, pf, &pfd) == false){
MessageBox(NULL,"SetPixelFormat","ERROR",MB_OK|MB_ICONSTOP);
return -1;
}
DescribePixelFormat(hdc, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
HGLRC hrc = wglCreateContext(hdc);
wglMakeCurrent(hdc, hrc);
glewExperimental = true;
if(glewInit() != GLEW_OK){
MessageBox(NULL, "Couldn't initialize GLEW!", "Fatal Error", MB_ICONERROR);
}
wglMakeCurrent(NULL, NULL);
ReleaseDC(hWnd, hdc);
wglDeleteContext(hrc);
DestroyWindow(hWnd);
///////////////////////////////TO_CREATE A OPENGL CONTEXT WITH LATER VERSION///////////////////////////////////////
//////////////////////////////////////////////////////////////////////
#define iMajorVersion 3
#define iMinorVersion 1
hWnd = CreateWindow(
szWindowClass,
szTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
500, 500,
NULL,
NULL,
hInstance,
NULL
);
if (!hWnd)
{
MessageBox(NULL,"hWnd","ERROR",MB_OK|MB_ICONSTOP);
return -1;
}
hdc = GetDC(hWnd);
bool bError = false;
if(iMajorVersion <= 2)
{
cout << "version 2" <<endl;
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cDepthBits = 32;
pfd.iLayerType = PFD_MAIN_PLANE;
pf = ChoosePixelFormat(hdc, &pfd);
if (pf == 0){
MessageBox(NULL,"pf == 0","ERROR",MB_OK|MB_ICONSTOP);
return false;
}
if(!SetPixelFormat(hdc, pf, &pfd)){
MessageBox(NULL,"SetPixelFormat 1","ERROR",MB_OK|MB_ICONSTOP);
return false;
}
// Create the old style context (OpenGL 2.1 and before)
hrc = wglCreateContext(hdc);
if(hrc)wglMakeCurrent(hdc, hrc);
else bError = true;
}
else if(WGLEW_ARB_create_context && WGLEW_ARB_pixel_format)
{
cout << "version 3" <<endl;
const int iPixelFormatAttribList[] =
{
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
WGL_COLOR_BITS_ARB, 32,
WGL_DEPTH_BITS_ARB, 24,
WGL_STENCIL_BITS_ARB, 8,
0 // End of attributes list
};
int iContextAttribs[] =
{
WGL_CONTEXT_MAJOR_VERSION_ARB, iMajorVersion,
WGL_CONTEXT_MINOR_VERSION_ARB, iMinorVersion,
WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
0 // End of attributes list
};
int iNumFormats;
if(!wglChoosePixelFormatARB(hdc, iPixelFormatAttribList, NULL, 1, &pf, (UINT*)&iNumFormats)){
MessageBox(NULL,"wglChoosePixelFormatARB","ERROR",MB_OK|MB_ICONSTOP);
return 0;
}
// PFD seems to be only redundant parameter now
if(!SetPixelFormat(hdc, pf, &pfd)){
MessageBox(NULL,"SetPixelFormat 2","ERROR",MB_OK|MB_ICONSTOP);
return false;
}
hrc = wglCreateContextAttribsARB(hdc, 0, iContextAttribs);
// If everything went OK
if(hrc) wglMakeCurrent(hdc, hrc);
else bError = true;
//glewInit();
}else{
bError = true;
}
if(bError)
{
// Generate error messages
char sErrorMessage[255], sErrorTitle[255];
sprintf(sErrorMessage, "OpenGL %d.%d is not supported! Please download latest GPU drivers!", iMajorVersion, iMinorVersion);
sprintf(sErrorTitle, "OpenGL %d.%d Not Supported", iMajorVersion, iMinorVersion);
MessageBox(hWnd, sErrorMessage, sErrorTitle, MB_ICONINFORMATION);
return false;
}
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
MSG msg;
progRun = true;
ShowWindow(hWnd,SW_SHOW);
UpdateWindow(hWnd);
//-----------Setup shader and objects
setupShader();
setupObject();
//-------
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL);
glClearColor(1,0,0,1);
while(progRun){
if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
glClear(GL_COLOR_BUFFER_BIT);
display();
SwapBuffers(hdc);
}
return (int) msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
switch (message){
case WM_ERASEBKGND:
display();
break;
case WM_PAINT:
BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
break;
case WM_SIZE:
glViewport(0, 0, LOWORD(lParam), HIWORD(lParam));
break;
case WM_DESTROY:
PostQuitMessage(0);
progRun = false;
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
If you use wglCreateContext then you get old context (<= 2.1).
You need wglCreateContextAttribsARB instead. But this first you need to get a pointer to this function, which requires using a context.
So:
Create a normal, old context, and set it current. Any pixelformat is
valid.
Get the pointers to wglCreateContextAttribsARB (and perhaps also for wglChoosePixelFormatARB), by using
wglGetProcAddress. Now you can delete the old context.
Set the pixelformat you wish and the context attributes you wish.
Create the context by that pointer.
Useful links from the wiki OpenGL are here and here and here
I have a callback function:
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
if(msg == WM_DESTROY || msg == WM_CLOSE) {
std::cout << "Close or get DESTROYED!\n";
}
if(g_mApp)
return g_mApp->MsgProc(hwnd, msg, wParam, lParam);
else
return DefWindowProc(hwnd, msg, wParam, lParam);
}
However, "Close or get Destroyed" isn't printed when I click on the X button or press Alt+F4. Infact, I am unable to move the window by the mouse!
Some other functions:
int GLApp::run() {
__int64 prevTime = 0;
QueryPerformanceCounter((LARGE_INTEGER*)&prevTime);
__int64 countsPerSec = 0;
QueryPerformanceCounter((LARGE_INTEGER*)&countsPerSec);
float secondsPerCount = 1.0f / countsPerSec;
MSG msg = {0};
while(msg.message != WM_QUIT) {
if(!PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else {
__int64 curTime = 0;
QueryPerformanceCounter((LARGE_INTEGER*)&curTime);
float deltaTime = (curTime - prevTime) * secondsPerCount;
update(deltaTime);
render();
calculateFPS(deltaTime);
prevTime = curTime;
}
}
shutdown();
return static_cast<int>(msg.wParam);
}
bool GLApp::initWindow() {
WNDCLASSEX wcex;
ZeroMemory(&wcex, sizeof(WNDCLASSEX));
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.hInstance = m_hAppInstance;
wcex.lpfnWndProc = MainWndProc;
wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
wcex.lpszClassName = "GLAPPWNDCLASS";
wcex.lpszMenuName = NULL;
wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&wcex)) {
return outErrorMessage("Failed to register GLAPPWNDCLASS");
}
// ADJUST WINDOW RECT FOR REQUESTED CLIENT SIZE
RECT r;
r.left = r.top = 0;
r.right = m_ClientWidth;
r.bottom = m_ClientHeight;
AdjustWindowRect(&r, m_WindowStyle, FALSE);
int width = r.right - r.left;
int height = r.bottom - r.top;
int x = GetSystemMetrics(SM_CXSCREEN)/2 - width / 2;
int y = GetSystemMetrics(SM_CYSCREEN)/2 - height / 2;
m_hAppWnd = CreateWindow("GLAPPWNDCLASS", m_AppTitle, m_WindowStyle, x, y, width, height, NULL, NULL, m_hAppInstance, NULL);
if(!m_hAppWnd) return outErrorMessage("Failed to create window from GLAPPWNDCLASS");
ShowWindow(m_hAppWnd, SW_SHOW);
return true;
}
g_mApp is my own object for implementing the window. initWindow() and run() are called only once respectively. The full class if you will:
#include "GLApp.h"
#include <iostream>
namespace {
GLApp* g_mApp = NULL;
}
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
if(msg == WM_DESTROY || msg == WM_CLOSE) {
std::cout << "Close or get DESTROYED!\n";
}
if(g_mApp)
return g_mApp->MsgProc(hwnd, msg, wParam, lParam);
else
return DefWindowProc(hwnd, msg, wParam, lParam);
}
GLApp::GLApp(void)
{
}
GLApp::GLApp(HINSTANCE hInstance) {
m_hAppInstance = hInstance;
m_hAppWnd = NULL;
m_hDevContext = NULL;
m_hGLRenderContext = NULL;
m_ClientWidth = 800;
m_ClientHeight = 600;
m_AppTitle = "OpenGL Application";
m_WindowStyle = WS_OVERLAPPED | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX;
m_FPS = 0.0f;
g_mApp = this;
}
GLApp::~GLApp()
{
}
int GLApp::run() {
__int64 prevTime = 0;
QueryPerformanceCounter((LARGE_INTEGER*)&prevTime);
__int64 countsPerSec = 0;
QueryPerformanceCounter((LARGE_INTEGER*)&countsPerSec);
float secondsPerCount = 1.0f / countsPerSec;
MSG msg = {0};
while(msg.message != WM_QUIT) {
if(!PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else {
__int64 curTime = 0;
QueryPerformanceCounter((LARGE_INTEGER*)&curTime);
float deltaTime = (curTime - prevTime) * secondsPerCount;
update(deltaTime);
render();
calculateFPS(deltaTime);
prevTime = curTime;
}
}
shutdown();
return static_cast<int>(msg.wParam);
}
bool GLApp::init() {
return initWindow() && initGL();
}
bool GLApp::initWindow() {
WNDCLASSEX wcex;
ZeroMemory(&wcex, sizeof(WNDCLASSEX));
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.hInstance = m_hAppInstance;
wcex.lpfnWndProc = MainWndProc;
wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
wcex.lpszClassName = "GLAPPWNDCLASS";
wcex.lpszMenuName = NULL;
wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&wcex)) {
return outErrorMessage("Failed to register GLAPPWNDCLASS");
}
// ADJUST WINDOW RECT FOR REQUESTED CLIENT SIZE
RECT r;
r.left = r.top = 0;
r.right = m_ClientWidth;
r.bottom = m_ClientHeight;
AdjustWindowRect(&r, m_WindowStyle, FALSE);
int width = r.right - r.left;
int height = r.bottom - r.top;
int x = GetSystemMetrics(SM_CXSCREEN)/2 - width / 2;
int y = GetSystemMetrics(SM_CYSCREEN)/2 - height / 2;
m_hAppWnd = CreateWindow("GLAPPWNDCLASS", m_AppTitle, m_WindowStyle, x, y, width, height, NULL, NULL, m_hAppInstance, NULL);
if(!m_hAppWnd) return outErrorMessage("Failed to create window from GLAPPWNDCLASS");
ShowWindow(m_hAppWnd, SW_SHOW);
return true;
}
bool GLApp::initGL() {
// CREATE OUR DEVICE CONTEXT
m_hDevContext = GetDC(m_hAppWnd);
// CREATE PIXEL FORMAT DESCRIPTOR
PIXELFORMATDESCRIPTOR pfd;
ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR));
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cDepthBits = 24;
pfd.cStencilBits = 8;
int format = ChoosePixelFormat(m_hDevContext, &pfd);
if(!SetPixelFormat(m_hDevContext, format, &pfd)) {
return outErrorMessage("Failed to set pixel format");
}
// CREATE RENDER CONTEXT
m_hGLRenderContext = wglCreateContext(m_hDevContext);
if(!wglMakeCurrent(m_hDevContext, m_hGLRenderContext)) {
return outErrorMessage("Failed to create and activate render context");
}
// INITIALIZE GLEW
if(glewInit() != GLEW_OK) {
return outErrorMessage("Failed to initialize GLEW");
}
return true;
}
LRESULT GLApp::MsgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch(msg) {
case WM_CLOSE: {
DestroyWindow(hwnd);
return 0;
}
case WM_DESTROY: {
PostQuitMessage(0);
return 0;
}
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
}
void GLApp::calculateFPS(float dt) {
}
void GLApp::shutdown() {
wglMakeCurrent(NULL, NULL);
wglDeleteContext(m_hGLRenderContext);
ReleaseDC(m_hAppWnd, m_hDevContext);
}
This is how it is implemented:
#include "GLApp.h"
#include <iostream>
class TestApp : public GLApp {
public:
TestApp(HINSTANCE hInstance);
~TestApp();
// OVERRIDES
bool init() override;
void update(float dt) override;
void render() override;
LRESULT MsgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) override;
};
TestApp::TestApp(HINSTANCE hInstance) : GLApp(hInstance) {
}
TestApp::~TestApp() {}
bool TestApp::init() {
return GLApp::init();
}
void TestApp::update(float dt) {
}
void TestApp::render() {
}
LRESULT TestApp::MsgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch(msg) {
default:
return GLApp::MsgProc(hwnd, msg, wParam, lParam);
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, LPSTR lpCmdLine, int nCmdShow) {
TestApp app(hInstance);
if(!app.init()) {
return 1;
}
return app.run();
}
bool outErrorMessage(const char* message) {
MessageBox(NULL, message, NULL, MB_OK);
return false;
}
!PeekMessage is wrong, if it returns non-zero you got a message you need to handle.
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!).