Winapi creating a tab menu - c++

I'm trying to make a tab menu, it should have an active state with different styling when a tab is selected, the problem is when starting the program the tabs get selected after two clicks. When displaying the contents of the buttonPressed array in WM_DRAWITEM even, is a delay in changing the value of the active state
case WM_CREATE:
buttonPressed[0] = 1;
buttonPressed[1] = 0;
buttonPressed[2] = 0;
buttonPressed[3] = 0;
button1 = CreateWindow("BUTTON","Overview",WS_VISIBLE | WS_CHILD | BS_OWNERDRAW, 0,0,200,50, hwnd , (HMENU) 1 , NULL, NULL);
button2 = CreateWindow("BUTTON","Send",WS_VISIBLE | WS_CHILD | BS_OWNERDRAW, 200,0,200,50, hwnd , (HMENU) 2, NULL, NULL);
button3 = CreateWindow("BUTTON","Receive",WS_VISIBLE | WS_CHILD | BS_OWNERDRAW, 400,0,200,50, hwnd , (HMENU) 3, NULL, NULL);
button4 = CreateWindow("BUTTON","Transactions",WS_VISIBLE | WS_CHILD | BS_OWNERDRAW, 600,0,200,50, hwnd , (HMENU) 4, NULL, NULL);
break;
case WM_DRAWITEM:
{
if((wParam == 1 && buttonPressed[0] == 1) || (wParam == 2 && buttonPressed[1] == 1) || (wParam == 3 && buttonPressed[2] == 1) || (wParam == 4 && buttonPressed[3] == 1) ){
FillRect(Item->hDC, &Item->rcItem, CreateSolidBrush(0x6C6C6C) );
SetBkMode(Item->hDC, 0x6C6C6C);
SetTextColor(Item->hDC, RGB(0,0,255));
}else{
FillRect(Item->hDC, &Item->rcItem, CreateSolidBrush(0x6C6C6C) );
SetBkMode(Item->hDC, 0x6C6C6C);
SetTextColor(Item->hDC, RGB(255,255,255));
}
int len;
len = GetWindowTextLength(Item->hwndItem);
LPSTR lpBuff;
lpBuff = new char[len+1];
GetWindowTextA(Item->hwndItem, lpBuff, len+1);
DrawTextA(Item->hDC, lpBuff, len, &Item->rcItem, DT_CENTER | DT_VCENTER | DT_WORDBREAK);
}
break;
case WM_COMMAND:
switch ( LOWORD(wParam) ){
case 1:
buttonPressed[0] = 1;
buttonPressed[1] = 0;
buttonPressed[2] = 0;
buttonPressed[3] = 0;
break;
case 2:
buttonPressed[0] = 0;
buttonPressed[1] = 1;
buttonPressed[2] = 0;
buttonPressed[3] = 0;
break;
case 3:
buttonPressed[0] = 0;
buttonPressed[1] = 0;
buttonPressed[2] = 1;
buttonPressed[3] = 0;
break;
case 4:
buttonPressed[0] = 0;
buttonPressed[1] = 0;
buttonPressed[2] = 0;
buttonPressed[3] = 1;
break;
}
break;

Your WM_COMMAND handler is not triggering any repaints of the buttons after changing the states in the buttonPressed array. Call InvalidateRect() on each button to trigger a new WM_PAINT message for each button.
Also, you are making the same mistakes in this code (leaking memory and resources, invalid parameter to SetBkMode(), etc) that you made in your earlier code. You are using very few portions of code from the accepted answer, and you are ignoring all of the mistakes that answer pointed out to you.
Try something more like this:
struct ButtonInfo {
HWND Wnd;
bool Pressed;
};
ButtonInfo button[4];
...
case WM_CREATE:
{
LPCTSTR captions[4] = {TEXT("Overview"), TEXT("Send"), TEXT("Receive"), TEXT("Transactions")};
for (int i = 0; i < 4; ++i) {
button[i].Pressed = false;
button[i].Wnd = CreateWindow(TEXT("BUTTON"), captions[i], WS_VISIBLE | WS_CHILD | BS_OWNERDRAW, i * 200, 0, 200, 50, hwnd, reinterpret_cast<HMENU>(i+1), NULL, NULL);
}
button[0].Pressed = true;
}
break;
case WM_DRAWITEM:
{
LPDRAWITEMSTRUCT Item = reinterpret_cast<LPDRAWITEMSTRUCT>(lParam);
HFONT hFont = CreateFont(17, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, TEXT("Arial Black"));
HFONT hOldFont = (HFONT) SelectObject(Item->hDC, hFont);
HBRUSH hBrush = CreateSolidBrush(RGB(0x6C, 0x6C, 0x6C));
FillRect(Item->hDC, &Item->rcItem, hBrush);
DeleteObject(hBrush);
SetBkMode(Item->hDC, TRANSPARENT);
int buttonID = wParam;
if (button[buttonID - 1].Pressed) {
SetTextColor(Item->hDC, RGB(0,0,255));
} else {
SetTextColor(Item->hDC, RGB(255,255,255));
}
int len = GetWindowTextLength(Item->hwndItem) + 1;
LPTSTR lpBuff = new TCHAR[len];
len = GetWindowText(Item->hwndItem, lpBuff, len);
DrawText(Item->hDC, lpBuff, len, &Item->rcItem, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
delete[] lpBuff;
SelectObject(Item->hDC, hOldFont);
DeleteObject(hFont);
}
break;
case WM_COMMAND:
{
int buttonID = LOWORD(wParam);
int buttonIdx = buttonID - 1;
for (int i = 0; i < 4; ++i) {
button[i].Pressed = (i == buttonIdx);
InvalidateRect(button[i].Wnd, NULL, TRUE);
}
switch (buttonID) {
// perform whatever actions you need based on which button was clicked....
}
}
break;

Related

Scrollbar duplicate winapi c++

I am making a scrollbar for the first time and don't understand why I have a duplicate of my scrollbar when content is scrollable.
Here is how it looks, I don't know if you can see it good enough but here's a screenshot; one scrollbar is the thick gray one (the one a want to keep, looks more like the classic scrollbar), and one is a little gray rectangle to the left of it. Both of these scrollbars work and scroll my program.
:
But when content is not scrollable then it looks like this:
Here is my ScrollBar.cpp if this will help:
#include "ScrollBar.h"
ScrollBar::ScrollBar(){}
ScrollBar::~ScrollBar(){
RemoveWindowSubclass(hWnd, scrollProc, IDC_STATIC);
delete con;
}
ScrollBar::ScrollBar(HWND hWnd, HINSTANCE hInst) : hWnd(hWnd),hInst(hInst) {
this->hWndParent = GetParent(hWnd);
con = new Controls(hWndParent);
}
void ScrollBar::createScroll(int x, int y, int w, int h, bool stickRight, bool stickBottom) {
this->x = x;
this->y = y;
this->width = w;
this->height = h;
hScroll = con->create("scrollbar", WS_VISIBLE | WS_CHILD | SBS_VERT, x, y, width, height,"scrollBar","",0, stickRight, stickBottom);
//Creates like this
/// CreateWindowEx(0, type, text, styles, cData.x, cData.y, cData.width, cData.height, hWnd, (HMENU)id, NULL, (LPVOID)lParam);
SetWindowSubclass(hScroll, scrollProc, IDC_STATIC, (DWORD_PTR)this);
SetWindowSubclass(hWndParent, scrollProc, IDC_STATIC, (DWORD_PTR)this);
con->setEventListener();
}
void ScrollBar::setScrollRange(int scrollMaxHeight) {
scrollMaxH = scrollMaxHeight == -1 ? scrollMaxH : scrollMaxHeight;
SCROLLINFO si = { 0 };
si.cbSize = sizeof(si);
si.fMask = SIF_RANGE;
si.nMin = 0;
si.nMax = scrollMaxH;
SetScrollInfo(hScroll, SB_VERT, &si, false);
}
void ScrollBar::setScrollSize() {
SCROLLINFO oSi = { 0 };
oSi.cbSize = sizeof(oSi);
oSi.fMask = SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS;
GetScrollInfo(hScroll, SB_VERT, &oSi);
RECT rect = GetLocalCoordinates(hWnd);
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
SCROLLINFO si = { 0 };
si.cbSize = sizeof(si);
si.fMask = SIF_PAGE;
si.nPage = height;
SetScrollInfo(hScroll, SB_VERT, &si, TRUE);
si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS;
GetScrollInfo(hScroll, SB_VERT, &si);
int res = oSi.nPos - si.nPos;
if (res > 0) {
setChildScrollOffset(hWnd, res);
}
}
void ScrollBar::handleVScroll(int action,int thum) {
int nPos;
int nOldPos;
SCROLLINFO si = { 0 };
si.cbSize = sizeof(si);
si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS;
GetScrollInfo(hScroll, SB_VERT, &si);
nOldPos = si.nPos;
switch (action)
{
case SB_TOP:
nPos = si.nMin;
break;
case SB_BOTTOM:
nPos = si.nMax;
break;
case SB_LINEUP:
nPos = si.nPos - 30;
break;
case SB_LINEDOWN:
nPos = si.nPos + 30;
break;
case SB_PAGEUP:
nPos = si.nPos - 30;
break;
case SB_PAGEDOWN:
nPos = si.nPos + 30;
break;
case SB_THUMBTRACK:
nPos = thum;
break;
default:
nPos = si.nPos;
break;
}
SetScrollPos(hScroll, SB_VERT, nPos, TRUE);
nPos = GetScrollPos(hScroll, SB_VERT);
if (nOldPos != nPos) {
ScrollWindowEx(hWnd, 0, nOldPos - nPos, NULL, NULL, NULL, NULL,
SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN);
UpdateWindow(hWnd);
setChildScrollOffset(hWnd, nOldPos - nPos);
}
}
void ScrollBar::setChildScrollOffset(HWND h, int offset) {
Controls* childsCon = reinterpret_cast<Controls*>(GetWindowLongPtr(h, GWLP_USERDATA));
for (auto it : childsCon->sControls)
{
childsCon->getControlItem(it.first)->y += offset;
}
}
LRESULT CALLBACK ScrollBar::scrollProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) {
ScrollBar* lpData = (ScrollBar*)dwRefData;
HDC hdc = (HDC)wParam;
PAINTSTRUCT ps;
HBRUSH hbrBackground;
switch (uMsg) {
case WM_SIZE:
{
lpData->setScrollSize();
break;
}
case WM_VSCROLL:
{
lpData->handleVScroll(LOWORD(wParam), HIWORD(wParam));
return true;
}
case WM_MOUSEWHEEL:
{
short zDelta = (short)(0xFFFF & (wParam >> 16));
if (zDelta > 0)
PostMessage(lpData->hScroll, WM_VSCROLL, SB_LINEUP, NULL);
else
PostMessage(lpData->hScroll, WM_VSCROLL, SB_LINEDOWN, NULL);
return 0;
}
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
I am blind and so can't see your screen shots but does your parent window have WS_VSCROLL? (you don't show the styles associated with that window). If so remove it, the WS_VSCROLL adds a scrollbar that is not control-based to the window's non-client area.
You need to distinguish between Standard Scroll Bars and Scroll Bar Controls. A scroll bar control is a control window that belongs to the SCROLLBAR window class.
For more details about how to Create Scroll Bar, I suggest you could refer to the Doc: How to Create Scroll Bars
According to the code, you want to create a Scroll Bar Controls. So you should creates a window without standard horizontal and vertical scroll bars and then use the CreateWindowEx function to create a scroll bar by specifying the SCROLLBAR window class.
Could you please show a minimal, reproducible sample?

How can I connect 2 text boxes with a line in Win32?

So I have this project where I have to make like a logical scheme. The only thing that I need to kinda learn to do is the line that can connect to boxe. Think at it like a tree in c++, I have the bubbles and all i need to do is connect them with a line ( I'm thinking like double click-ing on the first bubble then hold the click till i get to the other bubble). This is the code I have till now ( more like a test code )
#include <stdio.h>
#include <winuser.h>
#include <iostream>
#define File_Menu_NEW 1
#define File_Menu_OPEN 2
#define File_Menu_EXIT 3
#define Change_Title 4
#define Open_file 5
#define Save_file 6
LRESULT CALLBACK WindowProcedure(HWND,UINT,WPARAM,LPARAM);
void AddMenus(HWND);
void AddControls(HWND);
HMENU hMenu;
HWND hEdit;
HWND hDestroy;
int x=100,y=100,h=200,l=20,ok;
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR args, int ncmdshow)
{
WNDCLASSW wc = {0};
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.hCursor = LoadCursor(NULL,IDC_ARROW);
wc.hInstance = hInst;
wc.lpszClassName = L"myWindowClass";
wc.lpfnWndProc = WindowProcedure;
HCURSOR SetCursor(HCURSOR hCursor);
DRAGDROP_S_USEDEFAULTCURSORS;
if(!RegisterClassW(&wc))
return -1;
CreateWindowW(L"myWindowClass",L"Transformator Logic",WS_OVERLAPPEDWINDOW | WS_VISIBLE,100,100,500,500,
NULL,NULL,NULL,NULL);
MSG msg={0};
while(GetMessage(&msg,NULL,NULL,NULL) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
void display_file(char* path)
{
FILE *file;
file = fopen(path,"rb");
fseek(file,0,SEEK_END);
int _size = ftell(file);
rewind(file);
char *data = new char[_size+1];
fread(data,_size,1,file);
data[_size] = '\0';
SetWindowText(hEdit,data);
fclose(file);
}
void open_file(HWND hWnd)
{
OPENFILENAME ofn;
char file_name[100];
ZeroMemory(&ofn,sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = hWnd;
ofn.lpstrFile = file_name;
ofn.lpstrFile[0] = '\0';
ofn.nMaxFile = 100;
ofn.lpstrFilter = "All files\0*.*\0Source Files\0*.CPP\0Text Files\0*.TXT\0";
ofn.nFilterIndex = 1;
GetOpenFileName(&ofn);
display_file(ofn.lpstrFile);
}
void write_file(char *path)
{
FILE *file;
file = fopen(path,"w");
int _size = GetWindowTextLength(hEdit);
char *data = new char[_size+1];
GetWindowText(hEdit,data,_size+1);
fwrite(data,_size+1,1,file);
fclose(file);
}
void save_file(HWND hWnd)
{
OPENFILENAME ofn;
char file_name[100];
ZeroMemory(&ofn,sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = hWnd;
ofn.lpstrFile = file_name;
ofn.lpstrFile[0] = '\0';
ofn.nMaxFile = 100;
ofn.lpstrFilter = "All files\0*.*\0Source Files\0*.CPP\0Text Files\0*.TXT\0";
ofn.nFilterIndex = 1;
GetSaveFileName(&ofn);
write_file(ofn.lpstrFile);
}
LRESULT CALLBACK WindowProcedure(HWND hWnd,UINT msg,WPARAM wp,LPARAM lp)
{
switch(msg)
{
case WM_LBUTTONDBLCLK:
{
int xm = LOWORD(lp);
int ym = HIWORD(lp);
}
case WM_LBUTTONDOWN:
{
int iPosX = LOWORD(lp);
int iPosY = HIWORD(lp);
if(x<=iPosX&&x+l>=iPosX&&y<=iPosY&&y+h>=iPosY)
{
DestroyWindow(hDestroy);
ok=1;
}
break;
}
case WM_LBUTTONUP:
{
int iPosx = LOWORD(lp);
int iPosy = HIWORD(lp);
x=iPosx;
y=iPosy;
if(ok==1)
{
hDestroy=CreateWindowW(L"Static",L"Drag and drop test",WS_VISIBLE | WS_CHILD | WS_BORDER | SS_CENTER,x,y,h,l,hWnd,
NULL,NULL,NULL);
ok=0;
}
break;
}
case WM_COMMAND:
switch(wp)
{
case Open_file:
open_file(hWnd);
break;
case Save_file:
save_file(hWnd);
break;
case File_Menu_EXIT:
DestroyWindow(hWnd);
break;
case File_Menu_NEW:
MessageBeep(MB_ICONINFORMATION);
break;
case Change_Title:
wchar_t text[100];
GetWindowTextW(hEdit,text,100);
SetWindowTextW(hWnd,text);
break;
}
break;
case WM_CREATE:
AddMenus(hWnd);
AddControls(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hWnd,msg,wp,lp);
}
}
void AddMenus(HWND hWnd)
{
hMenu = CreateMenu();
HMENU hFileMenu = CreateMenu();
HMENU hSchemePrestabilite = CreateMenu();
HMENU hSubMenu = CreateMenu();
AppendMenu(hMenu,MF_POPUP,(UINT_PTR)hFileMenu,"File");
AppendMenu(hFileMenu,MF_STRING,File_Menu_NEW,"New");
AppendMenu(hFileMenu,MF_POPUP,(UINT_PTR)hSubMenu,"Open SubMenu");
AppendMenu(hSubMenu,MF_STRING,NULL,"SubMenu Item");
//AppendMenu(hSubMenu,MF_STRING,Change_Title,"Change Title");
AppendMenu(hFileMenu,MF_SEPARATOR,NULL,NULL);
AppendMenu(hFileMenu,MF_STRING,File_Menu_EXIT,"Exit");
AppendMenu(hMenu,MF_STRING,Open_file,"Open File");
AppendMenu(hMenu,MF_STRING,Save_file,"Save File");
SetMenu(hWnd,hMenu);
}
void AddControls(HWND hWnd)
{
hDestroy =CreateWindowW(L"Static",L"Drag and drop test",WS_VISIBLE | WS_CHILD | WS_BORDER | SS_CENTER,x,y,h,l,hWnd,
NULL,NULL,NULL);
CreateWindowW(L"Static",L"Line",WS_VISIBLE | WS_CHILD | WS_BORDER | SS_CENTER,100,200,200,20,hWnd,
NULL,NULL,NULL);
//hEdit = CreateWindowW(L"Edit",NULL,WS_CHILD | WS_VISIBLE | WS_BORDER | ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL,100,100,300,300,hWnd,
//(HMENU)Open_file,NULL,NULL);
// CreateWindowW(L"Button",L"Change Title",WS_VISIBLE | WS_CHILD,100,254,200,20,hWnd,
// (HMENU)Change_Title,NULL,NULL);
}
You need to handle the WM_PAINT message inside your WindowProc and draw the line yourself:
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
HPEN hpen = CreatePen(PS_SOLID, 2, RGB(0, 0, 0)); // specify line width and color
HANDLE oldpen = SelectObject(hdc, hpen);
MoveToEx(hdc, 10, 10, NULL); // specify "from" coordiates
LineTo(hdc, 400, 300); // specify "to" coordinates
SelectObject(hdc, oldpen);
DeleteObject(hpen);
EndPaint(hWnd, &ps);
break;
}
Alternatively, you can create a "line" component that can draw itself, and add it as a child to your window.

WinAPI WC_LISTVIEW paint issues

I created a ListView using CreateWindowEx and using the WC_LISTVIEW as class name.
I'm trying to create a smooth scrolling. Everything works perfectly except that list is not drawn correctly. See below the screenshot of the list:
The list view has the following style in CreateWindowEx:
WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_NOCOLUMNHEADER |
WS_TABSTOP | WS_BORDER | LVS_SHOWSELALWAYS | LVS_SINGLESEL | LVS_OWNERDRAWFIXED
I'm using a timer to scroll window. It does the following:
ScrollWindowEx(
listHandle,
0,
step * linesDelta,
NULL,
NULL,
0, 0, 0
);
UpdateWindow(listHandle);
Scroll works perfectly except painting.
I tried:
UpdateWindow() - screenshoot attached
RedrawWindow with all possible options - window is painted only once
InvalidateRect + UpdateWindow = same as 2
InvalidateRect + SendMessage(hwnd, WM_PAINT, 0, 0) - same as 2
The code that paints the item for the list is below:
LRESULT drawItem(HWND hwnd, DRAWITEMSTRUCT* drawStruct) {
Item *itemData = (Item *)drawStruct->itemData;
HDC hdc = drawStruct->hDC;
COLORREF backgroundColor;
COLORREF oldColor;
if (drawStruct->itemState & ODS_SELECTED || ListView_GetHotItem(hwnd) == drawStruct->itemID) {
backgroundColor = GetSysColor(COLOR_HIGHLIGHT);
oldColor = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
} else {
backgroundColor = RGB(255, 255, 255);
oldColor = SetTextColor(hdc, GetSysColor(COLOR_CAPTIONTEXT));
}
HBRUSH backgroundBrush = CreateSolidBrush(backgroundColor);
HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc, backgroundBrush);
FillRect(hdc, &drawStruct->rcItem, backgroundBrush);
drawStruct->rcItem.left += 5;
drawStruct->rcItem.right -= 5;
drawStruct->rcItem.left += 30;
DrawText(hdc, itemData->path, -1, &drawStruct->rcItem,
DT_NOPREFIX | DT_SINGLELINE | DT_END_ELLIPSIS);
drawStruct->rcItem.left -= 30;
if (itemData->searchData && itemData->searchData->bitmap) {
HBITMAP bitmap = itemData->searchData->bitmap;
HDC hdcMem = CreateCompatibleDC(hdc);
HGDIOBJ oldBitmap = SelectObject(hdcMem, bitmap);
BITMAPINFO bi = { 0 };
bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
// Get the bitmap info header.
if (0 != GetDIBits(
hdcMem, // hdc
bitmap, // hbmp
0, // uStartScan
0, // cScanLines
NULL, // lpvBits
&bi,
DIB_RGB_COLORS
)) {
BLENDFUNCTION blendFunc;
blendFunc.BlendOp = AC_SRC_OVER;
blendFunc.BlendFlags = 0;
blendFunc.SourceConstantAlpha = 255;
blendFunc.AlphaFormat = AC_SRC_ALPHA;
AlphaBlend(hdc,
drawStruct->rcItem.left + 2, //dest X
drawStruct->rcItem.top + 3, //dest Y
bi.bmiHeader.biWidth,
bi.bmiHeader.biHeight,
hdcMem, 0, 0,
bi.bmiHeader.biWidth,
bi.bmiHeader.biHeight, blendFunc);
}
SelectObject(hdcMem, oldBitmap);
DeleteDC(hdcMem);
}
SelectObject(hdc, hOldBrush);
DeleteObject(backgroundBrush);
SetTextColor(hdc, oldColor);
return 0;
}
Does anyone know a solution for this?
Please see below a complete example created from scratch that has exactly the same behavior:
#include "stdafx.h"
#include "TestList.h"
#include <strsafe.h>
#include <commctrl.h>
#define MAX_LOADSTRING 100
#define ID_LIST_BOX 200
#define TIMER_ID_SMOOTH_SCROLL 100
class ListData {
int scrollToDelta;
int currentScrollPos;
int numPixelsToChangeScrollPos;
int numPixelsChanged;
public:
HWND listWindow;
WNDPROC defaultListProcedure;
void startSmoothScrolling(HWND hwnd, int delta) {
if (delta < 0) {
scrollToDelta = 100;
} else {
scrollToDelta = -100;
}
SCROLLINFO si;
si.cbSize = sizeof(si);
si.fMask = SIF_RANGE | SIF_POS;
if (GetScrollInfo(listWindow, SB_VERT, &si)) {
double count = SendMessage(listWindow, LVM_GETITEMCOUNT, 0, 0);
double totalHeight = count * 30;
currentScrollPos = (int)((totalHeight * (double)si.nPos) / (double)si.nMax);
numPixelsToChangeScrollPos = totalHeight / si.nMax;
numPixelsChanged = 0;
} else {
currentScrollPos = 0;
numPixelsChanged = 0;
numPixelsToChangeScrollPos = 30;
}
}
void smoothScroll(HWND listHandle) {
SCROLLINFO si;
si.cbSize = sizeof(si);
si.fMask = SIF_RANGE | SIF_POS;
DWORD linesDelta;
SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &linesDelta, 0);
if (scrollToDelta < 0) {
if (GetScrollInfo(listHandle, SB_VERT, &si)) {
if (si.nPos == 0) {
KillTimer(listHandle, TIMER_ID_SMOOTH_SCROLL);
return;
}
}
scrollToDelta += 5;
int step = -5;
if (scrollToDelta > -80) {
step = -4;
} else if (scrollToDelta > -60) {
step = -3;
} else if (scrollToDelta > -40) {
step = -3;
} else if (scrollToDelta > -20) {
step = -2;
}
numPixelsChanged += abs(step);
if (numPixelsChanged >= numPixelsToChangeScrollPos) {
int posDelta = numPixelsChanged / numPixelsToChangeScrollPos;
numPixelsChanged -= posDelta * numPixelsToChangeScrollPos;
si.nPos = si.nPos + posDelta;
si.fMask = SIF_POS;
SetScrollInfo(listHandle, SB_VERT, &si, TRUE);
}
ScrollWindowEx(
listHandle,
0,
step * linesDelta,
NULL,
NULL,
0, 0,
SW_INVALIDATE);
if (scrollToDelta >= 0) {
KillTimer(listHandle, TIMER_ID_SMOOTH_SCROLL);
}
} else {
if (GetScrollInfo(listHandle, SB_VERT, &si)) {
int pos = GetScrollPos(listHandle, SB_VERT);
if (pos == si.nMax) {
KillTimer(listHandle, TIMER_ID_SMOOTH_SCROLL);
return;
}
}
scrollToDelta -= 5;
int step = 5;
if (scrollToDelta > -80) {
step = 4;
} else if (scrollToDelta > -60) {
step = 3;
} else if (scrollToDelta > -40) {
step = 3;
} else if (scrollToDelta > -20) {
step = 2;
}
numPixelsChanged += abs(step);
if (numPixelsChanged >= numPixelsToChangeScrollPos) {
int posDelta = numPixelsChanged / numPixelsToChangeScrollPos;
numPixelsChanged -= posDelta * numPixelsToChangeScrollPos;
si.nPos = si.nPos - posDelta;
si.fMask = SIF_POS;
SetScrollInfo(listHandle, SB_VERT, &si, TRUE);
}
ScrollWindowEx(
listHandle,
0,
step * linesDelta,
NULL,
NULL,
0, 0, 0
);
if (scrollToDelta <= 0) {
KillTimer(listHandle, TIMER_ID_SMOOTH_SCROLL);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//RedrawWindow(listHandle, NULL, NULL,
// RDW_UPDATENOW | RDW_INTERNALPAINT | RDW_INVALIDATE | RDW_NOERASE | RDW_ALLCHILDREN | RDW_ERASENOW);
//InvalidateRect(listHandle, NULL, FALSE);
//SendMessage(listHandle, WM_PAINT, 0, 0);
UpdateWindow(listHandle);
//ListView_RedrawItems(listHandle, 0, 300);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
};
struct Item {
WCHAR *name;
};
// Global Variables:
HINSTANCE hInst; // current instance
WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
// Initialize global strings
StringCchCopy(szTitle, MAX_LOADSTRING, L"Test");
StringCchCopy(szWindowClass, MAX_LOADSTRING, L"TestClassList");
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TESTLIST));
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_TESTLIST));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_TESTLIST);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
LRESULT drawItem(HWND hwnd, DRAWITEMSTRUCT* drawStruct) {
Item *itemData = (Item *)drawStruct->itemData;
HDC hdc = drawStruct->hDC;
COLORREF backgroundColor;
//pcd->clrTextBk;
COLORREF oldColor;
if (drawStruct->itemState & ODS_SELECTED || ListView_GetHotItem(hwnd) == drawStruct->itemID) {
backgroundColor = GetSysColor(COLOR_HIGHLIGHT);
oldColor = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
} else {
backgroundColor = RGB(255, 255, 255);
oldColor = SetTextColor(hdc, GetSysColor(COLOR_CAPTIONTEXT));
}
HBRUSH backgroundBrush = CreateSolidBrush(backgroundColor);
HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc, backgroundBrush);
FillRect(hdc, &drawStruct->rcItem, backgroundBrush);
drawStruct->rcItem.left += 5;
drawStruct->rcItem.right -= 5;
drawStruct->rcItem.left += 30;
DrawText(hdc, itemData->name, -1, &drawStruct->rcItem,
DT_NOPREFIX | DT_SINGLELINE | DT_END_ELLIPSIS);
drawStruct->rcItem.left -= 30;
SelectObject(hdc, hOldBrush);
DeleteObject(backgroundBrush);
SetTextColor(hdc, oldColor);
return 0;
}
LRESULT CALLBACK ListViewWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
////////////////////////////////////////////////////////////////////////////////////////////////////
case WM_TIMER: {
if (wParam == TIMER_ID_SMOOTH_SCROLL) {
ListData *listData = (ListData*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
listData->smoothScroll(hwnd);
}
break;
}
case WM_MOUSEWHEEL: {
int delta = HIWORD(wParam);
ListData *listData = (ListData*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
listData->startSmoothScrolling(hwnd, delta);
SetTimer(hwnd, TIMER_ID_SMOOTH_SCROLL, 200, NULL);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
default:
ListData *listData = (ListData*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
return CallWindowProc(listData->defaultListProcedure, hwnd, uMsg, wParam, lParam);
}
return 0;
}
//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
100, 100, 400, 400, nullptr, nullptr, hInstance, nullptr);
if (!hWnd) {
return FALSE;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
HWND listWindow = CreateWindowEx(
0,
WC_LISTVIEW,
L"",
WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_NOCOLUMNHEADER |
WS_TABSTOP | WS_BORDER | LVS_SHOWSELALWAYS | LVS_SINGLESEL | LVS_OWNERDRAWFIXED,
1, //x
1, //y
400 - 20, //width
400 - 20, //height
hWnd,
(HMENU)ID_LIST_BOX,
hInstance,
NULL);
ListData *listData = new ListData();
listData->listWindow = listWindow;
SetWindowLongPtr(listWindow, GWLP_USERDATA, (LPARAM)listData);
listData->defaultListProcedure = (WNDPROC)SetWindowLongPtr(listWindow, GWLP_WNDPROC, (LONG_PTR)ListViewWindowProc);
ListView_SetExtendedListViewStyle(listWindow, LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_AUTOSIZECOLUMNS);
SendMessage(listWindow, LVM_SETTEXTBKCOLOR, 0, 0xFFFFFF);
LVCOLUMN col;
col.mask = LVCF_TEXT | LVCF_WIDTH;
col.pszText = L"";
col.cx = 390;
SendMessage(listWindow, LVM_INSERTCOLUMN, 0, (LPARAM)&col);
LVITEM item;
item.mask = LVIF_PARAM | LVIF_TEXT;
item.iSubItem = 0;
for (int i = 0; i < 300; i++) {
item.iItem = i;
Item *itemData = (Item*)malloc(sizeof(Item));
WCHAR *name = (WCHAR*)malloc(sizeof(WCHAR) * 30);;
wsprintf(name, L"Item Name %d", i);
itemData->name = name;
item.pszText = name;
item.lParam = (LPARAM)itemData;
SendMessage(listWindow, LVM_INSERTITEM, 0, (LPARAM)&item);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_DRAWITEM: {
////////////////////////////////////////////////////////////////////////////////////////////////////
if (wParam == ID_LIST_BOX) {
DRAWITEMSTRUCT *drawStruct = (DRAWITEMSTRUCT*)lParam;
drawItem(drawStruct->hwndItem, drawStruct);
return TRUE;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
break;
}
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
EndPaint(hWnd, &ps);
}
break;
case WM_MEASUREITEM: {
if (wParam == ID_LIST_BOX) {
MEASUREITEMSTRUCT *measureStruct = (MEASUREITEMSTRUCT*)lParam;
measureStruct->itemHeight = 30;
measureStruct->itemWidth = 390;
return TRUE;
}
break;
}
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Here's an old trick: before invoking ScrollWindowEx() invalidate the entire listHandle area without erasing the background.
InvalidateRect(listHandle, NULL, FALSE);
ScrollWindowEx(...
Have a nice day!
From MSDN for ScrollWindowEx:
If the SW_INVALIDATE and SW_ERASE flags are not specified, ScrollWindowEx does not invalidate the area that is scrolled from. If either of these flags is set, ScrollWindowEx invalidates this area. The area is not updated until the application calls the UpdateWindow function, calls the RedrawWindow function (specifying the RDW_UPDATENOW or RDW_ERASENOW flag), or retrieves the WM_PAINT message from the application queue.
So let's look at what you tried:
UpdateWindow() - screenshoot attached
Nothing got invalidated, so the update region is empty, so UpdateWindow does nothing.
RedrawWindow with all possible options - window is painted only once
If called correctly, this should invalidate the client. You can cause the WM_ERASEBKGND to happen immediately, but the WM_PAINT message will come only when there's nothing else in the queue. I suspect this didn't work because the WM_TIMER takes priority over the WM_PAINT. (Both are special messages in that they are not actually posted but synthesized when you call GetMessage and nothing else is pending.)
InvalidateRect + UpdateWindow = same as 2
I would expect this to work, but it seems to make more sense to pass the flags to ScrollWindowEx to get the invalidation. I think what's happening is that the control is not designed to draw the items an non-integral positions. So you're getting invalidation, but the window is attempting to draw the items at different offsets than you expect. I don't see an straightforward way to solve this.
InvalidateRect + SendMessage(hwnd, WM_PAINT, 0, 0) - same as 2
That's not a valid WM_PAINT message. Don't do that.
The problem is that ListView is created using the LVS_REPORT flag. This means that list cannot scroll smoothly but only in lines. I.e. if line height is, for instance, 25, scrolling 20 pixels will make the list scroll 25 pixels.
One more issue is that ScrollWindowEx doesn't really scroll the list (or at least it wasn't used correctly). In order to scroll the list, the ListView_Scroll macro should be used (which again scrolls by lines not by pixels).

Menu item not working when compile as .dll

I have this odd behavior where my code was unable to call a event handler when i compile and run using JNI but it worked if i compile it as .exe in VS 2013.
The ones not working are listed under case ID_KRUSKAL_IMPERFECT, case ID_KRUSKAL_PERFECT, case ID_PRIM_IMPERFECT, case ID_PRIM_PERFECT. This cases are menu's (see image below for illustration ). By right it is suppose to pop up another dialog box
However, when i clicked case ID_FILE_EXIT the window closed (so it worked for this button)
Source code as attached :
#include <windows.h>
#include <iostream>
#include <string>
#include <fstream>
//#include "resource.h"
#include "maze.h"
#include <sstream>
#include <vector>
#include "HelloWorld.h"
#include "win_main.h"
#include "KruskalAlgo.h"
#include "PrimAlgo.h"
//JNI
#include <jni.h>
#include <stdio.h>
#include "Window.h"
//win32 GUI ID
#define IDR_MENU1 102
#define IDI_ICON1 103
#define IDD_DIALOG1 105
#define IDC_EDIT1 1005
#define IDC_WIDTH 1005
#define IDC_EDIT2 1006
#define IDC_EDIT3 1007
#define IDC_WALLBUTTON 1008
#define IDC_PATHBUTTON 1009
#define IDC_EDIT4 1010
#define IDC_HEIGHT 1010
#define ID_STUFF_GO 40001
#define ID_FILE_EXIT 40002
#define ID_FILE_GENERATEMAZE 40003
#define ID_FILE_UPLOADMAZE 40004
#define ID_GENERATEMAZE_KRUSKAL 40005
#define ID_GENERATEMAZE_PRIM 40006
#define ID_GENERATEMAZE_KRUSKAL40007 40007
#define ID_GENERATEMAZE_PRIM40008 40008
#define ID_GENERATEMANUALLY_KRUSKAL 40009
#define ID_GENERATEMANUALLY_PRIM 40010
#define ID_KRUSKAL_PERFECT 40011
#define ID_KRUSKAL_IMPERFECT 40012
#define ID_PRIM_PERFECT 40013
#define ID_PRIM_IMPERFECT 40014
#define ID_GENERATEMAZEAUTO 40015
//class name
LPCSTR g_szClassName = "mazeGenerator";
//2d vector to store 1s and 0s
typedef std::vector<std::vector<int>> IntMatrix;
IntMatrix vector2D;
//function header
void drawMaze(HWND hwnd);
void fileUpload(HWND hwnd);
void chooseColour(HWND hwnd);
//global height
int inRowCount;
//global width
int inColCount;
int disp;
PrimAlgo p;
PrimAlgo pi;
KruskalAlgo k;
KruskalAlgo ki;
INT_PTR CALLBACK ConfigDialog(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
//HWND hWndComboBox;
switch (Message)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_WALLBUTTON:
chooseColour(hwnd);
break;
case IDC_PATHBUTTON:
chooseColour(hwnd);
break;
case IDOK:
inColCount = GetDlgItemInt(hwnd, IDC_WIDTH, NULL, FALSE);
inRowCount = GetDlgItemInt(hwnd, IDC_HEIGHT, NULL, FALSE);
EndDialog(hwnd, IDD_DIALOG1);
break;
case IDCANCEL:
EndDialog(hwnd, IDD_DIALOG1);
break;
default:
return FALSE;
}
default:
return FALSE;
}
return TRUE;
}
// Step 4: the Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
HWND temp;
HINSTANCE htemp;
switch (msg)
{
case WM_CREATE:
{
//initialization
HMENU hMenu, hSubMenu1, hSubMenu2, hSubMenu3, hSubMenu4, hSubMenu5;
HICON hIcon, hIconSm;
//menu
hMenu = CreateMenu();
hSubMenu1 = CreatePopupMenu();
hSubMenu2 = CreatePopupMenu();
hSubMenu3 = CreatePopupMenu();
hSubMenu4 = CreatePopupMenu();
hSubMenu5 = CreatePopupMenu();
AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu1, "&File");
AppendMenu(hSubMenu1, MF_STRING | MF_POPUP, (UINT)hSubMenu2, "&New Game");
AppendMenu(hSubMenu2, MF_STRING, ID_GENERATEMAZEAUTO, "&Generate Automatically");
AppendMenu(hSubMenu2, MF_STRING | MF_POPUP, (UINT)hSubMenu3, "&Generate Manually");
AppendMenu(hSubMenu3, MF_STRING | MF_POPUP, (UINT)hSubMenu4, "&Kruskal");
AppendMenu(hSubMenu4, MF_STRING, ID_KRUSKAL_PERFECT, "&Perfect");
AppendMenu(hSubMenu4, MF_STRING, ID_KRUSKAL_IMPERFECT, "&Imperfect");
AppendMenu(hSubMenu3, MF_STRING | MF_POPUP, (UINT)hSubMenu5, "&Prim's");
AppendMenu(hSubMenu5, MF_STRING, ID_KRUSKAL_PERFECT, "&Perfect");
AppendMenu(hSubMenu5, MF_STRING, ID_KRUSKAL_IMPERFECT, "&Imperfect");
AppendMenu(hSubMenu1, MF_STRING, ID_FILE_EXIT, "&Exit");
/*hSubMenu = CreatePopupMenu();
AppendMenu(hSubMenu, MF_STRING, ID_STUFF_GO, "&Go");
AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "&Stuff");*/
SetMenu(hwnd, hMenu);
hIcon = (HICON)LoadImage(NULL, "logo.ico", IMAGE_ICON, 32, 32, LR_LOADFROMFILE);
if (hIcon)
SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
else
MessageBox(hwnd, "Could not load large icon!", "Error", MB_OK | MB_ICONERROR);
hIconSm = (HICON)LoadImage(NULL, "logo.ico", IMAGE_ICON, 16, 16, LR_LOADFROMFILE);
if (hIconSm)
SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIconSm);
else
MessageBox(hwnd, "Could not load small icon!", "Error", MB_OK | MB_ICONERROR);
}
break;
case WM_PAINT:
{
drawMaze(hwnd);
}
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case ID_FILE_EXIT:
PostMessage(hwnd, WM_CLOSE, 0, 0);
break;
case ID_GENERATEMAZEAUTO:
fileUpload(hwnd);
InvalidateRect(hwnd, 0, TRUE);
SetWindowPos(hwnd, 0, 0, 0, (inColCount * 10) + 17, (inRowCount * 10) + 60, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
break;
case ID_PRIM_PERFECT:
disp = DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG1), hwnd, ConfigDialog);
p.setDimension(inRowCount, inColCount);
p.setWallPath(0, 1);
p.generateMaze();
vector2D = p.get2DOutput();
InvalidateRect(hwnd, 0, TRUE);
SetWindowPos(hwnd, 0, 0, 0, (inColCount * 10) + 17, (inRowCount * 10) + 60, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
break;
case ID_PRIM_IMPERFECT:
disp = DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG1), hwnd, ConfigDialog);
pi.setDimension(inRowCount, inColCount);
pi.setWallPath(0, 1);
pi.generateMaze();
pi.generateImperfect();
vector2D = pi.get2DOutput();
InvalidateRect(hwnd, 0, TRUE);
SetWindowPos(hwnd, 0, 0, 0, (inColCount * 10) + 17, (inRowCount * 10) + 60, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
break;
case ID_KRUSKAL_PERFECT:
disp = DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG1), hwnd, ConfigDialog);
k.setDimension(inRowCount, inColCount);
k.setWallPath(0, 1);
k.generateMaze();
vector2D = k.get2DOutput();
InvalidateRect(hwnd, 0, TRUE);
SetWindowPos(hwnd, 0, 0, 0, (inColCount * 10) + 17, (inRowCount * 10) + 60, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
break;
case ID_KRUSKAL_IMPERFECT:
disp = DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG1), hwnd, ConfigDialog);
ki.setDimension(inRowCount, inColCount);
ki.setWallPath(0, 1);
ki.generateMaze();
ki.generateImperfect();
vector2D = ki.get2DOutput();
InvalidateRect(hwnd, 0, TRUE);
SetWindowPos(hwnd, 0, 0, 0, (inColCount * 10) + 17, (inRowCount * 10) + 60, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
break;
}
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;
//Step 1: Registering the Window Class
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
wc.lpszClassName = g_szClassName;
wc.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON1));
wc.hIconSm = (HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON1), IMAGE_ICON, 16, 16, 0);
if (!RegisterClassEx(&wc))
{
MessageBoxA(NULL, "Window Registration Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
// Step 2: Creating the Window
hwnd = CreateWindowEx(
WS_EX_WINDOWEDGE,
g_szClassName,
"Maze Generator 0.1",
WS_OVERLAPPEDWINDOW,
0, 0, 300, 60,
NULL, NULL, hInstance, NULL);
if (hwnd == NULL)
{
MessageBoxA(NULL, "Window Creation Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// Step 3: The Message Loop
while (GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
//draws maze based on vector2D
void chooseColour(HWND hwnd){
CHOOSECOLOR cc; // common dialog box structure
static COLORREF acrCustClr[16]; // array of custom colors
HBRUSH hbrush; // brush handle
static DWORD rgbCurrent; // initial color selection
ZeroMemory(&cc, sizeof(cc));
cc.lStructSize = sizeof(cc);
cc.hwndOwner = hwnd;
cc.lpCustColors = (LPDWORD)acrCustClr;
cc.rgbResult = rgbCurrent;
cc.Flags = CC_FULLOPEN | CC_RGBINIT;
if (ChooseColor(&cc) == TRUE)
{
hbrush = CreateSolidBrush(cc.rgbResult);
rgbCurrent = cc.rgbResult;
}
}
void drawMaze(HWND hwnd){
RECT rcClient;
GetClientRect(hwnd, &rcClient);
PAINTSTRUCT ps;
//starting x and y value for first maze cell
int startRow = 0;
int startCol = 0;
//displacement
int dRow = 10;
int dCol = 10;
//counter
int rowCounter = 0;
int colCounter = 0;
HDC hdc = BeginPaint(hwnd, &ps);
FillRect(hdc, &rcClient, (HBRUSH)GetStockObject(LTGRAY_BRUSH));
for (int rowId = 0; rowId < inRowCount; rowId++){
for (int colId = 0; colId < inColCount; colId++){
if (vector2D[rowId][colId] == 1){
RECT cell = { startCol, startRow, startCol + dCol, startRow + dRow };
FillRect(hdc, &cell, (HBRUSH)GetStockObject(WHITE_BRUSH));
}
if (vector2D[rowId][colId] == 0){
RECT cell = { startCol, startRow, startCol + dCol, startRow + dRow };
FillRect(hdc, &cell, (HBRUSH)GetStockObject(BLACK_BRUSH));
}
startCol += dCol;
colCounter++;
if (colCounter == inColCount)
{
startCol = 0;
colCounter = 0;
}
}
startRow += dRow;
rowCounter++;
if (rowCounter == inRowCount)
{
startRow = 0;
rowCounter = 0;
}
}
EndPaint(hwnd, &ps);
}
void fileUpload(HWND hwnd){
//file upload
OPENFILENAME ofn;
HANDLE hFile;
DWORD dwRead;
char filechar[20000] = "";
int countMaze = 0;
int countValue = 0;
int x = 0;
int y = 0;
int tempx = 0;
int tempy = 0;
char szFileName[MAX_PATH] = "";
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn); // SEE NOTE BELOW
ofn.hwndOwner = hwnd;
ofn.lpstrFilter = (LPCSTR)"Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0";
ofn.lpstrFile = (LPSTR)szFileName;
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
ofn.lpstrDefExt = (LPCSTR)"txt";
if (GetOpenFileName(&ofn))
{
// Load the file name for maze drawing
// Load the file name for maze drawing
//MessageBox(hWnd, (LPCWSTR)szFileName, (LPCWSTR)L"Notice",MB_OK | MB_ICONINFORMATION);
hFile = CreateFile((LPCSTR)szFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
ReadFile(hFile, filechar, sizeof(filechar), &dwRead, NULL);
int status = 1;//to track invalid input detected in the readfile
while (dwRead != countMaze)
{
char temp;
//temp in ASCII value (convert to 0 and 1)
temp = *&filechar[countMaze];
if (temp != '\r' && temp != '\n' && temp != '0' && temp != '1')
{
status = 0;
break;
}
if (temp == '\r')//For carriage return case.
{
countMaze = countMaze + 1;
continue;
}
if (temp == '\n')//For newline case.
{
y = dwRead / (x + 2);
break;
}
x = x + 1;
countMaze = countMaze + 1;
}
//return the width and height needed to print maze.
if (status == 1){
inColCount = x;
inRowCount = y;
//resize maze based on x and y values.
vector2D.resize(y);
for (int i = 0; i < y; i++){
vector2D[i].resize(x);
}
while (dwRead > countValue)
{
char temp;
//temp in ASCII value
temp = *&filechar[countValue];
if (temp)
if (temp == '\r')//For carriage return case.
{
countValue++;
continue;
}
if (temp == '\n')//For newline case.
{
countValue++;
tempx++;
tempy = 0;
continue;
}
//minus 48 to convert from ascii value to integer
vector2D[tempx][tempy] = int(temp - 48);
tempy = tempy + 1;
countValue++;
}
}
else{
MessageBox(hwnd, (LPCSTR)"Invalid maze file found ! Re-upload please with text file containing 0 and 1 only please", (LPCSTR)"Notice",
MB_OK | MB_ICONINFORMATION);
}
if (status == 1){
//close hFile handler
CloseHandle(hFile);
}
}
}
// Implementation of native method sayHello() of HelloJNI class
JNIEXPORT void JNICALL Java_Window_load(JNIEnv *env, jobject thisObj) {
WinMain(0,0,0,1);
printf("Hello World!\n");
return;
}
It doesn't work because the hInstance passed to WinMain is NULL in Java_Window_load(). You need to use the HINSTANCE of the DLL or else resources like your menus won't work.
Do something like this:
static HINSTANCE sDllInstance;
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
if (fdwReason == DLL_PROCESS_ATTACH) {
sDllInstance = hinstDLL;
}
return TRUE;
}
// Implementation of native method sayHello() of HelloJNI class
JNIEXPORT void JNICALL Java_Window_load(JNIEnv *env, jobject thisObj) {
WinMain(sDllInstance,0,0,1);
printf("Hello World!\n");
return;
}

C++ & WinApi - Text output from the keyboard to the screen in the created window

I do not see where the error is. The window display only the first character you type, and the other is not. Although the cursor moves when typing. And when minimize and maximize the window, the text becomes visible.
#include <windows.h>
#define IDI_MYICON 201
#define IDR_MYMENU 201
#define ID_FIO_FirstName 4002
#define ID_FIO_SecondName 4003
#define ID_FIO_Name 4001
#define ID_INFO_DeveloperStatus 9002
#define ID_INFO_LearningForm 9003
#define ID_INFO_Group 9004
#define BUFSIZE 6665535
#define SHIFTED 0x8000
const char g_szClassName[] = "MFW";
LONG APIENTRY WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
TEXTMETRIC tm;
static DWORD dwCharX;
static DWORD dwCharY;
static DWORD dwClientX;
static DWORD dwClientY;
static DWORD dwLineLen;
static int nCaretPosX = 0;
static int nCaretPosY = 0;
static int nCharWidth = 0;
static int cch = 0;
static int nCurChar = 0;
static PTCHAR pchInputBuf;
int i, j;
int cCR = 0;
int nCRIndex = 0;
int nVirtKey;
TCHAR szBuf[128];
TCHAR ch;
PAINTSTRUCT ps;
RECT rc;
SIZE sz;
COLORREF crPrevText;
COLORREF crPrevBk;
switch(Message)
{
case WM_CREATE:
{
hdc = GetDC(hwnd);
GetTextMetrics(hdc, &tm);
ReleaseDC(hwnd, hdc);
dwCharX = tm.tmAveCharWidth;
dwCharY = tm.tmHeight;
pchInputBuf=(LPTSTR)GlobalAlloc(GPTR,BUFSIZE*sizeof(TCHAR));
HMENU hMenu, hSubMenu;
HICON hIcon, hIconSm;
hMenu = CreateMenu();
hSubMenu = CreatePopupMenu();
AppendMenu(hSubMenu, MF_STRING, ID_FIO_FirstName, "FirstName");
AppendMenu(hSubMenu, MF_STRING, ID_FIO_SecondName, "SecondName");
AppendMenu(hSubMenu, MF_STRING, ID_FIO_Name, "Name");
AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "&FIO");
hSubMenu = CreatePopupMenu();
AppendMenu(hSubMenu, MF_STRING, ID_INFO_DeveloperStatus, "DeveloperStatus");
AppendMenu(hSubMenu, MF_STRING, ID_INFO_LearningForm, "LearningForm");
AppendMenu(hSubMenu, MF_STRING, ID_INFO_Group, "Group");
AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "&INFO");
SetMenu(hwnd, hMenu);
hIcon =(HICON)LoadImage(NULL, "my_icon.ico", IMAGE_ICON, 32, 32, LR_LOADFROMFILE);
if(hIcon)
SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
else
MessageBox(hwnd, "Could not load large icon!","Error", MB_OK | MB_ICONERROR);
hIconSm =(HICON)LoadImage(NULL, "my_icon.ico", IMAGE_ICON, 16, 16, LR_LOADFROMFILE);
if(hIconSm)
SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIconSm);
else
MessageBox(hwnd, "Could not load small icon!","Error", MB_OK | MB_ICONERROR);
break;
}
break;
case WM_PAINT:
if (cch==0)break;
hdc=BeginPaint(hwnd,&ps);
HideCaret(hwnd);
SetRect(&rc, 0, 0, dwLineLen, dwClientY);
DrawText(hdc, pchInputBuf,-1,&rc,DT_NOCLIP);
ShowCaret(hwnd);
EndPaint(hwnd, &ps);
break;
case WM_SIZE:
dwClientX=LOWORD(lParam);
dwClientY = HIWORD(lParam);
dwLineLen=dwClientX-dwCharX;
break;
case WM_SETFOCUS:
CreateCaret(hwnd, (HBITMAP) 0,3, dwCharY);
SetCaretPos(nCaretPosX,nCaretPosY*dwCharY);
ShowCaret(hwnd);
break;
case WM_KILLFOCUS:
HideCaret(hwnd);
DestroyCaret();
break;
case WM_CHAR:
if (cch > BUFSIZE-5)
{
pchInputBuf[cch] = 0x00;
SendMessage(hwnd,WM_PAINT, 0, 0);
}
switch (wParam)
{
case 0x08:
case 0x0A:
case 0x1B:
MessageBeep(0xFFFFFFFF);
return 0;
case 0x09:
for (i = 0; i < 4; i++)
SendMessage(hwnd, WM_CHAR, 0x20, 0);
return 0;
case 0x0D:
pchInputBuf[cch++] = 0x0D;
nCaretPosX = 0;
nCaretPosY += 1;
break;
default:
ch =(TCHAR)wParam;
HideCaret(hwnd);
hdc = GetDC(hwnd);
GetCharWidth32(hdc,wParam,wParam,&nCharWidth);
DrawText(hdc, pchInputBuf,-1,&rc, DT_NOCLIP);
ReleaseDC(hwnd, hdc);
pchInputBuf[cch++] = ch;
nCaretPosX += nCharWidth;
if ((DWORD) nCaretPosX > dwLineLen)
{
nCaretPosX = 0;
pchInputBuf[cch++] = 0x0D;
++nCaretPosY;
}
nCurChar = cch;
ShowCaret(hwnd);
break;
}
SetCaretPos(nCaretPosX, nCaretPosY * dwCharY);
break;
case WM_KEYDOWN:
switch (wParam)
{
case VK_LEFT:
if (nCaretPosX > 0)
{
HideCaret(hwnd);
ch = pchInputBuf[--nCurChar];
hdc = GetDC(hwnd);
GetCharWidth32(hdc, ch, ch, &nCharWidth);
ReleaseDC(hwnd, hdc);
nCaretPosX = max(nCaretPosX - nCharWidth, 0);
ShowCaret(hwnd);
} break;
case VK_RIGHT:
if (nCurChar > cch) {
HideCaret(hwnd);
ch = pchInputBuf[nCurChar];
if (ch == 0x0D) {
nCaretPosX = 0;
nCaretPosY++;
}
else {
hdc = GetDC(hwnd);
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);
}
GetCharWidth32(hdc, ch, ch, &nCharWidth);
ReleaseDC(hwnd, hdc);
nCaretPosX = nCaretPosX + nCharWidth;
}
nCurChar++;
ShowCaret(hwnd);
break;
}
break;
case VK_HOME:
nCaretPosX = nCaretPosY = 0;
nCurChar = 0;
break;
case VK_END:
for (i=0; i < cch; i++)
{
if (pchInputBuf[i] == 0x0D) {
cCR++;
nCRIndex = i + 1;
}
}
nCaretPosY = cCR;
for (i = nCRIndex, j = 0; i < cch; i++, j++)
szBuf[j] = pchInputBuf[i];
szBuf[j] = TEXT('\0');
hdc = GetDC(hwnd);
GetTextExtentPoint32(hdc,szBuf,lstrlen(szBuf),&sz);
nCaretPosX = sz.cx;
ReleaseDC(hwnd, hdc);
nCurChar = cch;
break;
default:
break;
}
SetCaretPos(nCaretPosX, nCaretPosY * dwCharY);
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_FIO_FirstName:
MessageBox(hwnd, "F-3", "FirstName", 0);
break;
case ID_FIO_SecondName:
MessageBox(hwnd, "B-2", "SecondName", 0);
break;
case ID_FIO_Name:
MessageBox(hwnd, "A-1", "Name", 0);
break;
case ID_INFO_DeveloperStatus:
MessageBox(hwnd, "S", "DeveloperStatus", 0);
break;
case ID_INFO_LearningForm:
MessageBox(hwnd, "FORM", "LearningForm", 0);
break;
case ID_INFO_Group:
MessageBox(hwnd, "GR", "Group", 0);
break;
}
break;
case WM_CLOSE:
DestroyWindow(hwnd);
GlobalFree((HGLOBAL) pchInputBuf);
UnregisterHotKey(hwnd, 0xAAAA);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, Message, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
HWND hwnd;
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_MYICON));
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = MAKEINTRESOURCE(IDR_MYMENU);
wc.lpszClassName = g_szClassName;
wc.hIconSm = (HICON)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_MYICON),IMAGE_ICON,16,16, 0);
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, "Window Registration Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
hwnd = CreateWindowEx(
WS_EX_OVERLAPPEDWINDOW,
g_szClassName,
"QWERTY",
WS_OVERLAPPEDWINDOW,
200, 100, 800, 600,
NULL, NULL, hInstance, NULL);
if(hwnd == NULL)
{
MessageBox(NULL, "Window Creation Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
MSG Msg;
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
You use WM_PAINT incorrectly. You shouldn't send it manually. You need to call InvalidateRect(hwnd, NULL, true); instead of SendMessage(hwnd,WM_PAINT, 0, 0); and it will post a WM_PAINT message to your WndProc correctly.
When you minimize/maximize the window, Windows call internally something like InvalidateRect(hwnd, NULL, true);
Addition by manuell:
Also always call BeginPaint/EndPaint in WM_PAINT handler (you shouldn't break before calling BeginPaint/EndPaint).