Как сделать всплывающее окно напоминания outlook поверх других окон
Как сделать всплывающее окно напоминания outlook поверх других окон?
после долгого поиска в Интернете; я не смог найти удовлетворительного ответа на этот вопрос.
с помощью Windows 7 и Microsoft Outlook 2007+; когда напоминание вспыхивает, он больше не дает модальное поле, чтобы привлечь ваше внимание. На работе, где дополнительные плагины могут быть проблематичными для установки (права администратора) и при использовании тихой системы, часто встречаются запросы упущенный.
есть ли более простой способ реализовать это, чем использование сторонних плагинов / приложений?
8 ответов
* для последнего макроса см. обновление 3*
после поиска некоторое время я нашел частичный ответ на веб-сайте, который, казалось, дал мне большую часть решения; https://superuser.com/questions/251963/how-to-make-outlook-calendar-reminders-stay-on-top-in-windows-7
однако, как отмечено в комментариях, первое напоминание не появилось; в то время как дальнейшие напоминания затем сделали. основываясь на коде, я предположил, что это потому, что окно не было обнаружено, пока оно не было создано один раз
Outlook VBA-запускайте код каждые полчасазатем объединение двух решений вместе дало рабочее решение этой проблемы.
из центра доверия я включил использование макросов, а затем открыл редактор visual basic из Outlook (alt+F11) я добавил следующий код в модуль "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
затем добавлен модуль и добавлен следующий код
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
вот и все; каждые 5 секунд таймер проверяет, существует ли окно с надписью "1 напоминание", а затем ударяет его наверх...
обновление (12 февраля 2015): после использования этого некоторое время я нашел реальную досаду с тот факт, что запуск таймера удаляет фокус из текущего окна. Это огромная проблема, как вы пишете по электронной почте.
таким образом, я обновил код, так что таймер работает только каждые 60 секунд, а затем при поиске первого активного напоминания таймер останавливается, а функция вторичного события затем используется для активации изменения фокуса окна.
обновление 2 (4 сентября 2015): имея перешло к В Outlook 2013 - этот код перестал работать для меня. Теперь я обновил его с помощью дополнительной функции (FindReminderWindow), которая ищет диапазон всплывающих напоминаний. Теперь это работает для меня в 2013 году и должно работать для версий ниже 2013 года.
функция FindReminderWindow принимает значение, которое представляет собой количество итераций, чтобы пройти, чтобы найти окно. Если у вас обычно больше напоминаний, чем всплывающее окно 10, вы можете увеличить это число в EventMacro подводная лодка...
обновленный код ниже: Добавьте следующий код в модуль '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
затем обновленный код модуля...
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
обновление 3 (8 августа, 2016): переосмыслив свой подход и основываясь на наблюдении - я переработал код, чтобы попытаться оказать минимальное влияние на работу, пока Outlook был открыт; я бы обнаружил, что таймер все еще отвлек внимание от электронной почты, которую я писал, и, возможно, другие проблемы с Windows, потеряв фокус, возможно, были связаны.
вместо этого-я предположил, что окно напоминаний, когда-то созданное, было просто скрыто и не уничтожено при отображении напоминаний; поэтому теперь я держу глобальный дескриптор окна, поэтому мне нужно только один раз взглянуть на заголовки окон и впоследствии проверить, видно ли окно напоминаний, прежде чем сделать его модальным.
кроме того - таймер теперь используется только при запуске окна напоминания, а затем повернул выключено после запуска функции; надеюсь, остановив любой навязчивый макрос работает в течение рабочего дня.
посмотреть, какой из них работает для вас, я думаю...
обновленный код ниже: Добавьте следующий код в модуль '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
затем обновленный код модуля...
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
С помощью AutoHotKey вы можете установить окно, чтобы быть всегда на вершине без кражи фокуса текущего окна. (Протестировано с 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
}
Я нашел бесплатную программу под названием PinMe! это будет делать именно то, что я хочу. Когда появится напоминание Outlook, щелкните правой кнопкой мыши на PinMe! в системном трее выберите Окно напоминания. Рядом с окном появится значок блокировки. Продолжайте отклонять или откладывать напоминание. В следующий раз, когда напоминание появится, оно должно появиться перед каждым другим окном. Это будет работать независимо от Outlook на переднем плане или свернуто.
У меня есть Office 2013 и Windows 8.1 Pro. Многие макросы, которые я нашел, не обрабатывали переменный характер заголовков Outlook в диалоговом окне напоминания. Когда у вас есть 1 напоминание, название "1 напоминание(Ы)" и т. д. Я создал простое приложение windows forms в VB.NET, который я загружаю при запуске и минимизирую в системном трее. В форму добавлен таймер 60, который запускает активный код. При наличии более 0 напоминаний диалоговое окно будет установлено в верхний и перемещено в 0,0.
вот код:
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
Outlook 2016 теперь предоставляет возможность "показывать" напоминания "поверх других окон". Использовать Файл > Параметры > Дополнительно, а затем установите флажок в разделе напоминания. Смотрите этоsupport.office.com страница на скриншоте. Эта опция была добавлена в версия 1804 Outlook 2016, выпущенный на" ежемесячный канал " 25 апреля 2018 года.
этот параметр Outlook 2016 помещает напоминание поверх всех приложений только изначально. Мне нравится keep напоминание сверху, пока я явно не уволю, даже если я нажму какое-то другое окно. К keep напоминание сверху я настоятельно рекомендую @Tragamor's принято отвечать по этому вопросу. Но если ответ @Tragamor кажется слишком сложным, и вы в порядке с напоминанием, находящимся сверху только изначально, опция теперь в Outlook 2016 очень проста.
Это должно работать в разных версиях Outlook, даже если я тестировал его только в Outlook 2013.
поскольку я не могу протестировать его в локализованной английской версии, вам может потребоваться настроить строки кода, связанные с поиском в окне напоминания, даже если в моем ответе я изменил связанные строки кода, чтобы найти окно в локализованной версии на английском языке.
Дайте мне знать, если макрос работает в английской версии Outlook.
пользователь может минимизировать или закройте окно напоминания.в этом случае при запуске нового или существующего напоминания окно напоминания будет самым верхним и не будет активировано.
заголовок окна напоминания всегда будет обновляться, отражая реальное количество видимых напоминаний, даже без его активации.
во всех случаях окно напоминания никогда не будет красть фокус, если, очевидно, окно переднего плана окно напоминания, то есть, если пользователь сознательно не выбрал напоминания окно.
этот макрос, кроме создания окна напоминания сверху, также выберет самое последнее напоминание в самом окне напоминания, вы можете настроить это поведение, пожалуйста, прочитайте код, чтобы иметь возможность сделать это.
макрос также мигает окно напоминания при первом отображении окна и при повторном запуске нового или существующего напоминания.
вы можете настроить, сколько раз мигает окно или любые другие параметры в связи с этим должно быть ясно, как это сделать.
вставьте следующие строки кода в модуль класса '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
вставьте следующий код в новый или существующий стандартный модуль:
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
в последнем Outlook эта функция встроена, и то же самое отвечает вhttps://superuser.com/a/1327856/913992
после вдохновения ответ Эрика Лабашовского, Я взял его концепцию на шаг дальше и создал приложение NotifyWhenMicrosoftOutlookReminderwindowisopen, который вы можете скачать бесплатно. Это небольшой исполняемый файл, который может обеспечить окно напоминания Outlook появляется поверх других окон, а также имеет некоторые другие дополнительные способы оповещения пользователя, что окно открыто.