How can I remove text after clicking? - c

I'm making the prototype for my own visual novel game engine.
while (i < 5)
{
switch (iMessage)
{
case WM_LBUTTONDOWN:
{
//InvalidateRect(hWnd, NULL, TRUE);
HDC hdc;
hdc = GetDC(hWnd);
_wsetlocale(LC_ALL, L"Korean");
ReadScn(buf);
//MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, char, strlen(buf), buf3, 256);
CharToWChar(buf, buf2);
TextOut(hdc, 320, 300, buf2, lstrlen(buf2)); //읽어들여서 출력함.
//TCHAR*str = TEXT("beautiful korea");
//TextOut(hdc, 320, 240, str, lstrlen(str));
ReleaseDC(hWnd, hdc);
i++;
return 0;
}
}
I wrote 5 lines of text to scn.txt. Then the program prints the texts to a window, but the text lines are overlapped.
How can I remove the previous text after clicking and print new text line?

The correct way to handle this is to NOT draw anything on the window from inside of the WM_LBUTTONDOWN message handler at all. That logic belongs in the WM_PAINT message handler instead. Have the WM_LBUTTONDOWN handler save the current line of text to a variable and then InvalidateRect() the window to trigger a repaint. The WM_PAINT handler can then draw the current line whenever the window needs to be painted (which can happen more than once between button clicks).
Try this:
case WM_LBUTTONDOWN:
{
_wsetlocale(LC_ALL, L"Korean");
ReadScn(buf); //read text from scn.txt and keep it in buf line by line.
CharToWChar(buf, buf2); //convert char into wChar.
InvalidateRect(hwnd, NULL, TRUE); //trigger a repaint
return 0;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
TextOut(hdc, 320, 300, buf2, lstrlen(buf2));
EndPaint(hwnd, &ps);
return 0;
}

Related

Why is window creation slow for many windows? Can it be faster?

For an experiment I want to create lots of small windows. I mean a lot, like a thousand or so.
The windows are small, containing some labels only (AB):
I created a hundred of them as an experiment, but their display is not instantaneous, it is visible as they are put on the screen. Why is that?
I expected for a C/C++ program to be very fast, so that I don't see the windows put on the screen at all. Is it a wrong expectation? Or should I use some kind of lighter window type (I'm no Windows-programmer, so I'm just guessing) which can be put up much faster?
Here's the relevant part of the code:
HWND parent = 0;
for (int i = 0; i < 100; ++i)
{
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_BORDER,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
if (parent == 0)
parent = hWnd;
else
SetWindowLong(hWnd, GWL_HWNDPARENT, (long)parent);
SetWindowLong(hWnd, GWL_STYLE, 0);
SetMenu(hWnd, NULL);
SetWindowPos(hWnd, HWND_TOP, 100 + (i * 20), 100, 20, 20, 0);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
}
...
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
SetBkColor(hdc, RGB(0,255,0));
TextOut(hdc, 1, 1, TEXT("AB"), strlen("AB"));
EndPaint(hWnd, &ps);
}
break;
SetWindowLong, SetMenu, SetWindowPos and ShowWindow can all be removed by giving the same information in the CreateWindowW arguments.
Then you can also remove the call to UpdateWindow.
Here its not the speed of C/C++ that matter, but the Win32 API calls which send windows messages.

Puzzle about the fourth parameter of "ScrollWindow" API function in Windows Programming

My code is shown below. When the program is running, I click the right mouse button first, then I click the left mouse button. The result is shown as in the first picture. According to the help document of ScrollWindow function, if the fourth parameter is NULL, the entire client area should be scrolled. Why is there a 10 pixels gap at x = 30 device units?
I'm wondering why the result is not shown like the second picture.
#include <windows.h>
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("HelloWin") ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, // window class name
TEXT ("The Hello Program"), // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
CW_USEDEFAULT, // initial x size
CW_USEDEFAULT, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL) ; // creation parameters
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc ;
PAINTSTRUCT ps ;
RECT rect;
switch (message)
{
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_LBUTTONDOWN:
hdc = GetDC(hwnd);
SetRect(&rect, 30, 0, 70, 100);
ScrollWindow(hwnd, 10, 0, NULL, &rect);
UpdateWindow(hwnd);
ReleaseDC(hwnd, hdc);
return 0;
case WM_RBUTTONDOWN:
hdc = GetDC(hwnd);
Ellipse(hdc, 0, 0, 100, 100);
ReleaseDC(hwnd, hdc);
return 0;
case WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
if the fourth parameter is NULL, the entire client area should be scrolled.
You also specify a clipping rectangle (the 5th parameter), so of course not the entire client area will be scrolled. But actually that's not relevant for the problem.
Why is there a 10 pixels gap at x = 30 device units?
Because you don't paint that gap when Windows tells you to do so.
From MSDN:
The area uncovered by ScrollWindow is not repainted, but it is combined into the window's update region. The application eventually receives a WM_PAINT message notifying it that the region must be repainted.
Your WM_PAINT handler does ... nothing except lying to Windows by validating the update region.
Fix your code by doing all the painting only in WM_PAINT. When you scroll in WM_LBUTTONDOWN you will also have to increment a variable that stores the scroll position. Add the scroll position to the coordinates you pass to Ellipse() in WM_PAINT. Now you should get a result like the 2nd picture.
I suggest to find a good tutorial on Win32 painting in general as some basic knowledge seems to be missing here. Get an understanding about what the "update region" is and how it interacts with the paint cycle.

Win32 - How Do I Intercept and Process Keyboard Input?

I am trying to create a simple program I can use to wrap console software. I have a basic window with an EDIT component. I know I can use WM_KEYUP and others to intercept keyborad input. I can't seem to discover an effective way to convert any of the parameters of CALLBACK WinProc; whereupon I will be able to complete this portion of my program:
#include <windows.h>
#define IDC_MAIN_EDIT 101
#define WIDTH 800
#define HEIGHT 600
LRESULT CALLBACK WinProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR lpCmdLine,int nShowCmd) {
WNDCLASSEX wClass;
ZeroMemory(&wClass,sizeof(WNDCLASSEX));
wClass.cbSize=sizeof(WNDCLASSEX);
wClass.hbrBackground=(HBRUSH)COLOR_WINDOW;
wClass.hCursor=LoadCursor(NULL,IDC_ARROW);
wClass.hIcon=NULL;
wClass.hIconSm=NULL;
wClass.hInstance=hInst;
wClass.lpfnWndProc=(WNDPROC)WinProc;
wClass.lpszClassName="Window Class";
wClass.lpszMenuName=NULL;
wClass.style=CS_HREDRAW|CS_VREDRAW;
if(!RegisterClassEx(&wClass)) {
int nResult=GetLastError();
MessageBox(NULL,
"Window class creation failed",
"Window Class Failed",
MB_ICONERROR);
}
HWND hWnd=CreateWindowEx(0,
"Window Class",
"Windows application",
WS_OVERLAPPEDWINDOW,
200,
200,
640,
480,
NULL,
NULL,
hInst,
NULL);
if(!hWnd) {
int nResult=GetLastError();
MessageBox(NULL,
"Window creation failed",
"Window Creation Failed",
MB_ICONERROR);
}
ShowWindow(hWnd,nShowCmd);
MSG msg;
ZeroMemory(&msg,sizeof(MSG));
while(GetMessage(&msg,NULL,0,0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WinProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam) {
static HWND hEdit;
switch(msg) {
case WM_DESTROY:
PostQuitMessage(0);
return 0;
break;
case WM_CREATE:
hEdit = CreateWindowEx(WS_EX_CLIENTEDGE,
"EDIT",
"",
WS_CHILD|WS_VISIBLE|ES_MULTILINE|WS_VISIBLE|WS_VSCROLL|ES_MULTILINE,
0,
0,
WIDTH,
HEIGHT,
hWnd,
(HMENU)IDC_MAIN_EDIT,
GetModuleHandle(NULL),
NULL);
HFONT hFont = CreateFont(0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, TEXT("Courier New"));
SendMessage(hEdit, WM_SETFONT, (WPARAM)hFont, 0);
SendMessage(hEdit,
WM_SETTEXT,
0,
(LPARAM)"Insert text here...");
break;
case WM_SIZE:
MoveWindow(hEdit, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
break;
}
return DefWindowProc(hWnd,msg,wParam,lParam);
}
What I should have said is: I can't seem to discover a way to intercept keyboard input as chars. How can I intercept all normal keyboard input?
To answer your question:
What I should have said is: I can't seem to discover a way to
intercept keyboard input as chars. How can I intercept all normal
keyboard input?
Take a look at this example from Microsoft on how to handle the WM_CHAR message to get the keyboard character input:
Using Keyboard Input
https://msdn.microsoft.com/en-us/library/windows/desktop/ms646268(v=vs.85).aspx
#define BUFSIZE 65535
#define SHIFTED 0x8000
LONG APIENTRY MainWndProc(HWND hwndMain, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HDC hdc; // handle to device context
TEXTMETRIC tm; // structure for text metrics
static DWORD dwCharX; // average width of characters
static DWORD dwCharY; // height of characters
static DWORD dwClientX; // width of client area
static DWORD dwClientY; // height of client area
static DWORD dwLineLen; // line length
static DWORD dwLines; // text lines in client area
static int nCaretPosX = 0; // horizontal position of caret
static int nCaretPosY = 0; // vertical position of caret
static int nCharWidth = 0; // width of a character
static int cch = 0; // characters in buffer
static int nCurChar = 0; // index of current character
static PTCHAR pchInputBuf; // input buffer
int i, j; // loop counters
int cCR = 0; // count of carriage returns
int nCRIndex = 0; // index of last carriage return
int nVirtKey; // virtual-key code
TCHAR szBuf[128]; // temporary buffer
TCHAR ch; // current character
PAINTSTRUCT ps; // required by BeginPaint
RECT rc; // output rectangle for DrawText
SIZE sz; // string dimensions
COLORREF crPrevText; // previous text color
COLORREF crPrevBk; // previous background color
size_t * pcch;
HRESULT hResult;
switch (uMsg)
{
case WM_CREATE:
// Get the metrics of the current font.
hdc = GetDC(hwndMain);
GetTextMetrics(hdc, &tm);
ReleaseDC(hwndMain, hdc);
// Save the average character width and height.
dwCharX = tm.tmAveCharWidth;
dwCharY = tm.tmHeight;
// Allocate a buffer to store keyboard input.
pchInputBuf = (LPTSTR) GlobalAlloc(GPTR,
BUFSIZE * sizeof(TCHAR));
return 0;
case WM_SIZE:
// Save the new width and height of the client area.
dwClientX = LOWORD(lParam);
dwClientY = HIWORD(lParam);
// Calculate the maximum width of a line and the
// maximum number of lines in the client area.
dwLineLen = dwClientX - dwCharX;
dwLines = dwClientY / dwCharY;
break;
case WM_SETFOCUS:
// Create, position, and display the caret when the
// window receives the keyboard focus.
CreateCaret(hwndMain, (HBITMAP) 1, 0, dwCharY);
SetCaretPos(nCaretPosX, nCaretPosY * dwCharY);
ShowCaret(hwndMain);
break;
case WM_KILLFOCUS:
// Hide and destroy the caret when the window loses the
// keyboard focus.
HideCaret(hwndMain);
DestroyCaret();
break;
case WM_CHAR:
// check if current location is close enough to the
// end of the buffer that a buffer overflow may
// occur. If so, add null and display contents.
if (cch > BUFSIZE-5)
{
pchInputBuf[cch] = 0x00;
SendMessage(hwndMain, WM_PAINT, 0, 0);
}
switch (wParam)
{
case 0x08: // backspace
case 0x0A: // linefeed
case 0x1B: // escape
MessageBeep((UINT) -1);
return 0;
case 0x09: // tab
// Convert tabs to four consecutive spaces.
for (i = 0; i < 4; i++)
SendMessage(hwndMain, WM_CHAR, 0x20, 0);
return 0;
case 0x0D: // carriage return
// Record the carriage return and position the
// caret at the beginning of the new line.
pchInputBuf[cch++] = 0x0D;
nCaretPosX = 0;
nCaretPosY += 1;
break;
default: // displayable character
ch = (TCHAR) wParam;
HideCaret(hwndMain);
// Retrieve the character's width and output
// the character.
hdc = GetDC(hwndMain);
GetCharWidth32(hdc, (UINT) wParam, (UINT) wParam,
&nCharWidth);
TextOut(hdc, nCaretPosX, nCaretPosY * dwCharY,
&ch, 1);
ReleaseDC(hwndMain, hdc);
// Store the character in the buffer.
pchInputBuf[cch++] = ch;
// Calculate the new horizontal position of the
// caret. If the position exceeds the maximum,
// insert a carriage return and move the caret
// to the beginning of the next line.
nCaretPosX += nCharWidth;
if ((DWORD) nCaretPosX > dwLineLen)
{
nCaretPosX = 0;
pchInputBuf[cch++] = 0x0D;
++nCaretPosY;
}
nCurChar = cch;
ShowCaret(hwndMain);
break;
}
SetCaretPos(nCaretPosX, nCaretPosY * dwCharY);
break;
case WM_KEYDOWN:
switch (wParam)
{
case VK_LEFT: // LEFT ARROW
// The caret can move only to the beginning of
// the current line.
if (nCaretPosX > 0)
{
HideCaret(hwndMain);
// Retrieve the character to the left of
// the caret, calculate the character's
// width, then subtract the width from the
// current horizontal position of the caret
// to obtain the new position.
ch = pchInputBuf[--nCurChar];
hdc = GetDC(hwndMain);
GetCharWidth32(hdc, ch, ch, &nCharWidth);
ReleaseDC(hwndMain, hdc);
nCaretPosX = max(nCaretPosX - nCharWidth,
0);
ShowCaret(hwndMain);
}
break;
case VK_RIGHT: // RIGHT ARROW
// Caret moves to the right or, when a carriage
// return is encountered, to the beginning of
// the next line.
if (nCurChar < cch)
{
HideCaret(hwndMain);
// Retrieve the character to the right of
// the caret. If it's a carriage return,
// position the caret at the beginning of
// the next line.
ch = pchInputBuf[nCurChar];
if (ch == 0x0D)
{
nCaretPosX = 0;
nCaretPosY++;
}
// If the character isn't a carriage
// return, check to see whether the SHIFT
// key is down. If it is, invert the text
// colors and output the character.
else
{
hdc = GetDC(hwndMain);
nVirtKey = GetKeyState(VK_SHIFT);
if (nVirtKey & SHIFTED)
{
crPrevText = SetTextColor(hdc,
RGB(255, 255, 255));
crPrevBk = SetBkColor(hdc,
RGB(0,0,0));
TextOut(hdc, nCaretPosX,
nCaretPosY * dwCharY,
&ch, 1);
SetTextColor(hdc, crPrevText);
SetBkColor(hdc, crPrevBk);
}
// Get the width of the character and
// calculate the new horizontal
// position of the caret.
GetCharWidth32(hdc, ch, ch, &nCharWidth);
ReleaseDC(hwndMain, hdc);
nCaretPosX = nCaretPosX + nCharWidth;
}
nCurChar++;
ShowCaret(hwndMain);
break;
}
break;
case VK_UP: // UP ARROW
case VK_DOWN: // DOWN ARROW
MessageBeep((UINT) -1);
return 0;
case VK_HOME: // HOME
// Set the caret's position to the upper left
// corner of the client area.
nCaretPosX = nCaretPosY = 0;
nCurChar = 0;
break;
case VK_END: // END
// Move the caret to the end of the text.
for (i=0; i < cch; i++)
{
// Count the carriage returns and save the
// index of the last one.
if (pchInputBuf[i] == 0x0D)
{
cCR++;
nCRIndex = i + 1;
}
}
nCaretPosY = cCR;
// Copy all text between the last carriage
// return and the end of the keyboard input
// buffer to a temporary buffer.
for (i = nCRIndex, j = 0; i < cch; i++, j++)
szBuf[j] = pchInputBuf[i];
szBuf[j] = TEXT('\0');
// Retrieve the text extent and use it
// to set the horizontal position of the
// caret.
hdc = GetDC(hwndMain);
hResult = StringCchLength(szBuf, 128, pcch);
if (FAILED(hResult))
{
// TODO: write error handler
}
GetTextExtentPoint32(hdc, szBuf, *pcch,
&sz);
nCaretPosX = sz.cx;
ReleaseDC(hwndMain, hdc);
nCurChar = cch;
break;
default:
break;
}
SetCaretPos(nCaretPosX, nCaretPosY * dwCharY);
break;
case WM_PAINT:
if (cch == 0) // nothing in input buffer
break;
hdc = BeginPaint(hwndMain, &ps);
HideCaret(hwndMain);
// Set the clipping rectangle, and then draw the text
// into it.
SetRect(&rc, 0, 0, dwLineLen, dwClientY);
DrawText(hdc, pchInputBuf, -1, &rc, DT_LEFT);
ShowCaret(hwndMain);
EndPaint(hwndMain, &ps);
break;
// Process other messages.
case WM_DESTROY:
PostQuitMessage(0);
// Free the input buffer.
GlobalFree((HGLOBAL) pchInputBuf);
UnregisterHotKey(hwndMain, 0xAAAA);
break;
default:
return DefWindowProc(hwndMain, uMsg, wParam, lParam);
}
return NULL;
}

WIN32 C Properly using SetWindowLongPtr and GetWindowLongPtr

Yes this is a homework assignment and I'm completely stumped.
So I've made a struct and two windows:
typedef struct thingy {
int count;
TCHAR* MSG;
COLORREF colour; };
The windows have:
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = sizeof(thingy*);
wndclass.cbWndExtra = sizeof(thingy*);
I need one window to display 0 and the next to display 1 using this struct stored in the clsextra using SetWindowLongPtr and GetWindowLongPtr/SetClassLongPtr and GetClassLongPtr
Count of course has to be initialized to 0 for the FIRST window but not for the second and I have no idea how to do this. Only one WndProc can be used to do this.
static thingy* mythingy = (thingy*)GetWindowLongPtr(hwnd, 0);
char buf[128];
int num = GetClassLongPtr(hwnd, 0);
static boolean set = false;
case WM_CREATE:
if (!set) {
mythingy = (thingy*)malloc(sizeof(thingy));
mythingy->count = 0;
mythingy->colour = RGB(0, 0, 0);
mythingy->MSG = TEXT("Hello Windows!");
set = true;
}
if (lParam != NULL) {
SetClassLongPtr(hwnd, 0, (LONG)mythingy->count);
}
mythingy->count++;
SetWindowLongPtr(hwnd, 0, (LONG)mythingy);
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rect);
DrawText(hdc, mythingy->MSG, -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
sprintf_s(buf, "%d", num);
TextOut(hdc, 0, 0, LPCWSTR(buf), 1);
EndPaint(hwnd, &ps);
return 0;
Right now both windows display 1 and I'm struggling to see why it isn't doing what I want as I can't find anything on Google about how to use these two functions or when I need to be calling them.
Window: 0x000a0528
count = 0
Add to class data
Window: 0x001f099a
count = 1
Add to class data
From the paint method I get the data and both of them are 1.
A Window Class
... is a set of attributes that the system uses as a template to create a window. Every window is a member of a window class.
Since the Windows API is exposed as a flat C interface, there is no inheritance at the language level. The phrase "is a member of" is implemented by sharing the class memory across window instances of that class. Consequently, every call to GetClassLongPtr accesses the same shared memory.
In contrast, each window can reserve cbWndExtra bytes of memory, that are attributed to the specific window instance. This memory is private to each window, and can store per-window data.
To implement your requirements you need to store the common information (current count of windows) in the window class' extra memory (cbClsExtra), and keep the per-window data (index, message, and color) in the window instance's extra memory (cbWndExtra).
Apply the following changes to your code:
// Total count of windows stored as an integer:
wndclass.cbClsExtra = sizeof(int);
In the WM_CREATE-handler, set the per-window data, increment the total count, and store it away:
case WM_CREATE:
{
int count = (int)GetClassLongPtr(hwnd, 0);
// Allocate new per-window data object:
thingy* mythingy = (thingy*)malloc(sizeof(thingy));
mythingy->count = count;
mythingy->colour = RGB(0, 0, 0);
mythingy->MSG = TEXT("Hello Windows!");
// Store the per-window data:
SetWindowLongPtr(hwnd, 0, (LONG_PTR)mythingy);
// Increment total count and store it in the class extra memory:
++count;
SetClassLongPtr(hwnd, 0, (LONG_PTR)count);
}
return DefWindowProc(hwnd, msg, wParam, lParam);
In the WM_PAINT-handler, access the per-window data:
case WM_PAINT:
{
PAINTSTRUCT ps;
hdc = BeginPaint(hwnd, &ps);
RECT rect;
GetClientRect(hwnd, &rect);
// Retrieve per-window data:
thingy* mythingy = (thingy*)GetWindowLongPtr(hwnd, 0);
DrawText(hdc, mythingy->MSG, -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
char buf[128];
sprintf_s(buf, "%d", mythingy->count);
TextOutA(hdc, 0, 0, buf, 1);
EndPaint(hwnd, &ps);
return 0;
}
Note: All error handling has been elided for brevity. Character-encoding issues have not really been addressed either (char vs. wchar_t). Likewise, resource management is missing. You'd probably want to deallocate memory in a WM_NCDESTROY-handler. The code assumes, that only windows of a single window class are created.

c - win32 api rectangle is not drawn if hdc passed to method

I have been playing with C and win32 recently and the following has me balked:
case WM_PAINT:
g_crntRect = (RECT*) malloc(sizeof(RECT));
GetWindowRect(hwnd, g_crntRect);
hpen = CreatePen(PS_SOLID, 1, RGB(255,25,5));
hdc = BeginPaint (hwnd, &ps) ;
oldPen = SelectObject(hdc, hpen);
drawRects(hwnd, hdc);
//Rectangle(hdc, 0, 0, 840, 525);
SelectObject(hdc,oldPen);
DeleteObject(hpen);
EndPaint (hwnd, &ps) ;
return 0 ;
So, if I call my own method above for drawing rectangles, it draws nothing, however the call to draw the rectangle in the WM_PAINT that I have commented above succeeds without a problem.
Here is my method:
BOOL drawRects(HWND hwnd, HDC hdc)
{
char buffer[50];
BOOL res = FALSE;
RECT tempRect = {0};
char quadStr[6] = "";
int i = 0;
quadStr[i]='*';
OutputDebugString("Going to draw");
for (i = 1; i <= 4; i++)
{
//get rect for each quadrent from the parent
OutputDebugString("inside for");
getRect(g_crntRect, &tempRect, i);
OutputDebugString("got rectr");;
res = Rectangle(hdc, tempRect.right, tempRect.top, tempRect.right, tempRect.bottom);
if (res == FALSE)
{
OutputDebugString("false");;
sprintf(buffer, "Error: %ld", GetLastError());
OutputDebugString(buffer);
}
else
{
OutputDebugString("drew");;
}
quadStr[i]='*';
printRect(quadStr, &tempRect);
}
return TRUE;
}
Looking at debug output, everything seems fine. Proper values are being passed into the Rectangle method. However, I wonder if I am not passing HDC correctly?
Any ideas?
Looks like a simple typo. In your method you have:
res = Rectangle(hdc, tempRect.right, tempRect.top, tempRect.right, tempRect.bottom);
The second parameter should be tempRect.left not tempRect.right. You're trying to draw a zero-width rectangle.
Change
BOOL drawRects(HWND hwnd, HDC* hdc)
to
BOOL drawRects(HWND hwnd, HDC hdc)
A Windows handle is actually a pointer, so there is no need to pass it by reference. But if you do, you would need to call your function as drawRects(hwnd, &hdc);
In general you don't paint outside the WM_PAINT handler. If you want your window to be updated, just call InvalidateRect on the area you want to be redrawn. That will trigger the WM_PAINT call which will then repaint the window.
Is there a reason you need to paint the window outside the paint handler?

Resources