Passo a passo para criar um componente do Windows Runtime em C++/CX e chamá-lo do JavaScript ou do C#

Observação

Este tópico existe para ajudar você a manter seu aplicativo em C++/CX. Entretanto, recomendamos usar C++/WinRT para novos aplicativos. C++/WinRT é uma projeção de linguagem C++17 completamente moderna e padrão para APIs do WinRT (Windows Runtime), implementada como uma biblioteca com base em cabeçalho e arquivo, projetada para fornecer acesso de primeira classe à API moderna do Windows. Para aprender a criar um componente do Windows Runtime usando C++/WinRT, confira Componentes do Windows Runtime com C++/WinRT.

Este passo a passo mostra como criar uma DLL básica do componente do Windows Runtime que pode ser chamada do JavaScript, do C# ou do Visual Basic. Antes de começar este procedimento passo a passo, assegure-se de que você compreendeu conceitos como a Abstract Binary Interface (ABI), as classes ref e as extensões de componente do Visual C++ que facilitam o trabalho com classes ref. Para obter mais informações, consulte Componentes do Tempo de Execução do Windows com C++/CX e Referência de Linguagem do Visual C++ (C++/CX).

Criando a DLL do componente C++

Neste exemplo, criamos o projeto de componente primeiro, mas você pode criar o projeto JavaScript primeiro. A ordem não importa.

Observe que a classe principal do componente contém exemplos de definições de propriedade e método e uma declaração de evento. Eles são fornecidos apenas para mostrar como isso é feito. Eles não são obrigatórios e, neste exemplo, substituiremos todo o código gerado por nosso próprio código.

Para criar o projeto de componente C++

  1. Na barra de menus do Visual Studio, escolha Arquivo, Novo, Projeto.

  2. Na caixa de diálogo Novo Projeto, no painel esquerdo, expanda Visual C++ e selecione o nó para aplicativos Universais do Windows.

  3. No painel central, selecione Componente do Tempo de Execução do Windows e nomeie o projeto WinRT_CPP.

  4. Clique no botão OK.

Para adicionar uma classe ativável ao componente

Uma classe ativável é aquela que o código do cliente pode criar usando uma nova expressão (New no Visual Basic ou ref new no C++). Em seu componente, você o declara como public ref class sealed. Na verdade, os arquivos Class1.h e .cpp já têm uma classe ref. Você pode alterar o nome, mas neste exemplo usaremos o nome padrão—Class1. Você pode definir classes ref adicionais ou classes regulares em seu componente, se necessário. Para obter mais informações sobre classes ref, consulte Sistema de Tipos (C++/CX).

Adicione estas diretivas #include a Class1.h:

#include <collection.h>
#include <ppl.h>
#include <amp.h>
#include <amp_math.h>

collection.h é o arquivo de cabeçalho para classes concretas C++, como a classe Platform::Collections::Vector e a classe Platform::Collections::Map, que implementam interfaces neutras em termos de linguagem definidas pelo Tempo de Execução do Windows. Os cabeçalhos amp são usados para executar cálculos na GPU. Eles não têm equivalentes do Tempo de Execução do Windows, e isso é bom porque eles são privados. Em geral, por motivos de desempenho, você deve usar o código ISO C++ e as bibliotecas padrão internamente no componente; é apenas a interface do Tempo de Execução do Windows que deve ser expressa em tipos do Tempo de Execução do Windows.

Para adicionar um delegado no escopo do namespace

Um delegado é um constructo que define os parâmetros e o tipo de retorno para métodos. Um evento é uma instância de um tipo de delegado específico, e qualquer método de manipulador de eventos que assina o evento deve ter a assinatura especificada no delegado. O código a seguir define um tipo delegado que usa um int e retorna void. Em seguida, o código declara um evento público desse tipo; Isso permite que o código do cliente forneça métodos que são invocados quando o evento é disparado.

Adicione a seguinte declaração delegada no escopo do namespace em Class1.h, logo antes da declaração Class1.

public delegate void PrimeFoundHandler(int result);

Se o código não estiver alinhado corretamente quando você colá-lo no Visual Studio, basta pressionar Ctrl+K+D para corrigir o recuo de todo o arquivo.

Para adicionar os membros públicos

A classe expõe três métodos públicos e um evento público. O primeiro método é síncrono porque sempre é executado muito rápido. Como os outros dois métodos podem levar algum tempo, eles são assíncronos para que não bloqueiem o thread da interface do usuário. Esses métodos retornam IAsyncOperationWithProgress e IAsyncActionWithProgress. O primeiro define um método assíncrono que retorna um resultado e o último define um método assíncrono que retorna void. Essas interfaces também permitem que o código do cliente receba atualizações sobre o andamento da operação.

public:

        // Synchronous method.
        Windows::Foundation::Collections::IVector<double>^  ComputeResult(double input);

        // Asynchronous methods
        Windows::Foundation::IAsyncOperationWithProgress<Windows::Foundation::Collections::IVector<int>^, double>^
            GetPrimesOrdered(int first, int last);
        Windows::Foundation::IAsyncActionWithProgress<double>^ GetPrimesUnordered(int first, int last);

        // Event whose type is a delegate "class"
        event PrimeFoundHandler^ primeFoundEvent;

Para adicionar os membros privados

A classe contém três membros privados: dois métodos auxiliares para os cálculos numéricos e um objeto CoreDispatcher que é usado para empacotar as invocações de evento de threads de trabalho de volta para o thread da interface do usuário.

private:
        bool is_prime(int n);
        Windows::UI::Core::CoreDispatcher^ m_dispatcher;

Para adicionar as diretivas header e namespace

  1. Em Class1.cpp, adicione estas #include diretivas:
#include <ppltasks.h>
#include <concurrent_vector.h>
  1. Agora adicione estas instruções using para extrair os namespaces necessários:
using namespace concurrency;
using namespace Platform::Collections;
using namespace Windows::Foundation::Collections;
using namespace Windows::Foundation;
using namespace Windows::UI::Core;

Para adicionar a implementação de ComputeResult

Em Class1.cpp, adicione a implementação do método a seguir. Esse método é executado de forma síncrona no thread de chamada, mas é muito rápido porque usa C++ AMP para paralelizar a computação na GPU. Para mais informações, confira Visão geral de C++ AMP. Os resultados são acrescentados a um tipo concreto Platform::Collections::Vector<T> , que é convertido implicitamente em um Windows::Foundation::Collections::IVector<T> quando é retornado.

//Public API
IVector<double>^ Class1::ComputeResult(double input)
{
    // Implement your function in ISO C++ or
    // call into your C++ lib or DLL here. This example uses AMP.
    float numbers[] = { 1.0, 10.0, 60.0, 100.0, 600.0, 10000.0 };
    array_view<float, 1> logs(6, numbers);

    // See http://msdn.microsoft.com/library/hh305254.aspx
    parallel_for_each(
        logs.extent,
        [=] (index<1> idx) restrict(amp)
    {
        logs[idx] = concurrency::fast_math::log10(logs[idx]);
    }
    );

    // Return a Windows Runtime-compatible type across the ABI
    auto res = ref new Vector<double>();
    int len = safe_cast<int>(logs.extent.size());
    for(int i = 0; i < len; i++)
    {      
        res->Append(logs[i]);
    }

    // res is implicitly cast to IVector<double>
    return res;
}

Para adicionar a implementação de GetPrimesOrdered e seu método auxiliar

Em Class1.cpp, adicione as implementações para GetPrimesOrdered e o método auxiliar is_prime. GetPrimesOrdered usa uma classe concurrent_vector e um loop de função parallel_for para dividir o trabalho e usar o máximo de recursos do computador no qual o programa está sendo executado para produzir resultados. Depois que os resultados são calculados, armazenados e classificados, eles são adicionados a um Platform::Collections::Vector<T> e retornados como Windows::Foundation::Collections::IVector<T> ao código do cliente.

Observe o código do relator de progresso, que permite que o cliente conecte uma barra de progresso ou outra interface do usuário para mostrar ao usuário quanto tempo a operação levará. O relatório de progresso tem um custo. Um evento deve ser disparado no lado do componente e manipulado no thread da interface do usuário, e o valor de progresso deve ser armazenado em cada iteração. Uma maneira de minimizar o custo é limitar a frequência com que um evento de progresso é disparado. Se o custo ainda for proibitivo ou se você não puder estimar a duração da operação, considere usar um anel de progresso, que mostra que uma operação está em andamento, mas não mostra o tempo restante até a conclusão.

// Determines whether the input value is prime.
bool Class1::is_prime(int n)
{
    if (n < 2)
        return false;
    for (int i = 2; i < n; ++i)
    {
        if ((n % i) == 0)
            return false;
    }
    return true;
}

// This method computes all primes, orders them, then returns the ordered results.
IAsyncOperationWithProgress<IVector<int>^, double>^ Class1::GetPrimesOrdered(int first, int last)
{
    return create_async([this, first, last]
    (progress_reporter<double> reporter) -> IVector<int>^ {
        // Ensure that the input values are in range.
        if (first < 0 || last < 0) {
            throw ref new InvalidArgumentException();
        }
        // Perform the computation in parallel.
        concurrent_vector<int> primes;
        long operation = 0;
        long range = last - first + 1;
        double lastPercent = 0.0;

        parallel_for(first, last + 1, [this, &primes, &operation,
            range, &lastPercent, reporter](int n) {

                // Increment and store the number of times the parallel
                // loop has been called on all threads combined. There
                // is a performance cost to maintaining a count, and
                // passing the delegate back to the UI thread, but it's
                // necessary if we want to display a determinate progress
                // bar that goes from 0 to 100%. We can avoid the cost by
                // setting the ProgressBar IsDeterminate property to false
                // or by using a ProgressRing.
                if(InterlockedIncrement(&operation) % 100 == 0)
                {
                    reporter.report(100.0 * operation / range);
                }

                // If the value is prime, add it to the local vector.
                if (is_prime(n)) {
                    primes.push_back(n);
                }
        });

        // Sort the results.
        std::sort(begin(primes), end(primes), std::less<int>());		
        reporter.report(100.0);

        // Copy the results to a Vector object, which is
        // implicitly converted to the IVector return type. IVector
        // makes collections of data available to other
        // Windows Runtime components.
        return ref new Vector<int>(primes.begin(), primes.end());
    });
}

Para adicionar a implementação de GetPrimesUnordered

A última etapa para criar o componente C++ é adicionar a implementação para o GetPrimesUnordered no Class1.cpp. Esse método retorna cada resultado conforme ele é encontrado, sem esperar até que todos os resultados sejam encontrados. Cada resultado é retornado no manipulador de eventos e exibido na interface do usuário em tempo real. Novamente, observe que um relator de progresso é usado. Esse método também usa o método auxiliar is_prime.

// This method returns no value. Instead, it fires an event each time a
// prime is found, and passes the prime through the event.
// It also passes progress info.
IAsyncActionWithProgress<double>^ Class1::GetPrimesUnordered(int first, int last)
{

    auto window = Windows::UI::Core::CoreWindow::GetForCurrentThread();
    m_dispatcher = window->Dispatcher;


    return create_async([this, first, last](progress_reporter<double> reporter) {

        // Ensure that the input values are in range.
        if (first < 0 || last < 0) {
            throw ref new InvalidArgumentException();
        }

        // In this particular example, we don't actually use this to store
        // results since we pass results one at a time directly back to
        // UI as they are found. However, we have to provide this variable
        // as a parameter to parallel_for.
        concurrent_vector<int> primes;
        long operation = 0;
        long range = last - first + 1;
        double lastPercent = 0.0;

        // Perform the computation in parallel.
        parallel_for(first, last + 1,
            [this, &primes, &operation, range, &lastPercent, reporter](int n)
        {
            // Store the number of times the parallel loop has been called  
            // on all threads combined. See comment in previous method.
            if(InterlockedIncrement(&operation) % 100 == 0)
            {
                reporter.report(100.0 * operation / range);
            }

            // If the value is prime, pass it immediately to the UI thread.
            if (is_prime(n))
            {                
                // Since this code is probably running on a worker
                // thread, and we are passing the data back to the
                // UI thread, we have to use a CoreDispatcher object.
                m_dispatcher->RunAsync( CoreDispatcherPriority::Normal,
                    ref new DispatchedHandler([this, n, operation, range]()
                {
                    this->primeFoundEvent(n);

                }, Platform::CallbackContext::Any));

            }
        });
        reporter.report(100.0);
    });
}

Criando um aplicativo cliente JavaScript (Visual Studio 2017)

Se você quiser criar um cliente C#, ignore esta seção.

Observação

Não há suporte para projetos da Plataforma Universal do Windows (UWP) em JavaScript no Visual Studio 2019. Consulte JavaScript e TypeScript no Visual Studio 2019. Para acompanhar esta seção, recomendamos que você use o Visual Studio 2017. Consulte JavaScript no Visual Studio 2017.

Para criar um projeto JavaScript

  1. No Gerenciador de Soluções (no Visual Studio 2017; consulte a Observação acima), abra o menu de atalho para o nó Solução e escolha Adicionar, Novo Projeto.

  2. Expanda JavaScript (pode estar aninhado em Outros idiomas) e escolha Aplicativo em branco (Universal Windows).

  3. Aceite o nome padrão — App1 — escolhendo o botão OK .

  4. Abra o menu de atalho para o nó do projeto App1 e escolha Definir como projeto de inicialização.

  5. Adicione uma referência de projeto a WinRT_CPP:

  6. Abra o menu de atalho para o nó Referências e escolha Adicionar referência.

  7. No painel esquerdo da caixa de diálogo Gerenciador de Referências, selecione Projetos e, em seguida, selecione Solução.

  8. No painel central, selecione WinRT_CPP e escolha o botão OK

Para adicionar o HTML que invoca os manipuladores de eventos JavaScript

Cole este HTML no <nó do corpo> da página default.html:

<div id="LogButtonDiv">
     <button id="logButton">Logarithms using AMP</button>
 </div>
 <div id="LogResultDiv">
     <p id="logResult"></p>
 </div>
 <div id="OrderedPrimeButtonDiv">
     <button id="orderedPrimeButton">Primes using parallel_for with sort</button>
 </div>
 <div id="OrderedPrimeProgress">
     <progress id="OrderedPrimesProgressBar" value="0" max="100"></progress>
 </div>
 <div id="OrderedPrimeResultDiv">
     <p id="orderedPrimes">
         Primes found (ordered):
     </p>
 </div>
 <div id="UnorderedPrimeButtonDiv">
     <button id="ButtonUnordered">Primes returned as they are produced.</button>
 </div>
 <div id="UnorderedPrimeDiv">
     <progress id="UnorderedPrimesProgressBar" value="0" max="100"></progress>
 </div>
 <div id="UnorderedPrime">
     <p id="unorderedPrimes">
         Primes found (unordered):
     </p>
 </div>
 <div id="ClearDiv">
     <button id="Button_Clear">Clear</button>
 </div>

Para adicionar estilos

Em default.css, remova o estilo de corpo e adicione estes estilos:

#LogButtonDiv {
border: orange solid 1px;
-ms-grid-row: 1; /* default is 1 */
-ms-grid-column: 1; /* default is 1 */
}
#LogResultDiv {
background: black;
border: red solid 1px;
-ms-grid-row: 1;
-ms-grid-column: 2;
}
#UnorderedPrimeButtonDiv, #OrderedPrimeButtonDiv {
border: orange solid 1px;
-ms-grid-row: 2;   
-ms-grid-column:1;
}
#UnorderedPrimeProgress, #OrderedPrimeProgress {
border: red solid 1px;
-ms-grid-column-span: 2;
height: 40px;
}
#UnorderedPrimeResult, #OrderedPrimeResult {
border: red solid 1px;
font-size:smaller;
-ms-grid-row: 2;
-ms-grid-column: 3;
-ms-overflow-style:scrollbar;
}

Para adicionar os manipuladores de eventos JavaScript que chamam a DLL do componente

Adicione as seguintes funções no final do arquivo default.js. Essas funções são chamadas quando os botões na página principal são escolhidos. Observe como o JavaScript ativa a classe C++ e, em seguida, chama seus métodos e usa os valores retornados para preencher os rótulos HTML.

var nativeObject = new WinRT_CPP.Class1();

function LogButton_Click() {

    var val = nativeObject.computeResult(0);
    var result = "";

    for (i = 0; i < val.length; i++) {
        result += val[i] + "<br/>";
    }

    document.getElementById('logResult').innerHTML = result;
}

function ButtonOrdered_Click() {
    document.getElementById('orderedPrimes').innerHTML = "Primes found (ordered): ";

    nativeObject.getPrimesOrdered(2, 10000).then(
        function (v) {
            for (var i = 0; i < v.length; i++)
                document.getElementById('orderedPrimes').innerHTML += v[i] + " ";
        },
        function (error) {
            document.getElementById('orderedPrimes').innerHTML += " " + error.description;
        },
        function (p) {
            var progressBar = document.getElementById("OrderedPrimesProgressBar");
            progressBar.value = p;
        });
}

function ButtonUnordered_Click() {
    document.getElementById('unorderedPrimes').innerHTML = "Primes found (unordered): ";
    nativeObject.onprimefoundevent = handler_unordered;

    nativeObject.getPrimesUnordered(2, 10000).then(
        function () { },
        function (error) {
            document.getElementById("unorderedPrimes").innerHTML += " " + error.description;
        },
        function (p) {
            var progressBar = document.getElementById("UnorderedPrimesProgressBar");
            progressBar.value = p;
        });
}

var handler_unordered = function (n) {
    document.getElementById('unorderedPrimes').innerHTML += n.target.toString() + " ";
};

function ButtonClear_Click() {

    document.getElementById('logResult').innerHTML = "";
    document.getElementById("unorderedPrimes").innerHTML = "";
    document.getElementById('orderedPrimes').innerHTML = "";
    document.getElementById("UnorderedPrimesProgressBar").value = 0;
    document.getElementById("OrderedPrimesProgressBar").value = 0;
}

Adicione código para adicionar os ouvintes de eventos substituindo a chamada existente para WinJS.UI.processAll em app.onactivated no default.js pelo código a seguir que implementa o registro de eventos em um bloco then. Para obter uma explicação detalhada disso, consulte Criar um aplicativo "Hello, World" (JS).

args.setPromise(WinJS.UI.processAll().then( function completed() {
    var logButton = document.getElementById("logButton");
    logButton.addEventListener("click", LogButton_Click, false);
    var orderedPrimeButton = document.getElementById("orderedPrimeButton");
    orderedPrimeButton.addEventListener("click", ButtonOrdered_Click, false);
    var buttonUnordered = document.getElementById("ButtonUnordered");
    buttonUnordered.addEventListener("click", ButtonUnordered_Click, false);
    var buttonClear = document.getElementById("Button_Clear");
    buttonClear.addEventListener("click", ButtonClear_Click, false);
}));

Pressione F5 para executar o aplicativo.

Criando um aplicativo cliente C#

Para criar um projeto C#

  1. No Gerenciador de Soluções, abra o menu de atalho para o nó Solução e escolha Adicionar, Novo Projeto.

  2. Expanda Visual C# (pode estar aninhado em Outras Linguagens), selecione Windows e, em seguida, Universal no painel esquerdo e, em seguida, selecione Aplicativo em Branco no painel do meio.

  3. Nomeie este aplicativo CS_Client e escolha o botão OK .

  4. Abra o menu de atalho para o nó do projeto CS_Client e escolha Definir como projeto de inicialização.

  5. Adicione uma referência de projeto a WinRT_CPP:

    • Abra o menu de atalho para o nó Referências e escolha Adicionar referência.

    • No painel esquerdo da caixa de diálogo Gerenciador de Referências, selecione Projetos e, em seguida, selecione Solução.

    • No painel central, selecione WinRT_CPP e escolha o botão OK .

Para adicionar o XAML que define a interface do usuário

Copie o código a seguir para o elemento Grid em MainPage.xaml.

<ScrollViewer>
            <StackPanel Width="1400">

                <Button x:Name="Button1" Width="340" Height="50"  Margin="0,20,20,20" Content="Synchronous Logarithm Calculation" FontSize="16" Click="Button1_Click_1"/>
                <TextBlock x:Name="Result1" Height="100" FontSize="14"></TextBlock>
            <Button x:Name="PrimesOrderedButton" Content="Prime Numbers Ordered" FontSize="16" Width="340" Height="50" Margin="0,20,20,20" Click="PrimesOrderedButton_Click_1"></Button>
            <ProgressBar x:Name="PrimesOrderedProgress" IsIndeterminate="false" Height="40"></ProgressBar>
                <TextBlock x:Name="PrimesOrderedResult" MinHeight="100" FontSize="10" TextWrapping="Wrap"></TextBlock>
            <Button x:Name="PrimesUnOrderedButton" Width="340" Height="50" Margin="0,20,20,20" Click="PrimesUnOrderedButton_Click_1" Content="Prime Numbers Unordered" FontSize="16"></Button>
            <ProgressBar x:Name="PrimesUnOrderedProgress" IsIndeterminate="false" Height="40" ></ProgressBar>
            <TextBlock x:Name="PrimesUnOrderedResult" MinHeight="100" FontSize="10" TextWrapping="Wrap"></TextBlock>

            <Button x:Name="Clear_Button" Content="Clear" HorizontalAlignment="Left" Margin="0,20,20,20" VerticalAlignment="Top" Width="341" Click="Clear_Button_Click" FontSize="16"/>
        </StackPanel>
</ScrollViewer>

Para adicionar os manipuladores de eventos para os botões

No Gerenciador de Soluções, abra MainPage.xaml.cs. (O arquivo pode estar aninhado em MainPage.xaml.) Adicione uma diretiva using para System.Text e, em seguida, adicione o manipulador de eventos para o cálculo Logarithm na classe MainPage.

private void Button1_Click_1(object sender, RoutedEventArgs e)
{
    // Create the object
    var nativeObject = new WinRT_CPP.Class1();

    // Call the synchronous method. val is an IList that
    // contains the results.
    var val = nativeObject.ComputeResult(0);
    StringBuilder result = new StringBuilder();
    foreach (var v in val)
    {
        result.Append(v).Append(System.Environment.NewLine);
    }
    this.Result1.Text = result.ToString();
}

Adicione o manipulador de eventos para o resultado ordenado:

async private void PrimesOrderedButton_Click_1(object sender, RoutedEventArgs e)
{
    var nativeObject = new WinRT_CPP.Class1();

    StringBuilder sb = new StringBuilder();
    sb.Append("Primes found (ordered): ");

    PrimesOrderedResult.Text = sb.ToString();

    // Call the asynchronous method
    var asyncOp = nativeObject.GetPrimesOrdered(2, 100000);

    // Before awaiting, provide a lambda or named method
    // to handle the Progress event that is fired at regular
    // intervals by the asyncOp object. This handler updates
    // the progress bar in the UI.
    asyncOp.Progress = (asyncInfo, progress) =>
        {
            PrimesOrderedProgress.Value = progress;
        };

    // Wait for the operation to complete
    var asyncResult = await asyncOp;

    // Convert the results to strings
    foreach (var result in asyncResult)
    {
        sb.Append(result).Append(" ");
    }

    // Display the results
    PrimesOrderedResult.Text = sb.ToString();
}

Adicione o manipulador de eventos para o resultado não ordenado e para o botão que limpa os resultados para que você possa executar o código novamente.

private void PrimesUnOrderedButton_Click_1(object sender, RoutedEventArgs e)
{
    var nativeObject = new WinRT_CPP.Class1();

    StringBuilder sb = new StringBuilder();
    sb.Append("Primes found (unordered): ");
    PrimesUnOrderedResult.Text = sb.ToString();

    // primeFoundEvent is a user-defined event in nativeObject
    // It passes the results back to this thread as they are produced
    // and the event handler that we define here immediately displays them.
    nativeObject.primeFoundEvent += (n) =>
    {
        sb.Append(n.ToString()).Append(" ");
        PrimesUnOrderedResult.Text = sb.ToString();
    };

    // Call the async method.
    var asyncResult = nativeObject.GetPrimesUnordered(2, 100000);

    // Provide a handler for the Progress event that the asyncResult
    // object fires at regular intervals. This handler updates the progress bar.
    asyncResult.Progress += (asyncInfo, progress) =>
        {
            PrimesUnOrderedProgress.Value = progress;
        };
}

private void Clear_Button_Click(object sender, RoutedEventArgs e)
{
    PrimesOrderedProgress.Value = 0;
    PrimesUnOrderedProgress.Value = 0;
    PrimesUnOrderedResult.Text = "";
    PrimesOrderedResult.Text = "";
    Result1.Text = "";
}

Executar o aplicativo

Selecione o projeto C# ou o projeto JavaScript como o projeto de inicialização abrindo o menu de atalho para o nó do projeto no Gerenciador de Soluções e escolhendo Definir como Projeto de Inicialização. Em seguida, pressione F5 para executar com depuração ou Ctrl+F5 para executar sem depuração.

Inspecionando seu componente no Pesquisador de Objetos (opcional)

No Pesquisador de Objetos, você pode inspecionar todos os tipos do Tempo de Execução do Windows definidos em arquivos .winmd. Isso inclui os tipos no namespace Platform e no namespace padrão. No entanto, como os tipos no namespace Platform::Collections são definidos no arquivo de cabeçalho collections.h, não em um arquivo winmd, eles não aparecem no Pesquisador de Objetos.

Para inspecionar um componente

  1. Na barra de menus, escolha Exibir, Pesquisador de Objetos (Ctrl+Alt+J).

  2. No painel esquerdo do Pesquisador de Objetos, expanda o nó WinRT_CPP para mostrar os tipos e métodos definidos no componente.

Dicas de depuração

Para uma melhor experiência de depuração, baixe os símbolos de depuração dos servidores de símbolos públicos da Microsoft:

Para baixar símbolos de depuração

  1. Na barra de menus, escolha Ferramentas, Opções.

  2. Na caixa de diálogo Opções, expanda Depuração e selecione Símbolos.

  3. Selecione Servidores de Símbolos da Microsoft e escolha o botão OK .

Pode levar algum tempo para baixar os símbolos pela primeira vez. Para um desempenho mais rápido, na próxima vez que você pressionar F5, especifique um diretório local no qual armazenar os símbolos em cache.

Ao depurar uma solução JavaScript que tem uma DLL de componente, você pode definir o depurador para habilitar a depuração do script ou a depuração do código nativo no componente, mas não os dois ao mesmo tempo. Para alterar a configuração, abra o menu de atalho para o nó do projeto JavaScript no Gerenciador de Soluções e escolha Propriedades, Depuração, Tipo de Depurador.

Certifique-se de selecionar os recursos apropriados no designer de pacotes. Você pode abrir o designer de pacotes abrindo o arquivo Package.appxmanifest. Por exemplo, se você estiver tentando acessar programaticamente arquivos na pasta Imagens, marque a caixa de seleção Biblioteca de Imagens no painel Recursos do designer de pacotes.

Se o código JavaScript não reconhecer as propriedades ou métodos públicos no componente, verifique se você está usando maiúsculas e minúsculas no JavaScript Por exemplo, o método C++ deve ser referenciado ComputeResult como computeResult em JavaScript.

Se você remover um projeto de componente do Tempo de Execução do Windows C++ de uma solução, também deverá remover manualmente a referência do projeto do JavaScript. Se isso não for feito, as operações subsequentes de depuração ou build serão executadas. Se necessário, você pode adicionar uma referência de assembly à DLL.