WinApi Zdarzenie o zadanym czasie

0

Witam
Piszę program w BTC++ który ma wykonać pewne zadania o określonej godzinie. I tu pytanko, czy robić to Timerem, odpowiednio co chwilę zmieniając jego Interval, czy może istnieje prostszy sposób?

0
VOID CALLBACK funkcja(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime) {
   // bla bla bla
}
UINT czasomierz = SetTimer(0, 0, czas, funkcja); // tworzy
KillTimer(0, czasomierz); // ubija, jeśli się rozmyśliłeś
0

http://msdn2.microsoft.com/en-us/library/ms644906.aspx
mowi, ze trzeci parametr oznacza ZA ILE ma sie odpalic callback, a nie KIEDY. autor prosil o info jak sprawic aby callback odpalil sie o danej godzinie.. jesli nie jest potrzebna wielka dokladnosc trafienia w punkt czasu, to mozna sobie przeliczyc KIEDY-TERAZ i taka wartosc podac.. ale jesli potrzeba hiperdokladnosci, trzeba uzyc czegos innego niz timer z timeoutem -- chocby dlatego ze czas pobrania czasu i przeliczenia wartosci zabiera chwilke i zaburza interwal ktory trzeba przeczekac :) wtedy to juz chyba tylko jakies timery multimedialne zostaja..

0

quetzalcoatl, jestem w bardzo złym humorze i powiem ci, że czepiasz się, jakby ci się nudziło i to tak konkretnie i ostro. Sam piszesz, że to jest jedno odejmowanie kiedy-teraz. A przecież to ma być alternatywa do timera, który działa tak samo - za ile, a nie o której. No i jaki interwał podczas odejmowania? No hello, rozdzielczość timerów w windowsie to 50ms, a multimedialny realnej gwarantowanej to nawet milisekundy nie ma, mimo, że oświadcza inaczej. Jakoś nie wyobrażam sobie, żeby czas calla do jednej funkcji systemowej liczony był w milisekundach na na procesorach, które mają taktowanie trochę szybsze, niż xxx KHz.

O KTóREJ, to tylko harmonogram zadań woła, a o jego dokładności to już nie ma co mówić... :]

0

wybacz mi tym razem.. sa walentynki i tez mam zwalony humor.. w takich przypadkach jestem jak RZEP.. wyczailes mnie idealnie - nudzi mi sie.. zaczalem poprawiac nasz tutejszy reference dla klasy string..

0

Ok, dzięki. A co, jeżeli nie chcę robić tego w WinAPI, tylko w zwykłym dosowym programie? Sleep() z <windows.h> to chyba nie jest najlepszy pomysł...

0

Zależy co dokładnie masz na myśli. W konsolowym pod Windows możesz WinAPI używać. W realnie DOSowym (omg, ktoś jeszcze pisze pod prawdziwy DOS? :O) musiałbym na dysku poszukać, opierało się to na postawieniu swojej procedury pod przerwanie bodajże 18H i przeprogramowaniu timera, żeby wywoływał się z inną częstotliwością. Ale to było przydatne bardziej przy cyklicznym uruchamianiu kodu, znając życie, to pewnie było spore ograniczenie co do zakresów czasu. Wielowątkowości w DOSie nie ma jako tako, więc "ludzkiego" odliczania w tle też niestety nie ma, jeśli dobrze pamiętam stare czasy (noobem wtedy byłem, więc to co pamiętam może się okazać głupie ;P )

0

Sprawa jest taka:
Wczytuje z pliku godziny, o których mam wywołać konkretną funkcję. I żeby chodziło pod DOS'em. Jakie byłoby najlepsze rozwiązanie?

0

Naprawdę o DOSie mówisz?! O jejku jej, niech ci będzie... do czegoś dokładnie takiego najlepiej napisać program rezydentny:
http://www.arl.wustl.edu/~lockwood/class/cse306-s04/books/artofasm/Chapter_18/CH18-1.html

w czym to piszesz? bo ja kojarzę DJGPP albo Turbo C++ stare. I one się znacznie różnią - jeden robi programy dla trybu rzeczywistego, drugi dla protected mode. TSR tylko w Turbo C++ jakieś pisałem...

btw: stawiam 100 do 1, że XP wysadzi taki DOSowy program z butów, więc będziesz to musiał pod Win9x albo DOSem prawdziwym testować.

0
Ranides napisał(a)

DOSem prawdziwym

A jako ten "nieprawdziwy" rozumiesz konsolę w Windows? Bo nie wiem czy się rozumiemy.

Piszę w Dev-cpp program, który będzie potem używany na jakimś kiepskim komputerze (czytaj "starym złomie"), dlatego nie chcę w to mieszać żadnego Windowsa. Program przez port drukarki będzie włączał\wyłączał urządzenie zewnętrzne (o zadanej godzinie).

Program rezydentny zawsze kojarzyłem z programem zminimalizowanym do tray'a :/ . Jeżeli w dalszym ciągu podtrzymujesz swoją propozycję, to może jednak coś po polsku...

A co do uruchamiania pod Windom, rzeczywiście muszę tak komplikować sprawę? Nie można tego obejść prościej?

0

Piszę w Dev-cpp program

Nooo, czyli normalny Windows, tylko konsola, bo naprawdę zaszokowany byłem. To, że masz czarne okienko, to nie znaczy, że już DOS ;)

będzie potem używany na jakimś kiepskim komputerze (czytaj "starym złomie"), dlatego nie chcę w to mieszać żadnego Windowsa

Jeśli "stary złom" ma chociażby Windows 95 to WinAPI bierz śmiało i nie truj sobie życia. Zresztą WinAPI zrobi to 10x razy wydajniej niż dowolna metoda "czysto dosowa", bo pod Windowsem realnie dosowe aplikacje pożerają moc, że aż miło.

A co do uruchamiania pod Windom, rzeczywiście muszę tak komplikować sprawę?

nie, bo już wiemy, że piszesz pod Windę ;] Jakbyś pisał DOSowy program przejmujący przerwania, żeby jako-tako chodzić w tle, to byś musiał.

Jeżeli w dalszym ciągu podtrzymujesz swoją propozycję,

Dzięki bogu nie muszę podtrzymywać - wracamy do punktu wyjścia. Do wyboru:

  • timery
  • harmonogram zadań (poleceniem schtasks zrobisz wszystko: opis)
  • oddzielny wątek sprawdzający sobie godzinę od czasu do czasu i uruchamiający coś (CreateThread i przyjaciele)
0
Ranides napisał(a)

Piszę w Dev-cpp program

Nooo, czyli normalny Windows

Hmm, ja dobrze wiem, że konsola w Windows jest jakby emulatorem dos'a. Myślałem, że jeżli napiszę taki program, to pod dos'em też dam radę go odpalić! Pomyliłem się???

Problem w tym, że ten program naprawdę ma być odpalany w dos'ie, bo z góry mam takie zalecenie. A z tego, co mówisz, w dev'ie takiego programu w ogóle napisać się nie da! To mnie zdziwiło.

Chciałem go napisać pod Windą, bo tak jest wygodniej, wypróbowywać również pod windą, a ostateczną wersję wsadzić do dos'a.

0

Myślałem, że jeżli napiszę taki program, to pod dos'em też dam radę go odpalić! Pomyliłem się???

obawiam się, że tak ;) znaczy Dev używa MinGWa, a mingw, jak sama nazwa wskazuje robi programy dla Windows. Twój program pod DOSem ruszy... tylko po to, aby wyrzucić info, że potrzebuje windowsa ;]

Jak ma być odpalony w DOSie, to kijowo... coś takiego posklejałem, ale w pisaniu pod DOS czuję się bardzo słaby, więc traktuj to tylko jako punkt wyjścia, mimo, że jako-tako to działa :|

#include <dos.h>
#include <conio.h>
#include <stdlib.h>

// numer przerwania zegarowego
#define CLOCK_INTR 0x1C

// zmniejszenie stosu i sterty, zeby program mniej zajmowal
extern unsigned _heaplen = 1024;
extern unsigned _stklen  = 512;

// pomocnicze typy
typedef unsigned int uint16_t;
typedef unsigned char uint8_t;
// w szczegolnosci: wskaznik na tablice reprezentujaca zawartosc ekranu
typedef uint16_t (far* screen_t)[25][80];


// wskaznik na stare przerwanie zegarowe
void interrupt ( *oldClock)(...);

// czy DOS jest zajety, o tym na koncu...
uint8_t dosBusyFalse=0;
uint8_t far* dosBusy = &dosBusyFalse;


// hmm... piszemy na ekranie bezposrednio, bo inaczej bedzie klops
void directWrite (char* text, char color, char x, char y) {
    screen_t screen;
    screen = (screen_t)MK_FP(0xB800,0);

    for(int i=0; text[i]; i++)
        (*screen)[y][x+i] = text[i] | (color<<8);
    }

// pobieramy czas bezposrednio z pamieci, bo przerwanie zrobi klops
void directTime(int far* h, int far* m, int far* s) {
   // godziny sa trywialne jak widac. w komorce 0:46EH siedza
   *h = *(uint16_t far*)MK_FP(0x0, 0x046e);
   // w komorce 0:046CH siedza "tykniecia", a nie sekundy
   // (18.2 tykniec na sekunde)
   *s = *(uint16_t far*)MK_FP(0x0, 0x046c) / 18.2;
   *m = *s/60;
   *s %= 60;
   }

// funkcja testowa
void test() {
   sound(1000);
   delay(150);
   nosound();
   delay(100);
   }

// nasze przerwanie zegarowe
void interrupt clockHook(...) {
    // taki tam sobie counter
    static int count;
    count = (count+1)%10;

    // na razie: jesli DOS zajety, to nie kombinujemy, w nastepnym
    // tyknieciu moze juz bedzie wolny. Jakkolwiek, patrz na dol
    if(*dosBusy) return;

    // pobieramy sobie czas i wyswietlamy na ekranie
    char buffer[40];
    int h,m,s;
    directTime(&h, &m, &s);

    directWrite(itoa(h,buffer,10), 7, 50, 1);
    directWrite(itoa(m,buffer,10), 7, 53, 1);
    directWrite(itoa(s,buffer,10), 7, 56, 1);

    // wyswietlamy na ekranie takie sobie tam migadlo
    directWrite("..........",7, 65,1);
    directWrite("*",15, 65+count,1);


    // !!!
    // !!! tutaj jest klucz: warunek sprawdza czas, i wola funkcje test
    // !!!
    if(s%15==0) {
       // khem... podobno przywracamy stare przerwanie
       // cli, sti nie wiem po co jest, w przykladach bylo, wiec zostawilem ;)
       asm { cli; }
       setvect(CLOCK_INTR, oldClock);
       asm { sti; }
       // khem... podobno informuje kontroler przerwan o tym,
       // ze przerwanie zegarowe skonczylo dzialac juz
       outportb(0x20, 0xa0);
       outportb(0x20, 0x20);

       // wolamy funkcje
       test();

       // przywracamy nasze przerwanie,
       // j/w po cholere jest cli/sti nie wiem ;P
       asm { cli; }
       setvect(CLOCK_INTR, clockHook);
       asm { sti; }

       }

    oldClock();
    }

int main() {
    // teoria (znaczy przyklady ;)) mowi, ze to pobiera adres
    // jakiejs flagi, ktora mowi, czy DOS nie jest wlasnie czyms zajety.
    // i jak ta flaga jest rozna od 0, to nie powinno sie w timerze
    // kombinowac...
    // fajnie, tylko pod XP to powoduje wypieprzenie programu, a bez
    // tego jakos mi chodzi... moze w realnym dosie bedzie trzeba
    // odkomentowac. Na razie pod dosBusy wstawilem adres wlasnej zmiennej
    // ktora zawsze jest rowna 0.
    /*
    union REGS regs;
    struct SREGS segments;
    regs.h.ah = 0x34;
    intdosx(&regs, &regs, &segments);
    dosBusy = (uint8_t far*)MK_FP(segments.es,regs.x.bx);
    */

    // zmieniamy przerwanie
    oldClock = getvect(CLOCK_INTR);
    setvect(CLOCK_INTR, clockHook);

    // a tak po prostu czeka na klawisza ;)
    getch();

    // zostawia program w pamieci. fragment przez Borlanda podany
    // ale taki nie do konca, bo pisza, zeby  tym uwazac. Tzn,
    // keep zostawia flaki w pamieci. Trzeba powiedziec, ile tej
    // pamieci ma zostawic. Metoda z _SS _SP itd podobno nie jest
    // do konca pewna
    keep(0, (_SS + (_SP/16) - _psp));
    return 0;
    }

Pisane w Turbo C++, nawet nie próbuj kompilować w Dev ;P Jak nie masz Turbo C++, to możesz okrojoną wersję ściągnąć sobie: http://www.ranides.xt.pl/misc/tc.rar

Komentarze ludzi, którzy się znają, bardzo mile widziane. Są tu fragmenty, bez których mi program działa, ale je zostawiłem, bo były w przykładach znalezionych. Kod może być trochę nadmiarowy, mam jednak nadzieję, że niczego w nim nie brakuje.

0

O kur*a! To nawet poczciwego ostream'a nie wolno użyć, tylko ładować trzeba znaki prosto do strumienia monitora!
Nie ma mowy - mówie gościowi, że musi być pod Winde i już!

0

niestety nie :| wiem, że między wszystkimi outport i sti można wywołać bezpiecznie inny program zamiast funkcji test, który już działa po ludzku. Niestety, nie wiem jaką funkcją bo system i exec** mi się wywalają :/ Poczekaj jeszcze, może ktoś inny się odezwie, albo może i ja do rana jakąś funkcję znajdę, która idzie - wtedy nie byłoby źle.

0

To nawet poczciwego ostream'a nie wolno użyć

Można , trzeba tylko mieć kompilator 16 bitowy pod DOS , ewent środowisko pod windowsa
które pozwala napisać taki program ( np, Borland 5.0 ) ostream nie jest związany
z windows tylko jest biblioteką standardową która działa i działała w kompilatorach 16 bit.

Wielowątkowość "emuluje" TSR pod dosem , ale to jest chyba trochę masakra żeby sie w tym
grzebać...
Terminate But Stay Resident .
Napisanie zegara w dos wyświetlanego w czasie działania systemu to były kiedys podstawy
programowania w Dos z użyciem asemblera ...
i jak podał Ranides można to napisać w C .
Jeśli program ma działac w całości jako TSR to ostream , odpada ...

Chciałem go napisać pod Windą, bo tak jest wygodniej, wypróbowywać również pod windą, a ostateczną wersję wsadzić do dos'a.

Można , pisząc program dla DOS 16 bit w środowisku działającym pod Win i potem sprawdzić np. startując z dyskietki '98 i odpalając program
niestety efekt nie zawsze jest w 100% ten sam...

0

Mówimy tu o (jak dla mnie) zbyt skomplikowanych rzeczach, żeby pojąć to za 2 dni. Jednak zrobie to chyba pod Windows'a. Trudno...

0

ej, JaskMar, nie poddawaj się. owszem z iostream i ogólnie z elastycznością nie jest lekko, ale jeśli masz robić tylko to, co piszesz: sterowaniem przez port drukarki, to wystarczą ci jeszcze dwie wstawki w asm używające in out i jesteś w domu. W Turbo C++ możesz używać wstawek:
asm { bla bla };
i masz opis LPT:
http://asembler.programuj.com/start.htm

Z tym, że w XP nie możesz już tego całkiem testować, bo on blokuje bezpośrednie grzebanie w portach, a ja mam tylko XP na kompie, więc już nie mogę pomóc i dopisać tego do kodu powyżej, chyba, że z palca i na czuja.

0

Chciałbym się nie poddawać, ale kilka ostatnich postów (począwszy od Twojego dłuższego kodu) rozumiem tylko połowicznie. Po prostu za mało wiedzy. A uczyć trzeba się po kolei.
Piszę ten program, bo mój nauczyciel od informatyki (nawet o tym nie wiedząc) chce podzielić się swoją wiedzą z zainteresowanymi uczniami. Mimo to program ma mieć swoje zastosowanie (sterowanie dzwonkami szkolnymi)

O bosze, czy jak byliście w moim wieku, też mieliście wrażenie, że aby być programistą, muszę zdobyć jeszcze multum do kwadratu wiedzy? I jeszcze w jaki sposób ją zdobywać... ?

P.S nie chodzi tylko o iostream. Ja nie mam pojęcia, dlaczego w tym przypadku iostream nie mogę używać! Przecież na dobrą sprawę, sam mógłbym sobie taką bibliotekę a_la_iostream napisać!

0

W sumie to tym dłuższym kodem chciałem Ci oszczędzić pracy, bo chociaż

Napisanie zegara w dos wyświetlanego w czasie działania systemu to były kiedys podstawy programowania w Dos z użyciem asemblera ...

to dzisiaj już to takie popularne nie jest.

W tym szkielecie faktycznie nie można doklejać wszystkiego, głównie dlatego, że nasz hook to obsługa przerwania - w jego środku innych przerwań już wywoływać nie można, a wszystkie uczciwe funkcje w standardowych bibliotekach korzystają z przerwania systemowego (21H) albo rzadziej innych, np BIOSowych. Stąd prawie wszystko trzeba robić na piechotę, albo nawet wstawkami.

PS. ja cały czas mam takie wrażenie, czasem mnie ogrom zadania przytłacza, przez tydzień gryzę paznokcie i wyrywam sobie włosy, aż przychodzi chwila kiedy mogę sobie powiedzieć, że znam nową technikę, bibliotekę, narzędzie, środowisko.

0
Ranides napisał(a)

Jak nie masz Turbo C++, to możesz okrojoną wersję ściągnąć sobie: http://www.ranides.xt.pl/misc/tc.rar

Dlaczego mówisz, że to okrojona wersja?

Koleś od infy będzie mi coś tłumaczył na ten temat. Zobaczymy co z tego będzie

@Edit: Po odpaleniu tego wypisuje mi: "Nie można odnaleźć DWCC.DLL"

0

Znaczy okrojona, bo wywalone przykłady, Turbo Vision, sterowniki BGI, i parę innych rzeczy, które mi w życiu nie są potrzebne ;)

Doobra, jak chcesz pełniejszą, to np:
http://www.vetusware.com/download/Borland%20Turbo%20C++%203.0/?id=163

0

Zauwarzyłem że obaj sie napisaliście tylko a rozwiazania brak a wystarczy tylko wykorzystać funkcję SYSTEMTIME pobrać aktualny czas sprawdzić czy jest rowny z czasem z pliku i po sprawie.
gd-software.com

0

wystarczy tylko wykorzystać funkcję SYSTEMTIME

HAHAHA! Śmiechu warte!
Po pierwsze nie spotkałem się jeszcze z funkcją SYSTEMTIME, a po drugie ta "funkcja" nie zadziała mi pod dosem

0

@JaskMar:
jak przeczytałem to, co Wujek Dobra Rada rzucił, to nawet nie miałem siły odpowiadać, poza tym mam ogromną rozterkę, jakiej ikonki użyć: [glowa] czy może po prostu [rotfl]

a tak btw: ta wersja ściągnięta "skądś-tam" ci taki błąd rzuca? uruchom program bc.exe, on w ogóle nie powinien DLLek wymagać, przecież DOSowy jest.

0

Nie. Ten skąśtam działa ok. Dzięki. Programik zrobiłem pod Windows, a facet mi obiecał, że kiedyś siądziemy przed dosem

1 użytkowników online, w tym zalogowanych: 0, gości: 1