Windows Mobile服务程序开发(Services Development)

http://www.microsoft.com/china/MSDN/library/Mobility/pocketpc/dnppc2k3ppcservices.mspx?mfr=true (中文)

http://www.pocketpcdn.com/articles/services.html (英文)(此版页面下方提供了两个示例,非常宝贵)

Samples

 

补充:在windows Mobile 5.0中,服务程序实现为Dll文件。服务Dll文件编译进设备的Windows目录后,在注册表添加相应信息(下文会有介绍),启动设备,WM便会通过services.exe进程根据注册表的设置加载相应的Dll文件,从而启动服务。服务都是作为services.exe的线程存在的。

(另外要注意,服务程序是需要较高权限的,感觉权限等级跟驱动差不多,经测试,通过ActiveSync拖进Windows目录下重启,服务是不会被加载的)

摘录:

简介

许多 Pocket PC 应用程序都需要后台进程。例如:

当插入 SD 卡时,显示一个窗口的程序

永久备份程序

控制 GPRS 流量的程序

Web 服务器

向任务栏添加特殊图标的程序

目前,几乎所有的 Pocket PC 开发人员都是创建一个可执行文件并将该文件的快捷方式放到 /Windows/StartUp 中,这样在重启后启动该程序并在后台运行。鉴于 Windows CE 中的进程数量限制为 32,这种方法存在严重的问题。例如,软重启后,XDA II Pocket PC 设备中运行有 27 个进程。如果您安装有 2-3 个需要后台进程的第三方程序,那么您就只有 1-2 个进程来运行程序!有些 Pocket PC 设备即使在硬重启后也有很多进程在运行,如图 1 所示。


图 1. 硬重启后运行在设备上的进程。

Microsoft 在 Windows Mobile 2003 中提出了该问题的一种解决方案。Windows Mobile 2003 支持作为不同的线程运行在一个进程中的 DLL 服务。它解决了该问题。本文说明如何为 Windows Mobile for Pocket PC 2003 创建和发布服务。

Pocket PC 服务接口类似于 Pocket PC 驱动程序接口。一项 Pocket PC 服务就是一个导出一组函数的 DLL。services.exe 进程加载这些 DLL 并通过调用这其中的一个函数来对它们进行初始化。

本文对于“将服务用于后台任务”的 Pocket PC 开发人员很具有吸引力!

利用 MFC 创建服务 DLL

为了实现基于 MFC 的服务,需要采取这些步骤:

在 Microsoft® eMbedded Visual C++® 中创建一个新 WCE MFC AppWizard (dll) 项目,如图 2 所示:


图 2. 创建新的 WCE MFC AppWizard (dll) 项目。

1.

添加导出函数定义(应当使用自己的前缀,而不用 MYS)。Services.exe 进程期望这些函数从各个服务 DLL 导出并调用它们来进行初始化并与服务进行通信:

extern "C" DWORD PASCAL EXPORT MYS_Close(DWORD dwData)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
return 0;
}

extern "C" DWORD PASCAL EXPORT MYS_Deinit(DWORD dwData)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
return 0;
}

extern "C" DWORD PASCAL EXPORT MYS_Init(DWORD dwData)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
return 1;
}

extern "C" DWORD PASCAL EXPORT MYS_IOControl(
DWORD dwData,
DWORD dwCode,
PBYTE pBufIn,
DWORD dwLenIn,
PBYTE pBufOut,
DWORD dwLenOut,
PDWORD pdwActualOut)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
return 1;
}

extern "C" DWORD PASCAL EXPORT MYS_Open(
DWORD dwData,
DWORD dwAccess,
DWORD dwShareMode)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
return 0;
}

extern "C" DWORD PASCAL EXPORT MYS_Read(
DWORD dwData,
LPVOID pBuf,
DWORD dwLen)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
return 0;
}

extern "C" DWORD PASCAL EXPORT MYS_Seek(
DWORD dwData,
long pos,
DWORD type)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
return 0;
}

extern "C" DWORD PASCAL EXPORT MYS_Write(
DWORD dwData,
LPCVOID pInBuf,
DWORD dwInLen)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
return 0;
}

这里,MYS 是函数名称前缀,应用程序用它并通过 Services.exe 来调用服务(此处的 MYS 表示 MY Service)。您应当使用您自己的 3-字母前缀来调用 _Init 和其他的函数。

由 于该 DLL 将会动态地进行链接,因此从该 DLL 导出的任何调用 MFC 的函数都必须要在函数的开头添加 AFX_MANAGE_STATE 宏。在对 MFC 进行任何调用之前,该宏要出现在每个函数中,这非常重要。这意味着,它必须作为函数中的第一条语句出现,甚至要位于任何对象变量的声明之前,因为它们的构 造函数可能会对 MFC DLL 进行调用。请参阅 MFC 技术说明 33 和 58,以获取其他详细信息。

2.

将这些函数名称添加到项目 .def 文件导出表中(您应当使用您自己的前缀,而不用 MYS)。“新项目向导”自动创建该文件:

EXPORTS
; Explicit exports can go here
MYS_Close
MYS_Deinit
MYS_Init
MYS_IOControl
MYS_Open
MYS_Read
MYS_Seek
MYS_Write

3.

向 MYS_Init 函数添加一些特殊的初始化代码。这里,您很可能需要创建一个新线程来封装所有的服务逻辑。为此要定义线程控制函数。该函数正是创建其他窗口、定时器或者任何其他应用程序特殊需要的地方。在该示例中,我们创建了一个定时器并运行线程消息循环。

UINT MyControllingFunction( LPVOID pParam )
{
theApp.m_nTimer = SetTimer(0, 0, 10 * 1000, MyTimerProc);

MSG msg;
while (GetMessage(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}

extern "C" DWORD PASCAL EXPORT MYS_Init(DWORD dwData)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());

theApp.m_pThread = AfxBeginThread( MyControllingFunction, 0);

return 1;
}

确保 MYS_Init 函数返回非零值,因为零返回值表示服务初始化失败并会引起立即卸载服务 DLL。

根据您的应用程序需要,您可以用同样的方式在其他的 MYS_ 方法中添加一些逻辑。

不使用 MFC 创建服务 DLL

为了实现基于 MFC 的服务,请采取下面的步骤:

在 Microsoft eMbedded Visual C++ 中创建一个新的 WCE 动态链接库项目,如图 3 所示:


图 3. 创建新的 WCE 动态链接库项目。

1.

添加导出函数定义(您应当使用您自己的前缀,而不用 MYS)。Services.exe 进程期望这些函数从各个服务 DLL 导出并调用它们来进行初始化并与服务进行通信:

DWORD MYS_Close(DWORD dwData)
{
return 0;
}

DWORD MYS_Deinit(DWORD dwData)
{
return 0;
}

DWORD MYS_Init(DWORD dwData)
{
return 1;
}

DWORD MYS_IOControl(
DWORD dwData,
DWORD dwCode,
PBYTE pBufIn,
DWORD dwLenIn,
PBYTE pBufOut,
DWORD dwLenOut,
PDWORD pdwActualOut)
{

return 1;
}

DWORD MYS_Open(
DWORD dwData,
DWORD dwAccess,
DWORD dwShareMode)
{
return 0;
}

DWORD MYS_Read(
DWORD dwData,
LPVOID pBuf,
DWORD dwLen)
{

return 0;
}

DWORD MYS_Seek(
DWORD dwData,
long pos,
DWORD type)
{

return 0;
}

DWORD MYS_Write(
DWORD dwData,
LPCVOID pInBuf,
DWORD dwInLen)
{

return 0;
}

这里,MYS 是函数名称前缀,应用程序用它并通过 Services.exe 来调用服务(此处的 MYS 表示 MY Service)。您应当使用您自己的 3-字母前缀来调用 _Init 和其他的函数。

2.

将这些函数名称添加到项目 .def 文件导出表中(您应当使用您自己的前缀,而不用 MYS)。您必须手动创建用项目命名而扩展名为 .def 的文本文件,并将它添加到项目中:

EXPORTS
; Explicit exports can go here
MYS_Close
MYS_Deinit
MYS_Init
MYS_IOControl
MYS_Open
MYS_Read
MYS_Seek
MYS_Write

3.

向 MYS_Init 函数添加一些特殊的初始化代码。这里,您很可能需要创建一个新线程来封装所有的服务逻辑。为此,要定义线程控制函数。该函数正是创建其他窗口、定时器或者任何其他应用程序特殊需要的地方。在该示例中,我们创建了一个定时器并运行线程消息循环。

unsigned long __cdecl SSWControllingFunction( LPVOID pParam )
{
g_nTimer = SetTimer(0, 0, 10 * 1000, SSWTimerProc);

MSG msg;
while (GetMessage(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}

DWORD MYS_Init(DWORD dwData)
{

HANDLE hThread = CreateThread( 0, 0, SSWControllingFunction, 0, 0, 0);

return 1;
}

确保 MYS_Init 函数返回非零值,因为零返回值表示服务初始化失败并会引起立即卸载服务 DLL。

根据您的应用程序需要,您可以用同样的方式在其他的 MYS_ 方法中添加一些逻辑。

在注册表中注册服务

为了使在系统启动时自动启动服务,您应当向注册表 HKEY_LOCAL_MACHINE/Services/Service 项添加一个唯一命名的子项,并指定下面的值:

Order : REG_DWORD

Services.exe 加载各项服务的次序。首先加载次序最低的服务。

Dll : REG_SZ

加载动态链接库 (DLL) 文件。只有文件名而没有路径。该 DLL 应当位于 /Windows 文件夹中。

Keep : REG_DWORD

对于应当在后台运行的服务 Keep 必须为 1,如果 Keep = 0,那么在初始化后将会立即卸载该 DLL。

Prefix : REG_SZ

从服务 DLL 导出函数的前缀(而不是 xxx_Init 中的 xxx,等等)。必须是 3 个符号。

Index : REG_SZ

服务索引(设置为 0)。

DisplayName : REG_SZ

显示服务名称。

Description : REG_SZ

显示服务的说明。

Context : REG_DWORD

传递给初始化例程的初始值(必须为 0)。

例如,对于基于 MFC 的示例服务,为了在启动时作为服务而启动,应当使用下面的注册表项。图 4 显示了注册表中的其他服务设置。

[HKEY_LOCAL_MACHINE/Services/MyServ]
"Dll"="MYS.dll"
"Order"=dword:8
"Keep"=dword:1
"Prefix"="MYS"
"Index"=dword:0
"Context"=dword:0
"DisplayName"="Sample MFC Service"
"Description"="Sample Service demonstratig MFC usage"

图 4.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值