Making Sure Outlook Calendar Reminders Actually Pop-up in Windows 7

Introduction

In Windows 7, MS Outlook seems to be horribly bad at popping up calendar reminders when outlook doesn’t have focus. This can cause a series of problems from minor annoyances to missed meetings. As discussed in this StackExchange question, there are some relatively easy work arounds to this issue that I’ll elaborate on here. If you’ve never used Outlook’s VBA editor to extend it’s capabilities before, this article will take you through how to set up everything you’ll need to do, start to finish. If you’re already familiar with using VBA in Outlook, then you can just skip to Step 5 and paste in the code and you’ll be all set.

Step By Step

  • 1) Hit the Windows Key and type “certificate”
  • 2) Select Digital Certificate for VBA Projects and type in a name for your certificate and hit OK
  • 3) Open Outlook 2010 and Hit Alt + F11 to start the VBA editor
  • 4) In the Project Pane on the left, Expand Project1 > Microsoft Outlook Objects > and double click on ThisOutlookSession
  • 5) Paste in the following code exactly:
'ensures all reminder notices receive focus
Private Sub Application_Reminder(ByVal Item As Object)
    If TypeOf Item Is AppointmentItem Then
        Application.ActiveWindow.Activate
    End If
End Sub

Edit: Added New Better Code Below:

'Declare Functions From User32 Library  
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  

'Declare Constants  
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  

'Only show the message the first time  
Private messageAlreadyShown As Boolean  

'Finds Reminder Window and Brings to TopMost position  
Private Sub Application_Reminder(ByVal Item As Object)  
    On Error Resume Next  

    'show message box for first reminder  
    If Not messageAlreadyShown Then  
        MsgBox "First Reminder", vbSystemModal, ""  
        messageAlreadyShown = True  
    End If  

    'find reminder window  
    ReminderWindow = FindWindowA(vbNullString, "1 Reminder")  
    'bring reminder window to front  
    SetWindowPos ReminderWindow, HWND_TOPMOST, 0, 0, 0, 0, FLAGS  
End Sub 
  • 6) Sign the Macro by going to Tools > Digital Signature and clicking Choose
  • 7) Select the certificate you created earlier and hit OK
  • 8) Select OK again, hit Ctrl + S to save and exit the VBA window
  • 9) To Enable Macros, Go to File > Options and select Trust Center from the left window
  • 10) Run the Trust center by clicking the Trust Center Settings button on the right.
  • 11) From the Trust Center, select Macro Settings, and select “Notifications for digitally signed macros, all other macros disabled” and hit OK
  • 12) Exit Outlook - It will ask you if you want to save the project, click Yes
  • 13) Start Outlook - It will give you a security notice. Select “Trust all documents from this publisher” (You can first confirm that you are the publisher by selecting “Show Signature Details”)
  • 14) That’s it! You’re all set. You never have to touch any of that code again or miss another meeting (unintentionally)

UPDATE!

I’ve update the code to use ActiveWindow instead of ActiveExplorer, which returns nothing “if no explorer is active.” Thanks to CW for the impetus to update my code.

20 comments:

  1. Is anything special needed in order to enable this feature to work. I followed the instructions exactly, and the reminder still does not pop up on top of other windows...

    ReplyDelete
    Replies
    1. Hey Jason, I added an update that should work better. Thanks for your feedback. Let me know how everything works out.

      Delete
  2. Worked perfectly. Thank you, thank you, thank you. This was driving me crazy.

    ReplyDelete
  3. This is really good thanks.
    Just one question it does not seem to work on the first reminder after the PC has been booted. Once the first reminder has been accepted all subsequent reminders work just fine. I have temporally resolved this issue by setting a daily reminder early each morning so it pops up when I start outlook, this is Ok but a bit ugly, is there anyway of modifying the code to resolve this nice & neatly
    Gary

    ReplyDelete
    Replies
    1. Gary, great work around. Nothing that I've found so far. I'll post any better solutions if I stumble across them. Please let me know if you find something as well and I'll post it here.

      Delete
    2. I have found another workaround for this; albeit slightly ugly. It essentially pops up a message box for the first reminder of the session, which somehow forces the first activation to work. I wouldn't deploy this accross an organization, but the crude fix works for my own computer. Thanks Kyle for posting this, it works great:

      'Delcare Functions From User32 Library
      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

      'Declare Constants
      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

      'Only show the message the first time
      Private messageAlreadyShown As Boolean

      'Finds Reminder Window and Brings to TopMost position
      Private Sub Application_Reminder(ByVal Item As Object)
      On Error Resume Next

      If Not messageAlreadyShown Then
      MsgBox "First Reminder", vbSystemModal, ""
      End If
      messageAlreadyShown = True

      ReminderWindow = FindWindowA(vbNullString, "1 Reminder")
      SetWindowPos ReminderWindow, HWND_TOPMOST, 0, 0, 0, 0, FLAGS
      End Sub

      Delete
    3. Thanks! This is a great quick fix. I've updated the post to include these changes.

      Delete
  4. Your code in step 5 worked for me, thanks. The longer recommended code did not work. I did have a few issues I was hoping you could comment on.

    1. This code opens up Outlook, rather than the reminder window. Is there any way to open up the reminder window itself? Another possibility is to use the code from the StackExchange thread you referenced to replace your 'Application.ActiveWindow.Activate' with a message box.

    Downside of this is that it is just a generic message.

    2. I know the main concern is appointments, but how would you modify the code to take all reminders into account? For example, what if you added a reminder directly to a message in your inbox?

    ReplyDelete
    Replies
    1. Hi JB,
      For 1), the last resort is to just display a message box. It's boring and dull, but it forces the application to receive focus in order to display the message box, which in turn, allows the reminder message to display. However this isn't maximally convenient because you then have to close two messages every time a reminder pops up and the point of this code was to get things to work correctly the first time as you'd expect they should. For anyone reading, just use this in your reminder event:

      MsgBox "Message text", vbSystemModal, "Message title"

      For 2), If you wanted it to work will all reminder items (AppointmentItem, MailItem, ContactItem, and TaskItem as per per Reminder Event, then you can just remove the following IF Block from the handling and it will fire for every event, although typically Appointment Items bear the most pertinent information.

      If TypeOf Item Is AppointmentItem Then

      I'm afraid I've been unable to fine tune it past what code I have so far. There's only so much to do to override what Windows is trying really hard to force upon the user.

      Delete
    2. Thanks Kyle - By the way, your write-up was excellent. I did a lot of research on this topic, and this is the only article that pulls everything together so that anyone benefit from it (even non-coders like me).

      Delete
  5. This works well however if reminder has come up and the reminder window then minmised, additional reminders don't bring the window up again.

    ReplyDelete
    Replies
    1. I get the same issue as this, I guess the workaround is to make sure you close it everytime and not just minimise which is easier said than done!

      Delete
  6. Hey, i am using outlook2007 and the above code is not working for me. It gives me an compliation error for ptrsafe function. It states that function or sub-function expected. Can you please help me.

    ReplyDelete
  7. Just wanted to give you a big THANK YOU for this!!!

    ReplyDelete
  8. Thank you!!!!! I was missing meetings after installing Outlook 2013.

    ReplyDelete
  9. This comment has been removed by the author.

    ReplyDelete
  10. This only works if there is only 1 reminder, because the Window name changes every time. If there is more than 1, then subsequent reminders don't pop on top. I made a loop that goes through 1-10, until it finds one. Probably a much way of doing this, but I'd don't really code stuff like this anymore.

    ReplyDelete
  11. Did the same as jeff suggested with a limit of 20, also its for OL 2013 ( 'n Reminder(s)' )

    here is the code:

    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
    Dim cnt As Long
    On Error Resume Next
    cnt = 1
    Do Until (cnt > 20 Or ReminderWindowHWnd <> 0)
    ReminderWindowHWnd = FindWindowA(vbNullString, cnt & " Reminder(s)")
    cnt = cnt + 1
    Loop
    SetWindowPos ReminderWindowHWnd, HWND_TOPMOST, 0, 0, 0, 0, FLAGS
    End Sub

    ReplyDelete