Este artigo foi traduzido por máquina.

Windows Azure

CyberNanny: Acesso remoto via componentes distribuídos

Angel Hernandez Hernandez

Baixar o código de exemplo

Este artigo é sobre um aplicativo chamado CyberNanny, que escrevi recentemente para me permitir ver remotamente minha filha Miranda em casa em qualquer lugar a qualquer momento. Ele é escrito em Visual C++ (MFC) e é composto por diferentes tecnologias como Kinect e seu SDK, Windows Azure, serviços Web e automação de escritório através do Outlook. O projeto é hospedado no CodePlex (cybernanny.codeplex.com), onde você pode verificar o código ou contribuir para ele.

Antes de eu entrar em porcas e parafusos do aplicativo, vou explicar brevemente as tecnologias usadas para construí-lo.

C++ foi — e ainda é — a força de trabalho em muitas lojas de software. Dizendo isso, o novo padrão C++ 11 leva a linguagem a um novo nível. Três termos para descrever é moderno, elegante e extremamente rápido. Também, MFC é ainda ao redor, e a Microsoft tem sido atualizá-lo com cada nova versão do seu compilador Visual C++.

A tecnologia do Kinect é surpreendente, para dizer o mínimo; Ele altera o modo como interagimos com computadores e jogos. E com a Microsoft, fornecendo aos desenvolvedores com um SDK, um novo mundo de oportunidades é revelado para a criação de software que requer interação humana. Curiosamente, porém, o SDK do Kinect se baseia COM (como o novo modelo de programação em Windows 8, chamado de tempo de execução do Windows, muitas vezes abreviado como WinRT). O SDK também está disponível para os idiomas do Microsoft .net Framework.

O Windows Azure é a plataforma Microsoft como serviço (PaaS), oferecendo o que tem sido em torno de um par de anos. Ele fornece uma série de serviços que permitem a criação de soluções em cima deles (como computação e armazenamento). Um dos requisitos que tive com CyberNanny foi a entrega confiável de mensagens através de uma fila altamente disponível e o Windows Azure fornece que.

O uso nativo e o consumo de serviços Web é possível usar o Windows Web Services API (WWSAPI), que foi introduzido com o Windows 7. Eu tenho um blog (bit.ly/LiygQY) que descreve um aplicativo Windows Presentation Foundation (WPF) implementação de um componente nativo usando WWSAPI. É importante mencionar que WWSAPI é construído para o sistema operacional, portanto não é necessário baixar ou instalar qualquer coisa, mas o SDK do Windows (para arquivos de cabeçalho e lib).

Para quê reinventar a roda? Um dos requisitos para CyberNanny foi a capacidade de enviar e-mails com fotos em anexo, então em vez de escrever a minha própria classe e-mailing, preferi reutilizar a funcionalidade fornecida pelo Outlook para esta tarefa. Isso me permitiu focar o objetivo principal: Construindo um aplicativo distribuído para cuidar do meu bebê.

Este artigo está organizado em quatro seções principais:

  1. Visão geral da solução arquitetônica geral
  2. Arquitetura do Kinect
  3. Componentes implantados localmente (nativo)
  4. Componentes hospedados em nuvem (gerenciado)

Visão geral da solução arquitetônica geral

O conceito de CyberNanny é simples (como mostrado em Figura 1), mas também tem algumas peças em movimento. Brevemente pode ser descrito como um cliente grosso escrito em Visual C++, que captura pacotes via o sensor Kinect. Esses quadros podem ser usados mais tarde como uma imagem que é anexada a um e-mail novo composto no Outlook através da automação. O aplicativo é notificado sobre solicitações pendentes por desova um segmento disparado de um temporizador, que controla a fila hospedada no Windows Azure. Os pedidos são inseridos na fila através de uma página da Web do ASP.NET.

CyberNanny Architecture
Figura 1 arquitetura de CyberNanny

Observe que para executar e testar a solução, que você deve ter:

  • Sensor Kinect (eu usei no meu Xbox 360)
  • Assinatura do Windows Azure
  • SDK do Kinect

Arquitetura do Kinect

Ter um bom entendimento arquitetônico de como as coisas funcionam e como elas podem ser implementadas é crucial para o desenvolvimento de projetos, e neste caso Kinect não é excepção. A Microsoft forneceu um SDK para desenvolvedores de código gerenciado e nativo. Vou descrever a arquitetura do Kinect é construído em cima, como mostrado na Figura 2.

Kinect for Windows Architecture
Figura 2 Kinect for Windows arquitetura

Os números dentro de um círculo Figura 2 correspondem ao seguinte:

  1. Hardware Kinect: Os componentes de hardware, incluindo o Kinect e o hub USB através do qual o sensor é conectado ao computador.
  2. Drivers do Kinect: Os drivers do Windows para o Kinect, que são instalados como parte do processo de instalação do SDK, como descrito neste artigo. O suporte de drivers do Kinect:
    • A matriz de microfone do Kinect como um dispositivo de áudio de modo de kernel que você pode acessar através das APIs de áudio padrão no Windows.
    • Áudio e vídeo streaming controles para streaming de áudio e vídeo (cor, profundidade e esqueleto).
    • Funções de enumeração de dispositivos que permitem que um aplicativo para usar mais de um Kinect.
  3. Componentes de áudio e vídeo: O Kinect Natural User Interface (NUI) para acompanhamento de esqueleto, áudio, cor e imagem de profundidade.
  4. Objeto de mídia DirectX (DMO): Isso é para formação de feixe de matriz de microfone e a localização da fonte de áudio.
  5. APIs padrão do Windows 7: O áudio, discurso e mídia APIs no Windows 7, conforme descrito no SDK do Windows 7 e o Microsoft Speech SDK.

Vou demonstrar como eu usei o componente de vídeo para captura de quadros que são salvos como arquivos JPEG para fins de e-mail. O processamento de quadros capturados é feito via Direct2D.

A classe Nui_Core, escrevi uma classe chamada Nui_Core, que encapsula a funcionalidade que eu precisava do sensor Kinect. Não há uma única instância do objeto do aplicativo. O aplicativo interage com o sensor através de um membro do tipo INuiSensor que representa o dispositivo físico conectado ao computador. É importante lembrar que o SDK do Kinect é baseado, portanto, a referida interface — bem como todas as outras COM interfaces usados em todo o aplicativo — é gerenciado por ponteiros inteligentes (por exemplo, CComPtr <INuiSensor> m_pSensor;).

As etapas para iniciar a captura de quadros com o sensor são:

  1. Verifique se há um sensor, chamado NuiGetSensorCount.
  2. Crie uma instância do sensor Kinect, chamando NuiCreateSensorByIndex.
  3. Crie um objeto de fábrica para a criação de recursos de Direct2D, chamando D2D1CreateFactory.
  4. Crie eventos para cada fluxo exigido pelo aplicativo.
  5. Abra os fluxos chamando NuiImageStreamOpen.
  6. Processe os dados capturados (quadro).

Uma vez que a instância de Nui_Core é configurada, você pode facilmente levar uma imagem sob demanda, chamando o método TakePicture, conforme Figura 3.

Figura 3 O método de TakePicture

void Nui_Core::TakePicture(std::shared_ptr<BYTE>& imageBytes, int& bytesCount) {
  byte *bytes;
  NUI_IMAGE_FRAME imageFrame;
  NUI_LOCKED_RECT LockedRect;
  if (SUCCEEDED(m_pSensor->NuiImageStreamGetNextFrame(m_hVideoStream,
    m_millisecondsToWait, &imageFrame))) {
    auto pTexture = imageFrame.pFrameTexture;
    pTexture->LockRect(0, &LockedRect, NULL, 0);
    if (LockedRect.Pitch != 0) {
      bytes = static_cast<BYTE *>(LockedRect.pBits);
      m_pDrawColor->Draw(bytes, LockedRect.size);
    }
    pTexture->UnlockRect(0);
    imageBytes.reset(new BYTE[LockedRect.size]);
    memcpy(imageBytes.get(), bytes, LockedRect.size);
    bytesCount = LockedRect.size;
    m_pSensor->NuiImageStreamReleaseFrame(m_hVideoStream, &imageFrame);
  }
}

Observe que você passar um ponteiro inteligente para armazenar os bytes da imagem, bem como o número de bytes que são copiados para ele e, em seguida, essa informação é usada para artesanato seu bitmap.

É importante mencionar que quando você terminar usando o sensor, tem que ser desligado pelo chamado NuiShutdown, e precisam de identificadores que foram usados ser lançado.

A classe DrawDevice como mencionado anteriormente, os recursos de renderização são fornecidos pelo Direct2D; é por isso que outra classe de suporte é necessário para o uso em conjunto com Nui_Core. Essa classe é responsável por assegurar que existem recursos disponíveis para o quadro capturado, como um bitmap neste caso.

Os três métodos principais são Initialize, Draw e EnsureResources. Vou descrever cada uma.

Inicialize: Este é responsável pela criação de três membros do tipo DrawDevice. O aplicativo tem um controle guia com três guias, para que haja um membro para cada guia (ver cor, esquelética e profundidade). Cada guia é uma janela que é responsável por processar o quadro correspondente. O InitializeColorView mostrado o código a seguir é um bom exemplo de chamar o método Initialize:

bool Nui_Core::InitializeColorView() {
  auto width = m_rect.Width();
  auto height = m_rect.Height();
  m_pDrawColor = std::shared_ptr<DrawDevice>(new DrawDevice());
  return (m_pDrawColor.get()->Initialize(m_views[TAB_VIEW_1]->m_hWnd,
  m_pD2DFactory.p, 640, 320, NULL));
}

Sorteio: Isso apresenta um quadro na guia apropriado. Ele utiliza como argumento um Byte * capturada pelo sensor. Assim como no cinema, o efeito de animação vem de prestação sucessiva de quadros estáticos.

EnsureResources: Este é responsável por criar um bitmap quando solicitado pelo método Draw.

Componentes implantados localmente (nativo)

O projeto de CyberNanny compreende o seguinte:

  • aplicativo
    • CCyberNannyApp (Herdado de CWinApp). O aplicativo tem um único membro do tipo Nui_Core para interagir com o sensor.
  • Elementos de interface do usuário
    • CCyberNannyDlg (Main Window, herdado de CDialogEx)
    • CAboutDlg (sobre diálogo, herdado de CDialogEx)
  • Cliente de serviço Web
    • Arquivos gerados automaticamente após a execução de WSUTIL contra um serviço, linguagem WSDL (WSDL). Esses arquivos contêm as mensagens, estruturas e métodos expostos pelo serviço da Web do WCF.
  • Classes de objeto do Outlook
    • Para manipular alguns objetos do Outlook, você deve importá-los para seu projeto, selecionando "Adicionar classe de MFC" de Assistente de controle ActiveX. Os objetos usados nesta solução são aplicativos, acessório, Item de email e Namespace.
  • Proxy
    • Esta é uma classe personalizada que encapsula a criação dos objetos necessários para interagir com WWSAPI.
  • Classes auxiliares
    • Essas classes são usadas para suportar a funcionalidade do aplicativo, como converter um bitmap em JPEG para reduzir o tamanho de arquivo, fornecendo um wrapper para enviar e-mails e interagir com o Outlook e assim por diante.

Quando o aplicativo for iniciado, os seguintes eventos ocorrem:

  1. Uma nova janela de mensagem é definida, chamando o Register-WindowMessage. Isto é para adicionar itens à lista de eventos quando uma solicitação é processada. Isso é necessário porque você não pode modificar diretamente os elementos de interface do usuário de um thread diferente do thread da interface do usuário, ou você vai incorrer uma chamada ilegal de thread cruzado. Isso é gerenciado por infra-estrutura de mensagens do MFC.
  2. Você inicializar seu membro Nui_Core e definir um par de temporizadores (um para atualizar a hora atual na barra de status e outro que arranca um segmento para a fila para verificar se há uma solicitação pendente de votação).
  3. O sensor Kinect inicia a captura de quadros, mas o aplicativo não tirar uma foto, a menos que haja uma solicitação na fila. O método ProcessRequest é responsável por tirar uma foto, serializar a imagem no disco, escrita para o Visualizador de eventos e dando início a automação do Outlook, como mostrado na Figura 4.

Figura 4: chamar O ProcessRequest Método

void CCyberNannyDlg::ProcessRequest(_request request) {
  if (!request.IsEmpty) {
    auto byteCount = 0;
    ImageFile imageFile;
    std::shared_ptr<BYTE> bytes;
    m_Kinect.TakePicture(bytes, byteCount);
    imageFile.SerializeImage(bytes, byteCount);
    EventLogHelper::LogRequest(request);
    m_emailer.ComposeAndSend(request.EmailRecipient,
    imageFile.ImageFilePath_get());
    imageFile.DeleteFile();
  }
}

O quadro originalmente capturado pelo Kinect é um bitmap que é aproximadamente 1.7 MB de tamanho (o que não é conveniente para enviar emails e, portanto, precisa ser convertido em uma imagem JPEG). É também cabeça para baixo, por uma rotação de 180 ° é necessária. Isto é feito fazendo um par de chamadas para GDI +. Essa funcionalidade é encapsulada na classe ImageFile.

A classe ImageFile serve como um wrapper para a realização de operações com GDI+. Os dois principais métodos são:

  1. SerializeImage: Este método utiliza um shared_ptr <BYTE>, que contém os bytes do frame capturado para ser serializado como uma imagem, bem como a contagem de bytes. A imagem também é girada, chamando o método RotateFlip.
  2. GetEncoderClsid: Como mencionado, o tamanho do arquivo de imagem é grande demais para usar como um anexo — portanto, ele precisa ser codificado em um formato com uma pegada menor (JPEG, por exemplo). GDI+ fornece uma função de GetImageEncoders que permite descobrir quais codificadores estão disponíveis no sistema.

Até agora abordei como o aplicativo utiliza o sensor Kinect e como os quadros capturados são usados para criar uma imagem para enviar emails. Em seguida, mostrarei a você como chamar o serviço WCF hospedado no Windows Azure.

WWSAPI, introduzido no Windows 7, permite que desenvolvedores nativos consumir serviços WCF ou Web de forma fácil e conveniente, sem se preocupar com os detalhes de comunicação (soquetes). O primeiro passo para o consumo de um serviço é ter um WSDL para usar com WSUTIL que por sua vez produz codegen c código para proxies de serviço, que são estruturas de dados exigidas pelo serviço. Há uma alternativa chamada Casablanca (bit.ly/JLletJ), que suporta a comunicação cliente-servidor baseado em nuvem em código nativo, mas não estava disponível quando eu escrevi CyberNanny.

É comum para obter o WSDL e salvá-lo em disco e, em seguida, use o arquivo WSDL e arquivos de esquema relacionados como entrada para WSUTIL. Um aspecto a ter em conta é a esquemas. Eles devem ser baixados junto com o WSDL, caso contrário WSUTIL vai reclamar ao produzir os arquivos. Você pode facilmente determinar os esquemas necessários, verificando o parâmetro. xsd na seção do arquivo WSDL do esquema:

Wsutil /wsdl:cybernanny.wsdl /xsd:cybernanny0.xsd cybernanny1.xsd cybernanny2.xsd cybernanny3.xsd /string:WS_STRING

Os arquivos resultantes podem ser adicionados à solução, e, em seguida, prosseguir para chamar de seu serviço via arquivos codegen. Quatro principais objetos são necessários para usar com WWSAPI:

  1. WS_HEAP
  2. WS_ERROR
  3. WS_SERVICE_PROXY
  4. WS_CHANNEL_PROPERTY

Esses objetos permitem que a interação entre o cliente e o serviço. Eu coloquei a funcionalidade para invocar o serviço na classe de Proxy.

A maioria das funções WWSAPI retorna um HRESULT, para que depuração de erros pode ser uma tarefa desafiadora. Mas não tenha medo, porque você pode habilitar o rastreamento de Visualizar eventos do Windows e ver exatamente por que uma determinada função falha. Para ativar o rastreamento, navegue para Logs de aplicativos e serviços | Microsoft | WebServices | Rastreamento (clique sobre ela para ativá-lo).

Que abrange praticamente os componentes nativos da solução. Para obter mais informações, consulte o código fonte no site da CodePlex acima mencionado. A seção seguinte é sobre o componente de Windows Azure da solução.

Componentes hospedados em nuvem (gerenciado)

Por favor, note que este não é um tutorial extenso no Windows Azure, mas sim uma descrição dos componentes do Windows Azure em CyberNanny. Para mais informações detalhadas e detalhadas, consulte o site do Windows Azure em windowsazure.com. A plataforma Windows Azure (Figura 5) compreende os seguintes serviços:

  • Computação do Windows Azure
  • Armazenamento do Windows Azure
  • O banco de dados do Windows Azure SQL
  • Windows Azure AppFabric
  • Windows Azure Marketplace
  • Windows Azure rede Virtual

Azure Platform Services
Figura 5 Windows Azure Platform Services

CyberNanny só tem uma função de Web que alocou dois núcleos para garantir alta disponibilidade. Se houver falha em um de nós, a plataforma irá mudar para o nó saudável. A função de Web é um aplicativo ASP.NET, e ele apenas insere itens de mensagem em uma fila. Essas mensagens são, então, bateu para fora de CyberNanny. Há também um serviço WCF, que é parte da função de Web que é responsável por lidar com a fila.

Observe que uma função do Windows Azure é um componente individual executando na nuvem onde cada instância de uma nuvem corresponde a uma instância de máquina virtual (VM). No caso do CyberNanny, em seguida, eu alocou duas VMs.

CyberNanny tem uma função de Web é uma aplicação Web (seja apenas páginas ASPX ou serviços WCF) em execução no IIS. É acessível através de pontos de extremidade HTTP/HTTPS. Há também outro tipo de função que foi chamado uma função de trabalho. É um plano de fundo processamento do aplicativo (por exemplo, para cálculos financeiros), e também tem a capacidade de expor pontos de extremidade internos e voltados para a Internet.

Este aplicativo também utiliza uma fila fornecida pelo Windows Azure Storage, que permite o armazenamento confiável e entrega de mensagens. A beleza da fila é que você não tem que escrever nenhum código especializado para aproveitá-la. Também não são responsáveis por configurar o armazenamento de dados com uma certa estrutura para se assemelhar a uma fila, porque toda essa funcionalidade é fornecida para fora da caixa pela plataforma.

Além de alta disponibilidade e escalabilidade, um dos benefícios proporcionados pela plataforma Windows Azure é o ponto em comum para fazer coisas como desenvolvimento, teste e implantação de soluções de Windows Azure no Visual Studio, bem como tendo .net como o lingua-franca para construir soluções.

Existem alguns outros recursos interessantes que eu gostaria de adicionar a CyberNanny, tais como detecção de movimento e reconhecimento de voz. Se você quiser usar este software ou contribuir para o projeto, sinta-se livre para fazê-lo. As tecnologias utilizadas estão disponíveis agora e mesmo que eles parecem "diferentes", podem interoperar e jogar muito bem um com o outro.

Boa codificação.

Angel Hernandez Matos é um gerente da equipe de aplicativos corporativos na Avanade Austrália. Ele baseia-se em Sydney, na Austrália, mas é originalmente de Caracas, Venezuela. Ele foi um destinatário do Prêmio Microsoft MVP por oito anos consecutivos e atualmente é MVP em Visual C++. Ele tem escrito software desde os 12 anos de idade e se considera um "geek existencial".

Agradecemos aos seguintes especialistas técnicos pela revisão deste artigo: Scott Berry, Diego Dagum, Yonghwi Kwon e Nish Sivakumar