Compartilhar via


Implementando o comportamento do dispositivo

O comportamento de um dispositivo é definido pelos serviços que ele expõe. Cada serviço tem uma descrição de serviço que lista suas ações e variáveis de estado. Juntas, essas descrições de serviço compõem a interface de serviço, que define a maneira como um ponto de controle pode interagir com um serviço. Cada serviço deve ter pelo menos uma ação.

Para implementar um serviço, um dispositivo hospedado deve fornecer um objeto COM (Component Object Model) que expõe a interface para o serviço. Na descrição do serviço, as interfaces de serviço são especificadas em UTL (Linguagem de Modelo UPnP); no entanto, as interfaces de objeto COM normalmente são especificadas em IDL (Interface Definition Language). Você também pode especificar a interface COM em uma biblioteca de tipos ou arquivo de cabeçalho. O SDK (Platform Software Development Kit) inclui a ferramenta Utl2idl, que converte uma descrição de serviço em UTL para uma interface COM no IDL.

Os exemplos a seguir ilustram esse processo de conversão. A descrição do serviço é fornecida pelo desenvolvedor do dispositivo e é escrita em UTL.

<?xml version="1.0" ?> 
  <scpd xmlns="urn:schemas-upnp-org:service-1-0">

    <specVersion>
      <major>1</major> 
      <minor>0</minor> 
    </specVersion>

    <serviceStateTable>
      <stateVariable>
        <name>Power</name> 
        <dataType>Boolean</dataType> 
        <defaultValue>0</defaultValue> 
      </stateVariable>

      <stateVariable>
        <name>Level</name> 
        <dataType>i4</dataType> 
        <allowedValueRange>
          <minimum>0</minimum> 
            <maximum>10</maximum> 
            <step>1</step> 
        </allowedValueRange>
        <defaultValue>0</defaultValue> 
      </stateVariable>

      <stateVariable>
        <name>State</name> 
        <dataType>string</dataType> 
        <allowedValueList>
          <allowedValue>ON</allowedValue> 
          <allowedValue>OFF</allowedValue> 
          <allowedValue>DIMMED</allowedValue> 
        </allowedValueList>
        <defaultValue>OFF</defaultValue> 
      </stateVariable>
    </serviceStateTable>

    <actionList>
      <action>
        <name>PowerOn</name> 
      </action>

      <action>
        <name>PowerOff</name> 
      </action>

      <action>
        <name>SetLevel</name> 
        <argumentList>
          <argument>
            <name>NewLevel</name> 
            <relatedStateVariable>Level</relatedStateVariable> 
            <direction>in</direction> 
          </argument>
          <argument>
            <name>NewState</name> 
            <relatedStateVariable>State</relatedStateVariable> 
            <direction>out</direction> 
          </argument>
        </argumentList>
      </action>

      <action>
        <name>IncreaseLevel</name> 
      </action>

      <action>
        <name>DecreaseLevel</name> 
      </action>
    </actionList>
</scpd>

A próxima etapa é executar a ferramenta Utl2idl. Ele produz o arquivo IDL que contém a interface COM. Para obter mais informações sobre arquivos IDL e a interface palavra-chave, consulte Arquivo e interfaceIDL (Definição de Interface) na referência MIDL.

#include <windows.h>
typedef [v1_enum] enum SCPD_DISPIDS
{
     DISPID_POWER = 1,
     DISPID_LEVEL,
     DISPID_STATE,
     DISPID_POWERON,
     DISPID_POWEROFF,
     DISPID_SETLEVEL,
     DISPID_INCREASELEVEL,
     DISPID_DECREASELEVEL
} SCPD_DISPIDS;

[
     uuid(68369839-960d-4c8c-8d0d-c319c69e73be),
     oleautomation,
     pointer_default(unique)
]
interface IUPnPService_scpd : IUnknown 
{
     [propget, id(DISPID_POWER), helpstring("Property Power")]
     HRESULT Power(
          [out, retval] VARIANT_BOOL *pPower);

     [propget, id(DISPID_LEVEL), helpstring("Property Level")]
     HRESULT Level(
          [out, retval] long *pLevel);

     [propget, id(DISPID_STATE), helpstring("Property State")]
     HRESULT State(
          [out, retval] BSTR *pState);

     [ id(DISPID_POWERON), helpstring("Method PowerOn")]
     HRESULT PowerOn();

     [ id(DISPID_POWEROFF), helpstring("Method PowerOff")]
     HRESULT PowerOff();

     [ id(DISPID_SETLEVEL), helpstring("Method SetLevel")]
     HRESULT SetLevel(
          [in] long NewLevel,
          [in, out] BSTR *pNewState;
                                
     [ id(DISPID_INCREASELEVEL), helpstring("Method IncreaseLevel")]
     HRESULT IncreaseLevel();

     [ id(DISPID_DECREASELEVEL), helpstring("Method DecreaseLevel")]
     HRESULT DecreaseLevel();
};

Observação

O valor retornado é o primeiro parâmetro [out] na lista de argumentos na descrição do serviço; no entanto, ele é listado como o último parâmetro após a tradução.

Todos os outros parâmetros permanecem na mesma ordem.

 

Para fornecer a funcionalidade do serviço, implemente essa interface COM.

Obtendo informações sobre um ponto de extremidade

Na estrutura UPnP, as informações do ponto de extremidade incluem informações sobre uma solicitação e sua origem. Um dispositivo pode examinar essas informações para tomar uma decisão sobre a solicitação.

Opcionalmente, as informações de ponto de extremidade estão disponíveis para o serviço implementado. O host do dispositivo tem acesso a informações de ponto de extremidade; no entanto, o host do dispositivo não comunica as informações para o serviço implementado por padrão. Você pode habilitar o host do dispositivo para compartilhar as informações do ponto de extremidade com o serviço implementado modificando a interface COM no arquivo IDL (produzido pela ferramenta Utl2idl). Você pode adicionar um parâmetro [in] a cada método que requer informações de ponto de extremidade. O parâmetro [in] adicional deve ser o primeiro na lista de argumentos, um ponteiro para uma interface IUnknown e explicitamente chamado punkRemoteEndpointInfo. Modificações no XML de Serviço não são necessárias ou recomendadas. O exemplo a seguir mostra a nova definição do método PowerOn quando ele é alterado para que ele receba informações de ponto de extremidade:

"HRESULT PowerOn([in] IUnknown *punkRemoteEndpointInfo);"

Um ponteiro para um objeto de informações de ponto de extremidade, uma interface IUPnPRemoteEndpointInfo , é passado por esse novo parâmetro pelo host do dispositivo. A interface IUPnPRemoteEndpointInfo fornece três métodos para acessar as informações do ponto de extremidade. Você deve chamar o método apropriado para obter as informações de ponto de extremidade exigidas pela implementação do serviço.

Como alternativa à modificação manual da interface COM, você pode usar a ferramenta Utl2idl com a opção -ci . Essa opção faz com que a ferramenta adicione o parâmetro de informações de ponto de extremidade a cada um dos métodos na interface COM. O uso da opção -ci não facilita a modificação de métodos individuais. Se as informações do ponto de extremidade não forem necessárias para todos os métodos de uma interface, você deverá adicionar o parâmetro manualmente para produzir as implementações mais eficientes.

Implementando um objeto de serviço

Você deve usar a ferramenta Utl2idl para traduzir cada descrição de serviço de um dispositivo.

Um objeto que fornece a funcionalidade de um serviço é chamado de objeto de serviço. Além de fornecer funcionalidade de serviço, os objetos de serviço lidam com erros usando a interface IDispatch . Para obter mais informações, consulte Usando a API de Host do Dispositivo com a Tecnologia UPnP.

Para garantir a compatibilidade com o Visual Basic, que não dá suporte a parâmetros [out], os parâmetros de direçãoout**/direction** na descrição do serviço são convertidos em parâmetros [in, out] em IDL. O servidor deve liberar esses parâmetros [in, out].

Implementando um objeto de controle de dispositivo

Além de implementar objetos de serviço, você deve implementar um objeto de controle de dispositivo. Um objeto de controle de dispositivo é o ponto central de gerenciamento e controle para os objetos de serviço do dispositivo. No momento do registro, o objeto de controle do dispositivo é passado para o host do dispositivo. Quando uma assinatura de evento ou solicitação de controle chega para um dos serviços do dispositivo, o host do dispositivo chama esse objeto de controle de dispositivo para obter o objeto de serviço relevante. Nesse momento, o objeto de controle do dispositivo cria uma instância do objeto de serviço ou retorna a interface de uma instância existente do objeto de serviço.

Você pode registrar uma descrição do dispositivo em vários computadores ou várias vezes no mesmo computador. Como o UDN (Nome exclusivo do dispositivo) deve ser diferente para cada instância do dispositivo, o host do dispositivo gera uma UDN exclusiva para cada dispositivo e dispositivo inserido sempre que o dispositivo é registrado. Use a UDN especificada no modelo de descrição do dispositivo para obter o UDN real gerado pelo host do dispositivo e associado ao dispositivo. Para cancelar o registro de um dispositivo, você deve usar a ID fornecida pela estrutura UPnP quando o dispositivo foi registrado.

Os objetos de controle do dispositivo devem implementar a interface IUPnPDeviceControl . O host do dispositivo invoca o método IUPnPDeviceControl::Initialize do objeto de controle do dispositivo, passando a descrição do dispositivo baseada em UPnP que o host do dispositivo publicou anteriormente para o dispositivo e uma cadeia de caracteres de inicialização especificada no momento do registro (consulte Registrando um dispositivo hospedado com o host do dispositivo). Nesta descrição do dispositivo, o objeto de controle do dispositivo lê as UDNs atribuídas a cada um dos dispositivos na árvore de dispositivos. Você também pode usar o método IUPnPRegistrar::GetUniqueDeviceName para obter essas informações.

Quando o host do dispositivo requer um ponteiro para um objeto de serviço que implementa um serviço específico, ele invoca o método IUPnPDeviceControl::GetServiceObject no objeto de controle do dispositivo. O host do dispositivo passa o UDN e a ID de serviço do serviço para o qual ele está solicitando um objeto de serviço e o endereço de um ponteiro IDispatch no qual o método deve retornar um ponteiro para o objeto de serviço. O parâmetro UDN é necessário porque o objeto de controle de dispositivo gerencia serviços para toda a árvore de dispositivos, incluindo dispositivos aninhados. Se o host do dispositivo solicitar um dispositivo aninhado, GetServiceObject usará o UDN para identificá-lo.