quarta-feira, 25 de junho de 2008

Bem,

vamos ver como enviar e pegar mensagens enviadas para uma determinada janela.

Mas o que seria uma mensagem, por exemplo quando movimentamos o mouse em uma janela é enviado o sistema operacional envia uma mensagem para a janela dizendo que o mouse movimentou e também nos diz para onde ele foi ou seja X e Y.

Vale lembrar que tudo no Windows é uma janela desde um botão, listview, textbox, checkbox...

Ou seja, um evento de um botão nada mais é um envio de mensagem. Dizendo que o usuário está fazendo algum ação no botão. Abaixo um exemplo de como criar uma janela (botão).

Option Explicit
Private Declare Function CreateWindowEx Lib "user32" Alias "CreateWindowExA" (ByVal dwExStyle As Long, ByVal lpClassName As String, ByVal lpWindowName As String, ByVal dwStyle As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hWndParent As Long, ByVal hMenu As Long, ByVal hInstance As Long, lpParam As Any) As Long

Private Const WS_CHILD = &H40000000
Private Const WS_VISIBLE = &H10000000

Private hwndText As Long

Private Sub Form_Activate()
hwndText = CreateWindowEx(0, "Button", "My button", WS_CHILD Or WS_VISIBLE, 10, 10, 100, 25, Me.hWnd, 0, App.hInstance, ByVal 0&)
End Sub

Ficava imaginando como seria para adicionar um evento para um botão.
Bem existe uma função chamada
SetWindowsHookEx que monitora os eventos de um objeto. Todo os objetos contém uma lista de eventos, o que essa função faz é quando chegar um evento a sua janela vai ser chamada um função de você definir, ou seja, você vai poder analisar todos os eventos(mensagens) que chegar na sua janela.
A função que será chamada deve ter a seguinte assinatura:

Public Function GetMsgProc(ByVal idHook As Long, wParam As Long, lParam As Msg) As Long

O nome da função não tem a necessidade de ser exatamente esse poderia ser qualquer outro, mas os parâmetros devem ser iguais.
Observe que é passado uma estrutura de dados com o tipo MSG a baixo a declaração dessa estrutura:

Private Type Msg
hwnd As Long
message As Long
wParam As Long
lParam As Long
time As Long
pt As POINTAPI
End Type

Quando quando é chamada a sua função dizendo que tem uma mensagem todos esses campos vão ser preenchidos de acordo com cada mensagem.

hwnd
Handle da Janela
message
Valor da mensagem
wParam
Especifica informações adicionais sobre a mensagem, nem todas as mensagem utiliza esse parâmetro
lParam
Especifica informações adicionais sobre a mensagem, nem todas as mensagem utiliza esse parâmetro
time
Especifica o tempo que a mensagem foi postada(enviada)
pt
Especifica a posição do curso na tela quando a mensagem foi enviada

O parâmetro pt também tem uma estrutura que é definida da seguinte maneira. Nessa estrutura são passados as coordenas X e Y do posicionamento do mouse.

Private Type POINTAPI
x As Long
y As Long
End Type

O exemplo abaixo mostra como é possível adicionar um evento em uma janela. O evento utilizado foi o click do mouse.

No form1 coloque o código.

Option Explicit

Private Sub Form_Load()
'set um hook de menssagem
hwndcmd = CreateWindowEx(0, "Button", "Meu btn", WS_CHILD Or WS_VISIBLE, 10, 10, 100, 25, Me.hwnd, 0, App.hInstance, ByVal 0&)

hHook = SetWindowsHookEx(WH_GETMESSAGE, AddressOf GetMsgProc, App.hInstance, App.ThreadID)
End Sub
Private Sub Form_Unload(Cancel As Integer)
'remove o windows-hook
UnhookWindowsHookEx hHook
End Sub


E em um módulo adicione o código.


'Em um módulo

Public Const WH_GETMESSAGE = 3
Public Const WS_CHILD = &H40000000
Public Const WS_VISIBLE = &H10000000

Private Type POINTAPI
x As Long
y As Long
End Type

Private Type Msg
hwnd As Long 'Handle to the window whose window procedure receives the message.
'hwnd is NULL when the message is a thread message.

message As Long 'Specifies the message identifier. Applications can only use the low word;
'the high word is reserved by the system.

wParam As Long 'Specifies additional information about the message.
'The exact meaning depends on the value of the message member.

lParam As Long 'Specifies additional information about the message.
'The exact meaning depends on the value of the message member.

time As Long 'Specifies the time at which the message was posted.

pt As POINTAPI 'Specifies the cursor position, in screen coordinates, when the message was posted.
End Type


Public Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, ByVal ncode As Long, ByVal wParam As Long, lParam As Any) As Long
Public Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long
Public Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long
Public Declare Function CreateWindowEx Lib "user32" Alias "CreateWindowExA" (ByVal dwExStyle As Long, ByVal lpClassName As String, ByVal lpWindowName As String, ByVal dwStyle As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hWndParent As Long, ByVal hMenu As Long, ByVal hInstance As Long, lpParam As Any) As Long

Public hHook As Long
Public hwndcmd As Long

Public Function GetMsgProc(ByVal idHook As Long, wParam As Long, lParam As Msg) As Long
If idHook < 0 Then
'chama o proximo hook
GetMsgProc = CallNextHookEx(hHook, idHook, wParam, ByVal lParam)

Else
If lParam.hwnd = hwndcmd Then
If lParam.message = CInt(&H202) Then 'Public Const WM_LBUTTONUP = &H202
mouseClick

End If
End If
End If
End Function

Private Sub mouseClick()
MsgBox "Mouse click()"
End Sub


Bem a função SetWindowsHookEx ela fica escutando toda vez que uma menssagem vai ser executada a função que é passada por AddressOf GetMsgProc essa função deve ter obrigatoriamente essa assinatura ou seja:

Public Function GetMsgProc(ByVal idHook As Long, wParam As Long, lParam As Msg) As Long

Nesse exemplo foi visto como criar uma janela, e adicionar um "evento" a ela.

Abaixo um listagem das mensagens mais utilizada.

Option Explicit
'Lista de menssagens a janelas

Public Const WM_NULL = &H0
Public Const WM_CREATE = &H1
Public Const WM_DESTROY = &H2
Public Const WM_MOVE = &H3
Public Const WM_SIZE = &H5
Public Const WM_ACTIVATE = &H6
Public Const WM_SETFOCUS = &H7
Public Const WM_KILLFOCUS = &H8
Public Const WM_ENABLE = &HA
Public Const WM_SETREDRAW = &HB
Public Const WM_SETTEXT = &HC
Public Const WM_GETTEXT = &HD
Public Const WM_GETTEXTLENGTH = &HE
Public Const WM_PAINT = &HF
Public Const WM_CLOSE = &H10
Public Const WM_QUERYENDSESSION = &H11
Public Const WM_QUIT = &H12
Public Const WM_QUERYOPEN = &H13
Public Const WM_ERASEBKGND = &H14
Public Const WM_SYSCOLORCHANGE = &H15
Public Const WM_ENDSESSION = &H16
Public Const WM_SYSTEMERROR = &H17
Public Const WM_SHOWWINDOW = &H18
Public Const WM_CTLCOLOR = &H19
Public Const WM_WININICHANGE = &H1A
Public Const WM_SETTINGCHANGE = &H1A
Public Const WM_DEVMODECHANGE = &H1B
Public Const WM_ACTIVATEAPP = &H1C
Public Const WM_FONTCHANGE = &H1D
Public Const WM_TIMECHANGE = &H1E
Public Const WM_CANCELMODE = &H1F
Public Const WM_SETCURSOR = &H20
Public Const WM_MOUSEACTIVATE = &H21
Public Const WM_CHILDACTIVATE = &H22
Public Const WM_QUEUESYNC = &H23
Public Const WM_GETMINMAXINFO = &H24
Public Const WM_PAINTICON = &H26
Public Const WM_ICONERASEBKGND = &H27
Public Const WM_NEXTDLGCTL = &H28
Public Const WM_SPOOLERSTATUS = &H2A
Public Const WM_DRAWITEM = &H2B
Public Const WM_MEASUREITEM = &H2C
Public Const WM_DELETEITEM = &H2D
Public Const WM_VKEYTOITEM = &H2E
Public Const WM_CHARTOITEM = &H2F
Public Const WM_SETFONT = &H30
Public Const WM_GETFONT = &H31
Public Const WM_SETHOTKEY = &H32
Public Const WM_GETHOTKEY = &H33
Public Const WM_QUERYDRAGICON = &H37
Public Const WM_COMPAREITEM = &H39
Public Const WM_COMPACTING = &H41
Public Const WM_COMMNOTIFY = &H44 '(obsolete in Win32)
Public Const WM_WINDOWPOSCHANGING = &H46
Public Const WM_WINDOWPOSCHANGED = &H47
Public Const WM_POWER = &H48
Public Const WM_COPYDATA = &H4A
Public Const WM_CANCELJOURNAL = &H4B
Public Const WM_NOTIFY = &H4E
Public Const WM_INPUTLANGCHANGEREQUEST = &H50
Public Const WM_INPUTLANGCHANGE = &H51
Public Const WM_TCARD = &H52
Public Const WM_HELP = &H53
Public Const WM_USERCHANGED = &H54
Public Const WM_NOTIFYFORMAT = &H55
Public Const WM_CONTEXTMENU = &H7B
Public Const WM_STYLECHANGING = &H7C
Public Const WM_STYLECHANGED = &H7D
Public Const WM_DISPLAYCHANGE = &H7E
Public Const WM_GETICON = &H7F
Public Const WM_SETICON = &H80
Public Const WM_NCCREATE = &H81
Public Const WM_NCDESTROY = &H82
Public Const WM_NCCALCSIZE = &H83
Public Const WM_NCHITTEST = &H84
Public Const WM_NCPAINT = &H85
Public Const WM_NCACTIVATE = &H86
Public Const WM_GETDLGCODE = &H87
Public Const WM_NCMOUSEMOVE = &HA0
Public Const WM_NCLBUTTONDOWN = &HA1
Public Const WM_NCLBUTTONUP = &HA2
Public Const WM_NCLBUTTONDBLCLK = &HA3
Public Const WM_NCRBUTTONDOWN = &HA4
Public Const WM_NCRBUTTONUP = &HA5
Public Const WM_NCRBUTTONDBLCLK = &HA6
Public Const WM_NCMBUTTONDOWN = &HA7
Public Const WM_NCMBUTTONUP = &HA8
Public Const WM_NCMBUTTONDBLCLK = &HA9
Public Const WM_KEYFIRST = &H100
Public Const WM_KEYDOWN = &H100
Public Const WM_KEYUP = &H101
Public Const WM_CHAR = &H102
Public Const WM_DEADCHAR = &H103
Public Const WM_SYSKEYDOWN = &H104
Public Const WM_SYSKEYUP = &H105
Public Const WM_SYSCHAR = &H106
Public Const WM_SYSDEADCHAR = &H107
Public Const WM_KEYLAST = &H108
Public Const WM_IME_STARTCOMPOSITION = &H10D
Public Const WM_IME_ENDCOMPOSITION = &H10E
Public Const WM_IME_COMPOSITION = &H10F
Public Const WM_IME_KEYLAST = &H10F
Public Const WM_INITDIALOG = &H110
Public Const WM_COMMAND = &H111
Public Const WM_SYSCOMMAND = &H112
Public Const WM_TIMER = &H113
Public Const WM_HSCROLL = &H114
Public Const WM_VSCROLL = &H115
Public Const WM_INITMENU = &H116
Public Const WM_INITMENUPOPUP = &H117
Public Const WM_MENUSELECT = &H11F
Public Const WM_MENUCHAR = &H120
Public Const WM_ENTERIDLE = &H121
Public Const WM_CTLCOLORMSGBOX = &H132
Public Const WM_CTLCOLOREDIT = &H133
Public Const WM_CTLCOLORLISTBOX = &H134
Public Const WM_CTLCOLORBTN = &H135
Public Const WM_CTLCOLORDLG = &H136
Public Const WM_CTLCOLORSCROLLBAR = &H137
Public Const WM_CTLCOLORSTATIC = &H138
Public Const WM_MOUSEFIRST = &H200
Public Const WM_MOUSEMOVE = &H200
Public Const WM_LBUTTONDOWN = &H201
Public Const WM_LBUTTONUP = &H202
Public Const WM_LBUTTONDBLCLK = &H203
Public Const WM_RBUTTONDOWN = &H204
Public Const WM_RBUTTONUP = &H205
Public Const WM_RBUTTONDBLCLK = &H206
Public Const WM_MBUTTONDOWN = &H207
Public Const WM_MBUTTONUP = &H208
Public Const WM_MBUTTONDBLCLK = &H209
Public Const WM_MOUSELAST = &H20A
Public Const WM_MOUSEWHEEL = &H20A
Public Const WM_PARENTNOTIFY = &H210
Public Const WM_ENTERMENULOOP = &H211
Public Const WM_EXITMENULOOP = &H212
Public Const WM_NEXTMENU = &H213
Public Const WM_SIZING = &H214
Public Const WM_CAPTURECHANGED = &H215
Public Const WM_MOVING = &H216
Public Const WM_POWERBROADCAST = &H218
Public Const WM_DEVICECHANGE = &H219
Public Const WM_MDICREATE = &H220
Public Const WM_MDIDESTROY = &H221
Public Const WM_MDIACTIVATE = &H222
Public Const WM_MDIRESTORE = &H223
Public Const WM_MDINEXT = &H224
Public Const WM_MDIMAXIMIZE = &H225
Public Const WM_MDITILE = &H226
Public Const WM_MDICASCADE = &H227
Public Const WM_MDIICONARRANGE = &H228
Public Const WM_MDIGETACTIVE = &H229
Public Const WM_MDISETMENU = &H230
Public Const WM_ENTERSIZEMOVE = &H231
Public Const WM_EXITSIZEMOVE = &H232
Public Const WM_DROPFILES = &H233
Public Const WM_MDIREFRESHMENU = &H234
Public Const WM_IME_SETCONTEXT = &H281
Public Const WM_IME_NOTIFY = &H282
Public Const WM_IME_CONTROL = &H283
Public Const WM_IME_COMPOSITIONFULL = &H284
Public Const WM_IME_SELECT = &H285
Public Const WM_IME_CHAR = &H286
Public Const WM_IME_KEYDOWN = &H290
Public Const WM_IME_KEYUP = &H291
Public Const WM_MOUSEHOVER = &H2A1
Public Const WM_MOUSELEAVE = &H2A3
Public Const WM_CUT = &H300
Public Const WM_COPY = &H301
Public Const WM_PASTE = &H302
Public Const WM_CLEAR = &H303
Public Const WM_UNDO = &H304
Public Const WM_RENDERFORMAT = &H305
Public Const WM_RENDERALLFORMATS = &H306
Public Const WM_DESTROYCLIPBOARD = &H307
Public Const WM_DRAWCLIPBOARD = &H308
Public Const WM_PAINTCLIPBOARD = &H309
Public Const WM_VSCROLLCLIPBOARD = &H30A
Public Const WM_SIZECLIPBOARD = &H30B
Public Const WM_ASKCBFORMATNAME = &H30C
Public Const WM_CHANGECBCHAIN = &H30D
Public Const WM_HSCROLLCLIPBOARD = &H30E
Public Const WM_QUERYNEWPALETTE = &H30F
Public Const WM_PALETTEISCHANGING = &H310
Public Const WM_PALETTECHANGED = &H311
Public Const WM_HOTKEY = &H312
Public Const WM_PRINT = &H317
Public Const WM_PRINTCLIENT = &H318
Public Const WM_HANDHELDFIRST = &H358
Public Const WM_HANDHELDLAST = &H35F
Public Const WM_PENWINFIRST = &H380
Public Const WM_PENWINLAST = &H38F
Public Const WM_COALESCE_FIRST = &H390
Public Const WM_COALESCE_LAST = &H39F
Public Const WM_DDE_FIRST = &H3E0
Public Const WM_DDE_INITIATE = &H3E0
Public Const WM_DDE_TERMINATE = &H3E1
Public Const WM_DDE_ADVISE = &H3E2
Public Const WM_DDE_UNADVISE = &H3E3
Public Const WM_DDE_ACK = &H3E4
Public Const WM_DDE_DATA = &H3E5
Public Const WM_DDE_REQUEST = &H3E6
Public Const WM_DDE_POKE = &H3E7
Public Const WM_DDE_EXECUTE = &H3E8
Public Const WM_DDE_LAST = &H3E8
Public Const WM_USER = &H400
Public Const WM_APP = &H8000

Para saber qual foi a mensagem enviada a nossa janela usamos o seguinte techo de código:

If lParam.hwnd = hwndcmd Then
If lParam.message = CInt(&H202) Then 'Public Const WM_LBUTTONUP = &H202
mouseClick

End If
End If

O primeiro if é para saber se o evento ocorreu realmente no botão.
O segundo if é o parâmetro da mensagem.
Se tudo for igual, vai ser chamada a função mouseClick.
Bem vimos como pegar e identificar mensagens como seria para enviar uma mensagem para uma janela.
Utilizando a função SendMessage.
A função envia uma menssagem específica para janelas. SendMessage não é informada se a mensagem foi executada com sucesso, ela apenas manda a mensagem para fila de mensagem de um janela.
Para retornar uma mensagem dizendo o paradeiro da mensagem então temos
SendMessageCallback ou SendNotifyMessage.
Sintaxe.

LRESULT SendMessage(
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam
);

Parâmetros

hWnd [in]

Identifica a janela na qual irá receber a menssagem. Se este parâmetro for HWND_BROADCAST, a menssagem é enviada a todas as janelas top-level no sistema, incluindo desativas, invisiveis, janelas unowned(sem dono), overlapped windows, e janelas pop-up; mas a menssagem não é enviada a janelas filhas.

Microsoft Windows Vista e posteriores. O envio de menssagens é está sujeito a User Interface Privilege Isolation(UIPI). O thread do processo pode enviar menssagens somente para filas de menssagens do threads no processo de baixa integridade.

Msg
[in] Especifica a mensagem a ser enviada.
wParam
[in] Especifica informações de message-specific.
lParam
[in] Especifica informações de message-specific.

Valor de retorno

O valor de retorno depende do tipo de menssagem


Nesse exemplo apenas clico no botão e a janela em questão é fechada usando SendMessage.
Então crie um formulário e adicione um botão, depois cole o código.

Private Declare Function SendMessageStr Lib "USER32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As String) As Long

Private Const WM_CLOSE = &H10
Private Sub Command1_Click()
SendMessageStr Me.hWnd, WM_CLOSE, CInt(True), 0
End Sub

Um outro exemplo de SendMenssage.
Nesse exemplo ele limpa o conteúdo da listview de processos.
Crie um módulo e adicione o código abaixo, depois coloque para inicializar da sub main.
Depois de executado o programa precione ctrl+alt+del e acesse a aba processo.
Esse programa fica analizando todas as janelas que estão em foco usando a função
GetForegroundWindow que retorna o handle da janela em foco, se a janela tiver o titulo Gerenciador de tarefas do Windows ele vai analizar todas as janelas filhas, até encontrar uma janela com o nome Processos que é a listview de processos, quando encontrar vai enviar uma menssagem para a janela dizendo para limpar todo o conteudo da listview.

Option Explicit

'Funções da API
Private Declare Function EnumChildWindows Lib "user32" (ByVal hWndParent As Long, ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long
Private Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hWnd As Long) As Long
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hWnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function SetTimer Lib "user32" (ByVal hWnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
Private Declare Function GetForegroundWindow Lib "user32" () As Long
Private Declare Function GetNextWindow Lib "user32" Alias "GetWindow" (ByVal hWnd As Long, ByVal wFlag As Long) As Long
Private Declare Function EnableWindow Lib "user32" (ByVal hWnd As Long, ByVal fEnable As Long) As Long

'Variáveis
Dim buffer As String
Dim janelaPrincipal As Long

Public Function EnumChildProc(ByVal hWnd As Long, ByVal lParam As Long) As Long
Dim sTitle As String

If GetWindowTextLength(hWnd) > 0 Then
sTitle = Space$(256)
Call GetWindowText(hWnd, sTitle, 256)

If InStr(sTitle, Chr$(0)) Then
sTitle = Left$(sTitle, InStr(sTitle, Chr$(0)) - 1)
End If
End If

'Nome da janela processo
If sTitle = "Processos" Then
SendMessage hWnd, (&H1000 + 9), 0, 0&
EnumChildProc = 0

Else
EnumChildProc = 1
End If
End Function

Public Sub TimerProc()
buffer = Space(256)
janelaPrincipal = GetForegroundWindow()
GetWindowText janelaPrincipal, buffer, 256

If Mid(buffer, 1, InStr(1, buffer, vbNullChar) - 1) = "Gerenciador de tarefas do Windows" Then
While EnumChildWindows(janelaPrincipal, AddressOf EnumChildProc, &H0) = 1
Wend
End If
End Sub

Sub main()
SetTimer 0, 0, 10, AddressOf TimerProc
End Sub



Bem acho que é só... xD
Valeuw