如何应用VS2010中来创建Windows服务程序

如何应用VS2010中来创建Windows服务程序,第1张

1,new project ->选择 ATL Project, 设置工程名,如:PureSsl

2,在向导的“Application Setting”页,“Application Type”项选择: Service(EXE)

3, 更改主文件PureSsl.cpp,如下:

// PureSsl.cpp : Implementation of WinMain

#include "stdafx.h"

#include "resource.h"

#include "PureSsl_i.h"

#include <atlcomcli.h>

#include <stdio.h>

class CPureSslModule : public ATL::CAtlServiceModuleT<CPureSslModule, IDS_SERVICENAME >

{

public :

DECLARE_LIBID(LIBID_PureSslLib)

DECLARE_REGISTRY_APPID_RESOURCEID(IDR_PURESSL, "{A0D1CDBB-EE9F-4110-9710-498FEB5194F5}")

HRESULT InitializeSecurity() throw()

{

// TODO : Call CoInitializeSecurity and provide the appropriate security settings for your service

// Suggested - PKT Level Authentication,

// Impersonation Level of RPC_C_IMP_LEVEL_IDENTIFY

// and an appropiate Non NULL Security Descriptor.

return S_OK

}

HRESULT RegisterAppId(bool bService = false) throw ()

HRESULT PreMessageLoop(int nShowCmd) throw()

HRESULT PostMessageLoop() throw()

void OnStop() throw()

void OnPause() throw()

void OnContinue() throw()

}

HRESULT CPureSslModule::RegisterAppId(bool bService ) throw ()

{

HRESULT hr = S_OK

BOOL res = __super ::RegisterAppId(bService)

if (bService)

{

if (IsInstalled())

{

SC_HANDLE hSCM = ::OpenSCManagerW(NULL, NULL, SERVICE_CHANGE_CONFIG)

SC_HANDLE hService = NULL

if (hSCM == NULL)

{

hr = ATL::AtlHresultFromLastError()

}

else

{

hService = ::OpenService(hSCM, m_szServiceName, SERVICE_CHANGE_CONFIG)

if (hService != NULL)

{

::ChangeServiceConfig(hService, SERVICE_NO_CHANGE,

SERVICE_AUTO_START,// 修改服务为自动启动

NULL, NULL, NULL, NULL, NULL, NULL, NULL,

m_szServiceName)// 通过修改资源IDS_SERVICENAME 修改服务的显示名字

SERVICE_DESCRIPTION Description

TCHAR szDescription[1024]

ZeroMemory(szDescription, 1024)

ZeroMemory(&Description, sizeof (SERVICE_DESCRIPTION))

lstrcpy(szDescription, _T("测试服务描述信息" ))

Description.lpDescription = szDescription

::ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &Description)

::CloseServiceHandle(hService)

}

else

{

hr = ATL::AtlHresultFromLastError()

}

::CloseServiceHandle(hSCM)

}

}

}

return hr

}

HRESULT CPureSslModule::PreMessageLoop(int nShowCmd) throw()

{

// 让暂停继续按钮可以使用

m_status.dwControlsAccepted = m_status.dwControlsAccepted | SERVICE_ACCEPT_PAUSE_CONTINUE

HRESULT hr = __super::PreMessageLoop(nShowCmd)

// 微软Bug

if (hr == S_FALSE)

hr = S_OK

// 这里添加自己的初始化代码...

if (SUCCEEDED(hr))

{

// 这个状态一定要修改,否则会出现1053错误,

// 这个错误我花了很多时间才搞定

SetServiceStatus(SERVICE_RUNNING)

}

return hr

}

HRESULT CPureSslModule::PostMessageLoop() throw()

{

HRESULT hr = __super ::PostMessageLoop()

if (FAILED(hr))

return hr

// 这里添加自己的清除代码

return hr

}

void CPureSslModule::OnStop() throw()

{

__super::OnStop()

SetServiceStatus(SERVICE_STOPPED)

}

void CPureSslModule::OnPause() throw()

{

__super::OnPause()

SetServiceStatus(SERVICE_PAUSED)

}

void CPureSslModule::OnContinue() throw()

{

__super::OnContinue()

SetServiceStatus(SERVICE_RUNNING)

}

CPureSslModule _AtlModule

//

extern "C" int WINAPI _tWinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/,

LPTSTR /*lpCmdLine*/, int nShowCmd)

{

return _AtlModule.WinMain(nShowCmd)

}

4, 编译并设置服务

当ATL COM对象生成作为服务,它才会注册为本地服务器,并且,在控制面板不会出现在服务列表。这是因为,调试服务作为本地服务器上作为服务更为方便。若要安装它作为服务,请运行以下命令提示:

YourEXE.exe /Service

若要卸载该文件,请运行以下 *** 作:

YourEXE.exe /UnregServer

打开cmd窗口,进入生成的PureSsl.exe所在的目录执行:

> PureSsl.exe /service

>net start PureSsl

即可将服务设置到服务管理器,并启动它。

要删除服务:

>sc delete PureSsl

5, 注意

未经第4步直接运行会报以下错误:

The program '[24636] PureSsl.exe: Native' has exited with code 2 (0x2).

若要直接在vs中调试运行应当执行:

YourEXE.exe /UnregServer

否则会报

First-chance exception at 0x75c49673 in CloudS.exe: 0x00000005: 拒绝访问。.

The thread 'Win32 Thread' (0x314) has exited with code 1063 (0x427).

这两天想学习关于如何编写windows服务程序的知识,就上网查了些资料。看了一篇文章《用C 语言编写Windows 服务程序的五个步骤》。但可能由于译者的疏忽,忘记了将关键代码放入该文档,导致初学者可能会看不懂。所以又查阅了相关资料。自己完成了《用C 语言编写Windows 服务程序的五个步骤》中的样例程序。

在本文中我希望能给初学者一些帮助,大致讲一下编写windows服务程序需要的知识。

首先Microsoft Windows 服务(即,以前的NT 服务)使您能够创建在它们自己的Windows 会话中可长时间运行的可执行应用程序。这些服务可以在计算机启动时自动启动,可以暂停和重新启动而且不显示任何用户界面。这使服务非常适合在服务器上使用,或任何时候,为了不影响在同一台计算机上工作的其他用户,需要长时间运行功能时使用。还可以在不同于登录用户的特定用户帐户或默认计算机帐户的安全上下文中运行服务。

服务是有状态的,当我们使用windows自带的服务管理程序sc.exe查看服务状态时可以显示服务的当前状态,这个状态是由我们在程序代码中进行控制的。你最好在服务初始化的时候将服务设置为SERVICE_START_PENDING,当初始化完毕时设为SERVICE_RUNNING,这些状态是系统自定义的状态,可通过msdn查看其他状态。这个状态信息你会在sc.exe中看到。

在编写windows服务程序过程中你需要关注的函数有:

1.首先是main函数,由于windows服务不需要界面,所以大部分程序为win32控制台应用程序,所以程序主函数为main 而不是WinMain()。在主函数要做的主要工作就是初始化一个SERVICE_TABLE_ENTRY 分派表结构体,然后调用StartServiceCtrlDispatcher()这将把调用进程的主线程转换为控制分派器。该分派器启动一个新线程,该线程运行分派表中对应于你的服务的ServiceMain()函数。ServiceMain()函数将在下面提到。

此过程示例代码如下:

SERVICE_TABLE_ENTRY entrytable[2]

entrytable[0].lpServiceName="testservice"

entrytable[0].lpServiceProc=(LPSERVICE_MAIN_FUNCTION)ServiceMain

entrytable[1].lpServiceName=NULL

entrytable[1].lpServiceProc=NULL

StartServiceCtrlDispatcher(entrytable)

在这之后系统将自动创建一个线程去执行ServiceMain函数的内容,你应该将你要执行的任务在ServiceMain中循环,这样服务就开始运行了。

2.ServiceMain函数为void WINAPI ServiceMain(int argc, char** argv)格式的函数,函数名字可以任意定义。它的作用就是:将你需要执行的任务放到该函数中循环执行即可。这就是服务程序的工作函数。在ServiceMain执行你的任务前,需要给SERVICE_TABLE_ENTRY 分派表结构体进行赋值,注意由于此时服务还没有开始执行你的任务所以我们将服务的状态设置为SERVICE_START_PENDING,即正在初始化。我们进行如下赋值:

servicestatus.dwServiceType = SERVICE_WIN32

servicestatus.dwCurrentState = SERVICE_START_PENDING

servicestatus.dwControlsAccepted=SERVICE_ACCEPT_SHUTDOWN|SERVICE_ACCEPT_STOP

//在本例中只接受系统关机和停止服务两种控制命令

servicestatus.dwWin32ExitCode = 0

servicestatus.dwServiceSpecificExitCode = 0

servicestatus.dwCheckPoint = 0

servicestatus.dwWaitHint = 0

hstatus = ::RegisterServiceCtrlHandler("testservice", CtrlHandler)

CtrlHandler为void WINAPI CtrlHandler(DWORD request)型的函数,函数名字可以任意设定。将在下一点讲到。

Hstatus为SERVICE_STATUS_HANDLE类型的全局变量。当需要改变服务状态时SetServiceStatus()函数需要它做为参数来标识一个服务。

3. void WINAPI CtrlHandler(DWORD request),函数的主要功能是,接收系统传递的控制命令,比如当你通过sc.exe关闭服务时,该函数会收到SERVICE_CONTROL_STOP消息,你就可以对服务进行必要的管理。在本例子程序中就只接收SERVICE_ACCEPT_SHUTDOWN和SERVICE_ACCEPT_STOP消息,这是通过前面给servicestatus赋值设定的。

这样一个基本的服务程序就完成了。

下面贴出我的示例代码仅供参考。该代码在vs2008中调试通过。本文结束的时候会附上如何安装服务。

#include <stdio.h>

#include <Windows.h>

#define SLEEP_TIME 5000 //间隔时间

#define FILE_PATH "C:\\log.txt" //信息输出文件

bool brun=false

SERVICE_STATUS servicestatus

SERVICE_STATUS_HANDLE hstatus

int WriteToLog(char* str)

void WINAPI ServiceMain(int argc, char** argv)

void WINAPI CtrlHandler(DWORD request)

int InitService()

int WriteToLog(char* str)

{

FILE* pfile

fopen_s(&pfile,FILE_PATH,"a+")

if (pfile==NULL)

{

return -1

}

fprintf_s(pfile,"%s\n",str)

fclose(pfile)

return 0

}

void WINAPI ServiceMain(int argc, char** argv)

{

servicestatus.dwServiceType = SERVICE_WIN32

servicestatus.dwCurrentState = SERVICE_START_PENDING

servicestatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN|SERVICE_ACCEPT_STOP//在本例中只接受系统关机和停止服务两种控制命令

servicestatus.dwWin32ExitCode = 0

servicestatus.dwServiceSpecificExitCode = 0

servicestatus.dwCheckPoint = 0

servicestatus.dwWaitHint = 0

hstatus = ::RegisterServiceCtrlHandler("testservice", CtrlHandler)

if (hstatus==0)

{

WriteToLog("RegisterServiceCtrlHandler failed")

return

}

WriteToLog("RegisterServiceCtrlHandler success")

//向SCM 报告运行状态

servicestatus.dwCurrentState = SERVICE_RUNNING

SetServiceStatus (hstatus, &servicestatus)

//下面就开始任务循环了,你可以添加你自己希望服务做的工作

brun=true

MEMORYSTATUS memstatus

char str[100]

memset(str,'\0',100)

while (brun)

{

GlobalMemoryStatus(&memstatus)

int availmb=memstatus.dwAvailPhys/1024/1024

sprintf_s(str,100,"available memory is %dMB",availmb)

WriteToLog(str)

Sleep(SLEEP_TIME)

}

WriteToLog("service stopped")

}

void WINAPI CtrlHandler(DWORD request)

{

switch (request)

{

case SERVICE_CONTROL_STOP:

brun=false

servicestatus.dwCurrentState = SERVICE_STOPPED

break

case SERVICE_CONTROL_SHUTDOWN:

brun=false

servicestatus.dwCurrentState = SERVICE_STOPPED

break

default:

break

}

SetServiceStatus (hstatus, &servicestatus)

}

void main()

{

SERVICE_TABLE_ENTRY entrytable[2]

entrytable[0].lpServiceName="testservice"

entrytable[0].lpServiceProc=(LPSERVICE_MAIN_FUNCTION)ServiceMain

entrytable[1].lpServiceName=NULL

entrytable[1].lpServiceProc=NULL

StartServiceCtrlDispatcher(entrytable)

}

如何安装服务:

运行命令提示符cmd.exe

输入sc create testservicename binpath= D:\test.exe

输入sc start testservicename 启动服务

输入sc query 会在最底部显示你的服务当前的状态

输入sc stop testservicename 停止服务

输入sc delete testservicename删除服务,该服务将在下次重启后删除,在重启之前将不能注册同一个名字的服务。

一、打开WinCE模拟器启动Visual Studio 2008

在菜单栏里:工具->连接到设备,d出“连接到设备”这个界面,在“平台”下拉列表里面选择为“Windows CE”,之后在显示出来的列表中选择“Pocket PC 2003 SE 仿真程序”,然后点击“连接”按钮。截图如下:

连接成功后,就d出了仿真模拟器的界面,界面完全就是一个掌上电脑,很不错哦!截图如下:

二、设置WinCE仿真模拟器的属性

如果想要上网,你一定要先装上Virtual PC 2007 setup.exe,然后再重新连接模拟器。Virtual PC直接装完就OK了,无需对其进行任何设置。

1、设置共享文件夹

单击模拟器界面中的菜单栏:文件->配置,在“仿真程序属性”界面中,“常规”选项卡里面,选择你的“共享文件夹”的目录。然后确定即可,最后要插入底座才生效哦。截图如下:

2、设置网络

再提一下,先要装Virtual PC 2007。(好啰嗦……呵呵)

进入“仿真程序属性”界面的“网络”选项卡,勾上“启用NE2000 PCMCIA网络适配器并绑定到”,下拉列表中选择“数据包计划程序微型端口”。确认即可,最后要插入底座才生效哦。当然,你还要在模拟器中设置网络连接的属性才能上网,一定要看完再 *** 作哦!

截图如下:

3、设置串口、耳机等

进入“仿真程序属性”界面的“外围设备”选项卡,勾上相应的选项即可。截图如下:

4、插入底座,使设置生效

在VS2008的菜单栏中,工具->设备仿真器管理,右击你目前正在用的“Pocket PC 2003 SE 仿真程序”,选择“连接”,然后再次右击,选择“插入底座”,现在你的模拟器就可以使用你的电脑上的那些网络、串口、耳机等资源了。截图如下:


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/12079760.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-20
下一篇 2023-05-20

发表评论

登录后才能评论

评论列表(0条)

保存