Windows服务安装与运行失败的根本原因是权限、路径、上下文和超时问题。需管理员运行匹配.NET版本的InstallUtil.exe,OnStart须快速返回并异步初始化,注意Session 0隔离、账户权限、注册表路径及卸载清理。

服务安装失败提示“拒绝访问”或“系统找不到指定文件”
本质是权限和路径问题。Windows 服务安装必须以管理员身份运行命令行,且 InstallUtil.exe 路径必须准确匹配当前 .NET 版本。
- 用管理员权限打开 PowerShell 或 CMD,别双击直接运行脚本
- .NET Framework 4.8 服务要用
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe(x64)或Framework\v4.0.30319\(x86),路径错一个字符就报“系统找不到指定文件” - 确保你的服务程序集已生成
.exe(不是.dll),InstallUtil只认可执行文件 - 如果项目是 AnyCPU 但引用了 x86 原生库,安装时可能静默失败——改用明确的 x64/x86 平台重新编译
StartService 失败报错“服务未响应启动或控制请求”
这是最常被忽略的超时陷阱。Windows 默认只给服务 30 秒启动时间,OnStart 里做耗时操作(比如连数据库、读大文件、调 HTTP)必然超时。
-
OnStart必须快速返回,所有初始化逻辑要扔进新线程或Task.Run,但注意:别用async void,服务框架不 await 它 - 不要在
OnStart里写Thread.Sleep(5000)测试——这直接卡死启动流程 - 日志优先写到文件(如
EventLog.WriteEntry或自建文本日志),别依赖调试器——服务没界面,断点无效 - 检查服务账户权限:默认是
LocalSystem,但如果代码里访问网络共享或 SQL Server,得换成带对应权限的域账户
服务能启动但无法访问本地文件或注册表
服务默认运行在隔离会话(Session 0),看不到用户桌面环境,也受 UAC 和沙箱限制,很多“本地路径”行为和你预想的不一样。
-
Environment.CurrentDirectory是C:\Windows\System32,不是你的程序目录——用AppDomain.CurrentDomain.BaseDirectory或Assembly.GetExecutingAssembly().Location拿真实路径 - 写文件别硬写
C:\temp\log.txt,先检查目录是否存在并有写权限;推荐用Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "MyService") - 注册表操作:
HKEY_CURRENT_USER对服务无效(它没有“当前用户”概念),必须用HKEY_LOCAL_MACHINE或显式指定用户配置单元 - 如果服务需要访问用户桌面资源(比如某个用户下的 SQLite 文件),得启用“允许服务与桌面交互”(已弃用,Win10+ 不生效),正确做法是改用 Windows 事件或命名管道通信
卸载服务后残留注册表项或服务状态异常
卸载不干净不是小问题——残留的 Services 注册表项会导致下次安装失败,甚至影响其他服务。
- 卸载务必用原安装路径的
InstallUtil.exe /u YourService.exe,不能换 SDK 版本或路径 - 卸载后手动检查注册表:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\YourServiceName是否还存在;存在就删掉(删前备份) - 如果服务名含空格或特殊字符,安装命令里必须加英文引号:
InstallUtil.exe "My Service.exe",否则注册表键名会截断 - 服务状态卡在 “Stopping” 或 “Start Pending”?用
sc queryex YourServiceName查STATE和WIN32_EXIT_CODE,再查eventvwr.msc系统日志里的错误详情
服务生命周期和普通进程完全不同,所有你以为“本地就能跑通”的逻辑,在服务上下文里都可能失效。真正麻烦的从来不是怎么装,而是装完之后它到底在哪个上下文里、以谁的身份、访问了什么资源。










