I've just started programming in C++ and I have a lot of fun fiddeling around. But right now I have hit a brick wall for me: the WM_QUERYENDSESSION. I have no idea how to implement it. Let me explain how my code should work.
I have a txt document where I write down the time in days, hours, minutes and seconds. My program reads this txt and converts them into seconds. If the seconds are negative, a message box will appear. If they are positive, my program will get the current system time. When the user decides to shut down the PC, my program should get the current system time again and calculate the elapsed-seconds from start to end. The program now calculates the difference between the seconds from my txt document and the elapsed-seconds, converting this back to my days, hours, minutes, seconds format and re-write them back into my txt document.
I tested my code with a manual stop, just worked fine. I just have to implement the WM_QUERYENDSESSION. I thought about a while-loop with a variable that's true in the beginning and in this loop my program should check if the lParam (I think) is 0. If it is, set the loop variable to false, run the rest of the program and close it.
I hope, some of you can help me and explain how it works and what something does.
Note: Some codelines are going to be deleted. They were just to see if he read the text file the way i wanted it to for example.
I already searched for examples for that but i never understood exactly how to do it. The Microsoft website didn't help me aswell
#include <iostream>
#include <ctime>
#include <string>
#include <cmath>
#include <fstream>
#include <chrono>
#include <windows.h>
using namespace std;
double k; //Get leftover time from txt doc//
int s; //Seconds//
int m; //Minutes//
int h; //Hours//
int d; //Days//
int t; //Var containing new leftover time//
bool z = true; //Loop variable//
int main()
{
ifstream Check ("Test.txt");
Check >> d; //Writing days from txt doc to d//
Check >> h; //Writing hours from txt doc to h//
Check >> m; //Writing minutes from txt doc to m//
Check >> s; //Writing seconds from txt doc to s//
cout << d << "\n" << h << "\n" << m << "\n" << s << "\n";
//Display leftover time; will be deleted//
k = (s + 60*m + 3600*h + 24*3600*d);
//Converting days, hours, minutes and seconds into seconds//
cout << k << "\n";
//Displaying k; will be deleted//
if (k <= 0) //Show messagebox when k <= 0//
{
MessageBox(0,
"Textmessage",
"Texttitle",
MB_OK | MB_ICONEXCLAMATION); //Support MessageBox//
}
auto start = std::chrono::system_clock::now();
//Get current time starting the program//
while (z = true)
{
if () {
}
};
auto end = std::chrono::system_clock::now();
//Get current time ending the program//
std::chrono::duration<double> elapsed_seconds = end-start;
//Calculate difference between start and end//
t = (k-round(elapsed_seconds.count()));
//Calculate time difference in seconds//
//Converting seconds into days, hours, minutes, seconds//
d = t / (24*3600);
h = (t / 3600) % 24;
m = (t / 60) % 60;
s = t % 60;
//End of converting//
ofstream Write ("Test.txt");
Write << d << "\n" << h << "\n" << m << "\n" << s;
//Write all values back to txt doc//
}
Since you don't have a window, or a window handle, or a message pump for that window, you should use the console functions. In particular, you should register a handler with SetConsoleCtrlHandler to receive CTRL_CLOSE_EVENT.
WM_QUERYENDSESSION is a "Windows Message", part of Win32 API.
To receive and process such messages you need to put a message loop in your program.
This loop should be put after all your initialization code, because it will not end until the user exits your program.
Usually, the loop just dispatches the message to GUI windows, and each window has a function attached that handles relevant messages.
This is what is shown in the example in the link.
Your program is different, because you do not have any windows, and only run in background.
So your loop should look something like this:
// Start the message loop.
MSG msg;
BOOL bRet;
while( (bRet = GetMessage( &msg, NULL, WM_QUERYENDSESSION, WM_QUERYENDSESSION )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
DispatchMessage(&msg); //just in case
//if you want to check that user is logging off:
if (msg.lParam & ENDSESSION_LOGOFF > 0) {
//do the time thing you want, then exit the program
}
}
}
Your program will only look for one message and handle it directly in the loop.
I left the dispatch function in because I could not find any documentation about what would happen if a message is retrieved and not dispatched.
You can try removing it, but it may cause issues when the user tries to shutdown the computer, because the OS needs all apps to return non-zero value (TRUE) for this message to close cleanly.
EDIT: The lParam of the message is a bit mask, so should not be compared to possible values directly (it is in the doc, but easy to miss).
Also, since your application does not have a permanent window on screen, it may be a better choice to use a different method to detect shutdown, such as this:
BOOL WINAPI ShutdownHandler(DWORD dwCtrlType) {
//you can delete the second condition if you only care about shutdown
if (dwCtrlType == CTRL_SHUTDOWN_EVENT || dwCtrlType == CTRL_LOGOFF_EVENT) {
//do the date and time stuff
return TRUE;
}
return FALSE;
}
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nShowCmd) {
//you code to read the file
BOOL res = SetConsoleCtrlHandler(ShutdownHandler, TRUE);
if (res) {
while (true) { Sleep(10000); } //note your app will never exit like this
//maybe add some more logic to allow user to shut it down
} else {
//handle the error, you will not get shutdown notifications in this case!
}
}
Another option is to turn your app in to a service and then use RegisterServiceCtrlHandlerEx to get shutdown notifications.
Related
I've encountered a huge problem! I'm making a C++ Zombie game and it works perfectly besides the barrier part. I want the zombies to come to the barrier, then have them wait around 5 seconds, and then break through the barrier. Now I don't think you need my whole code for this since it's just a timer, but if you do let me know! Basically, I tried many timers AND the Sleep command, but when I use them it makes the zombies stay at the barrier, but then everything else freezes until the timers. For exmaple if the zombies at the barrier and I use a timer for 5 seconds, the zombie stays at the barrier for 5 seconds! but so does everything else, nothing else can move for 5 seconds! Is their any way I could use a sleep command only for a CERTAIN part of my code? Here is one of the few timers I used.
int Timer()
{
int s = 0;
int m = 0;
int h = 0;
while (true)
{
CPos(12,58);
cout << "Timer: ";
cout << h/3600 << ":" << m/60 << ":" << s;
if (s == 59) s = -1;
if (m == 3599) m = -1; //3599 = 60*60 -1
s++;
m++;
h++;
Sleep(1000);
cout<<"\b\b\b";
}
}
This one involves a sleep command, I also used a timer where while(number > 0) --number, but it works! but it still freezes everything else in my program!
If you need anything, Let me know!
Unless you have EACH zombie and everything else running on different threads, calling Sleep will pause the entire application for x milliseconds... You need to stop the zombie a different way, namely by just not moving him until the time has passed, while still updating the other entities as normal (don't use sleep).
EDIT:
You can't just create a timer and then wait until that timer is done. At the time when the zombie needs to stop moving, you have to 'remember' the current time, but continue on. Then each time you get back to that zombie again to update its position, you check to see if he has a pause timer. If he does, then you have to compare the elapsed time between what you 'remembered' against the current time and check whether he has paused long enough... here is some psuedo code:
#include <time>
class Zombie {
private:
int m_xPos;
time_t m_rememberedTime;
public:
Zombie() {
this->m_xPos = 0;
this->m_rememberedTime = 0;
}
void Update() {
if (CheckPaused()) {
// bail out before we move this zombie if he is paused at a barrier.
return;
}
// If it's not paused, then move him as normal.
this->m_xPos += 1; // or whatever.
if (ZombieHitBarrier()) {
PauseZombieAtBarrier();
}
}
bool CheckPaused() {
if (this.m_rememberedTime > 0) {
// If we have a remembered time, calculate the elapsed time.
time_t currentTime;
time(¤tTime);
time_t elapsed = currentTime - this.m_rememberedTime;
if (elapsed > 5.0f) {
// 5 seconds has gone by, so clear the remembered time and continue on to return false.
this.m_rememberedTime = 0;
} else {
// 5 seconds has not gone by yet, so return true that we are still paused.
return true;
}
}
// Either no timer exists, or the timer has just finished, return false that we are not paused.
return false;
}
// Call this when the zombie hits a wall.
void PauseZombieAtBarrier() {
// Store the current time in a variable for later use.
time(&this->m_rememberedTime);
}
};
Hey guys i have a do while loop its simple but the program goes into a none responsive state while running it heres the loop.
bool SetTime(const int hour,const int min,HWND sec)
{
do
{
time_t s=time(0);
tm t=*localtime(&s);
itoa(t.tm_sec,buf3,10);
SetWindowText(sec,buf3);
if (hour == t.tm_hour && min == t.tm_min)
{
exit(0);
}
Sleep(1000);
}
while( hour == t.tm_hour && min >t.tm_min);
}
it runs every second and when it reaches the proper time it stops
Assuming Win32 due to the HWND, you are blocking the event loop. If you want to defer an operation look at using a timer.
So I am trying to program a simple tick-based game. I write in C++ on a linux machine. The code below illustrates what I'm trying to accomplish.
for (unsigned int i = 0; i < 40; ++i)
{
functioncall();
sleep(1000); // wait 1 second for the next function call
}
Well, this doesn't work. It seems that it sleeps for 40 seconds, then prints out whatever the result is from the function call.
I also tried creating a new function called delay, and it looked like this:
void delay(int seconds)
{
time_t start, current;
time(&start);
do
{
time(¤t);
}
while ((current - start) < seconds);
}
Same result here. Anybody?
To reiterate on what has already been stated by others with a concrete example:
Assuming you're using std::cout for output, you should call std::cout.flush(); right before the sleep command. See this MS knowledgebase article.
sleep(n) waits for n seconds, not n microseconds.
Also, as mentioned by Bart, if you're writing to stdout, you should flush the stream after each write - otherwise, you won't see anything until the buffer is flushed.
So I am trying to program a simple tick-based game. I write in C++ on a linux machine.
if functioncall() may take a considerable time then your ticks won't be equal if you sleep the same amount of time.
You might be trying to do this:
while 1: // mainloop
functioncall()
tick() # wait for the next tick
Here tick() sleeps approximately delay - time_it_takes_for(functioncall) i.e., the longer functioncall() takes the less time tick() sleeps.
sleep() sleeps an integer number of seconds. You might need a finer time resolution. You could use clock_nanosleep() for that.
Example Clock::tick() implementation
// $ g++ *.cpp -lrt && time ./a.out
#include <iostream>
#include <stdio.h> // perror()
#include <stdlib.h> // ldiv()
#include <time.h> // clock_nanosleep()
namespace {
class Clock {
const long delay_nanoseconds;
bool running;
struct timespec time;
const clockid_t clock_id;
public:
explicit Clock(unsigned fps) : // specify frames per second
delay_nanoseconds(1e9/fps), running(false), time(),
clock_id(CLOCK_MONOTONIC) {}
void tick() {
if (clock_nanosleep(clock_id, TIMER_ABSTIME, nexttick(), 0)) {
// interrupted by a signal handler or an error
perror("clock_nanosleep");
exit(EXIT_FAILURE);
}
}
private:
struct timespec* nexttick() {
if (not running) { // initialize `time`
running = true;
if (clock_gettime(clock_id, &time)) {
//process errors
perror("clock_gettime");
exit(EXIT_FAILURE);
}
}
// increment `time`
// time += delay_nanoseconds
ldiv_t q = ldiv(time.tv_nsec + delay_nanoseconds, 1000000000);
time.tv_sec += q.quot;
time.tv_nsec = q.rem;
return &time;
}
};
}
int main() {
Clock clock(20);
char arrows[] = "\\|/-";
for (int nframe = 0; nframe < 100; ++nframe) { // mainloop
// process a single frame
std::cout << arrows[nframe % (sizeof(arrows)-1)] << '\r' << std::flush;
clock.tick(); // wait for the next tick
}
}
Note: I've used std::flush() to update the output immediately.
If you run the program it should take about 5 seconds (100 frames, 20 frames per second).
I guess on linux u have to use usleep() and it must be found in ctime
And in windows you can use delay(), sleep(), msleep()
I am working on writing a program that will do a few mouse clicks for me in a loop. I created a struct and set it to type INPUT_MOUSE to replicate the clicks and used SendInput() to send the info. everything compiles right and could be called a "working" program but I ran into a rather funny glitch. I wrote the program on my laptop (windows vista) tried it and it worked fine. When I rewrote the same exact code and used it on my desktop (Windows 7) when I run the program my screen will go to black as soon as I start the automation part of the program just like it does when it goes into sleep mode. The program will run in the background just fine, but its kind of a pain that the automater blacks my screen out. What is going on here?
I am adding my code:
#include "stdafx.h"
#include <windows.h>
#include <iostream>
#include <string>
#include <time.h>
using namespace std;
void clicky(int x, int y)
{
// 5 sec wait
clock_t run;
run = clock()+5*CLOCKS_PER_SEC;
while (clock() < run) {}
//plug in cursor coords and click down and up
SetCursorPos(x,y);
INPUT mouse;
mouse.type = INPUT_MOUSE;
mouse.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
SendInput(1,&mouse,sizeof(INPUT));
mouse.type = INPUT_MOUSE;
mouse.mi.dwFlags= MOUSEEVENTF_LEFTUP;
SendInput(1,&mouse,sizeof(INPUT));
}
void main()
{
int coords=0;
string h;
//find out how many clicks are needed
cout << "How many clicks will you need?";
cin >> coords;
//extra getline here without it when return is hit
//from entering the click amount it would also enter
//a cursor coordinate
getline(cin,h);
POINT p[21];
for (int count = 1;count<=coords;count++)
{
cout << "Place mouse cursor where you want a click and press return"<<endl;
//each time return is hit the cursor coordinates
//will be stored in the corresponding spot in
// the p array
string key = "r";
getline(cin,key);
GetCursorPos(&p[count]);
break;
}
string go;
cout << "Hit Return to initialize your click loop";
getline(cin,go);
while (true)
//infinite loop cycling through the users
//cursor coordinates and clicking
{
for(int click=1;click<=coords;click++)
{
int x = p[click].x;
int y = p[click].y;
clicky(x,y);
}
}
}
Try initializing the INPUT structure to all zeroes before calling SendInput(), like
INPUT i;
ZeroMemory(&i, sizeof(i));
In addition to that, make sure that the coordinates you specify are not too large.
I had the screen go blank (in fact, the screensaver kicked in) when doing either of these two wrong.
I am developing a simple game in c++, a chase-the-dot style one, where you must click a drawn circle on the display and then it jumps to another random location with every click, but I want to make the game end after 60 seconds or so, write the score to a text file and then upon launching the program read from the text file and store the information into an array and somehow rearrange it to create a high score table.
I think I can figure out the high score and mouse clicking in a certain area myself, but I am completely stuck with creating a possible timer.
Any help appreciated, cheers!
In C++11 there is easy access to timers. For example:
#include <chrono>
#include <iostream>
int main()
{
std::cout << "begin\n";
std::chrono::steady_clock::time_point tend = std::chrono::steady_clock::now()
+ std::chrono::minutes(1);
while (std::chrono::steady_clock::now() < tend)
{
// do your game
}
std::cout << "end\n";
}
Your platform may or may not support <chrono> yet. There is a boost implementation of <chrono>.
Without reference to a particular framework or even the OS this is unanswerable.
In SDL there is SDL_GetTicks() which suits the purpose.
On linux, there is the general purpose clock_gettime or gettimeofday that should work pretty much everywhere (but beware of the details).
Win32 API has several function calls related to this, including Timer callback mechanisms, such as GetTickCount, Timers etc. (article)
Using timers is usually closely related to the meme of 'idle' processing. So you'd want to search for that topic as well (and this is where the message pump comes in, because the message pump decides when (e.g.) WM_IDLE messages get sent; Gtk has a similar concept of Idle hooks and I reckon pretty much every UI framework does)
Usually GUI program has so called "message pump" loop. Check of that timer should be a part of your loop:
while(running)
{
if( current_time() > end_time )
{
// time is over ...
break;
}
if( next_ui_message(msg) )
dispatch(msg);
}
Try this one out:
//Creating Digital Watch in C++
#include<iostream>
#include<Windows.h>
using namespace std;
struct time{
int hr,min,sec;
};
int main()
{
time a;
a.hr = 0;
a.min = 0;
a.sec = 0;
for(int i = 0; i<24; i++)
{
if(a.hr == 23)
{
a.hr = 0;
}
for(int j = 0; j<60; j++)
{
if(a.min == 59)
{
a.min = 0;
}
for(int k = 0; k<60; k++)
{
if(a.sec == 59)
{
a.sec = 0;
}
cout<<a.hr<<" : "<<a.min<<" : "<<a.sec<<endl;
a.sec++;
Sleep(1000);
system("Cls");
}
a.min++;
}
a.hr++;
}
}
See the details at: http://www.programmingtunes.com/creating-timer-c/#sthash.j9WLtng2.dpuf