Show Windows 10 native clock widget programmatically Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
VarunAgw
Posts: 25
Joined: 05 Jan 2016, 11:51
Contact:

Show Windows 10 native clock widget programmatically

08 Aug 2016, 13:34

So I use a clock replacement program. The problem is it also hijack clicks on the clock. So whenever I click on the clock in the notification area, program's popup menu launch rather than the default windows clock widget.

I also tried "ControlClick" on "TrayClockWClass". I still didn't get original widget. Is there any way to launch the original widget programmatically? I use Windows 10 1607.
qwerty12
Posts: 468
Joined: 04 Mar 2016, 04:33
Contact:

Re: Show Windows 10 native clock widget programmatically

11 Aug 2016, 10:57

If you're running a 64-bit version of AutoHotkey (this doesn't work with 32-bit; I guess I'm doing something wrong with the VARIANT structure somewhere) - fixed thanks to Eidola, this works with the clock replacement program I use to show the original clock hosted by the Explorer process:

Code: Select all

ControlGet, hClock, Hwnd,, TrayClockWClass1, ahk_class Shell_TrayWnd ; https://autohotkey.com/board/topic/70770-win7-taskbar-clock-toggle/
if (hClock) {
	VarSetCapacity(IID_IAccessible, 16), DllCall("ole32\CLSIDFromString", "WStr", "{618736e0-3c3d-11cf-810c-00aa00389b71}", "Ptr", &IID_IAccessible)
	if (DllCall("oleacc\AccessibleObjectFromWindow", "Ptr", hClock, "UInt", OBJID_CLIENT := 0xFFFFFFFC, "Ptr", &IID_IAccessible, "Ptr*", accTrayClock))
		return
	VarSetCapacity(variant, A_PtrSize == 8 ? 24 : 16, 0), NumPut(VT_I4 := 3, variant,, "UShort")
	if (A_PtrSize == 4) ; https://autohotkey.com/boards/viewtopic.php?p=111355#p111355
		DllCall(NumGet(NumGet(accTrayClock+0)+25*A_PtrSize), "Ptr", accTrayClock, "Int64", NumGet(variant, 0, "Int64"), Int64, NumGet(variant, 8, "Int64")) ; IAccessible::DoDefaultAction
	else
		DllCall(NumGet(NumGet(accTrayClock+0)+25*A_PtrSize), "Ptr", accTrayClock, "Ptr", &variant) ; IAccessible::DoDefaultAction
	ObjRelease(accTrayClock)
}
or if you're using the same program as I do, you could try

Code: Select all

ControlGet, hClock, Hwnd,, TrayClockWClass1, ahk_class Shell_TrayWnd ; https://autohotkey.com/board/topic/70770-win7-taskbar-clock-toggle/
PostMessage, 0x466, 1, 0,, ahk_id %hClock%
Last edited by qwerty12 on 19 Oct 2016, 09:28, edited 1 time in total.
VarunAgw
Posts: 25
Joined: 05 Jan 2016, 11:51
Contact:

Re: Show Windows 10 native clock widget programmatically

13 Aug 2016, 08:12

qwerty12 wrote:If you're running a 64-bit version of AutoHotkey (this doesn't work with 32-bit; I guess I'm doing something wrong with the VARIANT structure somewhere), this works with the clock replacement program I use to show the original clock hosted by the Explorer process:

Code: Select all

ControlGet, hClock, Hwnd,, TrayClockWClass1, ahk_class Shell_TrayWnd ; https://autohotkey.com/board/topic/70770-win7-taskbar-clock-toggle/
if (hClock) {
	VarSetCapacity(IID_IAccessible, 16), DllCall("ole32\CLSIDFromString", "WStr", "{618736e0-3c3d-11cf-810c-00aa00389b71}", "Ptr", &IID_IAccessible)
	if (DllCall("oleacc\AccessibleObjectFromWindow", "Ptr", hClock, "UInt", OBJID_CLIENT := 0xFFFFFFFC, "Ptr", &IID_IAccessible, "Ptr*", accTrayClock))
		return
	VarSetCapacity(variant, A_PtrSize == 8 ? 24 : 16, 0), NumPut(VT_I4 := 3, variant,, "UShort")
	DllCall(NumGet(NumGet(accTrayClock+0)+25*A_PtrSize), "Ptr", accTrayClock, "Ptr", &variant) ; IAccessible::DoDefaultAction
	ObjRelease(accTrayClock)
}
Thanks a lot! It worked perfectly
VarunAgw
Posts: 25
Joined: 05 Jan 2016, 11:51
Contact:

Re: Show Windows 10 native clock widget programmatically

05 May 2020, 06:53

qwerty12 wrote:
11 Aug 2016, 10:57
If you're running a 64-bit version of AutoHotkey (this doesn't work with 32-bit; I guess I'm doing something wrong with the VARIANT structure somewhere) - fixed thanks to Eidola, this works with the clock replacement program I use to show the original clock hosted by the Explorer process:

Code: Select all

ControlGet, hClock, Hwnd,, TrayClockWClass1, ahk_class Shell_TrayWnd ; https://autohotkey.com/board/topic/70770-win7-taskbar-clock-toggle/
if (hClock) {
	VarSetCapacity(IID_IAccessible, 16), DllCall("ole32\CLSIDFromString", "WStr", "{618736e0-3c3d-11cf-810c-00aa00389b71}", "Ptr", &IID_IAccessible)
	if (DllCall("oleacc\AccessibleObjectFromWindow", "Ptr", hClock, "UInt", OBJID_CLIENT := 0xFFFFFFFC, "Ptr", &IID_IAccessible, "Ptr*", accTrayClock))
		return
	VarSetCapacity(variant, A_PtrSize == 8 ? 24 : 16, 0), NumPut(VT_I4 := 3, variant,, "UShort")
	if (A_PtrSize == 4) ; https://autohotkey.com/boards/viewtopic.php?p=111355#p111355
		DllCall(NumGet(NumGet(accTrayClock+0)+25*A_PtrSize), "Ptr", accTrayClock, "Int64", NumGet(variant, 0, "Int64"), Int64, NumGet(variant, 8, "Int64")) ; IAccessible::DoDefaultAction
	else
		DllCall(NumGet(NumGet(accTrayClock+0)+25*A_PtrSize), "Ptr", accTrayClock, "Ptr", &variant) ; IAccessible::DoDefaultAction
	ObjRelease(accTrayClock)
}
or if you're using the same program as I do, you could try

Code: Select all

ControlGet, hClock, Hwnd,, TrayClockWClass1, ahk_class Shell_TrayWnd ; https://autohotkey.com/board/topic/70770-win7-taskbar-clock-toggle/
PostMessage, 0x466, 1, 0,, ahk_id %hClock%
Hello, Sadly the code is broken now. AHK crash whenever I call this function on this statement "DllCall(NumGet(NumGet(accTrayClock+0)+25*A_PtrSize), "Ptr", accTrayClock, "Ptr", &variant)". If you get a chance, can you please look into it.
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: Show Windows 10 native clock widget programmatically

05 May 2020, 07:19

I recommend You to load all dlls that You use except of User32.dll, Kernel32.dll, ComCtl32.dll, or Gdi32.dll.
teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

Re: Show Windows 10 native clock widget programmatically  Topic is solved

05 May 2020, 07:28

For me this works:

Code: Select all

ControlGet, hClock, hwnd,, TrayClockWClass1, ahk_class Shell_TrayWnd
accClock := AccObjectFromWindow(hClock, OBJID_CLIENT := 0xFFFFFFFC)
accClock.accDoDefaultAction(0)

AccObjectFromWindow(hWnd, idObject = 0) {
   static IID_IDispatch   := "{00020400-0000-0000-C000-000000000046}"
        , IID_IAccessible := "{618736E0-3C3D-11CF-810C-00AA00389B71}"
        , OBJID_NATIVEOM  := 0xFFFFFFF0, VT_DISPATCH := 9, F_OWNVALUE := 1
        , h := DllCall("LoadLibrary", "Str", "oleacc", "Ptr")
        
   VarSetCapacity(IID, 16), idObject &= 0xFFFFFFFF
   DllCall("ole32\CLSIDFromString", "Str", idObject = OBJID_NATIVEOM ? IID_IDispatch : IID_IAccessible, "Ptr", &IID)
   if DllCall("oleacc\AccessibleObjectFromWindow", "Ptr", hWnd, "UInt", idObject, "Ptr", &IID, "PtrP", pAcc) = 0
      Return ComObject(VT_DISPATCH, pAcc, F_OWNVALUE)
}
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: Show Windows 10 native clock widget programmatically

05 May 2020, 07:31

Without using comobject it also works.
Just need to add

Code: Select all

DllCall("LoadLibrary", "Str", "oleacc", "Ptr")
teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

Re: Show Windows 10 native clock widget programmatically

05 May 2020, 07:36

malcev wrote: Without using comobject
I haven't understood why qwerty12 didn't use a com object approach.
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: Show Windows 10 native clock widget programmatically

05 May 2020, 07:41

I do not know too.
But I think that it is good example for understanding how to work with com interfaces.
User avatar
JoeWinograd
Posts: 2179
Joined: 10 Feb 2014, 20:00
Location: U.S. Central Time Zone

Re: Show Windows 10 native clock widget programmatically

05 May 2020, 10:57

teadrinker wrote:
05 May 2020, 07:28
For me this works:
Hi teadrinker,
That is superb code! It works perfectly here on W10 V1909 and V2004. Would you be able to modify that code to expose the W10 horizontal volume slider instead of the clock? You've helped me before with code to enhance my own GUI horizontal volume slider, but I'm wondering if it is possible to expose the native horizontal volume slider programmatically. Thanks again for your help. Regards, Joe
teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

Re: Show Windows 10 native clock widget programmatically

05 May 2020, 13:27

Hi Joe,
I think it's possible, but I'm not sure that an universal method exists. It depends on what process is associated with the icon, clicking on which you can call up a window with a slider. For me it's RtkNGUI64.exe. You need to know yours.
User avatar
JoeWinograd
Posts: 2179
Joined: 10 Feb 2014, 20:00
Location: U.S. Central Time Zone

Re: Show Windows 10 native clock widget programmatically

05 May 2020, 13:48

Hi teadrinker,
I need a universal method that works on all W10 systems without having to know what each user's EXE is. I'll stick with my own GUI, which is working beautifully since I added your code...does not crash...does not freeze. Regards, Joe
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: Show Windows 10 native clock widget programmatically

05 May 2020, 16:51

If You need universal method then it will be better to use UI Automation because there You can find elements with AutomationID property.
Or You can find position of volume button with its guid (it is equal AutomationID) and then sending clicks with postmessage, but at this case You have to run ahk with the same bitness as Your system.
User avatar
JoeWinograd
Posts: 2179
Joined: 10 Feb 2014, 20:00
Location: U.S. Central Time Zone

Re: Show Windows 10 native clock widget programmatically

05 May 2020, 20:51

Hi malcev,
Thanks for the comment. What I'm looking for is a way to expose the W10 horizontal volume slider programmatically. A simple left-click on the speaker icon in the system tray does it, but what I want is to do that with AHK code. Once it's exposed, left and right arrow keys will adjust the volume. Regards, Joe
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: Show Windows 10 native clock widget programmatically

05 May 2020, 20:57

With UIA it can be done like this:

Code: Select all

f11::
if !hVolume
{
   ControlGet, hVolume, hwnd,, ToolbarWindow323, ahk_class Shell_TrayWnd
   IUIAutomation := ComObjCreate(CLSID_CUIAutomation := "{ff48dba4-60ef-4201-aa87-54103eef594e}", IID_IUIAutomation := "{30cbe57d-d9d0-452a-ab13-7ac5ac4825ee}")
   DllCall(NumGet(NumGet(IUIAutomation+0)+6*A_PtrSize), "ptr", IUIAutomation, "ptr", hVolume, "ptr*", tray)   ; IUIAutomation::ElementFromHandle
   VOLUME_GUID := DllCall("oleaut32\SysAllocString", "str", "{7820AE73-23E3-4229-82C1-E41CB67D5B9C}", "ptr")
   VarSetCapacity(variant, 8+A_PtrSize*2, 0)
   NumPut(VT_BSTR := 8, variant, 0, "ushort")
   NumPut(VOLUME_GUID, variant, 8, "ptr")
   if (A_PtrSize = 4)
      DllCall(NumGet(NumGet(IUIAutomation+0)+23*A_PtrSize), "ptr", IUIAutomation, "int", UIA_AutomationIdPropertyId := 30011, "int64", NumGet(variant, 0, "int64"), "int64", NumGet(variant, 8, "int64"), "ptr*", condition)   ; IUIAutomation::CreatePropertyCondition
   else
      DllCall(NumGet(NumGet(IUIAutomation+0)+23*A_PtrSize), "ptr", IUIAutomation, "int", UIA_AutomationIdPropertyId := 30011, "ptr", &variant, "ptr*", condition)   ; IUIAutomation::CreatePropertyCondition
   DllCall("oleaut32\SysFreeString", "ptr", VOLUME_GUID)
   VarSetCapacity(GUID, 16)
   DllCall("ole32\CLSIDFromString", "wstr", IID_IUIAutomationLegacyIAccessiblePattern := "{828055ad-355b-4435-86d5-3b51c14a9b1b}", "ptr", &GUID)
}
DllCall(NumGet(NumGet(tray+0)+5*A_PtrSize), "ptr", tray, "int", TreeScope_Descendants := 0x4, "ptr", condition, "ptr*", element) ; IUIAutomationElement::FindFirst
DllCall(NumGet(NumGet(element+0)+14*A_PtrSize), "ptr", element, "int", UIA_LegacyIAccessiblePatternId := 10018, "ptr", &GUID, "ptr*", legacy)   ; IUIAutomationElement::GetCurrentPatternAs
DllCall(NumGet(NumGet(legacy+0)+4*A_PtrSize), "ptr", legacy)   ; IUIAutomationLegacyIAccessiblePattern::DoDefaultAction
ObjRelease(element)
ObjRelease(legacy)
User avatar
JoeWinograd
Posts: 2179
Joined: 10 Feb 2014, 20:00
Location: U.S. Central Time Zone

Re: Show Windows 10 native clock widget programmatically

05 May 2020, 21:33

Thanks very much, malcev, tested on W10 V1909 and V2004...works perfectly! Regards, Joe
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: Show Windows 10 native clock widget programmatically

16 May 2020, 15:36

May be it is better to use invoke method instead of legacy dodefaultaction.

Code: Select all

f11::
if !hVolume
{
   ControlGet, hVolume, hwnd,, ToolbarWindow323, ahk_class Shell_TrayWnd
   IUIAutomation := ComObjCreate(CLSID_CUIAutomation := "{ff48dba4-60ef-4201-aa87-54103eef594e}", IID_IUIAutomation := "{30cbe57d-d9d0-452a-ab13-7ac5ac4825ee}")
   DllCall(NumGet(NumGet(IUIAutomation+0)+6*A_PtrSize), "ptr", IUIAutomation, "ptr", hVolume, "ptr*", tray)   ; IUIAutomation::ElementFromHandle
   VOLUME_GUID := DllCall("oleaut32\SysAllocString", "str", "{7820AE73-23E3-4229-82C1-E41CB67D5B9C}", "ptr")
   VarSetCapacity(variant, 8+A_PtrSize*2, 0)
   NumPut(VT_BSTR := 8, variant, 0, "ushort")
   NumPut(VOLUME_GUID, variant, 8, "ptr")
   if (A_PtrSize = 4)
      DllCall(NumGet(NumGet(IUIAutomation+0)+23*A_PtrSize), "ptr", IUIAutomation, "int", UIA_AutomationIdPropertyId := 30011, "int64", NumGet(variant, 0, "int64"), "int64", NumGet(variant, 8, "int64"), "ptr*", condition)   ; IUIAutomation::CreatePropertyCondition
   else
      DllCall(NumGet(NumGet(IUIAutomation+0)+23*A_PtrSize), "ptr", IUIAutomation, "int", UIA_AutomationIdPropertyId := 30011, "ptr", &variant, "ptr*", condition)   ; IUIAutomation::CreatePropertyCondition
   DllCall("oleaut32\SysFreeString", "ptr", VOLUME_GUID)
}
DllCall(NumGet(NumGet(tray+0)+5*A_PtrSize), "ptr", tray, "int", TreeScope_Descendants := 0x4, "ptr", condition, "ptr*", element) ; IUIAutomationElement::FindFirst
DllCall(NumGet(NumGet(element+0)+16*A_PtrSize), "ptr", element, "int", UIA_InvokePatternId := 10000, "ptr*", invoke)   ; IUIAutomationElement::GetCurrentPattern
DllCall(NumGet(NumGet(invoke+0)+3*A_PtrSize), "ptr", invoke)   ; IInvokeProvider::Invoke
ObjRelease(element)
ObjRelease(invoke)
User avatar
JoeWinograd
Posts: 2179
Joined: 10 Feb 2014, 20:00
Location: U.S. Central Time Zone

Re: Show Windows 10 native clock widget programmatically

16 May 2020, 16:46

Hi malcev,
I tested the Invoke method script on V1909. It works perfectly, but so does the legacy DoDefaultAction one. I don't know if one is better to use than the other, but, generally speaking, you're right that it's better to use a current method than a legacy method. Thanks for your follow-up and extra effort on this...very much appreciated! Regards, Joe
VarunAgw
Posts: 25
Joined: 05 Jan 2016, 11:51
Contact:

Re: Show Windows 10 native clock widget programmatically

24 May 2020, 08:50

teadrinker wrote:
05 May 2020, 07:28
For me this works:

Code: Select all

ControlGet, hClock, hwnd,, TrayClockWClass1, ahk_class Shell_TrayWnd
accClock := AccObjectFromWindow(hClock, OBJID_CLIENT := 0xFFFFFFFC)
accClock.accDoDefaultAction(0)

AccObjectFromWindow(hWnd, idObject = 0) {
   static IID_IDispatch   := "{00020400-0000-0000-C000-000000000046}"
        , IID_IAccessible := "{618736E0-3C3D-11CF-810C-00AA00389B71}"
        , OBJID_NATIVEOM  := 0xFFFFFFF0, VT_DISPATCH := 9, F_OWNVALUE := 1
        , h := DllCall("LoadLibrary", "Str", "oleacc", "Ptr")
        
   VarSetCapacity(IID, 16), idObject &= 0xFFFFFFFF
   DllCall("ole32\CLSIDFromString", "Str", idObject = OBJID_NATIVEOM ? IID_IDispatch : IID_IAccessible, "Ptr", &IID)
   if DllCall("oleacc\AccessibleObjectFromWindow", "Ptr", hWnd, "UInt", idObject, "Ptr", &IID, "PtrP", pAcc) = 0
      Return ComObject(VT_DISPATCH, pAcc, F_OWNVALUE)
}
Thank you for the answer. It worked!
VarunAgw
Posts: 25
Joined: 05 Jan 2016, 11:51
Contact:

Re: Show Windows 10 native clock widget programmatically

26 Nov 2021, 14:58

I am wondering if it's possible to update this code for Windows 11 clock widget? Thanks

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Google [Bot], OrangeCat and 130 guests