Tempo de Execução do Windows

Reimaginando o Desenvolvimento de Aplicativo com o Tempo de Execução do Windows

Jason Olson

 

Desenvolver aplicativos Windows e usar os novos recursos do Windows com a linguagem de programação de sua escolha nem sempre foi simples e direto. Para os clientes terem a melhor experiência no Windows 8 e para dar autonomia aos desenvolvedores para criar os melhores aplicativos no Windows, investimentos são necessários para melhorar o desenvolvimento e a experiência de ponta a ponta no Windows. No centro desses investimentos está o Tempo de Execução do Windows (WinRT).

O Tempo de Execução do Windows faz parte de uma releitura da experiência do desenvolvedor para Windows. É a superfície moderna da API do Windows usada para criar novos aplicativos para a Windows Store no Windows 8. O Tempo de Execução do Windows foi desenvolvido desde o princípio para suportar várias das principais linguagens de programação (C#/Visual Basic, JavaScript e C++) para permitir que os desenvolvedores usem suas habilidades e ativos existentes para fornecer uma superfície de API elaborada e projetada de forma consistente para ser fortemente integrada à cadeia de ferramentas para desenvolvedores.</p>

O Tempo de Execução do Windows permite a escolha da linguagem

Há muitos desenvolvedores de aplicativos por aí. Eles variam de desenvolvedores que usam JavaScript/HTML/CSS para criar aplicativos Web a desenvolvedores que usam C#/Visual Basic para criar aplicativos com o Microsoft .NET Framework, e há também aqueles que criam aplicativos com C++. O Tempo de Execução do Windows permite que os aplicativos da Windows Store sejam escritos em qualquer uma dessas linguagens de programação, dando autonomia para todos esses desenvolvedores para criarem grandes aplicativos Windows, como mostrado na Figura 1.


Figura 1 O Tempo de Execução do Windows permite que novos aplicativos da Windows Store sejam escritos em várias linguagens

Isso é benéfico para desenvolvedores e consumidores. Existe uma enorme oportunidade de mercado para os desenvolvedores ganharem dinheiro com a criação de aplicativos da Windows Store. E com o suporte de todas as principais linguagens da Microsoft, muitos desenvolvedores estão disponíveis para criar os grandes aplicativos Windows que os consumidores querem comprar e usar.

Como desenvolvedor, você tem habilidades existentes e experiência na linguagem de programação de sua escolha. Você também tem muitos ativos existentes usados para desenvolver aplicativos (como o código existente, infraestrutura de criação e assim por diante). Você não deve ser obrigado a aprender a usar uma linguagem de programação e um conjunto de ferramentas totalmente novos simplesmente para desenvolver aplicativos da Windows Store no Windows 8 quando já existe um rico conjunto de linguagens de programação e ferramentas de desenvolvimento fornecidas pela Microsoft.

O Tempo de Execução do Windows é Natural e Familiar

A experiência anterior de desenvolvimento do Windows foi concebida quando C era a linguagem de programação dominante, quando o código baseado em exceção era raro e quando ser associado a uma única linguagem era aceitável para um sistema operacional Windows. O mundo moderno do desenvolvedor de hoje é completamente diferente. Recursos de programação como namespaces, coleções, eventos, assincronismo etc. não são apenas comuns hoje, eles são esperados.

Vamos dar uma olhada no uso de um dos dispositivos mais comuns no Windows hoje: a webcam. Era assim que parte da API da webcam era declarada anteriormente no Windows:

HWND VFWAPI capCreateCaptureWindow(
  LPCTSTR lpszWindowName,
  DWORD dwStyle,
  int x,
  int y,
  nit nWidth,
  int nHeight,
  HWND hWnd,
  int nID
);

As APIs anteriores do Windows eram basicamente declaradas em um arquivo de cabeçalho nativo (*. h) fornecido como parte do SDK do Windows. O SDK também incluía um arquivo. lib, ao qual o código que usava a API era vinculado. As APIs do Windows eram implementadas em C/C como funções C simples nativas ou como componentes COM nativos e empacotados em um arquivo. dll fornecido como parte do Windows. O modelo de programação era elaborado nativamente com o desempenho em mente.

Não havia namespaces, coleções modernas ou exceções reais. Mesmo para os desenvolvedores nativos clássicos a experiência de desenvolvimento não era ideal, pois havia problemas com IntelliSense, navegação de código, falta de namespaces e muito mais.

Essa plataforma puramente nativa apresentou problemas de usabilidade reais também para desenvolvedores do .NET que tentavam usar APIs do Windows, como mostrado na Figura 2.

Figura 2 A plataforma puramente nativa anterior apresentou problemas de usabilidade reais

[DllImport("avicap32.dll", EntryPoint = "capCreateCaptureWindow")]
static extern int capCreateCaptureWindow(
  string lpszWindowName, int dwStyle,
  int X, int Y, int nWidth, int nHeight,
  System.IntPtr hwndParent, int nID);
[DllImport("avicap32.dll")]
static extern bool capGetDriverDescription(
  int wDriverIndex,
  [MarshalAs(UnmanagedType.LPTStr)] ref string lpszName,
  int cbName,
  [MarshalAs(UnmanagedType.LPTStr)] ref string lpszVer,
  int cbVer);

Alguém precisava escrever uma série de códigos para preencher manualmente essa lacuna entre o código e as APIs tradicionais do Windows. Se ninguém o fizesse, você mesmo teria de tentar escrever esse código complicado. Muitos recursos para desenvolvedores visam especificamente eliminar essa lacuna, incluindo o pinvoke.net, a biblioteca de amostras do Vista Bridge (code.msdn.microsoft.com/VistaBridge) e o pacote de códigos de API do Windows para Microsoft .NET Framework (code.msdn.microsoft.com/WindowsAPICodePack).

Agora, com o Windows 8, você pode usar APIs do Windows imediatamente no dia em que são lançadas pelo Windows, exatamente da mesma maneira que você usa outras APIs em seus aplicativos atualmente (como no .NET Framework para desenvolvedores de C#/Visual Basic). O código não precisa mais ser escrito para preencher a lacuna entre o código e as APIs tradicionais do Windows. Por exemplo, usar a webcam é muito mais simples hoje:

using Windows.Media.Capture;
MediaCapture captureMgr = new MediaCapture();
await captureMgr.InitializeAsync();
// Start capture preview; capturePreview
// is a CaptureElement defined in XAML
capturePreview.Source = captureMgr;
await captureMgr.StartPreviewAsync();

Então, como usar o Tempo de Execução do Windows é natural e familiar para os desenvolvedores? Como muitos aplicativos recuperam dados da Internet, vamos examinar esta questão no contexto de um cenário de rede comum: recuperar um RSS feed. Este é o código C# para recuperar esse feed assincronamente:

var feedUri = 
  new Uri("http://www.devhawk.com/rss.xml");
var client = new Windows.Web.Syndication.SyndicationClient();
var feed = await client.RetrieveFeedAsync(feedUri);
var title = feed.Title.Text;

Este é o código do Visual Basic equivalente:

Dim feedUri = New Uri("http://www.devhawk.com/rss.xml");
Dim client = New Windows.Web.Syndication.SyndicationClient();
Dim feed = Await client.RetrieveFeedAsync(feedUri);
Dim title = feed.Title.Text;

Exceto para o namespace raiz (Windows), não há muita diferença neste código em relação ao código que você já escreve com o .NET Framework. Há namespaces. Há classes e construtores. Há métodos e propriedades. Os identificadores estão em Pascal case porque estão no .NET Framework, e também usamos a palavra-chave await para a programação assíncrona — tudo que um desenvolvedor espera quando escreve código usando C# e Visual Basic hoje em dia.

Similar à experiência de desenvolvimento em C#/Visual Basic, C++ usa namespaces, classes, construtores, métodos e propriedades. Você também pode usar tipos C++ integrados, como cadeias de caracteres (ao contrário de tipos de dados Win32 anteriores). Operadores padrão como “::” e “->” e outros são usados também conforme esperado. E para a programação assíncrona, oferecemos uma experiência semelhante ao tempo de execução em simultaneidade. Este é o código C++ para recuperar um RSS feed de forma assíncrona:

auto feedUri = ref new 
  Windows::Foundation::Uri("http://www.devhawk.com/rss.xml");
auto client = ref new Windows::Web::Syndication::SyndicationClient();
task<SyndicationFeed^> 
  retrieveTask(client->RetrieveFeedAsync(feedUri));
retrieveTask.then([this] (SyndicationFeed^ feed) {
  this->title = feed->Title->Text;
});

Finalmente, há o JavaScript, que mostra algumas diferenças interessantes no código equivalente:

var title;
var feedUri = 
  new Windows.Foundation.Uri("http://www.devhawk.com/rss.xml");
var client = new Windows.Web.Syndication.SyndicationClient();
client.retrieveFeedAsync(feedUri).done(function (feed) {
  title = feed.title.text;
});

Você vai notar no JavaScript que todos os métodos e propriedades estão em camel case porque é natural e familiar para os desenvolvedores de JavaScript. Também estamos usando uma estrutura de promessas com funções anônimas para escrever o código assíncrono. Vamos continuar utilizando os tipos integrados da linguagem aqui também.

A experiência do desenvolvedor também é familiar, com ferramentas de recursos que os desenvolvedores esperam, como o IntelliSense e ferramentas padrão como ILDASM e .NET Reflector (veja a Figura 3).


Figura 3 Visual Studio IntelliSense para APIs do WinRT

O Tempo de Execução do Windows oferece essa experiência natural e familiar, estendendo e combinando conceitos básicos do .NET e COM para adicionar semântica moderna a APIs do WinRT, como classes, construtores, eventos e estatísticas. Essa semântica pode ser exposta de diferentes maneiras em linguagens diferentes, tudo dependendo do que é natural e familiar para os desenvolvedores nessa linguagem.

Isso é possível porque todas as APIs do WinRT incluem metadados que as linguagens de programação usam para saber como essa API é exposta pelo Tempo de Execução do Windows. Os arquivos de metadados do WinRT usam uma versão atualizada do formato de metadados do .NET. Esses metadados estão disponíveis para todos os desenvolvedores, porque é instalado em cada máquina do Windows 8.

Com a releitura da superfície de desenvolvimento de API do Windows, não parece que está se conhecendo ou usando uma nova plataforma. Não parece um “ET”. Parece o código que você escreve. Você está aproveitando as habilidades existentes e os ativos que você tem para criar novos aplicativos da Windows Store.

O Tempo de Execução do Windows é rico em funcionalidades

O Tempo de Execução do Windows tem menos APIs que o Win32. Por isso, é fácil de aprender, e ainda é rico em funcionalidades. A riqueza do Tempo de Execução Windows é suficiente para cobrir inteiramente em um artigo deste tamanho, mas os recursos padrão do Windows e os novos recursos do Windows 8 que você espera encontrar estão lá, como mostrado na Figura 4.


Figure 4 O Tempo de Execução do Windows inclui os recursos padrão do Windows e os novos recursos do Windows 8

E o Tempo de Execução do Windows foi consistentemente projetado pelo uso de um conjunto unificado de diretrizes de design de API. Você conhece os conceitos e o design uma vez com uma única API, e depois pode aplicar esse conhecimento ao uso de APIs diferentes em toda a superfície de API do Windows. 

No Centro de Desenvolvimento do Windows (dev.windows.com), você encontrará muitos exemplos que abrangem a maior parte dessas áreas. A seguir estão alguns exemplos.

Contratos Você pode deixar que os usuários pesquisem em seu aplicativo quando selecionam o botão Pesquisar e exibir sugestões no painel de pesquisa. Seu aplicativo também pode compartilhar conteúdo com outro aplicativo usando o botão Compartilhar. Estes são alguns exemplos:

  • Exemplo de contato de pesquisa: bit.ly/QxsLQk
  • Exemplo de compartilhamento de aplicativo de origem de conteúdo: bit.ly/H10Nd0
  • Exemplo de compartilhamento de aplicativo de destino de conteúdo: bit.ly/HeuMOL

Social Usando classes do namespace Windows.ApplicationModel.Contacts, você pode abrir Seleção de Contatos e adquirir contatos. Para aplicativos que precisam fornecer contatos para outros aplicativos, você pode usar a classe ContactPickerUI para criar uma coleção de contatos:

Mídia Da simples reprodução e captura de mídia à transcodificação e reprodução de mídia em dispositivos externos através do contrato do botão Reproduzir em, você encontrará APIs do Windows no namespace Windows.Media:

Segurança Você pode recuperar credenciais, que pode então ser passadas para APIs que podem exigir credenciais (por exemplo, para oferecer suporte ao logon único). Você também pode usar criptografia segura baseada em senha para armazenar informações particulares com segurança em um computador local para proteger contas de cartão de crédito, contas bancárias e produtos de software. Você pode até mesmo executar muitas formas diferentes de criptografia usando o namespace Windows.Security.Cryptography:

Redes/Web Se você for se conectar à rede via TCP usando a classe StreamSocket, via protocolo UDP (User Datagram) usando o DatagramSocket, ou for simplesmente consultar o status das informações de rede para descobrir se pode salvar alguns dados de aplicativo em um serviço Web ou precisa salvá-los localmente, poderá encontrar o que precisa no namespace Windows.Networking:

Essa não é toda a funcionalidade do Tempo de Execução do Windows, é claro. Há muito mais funcionalidade disponível para você como desenvolvedor do Windows, e você pode investigar mais no Centro de Desenvolvimento do Windows em bit.ly/yyJI2J.

O Tempo de Execução do Windows é rápido e fluido (nativo e assíncrono)

O Tempo de Execução do Windows é implementado no nível mais baixo como objetos nativos com contrato de binário, mas ele é exposto ao mundo através de metadados, um sistema de tipo comum e linguagens compartilhadas. As APIs do WinRT continuam oferecendo os recursos de desempenho rápido das APIs anteriores do Windows, fornecendo também uma experiência de desenvolvimento moderna, conforme demonstrei anteriormente.

Para os aplicativos permanecerem fluidos e ágeis, o diferente é outro. Nós, seres humanos, somos instintivamente multitarefa, o que afeta diretamente como esperamos que os aplicativos nos respondam. Esperamos que os aplicativos respondam a todas as interações. Quando usamos nosso aplicativo de leitura de notícias favorito, queremos adicionar feeds de notícias, ler notícias e artigos, guardar artigos de notícias e assim por diante. E devemos ser capazes de fazer tudo isso mesmo quando o aplicativo está recuperando os artigos mais recentes da Internet.

Isso se torna especialmente importante quando interagimos com aplicativos usando o toque. Percebemos quando o aplicativo não "segue" nosso dedo. Problemas de desempenho ainda menores podem degradar nossa experiência e quebrar a sensação de agilidade e fluidez.

Muitos aplicativos modernos se conectam a sites sociais, armazenam dados na nuvem, funcionam com arquivos no disco rígido, se comunicam com outros gadgets e dispositivos, e assim por diante. Algumas dessas fontes têm latências imprevisíveis, o que torna a criação de aplicativos rápidos e fluidos desafiadora. A menos que criados corretamente, os aplicativos passam mais tempo esperando o ambiente externo e menos tempo atendendo às necessidades do usuário.

Atender esse mundo conectado é um princípio básico do Tempo de Execução do Windows. Você, o desenvolvedor, deve cair no "poço do sucesso" (ver bit.ly/NjYMXM) para criar aplicativos conectados ao mundo. Para conseguir isso, APIs potencialmente associadas à E/S ou de execução demorada são assíncronas no Tempo de Execução do Windows. Elas são os candidatos mais prováveis para degradar o desempenho visivelmente se escritas de forma síncrona (por exemplo, provavelmente demorariam mais de 50 ms para executar). Essa abordagem assíncrona para APIs permite que você escreva um código rápido e fluido por padrão e promove a importância da capacidade de resposta do aplicativo no desenvolvimento de aplicativos da Windows Store.

Para saber mais sobre a natureza assíncrona do Tempo de Execução do Windows, leia a publicação do blog “Mantendo os aplicativos rápidos e fluidos com assincronia no Tempo de Execução do Windows”, em bit.ly/GBLQLr.

O Tempo de Execução do Windows permite aplicativos híbridos

Um poderoso recurso do Tempo de Execução do Windows é que você não fica restrito à linguagem de programação que escolher para criar seu aplicativo. Você não fica limitado apenas às bibliotecas e o código disponível para esse ambiente de linguagem de programação. Você pode usar a linguagem, biblioteca ou componente mais adequado para o trabalho. Pode ser uma biblioteca de código aberto.

E se você estiver escrevendo um jogo com JavaScript/HTML/CSS e quiser uma biblioteca física muito rápida? Você pode usar o Box2D em C++. Escrevendo um aplicativo da Windows Store com JavaScript e quer trabalhar em alguns arquivos compactados? Você pode usar a funcionalidade zip no .NET Framework de forma simples. Criando um novo aplicativo de música da Windows Store em C# e quer fazer programação de áudio de nível inferior? Sem problemas, basta usar o Xaudio ou WASAPI em C++. Esses recursos são ilustrados na Figura 5.


Figura 5 O Tempo de Execução do Windows permite aplicativos híbridos

Vejamos um exemplo de aplicativo sintetizador de software que usa XAML escrito em C#. Quero adicionar um suporte de filtro legal. Então, vou usar o Xaudio para ter o controle direto dos buffers de áudio. Uso C++/CX para criar as APIs que ficarão expostas ao projeto C#.

Primeiramente, crio um wrapper simples do WinRT em torno da funcionalidade Xaudio que quero expor (veja a Figura 6).

Figura 6 XAudioWrapper.h

#pragma once
#include "mmreg.h"
#include <vector>
#include <memory>
namespace XAudioWrapper
{
  public ref class XAudio2SoundPlayer sealed
  {
    public:
      XAudio2SoundPlayer(uint32 sampleRate);
      virtual ~XAudio2SoundPlayer();
      void Initialize();
      bool   PlaySound(size_t index);
      bool   StopSound(size_t index);
      bool   IsSoundPlaying(size_t index);
      size_t GetSoundCount();
      void Suspend();
      void Resume();
    private:
      interface IXAudio2*                m_audioEngine;
      interface IXAudio2MasteringVoice*  m_masteringVoice;
      std::vector<std::shared_ptr<ImplData>>  m_soundList;
    };
}

Primeiro, observe o uso das palavras-chave “public,” “ref” e “sealed” na declaração da classe. É simplesmente assim que você declara uma classe pública do WinRT em C++/CX. Isso permitirá que você use essa classe em outras linguagens, como JavaScript, C# ou Visual Basic. É importante observar que isso não é C++ gerenciado ou C++/CLI(Common Language Infrastructure). Isso não é compilar na linguagem intermediária da Microsoft; é um componente nativo de ponta a ponta.

Você também perceberá que a funcionalidade pública (métodos, propriedades e assim por diante) da classe é limitada a tipos C++ integrados ou tipos WinRT. Esses são os únicos tipos permitidos para cruzar a fronteira da linguagem em componentes WinRT. No entanto, você pode usar bibliotecas C++ existentes (por exemplo, Standard Template Library) o quanto quiser na implementação de seus componentes do WinRT.

Para obter mais detalhes sobre como criar componentes do WinRT em C++, leia o tópico do Centro de Desenvolvimento do Windows "Criando componentes do Tempo de Execução do Windows em C++" em bit.ly/TbgWz7.

Agora que defini a interface básica para minha classe, vamos dar uma olhada rápida em alguns dos métodos implementados (os detalhes não são importantes) como mostrado na Figura 7.

Figura 7 XAudioWrapper.cpp

XAudio2SoundPlayer::XAudio2SoundPlayer(uint32 sampleRate) :
  m_soundList()
{
  ...
  XAudio2Create(&m_audioEngine, flags);
  // Create the mastering voice
  m_audioEngine->CreateMasteringVoice(
    &m_masteringVoice,
    XAUDIO2_DEFAULT_CHANNELS,
    sampleRate
  );
}
bool XAudio2SoundPlayer::PlaySound(size_t index)
{
  //
  // Setup buffer
  //
  XAUDIO2_BUFFER playBuffer = { 0 };
  std::shared_ptr<ImplData> soundData = m_soundList[index];
  playBuffer.AudioBytes = soundData->playData->Length;
  playBuffer.pAudioData = soundData->playData->Data;
  playBuffer.Flags = XAUDIO2_END_OF_STREAM;
  HRESULT hr = soundData->sourceVoice->Stop();
  if (SUCCEEDED(hr))
  {
    ...
  }
  ...
}

Como pode perceber no trecho de código da Figura 7, estou usando as APIs COM Xaudio2 disponíveis no Windows SDK para aplicativos da Windows Store para conectar o mecanismo de áudio. Além disso, estou usando construtores e tipos C++ além dos tipos WinRT para implementar a funcionalidade necessária.

Uma vez que defini e implementei minha classe básica, posso simplesmente adicionar uma referência ao meu projeto C++ do meu projeto C#. Em resultado, a classe exposta do meu projeto C++ torna-se disponível para meu projeto C# (veja a Figura 8).

Figura 8 MainPage.cs

using XAudioWrapper;
namespace BasicSoundApp
{   
  public sealed partial class MainPage : Page
  {
    XAudio2SoundPlayer _audioPlayer = new XAudio2SoundPlayer(48000);
    public MainPage()
    {
      this.InitializeComponent();
    }
    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
      _audioPlayer.Initialize();
    }
    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
      _audioPlayer.PlaySound(0);
    }
  }}

Você pode ver que, embora o XAudioWrapper tenha sido escrito em C++ nativo, ele pode ser usado como se fosse uma classe .NET regular. Eu referencio seu namespace, instancio o componente e começo a chamar diversos métodos que ele expõe — tudo sem exigir DllImports para chamar o código nativo!

Não há limites. Como desenvolvedor de JavaScript, você não fica limitado às bibliotecas de JavaScript. Como desenvolvedor de C#/Visual Basic, você não fica limitado às bibliotecas do .NET. E como desenvolvedor de C++, você não fica limitado às bibliotecas de C/C++. Você vai precisar criar seus próprios componentes frequentemente? Talvez não. Mas a opção está disponível para você.

Resumindo, o Tempo de Execução do Windows é o centro da criação de aplicativos da Windows Store no Windows 8. Ele fornece uma plataforma poderosa criar aplicativos da Windows Store. O Tempo de Execução do Windows fornece uma superfície de desenvolvimento que tem um design consistente e elaborado, e é rico em funcionalidades. E se você for desenvolvedor de JavaScript, C#/Visual Basic ou C++, já pode ser um desenvolvedor Windows que cria novos aplicativos da Windows Store para o Windows 8.

Perguntas frequentes

P. O Tempo de Execução do Windows é um substituto do CLR ou do Microsoft .NET Framework?

R. Não. O Tempo de Execução do Windows não substitui o .NET Framework ou quaisquer outras estruturas. Quando você cria um aplicativo da Windows Store em C#, seu código ainda pode ser executado usando o CLR. Fora isso, um subconjunto do .NET Framework (bem como Win32 e COM) está disponível para você usar para criar seus aplicativos da Windows Store.

P. Então, quando escrevo aplicativos da Windows Store em C++, uso C++/CLI?

R. Não. O código que usa o Tempo de Execução do Windows para aplicativos da Windows Store é escrito usando C++/CX. Embora ele possa parecer C++/CLI a princípio, é verdadeiramente nativo. Você não introduzirá coleta de lixo ou outros recursos C++/CLI em seu aplicativo nativo.

Recursos

Para obter mais informações, confira os seguintes recursos:

  • Exemplos de aplicativo da Windows Store: dev.windows.com
  • “Mantendo os aplicativos rápidos e fluidos com assincronia no Tempo de Execução do Windows”: bit.ly/GBLQLr
  • “Criando componentes do Tempo de Execução do Windows em C# e Visual Basic”: bit.ly/OWDe2A
  • “Criando componentes do Tempo de Execução do Windows em C++”: bit.ly/TbgWz7
  • Referência de API para aplicativos da Windows Store: bit.ly/zdFRK2

Jason Olson é gerente de programação sênior e trabalha na equipe do Tempo de Execução do Windows na Microsoft. Quando ele não está trabalhando no Windows, ele pode ser encontrado tocando piano na região de Seattle e passando tempo com sua esposa e dois filhos.

Agradecemos aos seguintes especialistas técnicos pela revisão deste artigo: Noel Cross, Anantha Kancherla, Ines Khelifi, John Lam, Martyn Lovell, Harry Pierson, Mahesh Prakriya e Steve Rowe