FillRect won't draw anything - winapi

I'm trying to create a simple window in Win32 and draw a rectangle in it, but for some reason FillRect isn't working for me. Here's my source:
#include <windows.h>
#include "resource.h"
RECT rect;
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static PAINTSTRUCT ps;
static HDC hDC;
switch(msg)
{
case WM_PAINT:
hDC = BeginPaint(hWnd, &ps);
FillRect(hDC, &rect, (HBRUSH)(COLOR_WINDOW+1));
EndPaint(hWnd, &ps);
break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hWnd;
MSG msg;
rect.left = 0;
rect.right = 0;
rect.top = 100;
rect.bottom = 100;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_ACTIVEBORDER+1);
wc.lpszMenuName = MAKEINTRESOURCE(IDR_MAIN_MENU);
wc.lpszClassName = "Main";
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
RegisterClassEx(&wc);
hWnd = CreateWindowEx(NULL, "Main", "Main", WS_SYSMENU | WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, 240, 360, NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
Is there something I'm missing or doing wrong in my code? Thanks in advance

Your code is fine. The problem is that you have
rect.left = 0 and rect.right = 0 and the rect.top and rect.bottom are also the same. So your rect is 0 size.
Try this
rect.left = 0;
rect.right = 100;
rect.top = 0;
rect.bottom = 100;

Related

How do I make a static control with custom width and color?

To change the static's control color and width, I did process the WM_NCPAINT message, but it's not working properly:
the text isn't properly displayed. Should I draw it in this message? When I call SetWindowText(), the new text is properly set, but I still have the issue #2.
after a call to SetWindowText(), the text is set, but the border differs, it's smaller than the one I've draw in the WM_NCPAINT message.
Here's how I'm handling WM_NCPAINT:
case WM_NCPAINT:
{
PAINTSTRUCT ps;
HDC dc = BeginPaint(hwnd, &ps);
RECT rt = {0};
GetClientRect(hwnd, &rt);
HPEN pen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0));
HPEN holdPen = SelectObject(dc, pen);
DrawBorder(dc, &rt);
SelectObject(dc, holdPen);
EndPaint(hwnd, &ps);
DeleteObject(pen);
pen = NULL;
return 0;
}
When the application starts, the static control border looks like the one I've draw at WM_NCPAINT:
But once I call SetWindowText(), for example, from a button click, it looks like this:
What am I missing?
Here's full code:
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "Comctl32.lib")
#pragma comment(lib, "Gdi32.lib")
#define WIN32_LEAN_AND_MEAN
#define UNICODE
#define _UNICODE
#include <windows.h>
#include <Commctrl.h>
#include <crtdbg.h>
#include <strsafe.h>
#include <string.h>
#include <assert.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void EnableVisualStyles2(void);
LRESULT CALLBACK ButtonProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void SetDefaultFont(HWND hwnd);
void DrawLine(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2);
void DrawBorder(HDC hdc, RECT *rect);
HFONT getSystemDefaultFont(void);
WNDPROC oldButtonProc;
HINSTANCE ghInstance;
HFONT hDefaultFont;
HWND btn, btn2;
enum
{
BTN_ID = 10,
BTN2_ID,
};
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PWSTR pCmdLine, int nCmdShow)
{
MSG msg = {0};
HWND hwnd;
WNDCLASSW wc = {0};
wc.lpszClassName = L"Window";
wc.hInstance = hInstance;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpfnWndProc = WndProc;
wc.hCursor = LoadCursor(0, IDC_ARROW);
EnableVisualStyles2();
if(!RegisterClass(&wc)) {
return -1;
}
int width = 540;
int height = 460;
int screenWidth = GetSystemMetrics(SM_CXSCREEN);
int screenHeight = GetSystemMetrics(SM_CYSCREEN);
int cx = (screenWidth - width) / 2;
int cy = (screenHeight - height) / 2;
hwnd = CreateWindowW(wc.lpszClassName, L"Window",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
cx, cy, width, height, NULL, NULL,
hInstance, NULL);
ghInstance = hInstance;
while (GetMessage(&msg, NULL, 0, 0))
{
if (!IsDialogMessage(hwnd, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
DeleteObject(hDefaultFont);
return (int) msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
{
btn =
CreateWindow(L"static", L"+",
WS_VISIBLE | WS_CHILD | WS_TABSTOP |
SS_NOTIFY | SS_CENTER | SS_CENTERIMAGE,
15, 25, 50, 50,
hwnd, (HMENU) BTN_ID, NULL, NULL);
SetDefaultFont(btn);
oldButtonProc = (WNDPROC) SetWindowLongPtr(btn,
GWLP_WNDPROC,
(LONG_PTR) ButtonProc);
btn2 =
CreateWindow(L"Button", L"Click me!",
WS_VISIBLE | WS_CHILD | WS_TABSTOP,
15, 100, 70, 25,
hwnd, (HMENU) BTN2_ID,
NULL, NULL);
SetDefaultFont(btn2);
}
break;
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
case BTN_ID:
{
//InvalidateRect(btn, NULL, TRUE);
if(IsWindowVisible(btn2))
{
SetWindowText(btn, L"+");
ShowWindow(btn2, SW_HIDE);
}
else
{
SetWindowText(btn, L"-");
ShowWindow(btn2, SW_SHOW);
}
}
break;
case BTN2_ID:
{
InvalidateRect(btn, NULL, TRUE);
//SetWindowText(btn, L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0");
}
break;
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
LRESULT CALLBACK ButtonProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_NCPAINT:
{
PAINTSTRUCT ps;
HDC dc = BeginPaint(hwnd, &ps);
RECT rt = {0};
GetClientRect(hwnd, &rt);
HPEN pen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0));
HPEN holdPen = SelectObject(dc, pen);
DrawBorder(dc, &rt);
SelectObject(dc, holdPen);
EndPaint(hwnd, &ps);
DeleteObject(pen);
pen = NULL;
return 0;
}
}
return CallWindowProc(oldButtonProc, hwnd, msg, wParam, lParam);
}
void EnableVisualStyles2(void)
{
TCHAR dir[MAX_PATH] = {0};
GetSystemDirectory(dir, sizeof(dir) / sizeof(*dir));
ACTCTX actCtx = {0};
actCtx.cbSize = sizeof(ACTCTX);
actCtx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID |
ACTCTX_FLAG_SET_PROCESS_DEFAULT |
ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID;
actCtx.lpSource = L"shell32.dll";
actCtx.lpAssemblyDirectory = dir;
actCtx.lpResourceName = (LPCTSTR) 124;
ULONG_PTR cookie = FALSE;
HANDLE h = CreateActCtx(&actCtx);
assert(h != INVALID_HANDLE_VALUE);
assert(ActivateActCtx(h, &cookie));
}
HFONT getSystemDefaultFont(void)
{
if(!hDefaultFont)
{
// get system default font
NONCLIENTMETRICS ncm;
ncm.cbSize = sizeof(NONCLIENTMETRICS);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0);
hDefaultFont = CreateFontIndirect(&ncm.lfMessageFont);
}
return hDefaultFont;
}
void SetDefaultFont(HWND hwnd)
{
SendMessage(hwnd, WM_SETFONT, (WPARAM)getSystemDefaultFont(), FALSE);
}
void DrawLine(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2)
{
MoveToEx(hdc, x1, y1, NULL);
LineTo(hdc, x2, y2);
}
void DrawBorder(HDC hdc, RECT *rect)
{
DrawLine(hdc, rect->left, rect->top, rect->left, rect->bottom);
DrawLine(hdc, rect->left, rect->top, rect->right, rect->top);
DrawLine(hdc, rect->right, rect->top, rect->right, rect->bottom);
DrawLine(hdc, rect->left, rect->bottom, rect->right, rect->bottom);
}
Your static control does not have a transparent background, so when you call the SetWindowText function, the static control partially covers the external lines you draw.
You can add the following code in WndProc:
case WM_CTLCOLORSTATIC:
{
HDC hdcStatic = (HDC)wParam;
SetBkMode(hdcStatic, TRANSPARENT);
return (LRESULT)GetStockObject(NULL_BRUSH);
}
But this code tells the static control to draw the text without a background color and not to repaint the background. So the new text is drawn on top of the old text instead of on a fresh background.You can refer to this thread to try to solve it.
Of course, you can also extend the boundary of the straight line when drawing a straight line (you do not need to process the WM_CTLCOLORSTATIC message), as shown in the following code:
void DrawBorder(HDC hdc, RECT* rect)
{
DrawLine(hdc, rect->left - 3, rect->top - 3, rect->left - 3, rect->bottom + 3) ;
DrawLine(hdc, rect->left - 3, rect->top - 3, rect->right + 3, rect->top - 3);
DrawLine(hdc, rect->right + 3, rect->top - 3, rect->right + 3, rect->bottom + 3);
DrawLine(hdc, rect->left - 3, rect->bottom + 3, rect->right + 3, rect->bottom + 3);
}
This is the modified effect:

How to properly grow label automatically according to text's size?

I did create a new rectangle in the WM_PAINT but in order to change the text, I also SetWindowText(), I need a InvalidateRect() so it seems quite hacky to me. What's the proper way to do that? I'm not sure if I'm calculating the proper height and width properly either. I've tried grow using SetWindowPos() from WM_PAINT but it failed so I switch to draw it using Rectangle(). I did that because I wanted the text o vertical center but static control doesn't support that, so I went to do the paiting myself so I can use DrawText() with DT_CENTER | DT_SINGLELINE | DT_VCENTER flags. Here's how I'm handling VM_PAINT:
case WM_PAINT:
{
PAINTSTRUCT ps;
RECT rt = {0};
GetClientRect(hwnd, &rt);
int height = rt.right - rt.left;
int width = rt.bottom - rt.top;
int len = GetWindowTextLength(hwnd);
wchar_t s[len+1];
GetWindowText(hwnd, s, len+1);
int flags = DT_CENTER | DT_SINGLELINE | DT_VCENTER;
HDC dc = BeginPaint(hwnd, &ps);
// calculate the width and height
DrawText(dc, s, -1, &rt, DT_CALCRECT | flags);
width += rt.right;
height += rt.bottom;
// update width and height
rt.right = width;
rt.bottom = height;
Rectangle(dc, rt.left, rt.top, rt.right, rt.bottom);
// this prevent from painting the border.
InflateRect(&rt, -1, -1);
FillRect(dc, &rt, GetSysColorBrush(COLOR_BTNFACE));
SetBkMode(dc, TRANSPARENT);
DrawText(dc, s, -1, &rt, flags);
EndPaint(hwnd, &ps);
return 0;
}
full code:
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "Comctl32.lib")
#pragma comment(lib, "Gdi32.lib")
#define WIN32_LEAN_AND_MEAN
#define UNICODE
#define _UNICODE
#include <windows.h>
#include <Commctrl.h>
#include <crtdbg.h>
#include <strsafe.h>
#include <string.h>
#include <assert.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK ButtonProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
WNDPROC oldButtonProc;
HINSTANCE ghInstance;
HWND hTab;
HFONT hdDfaultFont;
HWND btn;
enum
{
BTN_ID = 10,
BTN2_ID,
};
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PWSTR pCmdLine, int nCmdShow)
{
MSG msg = {0};
HWND hwnd;
WNDCLASSW wc = {0};
wc.lpszClassName = L"Window";
wc.hInstance = hInstance;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpfnWndProc = WndProc;
wc.hCursor = LoadCursor(0, IDC_ARROW);
//InitComControls();
if(!RegisterClass(&wc)) {
return -1;
}
int width = 540;
int height = 460;
int screenWidth = GetSystemMetrics(SM_CXSCREEN);
int screenHeight = GetSystemMetrics(SM_CYSCREEN);
int cx = (screenWidth - width) / 2;
int cy = (screenHeight - height) / 2;
hwnd = CreateWindowW(wc.lpszClassName, L"Window",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
cx, cy, width, height, NULL, NULL,
hInstance, NULL);
ghInstance = hInstance;
while (GetMessage(&msg, NULL, 0, 0))
{
if (!IsDialogMessage(hwnd, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
DeleteObject(hdDfaultFont);
return (int) msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
{
btn =
CreateWindow(L"static", L"init text",
SS_NOTIFY |
WS_VISIBLE | WS_CHILD | WS_TABSTOP,
0, 0, 20, 30,
hwnd, (HMENU) BTN_ID, NULL, NULL);
oldButtonProc = (WNDPROC) SetWindowLongPtr(btn,
GWLP_WNDPROC,
(LONG_PTR) ButtonProc);
HWND btn2 =
CreateWindow(L"Button", L"Click me!",
WS_VISIBLE | WS_CHILD | WS_TABSTOP,
10, 50, 70, 25,
hwnd, (HMENU) BTN2_ID,
NULL, NULL);
SetDefaultFont(btn2);
}
break;
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
case BTN2_ID:
{
SetWindowText(btn, L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0");
InvalidateRect(btn, NULL, TRUE);
}
break;
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
LRESULT CALLBACK ButtonProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_PAINT:
{
PAINTSTRUCT ps;
RECT rt = {0};
GetClientRect(hwnd, &rt);
int height = rt.right - rt.left;
int width = rt.bottom - rt.top;
int len = GetWindowTextLength(hwnd);
wchar_t s[len+1];
GetWindowText(hwnd, s, len+1);
int flags = DT_CENTER | DT_SINGLELINE | DT_VCENTER;
HDC dc = BeginPaint(hwnd, &ps);
// calculate the width and height
DrawText(dc, s, -1, &rt, DT_CALCRECT | flags);
width += rt.right;
height += rt.bottom;
// update width and height
rt.right = width;
rt.bottom = height;
Rectangle(dc, rt.left, rt.top, rt.right, rt.bottom);
InflateRect(&rt, -1, -1);
FillRect(dc, &rt, GetSysColorBrush(COLOR_BTNFACE));
SetBkMode(dc, TRANSPARENT);
DrawText(dc, s, -1, &rt, flags);
EndPaint(hwnd, &ps);
return 0;
}
break;
}
return CallWindowProc(oldButtonProc, hwnd, msg, wParam, lParam);
}
You can use GetTextExtentPoint32 to find the string length and then you don't need to do calculations.
case WM_PAINT:
{
PAINTSTRUCT ps;
RECT rt = { 0 };
GetClientRect(hwnd, &rt);
int len = GetWindowTextLength(hwnd);
wchar_t s[len + 1];
GetWindowText(hwnd, s, len + 1);
int flags = DT_CENTER | DT_SINGLELINE | DT_VCENTER;
HDC dc = BeginPaint(hwnd, &ps);
SIZE sz;
GetTextExtentPoint32(dc, s, len, &sz);
rt.right = sz.cx + 10; //I added 10 to make the display less crowded.
rt.bottom = sz.cy;
Rectangle(dc, rt.left, rt.top, rt.right, rt.bottom);
// this prevent from painting the border.
InflateRect(&rt, -1, -1);
FillRect(dc, &rt, GetSysColorBrush(COLOR_BTNFACE));
SetBkMode(dc, TRANSPARENT);
DrawText(dc, s, -1, &rt, flags);
EndPaint(hwnd, &ps);
return 0;
}
To answer the X part of the XY problem, DT_VCENTER | DT_SINGLELINE implies single-line text, and in that case a static control with the SS_CENTERIMAGE style will center the text vertically.
SS_CENTERIMAGE -
A bitmap is centered in the static control that contains it. The control is not resized, so that a bitmap too large for the control will be clipped. If the static control contains a single line of text, the text is centered vertically in the client area of the control.

How to paint over white line between menu bar and client area of window?

I tried to color customize menu items (pure WinAPI). But there is a line in the menu bar which does not draw with MenuInfo.hbrBack color. If the mouse cursor hover above items a part of this line is redrawn. But if I resize the window the line will return. And in the area of menu bar where no items the line drawn constantly. How can I draw over this annoying line?
#include <windows.h>
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
struct
{
COLORREF text = RGB(200, 200, 250);
COLORREF clientBorder = RGB(120, 0, 0);
COLORREF clientBackground = RGB(100, 100, 100);
COLORREF itemBorder = RGB(0, 0, 255);
COLORREF itemBackground = RGB(0, 120, 0);
COLORREF pink = RGB(255, 0, 255);
} colorTheme;
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
WNDCLASSEX wc;
wc.cbSize = sizeof(wc);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.lpszMenuName = NULL;
wc.lpszClassName = "MainWindow";
wc.cbWndExtra = NULL;
wc.cbClsExtra = NULL;
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wc.hIconSm = LoadIcon(NULL, IDI_WINLOGO);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = CreateSolidBrush(colorTheme.clientBackground);
wc.hInstance = hInst;
RegisterClassEx(&wc);
HWND hMainWnd = CreateWindow(
"MainWindow",
"MainWindow",
WS_OVERLAPPEDWINDOW,
100, 100, 450, 120,
(HWND)NULL, NULL, HINSTANCE(hInst), NULL);
HMENU hMenu = CreateMenu();
HMENU hMenuSub1 = CreatePopupMenu();
HMENU hMenuSub2 = CreatePopupMenu();
HMENU hMenuSub3 = CreatePopupMenu();
AppendMenu(hMenu, MF_OWNERDRAW | MF_POPUP, (UINT)hMenuSub1, "SubMenu1");
AppendMenu(hMenuSub1, MF_OWNERDRAW, 0, "Item01");
AppendMenu(hMenuSub1, MF_OWNERDRAW, 0, "Item02");
AppendMenu(hMenuSub1, MF_OWNERDRAW, 0, "Item03");
AppendMenu(hMenuSub1, MF_OWNERDRAW, 0, "Item04");
AppendMenu(hMenuSub1, MF_OWNERDRAW, 0, "Item05");
AppendMenu(hMenu, MF_OWNERDRAW | MF_POPUP, (UINT)hMenuSub2, "SubMenu2");
AppendMenu(hMenu, MF_OWNERDRAW | MF_POPUP, (UINT)hMenuSub3, "SubMenu3");
MENUINFO menuInfo;
menuInfo.cbSize = sizeof(menuInfo);
menuInfo.fMask = MIM_BACKGROUND;
menuInfo.hbrBack = CreateSolidBrush(colorTheme.pink);
SetMenuInfo(hMenu, &menuInfo);
SetMenu(hMainWnd, hMenu);
ShowWindow(hMainWnd, nCmdShow);
while (GetMessage(&msg, NULL, NULL, NULL)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg) {
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hDC = BeginPaint(hWnd, &ps);
HFONT hApplicationFont;
LOGFONT applicationFont;
applicationFont.lfHeight = 16;
applicationFont.lfWidth = 6;
applicationFont.lfEscapement = 0;
applicationFont.lfOrientation = 0;
applicationFont.lfWeight = FW_NORMAL;
applicationFont.lfItalic = FALSE;
applicationFont.lfUnderline = FALSE;
applicationFont.lfStrikeOut = FALSE;
applicationFont.lfCharSet = DEFAULT_CHARSET;
applicationFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
applicationFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
applicationFont.lfQuality = ANTIALIASED_QUALITY;
applicationFont.lfPitchAndFamily = DEFAULT_PITCH;
strcpy_s(applicationFont.lfFaceName, "Arial");
hApplicationFont = CreateFontIndirectA(&applicationFont);
SelectObject(hDC, hApplicationFont);
SelectObject(hDC, GetStockObject(DC_PEN));
SetDCPenColor(hDC, colorTheme.clientBorder);
SelectObject(hDC, GetStockObject(DC_BRUSH));
SetDCBrushColor(hDC, colorTheme.clientBackground);
RECT clientRect;
GetClientRect(hWnd, &clientRect);
Rectangle(hDC, 0, 0, clientRect.right, clientRect.bottom);
EndPaint(hWnd, &ps);
break;
}
case WM_MEASUREITEM:
{
LPMEASUREITEMSTRUCT itemStruct = (LPMEASUREITEMSTRUCT)lParam;
const char* str = (const char*)(itemStruct->itemData);
SIZE strSize;
HDC hDC = GetDC(hWnd);
GetTextExtentPoint32(hDC, str, lstrlen(str), &strSize);
itemStruct->itemWidth = strSize.cx;
itemStruct->itemHeight = 30;
ReleaseDC(hWnd, hDC);
return TRUE;
break;
}
case WM_DRAWITEM:
{
LPDRAWITEMSTRUCT itemStruct = (LPDRAWITEMSTRUCT)lParam;
HDC hDC = itemStruct->hDC;
SelectObject(hDC, GetStockObject(DC_PEN));
SetDCPenColor(hDC, colorTheme.itemBorder);
SelectObject(hDC, GetStockObject(DC_BRUSH));
SetDCBrushColor(hDC, colorTheme.itemBackground);
SetTextColor(hDC, colorTheme.text);
SetBkMode(hDC, TRANSPARENT);
Rectangle(hDC, itemStruct->rcItem.left,
itemStruct->rcItem.top,
itemStruct->rcItem.right,
itemStruct->rcItem.bottom + 1);
DrawText(hDC, (const char*)(itemStruct->itemData), -1, &(itemStruct->rcItem), DT_SINGLELINE | DT_CENTER | DT_VCENTER);
break;
}
case WM_DESTROY:
{
PostQuitMessage(NULL);
break;
}
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return NULL;
}
It seems to be part of the non-client area of the window. If that's the case then to paint there you need to handle WM_NCPAINT.
It is a single pixel line above the window's client area, so for example if I add the following code to your program I can paint it in red.
// ... in the WNDPROC
case WM_NCPAINT:
{
auto result = DefWindowProc(hWnd, WM_NCPAINT, wParam, lParam);
HDC hdc = GetWindowDC(hWnd);
RECT r = GetNonclientMenuBorderRect(hWnd);
HBRUSH red = CreateSolidBrush(RGB(255, 0, 0));
FillRect(hdc, &r, red);
DeleteObject(red);
ReleaseDC(hWnd, hdc);
return result;
}
// ... elsewhere
RECT MapRectFromClientToWndCoords(HWND hwnd, const RECT& r)
{
RECT wnd_coords = r;
// map to screen
MapWindowPoints(hwnd, NULL, reinterpret_cast<POINT*>(&wnd_coords), 2);
RECT scr_coords;
GetWindowRect(hwnd, &scr_coords);
// map to window coords by substracting the window coord origin in
// screen coords.
OffsetRect(&wnd_coords, -scr_coords.left, -scr_coords.top);
return wnd_coords;
}
RECT GetNonclientMenuBorderRect(HWND hwnd)
{
RECT r;
GetClientRect(hwnd, &r);
r = MapRectFromClientToWndCoords(hwnd, r);
int y = r.top - 1;
return {
r.left,
y,
r.right,
y+1
};
}
Now an issue with the above code is that it is over-painting the rectangle after the default non-client painting is done. In theory this could flicker; in practice I don't notice a flicker. If it did flicker, however, a safer way to do this would be to modify the WPARAM you pass to DefWindowProc(hWnd, WM_NCPAINT, ... ) such that it is the handle to a region that is the region passed to WM_NCPAINT minus the rectangle you want to paint. This doesnt seem necessary to me, for whatever reason.
If you are using themes / visual styles, which pretty much everything is nowadays, you can't override a lot of the menu styling without using a workaround like https://github.com/adzm/win32-custom-menubar-aero-theme which also uses the same approach to get rid of the white line. Note that you will need to handle this in WM_NCPAINT and WM_NCACTIVATE.

Error LNK2019, LNK1120 when I try to build via VS2013

Here is the original code.
#include <windows.h>
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
int WINAPI Winmain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpszCmdLine, int nCmdShow)
{
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 = "Window Class Name";
RegisterClass(&WndClass);
hwnd = CreateWindow("Window Class Name", "Window Title Name", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
switch (iMsg)
{
case WM_CREATE:
break;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
//TextOut(hdc, 0, 0, "HelloWorld", 10);
rect.left = 50;
rect.top = 40;
rect.right = 200;
rect.bottom = 120;
DrawText(hdc, "HelloWorld", 10, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hwnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
I think there is no problem in this code, but there is still fatal error LNK2019 & LNK1120.
I already tried changing to console to windows. But still same.
Can anybody help me? I cannot check anything in API programming.

How to draw image on a window?

I have created a window with createwindow() api using VS2005 in C++ on Windows Vista
My requirement is to draw an image (of any format) on that window. I am not using any MFC in this application.
not exactly sure what is your problem: draw a bitmap on the form, or you would like know how to work with various image formats, or both. Anyways below is an example of how you could load a bitmap and draw it on the form:
HBITMAP hBitmap = NULL;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
switch (message)
{
<...>
case WM_CREATE:
hBitmap = (HBITMAP)LoadImage(hInst, L"c:\\test.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
break;
case WM_PAINT:
PAINTSTRUCT ps;
HDC hdc;
BITMAP bitmap;
HDC hdcMem;
HGDIOBJ oldBitmap;
hdc = BeginPaint(hWnd, &ps);
hdcMem = CreateCompatibleDC(hdc);
oldBitmap = SelectObject(hdcMem, hBitmap);
GetObject(hBitmap, sizeof(bitmap), &bitmap);
BitBlt(hdc, 0, 0, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCCOPY);
SelectObject(hdcMem, oldBitmap);
DeleteDC(hdcMem);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
DeleteObject(hBitmap);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
LoadImage loads an icon, cursor, animated cursor, or bitmap. Details here
For working with various images formats you can use Windows Imaging Component (see IWICBitmapDecoder) or code from here Loading JPEG and GIF pictures or 3rd party tools like FreeImage or LeadTools
hope this helps, regards
void LoadScreen(HWND hWnd) {
RECT rect;
HDC hdc = GetDC(hWnd);
HBRUSH brush = CreatePatternBrush((HBITMAP)LoadImage(NULL, L"file.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE));
GetWindowRect(hWnd, &rect);
FillRect(hdc, &rect, brush);
DeleteObject(brush);
ReleaseDC(hWnd, hdc);
}
#include <windows.h>
#include <string.h>
HBITMAP hBitmap, hOldBitmap;
HDC hdc, hdcMem;
BITMAP bm;
HINSTANCE hI;
PAINTSTRUCT ps;
RECT rect;
RECT rc;
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
hBitmap = (HBITMAP)LoadImage(hI, "1.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
GetObject(hBitmap, sizeof(BITMAP), &bm);
hdc = GetDC(hWnd);
hdcMem = CreateCompatibleDC(hdc);
hOldBitmap = SelectBitmap(hdcMem, hBitmap);
ReleaseDC(hWnd, hdc);
return 0;
case WM_LBUTTONDOWN:
//for dragging not only by the title, but also by any part of the window
ReleaseCapture();
SendMessage(hWnd, 0xA1, 2, 0);
break;
case WM_PAINT:
hdc=BeginPaint(hWnd,&ps);
//overlay image with stretching to fit the window
GetClientRect(hWnd,&rect);
SetStretchBltMode(hdc, STRETCH_HALFTONE);
StretchBlt(hdc,0,0,rect.right,rect.bottom,
hdcMem,0,0,bm.bmWidth,bm.bmHeight,SRCCOPY);
EndPaint(hWnd,&ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
DeleteDC(hdcMem);
DeleteObject(hBitmap);
DeleteObject(hOldBitmap);
break;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPInst, LPSTR lpCmdLine, int nCmdShow)
{
//copying a pointer to a running application instance (module)
hI=hInstance;
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProcedure;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) GetStockObject(LTGRAY_BRUSH);
wc.lpszClassName = "test_class";
wc.lpszMenuName = NULL;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
RegisterClass(&wc);
HWND hWnd = CreateWindow(wc.lpszClassName, "Image Window",
//window with title (overlapping window)
WS_OVERLAPPEDWINDOW,
//window without title
//WS_VISIBLE | WS_POPUP | WS_SYSMENU | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
CW_USEDEFAULT, CW_USEDEFAULT, 500, 500, NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
MSG msg;
while(GetMessage (&msg, NULL, 0, 0))
{
DispatchMessage (&msg);
TranslateMessage (&msg);
}
UnregisterClass(wc.lpszClassName, hInstance);
return (int) msg.wParam;
}

Resources