PDA

View Full Version : [VB.Net] Problema con API


birmarco
31-05-2009, 20:20
Ciao a tutti. Ho un problema con l'intercettazione dgli input da tastiera dalle API di windows. Per registrare uso queste righe di codice:

Public Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer
---------------------------------------
Public valoreRitorno As Integer = 0
---------------------------------------
Private Sub tmrInputTasti_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrImputTasti.Tick
'Controllo input da tatiera
Dim i As Integer
For i = 0 To 300
valoreRitorno = GetAsyncKeyState(i)
If valoreRitorno = -32768 Then
ListBox1.Items.Add(i & " -> " & Chr(i))
Select Case (i)
Case 97
btn1.PerformClick()
Case 49
btn1.PerformClick()
Case Else
'...
End Select
End If
Next i
End Sub

Il listbox è per registrare i numeri di input tasti
Il tick del timer è impostato a 10ms ed è enabled. Nel Form Load ho impostato l'avvio del timer ( tmrInputTasti.Start() )

Il problema è che non funziona...:confused: Non dà errore ma se premo i tasti non succede nulla. Non sono molto esperto e credevo fosse "user32" a creare problemi (uso windows 7 x64) ma user64 non esiste e a riconferma in un'altro programma che ho fatto in cui uso questa procedura funziona tutto. Come impostazioni compilatore ho impostato "Per CPU x64" ma non va nemmeno con "Any CPU". Idee?? Grazie mille a chi mi aiuta! :)

birmarco
31-05-2009, 20:34
Ho trovato il problema: è la compilazione a 64bit. Il problema non si presenta impostando x86 ma si presenta con "Any CPU" e "x64". Come faccio per usare la funzione a 64bit??

birmarco
31-05-2009, 21:36
UP!

MarcoGG
01-06-2009, 10:29
Non avendo gran dimestichezza con i S.O. 64bit, la prima domanda è : sicuro che in Win7 64 ci sia una user32.dll ? :p
Quasi certamente, sì.
Il VS da cui sviluppi/compili è su Win-32 o su Win7-64 ?
Infine, mi pare di aver capito che il tuo compilato X86, come lecito aspettarsi, funziona sia su 32 che su 64, mentre quello che mi suona strano è l'AnyCpu che da problemi...
Dal momento che la stragrande maggioranza del software applicativo che c'è in giro è a 32bit ( da quel che so, solo chi scrive antivirus, drivers ecc... è praticamente costretto a fare 2 versioni separate... ), e sarà così per un bel pezzo ancora, il mio umile consiglio è : mettiti l'animo in pace e compila per X86... :stordita:

birmarco
02-06-2009, 16:19
Non avendo gran dimestichezza con i S.O. 64bit, la prima domanda è : sicuro che in Win7 64 ci sia una user32.dll ? :p
Quasi certamente, sì.
Il VS da cui sviluppi/compili è su Win-32 o su Win7-64 ?
Infine, mi pare di aver capito che il tuo compilato X86, come lecito aspettarsi, funziona sia su 32 che su 64, mentre quello che mi suona strano è l'AnyCpu che da problemi...
Dal momento che la stragrande maggioranza del software applicativo che c'è in giro è a 32bit ( da quel che so, solo chi scrive antivirus, drivers ecc... è praticamente costretto a fare 2 versioni separate... ), e sarà così per un bel pezzo ancora, il mio umile consiglio è : mettiti l'animo in pace e compila per X86... :stordita:

Uso Visual Studio 2008 Professional x64 su Windows 7 64 bit. Software scritto e compilato sotto windows 7 x64 con VS08 PRO. La mia idea era di fare 2 versioni: una a 64bit e una a 32bit. Preferisco di gran lunga a 64bit visto che è il futuro. Le mie applicazioni non sono certo il futuro :p ma odio avere SW virtualizzati a 32 bit. Cmq va bè... mi metterò il cuore in pace :( . Ma la differenza tra SW a 64bit e a 32bit è come imposti il compilatore (detto in soldoni...)?? Se imposto il compilatore a 32bit l'applicazione viene virtualizzata, se imposto a 64bit no. Quindi a 64 bit è, ma quello che non so è se si comporta veramente a 64bit... ne sai qualcosa a riguardo?

Cmq grazie!

MarcoGG
02-06-2009, 19:33
Uso Visual Studio 2008 Professional x64 su Windows 7 64 bit. Software scritto e compilato sotto windows 7 x64 con VS08 PRO. La mia idea era di fare 2 versioni: una a 64bit e una a 32bit. Preferisco di gran lunga a 64bit visto che è il futuro. Le mie applicazioni non sono certo il futuro :p ma odio avere SW virtualizzati a 32 bit. Cmq va bè... mi metterò il cuore in pace :( . Ma la differenza tra SW a 64bit e a 32bit è come imposti il compilatore (detto in soldoni...)?? Se imposto il compilatore a 32bit l'applicazione viene virtualizzata, se imposto a 64bit no. Quindi a 64 bit è, ma quello che non so è se si comporta veramente a 64bit... ne sai qualcosa a riguardo?

Cmq grazie!

Il 64 bit è il futuro... Solo bisognerebbe farsi un'idea di quanto vicino e necessario sia questo "futuro". Voglio dire, ci sono aziende e aziende che camminano ancora col Cobol, e noi si discute sul fatto che sia più o meno performante un applicativo .NET compilato x64 su piattaforma x64, o un x86... Mah... Ammetto di non aver fatto nessun test in quel senso. Sono problemi che mi porrò quando ne avrò bisogno...
Qualche tempo fa avevo letto alcune statistiche sulla diffusione dei S.O. a 64 bit, e mi è sembrato un discorso marginale. C'è ancora molta gente che, se si parla di WinXP, l'unico che conosce è il 32, mentre non sospetta ne esista uno a 64. Per quanto riguarda Vista, avevo letto che tra gli utenti ad averlo accolto con maggior freddezza, c'erano proprio quelli che del pc ne fanno uso professionale, figuriamoci poi Vista 64...

Sulla tua ultima domanda, direi che è così, nel senso che se compili x86 hai la certezza che giri dappertutto, con x64 su S.O. 64 sfrutterà i vantaggi della piattaforma, e cmq l'exe prodotto è diverso, tanto che se provi ad seguirlo su WinXP 32 non gira.

La spiegazione che forse mi convince di più, al momento è questa :

In the wonderful world of .NET development, applications and assemblies can be compiled to target various platforms. By default, applications and assemblies are compiled as Any CPU in Visual Studio. In this scenario, the CLR will load the assembly as whatever the default target is for the machine it is being executed on. For example, when running an executable on an x64 machine, it will be run as a 64-bit process.

Visual Studio also provides for 3 specific platform targets: x86, x64 and Itanium (IA-64). When building an executable as a specific target, it will be loaded as a process of that type. For example, an x86-targeted executable run on an x64 machine will run as a 32-bit process using the 32-bit CLR and WOW64 layer. When assemblies are loaded at runtime, they can only be loaded by a process if their target matches that of the hosting process, or it is compiled as Any CPU. For example, if x64 were set as the target for an assembly, it can only be loaded by an x64 process.

birmarco
02-06-2009, 21:12
Il 64 bit è il futuro... Solo bisognerebbe farsi un'idea di quanto vicino e necessario sia questo "futuro". Voglio dire, ci sono aziende e aziende che camminano ancora col Cobol, e noi si discute sul fatto che sia più o meno performante un applicativo .NET compilato x64 su piattaforma x64, o un x86... Mah... Ammetto di non aver fatto nessun test in quel senso. Sono problemi che mi porrò quando ne avrò bisogno...
Qualche tempo fa avevo letto alcune statistiche sulla diffusione dei S.O. a 64 bit, e mi è sembrato un discorso marginale. C'è ancora molta gente che, se si parla di WinXP, l'unico che conosce è il 32, mentre non sospetta ne esista uno a 64. Per quanto riguarda Vista, avevo letto che tra gli utenti ad averlo accolto con maggior freddezza, c'erano proprio quelli che del pc ne fanno uso professionale, figuriamoci poi Vista 64...

Sulla tua ultima domanda, direi che è così, nel senso che se compili x86 hai la certezza che giri dappertutto, con x64 su S.O. 64 sfrutterà i vantaggi della piattaforma, e cmq l'exe prodotto è diverso, tanto che se provi ad seguirlo su WinXP 32 non gira.

La spiegazione che forse mi convince di più, al momento è questa :

In the wonderful world of .NET development, applications and assemblies can be compiled to target various platforms. By default, applications and assemblies are compiled as Any CPU in Visual Studio. In this scenario, the CLR will load the assembly as whatever the default target is for the machine it is being executed on. For example, when running an executable on an x64 machine, it will be run as a 64-bit process.
Visual Studio also provides for 3 specific platform targets: x86, x64 and Itanium (IA-64). When building an executable as a specific target, it will be loaded as a process of that type. For example, an x86-targeted executable run on an x64 machine will run as a 32-bit process using the 32-bit CLR and WOW64 layer. When assemblies are loaded at runtime, they can only be loaded by a process if their target matches that of the hosting process, or it is compiled as Any CPU. For example, if x64 were set as the target for an assembly, it can only be loaded by an x64 process.

Forse è per questo che la mia chiamata alla user32 non funziona con Any CPU dal momento che, essendo su x64, viene eseguita a 64bit.

Lasciando perdere l'utente medio, il 64bit si sta iniziando a diffondere anche in ambito professionale. Si pensi a Photoshop Extended CS4 che esiste anche in versione 64bit. I software Autodesk esistono in doppia versione e anche i software di minore importanza dispondogo del corrispettivo a 64bit. Anche WinRAR c'è a 64bit...

Sono d'accordo che non è molto diffuso cmq muoversi in quella direzione trovo sia una buona cosa. Non sono uno sviluppatore però, se posso dire la mia, non capisco come mai non si facciano SW a 64bit: su VB basta una stupida spunta e cambiare 4 righe di codice...

Saresti così gentile da spiegarmi come funziona la procedura paso passo che così magari riesco a capire come convertirla a 64bit? (Questa la scrivesti tu, sempre per me, qualche mese fa :D )

In generale la capisco ma ci sono alcuni passaggi che ho scritto proprio senza capirli... :p


Public Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer 'vKey che cosa mi rappresenta? User32 si chiama 32 perchè siamo su 32bit, no? Su 64bit come si chiama??? Perchè vKey è Long??? I tasti non sono così tanti...
---------------------------------------
Public valoreRitorno As Integer = 0
---------------------------------------
Private Sub tmrInputTasti_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrImputTasti.Tick
'Controllo input da tatiera
Dim i As Integer
For i = 0 To 300 'Perchè il tutto è in un for???
valoreRitorno = GetAsyncKeyState(i)
If valoreRitorno = -32768 Then 'Perchè -32768??32678 è il massimo per gli Integer, se restituisco in Int64 sarebbe 65K e rotti? Da cosa deriva quel -32678?
ListBox1.Items.Add(i & " -> " & Chr(i))
Select Case (i)
Case 97
btn1.PerformClick()
Case 49
btn1.PerformClick()
Case Else
'...
End Select
End If
Next i
End Sub

MarcoGG
03-06-2009, 11:23
Sì, ricordo, anche se non penso di averti suggerito io quel For i = 0 To 300... Bisognerebbe controllare solo i valori di interesse...

Comunque :

1. Che io sappia le cose sui vari Win 64 stanno così :
di user32.dll ce n'è una in XP32, mentre a quanto so io ce ne sono 2, ad es. in Vista64, la versione a 64 bit di user32, si chiama sempre user32.dll, e sta in C:\WINDOWS\System32\ , mentre la versione a 32 bit ( sempre user32.dll ) starebbe in C:\WINDOWS\SysWOW64\.
Ma queste sono cose che devi verificare meglio tu, in quanto stai usando un Win64... In ogni caso se cerchi una "user64.dll" temo rimarrai deluso.
Il perchè di tutto ciò lo sa solo Iddio e qualcuno alla MS, personalmente è solo uno tra i molti motivi che mi hanno fatto cestinare Vista.
Non so se in Win7 abbiano imparato la lezione... Lo proverò quando uscirà in versione finale...

2. vKey ecc... : la confusione deriva dal fatto che probabilmente ti avevo postato un codice preso da VB6 e riadattato velocemente per VB.NET.
In VB6 Integer è un intero con segno da 2 byte, mentre Long è a 4 byte.
Perciò Integer e Long in VB.NET non corrispondono. Sono più grandi.
E Long in VB.NET è un int64, un tipo di intero che in VB6 non esiste.

La signature corretta in VB.NET è questa :
Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Int32) As Int16

Significa che in VB.NET la posso anche scrivere :
Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Integer) As Short

Mentre in VB6, appunto :
Public Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer

Sicuramente sia il parametro di input, sia il valore in output sono sovradimensionati, ma non è un problema. Sono i valori richiesti da quella funzione API, come il fatto del valore di ritorno uguale all'estremo negativo del tipo int16. Bisogna documentarsi a fondo, per sapere l'esatto perchè, e di solito il mio approccio pratico alle cose non va proprio a nozze con questo tipo di "ricerche"... ;)

3. For : il For serve a controllare un range di tasti in un intervallo contiguo, per evitare di fare una lunga serie di If...

4. In conclusione ti riformulo l'esempio in modo forse più comprensibile e sicuramente più snello e adatto a VB.NET : poniamo debba intercettare tutti i tasti alfanumerici + 3 tasti speciali :

Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Int32) As Int16
Private vK As Int32 = 0
Private Const vOk As Int16 = -32767

Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick

'tasti ordinari
For Me.vK = 48 To 57 ' 0123456789
If GetAsyncKeyState(vK) = vOk Then ListBox1.Items.Add(Chr(vK))
Next vK
For Me.vK = 65 To 90 ' ABCDEFGHIJKLMNOPQRSTUVWXYZ
If GetAsyncKeyState(vK) = vOk Then ListBox1.Items.Add(Chr(vK))
Next vK

'tasti speciali
'F12
If GetAsyncKeyState(Keys.F12) = vOk Then ListBox1.Items.Add("F12")

'Right-CTRL
If GetAsyncKeyState(Keys.RControlKey) = vOk Then ListBox1.Items.Add("R-CTRL")

'NumPad 5
If GetAsyncKeyState(Keys.NumPad5) = vOk Then ListBox1.Items.Add("NumPad 5")

End Sub

Infine, se ti appassionano i global hooks ( a me per niente :D ) , ovviamente usando VB.NET le possibilità sono più ampie. Vedi anche questo articolo, che propone una strada alternativa :
http://www.developer.com/net/vb/article.php/10926_2193301_1

;)

birmarco
03-06-2009, 18:29
Sì, ricordo, anche se non penso di averti suggerito io quel For i = 0 To 300... Bisognerebbe controllare solo i valori di interesse...

Comunque :

1. Che io sappia le cose sui vari Win 64 stanno così :
di user32.dll ce n'è una in XP32, mentre a quanto so io ce ne sono 2, ad es. in Vista64, la versione a 64 bit di user32, si chiama sempre user32.dll, e sta in C:\WINDOWS\System32\ , mentre la versione a 32 bit ( sempre user32.dll ) starebbe in C:\WINDOWS\SysWOW64\.
Ma queste sono cose che devi verificare meglio tu, in quanto stai usando un Win64... In ogni caso se cerchi una "user64.dll" temo rimarrai deluso.
Il perchè di tutto ciò lo sa solo Iddio e qualcuno alla MS, personalmente è solo uno tra i molti motivi che mi hanno fatto cestinare Vista.
Non so se in Win7 abbiano imparato la lezione... Lo proverò quando uscirà in versione finale...

2. vKey ecc... : la confusione deriva dal fatto che probabilmente ti avevo postato un codice preso da VB6 e riadattato velocemente per VB.NET.
In VB6 Integer è un intero con segno da 2 byte, mentre Long è a 4 byte.
Perciò Integer e Long in VB.NET non corrispondono. Sono più grandi.
E Long in VB.NET è un int64, un tipo di intero che in VB6 non esiste.

La signature corretta in VB.NET è questa :
Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Int32) As Int16

Significa che in VB.NET la posso anche scrivere :
Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Integer) As Short

Mentre in VB6, appunto :
Public Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer

Sicuramente sia il parametro di input, sia il valore in output sono sovradimensionati, ma non è un problema. Sono i valori richiesti da quella funzione API, come il fatto del valore di ritorno uguale all'estremo negativo del tipo int16. Bisogna documentarsi a fondo, per sapere l'esatto perchè, e di solito il mio approccio pratico alle cose non va proprio a nozze con questo tipo di "ricerche"... ;)

3. For : il For serve a controllare un range di tasti in un intervallo contiguo, per evitare di fare una lunga serie di If...

4. In conclusione ti riformulo l'esempio in modo forse più comprensibile e sicuramente più snello e adatto a VB.NET : poniamo debba intercettare tutti i tasti alfanumerici + 3 tasti speciali :

Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Int32) As Int16
Private vK As Int32 = 0
Private Const vOk As Int16 = -32767

Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick

'tasti ordinari
For Me.vK = 48 To 57 ' 0123456789
If GetAsyncKeyState(vK) = vOk Then ListBox1.Items.Add(Chr(vK))
Next vK
For Me.vK = 65 To 90 ' ABCDEFGHIJKLMNOPQRSTUVWXYZ
If GetAsyncKeyState(vK) = vOk Then ListBox1.Items.Add(Chr(vK))
Next vK

'tasti speciali
'F12
If GetAsyncKeyState(Keys.F12) = vOk Then ListBox1.Items.Add("F12")

'Right-CTRL
If GetAsyncKeyState(Keys.RControlKey) = vOk Then ListBox1.Items.Add("R-CTRL")

'NumPad 5
If GetAsyncKeyState(Keys.NumPad5) = vOk Then ListBox1.Items.Add("NumPad 5")

End Sub

Infine, se ti appassionano i global hooks ( a me per niente :D ) , ovviamente usando VB.NET le possibilità sono più ampie. Vedi anche questo articolo, che propone una strada alternativa :
http://www.developer.com/net/vb/article.php/10926_2193301_1

;)

Sì, è vero nel for andavi da 65 a 67 ma io per sicurezza e includere tasti come shift ecc ho messo 300 e via... :D

Grazie mille per la funzione VB.Net dei tasti, ora è molto più chiara... un po' meno quella dei tipi di variabile anche perchè non ho mai sentito di variabili short... :D Dimmi se ho capito bene, da VB6 a .NET:

- Int -> Short (Int16)
- Long -> Integer (Int32)

C'è forse uno shift dei tipi? Ma esiste una differenza tra Int64 e Long? Se esistono gli short, perchè vengono usati più spesso gli integer?

Più che gli imput da tastiera ora come ora mi interessano le varie interazioni con l'ambiente di sistema (user32....) anche se prima forse dovrei studiarmi i database :D e il salvataggio lettura dei file (almeno di testo) :D :D

PS. Ho notato che un imput da numpad (es tasto 5) da un numero di imput differente rispetto ai numeri "sopre le lettere" (sempre per il numero 5, ad es), ma a lato pratico se schiaccio 5 sia sul tastierino che non l'applicazione risponde nel medesimo modo.... Strano... (Num Lock attivo)

MarcoGG
03-06-2009, 23:30
Grazie mille per la funzione VB.Net dei tasti, ora è molto più chiara... un po' meno quella dei tipi di variabile anche perchè non ho mai sentito di variabili short... :D Dimmi se ho capito bene, da VB6 a .NET:

- Int -> Short (Int16)
- Long -> Integer (Int32)

C'è forse uno shift dei tipi? Ma esiste una differenza tra Int64 e Long? Se esistono gli short, perchè vengono usati più spesso gli integer?


VB.NET :
- Short = Int16 signed
- Integer = Int32 signed
- Long = Int64 signed

VB6 :
- Short > N.D.
- Integer > Int16 signed
- Long > Int32 signed

Inoltre VB.NET ha i tipi Integer unsigned ( che ti permettono di raddoppiare il valore max, sul semiasse positivo ) : UShort, UInteger, ULong, che sono assenti in VB6.
Se vuoi farti un'idea dei valori estremi raggiungibili dai vari tipi, basta leggerne MaxValue e MinValue :
Dim a As ULong
MsgBox(a.MinValue & " > " & a.MaxValue)
Integer è l'intero usato più spesso, perchè forse è il più flessibile di tutti, perchè molti sviluppatori che provengono da VB6 ignorano Short, e anche perchè a molti non piace avere 8 tipi intero da gestire ( ci sono anche Byte e SByte... ).
Nella vita reale, già un Integer è sovrabbondante, un ULong è "cosmico" ( fai il MaxValue su ULong e ottieni : 18'446'744'073'709'551'615 ) :D .


PS. Ho notato che un imput da numpad (es tasto 5) da un numero di imput differente rispetto ai numeri "sopre le lettere" (sempre per il numero 5, ad es), ma a lato pratico se schiaccio 5 sia sul tastierino che non l'applicazione risponde nel medesimo modo.... Strano... (Num Lock attivo)


Cioè ? Chiaro, se NumLock è ON, darà sempre 5, ma il mio codice distingue tra i due tasti, perchè hanno codici diversi.
In ogni caso puoi anche gestire il NumLock :

'NumLock
If GetAsyncKeyState(Keys.NumLock) = vOk Then
If My.Computer.Keyboard.NumLock = True Then
ListBox1.Items.Add("NumLock ON")
Else
ListBox1.Items.Add("NumLock OFF")
End If
End If

;)

birmarco
04-06-2009, 21:37
VB.NET :
- Short = Int16 signed
- Integer = Int32 signed
- Long = Int64 signed

VB6 :
- Short > N.D.
- Integer > Int16 signed
- Long > Int32 signed

Inoltre VB.NET ha i tipi Integer unsigned ( che ti permettono di raddoppiare il valore max, sul semiasse positivo ) : UShort, UInteger, ULong, che sono assenti in VB6.
Se vuoi farti un'idea dei valori estremi raggiungibili dai vari tipi, basta leggerne MaxValue e MinValue :
Dim a As ULong
MsgBox(a.MinValue & " > " & a.MaxValue)
Integer è l'intero usato più spesso, perchè forse è il più flessibile di tutti, perchè molti sviluppatori che provengono da VB6 ignorano Short, e anche perchè a molti non piace avere 8 tipi intero da gestire ( ci sono anche Byte e SByte... ).
Nella vita reale, già un Integer è sovrabbondante, un ULong è "cosmico" ( fai il MaxValue su ULong e ottieni : 18'446'744'073'709'551'615 ) :D .



Cioè ? Chiaro, se NumLock è ON, darà sempre 5, ma il mio codice distingue tra i due tasti, perchè hanno codici diversi.
In ogni caso puoi anche gestire il NumLock :

'NumLock
If GetAsyncKeyState(Keys.NumLock) = vOk Then
If My.Computer.Keyboard.NumLock = True Then
ListBox1.Items.Add("NumLock ON")
Else
ListBox1.Items.Add("NumLock OFF")
End If
End If

;)

Nella teoria, ma nella pratica basta impostare per i tasti numerici normali e va anche col tastierino. Prova ;)

MarcoGG
05-06-2009, 09:15
Nella teoria, ma nella pratica basta impostare per i tasti numerici normali e va anche col tastierino. Prova ;)

Non ho capito cosa intendi. Cosa dovrei impostare, per vedere quale risultato ? :stordita:

birmarco
05-06-2009, 16:30
Non ho capito cosa intendi. Cosa dovrei impostare, per vedere quale risultato ? :stordita:

Mettiamo che il tasto 5 abbia come codice corrispondente 80 e che il tasto 5 del tastierino numerico abbia codice 90. Impostando la tua funzione con:


....

case 80
txtBox1.text = txtBox1.text + "5"
....



si ha un'aggiunta del numero 5 nella text box 1 ogni volta che si preme 5. Sia il 5 (quello col % sopre) che quello del tastierino. Non importa se c'è o no il case 90, il tastierino funziona ugualmente ;)

MarcoGG
05-06-2009, 17:04
Mettiamo che il tasto 5 abbia come codice corrispondente 80 e che il tasto 5 del tastierino numerico abbia codice 90. Impostando la tua funzione con:


....

case 80
txtBox1.text = txtBox1.text + "5"
....



si ha un'aggiunta del numero 5 nella text box 1 ogni volta che si preme 5. Sia il 5 (quello col % sopre) che quello del tastierino. Non importa se c'è o no il case 90, il tastierino funziona ugualmente ;)

Funziona ugualmente perchè evidentemente lo gestisci nel tuo codice ( con i che va da 0 a 300 ). Se fosse come dici tu, questo codice dovrebbe aggiungere un 5 sia dal tasto 5 ( codice 53 ), sia dal tasto NumPad5 :

Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick

If GetAsyncKeyState(53) = vOk Then ListBox1.Items.Add("5")

End Sub

Invece non succede... :mbe: . Sente solo il tasto 5, mentre non sente il NumPad5... Non so se è questo che intendevi... :D

birmarco
06-06-2009, 17:39
Funziona ugualmente perchè evidentemente lo gestisci nel tuo codice ( con i che va da 0 a 300 ). Se fosse come dici tu, questo codice dovrebbe aggiungere un 5 sia dal tasto 5 ( codice 53 ), sia dal tasto NumPad5 :

Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick

If GetAsyncKeyState(53) = vOk Then ListBox1.Items.Add("5")

End Sub

Invece non succede... :mbe: . Sente solo il tasto 5, mentre non sente il NumPad5... Non so se è questo che intendevi... :D

Quest'ultimo codice che hai postato non è quello che ho usato. Io ho usato quello con il for 0 to 300... i codici dei tasti li gestisce tutti i due dato che sono minori di 300, tuttavia basta impostare il case solo per uno dei due pulsanti 5 che funziona tutti e due. Ad esempio scrivere


....
For i=0 To 300
...
Case 53 '5
btnOK.PerformClick()
Case 101 'NumPad 5, NumLock Enable
btnOK.PerformClick()
...


è la stessa cosa di scrivere


....
For i=0 To 300
...
Case 53 '5
btnOK.PerformClick()
...


Passando dal primo al secondo codice per l'utente finale non cambia nulla: entrambi i tasti 5 funzionano. E' comodo per risparmiarsi righe di codice.

Altra cosa interessante: se premo il numpad5 con il num lock attivato nella listbox utilizzata per il debug compare 101 -> e invece di 101 -> 5. Perchè?

MarcoGG
07-06-2009, 09:04
Allora, vediamo di capirci. Torniamo al tuo codice iniziale e proviamo a gestire solo i due tasti, 5 e NumPad5.
Anzitutto il tuo valore di 300 è inutile, in quanto il parametro vKey è destinato a contenere valori da 0 a 255, come espressamente dichiarato nella documentazione MSDN della GetAsyncKeyState :
vKey
[in] Specifies one of 256 possible virtual-key codes

Perciò mettiamo di avere questo codice, nel Timer :

Dim i As Integer
For i = 0 To 255
valoreRitorno = GetAsyncKeyState(i)
If valoreRitorno = -32768 Then
Select Case (i)
Case 53 'Tasto 5
ListBox1.Items.Add("5")
Case 101 'NumPad 5
ListBox1.Items.Add("5")
Case Else
'...
End Select
End If
Next i

Questo sente sia il 5, sia il NumPad5.
Mentre il codice seguente, eliminando la gestione del 101, NO. :

Dim i As Integer
For i = 0 To 255
valoreRitorno = GetAsyncKeyState(i)
If valoreRitorno = -32768 Then
Select Case (i)
Case 53 'Tasto 5
ListBox1.Items.Add("5")
Case Else
'...
End Select
End If
Next i

Come è logico aspettarsi, in questo caso il NumPad5 non viene più ascoltato, perciò non capisco quando dici che il codice 53 è in grado di gestire anche il numpad. Da me no. Prova questi codici, se effettivamente c'è questo comportamento, evidentemente la user32.dll del Win64 che usi tu è diversa ed espone una GetAsyncKeyState che funziona in modo diverso... :mbe:

Infine vorrei fare chiarezza sul discorso del vKey. vKey NON è il codice ASCII della lettera associata al tasto premuto.
Esiste una corrispondenza tra codici vKey ( Virtual-Key Codes ) della tastiera, e tabella ASCII su tutti i caratteri alfanumerici, la spacebar, più pochi altri tasti "standard".
In questo caso solamente ha senso usare quel For e farsi ritornare la lettera/numero/simbolo del tasto premuto con la funzione Chr(). Per tutti gli altri casi ( tasti funzione, tasti NumPad ecc... ) i codici vKey e Ascii non corripsondono più, e infatti se si decide di costruire un vero e proprio keylogger usando GetAsyncKeyState, si dovrà creare una casistica completa, non basata sulla tabella Ascii, ma sulla tabella dei Virtual-Key Codes :

http://msdn.microsoft.com/en-us/library/ms645540(VS.85).aspx

Fortunatamente il buon VB ha lo spacename My. e in più l'Enum Keys. grazie ai quali il lavoro è notevolmente facilitato ( niente gestione diretta dei valori esadecimali delle Virtual-Key Codes ).

Quindi, in conclusione, quando mi avevi chiesto un buon sistema per mappare alcuni tasti alfa (A, B, C) la risposta fu naturalmente GetAsyncKeyState(), perchè senza spendere fiumi di codice su hooks di basso livello, con tre righe potevi risolvere. Chiaro che adesso se ti vuoi allargare e mappare tutta la tastiera dovrai andare ben oltre quel semplice For... ;)

Spero di essere stato chiaro. :)