REALbasic 中使用结构体作为 Win32 API 的参数及使用 Win32 API 停止服务

在之前,我使用 ShellExecute 这个 API 来执行命令(《REALbasic 中使用 ShellExecute 执行命令》),然后通过这个方法来停止某个服务,但是今天想加服务运行状态检测,这样就可以在服务没有运行的情况下不再询问用户是否需要停止某个服务。

为了省事,我一开始决定同样使用 cmd 去执行一个命令,将服务状态输出到一个临时文件中,再通过读取这个临时文件,查找特征字符串来判断服务是否运行:

// 伪代码
ShellExecute("cmd.exe /c sc query service_name > tmpfile")
dim serviceStatus as string
serviceStatus = TextInputStream.Open(tmpfile).ReadAll()
if instr(serviceStatus, "STOPPED") < 1 then
  // 提示用户是否停止服务
end if

但是这样做不太靠谱,因为 sc 这个命令执行是要时间的,而 ShellExecute 是异步的,这就导致了在调用 ShellExecute 执行完 sc query 之后,临时文件 tmpfile 里并不是马上就有服务状态的内容了。

为了防止这个情况,我再加了一个临时文件内容的检测,如果为空的话,sleep 100ms,再继续读取,如果超过 10 次仍没有内容,直接当作服务正在运行来对待。

// 伪代码
ShellExecute("cmd.exe /c sc query service_name > tmpfile")
dim serviceStatus as string
dim tryCount as integer
while tryCount < 10 and serviceStatus = ""
  tryCount = tryCount + 1
  App.SleepCurrentThread(100)
  serviceStatus = TextInputStream.Open(tmpfile).ReadAll()
 
wend
if instr(serviceStatus, "STOPPED") < 1 then
  // 提示用户是否停止服务
end if

但是这样仍然不能百分百保证正确,于是想到可不可以继续用 win32 api 来做这些,Google 了一下,找到一篇博客[1],看了之后发现如果只需要停止服务的话,还是蛮简单的,决定使用 win32 api 来实现我想要的功能了。

在停止服务这个过程中需要用到的 win32 api 有:OpenSCManagerW、OpenServiceW、QueryServiceStatus、ControlService,还有一个结构体:SERVICE_STATUS。

win32 api 的参数都很好对应,数值、句柄类型的参数直接使用 Integer 即可,字符串类型使用 CString,而 SERVICE_STATUS 这个结构体也可以直接通过工程菜单添加。

在传参的时候需要注意两点:

  1. 如果是字符串类型的参数并且调用的接口是 Unicode 类型的,那么需要在传入参数之前,将参数值转换为 Unicode 编码。可以通过 ConvertEncoding(text, Encodings.UTF16) 来转换。
  2. 如果参数是结构体,那么参数前的传参方式就要写 ByRef,也就是按引用传值,字符串和数值类型的参数可以不写或者写 ByVal。

以下是 4 个 win32 api 的 REALbasic 定义:

soft declare function OpenSCManagerW Lib "advapi32.dll" _
(ByVal lpMachineName As CString, ByVal lpDatabaseName As CString, _
ByVal dwDesiredAccess As Integer) As Integer
 
soft declare function OpenServiceW lib "advapi32.dll" _
(ByVal hSCManager As Integer, ByVal lpServiceName As CString, _
ByVal dwDesiredAccess As Integer) As Integer
 
soft declare function QueryServiceStatus lib "advapi32.dll" _
(byval hService as integer, byref lpServiceStatus as SERVICE_STATUS) _
as boolean
 
soft declare function ControlService lib "advapi32.dll" _
(byval hService as integer, byval dwControl as integer, _
byref lpServiceStatus as SERVICE_STATUS) as boolean

有了 api 定义之后,就可以直接根据上面提到的 vc++ 流程来停止某个服务了。

完整的服务操作 api 可以参阅微软的 MSDN。

这样看来,REALbasic 要写出支持 Windows 7 特性的应用程序也不是难事:)

参数资料

  1. VC++启动和停止服务, huangchonghai
  2. QueryServiceStatus, MSDN
发表评论?

0 条评论。

发表评论


注意 - 你可以用以下 HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>