Criando componentes do Tempo de Execução do Windows em C# e Visual Basic

Com o .NET Framework 4.5, você pode usar código gerenciado para criar seus próprios tipos do Tempo de Execução do Windows, compactados em um componente do Tempo de Execução do Windows. Você pode usar o componente nos aplicativos Windows Store com C++, JavaScript, Visual Basic ou C#. Este artigo descreve as regras para criar um componente e descreve alguns aspectos do suporte do .NET Framework para o Tempo de Execução do Windows. Normalmente, esse suporte é projetado para ser transparente para o programador .NET Framework. No entanto, quando você cria um componente para usar com JavaScript ou C++, é necessário estar ciente das diferenças na maneira como essas linguagens oferecem suporte ao Tempo de Execução do Windows.

Dica

Se você estiver criando um componente para usar apenas em aplicativos Windows Store com Visual Basic ou C# e o componente não contiver controles do Windows Store, considere usar o modelo Biblioteca de Classes (aplicativos da Windows Store) em vez do modelo Componente do Tempo de Execução do Windows. Há menos restrições em uma biblioteca de classe simples.

Este artigo contém as seguintes seções:

  • Declarando tipos em componentes do Tempo de Execução do Windows

  • Depurando seu componente

  • Transmitindo tipos de Tempo de Execução do Windows para código gerenciado

  • Transmitindo tipos gerenciados para o Tempo de Execução do Windows

  • Transmitindo matrizes

  • Métodos sobrecarregados

  • Operações assíncronas

  • Lançando exceções

  • Declarando e disparando eventos

Declarando tipos em componentes do Tempo de Execução do Windows

Internamente, o Tempo de Execução do Windows no seu componente pode usar qualquer funcionalidade do .NET Framework que seja permitida em um aplicativo Windows Store. (Consulte Visão geral dos aplicativos .NET para Windows Store para obter mais informações.) Externamente, os membros de seus tipos podem expor somente tipos do Tempo de Execução do Windows para seus parâmetros e valores de retorno. A lista a seguir descreve as limitações nos tipos do .NET Framework que são expostos a partir dos componentes do Tempo de Execução do Windows.

  • Os campos, os parâmetros e valores de retorno de todos os tipos e membros públicos em seu componente devem ser tipos do Tempo de Execução do Windows.

    Essa limitação inclui os tipos do Tempo de Execução do Windows que você cria, bem como os tipos fornecidos pelo próprio Tempo de Execução do Windows. Ela também inclui vários tipos do .NET Framework. A inclusão desses tipos faz parte do suporte fornecido pelo .NET Framework para permitir o uso natural do Tempo de Execução do Windows em código gerenciado: seu código parece usar tipos familiares do .NET Framework em vez dos tipos básicos do Tempo de Execução do Windows. Por exemplo, você pode usar tipos primitivos do .NET Framework, como Int32 e Double, determinados tipos fundamentais, como DateTimeOffset e Uri, e alguns tipos de interface genéricos usados com frequência, como IEnumerable<T> (IEnumerable(Of T) em Visual Basic) e IDictionary<TKey,TValue>. (Observe que os argumentos de tipo desses tipos genéricos devem ser tipos do Tempo de Execução do Windows.) Isso é discutido nas seções Transmitindo tipos do Tempo de Execução do Windows para código gerenciado e Transmitindo tipos gerenciados para o Tempo de Execução do Windows, posteriormente neste artigo.

  • As classes e interfaces públicas podem conter métodos, propriedades e eventos. Você pode declarar representantes para seus eventos ou usar o representante EventHandler<T>. Uma classe ou interface pública não pode:

    • Ser genérica.

    • Implementar uma interface que não seja do Tempo de Execução do Windows. (No entanto, é possível criar suas próprias interfaces do Tempo de Execução do Windows e implementá-las.)

    • Fazer a derivação de tipos que não estejam no Tempo de Execução do Windows, como System.Exception e System.EventArgs.

  • Todos os tipos públicos devem ter um namespace raiz que corresponda ao nome do assembly, e o nome do assembly não deverá começar com “Windows”.

    Dica

    Por padrão, os projetos no Visual Studio têm os nomes de namespace correspondentes ao nome do assembly. Em Visual Basic, a instrução Namespace para esse namespace padrão não é mostrada em seu código.

  • Estruturas públicas não podem ter outros membros que não sejam campos públicos, e esses campos devem ser tipos de valor ou cadeias de caracteres.

  • As classes públicas devem ser sealed (NotInheritable em Visual Basic). Se seu modelo de programação exigir polimorfismo, você poderá criar uma interface pública e implementá-la nas classes que deverão ser polimórficas.

Depurando seu componente

Se seu aplicativo Windows Store e seu componente forem criados com código gerenciado, você poderá depurá-los simultaneamente.

Quando você estiver testando o seu componente como parte de um aplicativo Windows Store usando C++, poderá depurar o código gerenciado e nativo ao mesmo tempo. O padrão é somente código nativo.

Para depurar tanto o código nativo C++ quanto o código gerenciado

  1. Abra o menu de atalho de seu projeto do Visual C++ e escolha Propriedades.

  2. Nas páginas de propriedades, em Propriedades de Configuração, escolha Depuração.

  3. Escolha Tipo de Depurador e, na caixa de lista suspensa, altere Apenas Nativo para Misto (Gerenciado e Nativo). Clique em OK.

  4. Defina pontos de interrupção no código nativo e gerenciado.

Quando você estiver testando o seu componente como parte de um aplicativo Windows Store usando JavaScript, por padrão, a solução estará no modo de depuração JavaScript. No Visual Studio 2012 e no Visual Studio Express 2012 for Windows 8, você não pode depurar JavaScript e o código gerenciado ao mesmo tempo.

Para depurar o código gerenciado em vez de JavaScript

  1. Abra o menu de atalho de seu projeto em JavaScript e escolha Propriedades.

  2. Nas páginas de propriedades, em Propriedades de Configuração, escolha Depuração.

  3. Escolha Tipo de Depurador e, na caixa de lista suspensa, altere Apenas Script para Apenas Gerenciado. Clique em OK.

  4. Defina pontos de interrupção no código gerenciado e faça a depuração normalmente.

Transmitindo tipos do Tempo de Execução do Windows para código gerenciado

Como mencionado anteriormente na seção Declarando tipos em componentes do Tempo de Execução do Windows, determinados tipos do .NET Framework podem aparecer nas assinaturas de membros de classes públicas. Isso faz parte do suporte fornecido pelo .NET Framework para permitir o uso natural do Tempo de Execução do Windows no código gerenciado. Ele inclui tipos primitivos e algumas classes e interfaces. Quando o componente é usado a partir de JavaScript ou de código C++, é importante saber como seus tipos do .NET Framework aparecem para o chamador. Consulte Passo a passo: Criando um componente simples no C# ou Visual Basic e chamá-lo a partir do JavaScript para obter exemplos com JavaScript. Esta seção descreve tipos de uso geral.

No .NET Framework, os tipos primitivos como a estrutura Int32, têm muitas propriedades e métodos úteis, como o método TryParse. Por outro lado, as estruturas e tipos primitivos do Tempo de Execução do Windows têm apenas campos. Quando você transmitir esses tipos para código gerenciado, eles parecerão ser tipos do .NET Framework, e você poderá usar normalmente as propriedades e os métodos dos tipos do .NET Framework. A lista a seguir resume as substituições realizadas automaticamente no IDE:

  • Para tipos primitivos do Tempo de Execução do Windows Int32, Int64, Single, Double, Boolean, String (uma coleção de caracteres Unicode imutável), Enum, UInt32, UInt64 e Guid, use o tipo de mesmo nome no namespace System.

  • Para UInt8, use System.Byte.

  • Para Char16, use System.Char.

  • Para a interface IInspectable, use System.Object.

Se C# ou Visual Basic fornecer uma palavra-chave de linguagem para qualquer um desses tipos, você poderá usá-la.

Além de tipos primitivos, alguns tipos básicos do Tempo de Execução do Windows usados com frequência aparecem no código gerenciado como seus equivalentes do .NET Framework. Por exemplo, suponha que seu código JavaScript use a classe Windows.Foundation.Uri, e você deseje transmiti-la a um método C# ou Visual Basic. O tipo equivalente em código gerenciado é a classe do .NET Framework System.Uri, e esse é o tipo a ser usado para o parâmetro do método. Você pode determinar quando um tipo do Tempo de Execução do Windows aparece como um tipo do .NET Framework, porque o IntelliSense no Visual Studio oculta o tipo do Tempo de Execução do Windows quando você grava um código gerenciado e apresenta o tipo equivalente do .NET Framework. (Em geral, os dois tipos têm o mesmo nome. No entanto, observe que a estrutura Windows.Foundation.DateTime aparece no código gerenciado como System.DateTimeOffset e não como System.DateTime.)

Para alguns tipos de coleção usados com frequência, o mapeamento é feito entre as interfaces implementadas por um tipo do Tempo de Execução do Windows e as interfaces implementadas pelo tipo correspondente do .NET Framework. Como com os tipos mencionados acima, você declara tipos de parâmetro usando o tipo do .NET Framework. Isso oculta algumas diferenças entre os tipos e torna a gravação de código do .NET Framework mais natural. A tabela a seguir lista os tipos de interface genérica mais comuns, juntamente com outros mapeamentos comuns de classes e interfaces. Para obter uma lista completa de tipos do Tempo de Execução do Windows que o .NET Framework mapeia, consulte Mapeamentos do .NET Framework de tipos do Tempo de Execução do Windows.

Tempo de Execução do Windows

.NET Framework

IIterable<T>

IEnumerable<T>

IVector<T>

IList<T>

IVectorView<T>

IReadOnlyList<T>

IMap<K, V>

IDictionary<TKey, TValue>

IMapView<K, V>

IReadOnlyDictionary<TKey, TValue>

IKeyValuePair<K, V>

KeyValuePair<TKey, TValue>

IBindableIterable

IEnumerable

IBindableVector

IList

Windows.UI.Xaml.Data.INotifyPropertyChanged

System.ComponentModel.INotifyPropertyChanged

Windows.UI.Xaml.Data.PropertyChangedEventHandler

System.ComponentModel.PropertyChangedEventHandler

Windows.UI.Xaml.Data.PropertyChangedEventArgs

System.ComponentModel.PropertyChangedEventArgs

    

Quando um tipo implementa mais de uma interface, você pode usar qualquer uma das interfaces que ele implementa como um tipo de parâmetro ou um tipo de retorno de um membro. Por exemplo, você pode transmitir ou retornar um Dictionary<int, string> (Dictionary(Of Integer, String) em Visual Basic) como IDictionary<int, string>IReadOnlyDictionary<int, string> ou IEnumerable<System.Collections.Generic.KeyValuePair<TKey, TValue>>.

Importante

O JavaScript usa a interface que aparece primeiro na lista de interfaces implementadas por um tipo gerenciado. Por exemplo, se você retornarDictionary<int, string> para o código JavaScript, ele aparecerá como IDictionary<int, string>, não importando qual interface você especificar como o tipo de retorno. Isso significa que se a primeira interface não incluir um membro que apareça nas interfaces posteriores, esse membro não será visível para JavaScript.

No Tempo de Execução do Windows, IMap<K, V> e IMapView<K, V> são iterados usando IKeyValuePair. Quando você os transmite para código gerenciado, eles aparecem como IDictionary<TKey, TValue> e IReadOnlyDictionary<TKey, TValue>, então, naturalmente, você usa System.Collections.Generic.KeyValuePair<TKey, TValue> para enumerá-los.

A forma como as interfaces aparecem no código gerenciado afeta a forma como aparecem os tipos que implementam essas interfaces. Por exemplo, a classe PropertySet implementa IMap<K, V>, que aparece no código gerenciado como IDictionary<TKey, TValue>. PropertySet aparece como se tivesse implementado IDictionary<TKey, TValue> em vez de IMap<K, V>, de modo que no código gerenciado ele parece ter um método Add, que se comporta como o método Add nos dicionários do .NET Framework. Ela não parece ter um método Insert. Você pode ver esse exemplo no artigo Passo a passo: Criando um componente simples no C# ou Visual Basic e chamá-lo a partir do JavaScript.

Transmitindo tipos gerenciados para o Tempo de Execução do Windows

Conforme abordado na seção anterior, alguns tipos do Tempo de Execução do Windows podem aparecer como tipos do .NET Framework nas assinaturas dos membros do seu componente ou nas assinaturas dos membros do Tempo de Execução do Windows quando você os usa no IDE. Quando você transmite tipos do .NET Framework para esses membros ou os usa como valores de retorno dos membros do seu componente, eles aparecem para o código no outro lado como o tipo correspondente do Tempo de Execução do Windows. Para obter exemplos dos efeitos que isso pode ter quando seu componente é chamado a partir de JavaScript, consulte a seção “Retornando tipos gerenciados de seu componente” em Passo a passo: Criando um componente simples no C# ou Visual Basic e chamá-lo a partir do JavaScript.

Transmitindo matrizes

No Tempo de Execução do Windows, todos os parâmetros são para a entrada ou saída; não há parâmetros ref (ByRef em Visual Basic). O conteúdo das matrizes transmitidas para o seu componente do Tempo de Execução do Windows deve ser para a entrada ou para a saída. Isto é, as matrizes não devem ser tratadas como mutáveis. Se uma matriz for transmitida por valor (ByVal em Visual Basic), você deverá aplicar o atributo ReadOnlyArrayAttribute ou o atributo WriteOnlyArrayAttribute para estabelecer a intenção. Consulte Passando matrizes para o componente Tempo de Execução do Windows.

Métodos sobrecarregados

No Tempo de Execução do Windows, os métodos podem ser sobrecarregados. No entanto, se você declarar várias sobrecargas com o mesmo número de parâmetros, deverá aplicar o atributo Windows.Foundation.Metadata.DefaultOverloadAttribute a apenas uma dessas sobrecargas. Essa sobrecarga é única que você pode chamar de JavaScript. Por exemplo, no seguinte código, a sobrecarga que usa int (Integer em Visual Basic) é a sobrecarga padrão.

        public string OverloadExample(string s)
        {
            return s;
        }
        [Windows.Foundation.Metadata.DefaultOverload()] 
        public int OverloadExample(int x)
        {
            return x;
        } 
    Public Function OverloadExample(ByVal s As String) As String
        Return s
    End Function
    <Windows.Foundation.Metadata.DefaultOverload> _
    Public Function OverloadExample(ByVal x As Integer) As Integer
        Return x
    End Function

Aviso

A linguagem JavaScript permite que você transmita qualquer valor para OverloadExample e força o valor para o tipo exigido pelo parâmetro. Você pode chamar OverloadExample com “quarenta e dois”, “42 " ou 42.3, mas todos esses valores são transmitidos para a sobrecarga padrão. A sobrecarga padrão no exemplo anterior retorna 0, 42 e 42, respectivamente.

Não é possível aplicar o atributo DefaultOverloadAttribute a construtores. Todos os construtores em uma classe devem ter diferentes números de parâmetros.

Operações assíncronas

Para implementar um método assíncrono no seu componente, adicione “Async” ao final do nome do método e retorne uma das interfaces do Tempo de Execução do Windows que representam ações ou operações assíncronas: IAsyncActionIAsyncActionWithProgress<TProgress>IAsyncOperation<TResult> ou IAsyncOperationWithProgress<TResult, TProgress>.

Você pode usar tarefas do .NET Framework (a classe Task e a classe genérica Task<TResult>) para implementar o método assíncrono. É necessário retornar uma tarefa que represente uma operação contínua, como uma tarefa retornada de um método assíncrono gravado em C# ou Visual Basic, ou uma tarefa retornada do método Task.Run. Se você usar um construtor para criar a tarefa, deverá chamar o método Task.Start antes de retorná-lo.

Um método que usa await (Await em Visual Basic) requer a palavra-chave async (Async em Visual Basic). Se você expuser esse método de um componente do Tempo de Execução do Windows, aplique a palavra-chave async ao representante que você transmitir para o método Run.

Para as ações e operações assíncronas que não oferecem suporte a relatórios de cancelamento e de andamento, você pode usar o método de extensão WindowsRuntimeSystemExtensions.AsAsyncAction ou AsAsyncOperation<TResult> para envolver a tarefa na interface apropriada. Por exemplo, o código a seguir implementa um método assíncrono usando o método Task.Run para iniciar uma tarefa. O método de extensão AsAsyncOperation<TResult> retorna a tarefa como uma operação assíncrona do Tempo de Execução do Windows.

        public static IAsyncOperation<IList<string>> DownloadAsStringsAsync(string id)
        {
            return Task.Run<IList<string>>(async () =>
            {
                var data = await DownloadDataAsync(id);
                return ExtractStrings(data);
            }).AsAsyncOperation();
        }


    Public Shared Function DownloadAsStringsAsync(ByVal id As String) _
         As IAsyncOperation(Of IList(Of String))

        Return Task.Run(Of IList(Of String))(
            Async Function()
                Dim data = Await DownloadDataAsync(id)
                Return ExtractStrings(data)
            End Function).AsAsyncOperation()
    End Function


O seguinte código JavaScript mostra como o método pode ser chamado usando um objeto WinJS.Promise. A função transmitida para o e, em seguida, para o método é executada quando a chamada assíncrona é concluída. O parâmetro stringList contém a lista de cadeias de caracteres que é retornada pelo método DownloadAsStringAsync, e a função executa o processamento que for necessário.

function asyncExample(id) {

    var result = SampleComponent.Example.downloadAsStringAsync(id).then(
        function (stringList) {
            // Place code that uses the returned list of strings here.
        });
}

Para as ações e operações assíncronas que oferecem suporte a relatórios de cancelamento ou de andamento, use a classe AsyncInfo para gerar uma tarefa iniciada e atrelá-la ao recursos de relatório de cancelamento e andamento da tarefa com os recursos de relatório de cancelamento e andamento da interface apropriada do Tempo de Execução do Windows. Para obter um exemplo que oferece suporte a relatórios de cancelamento e andamento, consulte Passo a passo: Criando um componente simples no C# ou Visual Basic e chamá-lo a partir do JavaScript.

Observe que você pode usar os métodos da classe AsyncInfo mesmo se o método assíncrono não oferecer suporte a relatórios de cancelamento ou de andamento. Se você usar uma função lambda Visual Basic ou um método anônimo C#, não forneça parâmetros para o token e a interface IProgress<T>. Se você usar uma função lambda C#, forneça um parâmetro de token, mas ignore-o. O exemplo anterior, que usou o método AsAsyncOperation<TResult>, tem esta aparência quando você usa a sobrecarga do método AsyncInfo.Run<TResult>(Func<CancellationToken, Task<TResult>>):

        public static IAsyncOperation<IList<string>> DownloadAsStringsAsync(string id)
        {
            return AsyncInfo.Run<IList<string>>(async (token) =>
            {
                var data = await DownloadDataAsync(id);
                return ExtractStrings(data);
            });
        }
    Public Function OverloadExample(ByVal s As String) As String
        Return s
    End Function
    <Windows.Foundation.Metadata.DefaultOverload> _
    Public Function OverloadExample(ByVal x As Integer) As Integer
        Return x
    End Function

Se você criar um método assíncrono que ofereça suporte opcionalmente a relatórios de cancelamento ou de andamento, considere adicionar as sobrecargas que não tenham parâmetros para um token de cancelamento ou a interface IProgress<T>.

Lançando exceções

Você pode lançar qualquer tipo de exceção que está incluído no Aplicativos .NET para Windows Store - APIs com suporte. Não é possível declarar seus próprios tipos de exceção pública em um componente do Tempo de Execução do Windows, mas é possível declarar e lançar tipos não públicos.

Se o componente não lidar com a exceção, uma exceção correspondente será gerada no código que chamou o componente. A maneira como a exceção aparece para o chamador depende da forma como a linguagem de chamada oferece suporte ao Tempo de Execução do Windows.

  • No JavaScript, a exceção aparece como um objeto no qual a mensagem de exceção é substituída por um rastreamento de pilha. Ao depurar seu aplicativo no Visual Studio, você verá o texto da mensagem original exibido na caixa de diálogo de exceção do depurador, identificado como "Informações de WinRT". Não é possível acessar o texto da mensagem original do código JavaScript.

    Dica

    No momento, o rastreamento de pilha contém o tipo de exceção gerenciado, mas não é recomendável analisar o rastreamento para identificar o tipo de exceção. Em vez disso, use um valor HRESULT conforme descrito posteriormente nesta seção.

  • Em C++, a exceção é exibida como uma exceção da plataforma. Caso a propriedade HResult da exceção gerenciada possa ser mapeada para o HRESULT de uma exceção da plataforma específica, a exceção específica é utilizada. Caso contrário, uma exceção Platform::COMException é lançada. O texto da mensagem da exceção gerenciada não está disponível para o código C++. Se uma exceção de plataforma específica tiver sido lançada, o texto da mensagem padrão para o tipo de exibição será exibido. Caso contrário, nenhum texto de mensagem aparecerá. Consulte Exceções (C + + / CX).

  • No C# ou no Visual Basic, uma exceção é uma exceção gerenciada normal.

Ao lançar uma exceção de seu componente, você poderá facilitar a manipulação da exceção para um chamador JavaScript ou C++, lançando um tipo de exceção não público cujo valor de propriedade HResult é específico para o seu componente. O HRESULT está disponível para um chamador JavaScript, através da propriedade number do objeto de exceção, e para um chamador C++, através da propriedade COMException::HResult.

Dica

Use um valor negativo para o seu HRESULT. Um valor positivo é interpretado como êxito, e nenhuma exceção é lançada no chamador JavaScript ou C++.

Declarando e disparando eventos

Quando você declara um tipo para armazenar os dados para o evento, faça a derivação de Object em vez de EventArgs, porque EventArgs não é um tipo do Tempo de Execução do Windows. Use EventHandler<TEventArgs> como o tipo do evento e use o tipo de argumento do evento como o argumento de tipo genérico. Gere o evento exatamente como você faria em um aplicativo do .NET Framework.

Quando o componente do Tempo de Execução do Windows for usado a partir de JavaScript ou C++, o evento seguirá o padrão de evento do Tempo de Execução do Windows esperado por essas linguagens. Quando você usa o componente de C# ou de Visual Basic, o evento aparece como um evento comum do .NET Framework. Um exemplo é fornecido em Passo a passo: Criando um componente simples no C# ou Visual Basic e chamá-lo a partir do JavaScript.

Se você implementar acessadores de evento personalizados (declarar um evento com a palavra-chave Custom, em Visual Basic), deverá seguir o padrão de evento do Tempo de Execução do Windows em sua implementação. Consulte Eventos personalizados e acessadores de evento nos componentes do Tempo de Execução do Windows. Quando você processa um evento de código C# ou Visual Basic, ele ainda parece ser um evento comum do .NET Framework.

Consulte também

Conceitos

Visão geral dos aplicativos .NET para Windows Store

Aplicativos .NET para Windows Store - APIs com suporte

Passo a passo: Criando um componente simples no C# ou Visual Basic e chamá-lo a partir do JavaScript

Criando componentes do Tempo de Execução do Windows

Eventos personalizados e acessadores de evento nos componentes do Tempo de Execução do Windows

Passando matrizes para o componente Tempo de Execução do Windows

Mapeamentos do .NET Framework de tipos do Tempo de Execução do Windows

Diagnosticando condições de erro do componente Tempo de Execução do Windows