Related
Trouble
Look at the picture,when I scroll the vertical scrollbar, there are some flicker. I guess there are some other messages should be handled which I missed. WM_NCPAINT has been handled by my own procedure. The flicker seems like the original scrollbar drawing has been trigger which I don't know where.
What I have done
I redraw the SysListView32 control, both client zone and the non-client zone. I redraw the scrollbar in the non-client zone as you saw in the picture. I use memory DC for the double buffer drawing , hoping no flicker problems, while not succeed.
I handle several messages as code below:
LRESULT CALLBACK LVCProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
pListViewStyle ls=ListView_GetSettings(hwnd);// this structure store some extra info. for my owner-drawing.
if(!ls) return 0;
switch(message){
case WM_NCCALCSIZE: {
return LVC_NCCalcSize(hwnd,wParam,lParam); // I adjust the scrollbar size
} break;
case WM_NCACTIVATE:
case WM_NCPAINT: {
LVC_NCDrawScrollBar(hwnd,SB_HORZ); // This function mainly implement the drawing for the scrollbar.
LVC_NCDrawScrollBar(hwnd,SB_VERT);
return 0;
} break;
case WM_NCMOUSEMOVE: return 1;
case WM_ERASEBKGND: {
return 1;
} break;
case WM_MOUSEWHEEL: {
// support the scrolling for the listview when you scrolling the mouse-wheel.
int wheel_delta=GET_WHEEL_DELTA_WPARAM(wParam);
int scroll_pixls=((double)wheel_delta/10)*5*-1;
SendMessage(hwnd,LVM_SCROLL,(WPARAM)0,(LPARAM)scroll_pixls);
return 1;
} break;
case WM_PAINT: {
// totally redraw the content of the control
LVC_Paint(hwnd,wParam,lParam);
return 0;
} break;
case WM_NCLBUTTONUP:
//WM_NCLBUTTONDON / WM_MOUSEMOVE / WM_NCLBUTTONUP ,
//these three messages are handled when you press the thumb block and scrolling the window.
ReleaseCapture();
break;
case WM_NCLBUTTONDOWN: {
return LVC_ScrollBefore(hwnd,wParam,lParam);
} break;
case WM_MOUSEMOVE: {
if(GetCapture()==hwnd) {
LVC_Scrolling(hwnd,wParam,lParam);
return 1;
}
} break;
case WM_SIZE: {
// update the nPage of SCROLLINFO for the control
LVC_Size(hwnd,wParam,lParam);
return 1;
} break;
case LVM_SCROLL: {
// scroll the content and update the invalidate rect.
LVC_Scroll(hwnd,wParam,lParam);
return 1;
} break;
case WM_NCHITTEST: {
// I change the return value for the scrollbar areas , which I abolish the two arrows area.
return LVC_HitTest(hwnd,wParam,lParam);
}
case WM_LBUTTONDOWN:
// when you click the item of the listview, you change the selected state for the item.
LVC_ModifySelState(hwnd,wParam,lParam);
return 0;
} break;
// this part has been canceled,
//I am not using the interface of owner-drawing each item provided by MS.
//I redraw directly by rewrite the WM_PAINT message.
/*
case WMYU_DRAWLISTVIEWITEM: {
LVC_DrawItem(hwnd,wParam,lParam);
return TRUE;
} break;
case WMYU_MEASURELISTVIEWITEM: {
LPMEASUREITEMSTRUCT lpmis=(LPMEASUREITEMSTRUCT)lParam;
lpmis->itemHeight=ls->content_height;
} break;
*/
case WM_NCDESTROY: {
// release the extra resources before destroy the control.
WNDPROC pre_proc=ls->pre_proc;
ListView_ClearSettings(hwnd);
if(pre_proc) return CallWindowProc(pre_proc,hwnd,message,wParam,lParam);
} break;
}
// other messages do not change.
return CallWindowProc(ls->pre_proc,hwnd,message,wParam,lParam);
}
/*WM_PAINT: redraw the whole content*/
int LVC_Paint(HWND hwnd,WPARAM wParam,LPARAM lParam)
{
int idx_item=0;
int page=0;
int x_offset=0,y_offset=0;
char item_text[256]="";//item text
//control extra info.
pListViewStyle ls=ListView_GetSettings(hwnd);
if(!ls) return -1;
//the sub-control head for the columns.
HWND head=ListView_GetHeader(hwnd);
int itm_count=ListView_GetItemCount(hwnd);
int col_count=Header_GetItemCount(head);
int col_start=0,col_stop=col_count-1;
RECT rcHead={0},rcClient;
int head_height=0;
GetWindowRect(head,&rcHead);
head_height=rcHead.bottom-rcHead.top;
GetClientRect(hwnd,&rcClient);
//axis x,y offset . calculated by the SCROLLINFO provided by the control
SCROLLINFO si={0};
si.cbSize=sizeof(si);
si.fMask=SIF_ALL;
UINT style=GetWindowLongPtr(hwnd,GWL_STYLE);
BOOL HasVScroll=((style&WS_VSCROLL)==WS_VSCROLL);
BOOL HasHScroll=((style&WS_HSCROLL)==WS_HSCROLL);
if(HasVScroll) {
GetScrollInfo(hwnd,SB_VERT,&si);
idx_item=si.nPos;
page=si.nPage;
}
else page=ListView_GetItemCount(hwnd);
if(HasHScroll) {
GetScrollInfo(hwnd,SB_HORZ,&si);
x_offset=si.nPos;
}
y_offset=head_height;
//prepare for painting
PAINTSTRUCT ps;
HDC hdc=BeginPaint(hwnd,&ps);
int cx=ps.rcPaint.right-ps.rcPaint.left;
int cy=ps.rcPaint.bottom-ps.rcPaint.top;
HDC memdc=CreateCompatibleDC(hdc);
HBITMAP bmp=CreateCompatibleBitmap(hdc,cx,cy);
HBITMAP pre_bmp=(HBITMAP)SelectObject(memdc,bmp);
HFONT pre_font=(HFONT)SelectObject(memdc,(HFONT)SendMessage(hwnd,WM_GETFONT,0,0));
SetBkMode(memdc,TRANSPARENT);
SetTextColor(memdc,RGB(255,255,255));
HPEN pen=CreatePen(PS_SOLID,1,RGB(40,46,44));
HPEN pre_pen=(HPEN)SelectObject(memdc,pen);
//memory rectangle for Mem DC
RECT rcMem;
CopyRect(&rcMem,&ps.rcPaint);
//offset the coordinate
POINT pt_org;
OffsetViewportOrgEx(memdc,-rcMem.left,-rcMem.top,&pt_org);
RECT rcItem;//item rectangle
COLORREF rgb_curr;
BOOL col_trigger=FALSE;//column painting stop flags.
int rcTop=0,rcBottom=0;
//background
HBRUSH bkbrush=CreateSolidBrush(RGB(20,20,20));
FillRect(memdc,&rcMem,bkbrush);
DeleteObject(bkbrush);
//update the rectangle specfied by the PAINTSTRUCT
for(int index=0;index<=page&&(index+idx_item<itm_count);index++) {
//calculate whether each visible item in current view is in invalid rect
rcTop=index*ls->content_height+y_offset;
rcBottom=rcTop+ls->content_height;
//Item ID
int itemID=index+idx_item;
//if this item in rectangle specified by PAINTSTRUCT, redraw it.
if(rcTop>=ps.rcPaint.top&&rcTop<=ps.rcPaint.bottom) {
//state
UINT state=ListView_GetItemState(hwnd,itemID,LVIS_SELECTED|LVIS_FOCUSED);
//even odd different color
if(itemID%2==0) rgb_curr=ls->rgb_even;
else rgb_curr=ls->rgb_odd;
if(state&LVIS_SELECTED==LVIS_SELECTED) rgb_curr=ls->rgb_sel;
if(state&LVIS_FOCUSED==LVIS_FOCUSED) rgb_curr=ls->rgb_focus;
HBRUSH brush=CreateSolidBrush(rgb_curr);
HBRUSH pre_brush=(HBRUSH)SelectObject(memdc,brush);
//draw item and subitem.
for(int idx_col=col_start;idx_col<=col_stop;idx_col++) {
ListView_GetSubItemRect(hwnd,itemID,idx_col, LVIR_LABEL,&rcItem);
//x,y axis offset
OffsetRect(&rcItem,-x_offset,-idx_item*ls->content_height);
//if current item or subitem not in update area, no need to hanle it
if(ps.rcPaint.left>rcItem.right) continue;
else if(!col_trigger){
col_start=idx_col;
col_trigger=TRUE;
}
if(ps.rcPaint.right<rcItem.left) {
col_stop=idx_col-1;
break;
}
//while painting
Rectangle(memdc,rcItem.left-1,rcItem.top-1,rcItem.right,rcItem.bottom);
memset(item_text,0x00,sizeof(item_text));
ListView_GetItemText(hwnd,itemID,idx_col,item_text,sizeof(item_text));
InflateRect(&rcItem,-5,-3);
DrawText(memdc,item_text,-1,&rcItem,DT_SINGLELINE|DT_VCENTER|DT_END_ELLIPSIS);
}
DeleteObject(brush);
}
}
//paste
BitBlt(hdc,ps.rcPaint.left,ps.rcPaint.top,cx,cy,
memdc,rcMem.left,rcMem.top,SRCCOPY);
//reset
SetViewportOrgEx(memdc,pt_org.x,pt_org.y,NULL);
//resource reset and release
SelectObject(memdc,pre_font);
DeleteObject(SelectObject(memdc,pre_pen));
DeleteObject(SelectObject(memdc,pre_bmp));
DeleteDC(memdc);
//paint finished
EndPaint(hwnd,&ps);
return 0;
}
/*Paint the scrollbar*/
int LVC_NCDrawScrollBar(HWND hwnd,UINT scrolltype)
{
RECT rc;
RECT rcThumb;
HDC hdc=GetWindowDC(hwnd);
UINT style=(UINT)GetWindowLongPtr(hwnd,GWL_STYLE);
//use memdc , double buffering. still flicker
if(scrolltype==SB_VERT) {
if(LVC_GetZoneRect(hwnd,ZVSCROLL,&rc,TRUE)==0&&
LVC_GetZoneRect(hwnd,ZVSTHUMB,&rcThumb,TRUE)==0) {
int cx=rc.right-rc.left,cy=rc.bottom-rc.top;
if((style&WS_HSCROLL)) cy+=SCROLLBAR_PIXLS;
HDC memdc=CreateCompatibleDC(hdc);
HBITMAP bmp=CreateCompatibleBitmap(hdc,cx,cy);
HBITMAP pre_bmp=(HBITMAP)SelectObject(memdc,bmp);
RECT rcMem;
CopyRect(&rcMem,&rc);
OffsetRect(&rcMem,-rcMem.left,-rcMem.top);
HBRUSH brush=CreateSolidBrush(RGB(15,15,15));
FillRect(memdc,&rcMem,brush);
DeleteObject(brush);
OffsetRect(&rcThumb,-rc.left-1,-rc.top);
InflateRect(&rcThumb,-1,0);
Graphics graphic(memdc);
GraphicsPath path;
LinearGradientBrush pbrush(Rect(rcThumb.left,rcThumb.top,rcThumb.right-rcThumb.left,rcThumb.bottom-rcThumb.top),
Color(255,50,50,50),
Color(255,20,20,20),
LinearGradientModeHorizontal);
graphic.SetSmoothingMode(SmoothingModeHighQuality);
path.AddArc(rcThumb.left,rcThumb.top,SCROLLBAR_PIXLS,SCROLLBAR_PIXLS,180,180);
path.AddArc(rcThumb.left,rcThumb.bottom-SCROLLBAR_PIXLS,SCROLLBAR_PIXLS,SCROLLBAR_PIXLS,0,180);
graphic.FillPath(&pbrush,&path);
BitBlt(hdc,rc.left,rc.top,cx,cy,memdc,0,0,SRCCOPY);
DeleteObject(SelectObject(memdc,pre_bmp));
DeleteDC(memdc);
}
}
else if(scrolltype==SB_HORZ) {
if(LVC_GetZoneRect(hwnd,ZHSCROLL,&rc,TRUE)==0&&
LVC_GetZoneRect(hwnd,ZHSTHUMB,&rcThumb,TRUE)==0) {
int cx=rc.right-rc.left,cy=rc.bottom-rc.top;
HDC memdc=CreateCompatibleDC(hdc);
HBITMAP bmp=CreateCompatibleBitmap(hdc,cx,cy);
HBITMAP pre_bmp=(HBITMAP)SelectObject(memdc,bmp);
RECT rcMem;
CopyRect(&rcMem,&rc);
OffsetRect(&rcMem,-rcMem.left,-rcMem.top);
HBRUSH brush=CreateSolidBrush(RGB(15,15,15));
FillRect(memdc,&rcMem,brush);
DeleteObject(brush);
OffsetRect(&rcThumb,-rc.left,-rc.top-1);
InflateRect(&rcThumb,0,-1);
Graphics graphic(memdc);
GraphicsPath path;
LinearGradientBrush pbrush(Rect(rcThumb.left,rcThumb.top,rcThumb.right-rcThumb.left,rcThumb.bottom-rcThumb.top),
Color(255,50,50,50),
Color(255,20,20,20),
LinearGradientModeVertical);
graphic.SetSmoothingMode(SmoothingModeHighQuality);
path.AddArc(rcThumb.left,rcThumb.top,SCROLLBAR_PIXLS,SCROLLBAR_PIXLS,90,180);
path.AddArc(rcThumb.right-SCROLLBAR_PIXLS,rcThumb.top,SCROLLBAR_PIXLS,SCROLLBAR_PIXLS,-90,180);
graphic.FillPath(&pbrush,&path);
BitBlt(hdc,rc.left,rc.top,cx,cy,memdc,0,0,SRCCOPY);
DeleteObject(SelectObject(memdc,pre_bmp));
DeleteDC(memdc);
}
}
ReleaseDC(hwnd,hdc);
return 0;
}
/* LVM_SCROLL*/
int LVC_Scroll(HWND hwnd,WPARAM wParam,LPARAM lParam)
{
HWND head=ListView_GetHeader(hwnd);
if(!head) return 0;
pListViewStyle ls=ListView_GetSettings(hwnd);
if(!ls) return 0;
int hscroll_pixls=(int)wParam;
int vscroll_pixls=(int)lParam;
RECT rc,rcScroll,rcHead,rcInvalid;
GetClientRect(hwnd,&rc);
CopyRect(&rcScroll,&rc);
GetWindowRect(head,&rcHead);
rcScroll.top=rcHead.bottom-rcHead.top;
CopyRect(&rcInvalid,&rcScroll);
SCROLLINFO si={0};
si.cbSize=sizeof(SCROLLINFO);
si.fMask=SIF_ALL;
if(hscroll_pixls!=0) {
GetScrollInfo(hwnd,SB_HORZ,&si);
int pre_pos=si.nPos;
si.fMask=SIF_POS;
si.nPos=pre_pos+hscroll_pixls;
if(si.nPos+si.nPage>=si.nMax) si.nPos=si.nMax-si.nPage+1;
else if(si.nPos<=si.nMin) si.nPos=si.nMin;
SetScrollInfo(hwnd,SB_HORZ,&si,TRUE);
InvalidateRect(head,NULL,TRUE);
if(hscroll_pixls>0) rcInvalid.left=rcInvalid.right-hscroll_pixls-1;
else rcInvalid.right=rcInvalid.left-hscroll_pixls+1;
ScrollWindow(hwnd,-hscroll_pixls,0,NULL,&rcScroll);
LVC_NCDrawScrollBar(hwnd,SB_HORZ);
InvalidateRect(hwnd,&rcInvalid,TRUE);
}
if(vscroll_pixls!=0) {
GetScrollInfo(hwnd,SB_VERT,&si);
int pre_pos=si.nPos;
int page=si.nPage;
si.fMask=SIF_POS;
int scroll_pos=vscroll_pixls/ls->content_height;
//recalculate the nPos.
si.nPos=pre_pos+scroll_pos;
if(si.nPos+si.nPage>=si.nMax) si.nPos=si.nMax-si.nPage+1;
else if(si.nPos<=si.nMin) si.nPos=si.nMin;
vscroll_pixls=(si.nPos-pre_pos)*ls->content_height;
SetScrollInfo(hwnd,SB_VERT,&si,TRUE);
if(vscroll_pixls>0)
rcInvalid.bottom=rcInvalid.top+vscroll_pixls;
else
rcInvalid.top=rcInvalid.top+(page+scroll_pos)*ls->content_height-1;
if(rcInvalid.top<rcScroll.top) rcInvalid.top=rcScroll.top;
if(rcInvalid.bottom>rcScroll.bottom) rcInvalid.bottom=rcScroll.bottom;
ScrollWindow(hwnd,0,-vscroll_pixls,NULL,&rcScroll);
InvalidateRect(hwnd,&rcInvalid,TRUE);
LVC_NCDrawScrollBar(hwnd,SB_VERT);
}
return 0;
}
int LVC_ScrollBefore(HWND hwnd,WPARAM wParam,LPARAM lParam)
{
UINT hit=wParam;
POINT pt={GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)};
pListViewStyle ls=ListView_GetSettings(hwnd);
if(!ls) return -1;
if(hit==HTHSCROLL) {
RECT rc_hs;
if(LVC_GetZoneRect(hwnd,ZHSTHUMB,&rc_hs,FALSE)!=0) return -1;
if(!PtInRect(&rc_hs,pt)) return -1;
ScreenToClient(hwnd,&pt);
ls->drag_pt.x=pt.x;
ls->drag_pt.y=-1;
SCROLLINFO si={0};
si.cbSize=sizeof(si);
si.fMask=SIF_POS;
GetScrollInfo(hwnd,SB_HORZ,&si);
ls->drag_pos.x=si.nPos;
ls->drag_pos.y=-1;
SetCapture(hwnd);
return 0;
}
else if(hit==HTVSCROLL) {
RECT rc_vs;
if(LVC_GetZoneRect(hwnd,ZVSTHUMB,&rc_vs,FALSE)!=0) return -1;
if(!PtInRect(&rc_vs,pt)) return -1;
ScreenToClient(hwnd,&pt);
ls->drag_pt.y=pt.y;
ls->drag_pt.x=-1;
SCROLLINFO si={0};
si.cbSize=sizeof(si);
si.fMask=SIF_POS;
GetScrollInfo(hwnd,SB_VERT,&si);
ls->drag_pos.y=si.nPos;
ls->drag_pos.x=-1;
SetCapture(hwnd);
return 0;
}
else {
return CallWindowProc(ls->pre_proc,hwnd,WM_NCLBUTTONDOWN,wParam,lParam);
}
}
int LVC_Scrolling(HWND hwnd,WPARAM wParam,LPARAM lParam)
{
POINT pt={GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)};
pListViewStyle ls=ListView_GetSettings(hwnd);
if(!ls) return -1;
if(GetCapture()!=hwnd) return -1;
if(ls->drag_pos.x!=-1) { // HORZ
RECT rc_hs,rc_thumb;
if(LVC_GetZoneRect(hwnd,ZHSCROLL,&rc_hs,TRUE)!=0) return -1;
if(LVC_GetZoneRect(hwnd,ZHSTHUMB,&rc_thumb,TRUE)!=0) return -1;
SCROLLINFO si;
si.cbSize=sizeof(si);
si.fMask=SIF_ALL;
GetScrollInfo(hwnd,SB_HORZ,&si);
int pre_pos=si.nPos;
si.nPos=(int)ls->drag_pos.x+(int)(si.nMax-si.nMin+1-si.nPage)*1.0*(int)(pt.x-ls->drag_pt.x)/((rc_hs.right-rc_hs.left)-(rc_thumb.right-rc_thumb.left));
if(si.nPos==ls->drag_pos.x) return -1;
if((int)si.nPos>(int)(si.nMax-si.nPage+1)) si.nPos=si.nMax-si.nPage+1;
else if(si.nPos<si.nMin) si.nPos=si.nMin;
ListView_Scroll(hwnd,si.nPos-pre_pos,0);
LVC_NCDrawScrollBar(hwnd,SB_HORZ);
}
else if(ls->drag_pos.y!=-1) {
RECT rc_vs,rc_thumb;
if(LVC_GetZoneRect(hwnd,ZVSCROLL,&rc_vs,TRUE)!=0) return -1;
if(LVC_GetZoneRect(hwnd,ZVSTHUMB,&rc_thumb,TRUE)!=0) return -1;
SCROLLINFO si;
si.cbSize=sizeof(si);
si.fMask=SIF_ALL;
GetScrollInfo(hwnd,SB_VERT,&si);
int pre_pos=si.nPos;
si.nPos=(int)ls->drag_pos.y+((int)(si.nMax-si.nMin+1-si.nPage))*1.0*((int)(pt.y-ls->drag_pt.y))/((rc_vs.bottom-rc_vs.top)-(rc_thumb.bottom-rc_thumb.top));
if(si.nPos==ls->drag_pos.y) return -1;
if((int)si.nPos>(int)(si.nMax-si.nPage+1)) si.nPos=si.nMax-si.nPage+1;
else if(si.nPos<si.nMin) si.nPos=si.nMin;
ListView_Scroll(hwnd,0,(si.nPos-pre_pos)*ls->content_height);
LVC_NCDrawScrollBar(hwnd,SB_VERT);
}
return 0;
}
int LVC_ScrollDone(HWND hwnd,WPARAM wParam,LPARAM lParam)
{
pListViewStyle ls=ListView_GetSettings(hwnd);
if(!ls) return -1;
if(GetCapture()==hwnd) {
ReleaseCapture();
if(ls->drag_pos.y!=-1) LVC_NCDrawScrollBar(hwnd,SB_VERT);
if(ls->drag_pos.x!=-1) LVC_NCDrawScrollBar(hwnd,SB_HORZ);
ls->drag_pt.x=ls->drag_pt.y=ls->drag_pos.x=ls->drag_pos.y=-1;
}
return 0;
}
I want to scroll my window, but when i do that, the previous image remains. How can i fix it?
My code, maybe there are some problems:
switch (LOWORD(wParam))
{
case SB_LINEDOWN:
iVScrollInc = 1;
break;
case SB_LINEUP:
iVScrollInc = -1;
break;
case SB_THUMBTRACK:
iVScrollInc = HIWORD(wParam) - iVScrollPos;
break;
default:
iVScrollInc = 0;
break;
}
iVScrollInc = max(-iVScrollPos, min(iVScrollInc, iVScrollMax - iVScrollPos));
if (iVScrollInc != 0)
{
iVScrollPos += iVScrollInc;
ScrollWindow(hWnd, 0, -cyChar * iVScrollInc, NULL, NULL);
SetScrollPos(hWnd, SB_VERT, iVScrollPos, TRUE);
UpdateWindow(hWnd);
}
EDIT (i cant paste all my code because of stackoverflow writes me that i have more code that describing of my question)
case WM_PAINT:{
PAINTSTRUCT ps;
HDC hDc = BeginPaint(hWnd, &ps);
for (int i = 0 ; i < buffer.size(); ++i)
TextOut(hDc, 20, 20 + i*cyChar, buffer[i].c_str(), buffer[i].length());
EndPaint(hWnd, &ps);
return 0;
}
// buffer - is std::vector<std::string>
// cyChar - is height of symbols
for (int i = 0 ; i < buffer.size(); ++i), it shouldn't be buffer.size().
Add int iPaintEnd = min(buffer.size(), iVscrollPos + ps.rcPaint.bottom / cyChar); Change to for (int i = 0 ; i < iPaintEnd ; ++i)
Besides, you should use std::vector<std::wstring> buffer.
Here is my code, you need refer to it.
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
static int cxChar, cxCaps, cyChar, cxClient, cyClient, iMaxWidth,
iVscrollPos, iVscrollMax;
HDC hdc;
int i, y, iPaintBeg, iPaintEnd, iVscrollInc;
PAINTSTRUCT ps;
TEXTMETRIC tm;
switch (iMsg)
{
case WM_CREATE:
hdc = GetDC(hwnd);
GetTextMetrics(hdc, &tm);
cxChar = tm.tmAveCharWidth;
cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2;
cyChar = tm.tmHeight + tm.tmExternalLeading;
ReleaseDC(hwnd, hdc);
iMaxWidth = 40 * cxChar + 22 * cxCaps;
return 0;
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
iVscrollMax = max(0,buffer.size() + 2 - cyClient / cyChar);
iVscrollPos = min(iVscrollPos, iVscrollMax);
SetScrollRange(hwnd, SB_VERT, 0, iVscrollMax, FALSE);
SetScrollPos(hwnd, SB_VERT, iVscrollPos, TRUE);
return 0;
case WM_VSCROLL:
switch (LOWORD(wParam))
{
case SB_TOP:
iVscrollInc = -iVscrollPos;
break;
case SB_BOTTOM:
iVscrollInc = iVscrollMax - iVscrollPos;
break;
case SB_LINEUP:
iVscrollInc = -1;
break;
case SB_LINEDOWN:
iVscrollInc = 1;
break;
case SB_PAGEUP:
iVscrollInc = min(-1, -cyClient / cyChar);
break;
case SB_PAGEDOWN:
iVscrollInc = max(1, cyClient / cyChar);
break;
case SB_THUMBTRACK:
iVscrollInc = HIWORD(wParam) - iVscrollPos;
break;
default:
iVscrollInc = 0;
}
iVscrollInc = max(-iVscrollPos,
min(iVscrollInc, iVscrollMax - iVscrollPos));
if (iVscrollInc != 0)
{
iVscrollPos += iVscrollInc;
ScrollWindow(hwnd, 0, -cyChar * iVscrollInc, NULL, NULL);
SetScrollPos(hwnd, SB_VERT, iVscrollPos, TRUE);
UpdateWindow(hwnd);
}
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
iPaintBeg = max(0, iVscrollPos + ps.rcPaint.top / cyChar - 1);
iPaintEnd = min(buffer.size(),
iVscrollPos + ps.rcPaint.bottom / cyChar);
for (i = iPaintBeg; i < iPaintEnd; i++)
{
y = cyChar * (1 - iVscrollPos + i);
TextOut(hdc, 0, y,
buffer[i].c_str(),
buffer[i].length());
SetTextAlign(hdc, TA_LEFT | TA_TOP);
}
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
In this code I am drawing line using LineTo function. When I run below code GetMessage function returning -1 value. I am not getting why it is happening. I search At some places it is given that if hwnd is already destroyed then GetMessage function will return -1. When I pass second parameter of GetMessage as NULL My code runs fine. I am using Visual Studio 2010.
#include<Windows.h>
#include<stdio.h>
long int count_paint =0;
LRESULT CALLBACK my_WindowsProc_1(HWND hwnd, UINT msgkdjaks, WPARAM w, LPARAM l)
{
HDC hdc;
PAINTSTRUCT ps;
switch(msgkdjaks)
{
case WM_PAINT:
hdc = BeginPaint(hwnd,&ps);
MoveToEx(hdc,30,30,NULL);
LineTo(hdc,210,125);
EndPaint(hwnd,&ps);
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd,msgkdjaks,w,l);
}
int WINAPI WinMain(HINSTANCE hCur, HINSTANCE hPre, LPSTR lpr, int cmd_arg)
{
MSG msg;
HWND hwnd1,hwnd2;
LPCTSTR class_name=L"My_Window_class";
int x=0;
WNDCLASSEX wc1;
wc1.cbSize=sizeof(WNDCLASSEX);
wc1.style=0;
wc1.lpfnWndProc=my_WindowsProc_1;
wc1.cbClsExtra=0;
wc1.cbWndExtra=0;
wc1.hInstance=hCur;
wc1.hIcon=LoadIcon(NULL, IDI_APPLICATION);
wc1.hCursor=LoadCursor(NULL,IDC_ARROW);
wc1.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);
wc1.lpszMenuName=NULL;
wc1.lpszClassName=class_name;
wc1.hIconSm=LoadIcon(NULL,IDI_APPLICATION);
if(!RegisterClassEx(&wc1))
{
return 10;
}
hwnd1 = CreateWindow(class_name, L"This is my window1",WS_OVERLAPPEDWINDOW,
200,200,300,300,NULL,NULL,hCur,NULL);
if(hwnd1==NULL)
{
return 20;
}
ShowWindow(hwnd1 , cmd_arg);
UpdateWindow(hwnd1);
BOOL bRet;
while((bRet = GetMessage( &msg, hwnd1, 0, 0 )) != 0)
{
if (bRet == -1){
return -20;
}
else{
TranslateMessage(&msg);//
DispatchMessage(&msg);
}
}
return 0;
}
I'd like to put a button in a foreign windows' title bar, much like Teamviewer does with the Quickconnect feature, or like Chrome has one in the top-right for switching users.
I know this is a repeat of How is Teamviewers Quickconnect button accomplished?
I'm just wondering if it would be possible to get a working example or a link to an open-source program that implements this. The answers given there are rather advanced for me. As in, how am I supposed to "hook" and "intercept" WM_NCPAINT message and so on.
This is the most simple example i can develop:
You need Visual Studio, add 2 project to the solution:
first project (HookDLL) is a dll project, second (Running app) is a win32 console project
in main.cpp (at project Running app) add this:
__declspec(dllimport) void RunHook();
int _tmain(int argc, _TCHAR* argv[])
{
RunHook();
return 0;
}
in dllmain button.cpp (at HookDLL project) add this code:
#include <Windows.h>
#include <stdio.h>
HINSTANCE hinstDLL;
HHOOK hhook_wndproc;
HWND b = NULL;
HBRUSH blue_brush = NULL, yellow_brush, red_brush;
int button_status = 0;
LRESULT CALLBACK DefaultWindowProc(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
switch(Msg)
{
case WM_CREATE:
if(!blue_brush)
{
blue_brush = CreateSolidBrush(RGB(0, 0, 255));
yellow_brush = CreateSolidBrush(RGB(255, 255, 0));
red_brush = CreateSolidBrush(RGB(255, 0, 0));
}
break;
case WM_PAINT:
{
HBRUSH b;
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
switch(button_status)
{
case 0:
b = blue_brush;
break;
case 1:
b = yellow_brush;
break;
default:
b = red_brush;
}
FillRect(hdc, &ps.rcPaint, b);
EndPaint(hwnd, &ps);
}
return 0;
case WM_MOUSEMOVE:
if(button_status == 0)
{
SetTimer(hwnd, 1, 100, NULL);
button_status = 1;
InvalidateRect(hwnd, NULL, false);
}
return 0;
case WM_TIMER:
{
POINT pt;
GetCursorPos(&pt);
if(button_status == 1 && WindowFromPoint(pt) != hwnd)
{
KillTimer(hwnd, 1);
button_status = 0;
InvalidateRect(hwnd, NULL, false);
}
}
return 0;
case WM_MOUSELEAVE:
button_status = 0;
InvalidateRect(hwnd, NULL, false);
return 0;
case WM_LBUTTONDOWN:
button_status = 2;
InvalidateRect(hwnd, NULL, false);
return 0;
case WM_LBUTTONUP:
if(button_status == 2) MessageBox(GetParent(hwnd), "teamviewer like button clicked", "Message", MB_OK);
button_status = 1;
InvalidateRect(hwnd, NULL, false);
return 0;
}
return DefWindowProc(hwnd, Msg, wParam, lParam);
}
void InitButton(HWND parent, int xPos, int yPos)
{
WNDCLASS wc;
wc.style = 0;
wc.lpfnWndProc = DefaultWindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hinstDLL;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = "DEFAULT_CLASS";
RegisterClass(&wc);
b = CreateWindowEx(WS_EX_TOOLWINDOW, "DEFAULT_CLASS", NULL, WS_BORDER | WS_POPUP | WS_VISIBLE, xPos, yPos, 20, 20, parent, NULL, hinstDLL, NULL);
}
LRESULT WINAPI HookCallWndProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if(nCode >= 0 && lParam != 0)
{
CWPRETSTRUCT *msg = (CWPRETSTRUCT*)lParam;
if(!IsWindow(msg->hwnd) || (GetWindowLong(msg->hwnd, GWL_STYLE) & WS_CHILD) != 0) return CallNextHookEx(hhook_wndproc, nCode, wParam, lParam);
switch(msg->message)
{
case WM_SHOWWINDOW:
if(!b && msg->wParam != 0)
{
b = (HWND)1;// see NOTES 5
RECT a;
GetWindowRect(msg->hwnd, &a);
InitButton(msg->hwnd, a.right - 150, a.top);
}
break;
case WM_SIZE:
if(GetParent(b) == msg->hwnd)
{
RECT a;
GetWindowRect(msg->hwnd, &a);
SetWindowPos(b, 0, a.right - 150, a.top, 0, 0, SWP_NOSIZE | SWP_NOOWNERZORDER | SWP_NOZORDER);
}
break;
case WM_SIZING:
case WM_MOVING:
if(GetParent(b) == msg->hwnd)
{
RECT* lprc = (LPRECT) msg->lParam;
SetWindowPos(b, 0, lprc->right - 150, lprc->top, 0, 0, SWP_NOSIZE | SWP_NOOWNERZORDER | SWP_NOZORDER);
}
}
}
return CallNextHookEx(hhook_wndproc, nCode, wParam, lParam);
}
__declspec(dllexport) void RunHook()
{
hhook_wndproc = SetWindowsHookEx(WH_CALLWNDPROCRET, HookCallWndProc, hinstDLL, 0);
char aux[10];
gets_s(aux);
UnhookWindowsHookEx(hhook_wndproc);
}
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hinstDLL = hModule;
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
Now, make dll project depedent of running app project in project->project dependencies:
NOTES:
1) i dont use NC paint code, because not always works, if windows buffer non client region, erases customized NC paint buttons
2) in 64 bits enviroment, you need to run a 32 bits hook for 32 bits apps, and other hook for 64 bits apps
3) YOU CAN NOT DEBUG YOUR HOOK WHEN IS CONNECTED TO ANOTHER PROCCESS, i suggest you debug it with a windows in your app and thread, and test it late in another proccess when is working
4) i use a button like approach for simplicity
5) this line
b = (HWND)1;
I use it for "solve" a multi thread problem, i suggest you make better code (syncronization) this case
HOW THIS WORKS:
run the app
when it start install a hook
open any other app (same 32/64 bits, see NOTE 2)
you must see a blue button at left side of title bar
click it and see a message box
for finish hook: just press ENTER at console window
CODE FLOW:
Running app just calls RunHook() procedure in dll, and dll do the work
RunHook() in dll starts a hook HookCallWndProc (global)
HookCallWndProc captures required message and creates the window button using InitButton() procedure
DefaultWindowProc handles button message
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!).