Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

win32serviceutil does not respect <_exe_name_> #2436

Open
pythoniac opened this issue Dec 11, 2024 · 2 comments
Open

win32serviceutil does not respect <_exe_name_> #2436

pythoniac opened this issue Dec 11, 2024 · 2 comments

Comments

@pythoniac
Copy link

I have successfully installed a python service for windows with a call to <win32serviceutil.HandleCommandLine>. It did copy the "pythonservice.exe" from the user site-lib to the python install folder (my case: "C:\Program Files\Python311"). When I tried to install another service onto the same machine I got the error that the "pythonservice.exe" could not be copied since it already existed in the target folder. I have set the "exe_name="DatenloggerDienst.exe"" in my class and traced its way through the code in win32serviceutil. It gets passed correctly to the "LocatePythonServiceExe" method as parameter named "exe" and I noted that on line 41 it gets overwritten by

exe = f"pythonservice{suffix}.exe" - so "exe" is "pythonservice.exe" from here on

and then the "correct" variable gets to hold the value

correct = os.path.join(sys.exec_prefix, exe)

After which a copy action is taken in the form of

print(f"moving host exe '{maybe}' -> '{correct}'")

Of course this fails as I have already a "pythonservice.exe" in the target location. Once I changed it, so that "correct" holds the Name I have given in my class ("exe_name" Parameter) it just works (i.e.: "pythonservice.exe" is copied from the user site-lib to the Python install folder with the new name "DatenloggerDienst.exe")

Maybe I am missing something here?! From my understanding, every new service gets a new file and the name of the file should be "exe_name" or - if this is not given "pythonservice.exe".

Thanks for having a look.

@mhammond
Copy link
Owner

and I noted that on line 41 it gets overwritten by

The comment just a few lines up says "# We are confused if we aren't now looking for our default." - so yeah, that code's confused. The rest of that code is trying to work around pip packaging issues, where pythonservice.exe can't be installed in a place where it can be used.

We only get to that if not os.path.isfile("DatenloggerDienst.exe") - in your scenario, how would that code locate the full path name to your executable? Should we just check os.path.join(sys.exec_prefix, exe)? (ie, is that executable already in your sys.exec_prefix?

@pythoniac
Copy link
Author

pythoniac commented Dec 12, 2024

Thanks for the swifty reply. I assume I am not qualified to suggest a "proper" way of handling things because I am completely unaware of all the dirty pitfalls that your code obviously needs to maneuver around. Maybe it is helpful if I share my changed two lines here (marked with "MY CHANGE" 01 and 02?!) that results in doing the copy action successfully (full paths here for clarity):

copying host exe 'C:\Users\fabian_admin\AppData\Roaming\Python\Python311\site-packages\win32\pythonservice.exe' -> 'C:\Program Files\Python311\DatenloggerDienst.exe'

I could now happily install any other Python script as a Windows Service, provided I always give my class a different exe_name (still assuming that every service needs its own .exe file).

Code here:

`def LocatePythonServiceExe(exe=None):

# MY CHANGE 01
fab_exe = exe
# -------------

if not exe and hasattr(sys, "frozen"):
    # If py2exe etc calls this with no exe, default is current exe,
    # and all setup is their problem :)
    return sys.executable

if exe and os.path.isfile(exe):
    return win32api.GetFullPathName(exe)

# We are confused if we aren't now looking for our default. But if that
# exists as specified we assume it's good.
exe = f"pythonservice{_d}.exe"
if os.path.isfile(exe):
    return win32api.GetFullPathName(exe)

# Now we are searching for the .exe
# We are going to want it here.

# MY CHANGE 02
correct = os.path.join(sys.exec_prefix, fab_exe)
# -------------

# Even if that file already exists, we copy the one installed by pywin32
# in-case it was upgraded.
# pywin32 installed it next to win32service.pyd (but we can't run it from there)
maybe = os.path.join(os.path.dirname(win32service.__file__), exe)
if os.path.exists(maybe):
    print(f"copying host exe '{maybe}' -> '{correct}'")
    win32api.CopyFile(maybe, correct)

`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants