A única maneira (pelo que eu sei) de criar uma barra de progresso em um botão da barra de tarefas é usar a interface ITaskbarList3 , mas isso só pode ser usado em C++, não em C. Existe alguma maneira de fazer isso em C, interagindo apenas com funções winapi?
Embora as interfaces COM possam se parecer muito com C++, com chamadas como
pTaskbar->lpVtbl->Release(pTaskbar)
, elas não são. São estruturas com ponteiros de função C, e você passa constantemente como argumento o "objeto" principal — diferentemente do que seria feito em C++.O código a seguir deve mostrar como fazer isso:
Testado no Windows 10, MSVC 2019, 64 bits, C17. Não deve ser muito diferente com outros compiladores ou padrões C, exceto, é claro, pelas diretivas #pragma comment(lib, ...), que só serão reconhecidas pelo MSVC — vincule essas 4 bibliotecas manualmente, se necessário.
Você pode compilá-lo com a seguinte linha de comando, a partir de um prompt do ambiente VS:
Não verifiquei com o MinGW ou outras versões do VS - como eu disse, este é um código C e Windows padrão, e seria compilado até mesmo em Windows muito antigos, se
ITaskbarList3
estivesse disponível. COM é algo muito antigo na API do Windows.Você compila, executa e clica no botão para exibir uma barra de progresso simulada. Os pontos-chave são destacados no código com comentários; todo o resto está sem comentários, pois está lá apenas para fornecer um aplicativo Windows mínimo – não há necessidade de entrar em detalhes sobre o gerador de mensagens ou o temporizador. Eu sei, é um pouco confuso, mas o objetivo não era mostrar as "melhores práticas" para construir um aplicativo Windows em C. Ele compila sem avisos, então é o suficiente para um exemplo rápido.
Para obter detalhes sobre cada função, consulte a documentação da Microsoft, especialmente se você não estiver familiarizado com interfaces COM (tenha cuidado para inicializar/desinicializar corretamente a API COM no início/fim do seu programa).
O COM foi projetado para ser independente de linguagem. A introdução ao Modelo de Objeto Componente explica isso:
C é capaz de criar estruturas (ou arrays) de ponteiros de função e chamar funções por meio deles. Isso significa que C pode ser usado para implementar e utilizar interfaces COM. A única razão pela qual você não encontrará muita abordagem para o uso de COM em C é que ele é muito trabalhoso.
No nível binário, um ponteiro de interface COM é um ponteiro para uma estrutura com uma (ou mais) tabelas de ponteiros de função. O compilador MIDL padrão gera arquivos de cabeçalho que chamam o ponteiro da tabela de funções
lpVtbl
. Em C++, isso é tratado de forma transparente pelo compilador, com os métodos sendo exibidos como se fossem funções-membro da classe. Em C, por outro lado, você precisa digitar manualmente as indireções de ponteiro e passar othis
ponteiro (implícito em C++).Supondo que
pTaskbarList3
seja um ponteiro para umaITaskbarList3
interface, os seguintes trechos mostram como chamar oITaskbarList::HrInit
método.C:
C++:
O código gerado é idêntico em ambos os casos. O compilador C++ apenas nos permite ser muito menos prolixos.
Os arquivos de cabeçalho fornecidos com o SDK do Windows geralmente fornecem uma interface C++ e uma interface C, que estão disponíveis condicionalmente com base na
__cplusplus
definição de "se" ou não. Ao usar um compilador C, você pode, opcionalmente, habilitar macros de conveniência por meio doCOBJMACROS
símbolo do pré-processador. Essas macros nos permitem nomear o ponteiro da interface apenas uma vez:Com os conceitos básicos abordados, veja como você criaria e usaria a
ITaskbarList3
interface em C.Abaixo está um programa de exemplo completo que demonstra como usar a
ITaskbarList3
interface de C:Você pode compilá-lo a partir de um prompt de comando do Visual Studio usando a seguinte linha de comando:
Alguns pontos que vale a pena destacar:
L"TaskbarButtonCreated"
mensagem para ser notificado quando o botão da barra de tarefas estiver pronto para ser usado.CoUninitialize
). Temos décadas de evidências de que permitir que a biblioteca COM seja limpa como parte do encerramento de threads é a opção mais segura. Ignore a documentação neste caso.