把nssm的windows api的c语言函数签名转化为vfp代码

2025-03-08

把nssm的windows api的c语言函数签名转化为vfp代码

把c语言函数签名转化为vfp代码

Visual FoxPro (VFP) 是一种基于 xBase 的编程语言,它本身不支持直接调用 C 语言的函数签名(如 CreateServiceCreateProcess 那样的低级 Windows API)。但是,VFP 可以通过 DECLARE - DLL 语句调用 Windows API 函数,将 C 函数签名“翻译”成 VFP 可用的形式。这种方式需要明确指定 DLL 文件、函数名、参数类型和返回值类型。

由于 VFP 没有像 C 那样的强类型声明,我们需要:

  1. 使用 VFP 的 DECLARE 语句声明外部函数。
  2. 将 C 的参数类型映射到 VFP 支持的类型(如整数、字符串、指针等)。
  3. 调用时传递正确的参数。

以下是将你在上一个问题中提到的 NSSM 常用 Windows API 函数签名从 C 语言转化为 VFP 代码的详细说明和示例。我会以几个代表性函数为例,逐步展示转化过程。


1. 基本映射规则

在 VFP 中,C 语言的类型需要映射为 VFP 支持的类型:

  • LPCWSTR(宽字符字符串指针):VFP 用 @ 表示传址字符串,或直接用字符串变量。
  • DWORD(32 位无符号整数):VFP 用 INTEGER。
  • HANDLE(句柄):VFP 用 INTEGER(句柄本质是整数)。
  • BOOL(布尔值):VFP 用 INTEGER(0 表示 FALSE,非 0 表示 TRUE)。
  • LPVOID(通用指针):VFP 用 INTEGER@ 传址。
  • 结构体(如 SERVICE_STATUS):需要用 VFP 的内存操作函数(如 SYS(2600))手动构造。

2.示例转化

以下是几个 NSSM 用到的典型 Windows API 函数的转化:

(1) OpenSCManager

  • C 函数签名:

c

SC_HANDLE OpenSCManager(
 LPCWSTR lpMachineName,
 LPCWSTR lpDatabaseName,
 DWORD dwDesiredAccess
);
  • VFP DECLARE 声明:

vfp

DECLARE INTEGER OpenSCManager IN advapi32;
 STRING @lpMachineName,;
 STRING @lpDatabaseName,;
 INTEGER dwDesiredAccess
  • 说明:

IN advapi32:指定函数来自 advapi32.dll

STRING @:表示传址字符串,VFP 会自动处理宽字符。

INTEGER:对应 DWORD 和返回值(SC_HANDLE 是句柄,用整数表示)。

  • 调用示例:

vfp

LOCAL hSCManager
hSCManager = OpenSCManager(NULL, NULL, 0xF003F) && SC_MANAGER_ALL_ACCESS = 0xF003F
IF hSCManager = 0
 MESSAGEBOX("无法打开服务控制管理器!")
ELSE
 MESSAGEBOX("成功打开 SCM,句柄: " + TRANSFORM(hSCManager))
ENDIF

(2) CreateService

C 函数签名:

c

SC_HANDLE CreateService(
 SC_HANDLE hSCManager,
 LPCWSTR lpServiceName,
 LPCWSTR lpDisplayName,
 DWORD dwDesiredAccess,
 DWORD dwServiceType,
 DWORD dwStartType,
 DWORD dwErrorControl,
 LPCWSTR lpBinaryPathName,
 LPCWSTR lpLoadOrderGroup,
 LPDWORD lpdwTagId,
 LPCWSTR lpDependencies,
 LPCWSTR lpServiceStartName,
 LPCWSTR lpPassword
);

VFP DECLARE 声明:

vfp

DECLARE INTEGER CreateService IN advapi32;
 INTEGER hSCManager,;
 STRING @lpServiceName,;
 STRING @lpDisplayName,;
 INTEGER dwDesiredAccess,;
 INTEGER dwServiceType,;
 INTEGER dwStartType,;
 INTEGER dwErrorControl,;
 STRING @lpBinaryPathName,;
 STRING @lpLoadOrderGroup,;
 INTEGER @lpdwTagId,;
 STRING @lpDependencies,;
 STRING @lpServiceStartName,;
 STRING @lpPassword
  • 说明:

INTEGER @lpdwTagId:表示传址整数,用于接收输出值。

参数较多,需注意顺序和类型匹配。

  • 调用示例:

vfp

LOCAL hSCManager, hService, nTagId
hSCManager = OpenSCManager(NULL, NULL, 0xF003F)
IF hSCManager != 0
 nTagId = 0
 hService = CreateService(hSCManager,;
 "MyService",; && 服务名
 "我的服务",; && 显示名称
 0xF01FF,; && SERVICE_ALL_ACCESS
 0x10,; && SERVICE_WIN32_OWN_PROCESS
 2,; && SERVICE_AUTO_START
 1,; && SERVICE_ERROR_NORMAL
 "C:\path\to\nssm.exe",; && 可执行路径
 NULL,; && 无加载顺序组
 @nTagId,; && 标签 ID
 NULL,; && 无依赖
 NULL,; && 默认账户
 NULL) && 无密码
 IF hService = 0
 MESSAGEBOX("服务创建失败,错误码: " + TRANSFORM(GetLastError()))
 ELSE
 MESSAGEBOX("服务创建成功,句柄: " + TRANSFORM(hService))
 ENDIF
ENDIF

(3) CreateProcess

C 函数签名:

c

BOOL CreateProcess(
 LPCWSTR lpApplicationName,
 LPWSTR lpCommandLine,
 LPSECURITY_ATTRIBUTES lpProcessAttributes,
 LPSECURITY_ATTRIBUTES lpThreadAttributes,
 BOOL bInheritHandles,
 DWORD dwCreationFlags,
 LPVOID lpEnvironment,
 LPCWSTR lpCurrentDirectory,
 LPSTARTUPINFO lpStartupInfo,
 LPPROCESS_INFORMATION lpProcessInformation
);

VFP DECLARE 声明:

vfp

DECLARE INTEGER CreateProcess IN kernel32;
 STRING @lpApplicationName,;
 STRING @lpCommandLine,;
 INTEGER lpProcessAttributes,;
 INTEGER lpThreadAttributes,;
 INTEGER bInheritHandles,;
 INTEGER dwCreationFlags,;
 INTEGER lpEnvironment,;
 STRING @lpCurrentDirectory,;
 STRING @lpStartupInfo,;
 STRING @lpProcessInformation
  • 说明:

LPSTARTUPINFO LPPROCESS_INFORMATION 是结构体,在 VFP 中需要用二进制字符串表示,并通过内存操作构造。

这里简化为 STRING @,实际使用时需预分配内存。

  • 调用示例:

vfp

LOCAL cStartupInfo, cProcessInfo, nResult
* 构造 STARTUPINFO 结构体(68 字节)
  cStartupInfo = REPLICATE(CHR(0), 68)
  STORE 68 TO cStartupInfo && cb 字段设为结构体大小
* 构造 PROCESS_INFORMATION 结构体(16 字节)
  cProcessInfo = REPLICATE(CHR(0), 16)

nResult = CreateProcess(;
 NULL,; && 应用程序名
 "C:\path\to\myapp.exe -arg",; && 命令行
 0,; && 无进程属性
 0,; && 无线程属性
 0,; && 不继承句柄
 0,; && 默认创建标志
 0,; && 无环境变量
 "C:\path\to",; && 工作目录
 @cStartupInfo,; && STARTUPINFO
 @cProcessInfo) && PROCESS_INFORMATION
IF nResult = 0
 MESSAGEBOX("进程创建失败,错误码: " + TRANSFORM(GetLastError()))
ELSE
 MESSAGEBOX("进程创建成功")
ENDIF

(4) SetServiceStatus

C 函数签名:

c

BOOL SetServiceStatus(
 SERVICE_STATUS_HANDLE hServiceStatus,
 LPSERVICE_STATUS lpServiceStatus
);

VFP DECLARE 声明:

vfp

DECLARE INTEGER SetServiceStatus IN advapi32;
 INTEGER hServiceStatus,;
 STRING @lpServiceStatus
  • 说明:

SERVICE_STATUS 是结构体(28 字节),需要用 VFP 手动构造。

  • 调用示例:

vfp

LOCAL cServiceStatus, hServiceStatus

*构造 SERVICE_STATUS 结构体
  cServiceStatus = REPLICATE(CHR(0), 28)
* 填充字段(示例:SERVICE_RUNNING)
  SYS(2600, @cServiceStatus, 0, 4) && dwServiceType = SERVICE_WIN32_OWN_PROCESS
  SYS(2600, @cServiceStatus, 4, 4) && dwCurrentState = SERVICE_RUNNING

hServiceStatus = ... && 假设已从 RegisterServiceCtrlHandler 获取
nResult = SetServiceStatus(hServiceStatus, @cServiceStatus)
IF nResult = 0
 MESSAGEBOX("状态设置失败")
ENDIF

3.注意事项

  1. DLL 位置:

VFP 需要知道 API 函数所在的 DLL(如 advapi32.dllkernel32.dll),这些是 Windows 系统自带的。

  1. 结构体处理:

C 中的结构体(如 SERVICE_STATUSSTARTUPINFO)在 VFP 中需要用 REPLICATE() 创建缓冲区,并用 SYS(2600)(内存写入)或类似函数填充。

示例:

vfp

SYS(2600, @buffer, offset, value)  && 将值写入缓冲区指定偏移
  1. 错误处理:

使用 GetLastError 获取错误码:

vfp

DECLARE INTEGER GetLastError IN kernel32
  1. 宽字符支持:

VFP 默认支持宽字符(Unicode),直接用字符串即可。

指针传递:

@ 表示传址参数,例如 @lpServiceName

4. 完整 NSSM 风格示例

假设你想用 VFP 模拟 NSSM 安装一个服务:

vfp

* 声明必要的 API
  DECLARE INTEGER OpenSCManager IN advapi32 STRING @, STRING @, INTEGER
  DECLARE INTEGER CreateService IN advapi32 INTEGER, STRING @, STRING @, INTEGER, INTEGER, INTEGER, INTEGER, STRING @, STRING @, INTEGER @, STRING @, STRING @, STRING @
  DECLARE INTEGER CloseServiceHandle IN advapi32 INTEGER
  DECLARE INTEGER GetLastError IN kernel32

* 安装服务
  LOCAL hSCManager, hService, nTagId
  hSCManager = OpenSCManager(NULL, NULL, 0xF003F)
  IF hSCManager != 0
  nTagId = 0
  hService = CreateService(hSCManager,;
    "MyService",;
    "我的服务",;
    0xF01FF,;
    0x10,;
    2,;
    1,;
    "C:\path\to\nssm.exe",;
    NULL,;
    @nTagId,;
    NULL,;
    NULL,;
    NULL)
  IF hService = 0
    MESSAGEBOX("错误: " + TRANSFORM(GetLastError()))
  ELSE
    MESSAGEBOX("服务创建成功")
    =CloseServiceHandle(hService)
  ENDIF
  =CloseServiceHandle(hSCManager)
  ELSE
  MESSAGEBOX("无法打开 SCM")
  ENDIF

5. 总结

将 C 语言的 Windows API 函数签名转化为 VFP 代码,需要:

  1. DECLARE 声明函数,指定 DLL 和参数类型。
  2. 将 C 类型映射到 VFP 类型(如 DWORD -> INTEGER)。
  3. 处理结构体时,使用 VFP 的内存操作。
  4. 通过 @ 传递指针参数。

NSSM 用到的 API(如 CreateServiceCreateProcess)在 VFP 中都可以通过这种方式调用,但由于 VFP 更适合高级业务逻辑,实际实现 NSSM 的完整功能(如服务监控)会更复杂,可能需要结合 VFP 的定时器或外部组件。

本文作者: yangmeng

原文链接: 把nssm的windows api的c语言函数签名转化为vfp代码

版权声明: 本站所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

免责声明: 文中如涉及第三方资源,均来自互联网,仅供学习研究,禁止商业使用,如有侵权,联系我们24小时内删除!

nssm 把nssm的windows api的c语言函数签名转化为vfp代码 vfp代码