pywin32 - Windows COM 调度作为独立脚本工作,但作为服务失败

问题描述 投票:0回答:1

我正在尝试启动一项服务,而该服务又需要使用单独的应用程序(EBSILON Professional;https://www.ebsilon.com/en/)。该应用程序安装在服务器上,当使用 pywin32 使用 COM 访问它时,这在简单的 Python 脚本中按预期工作。

但是,当启动 Windows 服务执行相同操作时,调度会超时。

该服务在 Windows Server 2025 Datacenter 和 Python 3.13.1 上运行。这是一个展示问题的示例脚本(dispatch-test.py):

import win32serviceutil
import win32service
import win32event
import win32com
import win32com.client
import servicemanager
import socket
import time
import logging
import sys


def configure_logging():
    logging.basicConfig(
        filename = r'C:\Users\Administrator\Desktop\dispatch-test.log',
        level = logging.DEBUG, 
        format = '[helloworld-service] %(levelname)-7.7s %(message)s'
    )


def dispatch():
    try:
        win32com.client.Dispatch('EbsOpen.Application')
        logging.info('Successful')
    except Exception as e:
        logging.error('Failed', exc_info=True)


class HelloWorldSvc(win32serviceutil.ServiceFramework):
    _svc_name_ = "Dispatch-Test"
    _svc_display_name_ = "Dispatch Test"
    
    def __init__(self, args):
        super().__init__(args)
        configure_logging()

    def SvcStop(self):
        logging.info('Stopping service ...')
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)

    def SvcDoRun(self):        
        servicemanager.LogMsg(
            servicemanager.EVENTLOG_INFORMATION_TYPE,
            servicemanager.PYS_SERVICE_STARTED,
            (self._svc_name_, '')
        )
        logging.info('Running service ...')
        dispatch()


if __name__ == '__main__':
    if len(sys.argv) == 1:
        configure_logging()
        dispatch()
    else:
        win32serviceutil.HandleCommandLine(HelloWorldSvc)

py dispatch-test.py
的输出(直接方法):

[helloworld-service] INFO    Successful

对于

py dispatch-test.py install; py dispatch-test.py start
(通过服务):

[helloworld-service] INFO    Running service ...
[helloworld-service] ERROR   Failed
Traceback (most recent call last):
  File "C:\Users\Administrator\AppData\Local\Programs\Python\Python313\Lib\site-packages\win32com\client\dynamic.py", line 80, in _GetGoodDispatch
    IDispatch = pythoncom.connect(IDispatch)
pywintypes.com_error: (-2147221021, 'Operation unavailable', None, None)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\Administrator\DEsktop\helloworld-service.py", line 23, in dispatch
    win32com.client.Dispatch('EbsOpen.Application')
    ~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Administrator\AppData\Local\Programs\Python\Python313\Lib\site-packages\win32com\client\__init__.py", line 114, in Dispatch
    dispatch, userName = dynamic._GetGoodDispatchAndUserName(dispatch, userName, clsctx)
                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Administrator\AppData\Local\Programs\Python\Python313\Lib\site-packages\win32com\client\dynamic.py", line 100, in _GetGoodDispatchAndUserName
    return (_GetGoodDispatch(IDispatch, clsctx), userName)
            ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Administrator\AppData\Local\Programs\Python\Python313\Lib\site-packages\win32com\client\dynamic.py", line 82, in _GetGoodDispatch
    IDispatch = pythoncom.CoCreateInstance(
        IDispatch, None, clsctx, pythoncom.IID_IDispatch
    )
pywintypes.com_error: (-2146959355, 'Server execution failed', None, None)

这两个命令都在 PowerShell 中运行为

Administrator

System
日志在服务启动后大约两分钟显示:

Log Name:      System
Source:        Microsoft-Windows-DistributedCOM
Date:          1/15/2025 8:04:40 PM
Event ID:      10010
Task Category: None
Level:         Error
Keywords:      Classic
User:          SYSTEM
Computer:      EC2AMAZ-M0C7SQ4
Description:
The server {F1A4BB7E-1E45-4040-ACBC-4E2600010118} did not register with DCOM within the required timeout.
Event Xml:
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
  <System>
    <Provider Name="Microsoft-Windows-DistributedCOM" Guid="{1B562E86-B7AA-4131-BADC-B6F3A001407E}" EventSourceName="DCOM" />
    <EventID Qualifiers="0">10010</EventID>
    <Version>0</Version>
    <Level>2</Level>
    <Task>0</Task>
    <Opcode>0</Opcode>
    <Keywords>0x8080000000000000</Keywords>
    <TimeCreated SystemTime="2025-01-15T20:04:40.5916644Z" />
    <EventRecordID>14925</EventRecordID>
    <Correlation ActivityID="{9df83d36-66ae-0000-8ec3-309eae66db01}" />
    <Execution ProcessID="952" ThreadID="9044" />
    <Channel>System</Channel>
    <Computer>EC2AMAZ-M0C7SQ4</Computer>
    <Security UserID="S-1-5-18" />
  </System>
  <EventData>
    <Data Name="param1">{F1A4BB7E-1E45-4040-ACBC-4E2600010118}</Data>
  </EventData>
</Event>

考虑到运行服务时可能遇到权限问题,我尝试显式设置哪个用户启动服务进程,如下(使用实际密码):

from win32service import OpenSCManager, SC_MANAGER_ALL_ACCESS, OpenService, SERVICE_ALL_ACCESS, SERVICE_NO_CHANGE, ChangeServiceConfig

sc_manager = OpenSCManager(None, None, SC_MANAGER_ALL_ACCESS)
my_service = OpenService(sc_manager, 'Dispatch-Test', SERVICE_ALL_ACCESS)

ChangeServiceConfig(my_service, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, None, None, False, None, r'.\Administrator', '<redacted>', None)

此操作成功完成,但无济于事:服务仍会启动并在日志中报告相同的堆栈跟踪。

静态调度/早期绑定同样会失败。

python winapi service com pywin32
1个回答
0
投票

如果无法访问您尝试启动的程序,就很难确定,但服务的一个限制是它们无法访问普通 Windows 程序拥有的所有 API。如果您从 Python 服务启动的程序尝试调用任何“禁止的”API,它就会崩溃,或者如果它等待用户输入,它就会挂起。

请参阅:在 Windows 服务中打开 Microsoft Word 文档似乎挂起,这是类似的情况。

© www.soinside.com 2019 - 2024. All rights reserved.