zoukankan      html  css  js  c++  java
  • 使用srvany.exe将任何程序作为Windows服务运行

    http://wangye.org/blog/archives/42/

    srvany.exe是什么?

    srvany.exe是Microsoft Windows Resource Kits工具集的一个实用的小工具,用于将任何EXE程序作为Windows服务运行。也就是说srvany只是其注册程序的服务外壳,这个特性对于我们来说非常实用,我们可以通过它让我们的程序以SYSTEM账户启动,或者实现随机器启动而自启动,也可以隐藏不必要的窗口,比如说控制台窗口等等。

    如何获取?

    你可以通过下载并安装Microsoft Windows Resource Kits获得或者可以通过我分享的下载地址1(国内线路)下载地址2(国外线路)得到。

    如何使用?

    当你获取到srvany后并决定将某程序作为服务启动后,请先将srvany安装为系统服务,具体的安装方法有很多,比如说可以通过Microsoft Windows Resource Kits中另外一个实用的小工具instsrv.exe进行安装(下载地址),将srvany.exe和instsrv.exe拷贝到C:WindowsSystem32后,我们可以通过下面的命令行进行srvany.exe的服务安装:

    instsrv ServiceName C:WindowsSystem32srvany.exe

    ServiceName即你自己定义的服务名称,可以是要作为系统服务启动的应用程序的名称。

    安装完毕后,我们需要对srvany.exe进行配置,以便于能够加载我们指定的程序,配置的方法是,开始 – 运行 – regedit,打开注册表,定位到下面的路径。

    HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesServiceName

    同样的ServiceName是你刚才安装服务时自定义的服务名称。

    如果该服务名下没有Parameters项目,则对服务名称项目右击新建项,名称为Parameters,然后定位到Parameters项,新建以下几个字符串值。

    名称 Application 值为你要作为服务运行的程序地址。
    名称 AppDirectory 值为你要作为服务运行的程序所在文件夹路径。
    名称 AppParameters 值为你要作为服务运行的程序启动所需要的参数。

    比如这里是个配置实例,我们这里配置的服务名称是NGINX,其余是nginx的安装配置情况。

    srvany配置

    当然还有一个比较简单的做法,那就是将下面的文本保存为*.reg文件,然后双击导入注册表。

    1
    2
    3
    4
    5
    6
    
    Windows Registry Editor Version 5.00 
     
    [HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServices服务名称Parameters] 
    "Application"="值为你要作为服务运行的程序地址"
    "AppDirectory"="值为你要作为服务运行的程序所在文件夹路径"
    "AppParameters"="值为你要作为服务运行的程序启动所需要的参数"

    2011年7月14日更新

    找到微软的官方文章《如何创建用户定义的服务》,大家可以看一看。

    2012年2月27日更新

    今天有朋友问到将某窗体程序通过srvany作为服务运行的时候,桌面右下角图标和窗体无法显示,这个就涉及到服务的运行方式了,一般服务程序是不包含窗体的,所以系统默认可能会抑制这些服务程序产生的窗体,如果你的服务程序比较特殊,确实需要出现窗体,可以参考下面的办法:

    控制面板 – 管理工具 – 服务(或者 开始 – 运行 – services.msc 确认)打开服务管理器,选择你刚刚安装并需要展示窗体的服务,然后右击选择属性,切换到 “登录” 选项卡,勾选上 “允许服务与桌面交互” 然后按确定保存,重启你的服务,看看窗体是否出现了:

    允许服务与桌面交互

    2012年7月3日更新

    为了大家利用srvany.exe创建自定义服务的方便我特别写了个名叫SrvanyUI的服务创建管理的小工具,大家可以移步这篇文章《SrvanyUI服务管理工具发布》来获得详细信息,这里放个截图:

    SrvanyUI服务管理工具

    2012年7月5日更新

    找到微软的一篇文章可以参考《故障排除使用 Cmd.exe 的 SrvAny》

    2012年7月23日更新

    近期有朋友咨询为什么勾选上 “允许服务与桌面交互”,窗体程序依旧不能显示,其实这个办法只适用于Windows XP或者Windows 2003系列的操作系统,对于以上版本的Windows Vista、Windows 2008、Windows 7以及Windows 2008 R2,微软做了改变,使用了Session 0会话隔离策略,所以再使用这个办法强制服务窗体显示就会出现提示框,只有手动允许后才会出现界面,并且桌面风格也将被更改:

    交互式服务检测提示

    交互式服务检测

    此计算机上运行的程序正在尝试显示一条消息,程序可能需要您的信息或权限来完成任务。

    交互式服务检测
    此计算机上运行的程序正在尝试显示一条消息
    程序可能需要您的信息或权限来完成任务。

    关于Vista及高版本Windows交互出现提示框是由Interactive Services Detection服务控制的。禁用此服务将不会出现上述提示框,当然窗体也就不会显示了。

    更详细的信息可以参考MSDN的《Interactive Services》文章。

    特别注意下面这段:

    Important Services cannot directly interact with a user as of Windows Vista. Therefore, the techniques mentioned in the section titled Using an Interactive Service should not be used in new code.

    如果要在新的Vista及以上操作系统上显示窗体,我们应当使用新的技术,比如使用WTSSendMessage在用户会话显示对话框,或者将服务程序与窗体分离开来再使用进程通信(推荐)。

    关于编程的方法可以参考这篇文章《解决vista和win7在windows服务中交互桌面权限问题:穿透Session 0 隔离》

    抱歉的是目前的办法仅限于编程方面的,其他有效的办法我暂时还没有找到。

    部分参考文档:

    2012年2月27日更新

    对于带参数的命令行方式直接利用srvany.exe创建自定义服务请参考文章《WScript/VBScript命令行参数使用srvany.exe创建自定义服务》

      1. 你好,我自己添加了一个服务成功了。可是启动失败,提示1053错误。可能会是哪里的错误呢。。
        是不是执行程序做为服务的时候是有要求的。

        •  

          @chy
          检查你的Application和AppDirectory路径值是否正确,下面以NGINX程序举个例子,reg文件内容应该形如下面这样,然后导入:
          Windows Registry Editor Version 5.00

          [HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesNGINXParameters]
          "Application"="E:\nginx-0.8.16\nginx.exe"
          "AppParameters"=""
          "AppDirectory"="E:\nginx-0.8.16\"
          如果已经导入了注册表,请选择开始,运行,输入regedit并确认以便于打开注册表编辑器,定位到HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServices你的服务名称Parameters,检查路径和参数配置是否正确。
          如果问题依旧,建议打开控制面板,“管理工具”下面的“事件查看器”,选择旁边的“系统项目”,选择类型为错误的日志,看看具体内容是什么。

      2.  

        谢谢。还是1053错误,系统错误日志提示:服务没有及时响应启动服务和控制请求。
        是不是03系统对要做为系统服务的执行程序有什么要求呢。
        是不是利用instsrv工具的时候,执行程序只能是单独的一个执行程序,不能有动态库文件其他东西呢。。

        •  

          @chy
          您好,貌似instsrv只能将服务程序(*.EXE)安装为服务,普通EXE程序,动态链接库等无法单独安装为服务,对于普通程序,建议采用本文所述利用instsrv将srvany.exe安装为服务,然后通过配置参数加载普通EXE程序作为服务运行,对于DLL,请参考svchost的做法进行加载,或者你可以写个简单的EXE服务程序,然后静态链接或者动态调用(LoadLibrary)这个DLL,然后再通过instsrv安装这个能加载DLL的简单EXE服务程序。

      3.  

        非常感谢您耐心的指导。
        还想问您一下,您说的“配置参数加载普通EXE程序作为服务运行”具体怎么理解呢。
        一个软件包含了可执行程序,dll文件,为了主执行程序作为系统服务运行,其他执行程序和dll文件都需要不同的操作吗。
        呵呵,我是个刚接触系统管理的小白,问的不对的地方请您见谅。

        •  

          @chy
          通过配置参数主要是配置的srvany.exe参数,当我们把srvany.exe作为服务安装的时候,我们还要告诉srvany.exe要加载的EXE的路径等参数信息,这样这个EXE才能以“服务”的形式存在,具体的做法是修改注册表相关项,这点可以参考本篇文章,如果说单纯谈一个软件包,里面有一个调用的EXE和一堆DLL链接库,我们只需要加载EXE就可以了,那些DLL动态库是为EXE提供必要函数指令的,也就是说EXE主程序需要它们时才会加载它们,这个是这个EXE主程序的事情,我们只需要将EXE主程序作为服务运行即可,如果该EXE是服务程序,可以直接安装为系统服务,然后再启动,如果该EXE程序是普通程序,那么就不能直接作为服务程序启动,请利用本篇文章所述的srvany.exe加载的办法进行相关操作,你可以下载一个叫Dependency Walker的程序,然后利用这个程序打开你的软件包中的EXE,如果该程序没有经过加壳压缩(比如UPX等加壳程序),你应该就会发现其静态所需要加载的DLL了,当然程序内部通过LoadLibrary方式动态加载的DLL可能需要其他手段,比如反编译等才能追踪到。关于应用程序EXE和动态链接库的关系,可以参考《Windows核心编程》的动态链接库部分。没关系,有什么疑问,欢迎提出:-)

      4.  

        您好。你说的“服务程序”是不是指windows系统自带的执行程序。“普通程序”是自己开发的程序呢。如果是这样,我我们的普通程序能不能修改为服务程序呢。
        我要做的这个服务就是我同事自己开发的程序,我利用srvany.exe添加了服务,注册表也修改了,可是就是启动服务到一半的时候就会报1053的错误。
        真的很头大。%>_

        •  

          @chy
          不是这样的,服务程序是指遵循微软的服务程序开发规范开发出来的特殊程序,这类程序和普通程序相比最大的特点是可以被系统作为服务启动,服务程序和普通程序都可以是自己开发的程序,普通程序不能直接作为服务程序启动,否则服务启动会报错,所以srvany.exe就是为解决这个问题而诞生的,srvany.exe本身是作为服务程序而开发的,其是遵循服务程序开发规范的,所以可以被系统作为服务程序启动,然后srvany.exe会根据注册表的配置参数启动你所设定的普通程序,所以进程列表会有两个一个是srvany.exe另一个是你的普通EXE程序,注意它们都是以SYSTEM账户启动的,如果srvany.exe服务被停止,那么相应的普通程序也会被srvany.exe停止,这样就将普通程序模拟出服务程序的功能了。你同事的那个程序是不是包含窗体界面,如果是这样的话,开始,运行,输入services.msc,打开服务管理器,找到你设置的那个服务项,右击属性,切换到“登录”选项卡,然后勾选“允许服务与桌面交互”试试,不过一般情况下不建议将有窗体的程序作为服务程序运行,这样会有一些问题。关于服务程序的介绍和开发示例可以参考《Using Services》《The Complete Service Sample》或者《用 C++ 创建简单的 Win32 服务程序》

      5.  

        您好。
        我现在可以把程序添加到服务,但是无法启动,是不是可以说是srvany.exe没有发挥作用的问题呢。

        •  

          @chy
          首先这个程序必须是能够持续运行的程序,如果是那种一运行很快就结束的程序,那么使用srvany.exe就没有效果了,因为srvany.exe启动了这个程序,而这个程序却很快就运行结束自动退出了,那么你在进程中将看不到你所希望运行的程序,只看到srvany.exe进程,因为它已经运行结束了,对于持续性程序,就是你不点关闭、不中止进程程序就不会退出的那种,在srvany.exe启动这类程序时,进程列表中将有你要启动的程序名和srvany.exe这两项,这时如果你停止服务,这两个进程将自动结束。
          我们知道系统自带的notepad.exe和nslookup.exe都是那种持续性程序,你不点关闭它们将不会退出,这两个程序一个是窗体程序、一个是控制台程序,将instsrv.exe和srvany.exe拷贝到SYSTEM32文件夹中,下面我用这两个程序做了实验:
          1.notepad.exe
          instsrv sample1 C:WindowsSystem32srvany.exe
          将下面导入注册表:
          Windows Registry Editor Version 5.00

          [HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicessample1Parameters]
          "Application"="C:\WINDOWS\SYSTEM32\notepad.exe"
          "AppDirectory"="C:\WINDOWS\SYSTEM32\"
          "AppParameters"=""
          然后启动服务sample1,观察任务管理器进程列表,出现srvany.exe和notepad.exe两个SYSTEM账户运行的进程,停止sample1服务后,两个进程消失,证明窗体类程序可以正常挂到srvany.exe下作为服务运行。
          2.nslookup.exe
          instsrv sample2 C:WindowsSystem32srvany.exe
          将下面导入注册表:
          Windows Registry Editor Version 5.00

          [HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicessample2Parameters]
          "Application"="C:\WINDOWS\SYSTEM32\nslookup.exe"
          "AppDirectory"="C:\WINDOWS\SYSTEM32\"
          "AppParameters"=""
          同上操作,证明控制台程序也是可以被srvany.exe作为服务启动的。
          对于持续性程序,可以通过 输入等待getchar()、死循环、互斥、消息循环等方式实现。

      6.  
        枯燥洒徒哈达 在 2011 年 10 月 13 日上午 6:59 说道:

        始终出现:本地计算机上的XX服务启动后又停止了。一些服务自动停止,
        如果它们没有什么可做的,例如“性能日志和警报”服务

        •  

          @枯燥洒徒哈达
          不知道你那个是不是因为程序是那种一闪而过的,自动结束的程序。看上面那条回复:
          “首先这个程序必须是能够持续运行的程序,如果是那种一运行很快就结束的程序,那么使用srvany.exe就没有效果了,因为srvany.exe启动了这个程序,而这个程序却很快就运行结束自动退出了,那么你在进程中将看不到你所希望运行的程序,只看到srvany.exe进程,因为它已经运行结束了,对于持续性程序,就是你不点关闭、不中止进程程序就不会退出的那种,在srvany.exe启动这类程序时,进程列表中将有你要启动的程序名和srvany.exe这两项,这时如果你停止服务,这两个进程将自动结束。”
          希望对你能有所帮助:-)

      7.  
        wangwj 在 2012 年 4 月 9 日上午 10:21 说道:

        你好,我想请问个问题,我想给Server 2003 或 2007 设置特定登陆用户显示窗体程序 ,比如系统登陆用户默认管理员是 Administrator 我设置了一个 sample1,我登陆sample1的时候才开启 服务中已设置好的窗体程序。

        •  

          暂时没能找到如何针对不同的用户启动不同服务的解决方案,不过可以将要启动的程序存放到用户的个性化启动文件夹中,比如Windows 7下是:
          C:Users<用户名>AppDataRoamingMicrosoftWindowsStart MenuProgramsStartup
          Windows XP下路径是:
          C:Documents and Settings<用户名>「开始」菜单程序启动
          假如说你需要运行的是服务程序,可以先将服务程序设置为手动启动,然后在上述用户启动文件夹中编写如下批处理文件(另存为*.bat):

          net start 服务名称

          这样不同的用户启动计算机就会自动执行其启动目录下的程序了,如果正好是启动服务的批处理,那么这个手动的服务也会被启动了。

      8.  

        让我非常收益的一片文章,谢谢!

      9.  
        小磊 在 2012 年 6 月 20 日下午 2:27 说道:

        我的程序就是一闪而过,然后自动结束了,不知道这个问题怎么解决呢?

        •  

          假如程序本身就是那种一运行就自动结束的话,则无法作为服务运行的,服务程序要求的就是持续驻留内存,如果程序运行完就自动结束则没有必要设为服务,你可以将其加入系统自动启动项内来实现开机启动等功能。
          典型的只要不手动关闭就持续运行的程序也有不少比如notepad.exe和nslookup.exe,你运行这些程序后,如果不输入退出命令或者点击右上角叉的话程序是不会自动结束的,所以这类程序更适合于被srvany.exe控制;假如是类似CScript.exe(不运行脚本)或者ipconfig.exe这类运行完就结束的程序,你可以在WindowsSystem32路径下找到,并双击运行,结果是一闪而过的,说明其执行完任务就自动退出了,这样srvany.exe就无法控制了,因为srvany启动这类程序的时候,它们可能已经在完成任务后自我结束了运行。
          从编程的方法解决可以给你几个思路:
          1、参考Windows 服务编程约定将应用程序改造成服务程序(如果这样实现的话,那么恭喜你,就不需要srvany.exe辅助了);
          2、在程序退出前使用死循环轮回执行任务(不推荐,可能有性能问题,一定要实现的话,可以加入sleep防止过高占用CPU);
          3、命令控制台程序可以使用类似getchar()这类等待输入的函数,将程序挂起(不推荐,因为执行到getchar()挂起程序这里,程序实际功能已经结束了,所以虽然持续运行着,但已经没有实际作用了);
          4、使用隐藏窗体,配合消息循环实现(这个可以考虑,虽然服务程序不应该用窗体编程的方式,但是要Hold住程序保持不退出,必须采取循环的方式)。
          暂时就想到这么多,仅供参考吧,本文前面的评论内容也可以看看,希望对你有所帮助:-)

      10.  
        小磊 在 2012 年 6 月 20 日下午 4:19 说道:

        谢谢,再问一下,我这个程序是连接数据源的中间件,能做成服务吗?

        •  

          一般情况下,我目前认为的两种适合作为服务的类型:一是定时处理某个任务,比如自动检查并更新的程序或者自动检查许可证是否有效的程序;二是监听请求,接受请求,处理请求这一类程序,比如远程受控服务端,基本上套接字(Socket)网络C/S应用的比较多。
          总结一下第一类是主动类型的服务程序,第二类属于被动类型的服务程序。我觉得你的情况适用于第二类被动接受请求,处理请求的服务程序。可以做成网络服务端程序,然后监听远程(或者本地)客户端的对资源(数据库)操作的请求,接受到此类请求后,然后服务程序按照一定的协议操作资源并反馈结果,简单如下:
          server --listen-- 服务器监听
          client --request-- 客户端请求
          server --accept-- 服务端收到请求并建立会话(此处可以加上身份验证)
          server do something 服务端根据客户请求处理资源
          server --return result-- 服务端返回处理结果
          client --accept-- 客户端收到结果并进一步处理

          上述一系列操作可以封装到类似死循环的逻辑里再作为服务程序,这样服务程序就不会只接受一次请求而终止了,而是一直永远的接受来自客户端的请求,这样有效的服务程序算是成型了。
          当然如果客户端仅仅是本地程序的话,可以不拘泥于网络套接字编程方式,比如进程间会话、管道通信什么的也是可以考虑的,说到底就是个C/S架构的东东,和普通的C/S数据库(MySQL、SQL Server)一样,只不过我们为了额外做一些事情(比如访问控制、事务控制)而自己用服务程序方式新建立了个服务端,然后客户端与新建立的服务端通讯,然后由新服务端将数据处理后按要求再与数据库服务程序通信:client – server – database,这样server服务程序就代理了数据库的相关操作。
          可能啰嗦了点,仅供参考吧。

      11.  

        你好,最近在使用srvany.exe和instsrv.exe注册为服务,碰到一个问题。我将一个普通exe启动文件注册成了服务,开机能够自动启动,但是srvany.exe的默认启动路径为C:winodwssystem32,这样导致exe启动,但是不能正确加载,exe的路径是在D:softin目录下,不知该如何修改?

        •  

          检查一下注册表AppDirectory信息是否设置为D:softin。建议使用SrvanyUI配置由srvany.exe创建的自定义服务(初次使用请删除原来手动建立的srvany.exe服务项目,然后用本工具重新创建)。

          •  

            好像用这个UI工具的确就可以了,instsrv.exe没有作用么,之前我是借鉴了别人一个bat脚本来生成服务的,我现在也是想用脚本的方式来完成服务的注册,想集成到一个安装包中,不知高手是否方便告知一下QQ,方便我请教,在此先谢过

            •  

              抱歉,我在单位不方便使用QQ,你也可以使用邮箱与我联系。
              你用instsrv安装完srvany.exe后还需要对srvany进行注册表配置,具体请参考文章所述。
              不太清楚你是如何编写配置安装脚本的,如果你是使用NSIS进行安装脚本配置的话,首先通过ExecWait执行instsrv命令将srvany.exe安装为系统服务,然后参考下面的脚本实现配置部分:

              WriteRegStr HKEY_LOCAL_MACHINE "SYSTEMCurrentControlSetServices服务名称Parameters" "Application" "$INSTDIR你的程序.exe"
              WriteRegStr HKEY_LOCAL_MACHINE "SYSTEMCurrentControlSetServices服务名称Parameters" "AppDirectory" "$INSTDIR"
              WriteRegStr HKEY_LOCAL_MACHINE "SYSTEMCurrentControlSetServices服务名称Parameters" "AppParameters" ""

              特别需要注意的是注册表AppDirectory的配置,这个是你程序所在的目录。
              如果你的软件是面向大众的话,建议将srvany.exe与你的程序放在一起(同一个文件夹),避免不必要的麻烦。
              如果你需要独立脚本完成这项任务的话,下午如果有时间我会提供一个,敬请关注。

      12.  

        高手你好,又发现一个问题,特来请教
        当用Srvany.exe成功注册成服务并启动时,进程管理器中会出现3个进程,一个是Srvany.exe,一个是cmd.exe,一个就是注册为服务的exe,那这个cmd.exe是在运行什么,我结束它似乎也没有对服务产生影响,如果这个进程不起任何作用,那是否能在注册时就不开启这个进程呢?

        •  

          我猜测那个cmd.exe是你调用的命令行安装并启动srvany.exe自定义服务的程序,cmd.exe一般是随着命令行启动而出现的,至于你那个cmd.exe为什么不消失,我认为是通过cmd安装并启动srvany.exe的服务时需要一个过程,特别是在启动一个服务时,这时调用命令需要不停的查询服务状态,这也就是为什么cmd.exe进程会驻留内存中,一旦服务完全启动,cmd.exe自然会退出,因为其使命已经完成。
          你可以观察一下这三个进程出现时,是不是过一段时间cmd.exe会自动退出。

          •  

            我观察了下,cmd不会自动退出,一直存在,并且好像是保持静止状态,并且我用你的UISrvany工具也会出现这个进程,怎样能够让这个进程自动结束呢?

            •  

              我的SrvanyUI工具创建的基于srvany.exe的自定义服务是不会产生额外的cmd.exe进程的,我怀疑可能是你需要建成服务的程序自己创建的,你可以试着创建其他程序的基于srvany.exe的自定义服务,比如说记事本程序notepad.exe或者nslookup.exe,再观察是否会有cmd.exe,如果没有,则说明可能这个进程是你那个作为服务运行的程序自己产生的。

      13.  
        土著 在 2013 年 8 月 30 日下午 5:10 说道:

        您好!照你的方法,我的bat文件也可以做成服务。有个问题请教,服务启停本质上是不是打开/关闭srvany.exe进程?
        如果我想通过服务直接启停bat文件,该如何做呢?
        请赐教,谢谢。

        •  

          开始 运行 输入 services.msc (或者在控制面板管理工具找到 服务) 打开服务管理控制台,找到你的服务右击 启动或者停止。

          •  

            感谢回复。
            我做了测试,我的bat脚本调用了python。停止服务可以停止srvany.exe进程,但是对调用的python“无能为力”。

            •  

              恩,你停止了srvany.exe的服务的话,srvany.exe和cmd.exe进程应该会停止,但是bat调用的Python将不会停止,如果bat仅仅是调用Python来处理脚本的话,建议直接写到srvany服务调用中去,附加参数以服务参数的形式给出。

      14.  
        horsequan 在 2013 年 11 月 24 日下午 3:41 说道:

        受益匪浅,谢谢分析!

      15.  

        楼主的文章很棒,谢谢!

      16.  
        halaing 在 2014 年 2 月 16 日上午 11:07 说道:

        相当好的文章,作者是很nice的牛人!!

      17.  
        龙哥··· 在 2014 年 3 月 15 日下午 8:27 说道:

        不错不错

      18.  
        bookhu 在 2015 年 3 月 17 日上午 10:43 说道:

        按以上方法成功了!但注销系统后应用程序就停止了,重新登录系统也不能重启。一点缺陷,请问有什么办法可以解决?多谢

  • 相关阅读:
    Java设置环境变量
    php 生成二维码
    php 生成读取csv文件并解决中文乱码
    php 过滤重复的数组
    php 读取,生成excel文件
    php 逐行读取文本文件
    php 多维数组按键值分类
    python学习,day2:利用列表做购物车实例
    python学习,day1作业:设计一个三级菜单
    python学习,day2:字典
  • 原文地址:https://www.cnblogs.com/findumars/p/5167765.html
Copyright © 2011-2022 走看看