图片 2

Windows中实现不依赖账户登录的开机启动程序,不依赖账

Windows中完成不依附账户登入的开机运维程序,不借助账

在Windows中诸多的天职,大家盼望能够在Windows
运维现在自动运维。比方,公司有个订饭系统,基本每日都急需报到去订饭,于是写2个本子达成全自动订饭。但是您的微管理器天天要关机,当然不愿意开机后还索要手动运营那个订饭脚本了。于是此时大家要将其这种本子完毕为开机自动运行脚本。
但要注意本文要讲的开机启动的程序,是在用户还未有登入的情形下促成运转的。换句话说,本文描述的开机运转的程序运营在Session
0中
首要介绍了3中方法, 我们能够选择合适的艺术去达成。

前言:

透过探讨Windows服务注册卸载的法则,以为它并从未什么样特别复杂的事物,Windows服务正在一步步退去它那神秘的面纱,至于是还是不是常娥,我们可要睁大眼睛看理解了。

Windows Service

当Windows
运营的时候,还从未登入账号的时候,此时Windows中安装为auto状态的Service将会在Session 0中运维。能够遵照如下步骤去落实Windows Service:

  1. 一经还未有落到实处过Windows 瑟维斯 程序的校友,能够参见那篇作品《Simple
    Windows Service in C++》去贯彻。
  2. 通过命令行创立Service, 首要注意start= auto安装Service为开机运转。

    sc create “SERVICE_NAME” binpath= “SERVICE_PROGRAM” displayname= “SERVICE_DESCRIPTION” start= auto

工作中也许会遇到以下情况,利用windows作为中转,来贯彻两台linux服务器的文件传输。

接下去研商一下Windows服务的运营和休息的流程。

Windows Startup Script

遵从如下步骤:

  1. 开拓当地的组战术管理,运维命令gpedit
    贰.
    然后所有人家展开Computer Configuration->Windows Settings->Scripts->
    Startup, 在Startup中配置须要开机运营的剧本或然程序。
    在机械中的配置,大家都不遗余力的只求自动化,于是希望因此脚本来完毕这些动作。可惜未有CMD
    命令能够平素行使这种艺术增添运行程序,后来博主搜索了一些方式,有经过一贯修改注册表的、也许有通过vb脚本去贯彻的,但那些点子个人感觉还不够直接,轻易。
    于是乎博主找到了接下去要说的格局,通过Windows定期职务管理器。

落到实处步骤:

开发银行流程

运转时自然是从程序的入口点开首

extern "C" int WINAPI _tWinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, 
                                LPTSTR /*lpCmdLine*/, int nShowCmd)
{
    //这里是程序的入口点,直接调用了ATL框架中的CServiceModuleT类的WinMain方法
    return _AtlModule.WinMain(nShowCmd);
}

接下去进入_AtlModule.WinMain查看细节。

//处理命令行参数后,开始启动
if (pT->ParseCommandLine(lpCmdLine, &hr) == true)
    hr = pT->Start(nShowCmd);

WinMain方法中,主假若对命令行参数实行管理后,调用Start方法开始展览运维。

HRESULT Start(_In_ int nShowCmd) throw()
{
    T* pT = static_cast<T*>(this);
    // Are we Service or Local Server
    CRegKey keyAppID;
    LONG lRes = keyAppID.Open(HKEY_CLASSES_ROOT, _T("AppID"), KEY_READ);
    if (lRes != ERROR_SUCCESS)
    {
        m_status.dwWin32ExitCode = lRes;
        return m_status.dwWin32ExitCode;
    }

    CRegKey key;
    lRes = key.Open(keyAppID, pT->GetAppIdT(), KEY_READ);
    if (lRes != ERROR_SUCCESS)
    {
        m_status.dwWin32ExitCode = lRes;
        return m_status.dwWin32ExitCode;
    }

    TCHAR szValue[MAX_PATH];
    DWORD dwLen = MAX_PATH;
    //读取注册表信息
    //通过regserver方式注册服务,则lRes为ERROR_SUCCESS
    //通过service方式注册服务,   则lRes不等于ERROR_SUCCESS
    lRes = key.QueryStringValue(_T("LocalService"), szValue, &dwLen);

    m_bService = FALSE;
    if (lRes == ERROR_SUCCESS)
        m_bService = TRUE;

    if (m_bService)
    {
        //以Windows服务的方式运行
        SERVICE_TABLE_ENTRY st[] =
        {
            { m_szServiceName, _ServiceMain },
            { NULL, NULL }
        };
        if (::StartServiceCtrlDispatcher(st) == 0)
            m_status.dwWin32ExitCode = GetLastError();
        return m_status.dwWin32ExitCode;
    }
    // local server - call Run() directly, rather than
    // from ServiceMain()        
    //以普通应用程序的方式运行
    m_status.dwWin32ExitCode = pT->Run(nShowCmd);
    return m_status.dwWin32ExitCode;
}

Start方法中会依照读取到的注册表音信,来支配是还是不是以劳动的措施运维。假使是由此RegServer格局注册服务,则以常备程序运转;借使是通过Service情势注册服务,则以Windows服务的不二诀窍运维。

一般程序方法运转,不在本文的座谈范围以内,上面来看一下以Windows服务格局运维的历程。

以Windows服务措施运转以来,程序会调用StartServiceCtrlDispatcher方法,看一下有关此方法的MSDN的表明

Connects the main thread of a service process to the service control manager, which causes the thread to be the service control dispatcher thread for the calling process.


Remarks
When the service control manager starts a service process, it waits for the process to call the StartServiceCtrlDispatcher function. The main thread of a service process should make this call as soon as possible after it starts up (within 30 seconds). If StartServiceCtrlDispatcher succeeds, it connects the calling thread to the service control manager and does not return until all running services in the process have entered the SERVICE_STOPPED state. The service control manager uses this connection to send control and service start requests to the main thread of the service process. The main thread acts as a dispatcher by invoking the appropriate HandlerEx function to handle control requests, or by creating a new thread to execute the appropriate ServiceMain function when a new service is started.

这段话的马虎是
“调用此方法能够与服务管理器创设连接,那样服务管理器就可以处理服务的动静”,实际是劳动管理器发出指令后,服务可以对收到到的吩咐进行响应。

“当服务管理器运行二个劳动进度,服务管理器会等待服务进程调用StartServiceCtrlDispatcher方法。服务进度的主线程必须确认保证此方法在30秒内被尽早的实施。假设StartServiceCtrlDispatcher方法成功与服务管理器建构连接,那么它会等到劳动的情景变为SELANDVICE_STOPPED后才回来”。

想来,当Start方法调用StartServiceCtrlDispatcher后,会进入到_ServiceMain方法。

void ServiceMain(
        _In_ DWORD dwArgc,
        _In_reads_(dwArgc) _Deref_pre_z_ LPTSTR* lpszArgv) throw()
{
    lpszArgv;
    dwArgc;
    // Register the control request handler
    m_status.dwCurrentState = SERVICE_START_PENDING;
    m_dwThreadID = GetCurrentThreadId();
    //注册命令处理程序,用于响应服务管理器的控制命令
    RegisterServiceCtrlHandler(m_szServiceName, _Handler);

    //设置服务的状态为已启动
    SetServiceStatus(SERVICE_START_PENDING);

    m_status.dwWin32ExitCode = S_OK;
    m_status.dwCheckPoint = 0;
    m_status.dwWaitHint = 0;

    T* pT = static_cast<T*>(this);

    // When the Run function returns, the service has stopped.
    m_status.dwWin32ExitCode = pT->Run(SW_HIDE);
    //当Run方法结束后,会设置方法的状态为已停止
    SetServiceStatus(SERVICE_STOPPED);
}

_ServiceMain方法中珍视是挂号了2个劳务调整命令的管理程序,然后设置服务的事态为已开行,然后调用Run方法。

HRESULT Run(_In_ int nShowCmd = SW_HIDE) throw()
{
    HRESULT hr = S_OK;
    T* pT = static_cast<T*>(this);
    //初始化Com相关的东西
    hr = pT->PreMessageLoop(nShowCmd);

    if (hr == S_OK)
    {
        //处理Msg消息
        pT->RunMessageLoop();
    }

    if (SUCCEEDED(hr))
    {
        //释放Com相关资源
        hr = pT->PostMessageLoop();
    }

    return hr;
}

Run方法中重要性是循环管理Msg新闻,幸免主线程退出。

时至明日,服务到底完全运营了。

前方看到_ServiceMain方法中登记了一个劳动调节命令管理程序,接下去看一下以此法子做了怎么样。

void Handler(_In_ DWORD dwOpcode) throw()
{
    T* pT = static_cast<T*>(this);

    switch (dwOpcode)
    {
        //停止命令
    case SERVICE_CONTROL_STOP:
        pT->OnStop();
        break;
        //暂停命令
    case SERVICE_CONTROL_PAUSE:
        pT->OnPause();
        break;
        //恢复命令
    case SERVICE_CONTROL_CONTINUE:
        pT->OnContinue();
        break;
    case SERVICE_CONTROL_INTERROGATE:
        pT->OnInterrogate();
        break;
    case SERVICE_CONTROL_SHUTDOWN:
        pT->OnShutdown();
        break;
    default:
        pT->OnUnknownRequest(dwOpcode);
    }
}

能够见见,那些措施依照区别的调整命令,做了差别的拍卖。

 

Windows Schedule Task

Windows定期职责管理器,提供了有力的作用:能够定期的实行职务,除了根据时间去触发定时任务,其还提供了开机运行触及程序运转的功能,你可以通过图形界面包车型客车方法布署,也足以经过命令方式:

  • 次第展开Control Panel->Administrative Tools->Task Scheduler,然后再里面新建自身的天职。主要注意以下两点:
    • 使时局营的账号选成”System”
    • 触发器中,选用At Startup触发器
  • 运用如下命令行:

schtasks /create /TN "TASK_NAME" /RU SYSTEM /SC ONSTART /TR "TASK_PROGRAM"

壹、FTP上传和下载的bat脚本。

Windows服务的起步流程总括

图片 1

 

本子分为两局地:可推行bat脚本和ftp命令文件;

停下流程

上边大家看来当服务接受到结束服务的命令后,Hanlder方法会通过调用pT->OnStop方法来举行管理。

void OnStop() throw()
{
    SetServiceStatus(SERVICE_STOP_PENDING);
    ::PostThreadMessage(m_dwThreadID, WM_QUIT, 0, 0);
}

OnStop方法中,通过SetServiceStatus方法来安装服务意况为正值结束。并因而PostThreadMessage产生一个WM_QUIT的消息。

void RunMessageLoop() throw()
{
    MSG msg;
    while (GetMessage(&msg, 0, 0, 0) > 0)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

此时RunMessageLoop中的While循环中断。

While循环中断后会通过SetServiceStatus设置服务景况为已终止。

接下来WinMain方法推行完成,服务开始展览剥离。

那正是整个的服务结束流程。

 

可执行bat脚本:

Windows服务的停下流程总计

图片 2

 

@echo off
ftp -s:D:\ftp\ftp.txt

给服务充裕自个儿的启航和甘休时的管理

既然已经对Windows服务的启航和终止的流程有了贰个大致的打听,那么给劳务充足本人的起步和结束时的拍卖也就相对轻巧了一部分。

上边是自家的兑今世码

class CServicesModule : public ATL::CAtlServiceModuleT< CServicesModule, IDS_SERVICENAME >
{
public :
    DECLARE_LIBID(LIBID_ServicesLib)
    DECLARE_REGISTRY_APPID_RESOURCEID(IDR_SERVICES, "{0794CF96-5CC5-432E-8C1D-52B980ACBE0F}")
        HRESULT InitializeSecurity() throw()
    {
        // TODO : 调用 CoInitializeSecurity 并为服务提供适当的安全设置
        // 建议 - PKT 级别的身份验证、
        // RPC_C_IMP_LEVEL_IDENTIFY 的模拟级别
        // 以及适当的非 NULL 安全描述符。

        return S_OK;
    }
    //服务启动
    HRESULT Load();
    //服务停止
    HRESULT UnLoad();

    HRESULT Run(_In_ int nShowCmd = SW_HIDE) throw()
    {
        HRESULT hr = S_OK;
        OutputDebugString(_T("准备启动服务"));
        hr = Load();
        if(hr)
        {
            OutputDebugString(_T("启动服务失败"));
            return hr;
        }
        OutputDebugString(_T("Services服务已启动"));

        hr = ATL::CAtlServiceModuleT< CServicesModule, IDS_SERVICENAME >::Run(nShowCmd);

        hr = UnLoad();
        OutputDebugString(_T("Services服务正常退出"));
        return hr;
    }
};

CServicesModule _AtlModule;

//
extern "C" int WINAPI _tWinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, 
                                LPTSTR /*lpCmdLine*/, int nShowCmd)
{
    return _AtlModule.WinMain(nShowCmd);
}


HRESULT CServicesModule::Load()
{
    OutputDebugString(_T("服务正在启动"));
    return 0;
}

HRESULT CServicesModule::UnLoad()
{
    OutputDebugString(_T("服务正在停止"));
    return 0;
}

 

ftp命令ftp.txt:

数不清链接

玩转Windows服务多元——创造Windows服务

玩转Windows服务多元——Debug、Release版本的挂号和卸载,及其规律

玩转Windows服务连串——无COM接口Windows服务运行失败原因及消除方案

玩转Windows服务连串——服务运维、截至流程浅析

玩转Windows服务体系——Windows服务小本事

玩转Windows服务多元——命令行管理Windows服务

玩转Windows服务多元——Windows服务启动超时时间

玩转Windows服务连串——使用Boost.Application急迅创设Windows服务

玩转Windows服务多元——给Windows服务加多COM接口

open 192.168.1.166
ftp-user
passwd
prompt off
lcd D:\ftp
cd /home/myftp
mget *
close
open 10.10.12.12
ftp-user<br>passwd
lcd D:\ftp
cd /home/myftp
mput *
prompt on
bye
quit

 贰、加入Windows定期任务(网摘):

【定期职务|开机运营】Windows Server 二〇〇八/二〇一二安排职布满署(职责计划程序)每秒钟实践BAT

开荒布署职分急忙格局(在 “管理工科具”内):

C:\ProgramData\Microsoft\Windows\Start
Menu\Programs\Administrative Tools\Task Scheduler.lnk