【问题标题】:What is the correct type cast to avoid a compiler warning using SERVICE_TABLE_ENTRY from winsvc.h使用 winsvc.h 中的 SERVICE_TABLE_ENTRY 避免编译器警告的正确类型转换是什么
【发布时间】:2012-01-10 18:03:27
【问题描述】:

尝试使用示例设置 SERVICE_TABLE_ENTRY 时 Creating Windows service without Visual Studio 并在 Fedora 14 上使用 mingw32 交叉编译器进行编译,我收到编译器警告。

我能做的最短样本是

#include <stdio.h>
#include <windows.h>
#include <winsvc.h>

#define MY_SVC_NAME "My Service"

int cont_running = 1;

DWORD WINAPI ServiceHandlerProc(DWORD ControlCode, DWORD a, void *b, void *c)
{
  switch (ControlCode)
    {
    case SERVICE_CONTROL_STOP : ;
      cont_running = 0;
    }

  return 0;

}

void WINAPI ServiceMain(int argc, char *argv[], char *envp[])
{
  int hServiceStatus;
  hServiceStatus = RegisterServiceCtrlHandlerEx(MY_SVC_NAME, ServiceHandlerProc, 0);
}

int main(int argc, char *argv[], char *envp[])
{
  SERVICE_TABLE_ENTRY ServiceStartTable[] =
  {
    { MY_SVC_NAME, ServiceMain },
    { 0, 0 }
  };

}

但编译器抱怨 MY_SVC_NAME 类型错误。

$ /usr/bin/i686-pc-mingw32-gcc -o /tmp/test ~/c/sample.c 
sample.c: In function 'main':
sample.c:31:9: warning: initialization from incompatible pointer type

我尝试分配一个变量并使用类型 LPSTR LPWSTR char * 和 char [] 并且还尝试在花括号内转换类型,但它不起作用。

查看 /usr/i686-pc-mingw32/sys-root/mingw/include/winsvc.h 我看到它的定义为

typedef struct _SERVICE_TABLE_ENTRYA {
    LPSTR lpServiceName;
    LPSERVICE_MAIN_FUNCTIONA lpServiceProc;
} SERVICE_TABLE_ENTRYA,*LPSERVICE_TABLE_ENTRYA;
typedef struct _SERVICE_TABLE_ENTRYW {
    LPWSTR lpServiceName;
    LPSERVICE_MAIN_FUNCTIONW lpServiceProc;
} SERVICE_TABLE_ENTRYW,*LPSERVICE_TABLE_ENTRYW;
...
typedef SERVICE_TABLE_ENTRYW SERVICE_TABLE_ENTRY,*LPSERVICE_TABLE_ENTRY;
...
typedef SERVICE_TABLE_ENTRYA SERVICE_TABLE_ENTRY,*LPSERVICE_TABLE_ENTRY;

所以肯定会使用

LPSTR my_svc=MY_SVC_NAME;
  SERVICE_TABLE_ENTRY ServiceStartTable[] =
  {
    { my_svc, ServiceMain },
    { 0, 0 }
  };

应该有用???

抱歉,另一个搜索显示此示例代码位于 Windows Service C

我将代码更改为

  SERVICE_TABLE_ENTRY ServiceStartTable[2];
  ServiceStartTable[0].lpServiceName = MY_SVC_NAME;
  ServiceStartTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
  ServiceStartTable[1].lpServiceName = NULL;
  ServiceStartTable[1].lpServiceProc = NULL;

现在它编译时没有警告。

【问题讨论】:

  • LPSERVICE_MAIN_FUNCTION 是如何定义的?我有一种强烈的预感,它需要返回int,而不是void。尝试更改您的 ServiceMain 函数以返回 int 并删除演员表。
  • @KeithThompson 谢谢,但 typedef 确实指定了 void。 ` typedef void (WINAPI LPSERVICE_MAIN_FUNCTIONA)(DWORD,LPSTR); typedef void (WINAPI LPSERVICE_MAIN_FUNCTIONW)(DWORD,LPWSTR); typedef LPSERVICE_MAIN_FUNCTIONA LPSERVICE_MAIN_FUNCTION; typedef LPSERVICE_MAIN_FUNCTIONW LPSERVICE_MAIN_FUNCTION; `
  • 您错过了该评论中的结束反引号;你还有时间编辑它。
  • 是的 - 我编辑了几次,甚至删除了 \n,但我猜它太长或其他字符太多,反引号无法正常工作。
  • 您只需要删除开始反引号之后和结束反引号之前的空格(在 cmets 中会忽略换行符):typedef void (WINAPI LPSERVICE_MAIN_FUNCTIONA)(DWORD,LPSTR); typedef void (WINAPI LPSERVICE_MAIN_FUNCTIONW)(DWORD,LPWSTR); typedef LPSERVICE_MAIN_FUNCTIONA LPSERVICE_MAIN_FUNCTION; typedef LPSERVICE_MAIN_FUNCTIONW LPSERVICE_MAIN_FUNCTION;

标签: c windows-services


【解决方案1】:

此信息来自 cmets:

typedef void (WINAPI LPSERVICE_MAIN_FUNCTIONA)(DWORD,LPSTR);
typedef void (WINAPI LPSERVICE_MAIN_FUNCTIONW)(DWORD,LPWSTR);
typedef LPSERVICE_MAIN_FUNCTIONA LPSERVICE_MAIN_FUNCTION;
typedef LPSERVICE_MAIN_FUNCTIONW LPSERVICE_MAIN_FUNCTION;

(大概后两个 typedef 中只有一个会处于活动状态。)

LPSERVICE_MAIN_FUNCTION 是返回 void 并接受两个类型为 DWORDLPSTRLPWSTR 的函数的类型定义。您的ServiceMain 函数返回void 并接受intchar**char** 类型的三个 参数。

更改ServiceMain函数的定义,使其与LPSERVICE_MAIN_FUNCTION兼容。

ServiceMain 转换为LPSERVICE_MAIN_FUNCTION 将使编译器警告静音,但它并没有解决问题。这将导致您的函数被调用,就好像它被正确声明,结果不可预测(未定义的行为)。所有的演员表都应该被怀疑地看待;如果您的编译器警告您类型不匹配,最好的解决方案通常是更改您的声明以使类型匹配,而不是强制编译器假装它们没问题。

(根据配置,是否有 LPSTRLPWSTR 的 typedef?)

【讨论】:

    猜你喜欢
    • 2019-10-04
    • 2011-05-28
    • 2021-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多