So I'm creating a program, where 5 rectangles are spawned and they move in different directions like DVD Screensaver.
The problem is when I start moving them in infinite loop the program stops working not allowing any input to be made. If I make the loop not infinite, it will stop working until the loop ends, and after that the program allows you to do something.
I think the problem is in the way I try to move the rectangles, but I'm not sure.
void MovePredator(HDC hdc, PAINTSTRUCT ps,int size, int amount)
{
for (;;)
{
FillRect(hdc, &ps.rcPaint, (HBRUSH)(1));
for (int i = 0; i < amount; ++i)
{
int Offset = size / 2;
if (Predator[i].LocationX - Offset == 0 || Predator[i].LocationX + Offset == 1420)
{
Predator[i].MoveX *= -1;
}
if (Predator[i].LocationY - Offset == 0 || Predator[i].LocationY + Offset == 700)
{
Predator[i].MoveY *= -1;
}
Predator[i].LocationX += Predator[i].MoveX;
Predator[i].LocationY += Predator[i].MoveY;
Rectangle(hdc, Predator[i].LocationX - Offset, Predator[i].LocationY - Offset, Predator[i].LocationX + Offset, Predator[i].LocationY + Offset);
}
Sleep(10);
}
}
void SpawnPredator(HDC hdc, int size, int amount)
{
int Offset = size / 2;
for (int i = 0; i < amount; ++i)
{
Predator[i].LocationX = rand() % 1300 + 50;
Predator[i].LocationY = rand() % 600 + 50;
Predator[i].MoveX = rand()%2;
Predator[i].MoveY = rand()%2;
if (Predator[i].MoveX == 0) Predator[i].MoveX = -1;
if (Predator[i].MoveY == 0) Predator[i].MoveY = -1;
Rectangle(hdc, Predator[i].LocationX - Offset, Predator[i].LocationY - Offset, Predator[i].LocationX + Offset, Predator[i].LocationY + Offset);
}
}
This is how the loop interacts (I deleted cases that it doesn't interact with)
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
srand(time(NULL));
// TODO: Добавьте сюда любой код прорисовки, использующий HDC...
SpawnPredator(hdc, 50, 5);
MovePredator(hdc, ps, 50, 5);
EndPaint(hWnd, &ps);
}
}
}
The reason of this application hang is in nature of Windows application event based design.
What is going on at the background, any windows application is not allowed to access any hardware directly unlike operating system which able to run only one program at time like DOS for example. This is needed to share hardware like video card or mouse between multiple programs. Instead of the direct access to hardware, Windows kernel manipulate the hardware itself when running applications sending special request to the kernel (system calls), Win API is actually a set of functions can be used to send such request to the kernel.
When your application creates or draws into a Window, it actually asking operating system kernel to do it. Kernel select when and how to process this operation, and then use video card device driver to draw (over the hardware abstraction layer or special fast APIs like OpenGL or Direct X etc.).
Another thing - how application would know if user do some input using a mouse or keyboard. Windows stores those inputs in the special internal queue of structures - called events, each application thread have such a queue.
Application itself should have a loop which waits for an OS event, and react on them - such loops called run loop and usually looks like following:
MSG messages; // Here messages to the application are saved
// Run the message loop. It will run until GetMessage() returns 0
while (GetMessage (&messages, NULL, 0, 0))
{
/* Translate virtual-key messages into character messages */
TranslateMessage(&messages);
/* Send message to WindowProcedure */
DispatchMessage(&messages);
}
If you are using a library like MFC this loop is provided by the library, however it is still exist.
When you have created a window, you or your library – register a WindowProcedure callback function, this function react on messages run loop send to a window object like WM_PAINT. Such function usually calls to DefWindowProc function when your program don’t needs to handle some specific event.
WM_PAINT occurs when you maximize, minimize, restores or show hide a window, or you can send this message to window yourself using SendMessage function.
If you will do an infinity loop, or block a thread doing the run loop during handling a message – it will freezes run loop, as well as DefWindowProc or another custom messages handling would not be called when they needs to be called, and your application hangs.
Following MSDN article shows how to make an animation you’d like to implement.
DO NOT perform infinite loops inside of a UI message handler. This is the main reason why your app does not work. You are not allowing your app to stay responsive to messages from the OS.
Also, DO NOT perform non-drawing logic inside a paint handler. Updating your predators is not a task that belongs in your WM_PAINT event at all. Use a timer instead, and have it invalidate the window to trigger a repaint whenever a change occurs. Simply paint the existing predators as-is whenever you are asked to paint the window.
Also, your WndProc() is missing a call to DefWindowProc() for all unhandled messages.
Try something more like this:
void MovePredator(int size, int amount)
{
int Offset = size / 2;
for (int i = 0; i < amount; ++i)
{
if (Predator[i].LocationX - Offset == 0 || Predator[i].LocationX + Offset == 1420)
{
Predator[i].MoveX *= -1;
}
if (Predator[i].LocationY - Offset == 0 || Predator[i].LocationY + Offset == 700)
{
Predator[i].MoveY *= -1;
}
Predator[i].LocationX += Predator[i].MoveX;
Predator[i].LocationY += Predator[i].MoveY;
}
}
void SpawnPredator(int amount)
{
for (int i = 0; i < amount; ++i)
{
Predator[i].LocationX = rand() % 1300 + 50;
Predator[i].LocationY = rand() % 600 + 50;
Predator[i].MoveX = rand() % 2;
Predator[i].MoveY = rand() % 2;
if (Predator[i].MoveX == 0)
Predator[i].MoveX = -1;
if (Predator[i].MoveY == 0)
Predator[i].MoveY = -1;
}
}
void PaintPredator(HDC hdc, int size, int amount)
{
int Offset = size / 2;
for (int i = 0; i < amount; ++i)
{
Rectangle(hdc, Predator[i].LocationX - Offset, Predator[i].LocationY - Offset, Predator[i].LocationX + Offset, Predator[i].LocationY + Offset);
}
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
srand(time(NULL));
SetTimer(hWnd, 1, 10, NULL);
return 0;
case WM_TIMER:
SpawnPredator(5);
MovePredator(50, 5);
InvalidateRect(hWnd, NULL);
return 0;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(1));
PaintPredator(hdc, 50, 5);
EndPaint(hWnd, &ps);
return 0;
}
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
Thanks to everyone who helped. This is my final setup (I will edit this post if I find a better way to do this)
#define STEP 1
int idtimer = -1;
struct Mob
{
int LocationX = 0;
int LocationY = 0;
int MoveX = 0;
int MoveY = 0;
};
struct Mob Predator[100];
void SpawnPredator(int amount)
{
for (int i = 0; i < amount; ++i)
{
Predator[i].LocationX = rand() % 1300 + 50;
Predator[i].LocationY = rand() % 600 + 50;
Predator[i].MoveX = rand() % 2;
Predator[i].MoveY = rand() % 2;
if (Predator[i].MoveX == 0) Predator[i].MoveX = -STEP;
else Predator[i].MoveX = STEP;
if (Predator[i].MoveY == 0) Predator[i].MoveY = -STEP;
else Predator[i].MoveY = STEP;
}
}
void MovePredator(int size, int amount)
{
for (int i = 0; i < amount; ++i)
{
int Offset = size / 2;
if (Predator[i].LocationX - Offset <= 0 || Predator[i].LocationX + Offset >= 1420)
{
Predator[i].MoveX *= -1;
}
if (Predator[i].LocationY - Offset <= 0 || Predator[i].LocationY + Offset >= 700)
{
Predator[i].MoveY *= -1;
}
Predator[i].LocationX += Predator[i].MoveX;
Predator[i].LocationY += Predator[i].MoveY;
}
}
void PaintPredator(HDC hdc, int size, int amount)
{
for (int i = 0; i < amount; ++i)
{
int Offset = size / 2;
Rectangle(hdc, Predator[i].LocationX - Offset, Predator[i].LocationY - Offset, Predator[i].LocationX + Offset, Predator[i].LocationY + Offset);
}
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
srand(time(NULL));
switch (message)
{
case WM_CREATE:
{
SpawnPredator(5);
SetTimer(hWnd, idtimer = 1, 10, NULL);
}
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Разобрать выбор в меню:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_TIMER:
{
MovePredator(50, 5);
InvalidateRect(hWnd, NULL, FALSE);
break;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(4));
PaintPredator(hdc, 50, 5);
//Rectangle(hdc, 0, 10, 20, 30);
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
Related
I have the following WNDPROC:
LRESULT CALLBACK window_processing(HWND window, UINT message, WPARAM wPara, LPARAM lParam) {
#if WITH_DEBUG_UI
if(ImGui_ImplWin32_WndProcHandler(window, message, wPara, lParam)) {
return true;
}
#endif
switch(message) {
case WM_QUIT:
PostQuitMessage(0);
close_window();
exit();
return true;
break;
case WM_SIZE: {
auto new_size = get_window_size();
if(app.resize_handler) {
app.resize_handler(new_size.width, new_size.height);
return true;
}
break;
}
case WM_SIZING: {
RECT new_rect = *((LPRECT)(lParam));
GetClientRect(app.wnd, &new_rect);
auto new_size = window_size{std::size_t(new_rect.right - new_rect.left), std::size_t(new_rect.bottom - new_rect.top)};
if(app.resize_handler) {
app.resize_handler(new_size.width, new_size.height);
return true;
}
} break;
}
return DefWindowProc(window, message, wPara, lParam);
}
app.resize_handler is the following function:
void d3d11_loading_screen_renderer::window_size_changed(const std::size_t w, const std::size_t h) {
std::cout << "W : " << w << " H : " << h << std::endl;
back_buffer_rtv.Reset();
back_buffer.Reset();
swapchain->ResizeBuffers(0, w, h, DXGI_FORMAT_UNKNOWN, 0);
swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), &back_buffer);
back_buffer_rtv = create_back_buffer_rtv(device.Get(), back_buffer.Get());
back_buffer_viewport = viewport_from_window_size(window_size{w,h});
}
The WM_SIZE event is correctly handled; When the resizing is finished, the back buffers are correctly resized and refreshed.
But with WM_SIZING, nothing happens. the back buffer stays the same size, as seen in the following gif:
You can see how it resizes the buffers correctly when i finish resizing, but not during the resizing.
Anyone know what that could cause?
Edit: i dont receive any errors and the received size is correct.
I have the following problem with retrieving the window handle from a specific window (title and class name are known):
There are two identical windows with different handles under two different processes, but FindWindow() can find the handle only from the newest window spawned, never from the first one.
What can be used instead? Can EnumWindows() be used to retrieve a list of windows with the same characteristics?
Use the Win32 API EnumWindows , and then check which process each window belongs to by using the Win32 API GetWindowThreadProcessId.
Here is a sample:
#include <iostream>
#include <Windows.h>
using namespace std;
BOOL CALLBACK enumProc(HWND hwnd, LPARAM) {
TCHAR buf[1024]{};
GetClassName(hwnd, buf, 100);
if (!lstrcmp(buf, L"Notepad"))
{
GetWindowText(hwnd, buf, 100);
DWORD pid = 0;
GetWindowThreadProcessId(hwnd, &pid);
wcout << buf << " " << pid << endl;
}
return TRUE;
}
int main() {
EnumWindows(&enumProc, 0);
}
If you need to check the window of each process, you can refer to this answer.
typedef struct
{
const char *name;
const char *class;
HWND handles[10];
int handlesFound;
} SearchWindowInfo;
SearchWindowInfo wi;
wi.handlesFound = 0;
wi.title = "WindowName";
wi.class = "ClassName";
BOOL CALLBACK searchWindowCallback(HWND hwnd, LPARAM lParam)
{
SearchWindoInfo *wi = (SearchWindoInfo *)lParam;
char buffer[256];
if (wi->handlesFound == 10)
return FALSE;
buffer[255] = 0;
if (wi->name)
{
int rc = GetWindowText(hwnd, buffer, sizeof(buffer)-1);
if(rc)
{
if (strcmp(wi->name, buffer) == 0)
{
wi->handles[wi->handlesFound++] = hwnd;
return TRUE;
}
}
}
if (wi->class)
{
int rc = GetClassName (hwnd, buffer, sizeof(buffer)-1);
if(rc)
{
if (strcmp(wi->class, buffer) == 0)
{
wi->handles[wi->handlesFound++] = hwnd;
return TRUE;
}
}
}
return TRUE;
}
EnumWindows(searchWindowCallback, (LPARAM)&wi);
for(int i = 0; i < wi.handlesFound; i++)
{
// yeah...
}
I'm writing code for what should be a tetris game. It's early on, and right now it only displays a single piece (the piece that would be "falling" at that point), which is all it should do. The up arrow allows you to cycle forward (specifically only) through a randomly generated sequence of pieces (using the "bag" method). And, using the left and right arrows, you can rotate the pieces. Anyways, it's coded on a win32 platform, and I've found that after a certain number of frames (running WM_PAINT) the main HDC turns null and everything stops. It takes roughly twice as many frames of holding down the right or left arrow keys to achieve this as it does to hold down the up arrow key. Something odd is that after about 1000 frames the area of the console that I'm actively painting over (a 600x600 px frame) will go black (the hdc has not been nullified yet), and it's only when the up arrow is pressed that the hdc is nullified. What I suspect to be the problem is that the methods called when the up arrow key is pressed pass the hdc as a parameter to the in-class methods (tell me if this is poor practice or there's something I should be doing instead). I think the hdc might be corrupting or something (honestly I have no idea). The left and right arrow keys don't directly call methods with HDC's as a parameter. Because of case labels and how the win32 template is designed, I have to store an HDC who's scope falls out of any case-label, so that I can access the window's handle outside of the paint case (I feel like this is poor practice, but I'd like to understand why before I go out of my way to find a new way). I'll post the code, the stored HDC is called mainHDC, and it's defined just before the main case statement. To clue you in, I'll give an overview of the code structure:
The main .cpp file, which contains the basic win32 program, calls the Tetris class constructor in WM_PAINT and stores it universally like the mainHDC is and, when prompted, the "next" method (which brings the next piece), the "turnPiece" method (which rotates the piece clockwise or counter-clockwise based on the paramter), and the "paint" method which updates the screen, repainting the current piece. In the tetris class (which is in it's own header file), there is a sub-class called "pieces" which contain information about its objects, that are defined by another level of sub-classes named with a single character depicted by the pieces shape. The shape, color, and size of the pieces are stored in a 2d array of pointers (using COLORREF). "Pieces" contains its own "DrawObject" method which draws the object that calls it (which like all of the drawing/painting methods have an HDC as an argument). There's also a method that rotates the shape called "turnTet" (the "turnPiece" method relays the call from the main .cpp file to "pieces"). The only other applicable methods are those found in the "tetris" class which are "paint" and "next" (they ultimately paint the object). The WM_KEY cases, excluding the VK_UP case, don't use the saved hdc but rather use InvalidateRect().
Here's the applicable part of the .cpp file
int tempt = 2;
int tempvar = 0;
tetris *mainOBJ;
HDC mainHDC;
HDC testHDC;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_KEYDOWN:
switch (wParam) {
case VK_LEFT:
mainOBJ->turnPiece(false);
InvalidateRect(hWnd, 0, FALSE);
break;
case VK_RIGHT:
mainOBJ->turnPiece(true);
InvalidateRect(hWnd, 0, FALSE);
break;
case VK_UP:
mainOBJ->next(mainHDC);
InvalidateRect(hWnd, 0, FALSE);
break;
}
break;
case WM_COMMAND:
//Non-applicable & has not been changed
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
mainHDC = hdc;
HPEN oldP;
HPEN newP;
COLORREF qLC;
qLC = RGB(0, 0, 0);
newP = CreatePen(PS_SOLID, 1, qLC);
oldP = (HPEN) SelectObject(hdc, newP);
tempt++;
//USED FOR COUNTING FRAMES WITH DEBUGGER
if (tempt % 1 == 0) {
if (tempvar == 0) {
//CONSTRUCTOR CALL
mainOBJ = new tetris(hdc);
tempvar++;
}
//PAINT METHOD CALL
mainOBJ->paint(hdc);
}
if (hdc == NULL) {
int x = 3;
int y = x + 3; //SET DEBUG_BREAK POINT HERE
}
testHDC = hdc;
SelectObject(hdc, oldP);
DeleteObject(newP);
EndPaint(hWnd, &ps);
}
break;
}
}
The header file, which contains the Tetris and piece classes
class tetris {
public:
class pieces {
private:
COLORREF **test;
int size;
public:
//Abbreviated for space
class O {};
class I {};
class S {};
class Z {};
class T {};
class L {};
class J {};
void setSize(int a) {
//Initializing the piece-array
test = new COLORREF*[a];
size = a;
int i = 0;
while (i < a) {
test[i] = new COLORREF[a];
i++;
}
}
void setShape(COLORREF **shape) {
test = shape;
}
void setColor(HDC hdc, COLORREF rgb) {
HPEN Penn = CreatePen(PS_SOLID, 1, rgb);
HPEN Peno = (HPEN)SelectObject(hdc, Penn);
}
static pieces getObject(char type) {
pieces Gen;
switch (type) {
case 'O':
{
//Identical (almost) to the other cases
O pcs = O();
Gen = *pcs.getObject();
return Gen;
}
break;
case 'I':
case 'S':
case 'Z':
case 'T':
case 'L':
case 'J':
return pieces();
}
void turnTet(bool clockwise) {
int i = 0;
int s;
COLORREF **shape;
int ter = size - 1;
shape = new COLORREF*[2];
while (i < size) {
shape[i] = new COLORREF[2];
s = 0;
while (s < size) {
shape[i][s] = def;
s++;
}
i++;
}
i = 0;
while (i < size) {
s = 0;
while (s < size) {
if (clockwise) {
shape[s][ter - i] = test[i][s];
}
else {
shape[ter - s][i] = test[i][s];
}
s++;
}
i++;
}
test = shape;
}
void drawObject(HDC hWnd) {
int i = 0;
int s;
while (i < size) {
s = 0;
while (s < size) {
setColor(hWnd, test[i][s]);
int scaleOfBox = 90;
DrawBox((s + 1) * scaleOfBox, (i + 1) * scaleOfBox, scaleOfBox - 1, scaleOfBox - 1, hWnd);
s++;
}
i++;
}
}
void DrawBox(int x, int y, int w, int h, HDC hdc) {
if (h < 0) {
h *= -1;
}
if (w < 0) {
w *= -1;
}
int i = 0;
while (i < h) {
MoveToEx(hdc, x, y + i, NULL);
LineTo(hdc, x + w, y + i);
i++;
}
}
};
tetris(HDC hdc) {
refresh();
bagp[cur].drawObject(hdc);
}
void next(HDC hdc) {
bagp[cur].DrawBox(0, 0, 600, 600, hdc);
bagp[cur].drawObject(hdc);
cur++;
if (cur > 6) {
refresh();
}
}
void turnPiece(bool clockwise) {
bagp[cur].turnTet(clockwise);
}
void refresh() {
srand(time(NULL));
bag[0] = rand() % 7;
int i = 1;
while (i < 7) {
bool open = false;
cur = i;
while (!open) {
bag[i] = rand() % 7;
int s = 1;
open = true;
while (s <= i) {
if (bag[i] == bag[i - s]) {
open = false;
}
s++;
}
}
i++;
}
cur = 0;
while (cur < 7) {
switch (bag[cur]) {
case 0:
bagp[cur] = pieces::getObject('O');
break;
case 2:
bagp[cur] = pieces::getObject('T');
break;
case 1:
bagp[cur] = pieces::getObject('I');
break;
case 3:
bagp[cur] = pieces::getObject('S');
break;
case 4:
bagp[cur] = pieces::getObject('Z');
break;
case 5:
bagp[cur] = pieces::getObject('L');
break;
case 6:
bagp[cur] = pieces::getObject('J');
break;
}
cur++;
}
cur = 0;
}
void paint(HDC hdc) {
COLORREF temp = def;
bagp[cur].setColor(hdc, temp);
bagp[cur].DrawBox(0, 0, 600, 600, hdc);
bagp[cur].drawObject(hdc);
}
private:
int bag[7];
int cur;
pieces bagp[7];
};
I don't understand why the HDC nullifies like it does. Once again I suspect it's related to how the hdc is passed as a parameter or maybe how I'm saving the hdc. Help...please (and thank you).
Ooh, old school windows programming...
This may not be the entirety of the problem, but in your setColor function you're creating a Pen with CreatePen but never calling DeleteObject on it. This will leak the resource and eventually cause problems when Windows runs out of resource handles for objects.
Also, the Device Context returned by BeginPaint is (generally) only valid until EndPaint is called (unless you specify otherwise in the CreateWindow call, if I remember rightly). This can be another source of handle leakage.
In the Process tab of Task Manager, you can add the "GDI objects" column which will have an increasing number as your program runs if you're leaking handles. I saw this once with something I wrote way back when.
When Ever I compile my program it say "Debug Assertion Failed".
And when I click ignore twice my app shows up.
How can I fix it?
The whole code is below in case you want to test it for your self. The app increases in number as the scroll bar is moved to the right and decreases as the scroll bar is moved to the left. But my main problem is the debug assertion failed. If you can please post the part of the code that has problem and how I can fix it or fix it and post the code. Is there any way to get rid of that run time error with out using a try and catch. I mean to fix that problem please. This is a project and I have only a week and a half to do it. If you can help me with this project your help would be greatly appreciated. I am fairly new to visual c++. Part of the error is:
Program E:\BHCCHardwareStore\Debug\BHCCHardwareStore.exe FIle:f\dd\vctools\vc7libs\ship\atlmfc\src\mfc\appcore.cpp Line: 196. For information on how your program can cause an assertion failure see the Visual C++ documentation on asserts.
(Press Retry to debug the application).
Now when I click ignore it kind of displays the app perfectly fine. And the app seems to work just fine. How can I fix this error This code is not the entire code I am cutting and pasting?
#include "stdafx.h"
#include <strstream>
#include <afxwin.h>
#include <string.h>
const int IDC_SB1 = 100;
const int IDC_CS1 = 101;
const int IDC_CS2 = 102;
const int IDC_BUTTON = 103;
const int MIN_RANGE = 0;
const int MAX_RANGE = 100;
class CApp :public CWinApp
{
public:
virtual BOOL InitInstance();
};
CApp App;
class CSource :public CFrameWnd
{
CScrollBar*sb1;
CStatic* cs1;
CStatic* cs2;
CButton* button;
public:
CSource();
afx_msg void OnHScroll(UINT nSBCode,
UINT nPos, CScrollBar* pSccrollBar);
afx_msg void handleButton();
DECLARE_MESSAGE_MAP();
};
BEGIN_MESSAGE_MAP(CSource, CFrameWnd)
ON_WM_HSCROLL()
ON_BN_CLICKED(IDC_BUTTON, handleButton)
END_MESSAGE_MAP()
//Window cONSTRUCTOR
CSource::CSource()
{
}
void CSource::OnHScroll(UINT nSBCode,
UINT nPos, CScrollBar* pScrollBar)
{
int pos, dividend = 0, holder = 0, x = 0;
char array[9];
//;
pos = pScrollBar->GetScrollPos();
switch (nSBCode)
{
case SB_LINEUP:
pos -= 1;
break;
case SB_LINEDOWN:
pos += 1;
break;
case SB_PAGEUP:
pos -= 10;
break;
case SB_PAGEDOWN:
pos += 10;
break;
case SB_TOP:
pos = MIN_RANGE;
break;
case SB_BOTTOM:
pos = MAX_RANGE;
break;
case SB_THUMBTRACK:
pos = nPos;
break;
default:
return;
}
if (pos < MIN_RANGE)
pos = MIN_RANGE;
else if (pos > MAX_RANGE)
pos = MAX_RANGE;
sb1->SetScrollPos(pos, TRUE);
//Set the labels to the new values
char s[100];
TCHAR s1[100];
std::ostrstream ostr(s, 100);
ostr << "Decimal Value = " << pos << std::ends;
for (int i = 0; i < 100; i++){
s1[i] = (TCHAR) s[i];
}
SetDlgItemText(IDC_CS1, s1);
ostr.seekp(std::ios::beg);
dividend = pos;
for (int y = 0; y < 9; y++)
array[y] = '0';
int remainder = dividend % 2;
int quotient = dividend / 2;
array[x] = (char)(remainder + 48);
do
{
remainder = quotient % 2;
quotient = quotient / 2;
array[++x] = (char)(remainder + 48);
} while (quotient != 0);
array[8] = '\0';
ostr << "Binary Value = " << _strrev(array) << std::ends;
SetDlgItemText(IDC_CS2, s1);
}
void CSource::handleButton()
{
int result;
result = MessageBox(_T("Are you sure?"), _T("Exiting"),
MB_ICONQUESTION | MB_YESNO);
if (result == IDYES)
{
Beep(1000, 100);
DestroyWindow();
}
else
Beep(200, 100);
}
//Initialize the application and the main window
BOOL CApp::InitInstance()
{
m_pMainWnd = new CSource();
m_pMainWnd->ShowWindow(m_nCmdShow);
m_pMainWnd->UpdateWindow();
return TRUE;
}
Your code (in VS2013) produces assertion in MFC code:
BOOL CWnd::ShowWindow(int nCmdShow)
{
ASSERT(::IsWindow(m_hWnd) || (m_pCtrlSite != NULL));
From your call:
m_pMainWnd->ShowWindow(m_nCmdShow);
You must create your window first, before you can show it.
That's my callback function:
int CALLBACK SortMeAscending(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
int nRetVal = 0;
PITEMDATA pData1 = (PITEMDATA)lParam1;
PITEMDATA pData2 = (PITEMDATA)lParam2;
switch(lParamSort)
{
case 0:
if(pData1->iSeq < pData2->iSeq)
nRetVal = -1;
else if(pData1->iSeq > pData2->iSeq)
nRetVal = 1;
else
nRetVal = 0;
break;
case 1:
nRetVal = lstrcmp(pData2->pszCueName, pData1->pszCueName);
break;
case 2:
nRetVal = lstrcmp(pData2->pszTags, pData1->pszTags);
break;
default:
break;
}
return nRetVal;
}
int CALLBACK SortMeDescending(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
int nRetVal = 0;
PITEMDATA pData1 = (PITEMDATA)lParam1;
PITEMDATA pData2 = (PITEMDATA)lParam2;
switch(lParamSort)
{
case 0:
if(pData1->iSeq > pData2->iSeq)
nRetVal = -1;
else if(pData1->iSeq < pData2->iSeq)
nRetVal = 1;
else
nRetVal = 0;
break;
case 1:
nRetVal = lstrcmp(pData1->pszCueName, pData2->pszCueName);
break;
case 2:
nRetVal = lstrcmp(pData1->pszTags, pData2->pszTags);
break;
default:
break;
}
return nRetVal;
}
that's my OnCompareItems:
int CTest::OnCompareItems(LPARAM lParam1, LPARAM lParam2, int iColumn)
{
CMFCHeaderCtrl &headerCntrl = GetHeaderCtrl();
BOOL b = 0;
if(headerCntrl.IsAscending())
{
return SortItems(SortMeDescending, iColumn);
}
else
{
return SortItems(SortMeAscending, iColumn);
}
}
If I follow this post http://support.microsoft.com/kb/250614
I don't have arrows of sorting in headers.
If I use my method that you can see above, I get some gap in sorting.
I click it sorts and next time it won't be sort and again and again
please help me
I think you need to use CMFCHeaderCtrl::SetSortColumn to set the column's sort order. every time you sort. In addition to that, the actual sort function should be called from the HDN_ITEMCLICK handler.
So, assuming you have specified this:
ON_NOTIFY(HDN_ITEMCLICK, 0, OnItemclickList1)
In the OnItemclickList1 method write this code:
void CTest::OnItemclickList1(NMHDR* pNMHDR, LRESULT* pResult)
{
NMLISTVIEW *pLV = (NMLISTVIEW *) pNMHDR;
CMFCHeaderCtrl &headerCntrl = GetHeaderCtrl();
BOOL b = 0;
if(headerCntrl.IsAscending())
{
headerCntrl.SetSortColumn(pLV->iItem, FALSE);
SortItems(SortMeDescending, pLV->iItem);
}
else
{
headerCntrl.SetSortColumn(pLV->iItem, TRUE);
SortItems(SortMeAscending, iColumn);
}
*pResult = 0;
}
and ditch your OnCompareItems