win32 C++ put an image on the screen - c++

i am learning C++ but i am having problems with putting an image on the screen.
i have searched the internet for help but i couldn't find any.
i am trying to create a window and put a simple color in the client area when the WM_Paint message is called, but the program just displays a grey screen as usual. i am using code::blocks 10.05.
#include <windows.h>
#include <iostream>
using namespace std;
int winx = 500;
int winy = 500;
int winbpp = 24;
static char m_bibuf[ sizeof(BITMAPINFOHEADER) + 12 ];
static BITMAPINFO &m_bi = *(BITMAPINFO*)&m_bibuf;
static BITMAPINFOHEADER &m_bih = m_bi.bmiHeader;
int* buffer = new int[winx*winy*winbpp];
int setbuffer()
{
for(int x = 0; x < winx; x++)
{
for(int y=0; y < winy; y++)
{
for(int z =0; z < winbpp; z++)
{
buffer[x*y*z] = 1;
}
}
}
return 0;
}
/* Declare Windows procedure */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
/* Make the class name into a global variable */
char szClassName[ ] = "CodeBlocksWindowsApp";
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nCmdShow)
{
HWND hwnd; /* This is the handle for our window */
MSG messages; /* Here messages to the application are saved */
WNDCLASSEX wincl; /* Data structure for the windowclass */
/* The Window structure */
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */
wincl.style = CS_DBLCLKS; /* Catch double-clicks */
wincl.cbSize = sizeof (WNDCLASSEX);
/* Use default icon and mouse-pointer */
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL; /* No menu */
wincl.cbClsExtra = 0; /* No extra bytes after the window class */
wincl.cbWndExtra = 0; /* structure or the window instance */
/* Use Windows's default colour as the background of the window */
wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
/* Register the window class, and if it fails quit the program */
if (!RegisterClassEx (&wincl))
return 0;
/* The class is registered, let's create the program*/
hwnd = CreateWindowEx (
0, /* Extended possibilites for variation */
szClassName, /* Classname */
" project 1 ", /* Title Text */
WS_OVERLAPPEDWINDOW, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
winx, /* The programs width */
winy, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* No menu */
hThisInstance, /* Program Instance handler */
NULL /* No Window Creation data */
);
/* Make the window visible on the screen */
ShowWindow (hwnd, nCmdShow);
/* Run the message loop. It will run until GetMessage() returns 0 */
while (GetMessage (&messages, NULL, 0, 0))
{
/* Translate virtual-key messages into character messages */
TranslateMessage(&messages);
/* Send message to WindowProcedure */
DispatchMessage(&messages);
}
/* The program return-value is 0 - The value that PostQuitMessage() gave */
return messages.wParam;
}
/* This function is called by the Windows function DispatchMessage() */
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) /* handle the messages */
{
case WM_CREATE:
{
m_bih.biWidth = winx;
m_bih.biHeight = winy;
m_bih.biBitCount = winbpp;
m_bih.biSize = sizeof(m_bih);
m_bih.biPlanes = 1; // DIBs are upside down
m_bih.biCompression = BI_BITFIELDS;
m_bih.biSizeImage = 0;
m_bih.biXPelsPerMeter = 0;
m_bih.biYPelsPerMeter = 0;
m_bih.biClrUsed = 0;
m_bih.biClrImportant = 0;
setbuffer();
InvalidateRect(hwnd, NULL, TRUE);
} break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hDC = BeginPaint(hwnd, &ps);
RECT client;
GetClientRect(hwnd, &client);
StretchDIBits ( hDC,
0, // Destination top left hand
// corner X Position
0, // Destination top left hand
// corner Y Position
client.right, // Destinations width
client.bottom, // Destinations height
0, // Source top left hand
// corner's X Position
0, // Source top left hand
// corner's Y Position
winx, // Sources width
winy, // Sources height
buffer, // Source's data
&m_bi, // Bitmap Info
DIB_RGB_COLORS, // operations
SRCCOPY);
EndPaint(hwnd, &ps);
} break;
case WM_DESTROY:
delete buffer;
PostQuitMessage (0); /* send a WM_QUIT to the message queue */
break;
default: /* for messages that we don't deal with */
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
the program compiles normally, but instead of displaying the contents of 'buffer' in the client area,
it just displays the grey color like usual.
is 'buffer' formatted correctly?
=updated code below=
#include <windows.h>
int winx = 500;
int winy = 400;
int bpp = 24;
size_t pwidth;
int scanlinewidth = 0;
int numscanlines = 0;
bool setscanline = 1;
bool setbitmap = 1;
BITMAPINFO m_bi;
struct BGR{ char blue; char green; char red;};
BGR* buffer;
void setframebuffer()
{
m_bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
m_bi.bmiHeader.biPlanes = 1;
m_bi.bmiHeader.biBitCount = bpp;
m_bi.bmiHeader.biCompression = BI_RGB;
m_bi.bmiHeader.biSizeImage = 0;
m_bi.bmiHeader.biXPelsPerMeter = 100;
m_bi.bmiHeader.biYPelsPerMeter = 100;
m_bi.bmiHeader.biClrUsed = 0;
m_bi.bmiHeader.biClrImportant = 0;
if (setbitmap)
{
m_bi.bmiHeader.biWidth = scanlinewidth;
m_bi.bmiHeader.biHeight = numscanlines;
setbitmap = 0;
}
if (!setbitmap)
{
pwidth = (scanlinewidth * 3 + 3) & ~3;
buffer = new BGR[(scanlinewidth + pwidth)*numscanlines];
}
for (int i = 0; i < ((scanlinewidth + pwidth) * numscanlines); i++)
{
buffer[i].blue = 0;
buffer[i].green = 0;
buffer[i].red = 255;
}
}
/* Declare Windows procedure */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
/* Make the class name into a global variable */
char szClassName[ ] = "CodeBlocksWindowsApp";
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nCmdShow)
{
HWND hwnd; /* This is the handle for our window */
MSG messages; /* Here messages to the application are saved */
WNDCLASSEX wincl; /* Data structure for the windowclass */
/* The Window structure */
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */
wincl.style = CS_DBLCLKS; /* Catch double-clicks */
wincl.cbSize = sizeof (WNDCLASSEX);
/* Use default icon and mouse-pointer */
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL; /* No menu */
wincl.cbClsExtra = 0; /* No extra bytes after the window class */
wincl.cbWndExtra = 0; /* structure or the window instance */
/* Use Windows's default colour as the background of the window */
wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
/* Register the window class, and if it fails quit the program */
if (!RegisterClassEx (&wincl))
return 0;
/* The class is registered, let's create the program*/
hwnd = CreateWindowEx (
0, /* Extended possibilites for variation */
szClassName, /* Classname */
"framebuffer project for win32", /* Title Text */
WS_OVERLAPPEDWINDOW, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
winx, /* The programs width */
winy, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* No menu */
hThisInstance, /* Program Instance handler */
NULL /* No Window Creation data */
);
/* Make the window visible on the screen */
ShowWindow (hwnd, nCmdShow);
/* Run the message loop. It will run until GetMessage() returns 0 */
while (GetMessage (&messages, NULL, 0, 0))
{
/* Translate virtual-key messages into character messages */
TranslateMessage(&messages);
/* Send message to WindowProcedure */
DispatchMessage(&messages);
}
/* The program return-value is 0 - The value that PostQuitMessage() gave */
return messages.wParam;
}
/* This function is called by the Windows function DispatchMessage() */
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
DWORD result;
switch (message) /* handle the messages */
{
case WM_CREATE:
{
InvalidateRect(hwnd,0,0);
}break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hDC = BeginPaint(hwnd, &ps);
RECT client;
GetClientRect(hwnd,&client);
if(setscanline) {
scanlinewidth = client.right;
numscanlines = client.bottom;
setscanline = 0;
}
setframebuffer();
result = StretchDIBits(hDC,
0, 0,
client.right, client.bottom,
0, 0,
scanlinewidth, numscanlines,
buffer, &m_bi, DIB_RGB_COLORS, SRCCOPY);
if(result != winy)
{
//Drawing failed
DebugBreak();
}
EndPaint(hwnd, &ps);
}break;
case WM_KEYDOWN:{ int escpressed = GetAsyncKeyState(27); if(escpressed){PostQuitMessage(0);}}break;
case WM_DESTROY: {
PostQuitMessage (0); /* send a WM_QUIT to the message queue */
}break;
default: /* for messages that we don't deal with */
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
EDIT changed int setbuffer to setbuffer in WM_create
EDIT #2 changed getdc to begin paint.
EDIT #3 changed the bpp to 24 and also changed the WM_Create to set all the bitmap properties
EDIT #4 I have found a solution thanks to your help. i didn't understand Scan Line padding before, but now i understand it perfectly. the updated code prints a solid color on the screen and you can compile it for yourself and change the color. thanks for helping me solve my problem, now i can start drawing on the screen using my own code.

I'm not sure all of these issues are still relevant as I copied the code before you started editing. Either way, this works and you should be able to see the differences pretty easily.
The BITMAPINFO structure was not being initialized properly.
The buffer was being created incorrectly, it was too large and not necessarily aligned properly to be used as a bitmap. The width needs to be padded to a multiple of 4 which would have been okay for a width of 500 but not for a width of 499 as an example.
I also added a check to make sure StretchDIBits was successful and it'll dump you into the debugger if it fails. You can add more appropriate error checking if you like.
I also cut some comments out just to keep things as short as possible.
#include <windows.h>
const int winx = 500;
const int winy = 500;
const int winbpp = 3;
BITMAPINFO m_bi;
char* buffer = 0;
void setbuffer()
{
m_bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
m_bi.bmiHeader.biWidth = winx;
m_bi.bmiHeader.biHeight = winy;
m_bi.bmiHeader.biPlanes = 1;
m_bi.bmiHeader.biBitCount = 24;
m_bi.bmiHeader.biCompression = BI_RGB;
m_bi.bmiHeader.biSizeImage = 0;
m_bi.bmiHeader.biXPelsPerMeter = 100;
m_bi.bmiHeader.biYPelsPerMeter = 100;
m_bi.bmiHeader.biClrUsed = 0;
m_bi.bmiHeader.biClrImportant = 0;
size_t paddedWidth = (winx * 3 + 3) & ~3;
buffer = new char[paddedWidth * winy * winbpp];
for(int y = 0; y < winy; ++y)
{
for(int x = 0; x < winx; ++x)
{
for(int z = 0; z < 3; ++z)
{
buffer[y * paddedWidth + x * winbpp + z] = z * x;
}
}
}
}
LRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM, LPARAM);
char szClassName[] = "CodeBlocksWindowsApp";
int WINAPI WinMain(HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nCmdShow)
{
HWND hwnd; /* This is the handle for our window */
MSG messages; /* Here messages to the application are saved */
WNDCLASSEX wincl; /* Data structure for the windowclass */
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */
wincl.style = CS_DBLCLKS; /* Catch double-clicks */
wincl.cbSize = sizeof (WNDCLASSEX);
wincl.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor(NULL, IDC_ARROW);
wincl.lpszMenuName = NULL; /* No menu */
wincl.cbClsExtra = 0; /* No extra bytes after the window class */
wincl.cbWndExtra = 0; /* structure or the window instance */
wincl.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
if(!RegisterClassEx(&wincl))
return 0;
hwnd = CreateWindowEx(
0, /* Extended possibilites for variation */
szClassName, /* Classname */
" project 1 ", /* Title Text */
WS_OVERLAPPEDWINDOW, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
winx, /* The programs width */
winy, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* No menu */
hThisInstance, /* Program Instance handler */
NULL /* No Window Creation data */
);
ShowWindow(hwnd, nCmdShow);
while(GetMessage(&messages, NULL, 0, 0))
{
TranslateMessage(&messages);
DispatchMessage(&messages);
}
return messages.wParam;
}
LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hDC;
RECT client;
DWORD result;
switch(message) /* handle the messages */
{
case WM_CREATE:
setbuffer();
InvalidateRect(hwnd, NULL, TRUE);
break;
case WM_PAINT:
hDC = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &client);
result = StretchDIBits(hDC,
0, 0,
client.right, client.bottom,
0, 0,
winx, winy,
buffer, &m_bi, DIB_RGB_COLORS, SRCCOPY);
if(result != winy)
{
//Drawing failed
DebugBreak();
}
EndPaint(hwnd, &ps);
break;
case WM_DESTROY:
delete buffer;
PostQuitMessage(0); /* send a WM_QUIT to the message queue */
break;
default: /* for messages that we don't deal with */
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}

Related

Effect of MoveWindow in EnumChildWindows over listview inside the Dialog Box: Why ListView Header is not correctly scrolling

I have a listview control (lvc) and it is inside a DialogBox(dbx) and that dbx also has a vertical scroll bar.
Whenever the scrollbar is scrolled EnumChildWindows is called to enumerate all the child window of the dbx. The callback function contains a MoveWindow function that would move that lvc. lvc is scrolling fine but not its column headers, they are not moving with the list view.
If i comment out the MoveWindow function inside the callback function then nothing changes. ( Off-course lvc won't move! ) that means EnumChildWindow has got no problem, but MoveWindow inside the callback function is causing problem and i am sure about this because calling MoveWindow function from outside the callback function works correctly ( because in this example there is only one control, i.e. lvc, so i don't need to enumerate all the child window ).
here is the Code:
main.cpp
#if defined(UNICODE) && !defined(_UNICODE)
#define _UNICODE
#elif defined(_UNICODE) && !defined(UNICODE)
#define UNICODE
#endif
#include <tchar.h>
#define _WIN32_IE 0x0700
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <vector>
#include "res.h"
#define btn 0
#include <iostream>
/* Declare Windows procedure */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK diaproc(HWND hwmd, UINT msg, WPARAM wp, LPARAM lp);
BOOL CALLBACK edc(HWND hwmd,LPARAM lp);
HINSTANCE gi;
int iPrevVscroll=0;
/* Make the class name into a global variable */
TCHAR szClassName[ ] = _T("CodeBlocksWindowsApp");
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nCmdShow)
{
HWND hwnd; /* This is the handle for our window */
MSG messages; /* Here messages to the application are saved */
WNDCLASSEX wincl; /* Data structure for the windowclass */
/* The Window structure */
gi = wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */
wincl.style = CS_DBLCLKS ; /* Catch double-clicks */
wincl.cbSize = sizeof (WNDCLASSEX);
/* Use default icon and mouse-pointer */
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL; /* No menu */
wincl.cbClsExtra = 0; /* No extra bytes after the window class */
wincl.cbWndExtra = 0; /* structure or the window instance */
/* Use Windows's default colour as the background of the window */
wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
/* Register the window class, and if it fails quit the program */
if (!RegisterClassEx (&wincl))
return 0;
/* The class is registered, let's create the program*/
hwnd = CreateWindowEx (
0, /* Extended possibilites for variation */
szClassName, /* Classname */
_T("Code::Blocks Template Windows App"), /* Title Text */
WS_OVERLAPPEDWINDOW, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
544, /* The programs width */
375, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* No menu */
hThisInstance, /* Program Instance handler */
NULL /* No Window Creation data */
);
/* Make the window visible on the screen */
ShowWindow (hwnd, nCmdShow);
/* Run the message loop. It will run until GetMessage() returns 0 */
while (GetMessage (&messages, NULL, 0, 0))
{
/* Translate virtual-key messages into character messages */
TranslateMessage(&messages);
/* Send message to WindowProcedure */
DispatchMessage(&messages);
}
/* The program return-value is 0 - The value that PostQuitMessage() gave */
return messages.wParam;
}
/* This function is called by the Windows function DispatchMessage() */
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) /* handle the messages */
{
case WM_CREATE:
CreateWindow(WC_BUTTON, "CLICK", WS_CHILD | BS_DEFPUSHBUTTON | WS_VISIBLE, 10, 10, 80, 30, hwnd, (HMENU)btn, gi, NULL );
break;
case WM_COMMAND:{
if( LOWORD(wParam) == btn && HIWORD(wParam) == BN_CLICKED ) DialogBox(gi, MAKEINTRESOURCE(dia), hwnd,(DLGPROC)diaproc);
DWORD err = GetLastError();
std::cout<<err<<std::endl<<dia;
}
break;
case WM_DESTROY:
PostQuitMessage (0); /* send a WM_QUIT to the message queue */
break;
default: /* for messages that we don't deal with */
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
BOOL CALLBACK diaproc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lp)
{
static HWND lv_hwnd;
static int sci;
switch(msg)
{
case WM_INITDIALOG:
{
INITCOMMONCONTROLSEX is;
is.dwSize = sizeof(INITCOMMONCONTROLSEX);
is.dwICC = ICC_LISTVIEW_CLASSES;
InitCommonControlsEx(&is);
int col_fmt[5] = { LVCFMT_CENTER, LVCFMT_LEFT, LVCFMT_CENTER, LVCFMT_CENTER, LVCFMT_CENTER };
int col_wid[5] = { 30, 90, 50, 30, 70 };
std::vector<TCHAR*> col_nam(5);
col_nam[0] = _T("S.No"); col_nam[1] = _T("Description"); col_nam[2] = _T("HSN"); col_nam[3] = _T("QTY"); col_nam[4] = _T("Rate");
lv_hwnd = CreateWindow(
WC_LISTVIEW,
_T(""),
WS_CHILD | LVS_REPORT | LVS_EDITLABELS | WS_VISIBLE,
10, 0, 300, 200,
hwnd,
NULL,
(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE),
NULL
);
ListView_SetExtendedListViewStyle(lv_hwnd, LVS_EX_FLATSB | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_LABELTIP );
LVCOLUMN lvc;
lvc.mask = LVCF_FMT | LVCF_SUBITEM | LVCF_WIDTH | LVCF_TEXT;
for(int i =0; i < 5; i++)
{
lvc.fmt = col_fmt[i];
lvc.cx = col_wid[i];
lvc.pszText = col_nam[i];
lvc.iSubItem = i;
ListView_InsertColumn(lv_hwnd, i, &lvc);
}
SetScrollRange(hwnd, SB_VERT, 0, 225, TRUE);
SetScrollPos(hwnd, SB_VERT, 0, TRUE);
} return FALSE;
case WM_VSCROLL:
{
RECT rc; GetWindowRect(lv_hwnd, &rc);
POINT pt1 = {rc.left, rc.top}; ScreenToClient(hwnd, &pt1);
POINT pt2 = {rc.right, rc.bottom}; ScreenToClient(hwnd, &pt2);
std::cout<<"rc.top : "<< rc.top<<"\nrc.bottom: "<< rc.bottom <<"\nrc.right : "<<rc.right<<"\nrc.left : "<<rc.left<<"\n\n";
std::cout<<"pt1.y : "<< pt1.y<<"\npt2.y: "<< pt2.y<<"\npt2.x : "<<pt2.x<<"\npt1.x : "<<pt1.x<<"\n\n\n";
switch(LOWORD(wParam))
{
case SB_PAGEDOWN:
case SB_LINEDOWN:
sci += 10; break;
case SB_PAGEUP:
case SB_LINEUP:
sci -= 10; break;
case SB_THUMBTRACK:
sci = HIWORD(wParam); break;
};
sci = sci < 0 ? 0 : sci > 225 ? 225 : sci;
SetScrollPos(hwnd, SB_VERT, sci, FALSE);
//MoveWindow(lv_hwnd, pt1.x, pt1.y - sci + iPrevVscroll, pt2.x - pt1.x, pt2.y - pt1.y, TRUE);
EnumChildWindows(hwnd, edc, (LPARAM)sci);
}; return TRUE;
case WM_COMMAND:
if(LOWORD(wParam) == IDCANCEL) EndDialog(hwnd, wParam); return TRUE;
default: return FALSE;
}
}
BOOL CALLBACK edc(HWND hwnd, LPARAM lp)
{
long s = (long) lp;
RECT rc; GetWindowRect(hwnd, &rc);
POINT pt1 = {rc.left, rc.top}; ScreenToClient(hwnd, &pt1);
POINT pt2 = {rc.right, rc.bottom}; ScreenToClient(hwnd, &pt2);
MoveWindow(hwnd, pt1.x, pt1.y + s - iPrevVscroll, pt2.x - pt1.x, pt2.y - pt1.y, TRUE);
}
res.h
#define lv 1
#define dia 2
res.rc
#include <windows.h>
#include <commctrl.h>
#include <richedit.h>
#include "res.h"
dia DIALOGEX 0,0,500,300
CAPTION "New Invoice"
STYLE DS_3DLOOK | DS_CENTER | DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_SYSMENU | WS_THICKFRAME | WS_VSCROLL
FONT 8, "Ms Shell Dlg"
{
}
in main.cpp you find the MoveWindow and other related functions at the bottom.
The following Images are useful.
also that the logic of scrolling in both MoveWindow is different, again, for the purpose of illustration.
Initially i was working on a project with many controls when i encountered this problem. I analysed this separately and found out what i have written above. Although I bypassed this problem through adopting a different method to scroll down all the controls(the one which do not includes calling MoveWindow from inside EnumChildWindows ), but i am curious to know the reason and the solution of this problem.
Thank you for your time on this long post. Any suggestions or improvement would also be amazing!
From the remarks section of EnumChildWindows() reference:
If a child window has created child windows of its own,
EnumChildWindows enumerates those windows as well.
So what you are doing here is scrolling the listview control and then also scroll the header control separately. The result is that the header control moves relative to the listview control as seen in your 2nd screenshot.
Instead you should only move immediate children of the dialog box, because grand children will move automatically with their parents.
Possible solutions:
Check parent/child relationship in the EnumChildWindows() callback (e. g. by calling GetParent() on the child and compare it with your dialog handle).
Instead of calling EnumChildWindows() and MoveWindow(), call ScrollWindowEx() with SW_SCROLLCHILDREN. This is the easiest way of implementing scrolling, so I would prefer this solution.

Drawing rectangle in c++ using functions

I have a problem with create drawing rectangles functions in C++. I have prepared c++ file, when I must finished drawing functions.
I need to add functionality where on mouse click it will creating rectangle, and when I finished moving mouse and released it should be rectangle. next it should be created again and changes position.
I have completely no idea how to do it. Any ideas ? Code looks like this:
MsgHandlers.cpp (here all things happen):
#include "MsgHandlers.h"
#include "Utils.h"
#include <time.h>
#include <math.h>
int ClientWidth, ClientHeight;
BOOL EraseBkgnd = TRUE;
bool IgnoreTimer = false;
RECT Rect;
void OnCreate(HWND hwnd)
{
SetTimer(hwnd, 1, 25, NULL);
}
void OnSize(HWND hwnd, int width, int height, WPARAM wParam)
{
ClientWidth = width;
ClientHeight = height;
Rect.left = width/4;
Rect.right=Rect.left + width/2;
Rect.top = height/4;
Rect.bottom= Rect.top + height/2;
}
void OnTimer(HWND hwnd, WPARAM timerID)
{
if(IgnoreTimer) return;
Rect.left+=RandRange(-10, 10);
Rect.right +=RandRange(-10,10);
Rect.top +=RandRange(-10,10);
Rect.bottom +=RandRange(-10,10);
InvalidateRect(hwnd, NULL, EraseBkgnd);
}
void OnPaint(HWND hwnd, HDC hdc)
{
Rectangle(hdc,Rect.left,Rect.top,Rect.right,Rect.bottom);
}
void OnKeyDown(HWND hwnd, WPARAM keyCode)
{
switch (keyCode)
{
case VK_LEFT:
break;
case VK_UP:
break;
case VK_RIGHT:
break;
case VK_DOWN:
break;
case 0x43: // C
break;
case 0x45: // E
EraseBkgnd ^= 0x00000001;
break;
case 0x52: // R
break;
case 0x49: // I
IgnoreTimer = !IgnoreTimer;
case 0x53: // S
break;
}
//InvalidateRect(hwnd, NULL, EraseBkgnd);
}
void OnMouseMove(HWND hwnd, int x, int y, WPARAM wParam)
{
}
void OnLButtonDown(HWND hwnd, int x, int y, WPARAM wParam)
{
}
void OnLButtonUp(HWND hwnd, int x, int y, WPARAM wParam)
{
}
void OnDestroy(HWND hwnd)
{
KillTimer(hwnd, 1);
}
I put also others files from this C++ project:
Main:
#include <windows.h>
#include "MsgHandlers.h"
/* Declare Windows procedure */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
/* Make the class name into a global variable */
char szClassName[ ] = "CodeBlocksWindowsApp";
int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow)
{
HWND hwnd; /* This is the handle for our window */
MSG message; /* Here messages to the application are saved */
WNDCLASSEX wincl; /* Data structure for the windowclass */
/* The Window structure */
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */
wincl.style = CS_DBLCLKS; /* Catch double-clicks */
wincl.cbSize = sizeof (WNDCLASSEX);
/* Use default icon and mouse-pointer */
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL; /* No menu */
wincl.cbClsExtra = 0; /* No extra bytes after the window class */
wincl.cbWndExtra = 0; /* structure or the window instance */
/* Use Windows's default colour as the background of the window */
wincl.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
/* Register the window class, and if it fails quit the program */
if (!RegisterClassEx (&wincl))
return 0;
/* The class is registered, let's create the program*/
hwnd = CreateWindowEx (
0, /* Extended possibilites for variation */
szClassName, /* Classname */
"Progr.", /* Title Text */
WS_OVERLAPPEDWINDOW, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
1024, /* The programs width */
768, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* No menu */
hThisInstance, /* Program Instance handler */
NULL /* No Window Creation data */
);
/* Make the window visible on the screen */
ShowWindow (hwnd, nCmdShow);
/* Run the message loop. It will run until GetMessage() returns 0 */
while (GetMessage(&message, NULL, 0, 0))
{
/* Translate virtual-key messages into character messages */
TranslateMessage(&message);
/* Send message to WindowProcedure */
DispatchMessage(&message);
}
/* The program return-value is 0 - The value that PostQuitMessage() gave */
return message.wParam;
}
/* This function is called by the Windows function DispatchMessage() */
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
switch (message) /* handle the messages */
{
case WM_CREATE:
OnCreate(hwnd);
break;
case WM_SIZE:
OnSize(hwnd, short(lParam & 0x0000FFFF), short(lParam >> 16), wParam);
break;
case WM_TIMER:
OnTimer(hwnd, wParam);
break;
case WM_KEYDOWN:
OnKeyDown(hwnd, wParam);
break;
case WM_LBUTTONDOWN:
OnLButtonDown(hwnd, short(lParam & 0x0000FFFF), short(lParam >> 16), wParam);
break;
case WM_MOUSEMOVE:
OnMouseMove(hwnd, short(lParam & 0x0000FFFF), short(lParam >> 16), wParam);
break;
case WM_LBUTTONUP:
OnLButtonUp(hwnd, short(lParam & 0x0000FFFF), short(lParam >> 16), wParam);
break;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
OnPaint(hwnd, hdc);
EndPaint(hwnd, &ps);
break;
case WM_DESTROY:
OnDestroy(hwnd);
PostQuitMessage (0); /* send a WM_QUIT to the message queue */
break;
default: /* for messages that we don't deal with */
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
Utils.cpp:
#include "Utils.h"
#include <math.h>
//random <min, max>
int RandRange(int min, int max)
{
return min + rand() % (1 + max - min);
}
//Return -1 for negative argument;
//return +1 for positive argument or 0
int Sign(int arg)
{
return arg < 0 ? -1 : 1;
}
double Deg2Rad(double aDegrees)
{
return aDegrees * PI / 180.0;
}
double Rad2Deg(double aRadians)
{
return aRadians * 180 / PI;
}
float DirectionFromSpeedXY(int aSpeedX, int aSpeedY)
{
if(aSpeedX==0 && aSpeedY==0)
return 0;
else
return atan2(aSpeedX, -aSpeedY);
}
float SpeedFromSpeedXY(int aSpeedX, int aSpeedY)
{
return sqrt(aSpeedX*aSpeedX + aSpeedY*aSpeedY);// * Sign(aSpeedX*aSpeedY);
}
void SpeedXYFromSpeedDirection(float aSpeed, float aDirection, int *aSpeedX, int *aSpeedY)
{
aSpeed = abs(aSpeed);
*aSpeedX = aSpeed * sin(aDirection);
*aSpeedY = -aSpeed * cos(aDirection);
}
void CorrectRect(RECT *aRect)
{
int temp;
if(aRect->right < aRect->left)
{
temp = aRect->right;
aRect->right = aRect->left;
aRect->left = temp;
}
if(aRect->bottom < aRect->top)
{
temp = aRect->bottom;
aRect->bottom = aRect->top;
aRect->top = temp;
}
}
As mentioned, the code you provided is not standard.
To accomplish the task you described there are some steps that must be handled.
How to draw a (simple) rectangle:
// x and y are the x- and y-locations of the mouse cursor upon release
void drawRectangle(HWND hwnd, const int x, const int y)
{
// obtain a handle to the device context
HDC hdc = GetDC(hwnd);
// RECT_WIDTH and RECT_HEIGHT are elsewhere defined
// draw rectangle
Rectangle(hdc, x - RECT_WIDTH / 2, y - RECT_HEIGHT / 2, x + RECT_WIDTH / 2, y + RECT_HEIGHT / 2);
// release the DC
ReleaseDC(hwnd, hdc);
}
To capture the mouse button release you process the WM_LBUTTONUP message.
In the window's window procedure:
LRESULT __stdcall wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static int x;
static int y;
HDC hdc;
PAINTSTRUCT ps;
case WM_LBUTTONUP:
{
x = LOWORD(lParam); // grab the x-position
y = HIWORD(lParam); // grab the y-position
// invalidate the entire client area
// this will cause the window's client area to be "cleared"
// using the window class background brush upon BeginPaint call
// in WM_PAINT
InvalidateRect(hwnd, NULL, true);
return 0;
}
case WM_PAINT:
{
hdc = BeginPaint(hwnd, &ps);
// draw the rectangle
drawRectangle(hwnd, x, y);
EndPaint(hwnd, &ps);
return 0;
}
// other case handlers like WM_DESTROY
}
Obviously, there are other things to take into consideration, but this should get you started.

wxDev-C++ - HtmlHelp undeclared

In my C program's menu I have a Help section.
When pressed, it should open a help file.
I used Helpinator Professional to make a simple help file.
Now, pre-history:
I tried using the WinHelp() method by including <winuser.h>. It opened the file, but it gave me an error, saying that the file is not a Windows Help file or is corrupted. Then I read that WinHelp() is outdated and I should use HtmlHelp() instead by including <htmlhelp.h>. I included it by writing the full path to it, because wxDev-C++'s directories in compiler settings are not included normally and I don't exactly know how it checks the directories.
I included in my resources.h file.
Code in switch statement:
case ID_Help:
HtmlHelp(hwnd, "file location", HH_DISPLAY_TOPIC, 0);
break;
This gives me an error, saying that it is undeclared. Then, I declared HWMD help; before the switch statement and changed code to:
case ID_Help:
help = HtmlHelp(hwnd, "file location", HH_DISPLAY_TOPIC, 0);
break;
And it still tells me that it is undeclared.
What should I do? I'm stuck. I also encountered other problems on the way, some of them mentioned above, but nevermind them for now.
Source code:
#include "resources.h"
/* Declare Windows procedure */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
/* Make the class name into a global variable */
char window_class[] = "WindowsApp";
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nFunsterStil)
{
HWND hwnd; /* This is the handle for our window */
MSG messages; /* Here messages to the application are saved */
WNDCLASSEX wincl; /* Data structure for the windowclass */
/* The Window structure */
wincl.hInstance = hThisInstance;
wincl.lpszClassName = window_class;
wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */
wincl.style = CS_DBLCLKS; /* Catch double-clicks */
wincl.cbSize = sizeof (WNDCLASSEX);
/* Use default icon and mouse-pointer */
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_HAND);
wincl.lpszMenuName = MAKEINTRESOURCE (ID_Menu); /* No menu */
wincl.cbClsExtra = 0; /* No extra bytes after the window class */
wincl.cbWndExtra = 0; /* structure or the window instance */
/* Use Windows's default color as the background of the window */
wincl.hbrBackground = (HBRUSH) (COLOR_BACKGROUND + 2);
/* Register the window class, and if it fails quit the program */
if (!RegisterClassEx (&wincl))
return 0;
/* The class is registered, let's create the program*/
hwnd = CreateWindowEx (
0, /* Extended possibilites for variation */
window_class, /* Classname */
"Slacker Tracker v0.1", /* Title Text */
WS_OVERLAPPEDWINDOW, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
600, /* The programs width */
600, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* No menu */
hThisInstance, /* Program Instance handler */
NULL /* No Window Creation data */
);
MessageBox(NULL, "Message box #1 at your service.", "MESSAGE BOX #1", 0);
/* Make the window visible on the screen */
ShowWindow (hwnd, nFunsterStil);
/* Run the message loop. It will run until GetMessage() returns 0 */
while (GetMessage (&messages, NULL, 0, 0))
{
/* Translate virtual-key messages into character messages */
TranslateMessage(&messages);
/* Send message to WindowProcedure */
DispatchMessage(&messages);
}
/* The program return-value is 0 - The value that PostQuitMessage() gave */
return messages.wParam;
}
/* This function is called by the Windows function DispatchMessage() */
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
LPCTSTR name = "D:\\winapi\\1\\help.chm";
HANDLE file;
int size;
char buffer[100];
wchar_t error[256];
HWND help;
switch (message) /* handle the messages */
{
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_File_Exit:
PostMessage(hwnd, WM_CLOSE, 0, 0);
break;
case ID_NewMsgBox:
MessageBox(NULL, "Message box #3 at your service", "MESSAGE BOX #3", 0);
break;
case ID_Help:
//WinHelp(hwnd, "D:\\winapi\\1\\help.chm", HELP_INDEX, 0);
help = HtmlHelp(hwnd, "D:\\winapi\\1\\help.chm", HH_DISPLAY_TOPIC, 0);
break;
case ID_FSize:
file = CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (file == INVALID_HANDLE_VALUE){
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), error, 255, NULL);
MessageBoxW(NULL, error, (LPCWSTR)L"file", 0);
}
else{
size = GetFileSize(file, NULL);
itoa(size, buffer, 10);
MessageBox(NULL, buffer, "File Size", MB_OK);
}
CloseHandle(file);
break;
}
break;
case WM_LBUTTONDOWN:
MessageBox(hwnd, "Message box #2 at your service", "MESSAGE BOX #2", 0);
break;
case WM_DESTROY:
PostQuitMessage (0); /* send a WM_QUIT to the message queue */
break;
default: /* for messages that we don't deal with */
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
Compile log:
main.c: In function 'WindowProcedure':
main.c:99:36: error: 'HtmlHelp' undeclared (first use in this function)
main.c:99:36: note: each undeclared identifier is reported only once for each function it appears in
You should add this line to your .cpp file.
#include "htmlhelp.h"
Then you need to assign the event to call help. (this is where I think it is stating that it is undefined)
void CTestHelpDlg::OnHelp()
{
HtmlHelp(this->m_hWnd, "HelpSample.chm", HH_DISPLAY_TOPIC, NULL);
}
Further documentation and the tutorial I used for learning this is here
http://www.codeguru.com/cpp/w-p/help/html/article.php/c6503/Starting-Out-with-HtmlHelp.htm

Why is LB_GETITEMDATA returning 0?

I'm trying to create a program that suspends and resumes processes, it creates a listbox with text strings of all the running processes on the system, but when I click the suspend button to suspend a process I try to send WM_GETITEMDATA for the currently selected item in the listbox but the value returns 0. I expected the return value to be a string with the text of the lParam of LB_ADDSTRING.
I think this has something to do with the scope of the function I use LB_ADDSTRING in because when I use LB_GETITEMDATA right after LB_ADDSTRING it properly returns the value of the lParam of LB_ADDSTRING. Since I am unsure of where my error lies I'm adding the full source code to the bottom of my question. Here is the function I use to add strings to the listbox:
void RefreshList()
{
SendMessage (hlist, LB_RESETCONTENT, 0, 0);
HANDLE hSnapShot3 = CreateToolhelp32Snapshot(TH32CS_SNAPALL, NULL);
PROCESSENTRY32 pEntry3;
pEntry3.dwSize = sizeof (pEntry3);
BOOL hRes3 = Process32First(hSnapShot3, &pEntry3);
int listitem = 0;
while (hRes3)
{
SendMessage (hlist, LB_ADDSTRING, 0, (LPARAM)pEntry3.szExeFile);
SendMessage (hlist, LB_SETITEMDATA, listitem, (LPARAM)pEntry3.szExeFile);
SendMessage(hlist, LB_GETITEMDATA, listitem, NULL);
MessageBox(0,0,0,0);
listitem++;
hRes3 = Process32Next(hSnapShot3, &pEntry3);
}
CloseHandle(hSnapShot3);
}
Here is the part of the windows procedure where I catch clicks to my context menu and try to send the message LB_GETITEMDATA:
case WM_COMMAND:
if (HIWORD(wParam) == 0 && LOWORD(wParam) == 1)
{
selection = SendMessage(hlist, LB_GETCURSEL, 0, 0);
LRESULT selectionname = SendMessage(hlist, LB_GETITEMDATA, selection, NULL);
}
here is the full code
#define _WIN32_WINNT 0x0500
#include <windows.h>
#include <process.h>
#include <Tlhelp32.h>
#include <winbase.h>
#include <string.h>
#include <stdio.h>
#include <windowsx.h>
#define list1 1
#define button1 2
int selection;
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK ProcessListProc (HWND, UINT, WPARAM, LPARAM);
char szClassName[ ] = "mainwindowclass";
HWND hlist;
HWND hwnd;
void RefreshList()
{
SendMessage (hlist, LB_RESETCONTENT, 0, 0);
HANDLE hSnapShot3 = CreateToolhelp32Snapshot(TH32CS_SNAPALL, NULL);
PROCESSENTRY32 pEntry3;
pEntry3.dwSize = sizeof (pEntry3);
BOOL hRes3 = Process32First(hSnapShot3, &pEntry3);
int listitem = 0;
while (hRes3)
{
SendMessage (hlist, LB_ADDSTRING, 0, (LPARAM)pEntry3.szExeFile);
SendMessage (hlist, LB_SETITEMDATA, listitem, (LPARAM)pEntry3.szExeFile);
SendMessage(hlist, LB_GETITEMDATA, listitem, NULL);
MessageBox(0,0,0,0);
listitem++;
hRes3 = Process32Next(hSnapShot3, &pEntry3);
}
CloseHandle(hSnapShot3);
}
int SuspendProcess(TCHAR processname)
{
int doublePID = 0;
DWORD pidtoacton;
DWORD Result;
HANDLE hSnapShot3 = CreateToolhelp32Snapshot(TH32CS_SNAPALL, NULL);
PROCESSENTRY32 pEntry3;
pEntry3.dwSize = sizeof (pEntry3);
BOOL hRes3 = Process32First(hSnapShot3, &pEntry3);
while (hRes3)
{
if (processname == pEntry3.szExeFile);
{
if (doublePID != 0)
{
MessageBox (NULL, "2 processes of the same type detected, support not yet implimented!", NULL, MB_OK);
}
pidtoacton = pEntry3.th32ProcessID;
doublePID++;
}
hRes3 = Process32Next(hSnapShot3, &pEntry3);
}
HANDLE tsnap = CreateToolhelp32Snapshot (TH32CS_SNAPTHREAD, 0);
THREADENTRY32 tentry;
tentry.dwSize = sizeof (tentry);
BOOL CRec = Thread32First(tsnap, &tentry);
while (CRec)
{
if (tentry.th32OwnerProcessID == pidtoacton)
{
HANDLE handletoacton = OpenThread(2, 0, tentry.th32ThreadID);
Result = SuspendThread(handletoacton);
if (Result == -1)
{
MessageBox (NULL, "An unknown error has occured when attempting to suspend a thread in the process", NULL, MB_OK);
}
}
CRec = Thread32Next(tsnap, &tentry);
}
CloseHandle(tsnap);
}
MSG messages;
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nCmdShow)
{
/* Here messages to the application are saved */
WNDCLASSEX wincl; /* Data structure for the windowclass */
MSG messages2;
/* The Window structure */
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */
wincl.style = CS_DBLCLKS; /* Catch double-clicks */
wincl.cbSize = sizeof (WNDCLASSEX);
/* Use default icon and mouse-pointer */
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL; /* No menu */
wincl.cbClsExtra = 0; /* No extra bytes after the window class */
wincl.cbWndExtra = 0; /* structure or the window instance */
/* Use Windows's default colour as the background of the window */
wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
/* Register the window class, and if it fails quit the program */
if (!RegisterClassEx (&wincl))
return 0;
/* Register the window class, and if it fails quit the program */
/* The class is registered, let's create the program*/
hwnd = CreateWindowEx (
0, /* Extended possibilites for variation */
szClassName, /* Classname */
"Process suspender", /* Title Text */
WS_OVERLAPPEDWINDOW, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
350, /* The programs width */
650, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* No menu */
hThisInstance, /* Program Instance handler */
NULL /* No Window Creation data */
);
hlist = CreateWindowEx (0,TEXT("listbox"),NULL,WS_CHILD|WS_VISIBLE|LBS_NOTIFY|LBS_STANDARD|LBS_HASSTRINGS,10,15,320,500,hwnd,(HMENU)list1,NULL,NULL);
RefreshList();
HWND hWndButton = CreateWindowEx(NULL,
TEXT("button"),
TEXT("refresh"),
WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
130,
535,
80,
30,
hwnd,
(HMENU)button1,
NULL,
NULL);
/* Make the window visible on the screen */
ShowWindow (hwnd, nCmdShow);
/* Run the message loop. It will run until GetMessage() returns 0 */
while (GetMessage (&messages, NULL, 0, 0))
{
/* Translate virtual-key messages into character messages */
TranslateMessage(&messages);
/* Send message to WindowProcedure */
DispatchMessage(&messages);
}
/* The program return-value is 0 - The value that PostQuitMessage() gave */
return messages.wParam;
}
/* This function is called by the Windows function DispatchMessage() */
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) /* handle the messages */
{
case WM_CONTEXTMENU:
{
if ((HWND)wParam == hlist)
{
INPUT clickin;
clickin.type = 0;
clickin.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
clickin.mi.dx = 0;
clickin.mi.dy = 0;
clickin.mi.mouseData = 0;
clickin.mi.time = 0;
clickin.mi.dwExtraInfo = 0;
SendInput(1,&clickin,sizeof(clickin));
clickin.mi.dwFlags = MOUSEEVENTF_LEFTUP;
SendInput(1,&clickin,sizeof(clickin));
GetMessage (&messages, NULL, 0, 0);
TranslateMessage(&messages);
DispatchMessage(&messages);
int xPos = GET_X_LPARAM(lParam);
int yPos = GET_Y_LPARAM(lParam);
HMENU rightclickmenu = CreatePopupMenu();
InsertMenu(rightclickmenu, 1, MF_BYCOMMAND | MF_STRING | MF_ENABLED, 1, "Suspend");
InsertMenu(rightclickmenu, 0, MF_BYCOMMAND | MF_STRING | MF_ENABLED, 0, "Resume");
TrackPopupMenu(rightclickmenu, TPM_TOPALIGN | TPM_LEFTALIGN, xPos, yPos, 0, hwnd, NULL);
}
break;
}
case WM_DESTROY:
PostQuitMessage (0); /* send a WM_QUIT to the message queue */
break;
case WM_COMMAND:
if (HIWORD(wParam) == 0 && LOWORD(wParam) == 1)
{
selection = SendMessage(hlist, LB_GETCURSEL, 0, 0);
LRESULT selectionname = SendMessage(hlist, LB_GETITEMDATA, selection, NULL);
}
switch (wParam)
{
case button1:
RefreshList();
break;
}
default:
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
As #JonathanPotter mentions in his comment, you need to use LB_GETTEXT to retrieve the text of an item.
If you were going to use LB_SETITEMDATA to store, say, the process-id for each item, it is good practice to always use the index returned by the LB_ADDSTRING and not assume that the index will always increment by one, this will work for sorted and unsorted list boxes:
listitem = SendMessage(hlist, LB_ADDSTRING, 0, (LPARAM)pEntry3.szExeFile);
SendMessage(hlist, LB_SETITEMDATA, listitem, (LPARAM)pEntry3.th32ProcessID);

Windows message pump in infinite loop

I've been making a Window class for a game, and I'm having trouble with the message pump.
I pull events off the Windows-provided message queue and send them to the windows they pertain to. Here's the function that Translates and Dispatches.
From what I remember of Win32 programming, Translating and Dispatching a message calls the specified WindowProc with the message's contents for parameters. So here's the WindowProc I specified...
currWin, currhwnd and winMap are defined as variables local to Window.cpp, at the top...
Anyway, calling distributeSystemMessages() seems to cause an infinite loop.
IMPORTANT NOTE: THE GAME LOOP IS NOT INSIDE THE MESSAGE HANDLING LOOP, AND NEITHER IS THE MESSAGE HANDLING CODE. THE MESSAGE HANDLING LOOP SHOULD EMPTY THE MESSAGE QUEUE ONCE PER FRAME, SENDING EACH MESSAGE TO THE WINDOW IT PERTAINS TO.
Here's Window.h...
#ifndef WINDOW_H_INCLUDED
#define WINDOW_H_INCLUDED
#include "SystemMessage.h"
#include <queue>
#include <windows.h>
using namespace std;
///THIS FUNCTION MUST BE CALLED TO GET MESSAGES INTO WINDOW QUEUES
void distributeSystemMessages();
class Window
{
protected:
HDC hDC;
HWND hWnd;
HINSTANCE hInst;
HGLRC hRC;
public:
queue<SystemMessage> messages;
Window(unsigned int width, unsigned int height, const char* name, unsigned int colorBits = 24, unsigned int depthBits = 24, unsigned int stencilBits = 0);
~Window();
void makeContextCurrent();
void swapBuffers();
unsigned int getHeight();
unsigned int getWidth();
int getMouseX();
int getMouseY();
void setSize(unsigned int width, unsigned int height);
};
#endif // WINDOW_H_INCLUDED
Here's Window.cpp...
#include "Window.h"
#include <map>
#include <cstdio>
#include <GLee.h>
#include <GL/gl.h>
#include <GL/glu.h>
using namespace std;
HWND currhwnd;
Window* currWin;
map<HWND, Window*> winMap = map<HWND, Window*>();
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if(currhwnd != hwnd)
{
map<HWND, Window*>::iterator i = winMap.find(hwnd);
if(i != winMap.end())
{
currWin = (*i).second;
currhwnd = hwnd;
}
else return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
SystemMessage msg(hwnd, uMsg, wParam, lParam);
currWin->messages.push(msg);
return 0;
}
Window::Window(unsigned int width, unsigned int height, const char* name, unsigned int colorBits, unsigned int depthBits, unsigned int stencilBits)
{
//TODO: ADD TIME FUNCTIONS TO A TIMER CLASS
//QueryPerformanceCounter(&startTime);
//lastTime = startTime;
messages = queue<SystemMessage>();
hInst = GetModuleHandle(NULL);
WNDCLASSEX wincl; /* Data structure for the windowclass */
/* The Window structure */
wincl.hInstance = hInst;
wincl.lpszClassName = "Squirrel Engine Window";
wincl.lpfnWndProc = MainWndProc; /* This function is called by windows */
wincl.style = CS_DBLCLKS; /* Catch double-clicks */
wincl.cbSize = sizeof (WNDCLASSEX);
/* Use default icon and mouse-pointer */
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL; /* No menu */
wincl.cbClsExtra = 0; /* No extra bytes after the window class */
wincl.cbWndExtra = 0; /* structure or the window instance */
/* Use Windows's default colour as the background of the window */
wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
/* Register the window class, and if it fails quit the program */
if (!RegisterClassEx (&wincl))
{
printf("Could not register window class.\n");
return;
}
/* The class is registered, let's create the program*/
hWnd = CreateWindowEx (
0, /* Extended possibilites for variation */
"Squirrel Engine Window",/* Classname */
name, /* Title Text */
WS_OVERLAPPEDWINDOW, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends after on the screen */
10, /* The programs width */
10, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* No menu */
hInst, /* Program Instance handler */
NULL /* No Window Creation data */
);
RECT rcWindow;
RECT rcClient;
GetWindowRect(hWnd, &rcWindow);
GetClientRect(hWnd, &rcClient);
POINT ptDiff;
ptDiff.x = (rcWindow.right - rcWindow.left) - rcClient.right;
ptDiff.y = (rcWindow.bottom - rcWindow.top) - rcClient.bottom;
MoveWindow(hWnd,rcWindow.left, rcWindow.top, width + ptDiff.x, height + ptDiff.y, TRUE);
ShowWindow (hWnd, SW_SHOW);
hDC = GetDC( hWnd );
PIXELFORMATDESCRIPTOR pfd;
ZeroMemory( &pfd, sizeof( pfd ) );
pfd.nSize = sizeof( pfd );
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL |
PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = colorBits;
pfd.cDepthBits = depthBits;
pfd.cStencilBits = stencilBits;
pfd.iLayerType = PFD_MAIN_PLANE;
int iFormat = ChoosePixelFormat( hDC, &pfd );
SetPixelFormat( hDC, iFormat, &pfd );
hRC = wglCreateContext(hDC);
hDC = hDC;
//makeContextCurrent();
winMap[hWnd] = this;
//TODO: Find out what this function does
wglSwapIntervalEXT(0);
}
Window::~Window()
{
wglDeleteContext(hRC);
ReleaseDC(hWnd, hDC);
winMap.erase(hWnd);
PostQuitMessage(0);
}
unsigned int Window::getWidth()
{
RECT rcClient;
GetClientRect(hWnd, &rcClient);
return rcClient.right;
}
unsigned int Window::getHeight()
{
RECT rcClient;
GetClientRect(hWnd, &rcClient);
return rcClient.bottom;
}
void Window::setSize(unsigned int width, unsigned int height)
{
RECT rcWindow;
RECT rcClient;
GetWindowRect(hWnd, &rcWindow);
GetClientRect(hWnd, &rcClient);
POINT ptDiff;
ptDiff.x = (rcWindow.right - rcWindow.left) - rcClient.right;
ptDiff.y = (rcWindow.bottom - rcWindow.top) - rcClient.bottom;
MoveWindow(hWnd,rcWindow.left, rcWindow.top, width + ptDiff.x, height + ptDiff.y, TRUE);
}
void Window::makeContextCurrent()
{
wglMakeCurrent( hDC, hRC );
}
void Window::swapBuffers()
{
SwapBuffers( hDC );
}
int Window::getMouseX()
{
POINT p;
GetCursorPos(&p);
RECT rcWindow;
RECT rcClient;
GetWindowRect(hWnd, &rcWindow);
GetClientRect(hWnd, &rcClient);
POINT ptDiff;
ptDiff.x = (rcWindow.right - rcWindow.left) - rcClient.right;
ptDiff.y = (rcWindow.bottom - rcWindow.top) - rcClient.bottom;
return p.x - (rcWindow.left + ptDiff.x);
}
int Window::getMouseY()
{
POINT p;
GetCursorPos(&p);
RECT rcWindow;
RECT rcClient;
GetWindowRect(hWnd, &rcWindow);
GetClientRect(hWnd, &rcClient);
POINT ptDiff;
ptDiff.x = (rcWindow.right - rcWindow.left) - rcClient.right;
ptDiff.y = (rcWindow.bottom - rcWindow.top) - rcClient.bottom;
return p.y - (rcWindow.top + ptDiff.y);
}
void distributeSystemMessages()
{
MSG messages;
while(PeekMessage (&messages, NULL, 0, 0, PM_REMOVE))
{
printf("MessageLoop\n");
TranslateMessage(&messages);
DispatchMessage(&messages);
}
}
Typically, you use an object architecture. Windows provides access to space local to each hWnd that is explicitly reserved for your use for basically this exact purpose. You don't need any global variables to make this work.
class Window {
// Can be virtual if necessary
LRESULT WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
// Process the message here
}
static LRESULT WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
if (Window* ptr = reinterpret_cast<Window*>(GetWindowLongPtr(hwnd, GWLP_USERDATA))) {
return ptr->WindowProc(hwnd, uMsg, wParam, lParam);
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
HWND hwnd;
public:
Window() {
hwnd = CreateWindowEx(....);
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
ShowWindow(...); // update the ptr
}
void ProcessMessages() {
MSG messages;
while(PeekMessage (&messages, hwnd, 0, 0, PM_REMOVE))
{
printf("MessageLoop\n");
TranslateMessage(&messages);
DispatchMessage(&messages);
}
}
};