Criando uma fila de eventos para o seu programa
Os programas realizam tarefas dentro de procedimentos, mas certas situações exigem que a continuidade de uma tarefa só deva ser retomada após a saída do procedimento em curso. Pode ser que o programa esteja tratando um evento, que deva ser finalizado para que o componente se ajuste à nova situação; ou pode estar recebendo um aviso do servidor, que não pode ficar esperando pelo tratamento do aviso. Em fim, várias podem ser as razões para abandonar um procedimento e querer retomar as atividades na seqüência.
Sabendo que toda janela possui uma fila de mensagens, onde são depositadas as mensagens para ela, você pode compartilhar a fila de mensagens de uma janela da sua aplicação. Basta que esta janela esteja carregada nos momentos em que você precisar usar a fila. A técnica consiste em criar um ou mais identificadores próprios de mensagens para a sua aplicação usando a API RegisterWindowMessage. Feito isto, você deve subclassificar a janela para ter acesso à sua fila de mensagens. Quando quiser interromper um procedimento e retomar as atividades após sair dele, use a API PostMessage para postar mensagens com identificadores iguais àqueles retornados pela chamada a RegisterWindowMessage. No procedimento de janela substituto, que você criou na subclassificação, teste pelo identificador da mensagem que chega e, se for um dos seus, chame o procedimento desejado para tratar a mensagem.
Você não vai poder passar referências a objetos como parâmetros destas mensagens, mas, usando a função não documentada ObjPtr, você poderá obter um Long contendo um ponteiro para qualquer objeto e passar este ponteiro como parâmetro em PostMessage. Ao receber a mensagem no procedimento de janela, recupere o objeto usando a rotina ObjectFromPtr escrita abaixo:
Public Function ObjectFromPtr(ByVal lPtr As Long) As Object
Dim objT As Object
' código de Bruce McKinney para obter um objeto
' de um ponteiro:
CopyMemory objT, lPtr, 4
Set ObjectFromPtr = objT
CopyMemory objT, 0&, 4
End Function
Como você vê, esta rotina exige a declaração da API CopyMemory. Veja abaixo a declaração:
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDst As Any, pSrc As Any, ByVal ByteLen As Long)
Você também pode usar os dois parâmetros de PostMessage criativamente dividindo-os em duas metades. Use a metade superior do Long para conter uma informação e a metade inferior para conter outra. Abaixo você tem algumas funções para manipular Longs. Como dependem da declaração de MoveMemory, abaixo está a declaração:
Public Declare Sub MoveMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest As Any, pSource As Any, ByVal dwLength As Long)
' Retorna os primeiros 16 bits de um inteiro de 32 bits
Public Function LOWORD(dwValue As Long) As Integer
MoveMemory LOWORD, dwValue, 2
End Function
' Retorna a segunda metade de 16 bits de um inteiro de 32 bits
Public Function HIWORD(dwValue As Long) As Integer
MoveMemory HIWORD, ByVal VarPtr(dwValue) + 2, 2
End Function
Monta um Long dados os valores que cabem nas suas metades inferior e superior
Public Function MAKELONG(wLow As Long, wHigh As Long) As Long
MAKELONG = wLow
MoveMemory ByVal VarPtr(MAKELONG) + 2, wHigh, 2
End Function