how to know if windows media player is playing or not? Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
partof
Posts: 110
Joined: 16 Jan 2016, 08:38

how to know if windows media player is playing or not?

23 Dec 2017, 08:13

I tried several codes (such as these https://autohotkey.com/board/topic/3079 ... yer/?&st=0 ) but they don't seem to work anymore (maybe they are not compatible anymore with the newer version of ahk 1.1.26.01 or with windows 10).


Anyone knows how to simply know if wmp is playing or not?


PS: the code linked above give this error:
Error: Call to nonexistent function.
Specifically: COM_Init()
Rindis
Posts: 213
Joined: 23 Dec 2013, 13:58
Location: Norway
Contact:

Re: how to know if windows media player is playing or not?

23 Dec 2017, 08:46

Have you downloaded https://autohotkey.com/board/topic/2114 ... d-library/ ? (and put it in the same folder as your script)
partof
Posts: 110
Joined: 16 Jan 2016, 08:38

Re: how to know if windows media player is playing or not?

23 Dec 2017, 10:31

Thanks for your help!
I guess I need to add

Code: Select all

#Include C:\Users\Me\Desktop\my_folder\COM.ahk
at the beginning of the script (which is on the same folder than the github file)

When I run it I get the error below (when I run the COM.ahk it sends the same error):

Code: Select all

Error:  Call to nonexistent function.

Specifically: errord("silent", "COM Error Notification", "Function Name:	""" . name . """
ERROR:	" . sError . "	("...

	Line#
	226: bDebug := hr
	228: Return,COM_HR&&COM_LR ? COM_LR<<32|COM_HR:COM_HR
	229: }
	230: Else
	230: if !bDebug  
	231: Return
	232: hr ? (VarSetCapacity(sError,1023),VarSetCapacity(nError,10),DllCall("kernel32\FormatMessageA","Uint",0x1000,"Uint",0,"Uint",hr<>0x80020009 ? hr : (bExcep:=1)*(hr:=NumGet(pei+28)) ? hr : hr:=NumGet(pei+0,0,"Ushort")+0x80040200,"Uint",0,"str",sError,"Uint",1024,"Uint",0),DllCall("user32\wsprintfA","str",nError,"str","0x%08X","Uint",hr,"Cdecl")) : sError:="The COM Object may not be a valid Dispatch Object!
	First ensure that COM Library has been initialized through COM_Init().
", lr ? (VarSe
--->	233: errord("silent", "COM Error Notification", "Function Name:	""" . name . """
ERROR:	" . sError . "	(" . nError . ")" . (bExcep ? SubStr(NumGet(pei+24) ? DllCall(NumGet(pei+24),"Uint",pei) : "",1,0) . "
PROG:	" . COM_Ansi4Unicode(NumGet(pei+4)) . COM_SysFreeString(NumGet(pei+4)) . "
DESC:	" . COM_Ansi4Unicode(NumGet(pei+8)) . COM_SysFreeString(NumGet(pei+8)) . "
HELP:	" . COM_Ansi4Unicode(NumGet(pei+12)) . COM_SysFreeString(NumGet(pei+12)) . "," . NumGet(pei+16) : "") . (lr ? "

ERROR2:	" .
	235: Exit
	236: }
	239: {
	241: if Not	VarSetCapacity(IDispatch)  
	242: {
	243: VarSetCapacity(IDispatch,28,0),   nParams=3112469  
	244: Loop,Parse,nParams

The program will exit.
Guest

Re: how to know if windows media player is playing or not?

23 Dec 2017, 12:27

It's getting close, the com.ahk is working (but the one from Sean here https://github.com/ttnnkkrr/COM.AHK/releases/tag/1.0, the one on github you gave me doesn't work).


But I get an new error.

I tried this code (the smallest):

Code: Select all

#Include C:\Users\Me\Desktop\Ahk\com.ahk
COM_Invoke(wmp, "currentPlaylist", [color=red]"+"[/color] playlist) 
; playlist is a COM object, so the prefix [color=red]+[/color] is required when used as a parameter.
controls := COM_Invoke(wmp, "controls")
COM_Invoke(controls, "play")
Sleep 3000
playState := COM_Invoke(wmp, "playState")
But I get this error

Code: Select all

---------------------------
COM Error Notification
---------------------------
Function Name:	"controls"
ERROR:	No COM Dispatch Object!
	()
partof
Posts: 110
Joined: 16 Jan 2016, 08:38

Re: how to know if windows media player is playing or not?

23 Dec 2017, 12:51

(Sorry, for some reason it posted as guest)


I tried that:

Code: Select all

#Include com.ahk
com_Init()
playState := COM_CreateObject(wmp, "playState")
MsgBox %playState%
and that

Code: Select all

#Include com.ahk
com_Init()
playState  := COM_Invoke(wmp, "playState")	
MsgBox %playState%



it sends nothing (the play is not detected)
I find this microsoft page, but I don't know how to use that information in the syntax
https://msdn.microsoft.com/en-us/librar ... 2147217396
qwerty12
Posts: 468
Joined: 04 Mar 2016, 04:33
Contact:

Re: how to know if windows media player is playing or not?  Topic is solved

24 Dec 2017, 10:40

This works here (Windows 10 1703 / WMP 12 / AutoHotkey x64 1.1.26.01), but given the complexity of performing such a simple task and my inexperience, I can't say it'll work for you.

Code: Select all

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
#SingleInstance Off

Process, Exist, wmplayer.exe
if (!ErrorLevel) {
	MsgBox Run Windows Media Player first. Exiting
	ExitApp
}

wmp := ComObjCreate("WMPlayer.OCX")

rms := IWMPRemoteMediaServices_CreateInstance()
ocs := ComObjQuery(rms, "{00000118-0000-0000-C000-000000000046}")

ole := ComObjQuery(wmp, "{00000112-0000-0000-C000-000000000046}")
DllCall(NumGet(NumGet(ole+0)+3*A_PtrSize), "Ptr", ole, "Ptr", ocs)

states := {0: "Undefined", 1: "Stopped", 2: "Paused", 3: "Playing"}
state := states[wmp.playState]

DllCall(NumGet(NumGet(ole+0)+3*A_PtrSize), "Ptr", ole, "Ptr", 0)
for _, obj in [ole, ocs, rms]
	ObjRelease(obj)
wmp := ""

MsgBox %state%

; ---

IWMPRemoteMediaServices_CreateInstance()
{
	global IWMPRemoteMediaServices_size := ((A_PtrSize + 4) * 4) + 4
	static vtblUnk, vtblRms, vtblIsp, vtblOls
		 , vtblPtrs := 0

	if (!VarSetCapacity(vtblUnk)) {
		extfuncs := ["QueryInterface", "AddRef", "Release"]

		VarSetCapacity(vtblUnk, extfuncs.Length() * A_PtrSize)

		for i, name in extfuncs
			NumPut(RegisterCallback("IUnknown_" . name), vtblUnk, (i-1) * A_PtrSize)
	}
	if (!VarSetCapacity(vtblRms)) {
		extfuncs := ["GetServiceType", "GetApplicationName", "GetScriptableObject", "GetCustomUIMode"]

		VarSetCapacity(vtblRms, (3 + extfuncs.Length()) * A_PtrSize)
		DllCall("ntdll\RtlMoveMemory", "Ptr", &vtblRms, "Ptr", &vtblUnk, "Ptr", A_PtrSize * 3)

		for i, name in extfuncs
			NumPut(RegisterCallback("IWMPRemoteMediaServices_" . name, "Fast"), vtblRms, (2+i) * A_PtrSize)
	}
	if (!VarSetCapacity(vtblIsp)) {
		VarSetCapacity(vtblIsp, 4 * A_PtrSize)
		DllCall("ntdll\RtlMoveMemory", "Ptr", &vtblIsp, "Ptr", &vtblUnk, "Ptr", A_PtrSize * 3)
		NumPut(RegisterCallback("IServiceProvider_QueryService", "Fast"), vtblIsp, A_PtrSize * 3)
	}
	if (!VarSetCapacity(vtblOls)) {
		extfuncs := ["SaveObject", "GetMoniker", "GetContainer", "ShowObject", "OnShowWindow", "RequestNewObjectLayout"]
		VarSetCapacity(vtblOls, (3 + extfuncs.Length()) * A_PtrSize)
		DllCall("ntdll\RtlMoveMemory", "Ptr", &vtblOls, "Ptr", &vtblUnk, "Ptr", A_PtrSize * 3)

		for i, name in extfuncs
			NumPut(RegisterCallback("IOleClientSite_" . name, "Fast"), vtblOls, (2+i) * A_PtrSize)
	}
	if (!vtblPtrs)
		vtblPtrs := [&vtblUnk, &vtblRms, &vtblIsp, &vtblOls]

	pObj := DllCall("GlobalAlloc", "UInt", 0x0000, "Ptr", IWMPRemoteMediaServices_size, "Ptr")
	for i, ptr in vtblPtrs {
		off := (A_PtrSize * (i - 1)) + (4 * (i - 1))
		NumPut(ptr, pObj+0, off, "Ptr")
		NumPut(off, pObj+0, off + A_PtrSize, "UInt")
	}
	NumPut(1, pObj+0, IWMPRemoteMediaServices_size - 4, "UInt")

	return pObj
}

IUnknown_QueryInterface(this_, riid, ppvObject)
{
	static IID_IUnknown, IID_IWMPRemoteMediaServices, IID_IServiceProvider, IID_IOleClientSite
	if (!VarSetCapacity(IID_IUnknown))
		VarSetCapacity(IID_IUnknown, 16), VarSetCapacity(IID_IWMPRemoteMediaServices, 16), VarSetCapacity(IID_IServiceProvider, 16), VarSetCapacity(IID_IOleClientSite, 16)
		,DllCall("ole32\CLSIDFromString", "WStr", "{00000000-0000-0000-C000-000000000046}", "Ptr", &IID_IUnknown)
		,DllCall("ole32\CLSIDFromString", "WStr", "{CBB92747-741F-44FE-AB5B-F1A48F3B2A59}", "Ptr", &IID_IWMPRemoteMediaServices)
		,DllCall("ole32\CLSIDFromString", "WStr", "{6d5140c1-7436-11ce-8034-00aa006009fa}", "Ptr", &IID_IServiceProvider)
		,DllCall("ole32\CLSIDFromString", "WStr", "{00000118-0000-0000-C000-000000000046}", "Ptr", &IID_IOleClientSite)

	if (DllCall("ole32\IsEqualGUID", "Ptr", riid, "Ptr", &IID_IUnknown)) {
		off := NumGet(this_+0, A_PtrSize, "UInt")
		NumPut(this_ - off, ppvObject+0, "Ptr")
		IUnknown_AddRef(this_)
		return 0 ; S_OK
	}

	if (DllCall("ole32\IsEqualGUID", "Ptr", riid, "Ptr", &IID_IWMPRemoteMediaServices)) {
		off := NumGet(this_+0, A_PtrSize, "UInt")
		NumPut((this_ - off)+(A_PtrSize + 4), ppvObject+0, "Ptr")
		IUnknown_AddRef(this_)
		return 0 ; S_OK
	}

	if (DllCall("ole32\IsEqualGUID", "Ptr", riid, "Ptr", &IID_IServiceProvider)) {
		off := NumGet(this_+0, A_PtrSize, "UInt")
		NumPut((this_ - off)+((A_PtrSize + 4) * 2), ppvObject+0, "Ptr")
		IUnknown_AddRef(this_)
		return 0 ; S_OK
	}

	if (DllCall("ole32\IsEqualGUID", "Ptr", riid, "Ptr", &IID_IOleClientSite)) {
		off := NumGet(this_+0, A_PtrSize, "UInt")
		NumPut((this_ - off)+((A_PtrSize + 4) * 3), ppvObject+0, "Ptr")
		IUnknown_AddRef(this_)
		return 0 ; S_OK
	}

	NumPut(0, ppvObject+0, "Ptr")
	return 0x80004002 ; E_NOINTERFACE
}

IUnknown_AddRef(this_)
{
	global IWMPRemoteMediaServices_size
	off := NumGet(this_+0, A_PtrSize, "UInt")
	iunk := this_-off
	NumPut((_refCount := NumGet(iunk+0, IWMPRemoteMediaServices_size - 4, "UInt") + 1), iunk+0, IWMPRemoteMediaServices_size - 4, "UInt")
	return _refCount
}

IUnknown_Release(this_) {
	global IWMPRemoteMediaServices_size
	off := NumGet(this_+0, A_PtrSize, "UInt")
	iunk := this_-off
	_refCount := NumGet(iunk+0, IWMPRemoteMediaServices_size - 4, "UInt")
	if (_refCount > 0) {
		NumPut(--_refCount, iunk+0, IWMPRemoteMediaServices_size - 4, "UInt")
		if (_refCount == 0)
			DllCall("GlobalFree", "Ptr", iunk, "Ptr")
	}
	return _refCount
}

IWMPRemoteMediaServices_GetServiceType(this_, pbstrType)
{
	NumPut(DllCall("oleaut32\SysAllocString", "WStr", "Remote", "Ptr"), pbstrType+0, "Ptr")
	return 0
}

IWMPRemoteMediaServices_GetApplicationName(this_, pbstrName)
{
	NumPut(DllCall("oleaut32\SysAllocString", "WStr", "qwerty12's long-ass AHK script for something that should've been simple: the case for using foobar2000", "Ptr"), pbstrName+0, "Ptr")
	return 0
}

IWMPRemoteMediaServices_GetScriptableObject(this_, pbstrName, ppDispatch)
{
	return 0x80004001
}
IWMPRemoteMediaServices_GetCustomUIMode(this_, pbstrFile)
{
	return 0x80004001
}

IServiceProvider_QueryService(this_, guidService, riid, ppvObject)
{
	return IUnknown_QueryInterface(this_, riid, ppvObject)
}

IOleClientSite_SaveObject(this_)
{
	return 0x80004001
}

IOleClientSite_GetMoniker(this_, dwAssign, dwWhichMoniker, ppmk)
{
	return 0x80004001
}

IOleClientSite_GetContainer(this_, ppContainer)
{
	NumGet(0, ppContainer+0, "Ptr")
	return 0x80004002
}

IOleClientSite_ShowObject(this_)
{
	return 0x80004001
}

IOleClientSite_OnShowWindow(this_, fShow)
{
	return 0x80004001
}

IOleClientSite_RequestNewObjectLayout(this_)
{
	return 0x80004001
}
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: how to know if windows media player is playing or not?

24 Dec 2017, 13:20

- Well, I finally ran Windows Media Player for the first time on this PC, which I've had for ~3 years (C:\Users, file properties), and dealt with the dialogs. (I use Media Player Classic.)
- I managed to get a script working with Acc, although it may need to be modified based on what mode is on (Library/Skin/Now Playing).
- Also, there may be multiple windows called 'Windows Media Player ahk_class WMPlayerApp' which adds to the confusion. That is, even when you only have one instance open.

Code: Select all

;[Acc functions]
;Acc library (MSAA) and AccViewer download links - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=6&t=26201
;Acc: get text from all window/control elements - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=6&t=40615

;note: tested on Windows 7
;worked when Library mode was on
q:: ;Windows Media Player - get play/pause status
ControlGet, hCtl, Hwnd,, WMPAppHost1, A
oAcc := Acc_Get("Object", "4.1.16.2.14.3", 0, "ahk_id " hCtl)
vState := oAcc.accName(0)
oAcc := ""
MsgBox, % "is playing: " (vState = "Play" ? "n" : "y")
return
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
partof
Posts: 110
Joined: 16 Jan 2016, 08:38

Re: how to know if windows media player is playing or not?

26 Dec 2017, 08:27

Thank you so much for your help!

@Qwerty: my mind exploded while trying to follow your code...
qwerty12
Posts: 468
Joined: 04 Mar 2016, 04:33
Contact:

Re: how to know if windows media player is playing or not?

26 Dec 2017, 09:07

No problem, partof :-)
partof wrote:@Qwerty: my mind exploded while trying to follow your code...
Sorry, while I'm usually rather lazy when it comes to commenting, that script took me a while to write so I wasn't particularly enthused about the idea of going back to it in this case...

The stuff after the ; --- is my crude implementation of a COM object that has only one purpose: to return the string "Remote" when the Windows Media Player COM object asks, which tells the WMPlayer.OCX object to abandon efforts on hosting its own instance of WMP and to instead focus its efforts on controlling an instance of WMP started by you. Sadly, all that boilerplate is required just to get to that point. I should point out that something similar (but not for WMP) was done in far, far fewer lines here. Sadly, I did not see that before I had already written most of, well, what you see now.

Code: Select all

rms := IWMPRemoteMediaServices_CreateInstance()
ocs := ComObjQuery(rms, "{00000118-0000-0000-C000-000000000046}")
^ is the COM object after the ; --- being created and obtaining a pointer to the interface implementing IOleClientSite

Code: Select all

ole := ComObjQuery(wmp, "{00000112-0000-0000-C000-000000000046}")
DllCall(NumGet(NumGet(ole+0)+3*A_PtrSize), "Ptr", ole, "Ptr", ocs)
this asks for the IOleObject interface from the WMPlayer.OCX object and the DllCall line then plugs our IOleClientSite interface into WMPlayer.OCX's IOleObject - this starts the process of the OCX object asking our COM object what WMP it should control - eventually, our object responds with "Remote"

Code: Select all

states := {0: "Undefined", 1: "Stopped", 2: "Paused", 3: "Playing"}
state := states[wmp.playState]
Hopefully, all went well and it's connected to your running WMP. So now we can ask for the current state. (You could also ask for the current filename and Title tag at this point: MsgBox % wmp.currentMedia.name and MsgBox % wmp.currentMedia.sourceURL respectively)

Code: Select all

DllCall(NumGet(NumGet(ole+0)+3*A_PtrSize), "Ptr", ole, "Ptr", 0)
for _, obj in [ole, ocs, rms]
	ObjRelease(obj)
wmp := ""
This starts the cleanup and disconnection from the WMPlayer interface. The first line tells the WMPlayer object to stop using our object to determine what WMP it should control and the next lines release the references we hold to the WMPlayer.OCX and our long object at the bottom of the script - hopefully, the RAM they're using gets released

MsgBox %state%

Finally, get the state. The reason why I did this last is because MsgBox will block your script, and if the WMPlayer.OCX object is still connected to a remote WMP, it will restart WMP in the background if you happen to close WMP while the script is showing its state dialog
partof
Posts: 110
Joined: 16 Jan 2016, 08:38

Re: how to know if windows media player is playing or not?

26 Dec 2017, 09:56

@jeeswg I also tried your code (I followed your instructions here https://autohotkey.com/boards/viewtopic.php?f=6&t=26201 ) .
It doesn't work (it always believe it's playing)

I'm trying to understand how it works (I'm discovering the Acc tool which opens many possibilities for other code!)
"worked when Library mode was on" : I guess the library is on if the Acc is working.

Here is what the Acc gives (button + main screen)
Image
Image

I tried (I just changed the "windows Media Player" instead) :

Code: Select all

ControlGet, hCtl, Hwnd,, Windows Media Player, A
oAcc := Acc_Get("Object", "4.1.16.2.14.3", 0, "ahk_id " hCtl)
vState := oAcc.accName(0)
oAcc := ""
MsgBox, % "is playing: " (vState = "Play" ? "n" : "y")
return
But it seems that I'm missing some information:
Line 1: What means the "A"?
Line 2: Where did you get that "4.1.16.2.14.3" ? What the 0 stand for? Did you get those from Acc? And is oAcc suppose to select the whole wmp windows or just the get info about the play/pause button?
Line 3: what is it doing, what's the 0 for ?
Line 4: by curiosity: why do you empty this var ?
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: how to know if windows media player is playing or not?

26 Dec 2017, 10:08

- On Windows 7 (and possibly other OSes), Windows Media Player has 3 modes: Library/Skin/Now Playing. The mode determines whether the script works. I realise now that I should edit the script, if the text found is neither 'Play' nor 'Pause' it should report unknown. I might experiment further to get it working in all 3 modes. I found some quirks of Windows Media Player, regarding multiple windows with the same name/class that made it harder to investigate.
- 'A' means active window.
- I obtained '4.1.16.2.14.3' via a script, the link is at the top of the script.
- The '0' is to specify not to use a child item. Actually I'm not entirely sure when to use accName / accName() / accName(0). IIRC generally the latter is safest.
- I obtained the information using the Acc library and a custom function that I wrote. You can sometimes use AccViewer to retrieve such information, although Windows Media Player wasn't playing nicely with AccViewer, it wasn't showing the treeview hierarchy.
- It's supposed to latch onto a specific GUI element and retrieve its text.
- vState := oAcc.accName(0) oAcc is an object representing the Play/Pause button, accName gets its text, I mentioned about the 0 above.
- I empty the variable afterwards, because like with most things in AHK/programming generally, when you latch onto something, but no longer need it, you should release it, otherwise you can get things like memory leaks.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
partof
Posts: 110
Joined: 16 Jan 2016, 08:38

Re: how to know if windows media player is playing or not?

26 Dec 2017, 10:11

@Qwerty Thanks you so much for your explanation! It's impressive (I wish I could download your brain). I'm deeply touched by all the time you have invested in this code (I find it as impressing as your code!).
partof
Posts: 110
Joined: 16 Jan 2016, 08:38

Re: how to know if windows media player is playing or not?

26 Dec 2017, 10:38

@jeeswg : thanks a lot for your explanations I'm excited to be able to use it elsewhere! But, I still struggle with 2 points:

Question 1
I obtained '4.1.16.2.14.3' via a script, the link is at the top of the script
then you wrote (also about it?):
I obtained the information using the Acc library and a custom function that I wrote. You can sometimes use AccViewer to retrieve such information, although Windows Media Player wasn't playing nicely with AccViewer, it wasn't showing the treeview hierarchy.


About the first quote: I guess you are talking about information given by the AccViewer.ahk right? If so, in which field should I retrieve that information? (Cf. my print screen above). But you after wrote that you finally used a custom function to get that number. Is there a simple way to get that number?

And what is it called by the way? [update, you just replied: it's the "acc path"]

Question 2
it may need to be modified based on what mode is on (Library/Skin/Now Playing)
which specific part of your code should be modified to set the right mode? (I don't see any of those word in your code)
Last edited by partof on 26 Dec 2017, 11:13, edited 3 times in total.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: how to know if windows media player is playing or not?

26 Dec 2017, 10:52

- I got the path via this function:
Acc: get text from all window/control elements - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=6&t=40615
- Usually you can get the path via AccViewer, but it wasn't working with Windows Media Player.
- Re. Library mode. What I meant was, I'd only got the script to work, if Windows Media Player was in Library mode. So you'd have to set Windows Media Player manually to Library mode to get it working. Although, I suppose, setting the mode could also be automated. I will check over the script.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
partof
Posts: 110
Joined: 16 Jan 2016, 08:38

Re: how to know if windows media player is playing or not?

26 Dec 2017, 11:57

I still did not manage to make it work (using jeeswg code) but I'm sharing the progress I made to understand his code:


update: the code below actually work (but I don't know why: cf the acc path...):
+ when WMP is set on "library" mode,
+ and only when I press "q" on the WMP (pressing "q" above another app doesn't work. It always set playing to "yes")

(The comments bellow explain some part of the code, but also ask for clarification for the others)

Code: Select all

ControlGet, hCtl, Hwnd,, WMPAppHost1, A 
; hCtl : what is it? 
; Hwnd: see https://autohotkey.com/docs/commands/ControlGet.htm 
; WMPAppHost1 is the "classNN" (you'll find it using ahk windows spy)
; 'A' means active window.

oAcc := Acc_Get("Object","4.1.16.2.14.3",0,"ahk_id " hCtl) 
; It's supposed to latch onto a specific GUI element and retrieve its text ;
; The '0' is to specify not to use a child item. Not sure when to use accName / accName() / accName(0). IIRC generally the latter is safest.

; '4.1.16.2.14.3' is the "acc path" (of the button?). How to get it?
  ; option 1: using the AccViewer (https://autohotkey.com/boards/viewtopic.php?f=6&t=26201)(kind of windows spy). But it doesn't always show the info (eg. in Windows Media Player it doesn't show the treeview hierarchy. link

  ; option 2: run jeeswg 2d script of this page, hover WMP play button then press "q" (https://autohotkey.com/boards/viewtopic.php?f=6&t=40615). You'll get that kind of msg box https://i.imgur.com/AR2N1AD.png the acc path seems to be the number on the left. I see "4.8.2.15.3 push button [Play][]", so the 4.8... seems to be the path. So why is it working with '4.1.16.2.14.3' ? 

      ; **BUT** I'm not sure of these options since I don't find this acc path in both options (so, why is it working?)
  
vState := oAcc.accName(0) 
; oAcc is an object representing the Play/Pause button, accName gets its text. (For the 0 cf above)


oAcc :="" 
; when you latch onto something, but no longer need it, you should release it, otherwise, you can get things like memory leaks.

MsgBox, % "is playing: "(vState ="Play"?"n":"y")

return
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: how to know if windows media player is playing or not?

01 Jan 2018, 12:40

- I managed to get a script to get the playing/paused state from Windows Media Player for all 3 states: Library/Skin/Now Playing. Tested on Windows 7. It needs the Acc library.
- The problem is that, usually with Acc, what you want is information from the main window, but for Windows Media Player, in two of the modes, you have to get information from a second window that isn't the main window.
- It would be interesting to know if there is a direct way to get from the hWnd of the main window, to the hWnd of the secondary window.

Code: Select all

;[Acc functions]
;Acc library (MSAA) and AccViewer download links - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=6&t=26201

;tested on Windows 7
q:: ;Windows Media Player - get play/pause status
DetectHiddenWindows, On
vState := "Unknown", vDoBreak := 0
ControlGet, hCtl, Hwnd,, WMPAppHost1, Windows Media Player ahk_class WMPlayerApp
WinGet, vWinList, List, Windows Media Player ahk_class WMP Skin Host
Loop, % vWinList
{
	hWnd := vWinList%A_Index%
	vStateLib := Acc_Get("Name", "4.1.16.2.14.3", 0, "ahk_id " hCtl) ;Play/Pause
	vStateSkin := Acc_Get("Value", "4.5.2.2", 0, "ahk_id " hWnd) ;Paused/Playing 'Name'
	vStateNow := Acc_Get("Name", "4.8.2.15.3", 0, "ahk_id " hWnd) ;Play/Pause
	vTemp := "`n" vStateLib "`n" vStateSkin "`n" vStateNow "`n"
	;MsgBox, % vTemp
	if InStr(vTemp, "`nPaused`n") || InStr(vTemp, "`nPlay`n")
		vState := "Paused", vDoBreak := 1
	else if InStr(vTemp, "`nPlaying") || InStr(vTemp, "`nPause`n")
		vState := "Playing", vDoBreak := 1
	if vDoBreak
		break
}
MsgBox, % "state: " vState
return
- I used this code to get the hWnd for the window under the cursor (instead of the active window), and then retrieve all of the text for that window via Acc.

Code: Select all

;[Acc functions]
;Acc library (MSAA) and AccViewer download links - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=6&t=26201
;[JEE_AccGetTextAll function]
;Acc: get text from all window/control elements - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=6&t=40615

w:: ;Acc - get text from window under cursor
;WinGet, hWnd, ID, A
MouseGetPos, vCurX, vCurY, hWnd
vText := JEE_AccGetTextAll(hWnd, "`r`n")
Clipboard := vText
SoundBeep
return
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Vasco Esteves
Posts: 7
Joined: 25 May 2021, 10:15

Re: how to know if windows media player is playing or not?

25 May 2021, 10:24

qwerty12 wrote:
26 Dec 2017, 09:07
No problem, partof :-)
partof wrote:@Qwerty: my mind exploded while trying to follow your code...
Sorry, while I'm usually rather lazy when it comes to commenting, that script took me a while to write so I wasn't particularly enthused about the idea of going back to it in this case...

The stuff after the ; --- is my crude implementation of a COM object that has only one purpose: to return the string "Remote" Broken Link for safety when the Windows Media Player COM object asks, which tells the WMPlayer.OCX object to abandon efforts on hosting its own instance of WMP and to instead focus its efforts on controlling an instance of WMP started by you. Sadly, all that boilerplate is required just to get to that point. I should point out that something similar (but not for WMP) was done in far, far fewer lines here. Sadly, I did not see that before I had already written most of, well, what you see now.

Code: Select all

rms := IWMPRemoteMediaServices_CreateInstance()
ocs := ComObjQuery(rms, "{00000118-0000-0000-C000-000000000046}")
^ is the COM object after the ; --- being created and obtaining a pointer to the interface implementing IOleClientSite

Code: Select all

ole := ComObjQuery(wmp, "{00000112-0000-0000-C000-000000000046}")
DllCall(NumGet(NumGet(ole+0)+3*A_PtrSize), "Ptr", ole, "Ptr", ocs)
this asks for the IOleObject interface from the WMPlayer.OCX object and the DllCall line then plugs our IOleClientSite interface into WMPlayer.OCX's IOleObject - this starts the process of the OCX object asking our COM object what WMP it should control - eventually, our object responds with "Remote"

Code: Select all

states := {0: "Undefined", 1: "Stopped", 2: "Paused", 3: "Playing"}
state := states[wmp.playState]
Hopefully, all went well and it's connected to your running WMP. So now we can ask for the current state. (You could also ask for the current filename and Title tag at this point: MsgBox % wmp.currentMedia.name and MsgBox % wmp.currentMedia.sourceURL respectively)

Code: Select all

DllCall(NumGet(NumGet(ole+0)+3*A_PtrSize), "Ptr", ole, "Ptr", 0)
for _, obj in [ole, ocs, rms]
	ObjRelease(obj)
wmp := ""
This starts the cleanup and disconnection from the WMPlayer interface. The first line tells the WMPlayer object to stop using our object to determine what WMP it should control and the next lines release the references we hold to the WMPlayer.OCX and our long object at the bottom of the script - hopefully, the RAM they're using gets released

MsgBox %state%

Finally, get the state. The reason why I did this last is because MsgBox will block your script, and if the WMPlayer.OCX object is still connected to a remote WMP, it will restart WMP in the background if you happen to close WMP while the script is showing its state dialog
Hi qwerty12 ,
Your code runs very well on a script.ahk, but it doesn't retrieve data if the script is compiled, i.e., script.exe

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: garry, mikeyww, steve88 and 171 guests