Ecco la macro:
Sub CercaArtista()
'
' CercaArtista Macro
' Macro registrata il 12/12/2006 da M.E.W.O
'
'
Dim criterio
criterio = InputBox("Digitare il nome dell'Artista", "Cerca
Artista")
Range("A:A").Select
Selection.AutoFilter
Selection.AutoFilter Field:=1, Criteria1:=criterio
Range("A:A").Select
Columns("A:A").Select
End Sub
> Ecco il mio problema.
> Ho un semplice elenco in excel formato da 5 colonne:
> artista | album | codice | cd | note
> e svariate righe.
> Ho creato una macro (assegnata ad una immagine nel foglio excel) , per
> la ricerca dell'artista, ma cosě come si propone se nella finestra di
> ricerca che mi si apre non digito i due * uno all'inizio e uno alla
> fine della parola inserita non mi trova nulla, in quanto il campo
> artista puň contenere piů di una parola!
> Vorrei eseguire la ricerca senza dover digitare ogni volta * *, ma
> semplicemente che la macro esegua la ricerca nelle celle che
> contengono anche parte della parola inserita!
> Come posso fare?
> Grazie!
>
> Ecco la macro:
>
> Sub CercaArtista()
> '
> ' CercaArtista Macro
> ' Macro registrata il 12/12/2006 da M.E.W.O
> '
>
> '
> Dim criterio
> criterio = InputBox("Digitare il nome dell'Artista", "Cerca
> Artista")
> Range("A:A").Select
> Selection.AutoFilter
> Selection.AutoFilter Field:=1, Criteria1:=criterio
> Range("A:A").Select
> Columns("A:A").Select
> End Sub
Ciao Flavio,
prova qualcosa del genere:
Sub CercaArtista()
Dim criterio As String
criterio = InputBox("Digitare il nome dell'Artista", "Cerca
Artista")
criterio = "*" & criterio & "*"
Range("A:A").Select
Selection.AutoFilter
Selection.AutoFilter Field:=1, Criteria1:=criterio
Range("A:A").Select
Columns("A:A").Select
End Sub
scritta direttamente qua e non testata...
--
Spero d'esserti stato d'aiuto.
Ti ringrazio anticipatamente per il riscontro.
Ciao
Franz Verga
'------------------
Ho un semplice elenco in excel formato da 5 colonne:
artista | album | codice | cd | note
e svariate righe.
Ho creato una macro (assegnata ad una immagine nel foglio excel) , per
la ricerca dell'artista, ma cosě come si propone se nella finestra di
ricerca che mi si apre non digito i due * uno all'inizio e uno alla
fine della parola inserita non mi trova nulla, in quanto il campo
artista puň contenere piů di una parola!
Vorrei eseguire la ricerca senza dover digitare ogni volta * *, ma
semplicemente che la macro esegua la ricerca nelle celle che contengono
anche parte della parola inserita!
'------------------
Prova:
'=============>>
Public Sub CercaArtista()
Dim criterio As String
criterio = InputBox(Prompt:="Digitare il nome dell'Artista", _
Title:="Cerca Artista ")
With Range("A1")
.AutoFilter Field:=1, _
Criteria1:="*" & criterio & "*"
End With
End Sub
'<<=============
---
Regards,
Norman
> prova qualcosa del genere:
>
> Sub CercaArtista()
>
> Dim criterio As String
> criterio = InputBox("Digitare il nome dell'Artista", "Cerca
> Artista")
>
> criterio = "*" & criterio & "*"
>
> Range("A:A").Select
> Selection.AutoFilter
> Selection.AutoFilter Field:=1, Criteria1:=criterio
> Range("A:A").Select
> Columns("A:A").Select
> End Sub
>
>
> scritta direttamente qua e non testata...
>
> --
> Spero d'esserti stato d'aiuto.
>
> Ti ringrazio anticipatamente per il riscontro.
>
> Ciao
>
> Franz Verga
_____________________________________
Norman Jones ha scritto:
>Prova:
>
>'=============>>
>Public Sub CercaArtista()
> Dim criterio As String
>
> criterio = InputBox(Prompt:="Digitare il nome dell'Artista", _
> Title:="Cerca Artista ")
> With Range("A1")
> .AutoFilter Field:=1, _
> Criteria1:="*" & criterio & "*"
> End With
>
>End Sub
>'<<=============
>
>---
>Regards,
>Norman
Perfetto!!!
Grazie mille mi avete risolto un bel problema, prima di postare, da
bravo "nubbino" ho cercato ma aimè invano.
Ho testato tutte e due le macro con esito positio!
flavio
Ciao flavio.
Forse ti interessera' sapere che "testare" vuol dire (anche) provare a
vedere cosa succede quando si premono *tutti* i pulsanti presenti nelle
finestre, di dialogo e no, del progetto. Quindi anche il pulsante
"Annulla" della finestra di dialogo prodotta dall'istruzione "InputBox".
Perche' l'utente del tuo progetto potrebbe voler rinunciare
all'immissione, visto che gliene offri, anche se forse
involontariamente, la possibilita'.
Quindi:
criterio = VBA.InputBox(Prompt:="Digitare il nome dell'Artista" _
, Title:="Cerca Artista ")
If Len(Criterio) Then
' qui il codice per la ricerca.
Else
' qui quello che eventualmente vuoi venga fatto
' quando l'utente rinuncia.
End If
-oppure-
criterio = Application.InputBox(Prompt:="Digitare il nome dell'Artista"
_
, Title:="Cerca Artista ")
If Not ((criterio = False) Or (Len(criterio) = 0)) Then
' qui il codice per la ricerca.
Else
' qui quello che eventualmente vuoi venga fatto
' quando l'utente rinuncia.
End If
La cosa interessante di Application.InputBox e' che ti permette di
selezionare un intervallo di Excel col metodo del puntamento.
--
Ciao :o)
Maurizio Borrelli, Microsoft Office Access MVP
-------- http://mvp.support.microsoft.com/
?SPQR(C)
X RIO - Risorse in italiano per gli utenti di office
-------- http://www.riolab.org/
'-----------------
Forse ti interessera' sapere che "testare" vuol dire (anche) provare a
vedere cosa succede quando si premono *tutti* i pulsanti presenti nelle
finestre, di dialogo e no, del progetto. Quindi anche il pulsante
"Annulla" della finestra di dialogo prodotta dall'istruzione "InputBox".
Perche' l'utente del tuo progetto potrebbe voler rinunciare
all'immissione, visto che gliene offri, anche se forse
involontariamente, la possibilita'.
'-----------------
Forse Flavio ha proprio testato e provato "a vedere cosa
succede quando si premono *tutti* i pulsanti"!
Infatti, nel caso della domanda di Flavio e le soluzioni proposte,
ci sarebbe sempre un criterio valido: nel caso che l'utente non
inserisca un criterio esplicito, il criterio effettivo diventerebbe
"**" e tutti i record sarebbero visualizzati - che mi sembra una
risposta logica all'azione dell'utente.
---
Regards,
Norman
Ciao Norman.
Rispettabile opinione la tua ma io, come utente, quando premo "Annulla"
vorrei che non succedesse nulla.
> Rispettabile opinione la tua ma io, come utente, quando premo "Annulla"
> vorrei che non succedesse nulla.
In quel caso, forse si dovrebbe rispondere diversamente secondo
quale delle tre opzioni possibili sono selezionate:
1) un critrerio esplicito
2) Annulla
3) Un criterio vuoto
Forse, schematicamente, qualcosa del genere:
'=============>>
Public Sub CercaArtista2()
Dim Res As String
Dim criterio As String
Const Msg As String = "Digitare il nome dell'Artista "
Const Titolo As String = "Cerca Artista "
Do While Not CBool(Len(Res))
Res = InputBox(Prompt:=Msg, Title:=Titolo)
If StrPtr(Res) = 0 Then
MsgBox Prompt:="Hai cancellato - " & _
"I record non saranno cambiati!", _
Buttons:=vbCritical, _
Title:="USCITA"
Exit Do
ElseIf Res = vbNullString Then
MsgBox Prompt:="Non hai inserito un criterio" _
& vbNewLine & vbNewLine _
& "Per vedere tutti i record, " _
& "inserire un ""*""", _
Buttons:=vbCritical, _
Title:="ERRORE"
End If
Loop
If Res = vbNullString Then Exit Sub
With Range("A1")
.AutoFilter Field:=1, _
Criteria1:="*" & Res & "*"
Ciao Norman.
Dissento.
Come utente, quando premo il pulsante "Annulla" (o il tasto "Esc") ho
rinunciato. E basta. Tu progettista non sei autorizzato ad annoiarmi con
messaggi fastidiosi. Potevi progettare diversamente la tua interfaccia.
Per esempio usando uno UserForm.
Considera anche che una delle cose piu' imbarazzanti per l'utente
italiano e' la traduzione di To Cancel ( = annullare) con "Cancellare" (
= To Delete). "Annullare" vuol dire che l'utente ha *rinunciato* alla
operazione mentre un avviso tipo "Hai cancellato" mette in grave allarme
perche' l'utente in quel momento non si aspettava una *cancellazione*.
VBA.InputBox NON prevede la possibilita' di immissione di una stringa
nulla (equivale a premere "Annulla") a differenza di
Application.InputBox che lo prevede espressamente.
Public Sub test()
Dim criterio
criterio = Application.InputBox("Prompt", "Title")
If criterio = False Then
MsgBox "Hai premuto 'Annulla'."
ElseIf Len(criterio) Then
MsgBox "Hai immesso '" & criterio & "'."
Else
MsgBox "Hai immesso una stringa nulla."
End If
End Sub
> Come utente, quando premo il pulsante "Annulla" (o il tasto "Esc") ho
> rinunciato. E basta. Tu progettista non sei autorizzato ad annoiarmi con
> messaggi fastidiosi. Potevi progettare diversamente la tua interfaccia.
> Per esempio usando uno UserForm.
Ma hai rinunciato a che cosa? Ad l'inserimento di un *nuovo* criterio,
oppure ad un qualunque criterio?
Se ti sembra ovvio (oppure, se dovessi essere *ovvio* ad un utente
qualunque), cancella pure, l'istruzione:
MsgBox Prompt:="Hai cancellato - " & _
"I record non saranno cambiati!", _
Buttons:=vbCritical, _
Title:="USCITA"
> VBA.InputBox NON prevede la possibilita' di immissione di una stringa
> nulla (equivale a premere "Annulla")
Se:
> If StrPtr(Res) = 0 Then:
L'utente ha premuto "Annulla"
La tua esperienza e' diversa?
---
Regards,
Norman
Ciao Norman.
Non vorrei essere frainteso. "Tu progettista" sta per "tu ipotetico,
generico progettista" NON per "tu Norman".
> Non vorrei essere frainteso. "Tu progettista" sta per "tu ipotetico,
> generico progettista" NON per "tu Norman".
Ti ringrazio per il chiarimento, ma avevo capito il senso giusto.
Saluti.
---
Regards,
Norman
>> VBA.InputBox NON prevede la possibilita' di immissione di una stringa
>> nulla (equivale a premere "Annulla")
In questa riguarda, vedi anche il mio demo e le risposte di Harald Staff
(MVP) nel thread:
microsoft.public.excel.programming
http://tinyurl.com/y3pmhk
---
Regards,
Norman
Ciao Norman.
Si' ho visto. E concordo con Harald. Meglio uno UserForm. StrPtr e'
comunque una (simpatica) forzatura. Aggiungo che personalmente eviterei
l'uso di VBA.InputBox in quanto denota una progettazione sciatta,
povera, inutilmente frettolosa. Di Application.InputBox mi piace invece
la possibilita' del puntamento.
> Si' ho visto. E concordo con Harald. Meglio uno UserForm
Penso che tu non abbia capito la cronologia de quel thread!
Haold ha risposto a Otto, dicendo:
(1) Non e' possible isolare "l'annulla" con un (VBA) inputbox, e
(2) Pertanto, meglio sarebbe un Userform
Comunque, poi, avendo letto la mia risposta, Harald ha detto:
'-------------
Hi Norman
I stand corrected. This was good, thanks.
Best wishes Harald
'-----------------
Pertanto, ripeto il mio post da quel thread:
You can use the StrPtr function:
'------------------
Sub Tester()
Dim strInput As String
strInput = InputBox("Complete this quotation", _
"InputBox Demo", _
"Friends, Romans and Countrymen")
If StrPtr(strInput) = 0 Then
MsgBox "You pressed Cancel"
Else
If Len(strInput) = 0 Then
MsgBox "OK was pressed but no entry was made."
Else
MsgBox "Your entry was: " & strInput
End If
End If
End Sub
For information about StrPtr see Karl Peterson's site:
http://www.mvps.org/vb/index2.html?tips/varptr.htm
'------------------
Se non vuoi accettare (da me) tal uso della funzione StrPtr potrei
riferirti sia a Karl Peterson , sia a Chip Pearson ...
Per quanto riguarda l'uso di un tipo di inputbox, io utilizzo sia l'una
che l'altra.Come tutti gli strumenti di VBA/Excel, utilizzo quello che
mi sembra piu' addatto e quello che mi piace di piu' - in quel
momento; riscrivendo un tal codice, sarebbe anche possible che
cambiassi scelta di metodo/strumento.
---
Regards,
Norman
> Per quanto riguarda l'uso di un tipo di inputbox, io utilizzo sia l'una
> che l'altra.
Avrei voluto aggiungere, ci sono moltissimi esempi del mio uso di entrambi i
tipi di InputBox, sia in questo NG che in altri NG.
---
Regards,
Norman
Scusa Norman, ma nelle *tue* applicazioni, quelle vere, non
le cose che posti qui, tu le utilizzi le InputBox?
Io le evito come la puzza.
--
---------------------------
Mauro Gamberini
http://www.riolab.org/
'---------------
Scusa Norman, ma nelle *tue* applicazioni, quelle vere, non
le cose che posti qui, tu le utilizzi le InputBox?
'---------------
Dipende dalle circonstanze, ma si, certo si'.
'---------------
Io le evito come la puzza.
'---------------
Benissimo - ma, per piacere, vorresti spiegarmi cosa non
va con:
'---------------
Public Sub Tester()
Dim strInput As String
strInput = InputBox("Complete this quotation", _
"InputBox Demo", _
"Friends, Romans and Countrymen")
If StrPtr(strInput) = 0 Then
MsgBox "Hai premuto ANNULLA!"
Else
If Len(strInput) = 0 Then
MsgBox "Hai premuto 'OK' ma non hai inserito nulla!"
Else
MsgBox "Hai inserito " & strInput
End If
End If
End Sub
'---------------
In fine, in inglese si dice "Each to his own"
---
Regards,
Norman
Non c'è nulla che non va.
Solo che personalmente preferisco gestire una UserForm.
Come dicevo " Each to his own!"
Comunque, un ricerca rapida sui post di Tom Ogilvy, Chip Pearson,
Dave Peterson, Karl Peterson .... ha restituita moltissimi esempi
dell'uso di entrambi i tipi di InputBox.
Un esempio (fra moltissimi):
http://tinyurl.com/yl6ou6
Io evito l'uso di quello che non funziona oppure quella che e' difetoso -
per il resto me sembra (al meglio) opinione oppure (al peggio)
semplicemente un pregiudizio.
---
Regards,
Norman
'----------------
Scusa Norman, ma nelle *tue* applicazioni, quelle vere, non
le cose che posti qui, tu le utilizzi le InputBox?
Io le evito come la puzza.
'----------------
Per caso, ho fatto una ricerca di Google sui i tuoi post e il tu uso di
uno o l'altro tipo di Inputbox ,,,
Molto soprendentemente, dato il tuo commento di sopra, ho trovato
molti esempi moli esempi dell'uso degl'InputBox (tipo VBA) e, soltanto,
tre esempi dell tuo uso di Application.InputBox.
---
Regards,
Norman
'---------------
StrPtr e' comunque una (simpatica) forzatura. Aggiungo che
personalmente eviterei l'uso di VBA.InputBox in quanto denota una
progettazione sciatta, povera, inutilmente frettolosa.
Di Application.InputBox mi piace invece la possibilita' del puntamento.
'---------------
Visto che stavo utilizzando Google per rispondere a Mauro in
questo thread, , ho fatto anche una ricerca sul tuo uso di
VBA.Inputbox. Fra l'altro, ho trovato questo esempio
interessante:
Inputbox
http://tinyurl.com/uayey
'---------------
Public Sub InputBoxTest()
Dim strTitle As String
Dim strPrompt As String
Dim strDefault As String
Dim strRet As String
strTitle = "Titolo"
strPrompt = "Immetti un dato."
strDefault = "0"
strRet = InputBox(strPrompt, strTitle, strDefault)
If (Len(strRet) = 0) Then
MsgBox "L'utente ha scelto il pulsante Annulla."
Else
MsgBox "L'utente ha immesso: '" & strRet & "'."
End If
End Sub
'---------------
Aparte. l'uso della (VBA) InputBox, vedo anche che il codice
potrebbe non funzionare correttamente perche non hai utilizzato
la funzione StrPtr.
---
Regards,
Norman
Ciao Norman.
Non mi riferivo alla cronologia ma all'affermazione: "Which is nothing
but great fun to do". Valida sia prima che dopo, direi.
L'uso di StrPtr e' un "workaround" (in italiano "pezza", "toppa"). Il
fatto che si sia costretti a usarla in questo caso mi sembra argomento
sufficientemente a sfavore di VBA.InputBox.
Ciao Norman.
Io invece spero che non se ne trovino di miei. Pero', trattandosi di
codice di esempio, potrebbe succedere.
Ciao Norman.
Infatti. Non e' un uso *mio* ma la risposta a una domanda al riguardo.
Non capisco. Che errore potrebbe produrre quel codice?
Volendo essere precisissimi il messaggio avrebbe dovuto essere qualcosa
tipo "L'utente ha immesso stringa nulla o ha scelto il pulsante
Annulla."
--
Un conto è ciò che posto, un conto è se devo
fare una cosa *da vendere*.
Io parlavo prima di InputBox e UserForm, non
di quale delle due InputBox.
Molte volte diventa difficile spiegare una UserForm qui.
E poi mi appello alla legge(italiana) sulla privacy!
Non hai nessun diritto di fare simili ricerche!!! 8-)
> Infatti. Non e' un uso *mio* ma la risposta a una domanda al riguardo.
Visto la tua opinione:
>> personalmente eviterei l'uso di VBA.InputBox in quanto denota
>> una progettazione sciatta, povera, inutilmente frettolosa. Di
>> Application.InputBox mi piace invece la possibilita' del
>> puntamento.
e visto che l'OP non aveva postato del codice sua, non sarebbe
stato possible (consigliabile ?) suggerire l'uso del dialogo InputBox
di Excel?
> Non capisco. Che errore potrebbe produrre quel codice?
Il tuo codice potrebbe fornire il messaggio:
>>> "L'utente ha scelto il pulsante Annulla."
anche se l'utente non ha scelto il pulsante Annulla.
> Volendo essere precisissimi il messaggio avrebbe dovuto essere qualcosa
> tipo "L'utente ha immesso stringa nulla o ha scelto il pulsante Annulla."
Per essere preciso ed informativo, meglio sarebbe fornire
messaggio esatto, e.g.:
"L'utente ha inserito il valore "PIPPO" (Pulsante =OK
"L'utente ha scelto OK, ma non ha inserito niente" (Pulsante =OK)
oppure
"L'utente ha scelto il pulsante Annulla." (ANNULLA)
Se avessi utilizato la funzione StrPtr, sarebbe stato possible
essere informativo ed esatto.
---
Regards,
Norman
> L'uso di StrPtr e' un "workaround" (in italiano "pezza", "toppa").
Opinione tua. Non sono d'accordo.
StrPtr e le sue cugine VarPtr e ObjPtr sono delle funzione valide e
utilissime. Infatti, nel caso della funzione StrPtr, non c'e un altro modo
da notare la differenza fra una stringa vuota ("") ed una stringa nulla
(vbNullString): StrPtr(vbNullString) restituisce 0, mentre StrPtr("") e'
non-zero.
Forse e' arrivato il momento di lasciare morire in pace questo
discussione molto interessante ma non molto utile e ti ringrazio sia
delle tue opinioni e commenti, sia per il tuo codice.
Saluti.
---
Regards,
Norman
> Io parlavo prima di InputBox e UserForm, non
> di quale delle due InputBox.
Sono d'accordo con te che l'userform e' uno strumento utilissimo
e troppo spesso fruttato. Comunque, l'inputbox (sia di Excel, sia
di VBA) ed uno strumento che non dovrebbe essere scontato.
> Molte volte diventa difficile spiegare una UserForm qui.
Sono ancora d'accordo!
Saluti!
---
Regards,
Norman
Ciao Norman.
In Visual Basic, diversamente da altri linguaggi, NON c'e' differenza
fra stringa nulla e stringa vuota. Le funzioni (non documentate! non
supportate!) StrPtr & cugine esistono per l'uso con routine scritte in
altri linguaggi che invece fanno quella distinzione. Essere costretti a
usare StrPtr per rimediare a un evidente bug di VBA.InputBox e' un
workaround. E questo e' un fatto, non una opinione.
Non sono mai stato favorevole all'uso di funzioni non documentate o di
chiamate all'API, se non strettamente necessario, perche' si ottiene un
codice fragile, non resistente nel tempo. Una (ulteriore) dimostrazione
della ragionevolezza di questa (non solo) mia posizione sta qui:
http://msdn2.microsoft.com/en-gb/library/ex2dtcee(vs.71).aspx
The VarPtr, ObjPtr, StrPtr, VarPtrArray, and VarPtrStringArray functions
in Visual Basic 6.0 are undocumented and unsupported functions that
could be used to return a pointer to a memory address. Although
unsupported, these functions are sometimes used when working with
Windows API calls that would otherwise be inaccessible from Visual Basic
6.0.
These functions are not supported in Visual Basic 2005; however, most of
the scenarios where they were used can be addressed through new
functionality in the .NET Framework. Many of the Windows API calls that
were necessary in Visual Basic 6.0 are now encapsulated in the .NET
Framework; pointer references are no longer necessary.
--
---
Regards,
Norman
"Maurizio Borrelli" <maurizio...@freepass.it> wrote in message
news:%23RkGEh3...@TK2MSFTNGP06.phx.gbl...
Public Sub CercaArtista()
Dim Res As String
Dim criterio As String
Const Msg As String = "Digitare il nome dell'Artista "
Const Titolo As String = "Cerca Artista "
Do While Not CBool(Len(Res))
Res = InputBox(Prompt:=Msg, Title:=Titolo)
If StrPtr(Res) = 0 Then
Exit Do
ElseIf Res = vbNullString Then
MsgBox Prompt:="Non hai inserito l'Artista" _
& vbNewLine & vbNewLine _
& "inserisci l'Artista " _
& "e ritenta...", _
Buttons:=vbCritical, _
Title:="ERRORE"
End If
Loop
If Res = vbNullString Then Exit Sub
With Range("A1")
.AutoFilter Field:=1, _
Criteria1:="*" & Res & "*"
End With
ActiveWindow.ScrollRow = 3
End Sub
Ne approffito e vi chiedo un'altra cosa se possibile, nel caso in cui
l'artista sia un numero es. 883, non mi trova nulla! Ho risolto
inserendo l'apice prima del numero: '883, ma se volessi evitare di
inserire il dato senza dovre mette l'apicema?
Di nuovo grazie.
Ciao Flavio.
La cosa piu' saggia da fare, visto che vuoi gestire dati, e' impostare
il tipo di dato di ogni campo. Se un campo deve contenere testo assegna
alle celle il formato Testo. Fatto questo, immetti i dati. Non prima.
Per quelli gia' immessi... F2, Invio. Se sono pochi.
--
(Facci sapere se ed eventualmente come hai risolto. Grazie.)
Ricambio la tua citazione con quella di Matthew Curland, (MS Lead VB
Developer).
Matthew Curland e' molto stimato, non solo per il suo lavoro sul VB con
Microsoft, ma anche per i suoi articoli teoretichi e i suoi libri, ad
esempio:
"Advanced Visual Basic 6: Power Techniques for Everyday Programs"
'---------------------
Unofficial Documentation for VarPtr, StrPtr, and ObjPtr
http://vb.mvps.org/tips/varptr.asp
Historical Perspective
The VarPtr function has been in the BASIC language since long before it
turned into QuickBasic and Visual Basic. VarPtr has been in the VB runtime
since version 1.0. The function can be called through a Basic declare
statement pointing back into the VB runtime Dll.
Declare Function VarPtr Lib "vbrun100.Dll" (Var As Any) As Long
Over the years, vbrun100.Dll has turned into msvbvm50.dll, but the entry
point is still there. In order to get the address of a variable, simply pass
the variable name to VarPtr:
Dim l As Long
Debug.Print VarPtr(l)
Similarly, to get the pointer to a string instead of the variable holding
the string, pass the string variable ByVal instead.
Dim s As String
Debug.Print VarPtr(s), VarPtr(ByVal s)
Getting the pointer to a string buffer with this method was in common use
through VB3, but hit a brick wall with VB4.
ANSI/UNICODE Glitch
With the arrival of the 32-bit world and VB4, we entered a Windows world
which was suddenly half UNICODE and half ANSI instead of predominantly ANSI.
All VB strings are stored in UNICODE, but all API calls are made with ANSI
strings. This is accomplished by converting any string passed to an API call
to ANSI before the call and back to UNICODE afterwards. While this
conversion is transparent to the user most of the time, it makes it
impossible to pass a UNICODE string from VB to a DLL via an argument typed
As String in a Declare statement. Similarly, any structure which contains
strings will go through the double conversion process during an API call.
How does this affect the VarPtr function? When a string is passed
ByVal/ByRef to the VarPtr function shown in the Declare statement, the
address returned is the address of the temporary ANSI string/variable
holding the temporary ANSI string. In other words, it isn't the address of
the variable you've declared anymore, so the VarPtr function accessed
through a declare statement is totally useless for string variables or
variables for structures containing strings.
VB5 to the Rescue
To once again enable advanced programming with VarPtr, VB5 (and Office97)
added 3 entry points to the VBA type library which provide built-in
declarations for the VarPtr function. To maintain the traditionally eclectic
feel of VarPtr, and to stop beginning programmers from hurting themselves
(read: no one wanted to document them), these declarations remain hidden.
Since functions in a type library can be declared such that VarPtr returns
the address of any variable (except for variables containing arrays, see
October Visual Basic Programmer's Journal for more). VarPtr returns the
address of a variable. StrPtr returns the address of the real UNICODE string
buffer. ObjPtr returns the address of any object variable reference. Common
uses for each of these functions is described below.
StrPtr
StrPtr is used primarily to make efficient UNICODE API calls. In VB4, API
calls to a UNICODE function were made with the help of byte arrays:
Declare Sub MyUnicodeCall Lib "MyUnicodeDll.Dll" _
(pStr As Byte)
Sub MakeCall(MyStr As String)
Dim bTmp() As Byte
bTmp = MyStr & vbNullChar
MyUnicodeCall bTmp(0)
MyStr = bTmp
MyStr = Left$(MyStr, Len(MyStr - 1))
End Sub
Clearly, the amount of work to simply pass a NULL terminated UNICODE string
and return its value into the original string is totally unacceptable. By
the time correct handling of the terminating NULL character is included, No
less than 4 copies of the string are required.
With StrPtr, this code reduces to:
Declare Sub MyUnicodeCall Lib "MyUnicodeDll.Dll" _
(ByVal pStr As Long)
Sub MakeCall(MyStr As String)
MyUnicodeCall StrPtr(MyStr)
End Sub
VarPtr/StrPtr/ObjPtr are all very, very fast, so the overhead to call a
UNICODE function is now actually lower than calling the corresponding ANSI
function because no conversion is required.
StrPtr can also be used to optimize ANSI declare calls. Instead of passing
the same string variable multiple times to a declare function and incurring
the conversion overhead for each call, use the StrConv function once and
StrPtr in each call:
Declare Sub MyAnsiCall Lib "MyAnsiDll.Dll" _
(ByVal pStr As String)
MyAnsiCall MyStr
becomes:
Declare Sub MyAnsiCall Lib "MyAnsiDll.Dll" _
(ByVal pStr As Long)
MyStr = StrConv(MyStr, vbFromUnicode)
MyAnsiCall StrPtr(MyStr)
MyStr = StrConv(MyStr, vbUnicode) ' Not always required
StrPtr is also the only way to tell the different between an empty string
("") and a null string (vbNullString). StrPtr(vbNullString) returns 0, while
StrPtr("") is non-zero.
VarPtr
VarPtr can be used with API calls which require structures with UNICODE
strings in them. Passing MyUDTVariable to a ByRef UDTParam As MyUDT
parameter will always do ANSI/UNICODE conversion. However, passing
VarPtr(MyUDTVariable) to a ByVal UDTParam As Long parameter will leave all
data as is and pass the structure directly.
To see other programming techniques available with the VarPtr function,
refer to any C/C++ program. However, a word of caution is required here.
Pointer arithmetic in VB is non-trivial. Besides calculating the element
size, which isn't done for you in VB, you also have to deal with the lack of
an unsigned long data type. The following function will perform unsigned
arithmetic (positive increments only)
Function UnsignedAdd(ByVal Start As Long, _
ByVal Incr As Long) As Long
Const SignBit As Long = &H80000000
UnsignedAdd = (Start Xor SignBit) + Incr Xor SignBit
End Function
ObjPtr
ObjPtr returns the pointer to the interface referenced by an object
variable. Since most objects actually support multiple interfaces, it is
important to get the correct interface when looking at the address of an
object. With a VB declare design to take a generic object, there is no way
to guarantee that the interface received by the Dll will the same as the one
passed. For example, for a VB5 created Class1:
' Requires a stdole (OLE Automation) reference
Declare Function VBObjPtr Lib "msvbvm50.dll" _
Alias "VarPtr" (ByVal pObj As IUnknown) As Long
Dim Cls1 As New Class1
' These value will be different:
Debug.Print ObjPtr(Cls1), VBObjPtr(Cls1)
The most common use of ObjPtr I've found is for indexing objects placed in a
collection. By creating a key based on the address of the object, it is
possible to remove an object from a collection without walking the entire
collection and using the Is operator to find a match, then calling the
Remove method, which walks the collection again. In many cases, the address
of an object is the only thing you can reliably use as a key. For example,
the Name and Path properties of a Workbook object in Excel can change at any
time, so these can't be used as a key.
ObjColl.Add MyObj1, CStr(ObjPtr(MyObj1))
...
ObjColl.Remove CStr(ObjPtr(MyObj1))
-- Matthew Curland
'---------------------
---
Regards,
Norman
Ciao Norman.
Anche se gia' lo sapevo, mi fa molto piacere (ri)leggere che anche
Matthew Curland concorda con me. Grazie. Come vedi, sempre di API si
tratta. Che c'entra dunque col nostro discorso?
--
> Anche se gia' lo sapevo, mi fa molto piacere (ri)leggere che anche Matthew
> Curland concorda con me. Grazie. Come vedi, sempre di API si tratta. Che
> c'entra dunque col nostro discorso?
Non mi risulta che Matthew Curland concordi con te! Tu vuoi negare (o,
almeno non utilizzare le funzioni StrPtr, ObjPtr e VarPtr; Matthew spiega
quanto sono utili!
Matthew, ed altri che stimo (Tom Ogilvy MVP, Rob Bovey MVP, Jim Rech MVP,
Tushar Mehta MVP, Michel Pierron MVP,,, ) sono molto contento utilizzare
queste funzioni.
---
Regards,
Norman
Ciao Norman.
Anche Maurizio Borrelli MVP e' molto contento di usare quelle funzioni.
:))) Per questo dico che concordo con Matthew Curland. Ma nei casi da
lui descritti: API. Stiamo parlando di API noi? NO!
Come forse sarai stanco di leggere, l'uso con VBA.InputBox e' un uso
improprio. Una toppa. Una pezza. Un workaround. Un "monstrum". Uno
scherzo di natura. A te piace? Usalo. A me non piace. Tutto qui.
> Anche Maurizio Borrelli MVP e' molto contento di usare quelle funzioni
Mi stupisci!
E' questo lo stesso Maurizio Borrelli che non voleva mai utilizzare queste
funzioni in quanto non siano documentati:
'---------------
Non sono mai stato favorevole all'uso di funzioni non documentate
'---------------
E' questo lo stesso Maurizio Borrelli che qui diceva:
'--------------
:))) Per questo dico che concordo con Matthew Curland. Ma nei casi da
lui descritti: API. Stiamo parlando di API noi? NO!
'--------------
e che altrove diceva:
'----------------
http://tinyurl.com/yajk7v
Ho fatto 2 prove. Se dimensioni una variant questa viene immediatamente
inizializzata a qualcosa, infatti StrPtr è <>0. Se invece inizializzi una
variabile stringa, StrPtr vale 0.
E' questo lo stesso Maurizio Borrelli che diceva:
'----------------
Qui dimmi tu, "Stiamo parlando di API noi?" Oppure si tratta qui di:
'----------------
un uso improprio.Una toppa. Una pezza. Un workaround.
Un "monstrum". Uno scherzo di natura.
'----------------
??
E' questo lo stesso Maurizio Borrelli che (in questo thread) diceva:
'---------------
Come utente, quando premo il pulsante "Annulla" (o il tasto "Esc") ho
rinunciato. E basta. Tu progettista non sei autorizzato ad annoiarmi con
messaggi fastidiosi. Potevi progettare diversamente la tua interfaccia.
Per esempio usando uno UserForm.
'---------------
e poi, nello stesso post, ha suggerito il codice:
'---------------
If criterio = False Then
MsgBox "Hai premuto 'Annulla'."
ElseIf Len(criterio) Then
MsgBox "Hai immesso '" & criterio & "'."
Else
MsgBox "Hai immesso una stringa nulla."
End If
'---------------
---
Regards,
Norman