windows 7 - ¿Cómo se hace una ventana emergente de recordatorio de perspectiva sobre otras ventanas?
windows-7 outlook (9)
¿Cómo se hace una ventana emergente de recordatorio de perspectiva en la parte superior de otras ventanas?
Después de buscar en línea durante mucho tiempo; No pude encontrar una respuesta satisfactoria a esta pregunta.
Usando Windows 7 y Microsoft Outlook 2007+; cuando un recordatorio se ilumina, ya no da una caja modal para captar su atención. En el trabajo donde los complementos adicionales pueden ser problemáticos de instalar (derechos de administrador) y al usar un sistema silencioso, las convocatorias de reuniones a menudo se pasan por alto.
¿Hay una manera más fácil de implementar esto que usar complementos / aplicaciones de terceros?
¡He encontrado un programa gratuito llamado PinMe! Eso hará exactamente lo que yo quiero. Cuando aparezca su recordatorio de Outlook, haga clic derecho en PinMe! en la bandeja del sistema y seleccione la ventana Recordatorio. Esto colocará un icono de candado al lado de la ventana. Adelante Descartar o Posponer su recordatorio. La próxima vez que aparezca el recordatorio, debería aparecer en la parte frontal de todas las demás ventanas. Esto funcionará independientemente de Outlook en primer plano o minimizado.
Después de inspirarme en la respuesta de Eric Labashosky , di un paso más en su concepto y creé la aplicación NotifyWhenMicrosoftOutlookReminderWindowIsOpen , que puede descargar de forma gratuita. Es un pequeño archivo ejecutable que puede garantizar que la ventana de Recordatorios de Outlook aparezca encima de otras ventanas, además de tener otras formas opcionales de alertar al usuario de que la ventana se ha abierto.
Esto debería funcionar en diferentes versiones de Outlook incluso si lo probé solo en Outlook 2013.
Como no puedo probarlo en una versión localizada en inglés, es posible que deba personalizar las líneas de código relacionadas con la búsqueda en la ventana de recordatorios incluso si, en mi respuesta, cambié las líneas de código relacionadas para encontrar la ventana en la versión localizada en inglés.
Avísame si la macro funciona en tu versión de Outlook en inglés.
El usuario tiene la libertad de minimizar o cerrar la ventana de recordatorios, en cuyo caso, cuando se active un recordatorio nuevo o existente, la ventana de recordatorios será la más alta y no estará activada.
El título de la ventana de recordatorios siempre se actualizará reflejando el número real de recordatorios visibles, incluso sin activarlo.
En todos los casos, la ventana de recordatorios nunca robará el foco a menos que, obviamente, la ventana de primer plano sea la ventana de recordatorios, es decir, a menos que el usuario haya seleccionado deliberadamente la ventana de recordatorios.
Esta macro, además de hacer que la ventana de recordatorios aparezca en la parte superior, también seleccionará el recordatorio más reciente en la ventana de recordatorio, puede personalizar este comportamiento, lea el código para poder hacerlo.
La macro también muestra la ventana de recordatorios cuando se muestra la ventana por primera vez y cada vez que se dispara un recordatorio nuevo o existente.
Puede personalizar cuántas veces parpadea la ventana o cualquier otro parámetro relacionado con ella, debe quedar claro cómo hacerlo.
Pegue las siguientes líneas de código en el módulo de clase ''ThisOutlookSession'':
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function SetWindowPos Lib "user32" (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, _
ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
Private Declare Function ShowWindow Lib "user32" (ByVal hwnd As Long, ByVal nCmdShow As Long) As Long
Private Declare Function FlashWindowEx Lib "user32" (FWInfo As FLASHWINFO) As Boolean
Private Const FLASHW_STOP = 0
Private Const FLASHW_CAPTION = 1
Private Const FLASHW_TRAY = 2
Private Const FLASHW_ALL = FLASHW_CAPTION Or FLASHW_TRAY
Private Const FLASHW_TIMER = 4
Private Const FLASHW_TIMERNOFG = 12
Private Type FLASHWINFO
cbSize As Long
hwnd As Long
dwFlags As Long
uCount As Long
dwTimeout As Long
End Type
Private Const HWND_TOPMOST = -1
Private Const HWND_NOTOPMOST = -2
Private Const HWND_TOP = 0
Private Const HWND_BOTTOM = 1
Private Const SWP_NOSIZE = 1
Private Const SWP_NOMOVE = 2
Private Const SWP_NOACTIVATE = 16
Private Const SWP_DRAWFRAME = 32
Private Const SWP_NOOWNERZORDER = 512
Private Const SWP_NOZORDER = 4
Private Const SWP_SHOWWINDOW = 64
Private Existing_reminders_window As Boolean
Private WithEvents Rmds As Reminders
Public Reminders_window As Long
Private Sub Application_Reminder(ByVal Item As Object)
If Existing_reminders_window = False Then
Set Rmds = Application.Reminders
''In order to create the reminders window
ActiveExplorer.CommandBars.ExecuteMso ("ShowRemindersWindow")
Reminders_window = FindWindow("#32770", "0 Reminder(s)")
If Reminders_window = 0 Then
Reminders_window = FindWindow("#32770", "0 Reminder")
If Reminders_window = 0 Then
Reminders_window = FindWindow("#32770", "0 Reminder ")
End If
End If
''To prevent stealing focus in case Outlook was in the foreground
ShowWindow Reminders_window, 0
SetWindowPos Reminders_window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE Or SWP_NOMOVE Or SWP_NOACTIVATE
Existing_reminders_window = True
End If
End Sub
Private Sub Rmds_BeforeReminderShow(Cancel As Boolean)
Dim FWInfo As FLASHWINFO
If Existing_reminders_window = True Then
Cancel = True
With FWInfo
.cbSize = 20
.hwnd = Reminders_window
.dwFlags = FLASHW_CAPTION
.uCount = 4
.dwTimeout = 0
End With
''In case the reminders window was not the highest topmost. This will not work on Windows 10 if the task manager window is topmost, the task manager and some other system windows have special z position
SetWindowPos Reminders_window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE Or SWP_NOMOVE Or SWP_NOACTIVATE
ShowWindow Reminders_window, 4
Select_specific_reminder
FlashWindowEx FWInfo
End If
End Sub
Pegue las siguientes líneas de código en un módulo estándar nuevo o existente:
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Long) As Long
Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare Function EnumChildWindows Lib "user32" (ByVal hWndParent As Long, ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long
Private Const WM_CHAR = &H102
Private Const VK_HOME = &H24
Private Const VK_END = &H23
Private Const WM_KEYDOWN = &H100
Private Const WM_KEYUP = &H101
Public Sub Select_specific_reminder()
Dim Retval As Long
Retval = EnumChildWindows(ThisOutlookSession.Reminders_window, AddressOf EnumChildProc, 0)
End Sub
Private Function EnumChildProc(ByVal hwnd As Long, ByVal lParam As Long) As Long
Dim Nome_classe As String
Nome_classe = Space$(256)
GetClassName hwnd, Nome_classe, 256
If InStr(Nome_classe, "SysListView32") Then
''You can customize the next code line in order to select a specific reminder
SendMessage hwnd, WM_KEYDOWN, VK_HOME, ByVal 0&
End If
EnumChildProc = 1
End Function
La última versión de Outlook tiene esta característica incorporada y la misma se responde en https://superuser.com/a/1327856/913992
Outlook 2016 ahora ofrece una opción para "Mostrar recordatorios en la parte superior de otras ventanas". Use Archivo> Opciones> Avanzadas , y luego use la casilla de verificación en la sección Recordatorios. Vea esta página de support.office.com para la captura de pantalla. Esta opción se agregó en la Versión 1804 de Outlook 2016, lanzada al "canal mensual" el 25 de abril de 2018.
Esta opción de Outlook 2016 coloca el recordatorio sobre todas las aplicaciones solo inicialmente. Me gusta mantener el recordatorio en la parte superior hasta que lo rechace explícitamente, incluso si hago clic en otra ventana. Para mantener el recordatorio en la parte superior, recomiendo la respuesta aceptada de @ Tragamor a esta pregunta. Pero si la respuesta de @ Tragamor parece demasiado complicada, y está de acuerdo con que el recordatorio está en primer lugar solo inicialmente, la opción ahora en Outlook 2016 es muy simple.
Solo Alt F11 y copia este código ... Trabaja para mi
Option Explicit
Private Declare Function FindWindow Lib "User32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function GetWindowText Lib "User32" Alias "GetWindowTextA" (ByVal hWnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Private Declare Function GetWindowTextLength Lib "User32" Alias "GetWindowTextLengthA" (ByVal hWnd As Long) As Long
Private Declare Function GetWindow Lib "User32" (ByVal hWnd As Long, ByVal wCmd As Long) As Long
Private Declare Function IsWindowVisible Lib "User32" (ByVal hWnd As Long) As Boolean
Private Const GW_HWNDNEXT = 2
Private Declare PtrSafe Function FindWindowA Lib "User32" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare PtrSafe Function SetWindowPos Lib "User32" ( _
ByVal hWnd As Long, ByVal hWndInsertAfter As Long, _
ByVal X As Long, ByVal Y As Long, ByVal cx As Long, _
ByVal cy As Long, ByVal wFlags As Long) As Long
Private Const SWP_NOSIZE = &H1
Private Const SWP_NOMOVE = &H2
Private Const FLAGS As Long = SWP_NOMOVE Or SWP_NOSIZE
Private Const HWND_TOPMOST = -1
Private Sub Application_Reminder(ByVal Item As Object)
Dim ReminderWindowHWnd As Variant
On Error Resume Next
Dim lhWndP As Long
If GetHandleFromPartialCaption(lhWndP, "Reminder") = True Then
SetWindowPos lhWndP, HWND_TOPMOST, 0, 0, 0, 0, FLAGS
End If
End Sub
Private Function GetHandleFromPartialCaption(ByRef lWnd As Long, ByVal sCaption As String) As Boolean
Dim lhWndP As Long
Dim sStr As String
GetHandleFromPartialCaption = False
lhWndP = FindWindow(vbNullString, vbNullString) ''PARENT WINDOW
Do While lhWndP <> 0
sStr = String(GetWindowTextLength(lhWndP) + 1, Chr$(0))
GetWindowText lhWndP, sStr, Len(sStr)
sStr = Left$(sStr, Len(sStr) - 1)
If InStr(1, sStr, sCaption) > 0 Then
GetHandleFromPartialCaption = True
lWnd = lhWndP
Exit Do
End If
lhWndP = GetWindow(lhWndP, GW_HWNDNEXT)
Loop
End Function
Tengo Office 2013 y Windows 8.1 Pro. Muchas de las macros que encontré no manejaban la naturaleza variable del título que Outlook coloca en el cuadro de diálogo Recordatorio. Cuando tiene 1 recordatorio, el título es "1 Recordatorio (s)", etc. Creé una aplicación de formularios de Windows simple en VB.NET, que cargo al inicio y mantengo minimizada en la bandeja del sistema. Hay un temporizador 60 agregado al formulario que activa el código activo. Cuando hay más de 0 recordatorios, el cuadro de diálogo se establecerá en la parte superior y se moverá a 0,0.
Aquí está el código:
Imports System.Runtime.InteropServices
Imports System.Text
Module Module1
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
Public Function FindWindowEx(ByVal parentHandle As IntPtr, ByVal childAfter As IntPtr, ByVal lclassName As String, ByVal windowTitle As String) As IntPtr
End Function
<DllImport("user32.dll", SetLastError:=True)> _
Public Function SetWindowPos(ByVal hWnd As IntPtr, ByVal hWndInsertAfter As IntPtr, ByVal X As Integer, ByVal Y As Integer, ByVal cx As Integer, ByVal cy As Integer, ByVal uFlags As Integer) As Boolean
End Function
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Public Function GetWindowText(ByVal hwnd As IntPtr, ByVal lpString As StringBuilder, ByVal cch As Integer) As Integer
End Function
End Module
Public Class Form1
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
Dim titleString As String = ""
Dim nullHandle As New IntPtr
Dim windowHandle As New IntPtr
Dim titleLength As Long
Try
Do
Dim sb As New StringBuilder
sb.Capacity = 512
Dim prevHandle As IntPtr = windowHandle
windowHandle = FindWindowEx(nullHandle, prevHandle, "#32770", vbNullString)
If windowHandle <> 0 And windowHandle <> nullHandle Then
titleLength = GetWindowText(windowHandle, sb, 256)
If titleLength > 0 Then
titleString = sb.ToString
Dim stringPos As Integer = InStr(titleString, "Reminde", CompareMethod.Text)
If stringPos Then
Dim reminderCount As Integer = Val(Mid(titleString, 1, 2))
If reminderCount > 0 Then
Dim baseWindow As IntPtr = -1 ''-1 is the topmost position
SetWindowPos(windowHandle, baseWindow, 0, 0, 100, 100, &H41)
End If
Exit Sub
End If
End If
Else
Exit Sub
End If
Loop
Catch ex As Exception
MsgBox(ex.Message.ToString)
End Try
End Sub
Private Sub ToolStripMenuItem1_Click(sender As Object, e As EventArgs) Handles ToolStripMenuItem1.Click
Me.Close()
End Sub
Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown
Me.Hide()
End Sub
End Class
Usando AutoHotKey puede configurar la ventana para estar siempre arriba sin robar el foco de la ventana actual. (Probado con WIn10 / Outlook 2013)
TrayTip Script, Looking for Reminder window to put on top, , 16
SetTitleMatchMode 2 ; windows contains
loop {
WinWait, Reminder(s),
WinSet, AlwaysOnTop, on, Reminder(s)
WinRestore, Reminder(s)
TrayTip Outlook Reminder, You have an outlook reminder open, , 16
WinWaitClose, Reminder(s), ,30
}
* Para la última macro, por favor vea la actualización 3 *
Después de buscar por un tiempo encontré una respuesta parcial en un sitio web que parecía darme la mayor parte de la solución; https://superuser.com/questions/251963/how-to-make-outlook-calendar-reminders-stay-on-top-in-windows-7
Sin embargo, como se señaló en los comentarios, el primer recordatorio no se abrió; mientras que otros recordatorios luego lo hicieron. Según el código, asumí que esto se debía a que la ventana no se detectó hasta que se había instanciado una vez.
Para solucionar esto, busqué un temporizador para probar periódicamente si la ventana estaba presente y si estaba, y luego llevarla al frente. Tomando el código del siguiente sitio web; Outlook VBA - Ejecutar un código cada media hora
Luego, fusionar las dos soluciones juntas dio una solución funcional a este problema.
Desde el centro de confianza, habilité el uso de macros y luego abrí el editor visual básico de Outlook (alt + F11). Agregué el siguiente código al módulo ''ThisOutlookSession''
Private Sub Application_Startup()
Call ActivateTimer(5) ''Set timer to go off every 5 seconds
End Sub
Private Sub Application_Quit()
If TimerID <> 0 Then Call DeactivateTimer ''Turn off timer upon quitting
End Sub
Luego agregó un módulo y agregó el siguiente código.
Declare Function SetTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent _
As Long, ByVal uElapse As Long, ByVal lpTimerfunc As Long) As Long
Declare Function KillTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent _
As Long) As Long
Private Declare Function FindWindowA Lib "user32" (ByVal lpClassName _
As String, ByVal lpWindowName As String) As Long
Private Declare Function SetWindowPos Lib "user32" (ByVal hwnd As Long, ByVal _
hWndInsertAfter As Long, ByVal X As Long, ByVal Y As Long, ByVal cx As Long, _
ByVal cy As Long, ByVal wFlags As Long) As Long
Private Const SWP_NOSIZE = &H1
Private Const SWP_NOMOVE = &H2
Private Const FLAGS As Long = SWP_NOMOVE Or SWP_NOSIZE
Private Const HWND_TOPMOST = -1
Public TimerID As Long ''Need a timer ID to eventually turn off the timer.
'' If the timer ID <> 0 then the timer is running
Public Sub ActivateTimer(ByVal nSeconds As Long)
nSeconds = nSeconds * 1000
''The SetTimer call accepts milliseconds, so convert from seconds
If TimerID <> 0 Then Call DeactivateTimer
''Check to see if timer is running before call to SetTimer
TimerID = SetTimer(0, 0, nSeconds, AddressOf TriggerTimer)
If TimerID = 0 Then MsgBox "The timer failed to activate."
End Sub
Public Sub DeactivateTimer()
Dim lSuccess As Long
lSuccess = KillTimer(0, TimerID)
If lSuccess = 0 Then
MsgBox "The timer failed to deactivate."
Else
TimerID = 0
End If
End Sub
Public Sub TriggerTimer(ByVal hwnd As Long, ByVal uMsg As Long, _
ByVal idevent As Long, ByVal Systime As Long)
Call EventMacro
End Sub
Public Sub EventMacro()
Dim ReminderWindowHWnd As Variant
On Error Resume Next
ReminderWindowHWnd = FindWindowA(vbNullString, "1 Reminder")
If ReminderWindowHWnd <> 0 Then SetWindowPos ReminderWindowHWnd, _
HWND_TOPMOST, 0, 0, 0, 0, FLAGS
ReminderWindowHWnd = Nothing
End Sub
Eso es todo; cada 5 segundos, el temporizador comprueba si existe una ventana con un título "1 Recordatorio" y luego la coloca en la parte superior ...
ACTUALIZACIÓN (12 de febrero de 2015) : después de usar esto por un tiempo, encontré una verdadera molestia con el hecho de que al activar el temporizador se elimina el enfoque de la ventana actual. Es una molestia masiva mientras escribes un correo electrónico.
Como tal, actualicé el código para que el temporizador solo se ejecute cada 60 segundos, luego de encontrar el primer recordatorio activo, el temporizador se detiene y la función de evento secundario se usa de inmediato para activar el cambio de enfoque de la ventana.
ACTUALIZACIÓN 2 (4 de septiembre de 2015) : Habiendo realizado la transición a Outlook 2013, este código dejó de funcionar para mí. Ahora lo he actualizado con una función adicional (FindReminderWindow) que busca un rango de títulos de recordatorios emergentes. Esto ahora funciona para mí en 2013 y debería funcionar para versiones inferiores a 2013.
La función FindReminderWindow toma un valor que es el número de iteraciones que se deben recorrer para encontrar la ventana. Si habitualmente tiene un número mayor de recordatorios que 10 ventanas emergentes, puede aumentar este número en el sub de EventMacro ...
Código actualizado a continuación: agregue el siguiente código al módulo ''ThisOutlookSession''
Private Sub Application_Startup()
Call ActivateTimer(60) ''Set timer to go off every 60 seconds
End Sub
Private Sub Application_Quit()
If TimerID <> 0 Then Call DeactivateTimer ''Turn off timer upon quitting
End Sub
Private Sub Application_Reminder(ByVal Item As Object)
Call EventMacro
End Sub
Luego el código del módulo actualizado ...
Declare Function SetTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent _
As Long, ByVal uElapse As Long, ByVal lpTimerfunc As Long) As Long
Declare Function KillTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent _
As Long) As Long
Private Declare Function FindWindowA Lib "user32" (ByVal lpClassName _
As String, ByVal lpWindowName As String) As Long
Private Declare Function SetWindowPos Lib "user32" (ByVal hwnd As Long, ByVal _
hWndInsertAfter As Long, ByVal X As Long, ByVal Y As Long, ByVal cx As Long, _
ByVal cy As Long, ByVal wFlags As Long) As Long
Private Const SWP_NOSIZE = &H1
Private Const SWP_NOMOVE = &H2
Private Const FLAGS As Long = SWP_NOMOVE Or SWP_NOSIZE
Private Const HWND_TOPMOST = -1
Public TimerID As Long ''Need a timer ID to eventually turn off the timer.
'' If the timer ID <> 0 then the timer is running
Public Sub ActivateTimer(ByVal nSeconds As Long)
nSeconds = nSeconds * 1000
''The SetTimer call accepts milliseconds, so convert from seconds
If TimerID <> 0 Then Call DeactivateTimer
''Check to see if timer is running before call to SetTimer
TimerID = SetTimer(0, 0, nSeconds, AddressOf TriggerTimer)
If TimerID = 0 Then MsgBox "The timer failed to activate."
End Sub
Public Sub DeactivateTimer()
Dim lSuccess As Long
lSuccess = KillTimer(0, TimerID)
If lSuccess = 0 Then
MsgBox "The timer failed to deactivate."
Else
TimerID = 0
End If
End Sub
Public Sub TriggerTimer(ByVal hwnd As Long, ByVal uMsg As Long, _
ByVal idevent As Long, ByVal Systime As Long)
Call EventMacro
End Sub
Public Sub EventMacro()
Dim ReminderWindowHWnd As Variant
On Error Resume Next
ReminderWindowHWnd = FindReminderWindow(10)
If ReminderWindowHWnd <> 0 Then
SetWindowPos ReminderWindowHWnd, HWND_TOPMOST, 0, 0, 0, 0, FLAGS
If TimerID <> 0 Then Call DeactivateTimer
End If
ReminderWindowHWnd = Nothing
End Sub
Private Function FindReminderWindow(iUB As Integer) As Variant
Dim i As Integer: i = 1
FindReminderWindow = FindWindowA(vbNullString, "1 Reminder")
Do While i < iUB And FindReminderWindow = 0
FindReminderWindow = FindWindowA(vbNullString, i & " Reminder(s)")
i = i + 1
Loop
End Function
ACTUALIZACIÓN 3 (8 de agosto de 2016) : Después de haber repensado mi enfoque y basado en la observación, rediseñé el código para intentar tener un impacto mínimo en el trabajo mientras Outlook estaba abierto. Descubriría que el cronómetro aún estaba alejado de los correos electrónicos que estaba escribiendo y posiblemente otros problemas con la pérdida de enfoque de Windows podrían estar relacionados.
En cambio, asumí que la ventana de recordatorios una vez que se creaba una instancia estaba simplemente oculta y no se destruye cuando se muestran los recordatorios; como tal, ahora mantengo un identificador global de la ventana, por lo que solo debo mirar los títulos de la ventana y luego verificar si la ventana de recordatorios es visible antes de hacerla modal.
Además, el temporizador ahora solo se emplea cuando se activa la ventana de recordatorios, luego se apaga una vez que la función se ha ejecutado; Esperemos que detenga cualquier macro intrusivo durante la jornada laboral.
Ver cuál funciona para ti, supongo ...
Código actualizado a continuación: agregue el siguiente código al módulo ''ThisOutlookSession''
Private WithEvents MyReminders As Outlook.Reminders
Private Sub Application_Startup()
On Error Resume Next
Set MyReminders = Outlook.Application.Reminders
End Sub
Private Sub MyReminders_ReminderFire(ByVal ReminderObject As Reminder)
On Error Resume Next
Call ActivateTimer(1)
End Sub
Luego el código del módulo actualizado ...
Option Explicit
Private Declare Function SetTimer Lib "User32" (ByVal hWnd As Long, ByVal nIDEvent As Long, _
ByVal uElapse As Long, ByVal lpTimerfunc As Long) As Long
Private Declare Function KillTimer Lib "User32" (ByVal hWnd As Long, ByVal nIDEvent As Long) As Long
Private Declare Function IsWindowVisible Lib "User32" (ByVal hWnd As Long) As Long
Private Declare Function FindWindow Lib "User32" Alias "FindWindowA" (ByVal lpClassName _
As String, ByVal lpWindowName As String) As Long
Private Declare Function ShowWindow Lib "User32" (ByVal hWnd As Long, ByVal nCmdSHow As Long) As Long
Private Declare Function SetWindowPos Lib "User32" (ByVal hWnd As Long, ByVal hWndInsertAfter As Long, _
ByVal X As Long, ByVal Y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
Private Const SWP_NOSIZE = &H1
Private Const SWP_NOMOVE = &H2
Private Const FLAGS As Long = SWP_NOMOVE Or SWP_NOSIZE
Private Const HWND_TOPMOST = -1
Public TimerID As Long ''Need a timer ID to turn off the timer. If the timer ID <> 0 then the timer is running
Public hRemWnd As Long ''Store the handle of the reminder window
Public Sub ActivateTimer(ByVal Seconds As Long) ''The SetTimer call accepts milliseconds
On Error Resume Next
If TimerID <> 0 Then Call DeactivateTimer ''Check to see if timer is running before call to SetTimer
If TimerID = 0 Then TimerID = SetTimer(0, 0, Seconds * 1000, AddressOf TriggerEvent)
End Sub
Public Sub DeactivateTimer()
On Error Resume Next
Dim Success As Long: Success = KillTimer(0, TimerID)
If Success <> 0 Then TimerID = 0
End Sub
Public Sub TriggerEvent(ByVal hWnd As Long, ByVal uMsg As Long, ByVal idevent As Long, ByVal Systime As Long)
Call EventFunction
End Sub
Public Function EventFunction()
On Error Resume Next
If TimerID <> 0 Then Call DeactivateTimer
If hRemWnd = 0 Then hRemWnd = FindReminderWindow(100)
If IsWindowVisible(hRemWnd) Then
ShowWindow hRemWnd, 1 '' Activate Window
SetWindowPos hRemWnd, HWND_TOPMOST, 0, 0, 0, 0, FLAGS '' Set Modal
End If
End Function
Public Function FindReminderWindow(iUB As Integer) As Long
On Error Resume Next
Dim i As Integer: i = 1
FindReminderWindow = FindWindow(vbNullString, "1 Reminder")
Do While i < iUB And FindReminderWindow = 0
FindReminderWindow = FindWindow(vbNullString, i & " Reminder(s)")
i = i + 1
Loop
If FindReminderWindow <> 0 Then ShowWindow FindReminderWindow, 1
End Function