My Goal
I'm trying to create a plugin for Plex Media Server (PMS) that will interface with WMP (Windows Media Player) to get metadata about Windows media library items.
The Setup
PMS uses Python 2.7 as its primary script host. Plex Plugins are
written in Python, though they operate in a sandboxed capacity. Unfortunately there's sad little documentation on what exactly the boundaries are on this sandboxed functionality.
I decided to use Python for .NET to access the Windows SDK to interface with WMPLib.
Python for .NET (http://pythonnet.github.io/) is a Python
library used to access functionality from .NET assemblies from within
the Python runtime.
I created a .NET assembly to access WMPLib, which
is a part of the Windows SDK designed to programmatically access the
functionality of WMP. WMPLib is basically a COM Interop wrapper for
.NET targeting wmp.dll.
What's Working?
The whole chain from Python on through the COM-based WMP access is working. If I fire up the embedded Plex Script Host that comes with Plex Media Server (a version of Python 2.7), I can readily access data from WMP. That means that the following links in the chain are all working:
Python is loading Python for .NET
Python for .NET is loading my .NET assembly
My .NET assembly is loading WMPLib (Interop.WMPLib.dll, a .NET assembly for COM Interop)
WMPLib is successfully opening and utilizing wmp.dll (accessed from C:\Windows\System32)
What's Not Working?
Activating the COM Interop part of this chain is not working from within the sandboxed Plex plugin. Again, this plugin is written in standard Python, but something is subtly different about the Python execution environment once the sandboxing code has run. I get the following exception when running the WMP access code from within the plugin:
COMException: Exception from HRESULT: 0xC00D1327
at WMPLib.IWMPPlayer4.get_mediaCollection()
In this scenario I know that Python for .NET is working, because I've already loaded and accessed other things from my .NET assembly at this point.
C:\Windows\System32 is at the front of PATH variable. I'm assuming that COM dlls should be located via the PATH environment variable (This seems to say so), but I'm not entirely certain of that. How a COM assembly should be located in this unique scenario (Python accessing .NET accessing COM) is one of the biggest unknowns for me.
The Questions
How might the Plex plugin sandbox be changing the Python execution environment such that accessing the COM assembly is no longer working?
How should the COM assembly be located and accessed by the environment in this case?
Does it require specific permissions that the Plex sandbox may have locked down?
Maybe I should at least win some kind of prize for arriving at a question that intersects so many different technologies in a uniquely confusing way...
Edit 1
I've ruled out any .NET related issues entirely, thanks to #Paulo's suggestion below. I'm now doing all interop with WMPLib through the comtypes Python library. Now I'm getting the following error:
COMError: (-1072884953, None, (None, None, None, 0, None))
Though -1072884953 is a different error code, a little digging around makes it appear that this error is associated with (maybe equivalent to?) the same error that I was getting through .NET interop (this post makes it appear so).
So now the facts that I'm stuck with are these:
wmp.dll is loading in all cases (which #Paulo helped me to figure
out below).
When the code accessing WMP is run outside the Plex sandbox environment, library items can be accessed from WMP just fine.
When the code accessing WMP is run inside the Plex sandbox environment, library items cannot be accessed from WMP.
The error code that I get (whether from .NET or Python based COM interop is NS_E_CURL_INVALIDPATH: The URL contains a path that is not valid. This error appears to be involved with attempted playback in most cases.
This is odd because I've never gotten as far as playback in my scenario... I'm only attempting to call wmp.mediaCollection
So the Plex sandbox truly seems to be key in this scenario. Any further ideas?
Edit 2
Minimally, this is the code that it takes to fail:
from comtypes.client import CreateObject
wmp = CreateObject("{6BF52A52-394A-11d3-B153-00C04F79FAA6}")
collection = wmp.mediaCollection
That collection = wmp.mediaCollection is where the error happens.
So there really aren't any parameters being passed in that could be causing the failure. To reiterate, this code runs fine in the general Python 2.7 context. It only fails within the Plex plugin sandbox. I don't know how to get details on how the Plex sandbox may be changing the execution environment. I'd imagine my answer lies in that direction.
Let me get this straight, and correct me if I'm wrong:
You have a running instance of Python 2.7, Plex Media Server
You're using a library, Python for .NET, to load a .NET into your process
You're loading WMPLib, an imported COM interop assembly, in .NET to use the Windows Media Player library through Python for .NET
Let's clear this out:
0xC00D1327 is NS_E_CURL_INVALIDPATH:
The URL contains a path that is not valid.
It seems like a legitimate object error, not a COM error.
The DLL search order has little to do with it, since wmp.dll is registered with a full path under InProcServer32 registry keys for each provided class, and that's what ultimately matters.
In fact and as you stated, if you've reached this point, it's clearly not a problem about loading .NET assemblies or COM not finding a DLL.
Now, to the questions:
Since the error seems legit, you might not have access to the media collection (Internet zone?), or WMP is not correctly registered/installed, or some codec is missing or not correctly registered/installed, etc.
What are you loading into WMP? Try with basic things, such as local .WAV, .MP3, .AVI and .MPG files, then try more advanced formats e.g. MPEG4-encoded videos, or maybe remote locations.
You should attempt a more direct approach, although I can't really vouch which is better: win32com (part of pywin32) or comtypes.
It was a long while ago since I've looked at them, so take this with a grain of salt: with comtypes, you're able to use your COM objects much like regular Python objects with properties and methods, while win32com seems more inclined to do things by runtime name dispatching.
At least you'll be punching something you really have to put up with (Python) instead of loading .NET for something that doesn't even require it (WMP).
I don't know what that sandboxing is about, but my guess is that it's a Python-only sandbox, not something that restricts usage of the operating system.
EDIT: Are you providing a filename (e.g. C:\path\to\file.mp4) where a URL is expected (file:///C:/path/to/file.mp4), or vice-versa? I guess you must show the failing code and what values are being provided.
Related
I am trying to finish a personal project, which I describe its operation below.
My project consists of running a script (like a service) in the cloud.
I have on the one hand, a python script (created by me) which I want to host, and on the other hand a c++ script (not created by me), which I need to use from my python script, using boost-python.
My first way was to host my python script in pythonanywhere, but it doesn't work for me because the c++ script was designed for windows (it uses libraries only for the windows platform such as windows.h) and when compiling it ends in an error (pythonanywhere uses linux as base system).
So I would like someone to help me and tell me what is the correct way to do what I describe. I understand that it can be one of the following variants, but in some cases I am not entirely convinced that it can, or I do not know how to proceed.
Pay for a Virtual Desktop, and schedule the execution of my python script.
Use what is explained here.
Use a docket image with windows and host it somewhere.
Use Heroku
Note. My project needs/use a database.
Linux also supports C compilation. It's kernel is coded in C. Try compiling your code on linux with a tool like gcc, available on it.
I have developed an application where a small part of the solution is done in ironpython, but when I am migrating to production they (client) are not giving permission to install ironpython.
I am trying to get any portable version of IronPython. So that without installing I can run IronP` code.
Please Help.
There is no need to MSI-install IronPython on the clients you are deploying your application to.
Just XCOPY deploy your application as well as required portions of IronPython (e.g. by grabbing a current ZIP release or getting files from your local installation).
The required files will at least include
IronPython.dll,
Microsoft.Dynamic.dll,
Microsoft.Scripting.dll and
Microsoft.Scripting.Metadata.dll
from the correct Platforms-subfolder (e.g. Net45).
If the python standard library is used in your python code (or needs to be available to dynamically loaded code) the Lib-folder (or a subset) has to be included as well.
Should your application be deployed via MSI or a similar mechanism just include relevant IronPython files instead of XCOPYing.
I'm theory crafting a Python service which will manipulate domain joined machines into running tests as part of a suite. Details of requirements
We must be logged in as a domain user, and we must not have the automatic login enabled
We need to reboot machines a few times, so it's a requirement for this to be sustainable
I'm wondering if it's possible to, from a Python service, somehow convince Windows to log us in? Presumably a Python service runs in Session0, as does Microsoft's Hardware Certification Kit? If that's capable of doing it, Python should also be (so far as I can see).
Any suggestions most welcome, I've got a suspicion there's a cheeky Windows API call that does this, but can't seem to find it anywhere.
So I've found a way to do it from a Windows service (written in C++) and presumably the ctypes library will permit me to use it.
Simple as using LogonUser from Win32API so far as I can see. Yet to actually set up and test it but it does seem to be exactly what I need. The difficulty being that session0 can only be accessed once logged in or via some remote debugging, so getting something like this working is no easy feat.
I am trying to extract some data out of the Windows registry, both the software hive and ntuser.dat from XP computers. Currently I'm using reg.exe to load the hive and _winreg to extract the data. I need to use reg.exe as the computers I'm backing up data from are usually offline and I'm putting the hard drive from them in an external drive bay and loading the hives from that in another Windows session. It's not feasible to boot up the computers being backed up as they are often failing hard drives or otherwise unbootable.
I've seen a utility called hivex which runs under Linux which combines a c-module with a python wrapper to allow for read-only (limited write) access to the Windows registry, without using the Windows Registry APIs. Sadly there doesn't appear to be a Windows version of hivex, assumingly because no one figured a need to access the Windows registry under Windows by directly accessing the hive files.
I'd love to drop the dependency of reg.exe being called by subprocess.Popen() as calling an external executable has a host of issues, plus it makes the backup utility platform limited.
Does anyone know of a python module which allows for direct access of the hive files themselves? I already know of, and am currently using _winreg, so suggesting that would be less than helpful. Thanks in advance.
I'm not sure how much better it is, but the pywin32 library supplies bindings to most of the windows API. I don't know the windows API well enough to know if you can open arbitrary hive files, however it could be worth a quick look (the release contains a CHM with the full API mapping).
Did you have a look to regobj it provides pythonic access to registry value (but it is still based on _winreg)
Is your problem with calling an external application or using the registry APIs? If it is the former you can load and unload hives yourself using RegLoadKey / RegUnLoadKey. If it is the latter then I'm sure somebody has written a C library to parse hives directly. A quick Google search gave me Microsoft's Offline Registry Library.
I have a website that offers files to people; this site is related to a SAT decoder based on Linux. Some people developed "plugins" written in Python that access my site and get those files directly from the decoder without visiting the site. I know I could block them by using JavaScript methods on the website but I would like to know what this plugin does first. The files of those plugins are a series of pyo files which, from what I understood, are compiled Python scripts.
Is there a way I can get the source of those files or at least see what they "call"?
I only found non-working or not free services. I mean there must be a way; people crack almost every software made by major software houses and I can't "get" what a Python script does?
Exploring and decompiling python bytecode