我正在尝试启动一项服务,而该服务又需要使用单独的应用程序(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)
此操作成功完成,但无济于事:服务仍会启动并在日志中报告相同的堆栈跟踪。
静态调度/早期绑定同样会失败。
如果无法访问您尝试启动的程序,就很难确定,但服务的一个限制是它们无法访问普通 Windows 程序拥有的所有 API。如果您从 Python 服务启动的程序尝试调用任何“禁止的”API,它就会崩溃,或者如果它等待用户输入,它就会挂起。
请参阅:在 Windows 服务中打开 Microsoft Word 文档似乎挂起,这是类似的情况。