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()
Error: Call to nonexistent function.
Specifically: COM_Init()
Code: Select all
#Include C:\Users\Me\Desktop\my_folder\COM.ahk
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.
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")
Code: Select all
---------------------------
COM Error Notification
---------------------------
Function Name: "controls"
ERROR: No COM Dispatch Object!
()
Code: Select all
#Include com.ahk
com_Init()
playState := COM_CreateObject(wmp, "playState")
MsgBox %playState%
Code: Select all
#Include com.ahk
com_Init()
playState := COM_Invoke(wmp, "playState")
MsgBox %playState%
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
}
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
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...partof wrote:@Qwerty: my mind exploded while trying to follow your code...
Code: Select all
rms := IWMPRemoteMediaServices_CreateInstance()
ocs := ComObjQuery(rms, "{00000118-0000-0000-C000-000000000046}")
Code: Select all
ole := ComObjQuery(wmp, "{00000112-0000-0000-C000-000000000046}")
DllCall(NumGet(NumGet(ole+0)+3*A_PtrSize), "Ptr", ole, "Ptr", ocs)
Code: Select all
states := {0: "Undefined", 1: "Stopped", 2: "Paused", 3: "Playing"}
state := states[wmp.playState]
Code: Select all
DllCall(NumGet(NumGet(ole+0)+3*A_PtrSize), "Ptr", ole, "Ptr", 0)
for _, obj in [ole, ocs, rms]
ObjRelease(obj)
wmp := ""
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
then you wrote (also about it?):I obtained '4.1.16.2.14.3' via a script, the link is at the top of the script
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.
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)it may need to be modified based on what mode is on (Library/Skin/Now Playing)
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
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
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
Hi qwerty12 ,qwerty12 wrote: ↑26 Dec 2017, 09:07No problem, partof
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...partof wrote:@Qwerty: my mind exploded while trying to follow your code...
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.
^ is the COM object after the ; --- being created and obtaining a pointer to the interface implementing IOleClientSiteCode: Select all
rms := IWMPRemoteMediaServices_CreateInstance() ocs := ComObjQuery(rms, "{00000118-0000-0000-C000-000000000046}")
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
ole := ComObjQuery(wmp, "{00000112-0000-0000-C000-000000000046}") DllCall(NumGet(NumGet(ole+0)+3*A_PtrSize), "Ptr", ole, "Ptr", ocs)
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
states := {0: "Undefined", 1: "Stopped", 2: "Paused", 3: "Playing"} state := states[wmp.playState]
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 releasedCode: Select all
DllCall(NumGet(NumGet(ole+0)+3*A_PtrSize), "Ptr", ole, "Ptr", 0) for _, obj in [ole, ocs, rms] ObjRelease(obj) wmp := ""
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
Users browsing this forum: Leli196 and 313 guests