Isso é realmente possível, mas é um pouco trabalhoso e requer duas implementações completamente diferentes, dependendo da versão do Windows. Para ambos os métodos, você precisa definir o seu botão de energia para colocar o computador para dormir em suas opções de energia.
Windows XP e abaixo:
Você precisa sobrescrever a função WndProc
da janela principal do seu programa. Em IDEs que não suportam isso nativamente, isso pode ser feito usando SetWindowLong
na API user32. Na sua função WndProc
personalizada, ouça a mensagem WM_POWERBROADCAST (0x218)
. Se você receber uma mensagem com wParam de PBT_APMQUERYSUSPEND (0x0)
, chame sua função desejada e retorne BROADCAST_QUERY_DENY (0x424D5144)
em vez de chamar a função WndProc
de base. Exemplo de código:
//At program start
//GWL_WNDPROC = -4
oldWndProc = SetWindowLong(this.hWnd, GWL_WNDPROC, &MyWndProc)
//In MyWndProc(hWnd, wMsg, wParam, lParam)
//WM_POWERBROADCAST = 0x218
//PBT_APMQUERYSUSPEND = 0x0
//BROADCAST_QUERY_DENY = 0x424D5144
if wMsg = WM_POWERBROADCAST && wParam = PBT_APMQUERYSUSPEND (
//CALL YOUR FUNCTION HERE!
return BROADCAST_QUERY_DENY
)
return CallWindowProc(oldWndProc, hWnd, wMsg, wParam, lParam)
//Before exiting
SetWindowLong(Me.hWnd, GWL_WNDPROC, oldWndProc)
Windows Vista e amp; up: (obrigado a Remy Lebeau por me colocar no caminho certo)
Você precisa substituir WndProc
, como no XP, mas também chamar SetThreadExecutionState
na API do kernel32 para desabilitar o modo de suspensão e RegisterPowerSettingNotification
na API user32 para ouvir notificações avançadas de energia. Você estará ouvindo, em particular, a notificação GUID_SYSTEM_AWAYMODE
, que é enviada quando o sistema foi solicitado a adormecer, mas não consegue fazê-lo. Para converter facilmente uma string em LPCGUID
formada corretamente, você pode usar UuidFromStringA
na API rpcrt4.dll. Exemplo de código:
typedef struct UUID{
int d1, d2, d3, d4
} LPCGUID;
//At program start
//GWL_WNDPROC = -4
//ES_CONTINUOUS = 0x80000000
//ES_SYSTEM_REQUIRED = 0x1
//ES_AWAYMODE_REQUIRED = 0x40
//GUID_SYSTEM_AWAYMODE = "98a7f580-01f7-48aa-9c0f-44352c29e5C0"
LPCGUID uid;
oldWndProc = SetWindowLong(this.hWnd, GWL_WNDPROC, &MyWndProc)
SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_AWAYMODE_REQUIRED)
UuidFromStringA(*(GUID_SYSTEM_AWAYMODE), uid)
ps = RegisterPowerSettingNotification(this.hWnd, uid, 0)
//In MyWndProc(hWnd, wMsg, wParam, lParam)
//WM_POWERBROADCAST = 0x218
//PBT_POWERSETTINGCHANGE = 0x8013
if wMsg = WM_POWERBROADCAST && wParam = PBT_POWERSETTINGCHANGE (
//CALL YOUR FUNCTION HERE!
//You can additionally extract data from the lParam to verify
//this is the notification you're waiting for (see below)
)
return CallWindowProc(oldWndProc, hWnd, wMsg, wParam, lParam)
//Before exiting
SetWindowLong(Me.hWnd, GWL_WNDPROC, oldWndProc)
UnregisterPowerSettingNotification(ps)
Este método tem o efeito colateral de desligar sua tela física (não um problema em uma máquina sem cabeçalho), e também possivelmente travar sua sessão. Certifique-se de desativar a solicitação de senha depois de dormir para evitar isso. Há algumas informações úteis adicionais sobre RegisterPowerSettingNotification
disponível aqui que mostra como extrair informações do lParam
na sua função WndProc
caso você queira informações adicionais sobre a notificação. Divirta-se;)