Newsgroup: it.comp.programmare.win32
Titolo: [newbie] Domanda semplice su gestione finestre..

Ciao a tutti.
 Mi sto avvicinando alla programmazione in campo windows ( dopo anni di
programmazione unix ) e vorrei
scrivere un programminoche legge alcuni dati dall sharedmemory e li
scrive su un file.
La parte backend e' gia pronta ( a parte qualche bug :), e allora mi e'
venuto in mente di aggiungere una
microscopica interfaccia grafica, tanto per sfruttare le potenzialita'
di windows.
Naturalmente li sono iniziati i problemi.
Ho letto molti docs ed esempi in rete, ma nessuno si adatta alle mie
necessita':
in pratica dovrei aprire una finestra con due pulsanti ( start e stop ),
alla pressione dello start devo far partire
il mio ciclo "infinito" che legge i dati e li mette su un file, fino a
che non viene premuto stop che termina il ciclo
( e volendo termina il programma ).
Sono riuscito a creare la finestra, registrarla etc, ma cio' che non
riesco a capire e' come ( o dove ) far partire
il mio ciclo in modo che io possa "sentire" il tasto stop mentre cicla
all' infinito.
Tutti i tutorials che ho trovato mostrano la fase di creazione e
registrazione delle finestre, ma hanno tutte come
fine quello di mostrare un altra finestra con il suo pulsantino di
close, quindi non un ciclo di backend.
Avete qualche link, o riga di codice per mostrarmi la "retta via" ?
Grazie
Pigi
P.S. togliere il nospam se serve di contattarmi in privato.

 ( e volendo termina il programma ).
Se fai partire un ciclo infinito (o comunque molto lungo) tutto il resto 
del tuo programma viene bloccato, quindi non puoi gestire correttamente 
la successiva pressione del pulsante 'stop'. La soluzione e' quella di 
far girare il ciclo che si occupa della lettura/scrittura dei dati in un 
thread separato che giri parallelamente a quello principale (che 
restera' quindi reattivo alle azione operate sull'interfaccia grafica).
Luca.

E' ovvio che se vuoi, alla pressione di un pulsante,  far partire un ciclo
infinito ecc... devi per forza crearti un thread ovvero una procedura al cui
interno puoi metterci il tuo loop infinito che girera' sul tuo stack
separato le cui dimensioni gli verranno assegnate o dal compilatore ( vedi
Windows CE ) o dai parametri che hai scelto tu.
ti crei la tua procedura che ha un DWORD come valore di ritorno ( segui
scrupolosamente la sintasi che ti ho scritto)
col puntatore LPVOID puoi farci quello che ti pare, occhio che se questa
procedura e' un elemento funzione di una classe
devi per forza diciarare il prototipo come static e magari al posto di
LPVOID gli passi un puntatore alla tua classe
HANDLE hThread = INVALID_HANDLE_VALUE; // -1, dichiarato in winbase.h
DWORD WINAPI MiaProcedura ( LPVOID lpArg )
{
     for ( ; ; )
    {
            // qui processi le tue istruzioni di listen...
    }
    return (0);
}
poi ti crei il tuo thread MiaProcedura sulla pressione del tasto:
void MiaClasse::OnButtonPremuto()
{
      DWORD dwRes = 0u;
      hThread = CreateThread( NULL, 0 , MiaProcedura , 0, 0, &dwRes );
// il secondo parametro setta la quantita' di stack che vuoi prenderti, vedi
sopra
}
Poi sull'altro pulsante utilizzi la TerminateThread( hThread , 0 ) per
chiudere il thread
spero ti abbia aiutato, un consiglio: se poi il programma diventa piu'
complesso, studiateli bene i thread e gli oggetti kernel che windows ti
mette a disposizione...
ciao

se poi vuoi modificarti manualmente l'area di memoria che il sistema assega
allo stack del tuo thread ( di default e' 1MB di spazio ) vai sulla setting
del progetto e nel linker specifichi l'opzione /STACK: spazio che vuoi venga
assegnato, se nella createthread gli dai 0 al secondo parametro carichi
quelle di default che vanno benissimo
ciao

Era orientativamente l' idea che avevo avuto anche io, ma ovviamente tra
idea e azione...
Ho provato a tirare giu' due righe come mi hai consigliato, ma continuo
ad avere un errore
Dalla GetThreadContext.
Ora provo a mettere qualche messagebox di debug, ma se vedi qualche
cavolata incredibile, ed hai voglia,
fammelo sapere :)
...
HANDLE hThread = INVALID_HANDLE_VALUE;
static BOOL CALLBACK DialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam,
LPARAM lParam);
DWORD WINAPI ciclolettura(LPVOID lpArg)
{
   while (1)
       {
		 Sleep(WaitCycle);
		 DoRead();
       }
	return(0);
}
void DoRead()
{
// Codice della lettura della shared 
}
/*
Win main just registers a class of the same type that the dialog class,
and
then calls DialogBox. Then it exits. The return value is the return
value of
the dialog procedure.
*/
int APIENTRY WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR
lpCmdLine, int nCmdShow)
{
	WNDCLASS wc;
	memset(&wc,0,sizeof(wc));
	wc.lpfnWndProc = DefDlgProc;
	wc.cbWndExtra = DLGWINDOWEXTRA;
	wc.hInstance = hinst;
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
	wc.lpszClassName = "f4serdata";
	RegisterClass(&wc);
	return DialogBox(hinst, MAKEINTRESOURCE(IDD_MAINDIALOG), NULL,
(DLGPROC) DialogFunc);
}
/*
You should add your initialization code here. This function will be
called
when the dialog box receives the WM_INITDIALOG message.
*/
static int InitializeApp(HWND hDlg,WPARAM wParam, LPARAM lParam)
{
	return 1;
}
/*
This is the main function for the dialog. It handles all messages. Do
what your
application needs to do here.
*/
static BOOL CALLBACK DialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam,
LPARAM lParam)
{
DWORD dwRes = 0u;
	switch (msg) {
	/* This message means the dialog is started but not yet visible.
	   Do All initializations here
        */
	case WM_INITDIALOG:
		InitializeApp(hwndDlg,wParam,lParam);
		return TRUE;
	/* By default, IDOK means close this dialog returning 1, IDCANCEL means
           close this dialog returning zero
        */
	case WM_COMMAND:
		switch (LOWORD(wParam)) {
			case IDOK:
				/* Ciclo di wait */
				hThread = CreateThread( NULL, 0 , ciclolettura , 0, 0, &dwRes );
				return 1;
			case IDCANCEL:
				if (hThread != INVALID_HANDLE_VALUE )
					TerminateThread( hThread , 0 );
				EndDialog(hwndDlg,0);
				return 1;
		}
		break;
        /* By default, WM_CLOSE is equivalent to CANCEL */
	case WM_CLOSE:
		EndDialog(hwndDlg,0);
		return TRUE;
	}
	return FALSE;
}

Ok,ok il problema e' nel debugger, non nel codice.
Ora sembra tanto funzionare :)
Grazie a tutti

 ( e volendo termina il programma ).
Esiste un'altro metodo .... molto più semplice!
1 - crei una variabile membro della finestra m_bStop che si setta TRUE se
premi il pulsante stop
2 - crei una funzione tipo questa:
void CTuaClasse::FlushMessage(void)
{
    MSG msg;
    while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}
e la chiami "periodicamente" nel tuo ciclo subito seguita dalla verifica di
m_bStop;
se è TRUE interrombi il ciclo.
Funziona perfettamente.
ciao e buon lavoro.
DANILO.

 
La TerminateThread e' 'abbastanza brutale' come metodo di chiusura. 
Forse e' meglio una variabile booleana condivisa (come descrito nel 
metodo di Danilo) che, una volta settata a TRUE, fa uscire dal ciclo e 
chiamare la ExitThread.
Dalla documentazine MS:
-----------------------
TerminateThread is used to cause a thread to exit. When this occurs, the 
target thread has no chance to execute any user-mode code and its 
initial stack is not deallocated. DLLs attached to the thread are not 
notified that the thread is terminating. 
TerminateThread is a dangerous function that should only be used in the 
most extreme cases. You should call TerminateThread only if you know 
exactly what the target thread is doing, and you control all of the code 
that the target thread could possibly be running at the time of the 
termination.
-----------------------
Luca.

 
Fantastico, faro' cosi :)
Grazie
Pigi

Grazie anche a te Danilo, ma ormai sono partito nell' altra direzione e 
cmq funziona
Pigi