Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Use a API de transferência em segundo plano para copiar arquivos de forma confiável pela rede. A API de transferência em segundo plano fornece recursos avançados de upload e download que são executados em segundo plano durante a suspensão do aplicativo e persistem após o encerramento do aplicativo. A API monitoriza o estado da rede e suspende e retoma automaticamente as transferências quando a conectividade é perdida, e as transferências também reconhecem o Data Sense e o Battery Sense, o que significa que a atividade de transferência é ajustada com base na sua conectividade atual e no estado da bateria do dispositivo. A API é ideal para carregar e baixar arquivos grandes usando HTTP(S). FTP também é suportado, mas apenas para downloads.
A Transferência em Segundo Plano é executada separadamente do aplicativo de chamada e é projetada principalmente para operações de transferência de longo prazo para recursos como vídeo, música e imagens grandes. Para esses cenários, usar a Transferência em Segundo Plano é essencial porque os downloads continuam a progredir mesmo quando o aplicativo está suspenso.
Se estiveres a descarregar pequenos recursos que provavelmente serão concluídos rapidamente, deves usar as APIs de HttpClient em vez de Transferência em Segundo Plano.
Usando Windows.Networking.BackgroundTransfer
Como funciona o recurso Transferência em Segundo Plano?
Quando um aplicativo usa transferência em segundo plano para iniciar uma transferência, a solicitação é configurada e inicializada usando objetos de classe BackgroundDownloader ou BackgroundUploader. Cada operação de transferência é tratada individualmente pelo sistema e separada do aplicativo de chamada. As informações de progresso estão disponíveis se você quiser dar status ao usuário na interface do usuário do seu aplicativo, e seu aplicativo pode pausar, retomar, cancelar ou até mesmo ler os dados enquanto a transferência está ocorrendo. A forma como as transferências são tratadas pelo sistema promove o uso inteligente de energia e evita problemas que podem surgir quando um aplicativo conectado encontra eventos como suspensão do aplicativo, encerramento ou mudanças repentinas de status da rede.
Observação
Devido a restrições de recursos por aplicativo, um aplicativo não deve ter mais de 200 transferências (DownloadOperations + UploadOperations) em um determinado momento. Exceder esse limite pode deixar a fila de transferência do aplicativo em um estado irrecuperável.
Quando um aplicativo é iniciado, ele deve chamar AttachAsync em todos os objetos DownloadOperation existentes e UploadOperation existentes. Não fazer isso causará o vazamento de transferências já concluídas e, eventualmente, tornará seu uso do recurso de transferência em segundo plano inútil.
Executando solicitações de arquivos autenticados com transferência em segundo plano
A Transferência em Segundo Plano fornece métodos que suportam credenciais básicas de servidor e proxy, cookies e o uso de cabeçalhos HTTP personalizados (via SetRequestHeader) para cada operação de transferência.
Como esse recurso se adapta a alterações de status da rede ou desligamentos inesperados?
O recurso Transferência em Segundo Plano mantém uma experiência consistente para cada operação de transferência quando ocorrem alterações no status da rede, aproveitando de forma inteligente a conectividade e as informações de status do plano de dados da operadora fornecidas pelo recurso Connectivity. Para definir o comportamento para diferentes cenários de rede, um aplicativo define uma política de custo para cada operação usando valores definidos por BackgroundTransferCostPolicy.
Por exemplo, a política de custos definida para uma operação pode indicar que a operação deve ser pausada automaticamente quando o dispositivo estiver usando uma rede limitada. A transferência é então retomada automaticamente (ou reiniciada) quando uma conexão com uma rede "sem restrições" é estabelecida. Para obter mais informações sobre como as redes são definidas por custo, consulte NetworkCostType.
Embora o recurso Transferência em Segundo Plano tenha seus próprios mecanismos para lidar com alterações de status de rede, há outras considerações gerais de conectividade para aplicativos conectados à rede. Leia Aproveitando as informações de conexão de rede disponíveis para obter informações adicionais.
Observação Para aplicativos executados em dispositivos móveis, há recursos que permitem ao usuário monitorar e restringir a quantidade de dados transferidos com base no tipo de conexão, no status de roaming e no plano de dados do usuário. Devido a isso, as transferências em segundo plano podem ser pausadas no telefone, mesmo quando a BackgroundTransferCostPolicy indica que a transferência deve continuar.
A tabela a seguir indica quando as transferências em segundo plano são permitidas no telefone para cada valor de BackgroundTransferCostPolicy, dado o estado atual do telefone. Você pode usar a classe ConnectionCost para determinar o estado atual do telefone.
| Estado do dispositivo | Sem restriçõesApenas | Predefinido | Sempre |
|---|---|---|---|
| Conectado ao Wi-Fi | Permitir | Permitir | Permitir |
| Conexão limitada, não em roaming, sob limite de dados, no caminho certo para permanecer abaixo do limite | Recusar | Permitir | Permitir |
| Ligação medida, não em roaming, abaixo do limite de dados, prestes a exceder o limite | Recusar | Recusar | Permitir |
| Conexão limitada, roaming, abaixo do limite de dados | Recusar | Recusar | Permitir |
| Conexão medida, acima do limite de dados. Esse estado ocorre somente quando o usuário habilita "Restringir dados em segundo plano na interface do usuário do Data Sense. | Recusar | Recusar | Recusar |
Upload de arquivos
Ao usar a Transferência em Segundo Plano, existe um upload como um UploadOperation de
Os exemplos a seguir orientarão você pela criação e inicialização de um carregamento básico e como enumerar e reintroduzir operações persistentes de uma sessão anterior do aplicativo.
Carregar um único ficheiro
A criação de um upload começa com BackgroundUploader. Essa classe é usada para fornecer os métodos que permitem que seu aplicativo configure o carregamento antes de criar o resultante UploadOperation. O exemplo a seguir mostra como fazer isso com os objetos de Uri necessários e os objetos de StorageFile necessários.
Identificar o ficheiro e o destino para carregamento
Antes de começarmos com a criação de um UploadOperation, precisamos primeiro identificar o URI do local para onde fazer o upload e o arquivo que será carregado. No exemplo a seguir, o valor uriString é preenchido usando uma cadeia de caracteres da entrada da interface do utilizador, e o valor do arquivo é preenchido usando o objeto StorageFile retornado por uma operação PickSingleFileAsync.
function uploadFile() {
var filePicker = new Windows.Storage.Pickers.FileOpenPicker();
filePicker.fileTypeFilter.replaceAll(["*"]);
filePicker.pickSingleFileAsync().then(function (file) {
if (!file) {
printLog("No file selected");
return;
}
var upload = new UploadOp();
var uriString = document.getElementById("serverAddressField").value;
upload.start(uriString, file);
// Store the upload operation in the uploadOps array.
uploadOperations.push(upload);
});
}
Criar e inicializar a operação de carregamento
Na etapa anterior, os valores uriString e file são passados para uma instância do nosso próximo exemplo, UploadOp, onde são usados para configurar e iniciar a nova operação de upload. Primeiro,
Em seguida, as propriedades do StorageFile fornecido
Finalmente, BackgroundUploader cria o UploadOperation (upload).
function UploadOp() {
var upload = null;
var promise = null;
this.start = function (uriString, file) {
try {
var uri = new Windows.Foundation.Uri(uriString);
var uploader = new Windows.Networking.BackgroundTransfer.BackgroundUploader();
// Set a header, so the server can save the file (this is specific to the sample server).
uploader.setRequestHeader("Filename", file.name);
// Create a new upload operation.
upload = uploader.createUpload(uri, file);
// Start the upload and persist the promise to be able to cancel the upload.
promise = upload.startAsync().then(complete, error, progress);
} catch (err) {
displayError(err);
}
};
// On application activation, reassign callbacks for a upload
// operation persisted from previous application state.
this.load = function (loadedUpload) {
try {
upload = loadedUpload;
promise = upload.attachAsync().then(complete, error, progress);
} catch (err) {
displayError(err);
}
};
}
Observe as chamadas de método assíncronas definidas usando promessas de JavaScript. Olhando para uma linha do último exemplo:
promise = upload.startAsync().then(complete, error, progress);
A chamada do método assíncrono é seguida por uma then instrução que indica métodos, definidos pelo aplicativo, que são chamados quando um resultado da chamada do método assíncrono é retornado. Para obter mais informações sobre esse padrão de programação, consulte Programação assíncrona em JavaScript usando promessas.
Upload de vários arquivos
Identificar os ficheiros e o destino para o carregamento
Em um cenário envolvendo vários arquivos transferidos com um único UploadOperation, o processo começa como normalmente faz, fornecendo primeiro o URI de destino necessário e informações de arquivo local. Semelhante ao exemplo na seção anterior, o URI é fornecido como uma cadeia de caracteres pelo usuário final e FileOpenPicker pode ser usado para fornecer a capacidade de indicar arquivos através da interface do usuário também. No entanto, nesse cenário, o aplicativo deve, em vez disso, chamar o método PickMultipleFilesAsync para habilitar a seleção de vários arquivos por meio da interface do usuário.
function uploadFiles() {
var filePicker = new Windows.Storage.Pickers.FileOpenPicker();
filePicker.fileTypeFilter.replaceAll(["*"]);
filePicker.pickMultipleFilesAsync().then(function (files) {
if (files === 0) {
printLog("No file selected");
return;
}
var upload = new UploadOperation();
var uriString = document.getElementById("serverAddressField").value;
upload.startMultipart(uriString, files);
// Persist the upload operation in the global array.
uploadOperations.push(upload);
});
}
Criar objetos para os parâmetros fornecidos
Os próximos dois exemplos usam o código contido em um único método de exemplo, startMultipart, que foi chamado no final da última etapa. Para fins de instrução, o código no método que cria um array de objetos BackgroundTransferContentPart foi separado do código que cria a UploadOperation resultante .
Primeiro, a cadeia de caracteres de URI fornecida pelo usuário é inicializada como um Uri. Em seguida, a matriz de objetos IStorageFile (ficheiros) passados para este método é percorrida, cada objeto é usado para criar um novo objeto BackgroundTransferContentPart, o qual é então colocado na matriz contentParts.
upload.startMultipart = function (uriString, files) {
try {
var uri = new Windows.Foundation.Uri(uriString);
var uploader = new Windows.Networking.BackgroundTransfer.BackgroundUploader();
var contentParts = [];
files.forEach(function (file, index) {
var part = new Windows.Networking.BackgroundTransfer.BackgroundTransferContentPart("File" + index, file.name);
part.setFile(file);
contentParts.push(part);
});
Criar e inicializar a operação de carregamento de várias partes
Com nossa matriz contentParts preenchida com todos os
// Create a new upload operation.
uploader.createUploadAsync(uri, contentParts).then(function (uploadOperation) {
// Start the upload and persist the promise to be able to cancel the upload.
upload = uploadOperation;
promise = uploadOperation.startAsync().then(complete, error, progress);
});
} catch (err) {
displayError(err);
}
};
Reiniciando operações de carregamento interrompidas
Após a conclusão ou cancelamento de um UploadOperation, todos os recursos do sistema associados são liberados. No entanto, se seu aplicativo for encerrado antes que qualquer uma dessas coisas possa ocorrer, todas as operações ativas serão pausadas e os recursos associados a cada uma delas permanecerão ocupados. Se essas operações não forem enumeradas e reintroduzidas na próxima sessão do aplicativo, elas não serão concluídas e continuarão a ocupar os recursos do dispositivo.
Antes de definir a função que enumera operações persistentes, precisamos criar uma matriz que conterá a UploadOperation objetos que ela retornará:
var uploadOperations = [];Em seguida, definimos a função que enumera operações persistentes e as armazena em nossa matriz. Observe que o carregar método chamado para reatribuir retornos de chamada ao UploadOperation, caso persista por meio do encerramento do aplicativo, está na classe UploadOp que definimos mais adiante nesta seção.
function Windows.Networking.BackgroundTransfer.BackgroundUploader.getCurrentUploadsAsync() { .then(function (uploads) { for (var i = 0; i < uploads.size; i++) { var upload = new UploadOp(); upload.load(uploads[i]); uploadOperations.push(upload); } } };
Download de arquivos
Ao usar a Transferência em Segundo Plano, cada download existe como um DownloadOperation que expõe vários métodos de controle usados para pausar, retomar, reiniciar e cancelar a operação. Eventos de aplicativos (por exemplo, suspensão ou encerramento) e alterações de conectividade são tratados automaticamente pelo sistema por DownloadOperation; Os downloads continuarão durante os períodos de suspensão ou pausa do aplicativo e persistirão após o encerramento do aplicativo. Para cenários de rede móvel, definir a propriedade CostPolicy indicará se o seu aplicativo começará ou continuará os downloads enquanto uma rede com tarifação estiver a ser usada para conectividade com a Internet.
Se estiveres a descarregar pequenos recursos que provavelmente serão concluídos rapidamente, deves usar as APIs de HttpClient em vez de Transferência em Segundo Plano.
Os exemplos a seguir o orientarão pela criação e inicialização de um download básico e como enumerar e reintroduzir operações persistidas de uma sessão anterior do aplicativo.
Configurar e iniciar uma transferência de ficheiro em segundo plano
O exemplo a seguir demonstra como cadeias de caracteres que representam um URI e um nome de arquivo podem ser usadas para criar um objeto Uri
function DownloadOp() {
var download = null;
var promise = null;
var imageStream = null;
this.start = function (uriString, fileName) {
try {
// Asynchronously create the file in the pictures folder.
Windows.Storage.KnownFolders.picturesLibrary.createFileAsync(fileName, Windows.Storage.CreationCollisionOption.generateUniqueName).done(function (newFile) {
var uri = Windows.Foundation.Uri(uriString);
var downloader = new Windows.Networking.BackgroundTransfer.BackgroundDownloader();
// Create a new download operation.
download = downloader.createDownload(uri, newFile);
// Start the download and persist the promise to be able to cancel the download.
promise = download.startAsync().then(complete, error, progress);
}, error);
} catch (err) {
displayException(err);
}
};
// On application activation, reassign callbacks for a download
// operation persisted from previous application state.
this.load = function (loadedDownload) {
try {
download = loadedDownload;
printLog("Found download: " + download.guid + " from previous application run.<br\>");
promise = download.attachAsync().then(complete, error, progress);
} catch (err) {
displayException(err);
}
};
}
Observe as chamadas de método assíncronas definidas usando promessas de JavaScript. Observando a linha 17 do exemplo de código anterior:
promise = download.startAsync().then(complete, error, progress);
A chamada de método assíncrono é seguida por uma instrução 'then' que indica métodos, definidos pela aplicação, que são chamados quando um resultado, da chamada de método assíncrono, é retornado. Para obter mais informações sobre esse padrão de programação, consulte Programação assíncrona em JavaScript usando promessas.
Adicionando métodos de controle de operação adicionais
O nível de controle pode ser aumentado implementando métodos adicionais DownloadOperation. Por exemplo, adicionar o código a seguir ao exemplo acima introduzirá a capacidade de cancelar o download.
// Cancel download.
this.cancel = function () {
try {
if (promise) {
promise.cancel();
promise = null;
printLog("Canceling download: " + download.guid + "<br\>");
if (imageStream) {
imageStream.close();
}
}
else {
printLog("Download " + download.guid + " already canceled.<br\>");
}
} catch (err) {
displayException(err);
}
};
Enumerando operações persistentes na inicialização
Após a conclusão ou cancelamento de um DownloadOperation, todos os recursos do sistema associados são liberados. No entanto, se o aplicativo for encerrado antes que qualquer um desses eventos ocorra, os downloads serão pausados e persistirão em segundo plano. Os exemplos a seguir demonstram como reintroduzir downloads persistentes em uma nova sessão de aplicativo.
Antes de definir a função que enumera operações persistentes, precisamos criar uma matriz que conterá o DownloadOperation objetos que ela retornará:
var downloadOps = [];Em seguida, definimos a função que enumera operações persistentes e as armazena em nossa matriz. Observe que o
carregar método chamado para reatribuir retornos de chamada para um DownloadOperation depersistente está no exemplo DownloadOp que definimos mais adiante nesta seção. // Enumerate outstanding downloads. Windows.Networking.BackgroundTransfer.BackgroundDownloader.getCurrentDownloadsAsync().done(function (downloads) { for (var i = 0; i < downloads.size; i++) { var download = new DownloadOp(); download.load(downloads[i]); downloadOps.push(download); } });Agora você pode usar a lista preenchida para reiniciar operações pendentes.
Pós-processamento
Um novo recurso no Windows 10 é a capacidade de executar o código do aplicativo na conclusão de uma transferência em segundo plano, mesmo quando o aplicativo não está em execução. Por exemplo, seu aplicativo pode querer atualizar uma lista de filmes disponíveis depois que o download de um filme terminar, em vez de fazer com que seu aplicativo verifique novos filmes sempre que for iniciado. Ou seu aplicativo pode querer lidar com uma transferência de arquivos com falha tentando novamente usando um servidor ou porta diferente. O pós-processamento é invocado para transferências bem-sucedidas e com falha, para que você possa usá-lo para implementar a lógica personalizada de tratamento de erros e novas tentativas.
O pós-processamento usa a infraestrutura de tarefas em segundo plano existente. Você cria uma tarefa em segundo plano e a associa às suas transferências antes de iniciar as transferências. As transferências são então executadas em segundo plano e, quando são concluídas, sua tarefa em segundo plano é chamada para executar o pós-processamento.
O pós-processamento usa uma nova classe, BackgroundTransferCompletionGroup. Essa classe é semelhante ao existente
Você inicia uma transferência em segundo plano com pós-processamento da seguinte maneira.
- Crie um objeto BackgroundTransferCompletionGroup. Em seguida, crie um objeto BackgroundTaskBuilder. Defina a propriedade Trigger do objeto builder para o objeto do grupo de conclusão e a propriedade TaskEntryPoint do builder para o ponto de entrada da tarefa em segundo plano que deve ser executada na conclusão da transferência. Finalmente, chame o método BackgroundTaskBuilder.Register para registrar sua tarefa em segundo plano. Observe que muitos grupos de conclusão podem compartilhar um ponto de entrada de tarefa em segundo plano, mas você pode ter apenas um grupo de conclusão por registro de tarefa em segundo plano.
var completionGroup = new BackgroundTransferCompletionGroup();
BackgroundTaskBuilder builder = new BackgroundTaskBuilder();
builder.Name = "MyDownloadProcessingTask";
builder.SetTrigger(completionGroup.Trigger);
builder.TaskEntryPoint = "Tasks.BackgroundDownloadProcessingTask";
BackgroundTaskRegistration downloadProcessingTask = builder.Register();
- Em seguida, associe as transferências em segundo plano ao grupo de conclusão. Depois de todas as transferências serem criadas, ative o grupo de conclusão.
BackgroundDownloader downloader = new BackgroundDownloader(completionGroup);
DownloadOperation download = downloader.CreateDownload(uri, file);
Task<DownloadOperation> startTask = download.StartAsync().AsTask();
// App still sees the normal completion path
startTask.ContinueWith(ForegroundCompletionHandler);
// Do not enable the CompletionGroup until after all downloads are created.
downloader.CompletionGroup.Enable();
- O código na tarefa de fundo extrai a lista de operações a partir dos detalhes do gatilho, e o seu código pode então inspecionar os detalhes de cada operação e realizar o pós-processamento apropriado para cada operação.
public class BackgroundDownloadProcessingTask : IBackgroundTask
{
public async void Run(IBackgroundTaskInstance taskInstance)
{
var details = (BackgroundTransferCompletionGroupTriggerDetails)taskInstance.TriggerDetails;
IReadOnlyList<DownloadOperation> downloads = details.Downloads;
// Do post-processing on each finished operation in the list of downloads
}
}
A tarefa de pós-processamento é uma tarefa regular em segundo plano. Ele faz parte do pool de todas as tarefas em segundo plano e está sujeito à mesma política de gerenciamento de recursos que todas as tarefas em segundo plano.
Além disso, observe que o pós-processamento não substitui os manipuladores de conclusão de primeiro plano. Se seu aplicativo definir um manipulador de conclusão em primeiro plano e seu aplicativo estiver em execução quando a transferência de arquivos for concluída, tanto o manipulador de conclusão de primeiro plano quanto o manipulador de conclusão em segundo plano serão chamados. A ordem em que as tarefas em primeiro plano e em segundo plano são chamadas não é garantida. Se você definir ambos, deverá garantir que as duas tarefas funcionem corretamente e não interfiram uma na outra se estiverem sendo executadas simultaneamente.
Tempo limite de solicitação
Há dois cenários principais de tempo limite de conexão a serem levados em consideração:
Ao estabelecer uma nova conexão para uma transferência, a solicitação de conexão é anulada se não for estabelecida dentro de cinco minutos.
Depois que uma conexão for estabelecida, uma mensagem de solicitação HTTP que não recebeu uma resposta em dois minutos será anulada.
Observação Em qualquer um dos cenários, supondo que haja conectividade com a Internet, a Transferência em Segundo Plano tentará novamente uma solicitação até três vezes automaticamente. Caso a conectividade com a Internet não seja detetada, solicitações adicionais aguardarão até que seja restabelecida.
Diretrizes de depuração
Parar uma sessão de depuração no Microsoft Visual Studio é comparável a fechar seu aplicativo; Os carregamentos PUT são pausados e os carregamentos POST são encerrados. Mesmo durante a depuração, seu aplicativo deve enumerar e, em seguida, reiniciar ou cancelar quaisquer carregamentos persistentes. Por exemplo, você pode fazer com que seu aplicativo cancele operações de carregamento persistentes enumeradas na inicialização do aplicativo se não houver interesse em operações anteriores para essa sessão de depuração.
Ao enumerar downloads/uploads na inicialização do aplicativo durante uma sessão de depuração, você pode fazer com que seu aplicativo os cancele se não houver interesse em operações anteriores para essa sessão de depuração. Observe que, se houver atualizações de projeto do Visual Studio, como alterações no manifesto do aplicativo, e o aplicativo for desinstalado e reimplantado, GetCurrentUploadsAsync não poderá enumerar operações criadas usando a implantação anterior do aplicativo.
Ao usar a Transferência em Segundo Plano durante o desenvolvimento, você pode entrar em uma situação em que os caches internos de operações de transferência ativas e concluídas podem ficar fora de sincronia. Isso pode resultar na incapacidade de iniciar novas operações de transferência ou interagir com operações existentes e objetos BackgroundTransferGroup. Em alguns casos, a tentativa de interagir com operações existentes pode desencadear uma falha. Esse resultado pode ocorrer se a propriedade TransferBehavior estiver definida como Parallel. Esse problema ocorre apenas em determinados cenários durante o desenvolvimento e não é aplicável aos usuários finais do seu aplicativo.
Quatro cenários usando o Visual Studio podem causar esse problema.
- Você cria um novo projeto com o mesmo nome de aplicativo de um projeto existente, mas uma linguagem diferente (de C++ para C#, por exemplo).
- Você altera a arquitetura de destino (de x86 para x64, por exemplo) em um projeto existente.
- Você altera a cultura (de neutra para en-US, por exemplo) em um projeto existente.
- Você adiciona ou remove um recurso no manifesto do pacote (adicionando Autenticação Empresarial, por exemplo) num projeto existente.
A manutenção regular do aplicativo, incluindo atualizações de manifesto que adicionam ou removem recursos, não acionam esse problema nas implantações do usuário final do seu aplicativo. Para contornar esse problema, desinstale completamente todas as versões do aplicativo e reimplante com o novo idioma, arquitetura, cultura ou recurso. Isso pode ser feito através da tela Iniciar ou usando o PowerShell e o cmdlet Remove-AppxPackage.
Exceções em Windows.Networking.BackgroundTransfer
Uma exceção é lançada quando uma cadeia de caracteres inválida para um URI (Uniform Resource Identifier) é passada para o construtor do objeto Windows.Foundation.Uri .
.NET: O tipo Windows.Foundation.Uri aparece como System.Uri em C# e VB.
Em C# e Visual Basic, esse erro pode ser evitado usando a classe System.Uri no .NET 4.5 e um dos System.Uri.TryCreate métodos para testar a cadeia de caracteres recebida do usuário do aplicativo antes que o URI seja construído.
Em C++, não há nenhum método para tentar analisar uma cadeia de caracteres para um URI. Se uma aplicação recebe dados do utilizador para o Windows.Foundation.Uri , o construtor deve estar num bloco try/catch. Se uma exceção for lançada, o aplicativo poderá notificar o usuário e solicitar um novo nome de host.
O namespace Windows.Networking.backgroundTransfer tem métodos auxiliares convenientes e usa enumerações no namespace Windows.Networking.Sockets para manipular erros. Isso pode ser útil para lidar com exceções de rede específicas de forma diferente em seu aplicativo.
Um erro encontrado em um método assíncrono no namespace
Para erros de validação de parâmetro, um aplicativo também pode usar o HRESULT da exceção para obter informações mais detalhadas sobre o erro que causou a exceção. Os valores possíveis de HRESULT estão listados no ficheiro de cabeçalho Winerror.h. Para a maioria dos erros de validação de parâmetros, o HRESULT é retornado como E_INVALIDARG.