Às vezes, nosso componente COM deve enviar uma notificação ao cliente ou chamar a função de retorno de chamada. O esquema é simples: o componente publica a interface, o cliente cria um objeto herdado da interface e o passa para o componente, o componente, por sua vez, chama as funções da interface, chamando as funções no lado do cliente.
No caso do Visual Basic ou Visual Basic for Applicatons, podemos escrever uma classe herdada de qualquer interface, mas isso não é possível para arquivos de script VBScript.
Aqui a interface do IDispatch
corre em nosso auxílio. Usando essa interface, nosso componente poderoso assumirá humildemente o papel modesto de um cliente, e um pequeno script se tornará um servidor de automação real.
Vamos desenvolver o componente na linguagem de programação FreeBASIC.
Classes no arquivo de script
Você pode declarar e usar classes em arquivos de script. Tais classes são herdadas implicitamente da interface IDispatch
e são classes COM reais.
Declaramos uma classe, uma instância da qual passaremos para o nosso componente mais tarde:
Class CallBack Function CallBack(Param)
Nosso componente receberá uma instância da classe CallBack
, chamará a função CallBack
e passará uma string com texto no parâmetro
IDispatch
Essa interface é o obstáculo da automação. Normalmente, a implementação do IDispatch
baseada em uma biblioteca de tipos através da função ITypeInfo->Invoke
ou CreateStdDispatch
, mas nesse caso o servidor de automação está localizado em um script e não possui uma biblioteca de tipos, e nosso componente atua como um cliente. Para simplificar, o IDipatch
funciona assim: pega o nome da função e transfere o controle para ela.
A definição da interface está no cabeçalho "oaidl.bi" (recuos e quebras de linha são adicionados para facilitar a leitura):
Type IDispatch As IDispatch_ Type LPDISPATCH As IDispatch Ptr Type IDispatchVtbl
As funções GetIDsOfNames
e Invoke
são mais interessantes nessa interface.
GetIDsOfNames
Ele pega o nome da função e retorna seu identificador de despacho DISPID
. DISPID
é um alias para o tipo LONG
.
Do ponto de vista do cliente, DISPID
é simplesmente uma ferramenta de otimização que evita DISPID
linha. Para o servidor, DISPID
é o identificador da função que o cliente deseja chamar.
Invocar
Por identificador de despacho executa a função correspondente.
DISPPARAMS
Essa estrutura contém os parâmetros da função chamada. Todos os parâmetros são empacotados em VARIANT
.
Type tagDISPPARAMS
Para simplificar o código, não usaremos argumentos nomeados; em vez disso, definiremos NULL
.
Componente
Para uso em scripts, os componentes também devem herdar direta ou indiretamente do IDipatch
.
Interface ITestCOMServer
ITestCOMServer
criar a interface ITestCOMServer
com duas funções SetCallBack
e InvokeCallBack
. O primeiro salvará o objeto do servidor de automação, o segundo chamará a função de objeto.
Type ITestCOMServer As ITestCOMServer_ Type LPITESTCOMSERVER As ITestCOMServer Ptr Type ITestCOMServerVirtualTable
Classe TestCOMServer
Agora você pode declarar uma classe COM:
Type TestCOMServer
Função setcallback
A implementação da função SetCallBack
simples: salvamos o objeto do servidor de automação transmitido pelo cliente e o parâmetro de chamada da função.
Function TestCOMServerSetCallBack( _ ByVal pTestCOMServer As TestCOMServer Ptr, _ ByVal CallBack As IDispatch Ptr, _ ByVal UserName As BSTR _ )As HRESULT
Função InvokeCallBack
Mas a função InvokeCallBack
terá InvokeCallBack
trabalhar duro. Primeiro, você precisa obter o identificador de despachante da função CallBack
do servidor de automação.
Function TestCOMServerInvokeCallBack( _ ByVal pTestCOMServer As TestCOMServer Ptr _ )As HRESULT If pTestCOMServer->CallBack = NULL Then Return E_POINTER End If
Depois que o DISPID
função é recebido, ele pode ser chamado:
Conclusão
Como você pode ver, mesmo com um arquivo de script, um componente pode receber feedback. Isso é útil para notificar o cliente sobre as operações concluídas pelo componente.
As classes em scripts podem ser registradas no registro, caso em que estarão disponíveis para todo o sistema usando ProgID
, mas essa é uma história completamente diferente.
Referências
Código do projeto no site do github: https://github.com/zamabuvaraeu/TestCOMServer
PS De alguma forma, o destaque para a sintaxe BASIC desapareceu, usou o VBScript e alguns operadores não são destacados.