OVH Cloud OVH Cloud

Problème dans la fanction API GetDlgItemText

14 réponses
Avatar
mml
Bonjour,

Lorsque j'utilise la fonction GetDlgItemText, j'ai le message :

"Point d'entrée de GetDlgItem d'une DLL introuvable dans user32".

alors que la fonction SetDlgItem passe bien.

Je suis en Windows 2000 SP4.

Quelqu'un voit-il la solution ?

4 réponses

1 2
Avatar
Jean-marc
François Picalausa wrote:
Il vaudrait donc mieux utiliser la méthode avec StrPtr et StrConv (un
benchmark devrait être réalisé pour s'en assurer formellement), sauf



Un petit benchamrk donne des résultats qui vont
contre l'intuition.

Le plus rapide est :
res = SendMessage(Text1.hWnd, WM_GETTEXT, ByVal 255&, ByVal buf)

C'est plus rapide que la version avec Byval StrPtr, mais aussi plus
rapide (curieusement) que la version W.

Les différences de perfs sont peu importantes (différence de 15%).

Le tout est comme le disait François purement un exercice accadémique:
on manipule de l'UI, ce qui rend inutile ce genre de recherche de
perfs, surtout pour des différences de 10-15%.

Pour conclure, il semble que le meilleur compromis en terme
de performance, portabilité, robustesse et justess du code soit
ceci :

Option Explicit

Private Declare Function SendMessage Lib "USER32" Alias "SendMessageA" ( _
ByVal hwnd As Long, ByVal Msg As Long, _
wParam As Any, lParam As Any) As Long

Const WM_GETTEXT As Long = &HD
Const WM_GETTEXTLENGTH As Long = &HE

Private Function GetTextbyhandle(ByVal hwnd As Long) As String
Dim res As Long
Dim buf As String
Dim strSize As Long

buf = Space(SendMessage(hwnd, WM_GETTEXTLENGTH, ByVal 0&, ByVal 0&))
strSize = LenB(buf)
If strSize Then
res = SendMessage(hwnd, WM_GETTEXT, ByVal strSize, ByVal buf)
buf = Left(buf, res)
End If
GetTextbyhandle = buf
End Function


Private Sub Command1_Click()
Dim buf As String

buf = GetTextbyhandle(Text1.hwnd)
MsgBox "buf=" & buf
End Sub


Et pour info, l'exécution de cette fonction prend plus ou moins
1 microseconde : On peut faire 1 million d'appels en 1 seconde ...

Bonne nuit !

--
Jean-marc Noury (jean_marc_n2)
Microsoft MVP - Visual Basic
FAQ VB: http://faq.vb.free.fr/
mailto: remove '_no_spam_' ;
Avatar
parci
On Fri, 18 Jan 2008 00:13:09 +0100, "Jean-marc"
wrote:

François et Jean-Marc,

merci pour ces précisions très intéressantes.
Avatar
mml
Eh ben voilà !

Pas plus compliqué que ça.

Encore fallait-il le savoir...Mais tu me sauves la mise !

Merci très beaucoup.


"Jean-marc" a écrit dans le message
de news:478e77cb$0$29253$
mml wrote:
> D'autre part, pourrai-je avoir un bout de code illustrant la méthode
> utilisant SendMessage avec WM_GETTEXT, stp ?

Hello,

voici un petit bout de code.
Il te faut une form, un textbox et un bouton de commande.

tu tapes qq chose dans la textbox puis tu cliques sur
le bouton.

Option Explicit

Private Declare Function SendMessage Lib "USER32" Alias "SendMessageA" ( _
ByVal hWnd As Long, ByVal Msg As Long, _
wParam As Any, lParam As Any) As Long

Const WM_GETTEXT As Long = &HD

Private Sub Form_Load()

Text1.PasswordChar = "*"
End Sub

Private Sub Command1_Click()

Dim res As Long
Dim buf As String

buf = Space(255)
res = SendMessage(Text1.hWnd, WM_GETTEXT, ByVal 255&, ByVal


StrPtr(buf))
buf = StrConv(buf, vbUnicode)
MsgBox "buf = " & buf

End Sub

C'est comme ça que marchent les "révélateurs" de mots de passe ...

Cordialement;

--
Jean-marc Noury (jean_marc_n2)
Microsoft MVP - Visual Basic
FAQ VB: http://faq.vb.free.fr/
mailto: remove '_no_spam_' ;






Avatar
François Picalausa
On Jan 18, 12:13 am, "Jean-marc"
wrote:
François Picalausa wrote:
> Il vaudrait donc mieux utiliser la méthode avec StrPtr et StrConv (un
> benchmark devrait être réalisé pour s'en assurer formellement), sa uf

Un petit benchamrk donne des résultats qui vont
contre l'intuition.



<snip>

Pour conclure, il semble que le meilleur compromis en terme
de performance, portabilité, robustesse et justess du code soit
ceci :

<snip>



Hello,

Si c'est le cas pour WM_GETTEXT, je confirme que pour l'énumération de
fichiers, les conclusions restent valables.
C'est ce qu'illustre les résultats ci dessous:
20080118155341: Loop Overhead: 0 ms
20080118155341: ANSI Calls:16737 ms
20080118155341: Unicode Calls: 9268 ms
20080118155341: Unicode2 Calls: 9268 ms
Soit un ratio A:W de 1.8

Le code qui me donne ces résultats est repris en fin de post; c'est
basé sur la (plus que célèbre ?) CStopWatch. Les résultats sont
semblables en IDE ou compilé.

Le pourquoi réside peut-être (quoi que c'est une explication un peu
tordue) dans l'appel à CreateWindowA/CreateWindowW qui créerait une
fenêtre edit (lire TextBox), dont le texte serait représenté en ANSI
en interne. D'où l'appel en UNICODE générerait la nécessité d'une
conversion qui serait moins rapide que celles réalisées par Visual
Basic.

Pour le WM_GETTEXT, je propose dans la partie
buf = Space(SendMessage(hwnd, WM_GETTEXTLENGTH, ByVal 0&, ByVal 0&))
strSize = LenB(buf)
If strSize Then
res = SendMessage(hwnd, WM_GETTEXT, ByVal strSize, ByVal buf)
buf = Left(buf, res)
End If


de passer ByValstrSize/2:
lenB est OK pour les tests (parce que 0/2 = 0) et plus performant
que Len (par évitement du /2), mais il faut éviter d'en utiliser la
valeur faute que quoi on a une possibilité de buffer overrun
d'utiliser respectivement Space$ et Left$ en place de Space et de Left
(le $ augmente les performances pour pas cher)

François

Le code:

Option Explicit

' Déclaration des constantes
Private Const MAX_PATH As Long = 260
Private Const TWOMAX_PATH As Long = 520
Private Const INVALID_HANDLE_VALUE As Long = -1
Private Const ERROR_NO_MORE_FILES As Long = 18

' Déclaration des API
Private Declare Function FindFirstFile Lib "kernel32" Alias
"FindFirstFileA" _
(ByVal lpFileName As String, lpFindFileData As
WIN32_FIND_DATA) As Long
Private Declare Function FindNextFile Lib "kernel32" Alias
"FindNextFileA" _
(ByVal hFindFile As Long, lpFindFileData As WIN32_FIND_DATA)
As Long

Private Declare Function FindFirstFileW Lib "kernel32" _
(ByVal lpFileName As Long, lpFindFileData As WIN32_FIND_DATAW)
As Long
Private Declare Function FindNextFileW Lib "kernel32" _
(ByVal hFindFile As Long, lpFindFileData As WIN32_FIND_DATAW)
As Long

Private Declare Function FindFirstFileW2 Lib "kernel32" Alias
"FindFirstFileW" _
(ByVal lpFileName As Long, ByVal lpFindFileData As Long) As
Long
Private Declare Function FindNextFileW2 Lib "kernel32" Alias
"FindNextFileW" _
(ByVal hFindFile As Long, ByVal lpFindFileData As Long) As
Long

Private Declare Function FindClose Lib "kernel32" (ByVal hFindFile As
Long) As Long

' Déclaration des Types
Private Type FILETIME
dwLowDateTime As Long
dwHighDateTime As Long
End Type

Private Type WIN32_FIND_DATA
dwFileAttributes As Long
ftCreationTime As FILETIME
ftLastAccessTime As FILETIME
ftLastWriteTime As FILETIME
nFileSizeHigh As Long
nFileSizeLow As Long
dwReserved0 As Long
dwReserved1 As Long
cFileName As String * MAX_PATH
cAlternate As String * 14
End Type

Private Type WIN32_FIND_DATAW
dwFileAttributes As Long
ftCreationTime As FILETIME
ftLastAccessTime As FILETIME
ftLastWriteTime As FILETIME
nFileSizeHigh As Long
nFileSizeLow As Long
dwReserved0 As Long
dwReserved1 As Long
cFileName(TWOMAX_PATH - 1) As Byte
cAlternate(27) As Byte
End Type

Private Type WIN32_FIND_DATAW2
dwFileAttributes As Long
ftCreationTime As FILETIME
ftLastAccessTime As FILETIME
ftLastWriteTime As FILETIME
nFileSizeHigh As Long
nFileSizeLow As Long
dwReserved0 As Long
dwReserved1 As Long
cFileName As String * MAX_PATH
cAlternate As String * 14
End Type

'based on http://faq.vb.free.fr/index.php?question9
Private Function ListDirectory(Path As String) As Boolean
Dim lpFindFileData As WIN32_FIND_DATA
Dim hFindFile As Long
Dim fileName As String
ListDirectory = False

hFindFile = FindFirstFile(Path, lpFindFileData)
If hFindFile <> INVALID_HANDLE_VALUE Then
Do
fileName = Mid$(lpFindFileData.cFileName, 1,
InStr(lpFindFileData.cFileName, vbNullChar) - 1)
Loop Until FindNextFile(hFindFile, lpFindFileData) = 0
ListDirectory = Err.LastDllError = ERROR_NO_MORE_FILES
End If
FindClose hFindFile
End Function

Private Function ListDirectoryW(Path As String) As Boolean
Dim lpFindFileData As WIN32_FIND_DATAW
Dim hFindFile As Long
Dim fileName As String
ListDirectoryW = False

hFindFile = FindFirstFileW(StrPtr(Path & vbNullChar),
lpFindFileData)
If hFindFile <> INVALID_HANDLE_VALUE Then
Do
fileName = lpFindFileData.cFileName
fileName = Mid$(fileName, 1, InStr(fileName, vbNullChar) -
1)
Loop Until FindNextFileW(hFindFile, lpFindFileData) = 0
ListDirectoryW = Err.LastDllError = ERROR_NO_MORE_FILES
End If
FindClose hFindFile
End Function

Private Function ListDirectoryW2(Path As String) As Boolean
Dim lpFindFileData As WIN32_FIND_DATAW2
Dim hFindFile As Long
Dim fileName As String
ListDirectoryW2 = False

hFindFile = FindFirstFileW2(StrPtr(Path & vbNullChar),
VarPtr(lpFindFileData))
If hFindFile <> INVALID_HANDLE_VALUE Then
Do
fileName = Mid$(lpFindFileData.cFileName, 1,
InStr(lpFindFileData.cFileName, vbNullChar) - 1)
Loop Until FindNextFileW2(hFindFile, VarPtr(lpFindFileData)) =
0
ListDirectoryW2 = Err.LastDllError = ERROR_NO_MORE_FILES
End If
FindClose hFindFile
End Function

Private Function ClearLog()
Text1.Text = vbNullString
End Function

Private Function AppendToLog(Text As String)
Text1.Text = Text1.Text & Format(Now, "yyyymmddhhnnss: ") & Text &
vbCrLf
End Function

Private Sub Command1_Click()
Dim tmr As CStopWatch
Dim tL As Long
Dim t1 As Long, t2 As Long, t3 As Long
Dim i As Long
Dim BufferA As String
Dim BufferW() As Byte
Const Loops As Long = 500
Const MAX_PATH As Long = 260

' Create instance of stopwatch class
Set tmr = New CStopWatch

' Determine overhead of looping
tmr.Reset
For i = 1 To Loops
Next i
tL = tmr.Elapsed

BufferA = Space$(MAX_PATH)
tmr.Reset
For i = 1 To Loops
Call ListDirectory("c:windowssystem32*.*")
Next i
t1 = tmr.Elapsed

tmr.Reset
For i = 1 To Loops
Call ListDirectoryW("c:windowssystem32*.*")
Next i
t2 = tmr.Elapsed

tmr.Reset
For i = 1 To Loops
Call ListDirectoryW2("c:windowssystem32*.*")
Next i
t3 = tmr.Elapsed

' Output results, subtracting loop overhead
ClearLog
AppendToLog "Loop Overhead: " & tL & " ms"
AppendToLog "ANSI Calls:" & t1 - tL & " ms"
AppendToLog "Unicode Calls: " & t2 - tL & " ms"
AppendToLog "Unicode2 Calls: " & t2 - tL & " ms"
End Sub
1 2