1 | initial version |
With Win32 GUI (and MFC) you can use both method:
In both cases you have to define a static control that will holds the image from opencv.
Some note:
May be your code is incomplete but the grabbing thread will be never stopped because stop
(pointer to StopGrab
) variable is never set to true
.
In addiction if you will set in StopThread
this is a race condition because 2 threads can access to StopGrab
. In general to stop the thread you should use an event or a mutex, critical section to protect shared variables. In this case you can use atomic<bool>
that is lock free than faster than mutex or critical section.
For you and other user here is correct code using method 2 and atomic<bool>:
#include <opencv2/opencv.hpp>
#define ID_GRABWIN PB_QUIT + 1000
LRESULT CALLBACK SmplProc(HWND hWnd, UINT iMessage, UINT wParam, LONG lParam);
int OnGrab(void);
DWORD StopThread(LPDWORD lpdwParam);
DWORD GrabThread(LPDWORD lpdwParam);
static HANDLE HStopThread, HStopEvent, HThread;
static HINSTANCE hInst;
static HWND SmplHwnd, GrabHwnd;
static HWND HStop, HGrab, HQuit;
#include <atomic>
std::atomic<bool>StopGrab; //needed to protect the grab loop on/off flag
const char * WIN_NAME_CV = "OCV Image Display";
/** \brief Map an OpenCV window over a MFC/Win32 control
\param parentWnd the handle of MFC/Win32 static control
*/
bool cvWin2MfcControl(HWND parentWnd)
{
cv::namedWindow(WIN_NAME_CV, CV_WINDOW_KEEPRATIO); // create an OpenCV win
HWND hWnd = (HWND)cvGetWindowHandle(WIN_NAME_CV); // get the handle of OpenCV Window
if (!hWnd) return false;
HWND hParent = ::GetParent(hWnd);
::SetParent(hWnd, parentWnd); //move the OpenCV window to the new parent (your static control)
::ShowWindow(hParent, SW_HIDE); //hide the old parent window
//resize the OpenCV window to fit your static control
RECT parentRect;
::GetClientRect(parentWnd, &parentRect);
cvResizeWindow(WIN_NAME_CV, parentRect.right, parentRect.bottom);
return true;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{
TCHAR SmplClassName[] = L"Sample";
WNDCLASS SmplClass;
MSG msg;
hInst = hInstance;
if (!hPrevInstance)
{
SmplClass.style = CS_HREDRAW | CS_VREDRAW;
SmplClass.lpfnWndProc = (WNDPROC)SmplProc;
SmplClass.cbClsExtra = 0;
SmplClass.cbWndExtra = 0;
SmplClass.hInstance = hInstance;
SmplClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
SmplClass.hCursor = LoadCursor(NULL, IDC_ARROW);
SmplClass.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
SmplClass.lpszMenuName = 0;
SmplClass.lpszClassName = SmplClassName;
if (!RegisterClass(&SmplClass))
return (0);
}
SmplHwnd = CreateWindow(SmplClassName, L"LLGrab", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 1180, 740, NULL, NULL, hInstance, NULL);
// Create a static control where you want to draw the OpenCV frame (relative to parent win)
RECT rcDlg;
int border = 10;
int btnWidth = 80, btnHeight = 40,btnx,btny;
::GetClientRect(SmplHwnd, &rcDlg);
rcDlg.left = border;
rcDlg.top = border;
rcDlg.bottom -= (2 * border); //height
rcDlg.right -= (btnWidth + 3 * border); //width
if (!(GrabHwnd = CreateWindow(L"Static", L"Frame", SS_BITMAP | WS_CHILD | WS_VISIBLE | WS_BORDER,
rcDlg.left, rcDlg.top, rcDlg.right - rcDlg.left, rcDlg.bottom - rcDlg.top,
SmplHwnd, NULL, hInstance, NULL)))
return (FALSE);
cvWin2MfcControl(GrabHwnd);
// Draw the buttons out of the area used to draw the frame
btnx = rcDlg.right + border;
btny = rcDlg.top;
if (!(HGrab = CreateWindow(L"Button", L"Grab", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_BORDER, btnx, btny, btnWidth, btnHeight, SmplHwnd, (HMENU)PB_GRAB, hInstance, NULL)))
return (FALSE);
btny += btnHeight + border;
if (!(HStop = CreateWindow(L"Button", L"Stop", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_BORDER, btnx, btny, btnWidth, btnHeight, SmplHwnd, (HMENU)PB_STOP, hInstance, NULL)))
return (FALSE);
btny += btnHeight + border;
if (!(HQuit = CreateWindow(L"Button", L"Quit", BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_BORDER, btnx, btny, btnWidth, btnHeight, SmplHwnd, (HMENU)PB_QUIT, hInstance, NULL)))
return (FALSE);
btny += btnHeight + border;
EnableWindow(HStop, FALSE);
EnableWindow(HGrab, TRUE);
EnableWindow(HQuit, TRUE);
ShowWindow(SmplHwnd, SW_SHOW);
UpdateWindow(SmplHwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
WaitForSingleObject(HStopThread, INFINITE);
return (int)(msg.wParam);
}
LRESULT CALLBACK SmplProc(HWND hWnd, UINT iMessage, UINT wParam, LONG lParam)
{
WORD wmID;
switch (iMessage)
{
case WM_COMMAND:
wmID = LOWORD(wParam);
switch (wmID)
{
case PB_QUIT:
PostQuitMessage(0);
break;
case PB_GRAB:
OnGrab();
break;
case PB_STOP:
SetEvent(HStopEvent);
break;
}
break;
case WM_DESTROY:
SetEvent(HStopEvent);
PostQuitMessage(0);
default:
return DefWindowProc(hWnd, iMessage, wParam, lParam);
break;
}
return 0;
}
int OnGrab(void)
{
DWORD dwThreadId;
HStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!HStopEvent)
return 0;
HStopThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)StopThread, (LPWORD)&HStopEvent, 0, &dwThreadId);
if (!HStopThread)
return 0;
StopGrab.store(false);
HThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)GrabThread, NULL, 0, &dwThreadId);
if (HThread == NULL)
return 0;
return 0;
}
DWORD GrabThread(LPDWORD lpdwParam)
{
cv::VideoCapture captures;
captures.open(0);
cv::Mat frame;
EnableWindow(HStop, TRUE);
EnableWindow(HGrab, FALSE);
EnableWindow(HQuit, FALSE);
while (!StopGrab.load())
{
captures >> frame;
imshow(WIN_NAME_CV, frame); //display video here
//cvWaitKey(1); not needed
}
EnableWindow(HStop, FALSE);
EnableWindow(HGrab, TRUE);
EnableWindow(HQuit, TRUE);
return 0;
}
DWORD StopThread(LPDWORD lpdwParam)
{
DWORD dwResult;
HANDLE event = *((HANDLE*)lpdwParam);
dwResult = WaitForSingleObject(event, INFINITE);
StopGrab.store(true);
if (dwResult != WAIT_FAILED)
{
CloseHandle(event);
event = NULL;
}
return 0;
}
2 | No.2 Revision |
With Win32 GUI (and MFC) you can use both method:one of below:
cvWin2MfcControl
below for a complete exampleIn both cases you have to define a static control that will holds the image from opencv.
Some note:note about thread control:
May be your code is incomplete but the grabbing thread will be never stopped because stop
(pointer to StopGrab
) variable is never set to true
.
In addiction if you will set Doing StopGrab=true
in StopThread
this is you will have a race condition because 2 threads can access to StopGrab
. In general general, to stop the a thread you should use an event or a mutex, control var under a mutex or a critical section to protect the var from a shared variables. access. In this case you can use atomic<bool>
that is lock free than and faster than mutex or critical section.
For you and other user user, here is correct code using 2nd method 2 and atomic<bool>:atomic<bool>
:
#include <opencv2/opencv.hpp>
#define ID_GRABWIN PB_QUIT + 1000
#include <atomic>
std::atomic<bool>StopGrab; //needed to protect the grab loop on/off flag
HANDLE HStopThread, HStopEvent, HThread;
HINSTANCE hInst;
HWND SmplHwnd, GrabHwnd;
HWND HStop, HGrab, HQuit;
const char * WIN_NAME_CV = "OCV Image Display";
LRESULT CALLBACK SmplProc(HWND hWnd, UINT iMessage, UINT wParam, LONG lParam);
int OnGrab(void);
DWORD StopThread(LPDWORD lpdwParam);
DWORD GrabThread(LPDWORD lpdwParam);
static HANDLE HStopThread, HStopEvent, HThread;
static HINSTANCE hInst;
static HWND SmplHwnd, GrabHwnd;
static HWND HStop, HGrab, HQuit;
#include <atomic>
std::atomic<bool>StopGrab; //needed to protect the grab loop on/off flag
const char * WIN_NAME_CV = "OCV Image Display";
OnGrabClick(void);
/** ------------------------------------------------------------------------------------------
\brief Map an OpenCV window over a MFC/Win32 control
\param parentWnd the handle of MFC/Win32 static control
*/
bool cvWin2MfcControl(HWND parentWnd)
{
cv::namedWindow(WIN_NAME_CV, CV_WINDOW_KEEPRATIO); // create an OpenCV win
HWND hWnd cvWnd = (HWND)cvGetWindowHandle(WIN_NAME_CV); // get the handle of OpenCV Window
if (!hWnd) (!cvWnd) return false;
HWND hParent = ::GetParent(hWnd);
::SetParent(hWnd, hOldParent = ::GetParent(cvWnd);
::SetParent(cvWnd, parentWnd); //move // move the OpenCV window to the new parent (your static control)
::ShowWindow(hParent, ::ShowWindow(hOldParent, SW_HIDE); //hide // hide the old parent window
//resize // Resize the OpenCV window to fit your static control
RECT parentRect;
::GetClientRect(parentWnd, &parentRect);
cvResizeWindow(WIN_NAME_CV, parentRect.right, parentRect.bottom);
return true;
}
//------------------------------------------------------------------------------------------
DWORD GrabThread(LPDWORD lpdwParam)
{
cv::VideoCapture captures;
captures.open(0);
if (!captures.isOpened())
return -1;
cv::Mat frame;
EnableWindow(HStop, TRUE);
EnableWindow(HGrab, FALSE);
EnableWindow(HQuit, FALSE);
while (!StopGrab.load())
{
captures >> frame;
cv::imshow(WIN_NAME_CV, frame); //display video here
//cvWaitKey(1); not needed
}
EnableWindow(HStop, FALSE);
EnableWindow(HGrab, TRUE);
EnableWindow(HQuit, TRUE);
return 0;
}
//------------------------------------------------------------------------------------------
DWORD StopThread(LPDWORD lpdwParam)
{
DWORD dwResult;
HANDLE event = *((HANDLE*)lpdwParam);
dwResult = WaitForSingleObject(event, INFINITE);
StopGrab.store(true);
if (dwResult != WAIT_FAILED)
{
CloseHandle(event);
event = NULL;
}
return 0;
}
//----M A I N ----------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{
TCHAR SmplClassName[] = L"Sample";
WNDCLASS SmplClass;
MSG msg;
hInst = hInstance;
if (!hPrevInstance)
{
SmplClass.style = CS_HREDRAW | CS_VREDRAW;
SmplClass.lpfnWndProc = (WNDPROC)SmplProc;
SmplClass.cbClsExtra = 0;
SmplClass.cbWndExtra = 0;
SmplClass.hInstance = hInstance;
SmplClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
SmplClass.hCursor = LoadCursor(NULL, IDC_ARROW);
SmplClass.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
SmplClass.lpszMenuName = 0;
SmplClass.lpszClassName = SmplClassName;
if (!RegisterClass(&SmplClass))
return (0);
}
SmplHwnd = CreateWindow(SmplClassName, L"LLGrab", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1180, 740, NULL, NULL, hInstance, NULL);
// Create a the static control where you want to draw the OpenCV frame (relative to parent win)
RECT rcDlg;
int border = 10;
int btnWidth = 80, btnHeight = 40,btnx,btny;
::GetClientRect(SmplHwnd, &rcDlg);
rcDlg.left = border;
rcDlg.top = border;
rcDlg.bottom -= (2 * border); //height
rcDlg.right -= (btnWidth + 3 * border); //width
if (!(GrabHwnd = CreateWindow(L"Static", L"Frame", SS_BITMAP | WS_CHILD | WS_VISIBLE | WS_BORDER,
rcDlg.left, rcDlg.top, rcDlg.right - rcDlg.left, rcDlg.bottom - rcDlg.top,
SmplHwnd, NULL, hInstance, NULL)))
return (FALSE);
cvWin2MfcControl(GrabHwnd);
// Draw the buttons out of the area used to draw the frame
btnx = rcDlg.right + border;
btny = rcDlg.top;
if (!(HGrab = CreateWindow(L"Button", L"Grab", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_BORDER, WS_BORDER,
btnx, btny, btnWidth, btnHeight, SmplHwnd, (HMENU)PB_GRAB, hInstance, NULL)))
return (FALSE);
btny += btnHeight + border;
if (!(HStop = CreateWindow(L"Button", L"Stop", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_BORDER, btnx, btny, btnWidth, btnHeight, SmplHwnd, (HMENU)PB_STOP, hInstance, NULL)))
return (FALSE);
btny += btnHeight + border;
if (!(HQuit = CreateWindow(L"Button", L"Quit", BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_BORDER, btnx, btny, btnWidth, btnHeight, SmplHwnd, (HMENU)PB_QUIT, hInstance, NULL)))
return (FALSE);
btny += btnHeight + border;
EnableWindow(HStop, FALSE);
EnableWindow(HGrab, TRUE);
EnableWindow(HQuit, TRUE);
ShowWindow(SmplHwnd, SW_SHOW);
UpdateWindow(SmplHwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
WaitForSingleObject(HStopThread, INFINITE);
return (int)(msg.wParam);
}
//------------------------------------------------------------------------------------------
LRESULT CALLBACK SmplProc(HWND hWnd, UINT iMessage, UINT wParam, LONG lParam)
{
WORD wmID;
switch (iMessage)
{
case WM_COMMAND:
wmID = LOWORD(wParam);
switch (wmID)
{
case PB_QUIT:
PostQuitMessage(0);
break;
case PB_GRAB:
OnGrab();
OnGrabClick();
break;
case PB_STOP:
SetEvent(HStopEvent);
break;
}
break;
case WM_DESTROY:
SetEvent(HStopEvent);
PostQuitMessage(0);
default:
return DefWindowProc(hWnd, iMessage, wParam, lParam);
break;
}
return 0;
}
//------------------------------------------------------------------------------------------
int OnGrab(void)
OnGrabClick(void)
{
DWORD dwThreadId;
HStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!HStopEvent)
return 0;
HStopThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)StopThread, (LPWORD)&HStopEvent, 0, &dwThreadId);
if (!HStopThread)
return 0;
StopGrab.store(false);
HThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)GrabThread, NULL, 0, &dwThreadId);
if (HThread == NULL)
return 0;
return 0;
}
DWORD GrabThread(LPDWORD lpdwParam)
{
cv::VideoCapture captures;
captures.open(0);
cv::Mat frame;
EnableWindow(HStop, TRUE);
EnableWindow(HGrab, FALSE);
EnableWindow(HQuit, FALSE);
while (!StopGrab.load())
{
captures >> frame;
imshow(WIN_NAME_CV, frame); //display video here
//cvWaitKey(1); not needed
}
EnableWindow(HStop, FALSE);
EnableWindow(HGrab, TRUE);
EnableWindow(HQuit, TRUE);
return 0;
}
DWORD StopThread(LPDWORD lpdwParam)
{
DWORD dwResult;
HANDLE event = *((HANDLE*)lpdwParam);
dwResult = WaitForSingleObject(event, INFINITE);
StopGrab.store(true);
if (dwResult != WAIT_FAILED)
{
CloseHandle(event);
event = NULL;
}
return 0;
}
3 | No.3 Revision |
With Win32 GUI (and MFC) you can use one of below:
cvWin2MfcControl
below for a complete exampleIn both cases you have to define a static control that will holds the image from opencv.
Some note about thread control:
May be your code is incomplete but the grabbing thread will be never stopped because stop
(pointer to StopGrab
) variable is never set to true
.
Doing StopGrab=true
in StopThread
you will have a race condition because 2 threads can access to StopGrab
. In general, to stop a thread you should use an event or a control var under a mutex or a critical section to protect the var from a shared access. In this case you can use atomic<bool>
that is lock free and faster than mutex or critical section.
For you and other user, here is correct code using 2nd method and atomic<bool>
:.
EDIT: because atomic<bool>
is C++11 and isn't available in VS2008, a very simple class that defines a protected shared variable has been provided
#include <opencv2/opencv.hpp>
#if __cplusplus >= 199711L //is C++11 available ?
// Use std::atomic<bool> because is lock free
#include <atomic>
<atomic>
std::atomic<bool>StopGrab; //needed to protect the grab loop on/off flag
#else
// With old C++ compiler we create a very simple class to define
// a protected shared variable using CriticalSection
template<class T> class AtomicSimple
{
public:
AtomicSimple(){
InitializeCriticalSection(&CriticalSection);
};
AtomicSimple(T newVal) {
InitializeCriticalSection(&CriticalSection);
store(newVal);
}
~AtomicSimple(){
DeleteCriticalSection(&CriticalSection);
};
T load()
{
T curVal;
EnterCriticalSection(&CriticalSection);
curVal = val;
LeaveCriticalSection(&CriticalSection);
return curVal;
}
void store(T newVal)
{
EnterCriticalSection(&CriticalSection);
val = newVal;
LeaveCriticalSection(&CriticalSection);
}
private:
T val;
CRITICAL_SECTION CriticalSection;
};
AtomicSimple<bool>StopGrab; //needed to protect the grab loop on/off flag
#endif
HANDLE HStopThread, HStopEvent, HThread;
HINSTANCE hInst;
HWND SmplHwnd, GrabHwnd;
HWND HStop, HGrab, HQuit;
const char * WIN_NAME_CV = "OCV Image Display";
LRESULT CALLBACK SmplProc(HWND hWnd, UINT iMessage, UINT wParam, LONG lParam);
int OnGrabClick(void);
/** ------------------------------------------------------------------------------------------
\brief Map an OpenCV window over a MFC/Win32 control
\param parentWnd the handle of MFC/Win32 static control
*/
bool cvWin2MfcControl(HWND parentWnd)
{
cv::namedWindow(WIN_NAME_CV, CV_WINDOW_KEEPRATIO); // create an OpenCV win
HWND cvWnd = (HWND)cvGetWindowHandle(WIN_NAME_CV); // get the handle of OpenCV Window
if (!cvWnd) return false;
HWND hOldParent = ::GetParent(cvWnd);
::SetParent(cvWnd, parentWnd); // move the OpenCV window to the new parent (your static control)
::ShowWindow(hOldParent, SW_HIDE); // hide the old parent window
// Resize the OpenCV window to fit your static control
RECT parentRect;
::GetClientRect(parentWnd, &parentRect);
cvResizeWindow(WIN_NAME_CV, parentRect.right, parentRect.bottom);
return true;
}
//------------------------------------------------------------------------------------------
DWORD GrabThread(LPDWORD lpdwParam)
{
cv::VideoCapture captures;
captures.open(0);
if (!captures.isOpened())
return -1;
cv::Mat frame;
EnableWindow(HStop, TRUE);
EnableWindow(HGrab, FALSE);
EnableWindow(HQuit, FALSE);
while (!StopGrab.load())
{
captures >> frame;
cv::imshow(WIN_NAME_CV, frame); //display video here
//cvWaitKey(1); not needed
}
EnableWindow(HStop, FALSE);
EnableWindow(HGrab, TRUE);
EnableWindow(HQuit, TRUE);
return 0;
}
//------------------------------------------------------------------------------------------
DWORD StopThread(LPDWORD lpdwParam)
{
DWORD dwResult;
HANDLE event = *((HANDLE*)lpdwParam);
dwResult = WaitForSingleObject(event, INFINITE);
StopGrab.store(true);
if (dwResult != WAIT_FAILED)
{
CloseHandle(event);
event = NULL;
}
return 0;
}
//----M A I N ----------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{
TCHAR SmplClassName[] = L"Sample";
WNDCLASS SmplClass;
MSG msg;
hInst = hInstance;
if (!hPrevInstance)
{
SmplClass.style = CS_HREDRAW | CS_VREDRAW;
SmplClass.lpfnWndProc = (WNDPROC)SmplProc;
SmplClass.cbClsExtra = 0;
SmplClass.cbWndExtra = 0;
SmplClass.hInstance = hInstance;
SmplClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
SmplClass.hCursor = LoadCursor(NULL, IDC_ARROW);
SmplClass.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
SmplClass.lpszMenuName = 0;
SmplClass.lpszClassName = SmplClassName;
if (!RegisterClass(&SmplClass))
return (0);
}
SmplHwnd = CreateWindow(SmplClassName, L"LLGrab",
WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,
1180, 740, NULL, NULL, hInstance, NULL);
// Create the static control where you want to draw the OpenCV frame (relative to parent win)
RECT rcDlg;
int border = 10;
int btnWidth = 80, btnHeight = 40,btnx,btny;
::GetClientRect(SmplHwnd, &rcDlg);
rcDlg.left = border;
rcDlg.top = border;
rcDlg.bottom -= (2 * border); //height
rcDlg.right -= (btnWidth + 3 * border); //width
if (!(GrabHwnd = CreateWindow(L"Static", L"Frame", SS_BITMAP | WS_CHILD | WS_VISIBLE | WS_BORDER,
rcDlg.left, rcDlg.top, rcDlg.right - rcDlg.left, rcDlg.bottom - rcDlg.top,
SmplHwnd, NULL, hInstance, NULL)))
return (FALSE);
cvWin2MfcControl(GrabHwnd);
// Draw the buttons out of the area used to draw the frame
btnx = rcDlg.right + border;
btny = rcDlg.top;
if (!(HGrab = CreateWindow(L"Button", L"Grab", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_BORDER,
btnx, btny, btnWidth, btnHeight, SmplHwnd, (HMENU)PB_GRAB, hInstance, NULL)))
return (FALSE);
btny += btnHeight + border;
if (!(HStop = CreateWindow(L"Button", L"Stop", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_BORDER,
btnx, btny, btnWidth, btnHeight, SmplHwnd, (HMENU)PB_STOP, hInstance, NULL)))
return (FALSE);
btny += btnHeight + border;
if (!(HQuit = CreateWindow(L"Button", L"Quit", BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_BORDER,
btnx, btny, btnWidth, btnHeight, SmplHwnd, (HMENU)PB_QUIT, hInstance, NULL)))
return (FALSE);
btny += btnHeight + border;
EnableWindow(HStop, FALSE);
EnableWindow(HGrab, TRUE);
EnableWindow(HQuit, TRUE);
ShowWindow(SmplHwnd, SW_SHOW);
UpdateWindow(SmplHwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
WaitForSingleObject(HStopThread, INFINITE);
return (int)(msg.wParam);
}
//------------------------------------------------------------------------------------------
LRESULT CALLBACK SmplProc(HWND hWnd, UINT iMessage, UINT wParam, LONG lParam)
{
WORD wmID;
switch (iMessage)
{
case WM_COMMAND:
wmID = LOWORD(wParam);
switch (wmID)
{
case PB_QUIT:
PostQuitMessage(0);
break;
case PB_GRAB:
OnGrabClick();
break;
case PB_STOP:
SetEvent(HStopEvent);
break;
}
break;
case WM_DESTROY:
SetEvent(HStopEvent);
PostQuitMessage(0);
default:
return DefWindowProc(hWnd, iMessage, wParam, lParam);
break;
}
return 0;
}
//------------------------------------------------------------------------------------------
int OnGrabClick(void)
{
DWORD dwThreadId;
HStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!HStopEvent)
return 0;
HStopThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)StopThread, (LPWORD)&HStopEvent, 0, &dwThreadId);
if (!HStopThread)
return 0;
StopGrab.store(false);
HThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)GrabThread, NULL, 0, &dwThreadId);
if (HThread == NULL)
return 0;
return 0;
}