PDA

View Full Version : Registrazione click del mouse avvenuti sul desktop


Federicoat
13-05-2009, 11:43
Ciao a tutti,
ho un piccolo problema. Mi è stato richiesto di valutare la possibilità di monitorare (scrivere un file di log) i click del mouse avvenuti su delle porzioni del desktop (sistema operativo windows). Una specie di mouse logger.

Es: Ho una sbarra delle applicazioni nella parte alta del desktop da monitorare e in base a dove avvine in click in questa sbarra scriverlo in un file.

La mia idea sarebbe quella di creare un windows service. Questo programma deve funzionare sempre e deve avviarsi in automatico all'avvio di windows. In poche parole deve essere totalmente trasparente all'utente.

Secondo voi è possibile? Avete qualche idea o qualche consiglio da darmi.

Qualsiasi linguaggi di programmazione va bene.

Grazie a tutti.

!k-0t1c!
13-05-2009, 13:29
Qui troverai abbastanza informazioni da mettere insieme qualcosa, posto che tu abbia qualche conoscenza (anche minima) di C#.
http://www.codeproject.com/KB/cs/globalhook.aspx
Se vuoi filtrare i click puoi usare GetForegroundWindow per determinare qual'è la finestra che l'utente sta visualizzando in maniera tale da determinare a quale processo appartiene.

Federicoat
13-05-2009, 14:01
Qui troverai abbastanza informazioni da mettere insieme qualcosa, posto che tu abbia qualche conoscenza (anche minima) di C#.
http://www.codeproject.com/KB/cs/globalhook.aspx
Se vuoi filtrare i click puoi usare GetForegroundWindow per determinare qual'è la finestra che l'utente sta visualizzando in maniera tale da determinare a quale processo appartiene.

Grazie mille per la risposta.... purtroppo in C# non ho esperienza ma dovrei riuscire a cavarmela con le conoscenze di altri linguaggi (almeno spero). Adesso come adesso mi urgeva capire se era fattibile farlo e con che tempi...

MarcoGG
13-05-2009, 15:43
ho un piccolo problema. Mi è stato richiesto di valutare la possibilità di monitorare (scrivere un file di log) i click del mouse avvenuti su delle porzioni del desktop (sistema operativo windows). Una specie di mouse logger.


Mouse Logger ? Usa VB e la libreria API :
Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Integer) As Integer

E' semplice, ti faccio un breve esempio WinForm ( ma puoi portarlo facilmente su un WinService... ) :

Dichiarazioni generali :

Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Integer) As Integer

Private Const vKeyPSinistro = 1 'Click Sinistro
Private mouseDownSn As Boolean = False

Private Const vKeyPDestro = 2 'Click Destro
Private mouseDownDx As Boolean = False

Private Const vKeyPCentrale = 4 'Click Centrale
Private mouseDownCn As Boolean = False

'Coordinate al momento del MouseDown
Private mouseDownX As Integer = 0
Private mouseDownY As Integer = 0
'Coordinate Mouse Timer
Private mouseX As Integer = 0
Private mouseY As Integer = 0

Nel Timer, con intervallo opportunamente basso ( diciamo 10 ) :

mouseX = Cursor.Position.X
mouseY = Cursor.Position.Y

'Click Sinistro
If GetAsyncKeyState(vKeyPSinistro) And mouseDownSn = False Then
mouseDownSn = True
mouseDownX = mouseX
mouseDownY = mouseY
End If
If GetAsyncKeyState(vKeyPSinistro) = 0 Then
If mouseDownSn = True And mouseX = mouseDownX And mouseY = mouseDownY Then
'Click Sinistro accettato nel punto X,Y -> gestisco l'evento
ListBox1.Items.Add(Now & " - Click Sinistro in : X[" & mouseX & "]-Y[" & mouseY & "]")
End If
mouseDownSn = False
End If

'...
'...

E così via per gestire Click Destro e Centrale ( pulsante centrale o Click su rotella ). Nel mio caso ho deciso deliberatamente di escludere dal Log ( che effettuo aggiungendo una voce ad una ListBox, ma puoi fare l'append di una stringa in un file di Log tipo testo ) i casi in cui le coordinate del mouseDown NON corrispondono a quelle del mouseUp.
In ogni caso, il Log registra Data/Ora/Coordinate Desktop X ed Y/Click-Sn-Dx-Centrale.
;)

PGI-Bis
13-05-2009, 15:47
Occhio alla sbarra ci finisce chi lo usa e chi l'ha scritto.

!k-0t1c!
13-05-2009, 16:04
@MarcoGG, la tua soluzione per quanto possa funzionare è altamente inefficiente e consuma risorse della CPU in quantità comparata con i global hooks, fatti apposta per il proposito di Federicoat ed almeno altrettanto semplici da usare.

Federicoat
13-05-2009, 16:32
Grazie a tutti... purtroppo su vb c# o c++ non ho molta conoscenza.
Non devo fare questo programmino per svago ma per lavoro.
Ovviamente mi serve qualcosa che non consumi troppe risorse e che non interferisca con gli altri processi. Qualcosa che catturi il click del mouse ovunque si trovi....

ho trovato questo codice per iniziare... qualcuno mi sa dare un feedback?

http://blogs.msdn.com/toub/archive/2006/05/03/589468.aspx

Dimenticavo, una cosa è fondamentale... questo programma deve lavorare in background.. in poche parole deve essere un processo o qualcosa di simile...

Federicoat
14-05-2009, 09:11
Ragazzi ho bisogno di aiuto...
Ho provato a copiare e a compilare sta classe ma nulla da fare... non riesco a far partire nulla... vi prego aiutatemi... per lavorare con c# ho scaricato Microsoft visual c# express edition.


using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices;

class InterceptMouse
{
private static LowLevelMouseProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;

public static void Main()
{
_hookID = SetHook(_proc);
Application.Run();
UnhookWindowsHookEx(_hookID);
}

private static IntPtr SetHook(LowLevelMouseProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_MOUSE_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}

private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);

private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 &&
MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
{
MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
Console.WriteLine(hookStruct.pt.x + ", " + hookStruct.pt.y);
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}

private const int WH_MOUSE_LL = 14;

private enum MouseMessages
{
WM_LBUTTONDOWN = 0x0201,
WM_LBUTTONUP = 0x0202,
WM_MOUSEMOVE = 0x0200,
WM_MOUSEWHEEL = 0x020A,
WM_RBUTTONDOWN = 0x0204,
WM_RBUTTONUP = 0x0205
}

[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public int x;
public int y;
}

[StructLayout(LayoutKind.Sequential)]
private struct MSLLHOOKSTRUCT
{
public POINT pt;
public uint mouseData;
public uint flags;
public uint time;
public IntPtr dwExtraInfo;
}

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId);

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
}

71104
14-05-2009, 09:46
PM per Federicoat :p

!k-0t1c!
14-05-2009, 09:54
Non so se hai letto bene l'articolo di cui ti avevo dato il link, ma in cima è disponibile il download di alcuni sorgenti, nello specifico: http://www.codeproject.com/KB/cs/globalhook/globalhook2_src.zip
(richiede registrazione)

Se scarichi quello avrai i sorgenti di una libreria chiamata Gma.UserActivityMonitor che - una volta aggiunta tra le dipendenze del tuo progetto in Visual C# - non richiede nient'altro che la definizione di un EventHandler per l'evento che vuoi gestire e poi l'aggiunta dell'evento in questo modo:

HookManager.MouseClick += TUO_EVENT_HANDLER;

e supporta MouseClick, MouseMove e tanti altri eventi (compresi quelli della tastiera).

MarcoGG
14-05-2009, 09:59
@MarcoGG, la tua soluzione per quanto possa funzionare è altamente inefficiente e consuma risorse della CPU in quantità comparata con i global hooks, fatti apposta per il proposito di Federicoat ed almeno altrettanto semplici da usare.


"Per quanto possa funzionare" non è certo l'ultima ruota del carro, direi. In quanto al fatto che sia "altamente inefficiente", vorrei averne una dimostrazione pratica e tangibile. A fare i sapientoni come te siamo capaci tutti. Che non sia il massimo dell'efficienza, e che i low level hooks siano una scelta migliore, ne posso convenire, sta di fatto che se Federicoat avesse da subito usato il mio metodo a quest'ora avrebbe già finito da un pezzo, invece sta sbattendo la testa con classi per lui poco comprensibili e che non riesce manco a compilare...
@ Federicoat : ovviamente se preferisci studiare il metodo dei Global Hooks in C#, hai la mia benedizione. :D ...

Federicoat
14-05-2009, 10:14
Non so se hai letto bene l'articolo di cui ti avevo dato il link, ma in cima è disponibile il download di alcuni sorgenti, nello specifico: http://www.codeproject.com/KB/cs/globalhook/globalhook2_src.zip
(richiede registrazione)

Se scarichi quello avrai i sorgenti di una libreria chiamata Gma.UserActivityMonitor che - una volta aggiunta tra le dipendenze del tuo progetto in Visual C# - non richiede nient'altro che la definizione di un EventHandler per l'evento che vuoi gestire e poi l'aggiunta dell'evento in questo modo:

HookManager.MouseClick += TUO_EVENT_HANDLER;

e supporta MouseClick, MouseMove e tanti altri eventi (compresi quelli della tastiera).

Ciao, ho guardato il codice da te proposto ma m i è troppo difficile creare le dipendenze nel mio progetto, però ho scaricato sempre da codeproject un altro codice
http://www.codeproject.com/KB/cs/globalhook.aspx
(Mouse Hook version 1)
E' perfetto per le mie esigenze, ma l'unico problema è che non vorrei che mi venisse mostrato il form... cioè, io ho solo bisogno di loggare in modo stealth senza mostrare il form dell'applicazione... c'è qualcuno che mi suggerisce come eliminare il form, senza smontare l'event handling che mi sembra perfetto...
Poi mi gestisco da solo il logging su file, quello non è un problema

!k-0t1c!
14-05-2009, 10:20
"Per quanto possa funzionare" non è certo l'ultima ruota del carro, direi. In quanto al fatto che sia "altamente inefficiente", vorrei averne una dimostrazione pratica e tangibile. A fare i sapientoni come te siamo capaci tutti. Che non sia il massimo dell'efficienza, e che i low level hooks siano una scelta migliore, ne posso convenire, sta di fatto che se Federicoat avesse da subito usato il mio metodo a quest'ora avrebbe già finito da un pezzo, invece sta sbattendo la testa con classi per lui poco comprensibili e che non riesce manco a compilare...
@ Federicoat : ovviamente se preferisci studiare il metodo dei Global Hooks in C#, hai la mia benedizione. :D ...
Promuovere il codice migliore e non la scelta più facile (che invece è spesso la più stupida) ma è una questione di buon senso. Non solo la conoscenza acquisita nel processo per arrivare ad utilizzare il codice che gli ho consilgiato (che tra l'altro richiede 10 righe e due click per funzionare, e non di più) gli tornerà utile in futuro, ma gli eviterà di scrivere cattivo codice.
La soluzione che gli hai proposto è comunque inaccettabile perché Federicoat ha specificato che gli serve qualcosa di leggero, e un loop che ogni volta fa diverse chiamate tramite P/Invoke è tutto meno che leggero. Nella programmazione non conta solo il risultato, contano molto anche i passaggi, e sembra che tu non sia disposto a recepire questo concetto; pertanto finché posterai soluzioni molto discutibili continuerò a criticarle come debito (vd. thread stringa/hex), astenendomi tuttavia da un dibattito che reputo sterile e limitandomi a mostrare a chi fa la domanda perché dovrebbe evitare l'uso della tua risposta.

!k-0t1c!
14-05-2009, 10:23
Ciao, ho guardato il codice da te proposto ma m i è troppo difficile creare le dipendenze nel mio progetto, però ho scaricato sempre da codeproject un altro codice
http://www.codeproject.com/KB/cs/globalhook.aspx
(Mouse Hook version 1)
E' perfetto per le mie esigenze, ma l'unico problema è che non vorrei che mi venisse mostrato il form... cioè, io ho solo bisogno di loggare in modo stealth senza mostrare il form dell'applicazione... c'è qualcuno che mi suggerisce come eliminare il form, senza smontare l'event handling che mi sembra perfetto...
Poi mi gestisco da solo il logging su file, quello non è un problema
Imposta la proprietà visible del form su false, ed eventualmente anche ShowInTaskbar su false; lo puoi fare aprendo l'editor visuale del form da Visual C# e cercando tra le proprietà.

Federicoat
14-05-2009, 10:40
Imposta la proprietà visible del form su false, ed eventualmente anche ShowInTaskbar su false; lo puoi fare aprendo l'editor visuale del form da Visual C# e cercando tra le proprietà.

La proprietà ShowInTaskbar l'ho trovata mentre visible no.
Per quanto riguarda la compilazione delle classi alla fine sono riuscito a farla correttamente. Quella che vi ho incollato prima non riuscivo a compilarla perchè sbagliavo a creare il progetto.
Cmq la mia NON esperienza in c# deriva dal fatto che io nella vita faccio l'analista programmatore Oracle, ma, lavorando in una ditta piccola ogni tanto ti capita di dover fare qualcosa fuori dal tuo lavoro e che in università non hai fatto.

!k-0t1c!
14-05-2009, 10:51
My bad, mi sono dimenticato che Form non ha Visible.
Ad ogni modo puoi fare facilmente così: apri l'editor visuale, fai doppio click sullo sfondo del form, ti porterà ad una schermata di codice, all'interno dell'eventhandler per l'evento Load del form, inserisci come riga
Hide();
e sei a posto.
E sì, capisco che sta roba rispetto ad Oracle non abbia nulla a che vedere :)

Federicoat
14-05-2009, 11:02
My bad, mi sono dimenticato che Form non ha Visible.
Ad ogni modo puoi fare facilmente così: apri l'editor visuale, fai doppio click sullo sfondo del form, ti porterà ad una schermata di codice, all'interno dell'eventhandler per l'evento Load del form, inserisci come riga
Hide();
e sei a posto.
E sì, capisco che sta roba rispetto ad Oracle non abbia nulla a che vedere :)


mmmm non funziona... facendo duobleClick sulla form mi porta in questa portzione di codice:

void MainFormLoad(object sender, System.EventArgs e)
{
Hide();
actHook = new UserActivityHook(); // crate an instance with global hooks
// hang on events
actHook.OnMouseActivity+=new MouseEventHandler(MouseMoved);
actHook.KeyDown+=new KeyEventHandler(MyKeyDown);
actHook.KeyPress+=new KeyPressEventHandler(MyKeyPress);
actHook.KeyUp+=new KeyEventHandler(MyKeyUp);
}


Nonostante la scritta hide(); continua a farmelo vedere... Cmq sono disposto anche ad eliminarlo... ho provato a scrivere application.run(); senza nome del form dentro ma così facendo smette di funzionare tutto...


public static void Main(string[] args)
{
Application.Run(new MainForm());
}

MarcoGG
14-05-2009, 11:40
Nonostante la scritta hide(); continua a farmelo vedere... Cmq sono disposto anche ad eliminarlo... ho provato a scrivere application.run(); senza nome del form dentro ma così facendo smette di funzionare tutto...


Infatti, non funzionerà mai così.
Il modo più breve per nascondere una Form è :
-> ShowInTaskbar = false
-> Opacity = 0
Proprietà che puoi già definire nella Form a designer.
Il metodo static void Main in Program.cs lascialo stare così com'è.

!fazz
14-05-2009, 11:43
sostituisci hide(); con this.hide();

e cmq occhio che quello che stai creando è illegale

!k-0t1c!
14-05-2009, 11:44
Infatti, non funzionerà mai così.
Il modo più breve per nascondere una Form è :
-> ShowInTaskbar = false
-> Opacity = 0
Proprietà che puoi già definire nella Form a designer.
Il metodo static void Main in Program.cs lascialo stare così com'è.
Già, Hide a quanto pare non ha effetto nell'evento Load, ad ogni modo confermo che se rimuovi la chiamata di Application.Run il tuo programma in sostanza non farà nulla.
Se proprio volessi eliminare il form potresti spostare la registrazione degli eventi

actHook.OnMouseActivity+=new MouseEventHandler(MouseMoved); actHook.KeyDown+=new KeyEventHandler(MyKeyDown);
actHook.KeyPress+=new KeyPressEventHandler(MyKeyPress);
actHook.KeyUp+=new KeyEventHandler(MyKeyUp);

nel Main seguita da un loop di questo genere:

while(true)
{
Application.DoEvents();
System.Threading.Thread.Sleep(250);
}

ma non avresti particolari vantaggi salvo un minor consumo di memoria.

Federicoat
14-05-2009, 11:50
Infatti, non funzionerà mai così.
Il modo più breve per nascondere una Form è :
-> ShowInTaskbar = false
-> Opacity = 0
Proprietà che puoi già definire nella Form a designer.
Il metodo static void Main in Program.cs lascialo stare così com'è.
Ok con la proprietà opacity sparisce.... Ma sa qual'è il problema (forse).. che in realtà esiste... quindi se questa finistra opacity si trova sopra ad un'icona questa icona non sarà cliccabile... o mi sbaglio???

Federicoat
14-05-2009, 11:51
sostituisci hide(); con this.hide();

e cmq occhio che quello che stai creando è illegale

provato con this.hide();... nulla da fare...

cionci
14-05-2009, 11:56
PM per Federicoat :p
Sanzione comminata qui: http://www.hwupgrade.it/forum/showthread.php?p=27486377#post27486377

MarcoGG
14-05-2009, 12:26
Ok con la proprietà opacity sparisce.... Ma sa qual'è il problema (forse).. che in realtà esiste... quindi se questa finistra opacity si trova sopra ad un'icona questa icona non sarà cliccabile... o mi sbaglio???

Lo dici perchè ti succede o perchè supponi che possa accadere ?
A me non succede, anche se imposto la Form a Maximized nel Load, perciò non dovresti preoccuparti di questo.
In ogni caso, se vuoi essere sicuro al 100%, puoi anche spostare la Form all'esterno dei limiti dello schermo visibile, impostando :
this.Left = Screen.PrimaryScreen.Bounds.X; ;)


provato con this.hide();... nulla da fare...

Certo, perchè è esattamente la stessa istruzione.

!k-0t1c!
14-05-2009, 12:57
Dai un'occhiata alla soluzione che ti ho proposto prima con il loop while, potrebbe fare al caso tuo e liberarti dal form che comunque non desideri. Ad ogni modo, come ti è già stato fatto notare, quel che vuoi fare è legale solo se lo fai a conoscenza dell'utente e con il suo consenso non solo per il logging ma anche per come tratti i dati salvati. Visto che comunque la soluzione in C# non ti consente di nascondere il processo, sappi che se l'intento non è benigno non andrai lontano.

MarcoGG
14-05-2009, 12:58
Nella programmazione non conta solo il risultato, contano molto anche i passaggi, e sembra che tu non sia disposto a recepire questo concetto; pertanto finché posterai soluzioni molto discutibili continuerò a criticarle come debito (vd. thread stringa/hex), astenendomi tuttavia da un dibattito che reputo sterile e limitandomi a mostrare a chi fa la domanda perché dovrebbe evitare l'uso della tua risposta.


Sono dispostissimo ad accettare consigli e correzioni da tutti, purchè le eventuali critiche siano ben documentate, cosa che di solito tu non fai.
Hai semplicemente postato un link ad una tecnica che dimostri di non aver provato, e infatti non sei ancora stato in grado di risolvere i problemi sollevati da Federicoat nell'utilizzarla.
Consigliare poi Form.Visible=false o .Hide nell'evento Load, beh... Lasciamo perdere...

Se alludi a questa discussione :
http://www.hwupgrade.it/forum/showthread.php?t=1858539
avevo espresso chiaramente il perchè della mia soluzione.

Se poi vogliamo parlare anche di questa :
http://www.hwupgrade.it/forum/showthread.php?t=1972573
beh, ero in fiduciosa attesa che tu predisponessi l'algoritmo più adeguato. :D

Continuerai a criticare le soluzioni che non reputi valide, e mi sta bene, e finchè continuerai a farlo in questo modo, continuerò anch'io a rispondere che è sempre molto più facile intervenire in una discussione come fai tu, di come lo faccio io.

!fazz
14-05-2009, 13:29
provato con this.hide();... nulla da fare...

io l'ho provata con un button e funzionava, nascondendomi il form, il problema mi sa che è sul load

MarcoGG
14-05-2009, 13:30
In ogni caso, se vuoi essere sicuro al 100%, puoi anche spostare la Form all'esterno dei limiti dello schermo visibile, impostando :
this.Left = Screen.PrimaryScreen.Bounds.X; ;)


Chiedo scusa e mi auto-correggo, volevo dire :
this.Left = Screen.PrimaryScreen.Bounds.Width; :)

!k-0t1c!
14-05-2009, 13:35
Sono dispostissimo ad accettare consigli e correzioni da tutti, purchè le eventuali critiche siano ben documentate, cosa che di solito tu non fai.
Hai semplicemente postato un link ad una tecnica che dimostri di non aver provato, e infatti non sei ancora stato in grado di risolvere i problemi sollevati da Federicoat nell'utilizzarla.
Consigliare poi Form.Visible=false o .Hide nell'evento Load, beh... Lasciamo perdere...

Se alludi a questa discussione :
http://www.hwupgrade.it/forum/showthread.php?t=1858539
avevo espresso chiaramente il perchè della mia soluzione.

Se poi vogliamo parlare anche di questa :
http://www.hwupgrade.it/forum/showthread.php?t=1972573
beh, ero in fiduciosa attesa che tu predisponessi l'algoritmo più adeguato. :D

Continuerai a criticare le soluzioni che non reputi valide, e mi sta bene, e finchè continuerai a farlo in questo modo, continuerò anch'io a rispondere che è sempre molto più facile intervenire in una discussione come fai tu, di come lo faccio io.
I consigli che ho dato erano le prime cose che mi sono passate per la testa ed avendo anche altro da fare non è che avessi speso tempo a verificarli. Certo è che la tua soluzione proposta in questo thread aveva dei drawbacks pazzeschi . Quanto al non aver provato la tecnica che ho linkato, ti sbagli, l'ho provata e funziona, ma Federicoat non aveva l'esperienza (né la pazienza) per fare i 2 click in visual studio e servirsene. Infine quanto agli altri threads, nel primo puoi giustificare il tuo post quanto vuoi, ma a conti fatti la tua proposta era inefficiente e prolissa, mentre nel secondo thread ho spiegato abbastanza quanto fosse inutile fornire un algoritmo perché era inutlie la richiesta. Se veramente uno sbatte contro un limite del GC che ha conseguenze negative (non 10k di memoria "sprecati" per 2minuti in un sistema con oltre 1GB libero) allora si valuta come procedere, ma un algoritmo per determinare quando forzare la garbage collection o come dimensionare il working set (cosa che nella vita di un normale programmatore potrebbe/dovrebbe accadere non più di 0 volte) senza che ce ne sia la reale esigenza è come dar la caccia alle zanzare con un bazooka.

Federicoat
14-05-2009, 13:46
Dai un'occhiata alla soluzione che ti ho proposto prima con il loop while, potrebbe fare al caso tuo e liberarti dal form che comunque non desideri. Ad ogni modo, come ti è già stato fatto notare, quel che vuoi fare è legale solo se lo fai a conoscenza dell'utente e con il suo consenso non solo per il logging ma anche per come tratti i dati salvati. Visto che comunque la soluzione in C# non ti consente di nascondere il processo, sappi che se l'intento non è benigno non andrai lontano.

No tranquilli... non voglio fare nulla di non legale...

Federicoat
14-05-2009, 14:07
OK piano piano sto riuscendo a raffinare il programma... adesso stavo procedendo con la scrittura delle informazioni sul file..
Ovviamente il file andrò aperto una sola volta allo start del processo e chiuso alla fine.

La domanda è... come posso chiudere il file di testo dal momento che viene terminato il processo??

!k-0t1c!
14-05-2009, 14:42
Supponendo che tu usi un FileStream o uno StreamWriter puoi usare il metodo Close sull'oggetto in questione semplicemente usando oggettoLogFile.Close() all'interno dell'evento ApplicationExit documentato di seguito
http://msdn.microsoft.com/en-us/library/system.windows.forms.application.applicationexit.aspx

Un esempio di codice è questo:

//.... dentro al Main
Application.ApplicationExit += new EventHandler(this.OnApplicationExit);
oggettoLogFile = new StreamWriter(percorso_del_file_di_log);
//.... fine blocco dentro al main


//nella stessa classe del Main
private StreamWriter oggettoLogFile;
private void OnApplicationExit(object sender, EventArgs e)
{
oggettoLogFile.Close();
}

In questo modo puoi usare oggettoLogFile.Write o oggettoLogFile.WriteLine per scrivere testo all'interno del file di log. Se volessi scrivere dati binari ti invito a consultare la documentazione di FileStream, da usare al posto di StreamWriter. Nota che entrambi richiedono di importare il namespace System.IO

Federicoat
14-05-2009, 15:09
Supponendo che tu usi un FileStream o uno StreamWriter puoi usare il metodo Close sull'oggetto in questione semplicemente usando oggettoLogFile.Close() all'interno dell'evento ApplicationExit documentato di seguito
http://msdn.microsoft.com/en-us/library/system.windows.forms.application.applicationexit.aspx

Un esempio di codice è questo:

//.... dentro al Main
Application.ApplicationExit += new EventHandler(this.OnApplicationExit);
oggettoLogFile = new StreamWriter(percorso_del_file_di_log);
//.... fine blocco dentro al main


//nella stessa classe del Main
private StreamWriter oggettoLogFile;
private void OnApplicationExit(object sender, EventArgs e)
{
oggettoLogFile.Close();
}

In questo modo puoi usare oggettoLogFile.Write o oggettoLogFile.WriteLine per scrivere testo all'interno del file di log. Se volessi scrivere dati binari ti invito a consultare la documentazione di FileStream, da usare al posto di StreamWriter. Nota che entrambi richiedono di importare il namespace System.IO

Mmmm non funziona....

//.... dentro al Main
Application.ApplicationExit += new EventHandler(this.OnApplicationExit);
oggettoLogFile = new StreamWriter(percorso_del_file_di_log);
//.... fine blocco dentro al main

Non me lo fa mettere nel main... mi dice che la parola chiave this non può essere usata in un metodo statico. L'ho messo nel mainFormLoad...

il resto me l'ha compilato correttamente... unico problema... non passa mai dentro:

private void OnApplicationExit(object sender, System.EventArgs e)
{
Console.WriteLine("aaaaa");
writer.Close();
}


Conta che questo processo terminerà sempre o con lo shutdown del sistema operativo o quando faccio le prove con lo stop della modalita Debug di visual Studio

Ho appena provato con i systemEvents ma niente:

SystemEvents.SessionEnding += new SessionEndingEventHandler(SystemEvents_SessionEnding);
SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(SystemEvents_PowerModeChanged);

!k-0t1c!
14-05-2009, 15:27
Scusa, oggi devo essere fuso, naturalmente ti da quell'errore, ma visto che credo di non sbagliare se penso che non vorrai mai più istanze di questa classe puoi aggiungere quanto mi ero dimenticato di scrivere, ovvero al posto di
private StreamWriter oggettoLogFile;
scrivi
private static StreamWriter oggettoLogFile;
e tutto compilerà e si eseguirà a dovere.

Federicoat
14-05-2009, 15:36
Scusa, oggi devo essere fuso, naturalmente ti da quell'errore, ma visto che credo di non sbagliare se penso che non vorrai mai più istanze di questa classe puoi aggiungere quanto mi ero dimenticato di scrivere, ovvero al posto di
private StreamWriter oggettoLogFile;
scrivi
private static StreamWriter oggettoLogFile;
e tutto compilerà e si eseguirà a dovere.

il problema non lo da li... ma su questa dichiarazione:
Application.ApplicationExit += new EventHandler(this.OnApplicationExit);

ti faccio vedere come sono messo adesso:


//dichiarazione all'interno della classe:
private StreamWriter writer;

//il main
public static void Main(string[] args)
{
Application.Run(new MainForm());
}

//il metodo MainFormLoad
void MainFormLoad(object sender, System.EventArgs e)
{
actHook = new UserActivityHook(); // crate an instance with global hooks
// hang on events
actHook.OnMouseActivity+=new MouseEventHandler(MouseMoved);
actHook.KeyDown+=new KeyEventHandler(MyKeyDown);
actHook.KeyPress+=new KeyPressEventHandler(MyKeyPress);
actHook.KeyUp+=new KeyEventHandler(MyKeyUp);

Application.ApplicationExit += new EventHandler(this.OnApplicationExit);
// Register for system events to detect user trying to log off or low memory condition
SystemEvents.SessionEnding += new SessionEndingEventHandler(SystemEvents_SessionEnding);
SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(SystemEvents_PowerModeChanged);

writer = new StreamWriter(@"C:/TestFile.txt", true);
}


.........

Adesso se faccio partire il mio programmino... vedo che crea il file nella dirictory... ma.. se ammazzo il processo tramite task manager il file rimane vuoto mentre se riavvio o spengo il computer il file contiene i dati da me scritti.

Penso che questo sia dovuto all'introduzione di: SystemEvents.SessionEnding


private void SystemEvents_SessionEnding(object sender, SessionEndingEventArgs e)
{
writer.Close();
}


Dimenticavo... ovviamente se apro e chiudo il file ogni volta che faccio un click tutto funziona... ma non penso che sia una buona idea....

cionci
16-05-2009, 13:53
71104: la tua sospensione è stata tramutata in ban personale in quanto utente destabilizzante per la comunità intera (art. 5b del regolamento).
Il ban personale ti vieta di iscriverti nuovamente al forum, ogni tuo tentativo sarà prontamente stroncato.