如何将自己写的一个MFC程序添加成开机自动启动的系统服务

时间:2022-11-24 16:47:44
rt
需要将自己写的一个MFC程序添加成开机自动启动的系统服务

按照网上写的
加了以下注册表
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\程序名\DisplayName
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\程序名\Description
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\程序名\ImagePath
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\程序名\ObjectName
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\程序名\ErrorControl
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\程序名\Start
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\程序名\Type

的确成功地添加到了控制面板的系统服务中
但是每次启动服务的时候,总是告诉我超时

哪里弄错了?

41 个解决方案

#1


超时 ?什么意思?可以详细点么
RunServicesOnce注册键用来启动服务程序,启动时间在用户登录之前,而且先于其他通过注册键启动的程序。RunServicesOnce注册键的位置是:HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunServicesOnce,和HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunServicesOnce

#2


RunServices注册键指定的程序紧接RunServicesOnce指定的程序之后运行,但两者都在用户登录之前。RunServices的位置是:HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunServices,和HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunServices。

#3


一个服务程序还要 注册一个控制函数,和事年接收函数

onst char csServerNameInner[] = "xxxxxxxxxxx";

SERVICE_TABLE_ENTRY dispatchTable[] =
{
    { csServerNameInner, (LPSERVICE_MAIN_FUNCTION)ServiceMain},
    { NULL, NULL }
};

void winmain()
{
Init();
if (!::StartServiceCtrlDispatcher(dispatchTable))
{
return;
}
}



//初始化状态
void Init()
{
    hServiceStatus = NULL;
    status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
    status.dwCurrentState = SERVICE_STOPPED;
    status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
    status.dwWin32ExitCode = 0;
    status.dwServiceSpecificExitCode = 0;
    status.dwCheckPoint = 0;
    status.dwWaitHint = 0;
}

//服务主函数
void WINAPI ServiceMain()
{
    status.dwCurrentState = SERVICE_START_PENDING;
status.dwControlsAccepted = SERVICE_ACCEPT_STOP;

//注册服务控制
    hServiceStatus = ::RegisterServiceCtrlHandler(csServerNameInner, ServiceStrl);
    if (hServiceStatus == NULL)
    {
        return;
    }

    ::SetServiceStatus(hServiceStatus, &status);

    status.dwWin32ExitCode = S_OK;
    status.dwCheckPoint = 0;
    status.dwWaitHint = 0;
status.dwCurrentState = SERVICE_RUNNING;
::SetServiceStatus(hServiceStatus, &status);


if(g_hEvent != NULL)
{
//启动你的线程,并等待结束
}

    status.dwCurrentState = SERVICE_STOPPED;
    ::SetServiceStatus(hServiceStatus, &status);
}

//服务控制函数
void WINAPI ServiceStrl(DWORD dwOpcode)
{
    switch (dwOpcode)
    {
case SERVICE_CONTROL_STOP:
status.dwCurrentState = SERVICE_STOP_PENDING;
::SetServiceStatus(hServiceStatus, &status);
break;
case SERVICE_CONTROL_PAUSE:
break;
case SERVICE_CONTROL_CONTINUE:
break;
case SERVICE_CONTROL_INTERROGATE:
break;
case SERVICE_CONTROL_SHUTDOWN:
break;
default:
break;
    }
}




上面是大概的代码

#4


SERVICE_STATUS_HANDLE hServiceStatus;
SERVICE_STATUS status;

#5


关注。。。up

#6


先回1楼的

详细错误是
error 1053
没有在指定时间内应答

to:fairyprince
你说的这些代码,添加在哪里?
我写的是MFC的一个程序。。。。。。

#7


void winmain()
代表你的主函数,例:如果是对话框程序就将其中代码放到 InitInstance(),其它函数只要能放到能找到的地方就能

其实这段代码就是启动一个服务,你可以将它们放到你相放的任何地方
       Init();
        if (!::StartServiceCtrlDispatcher(dispatchTable))
        {
            return;
        }


最后建议最好用 win32 程序不要用 MFC 

#8


感谢fairyprince
我先去试试

不过基本框架肯定要用MFC的说
框架问题,没办法更改。。。。。。

#9


不好意思,再问一下fairyprince 
if(g_hEvent != NULL)
中的g_hEvent,什么类型?在哪里声明?

#10


那个去掉就行
,没用,是多写的

#11


3楼正解

#12


3楼正解,楼主应该在网上搜下怎样把可执行文件写成服务的文章。

#13


服务程序要做一些服务方面的处理,不是随便一个程序安装成服务就可以的。在初始化时需要调用StartServiceCtrlDispatcher函数,在ServiceMain中调用RegisterServiceCtrlHandler,并调用SetServiceStatus将服务状态设置为SERVICE_RUNNING。MFC修改成服务有点麻烦,建议你用一个Win32程序做服务,在该程序中加载MFC程序。

#14


按照楼上各位
新建了一个win32程序

但是运行到
StartServiceCtrlDispatcher(dispatchTable)
一直报错

用getlasterror得到error code 1063

继续发问。。。。。。

#15


代码怎么写的?

#16


基本就是和3楼一样

#17


是否正确的报告了service的状态
SetServiceStatus

#18


我的代码(基本就是3楼的copoy)

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
InitService();
if (!::StartServiceCtrlDispatcher(dispatchTable))
{
DWORD dwErrorCode = GetLastError();
return 0;
}
return 0;
}

void InitService()
{
    hServiceStatus = NULL;
    status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
    status.dwCurrentState = SERVICE_STOPPED;
    status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
    status.dwWin32ExitCode = 0;
    status.dwServiceSpecificExitCode = 0;
    status.dwCheckPoint = 0;
    status.dwWaitHint = 0;
}

void WINAPI ServiceMain()
{
    status.dwCurrentState = SERVICE_START_PENDING;
    status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
    hServiceStatus = ::RegisterServiceCtrlHandler(csServerNameInner, ServiceStrl);
    if (hServiceStatus == NULL)
    {
        return;
    }

    ::SetServiceStatus(hServiceStatus, &status);

    status.dwWin32ExitCode = S_OK;
    status.dwCheckPoint = 0;
    status.dwWaitHint = 0;
    status.dwCurrentState = SERVICE_RUNNING;
    ::SetServiceStatus(hServiceStatus, &status);
    
    ::WinExec("C:\\Program Files\\aaaa.exe",SW_SHOWNORMAL);
    
    status.dwCurrentState = SERVICE_STOPPED;
    ::SetServiceStatus(hServiceStatus, &status);
}

void WINAPI ServiceStrl(DWORD dwOpcode)
{
    switch (dwOpcode)
    {
        case SERVICE_CONTROL_STOP:
            status.dwCurrentState = SERVICE_STOP_PENDING;
            ::SetServiceStatus(hServiceStatus, &status);
            break;
        case SERVICE_CONTROL_PAUSE:
            break;
        case SERVICE_CONTROL_CONTINUE:
            break;
        case SERVICE_CONTROL_INTERROGATE:
            break;
        case SERVICE_CONTROL_SHUTDOWN:
            break;
        default:
            break;
    }
}

#19


dispatchTable怎么初始化的?服务名称与安装的服务一致吗?

#20


 ::WinExec("C:\\Program Files\\aaaa.exe",SW_SHOWNORMAL);  
//这里要自已做一个等待,待你目标程序完成,否则你的服务在启动上面程序后会立即结束(即出了 ServiceMain(),你的服务也就结束了)

dispatchTable 表中的名字和你注册表中的"程序名"要一致

#21


你是直接用VC调试运行的吧?服务程序不能直接运行,要通过服务管理器加载才行。

#22


TO:楼上的各位大侠

dispatchTable的初始化也和fairyprince写的一样

SERVICE_TABLE_ENTRY dispatchTable[] =
{
    { csServerNameInner, (LPSERVICE_MAIN_FUNCTION)ServiceMain},
    { NULL, NULL }
};


无论是用vc调试还是用通过控制面板里的service启动
都会启动失败

dispatchTable 表中的名字和注册表中的"程序名"也一样

等下确认一下,加一个等待是否能正常运行

还是多谢各位

#23


你的serviceMain中应该有一个无限循环... while(1)。只有到你退出的条件满足了
然后你才应该跳出while循环,服务也结束了

#24


你的serviceMain中应该有一个无限循环... while(1)。只有到你退出的条件满足了
然后你才应该跳出while循环,服务也结束了

#25


在::WinExec("C:\\Program Files\\aaaa.exe",SW_SHOWNORMAL)
之后加了一个sleep

果然可以成功启动服务了

不过又有了新的问题
通过服务所启动的那个mfc程序,也就是aaaa.exe
虽然在TaskManager里有
但没有显示界面......

#26


什么操作系统?注册表里添加与用户交互的键值了吗?

#27


因为不在一个"桌面上"   
你要切换到用户桌面

 DWORD dwThreadId; 
    HWINSTA hwinstaSave; 
    HDESK hdeskSave; 
    HWINSTA hwinstaUser; 
    HDESK hdeskUser;  
 
    // Ensure connection to service window station and desktop, and 
    // save their handles. 
    GetDesktopWindow();
    hwinstaSave = GetProcessWindowStation(); 
    dwThreadId = GetCurrentThreadId(); 
    hdeskSave = GetThreadDesktop(dwThreadId); 
 
    // Impersonate the client and connect to the User's 
    // window station and desktop. 

    hwinstaUser = ::OpenWindowStation("WinSta0", FALSE, MAXIMUM_ALLOWED); 
    if (hwinstaUser == NULL) 
    { 
        return 0; 
    }

    SetProcessWindowStation(hwinstaUser); 
    hdeskUser = ::OpenDesktop("Default", 0, FALSE, MAXIMUM_ALLOWED); 
    if (hdeskUser == NULL) 
    { 
        SetProcessWindowStation(hwinstaSave); 
        CloseWindowStation(hwinstaUser); 
        return 0; 
    } 
    SetThreadDesktop(hdeskUser); 

//你的代码

    //Restore window station and desktop. 
    SetThreadDesktop(hdeskSave); 
    SetProcessWindowStation(hwinstaSave); 
    CloseDesktop(hdeskUser); 
    CloseWindowStation(hwinstaUser);

#28


好象是type要“或”0x100。

#29


TO:fairyprince

也可能是我添加错误,
代码追加了还是没有用

确认一下,您的意思是

在winapi32的WinExc(。。。。)
前追加
    DWORD dwThreadId; 
    HWINSTA hwinstaSave; 
    HDESK hdeskSave; 
    HWINSTA hwinstaUser; 
    HDESK hdeskUser;  
 
    // Ensure connection to service window station and desktop, and 
    // save their handles. 
    GetDesktopWindow();
    hwinstaSave = GetProcessWindowStation(); 
    dwThreadId = GetCurrentThreadId(); 
    hdeskSave = GetThreadDesktop(dwThreadId); 
 
    // Impersonate the client and connect to the User's 
    // window station and desktop. 

    hwinstaUser = ::OpenWindowStation("WinSta0", FALSE, MAXIMUM_ALLOWED); 
    if (hwinstaUser == NULL) 
    { 
        return 0; 
    }

    SetProcessWindowStation(hwinstaUser); 
    hdeskUser = ::OpenDesktop("Default", 0, FALSE, MAXIMUM_ALLOWED); 
    if (hdeskUser == NULL) 
    { 
        SetProcessWindowStation(hwinstaSave); 
        CloseWindowStation(hwinstaUser); 
        return 0; 
    } 
    SetThreadDesktop(hdeskUser); 


然后在MFC程序里追加
    DWORD dwThreadId; 
    HWINSTA hwinstaSave; 
    HDESK hdeskSave; 
    HWINSTA hwinstaUser; 
    HDESK hdeskUser;  
 
    GetDesktopWindow();
    hwinstaSave = GetProcessWindowStation(); 
    dwThreadId = GetCurrentThreadId(); 
    hdeskSave = GetThreadDesktop(dwThreadId); 
 
    hwinstaUser = ::OpenWindowStation("WinSta0", FALSE, MAXIMUM_ALLOWED); 
    if (hwinstaUser == NULL) 
    { 
        return 0; 
    }

    SetProcessWindowStation(hwinstaUser); 
    hdeskUser = ::OpenDesktop("Default", 0, FALSE, MAXIMUM_ALLOWED); 
    if (hdeskUser == NULL) 
    { 
        SetProcessWindowStation(hwinstaSave); 
        CloseWindowStation(hwinstaUser); 
        return 0; 
    } 
    SetThreadDesktop(hdeskUser); 
    //Restore window station and desktop. 
    SetThreadDesktop(hdeskSave); 
    SetProcessWindowStation(hwinstaSave); 
    CloseDesktop(hdeskUser); 
    CloseWindowStation(hwinstaUser);


#估计是我理解错了,望指正

TO:cnzdgs
你说的是哪个type?
显示mode么?
貌似我或上了0x100也还是没有用处。。。。。

#30


先说说是什么操作系统。

#31


Windows XP

#32


Windows XP

#33


学习

#34


mfc 不用添代码
只在服务程序里加就行
以下代码应该在一个子线程中,独立于你的服务主线程

 DWORD dwThreadId; 
    HWINSTA hwinstaSave; 
    HDESK hdeskSave; 
    HWINSTA hwinstaUser; 
    HDESK hdeskUser;  
 
    // Ensure connection to service window station and desktop, and 
    // save their handles. 
    GetDesktopWindow();
    hwinstaSave = GetProcessWindowStation(); 
    dwThreadId = GetCurrentThreadId(); 
    hdeskSave = GetThreadDesktop(dwThreadId); 
 
    // Impersonate the client and connect to the User's 
    // window station and desktop. 

    hwinstaUser = ::OpenWindowStation("WinSta0", FALSE, MAXIMUM_ALLOWED); 
    if (hwinstaUser == NULL) 
    { 
        return 0; 
    }

    SetProcessWindowStation(hwinstaUser); 
    hdeskUser = ::OpenDesktop("Default", 0, FALSE, MAXIMUM_ALLOWED); 
    if (hdeskUser == NULL) 
    { 
        SetProcessWindowStation(hwinstaSave); 
        CloseWindowStation(hwinstaUser); 
        return 0; 
    } 
    SetThreadDesktop(hdeskUser); 
    
//你的代码 WinExc(。。。。) 
    
    //Restore window station and desktop. 
    SetThreadDesktop(hdeskSave); 
    SetProcessWindowStation(hwinstaSave); 
    CloseDesktop(hdeskUser); 
    CloseWindowStation(hwinstaUser);

#35


XP系统不必设置桌面,这样就可以:
void WINAPI ServiceMain(DWORD dwArgc, LPTSTR* lpszArgv)
{
WinExec("C:\\Program Files\\aaaa.exe", SW_SHOWNORMAL);
}

SERVICE_TABLE_ENTRY ServiceTableEntry[] = {
{"服务名称", ServiceMain},
{NULL, NULL}
};

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
StartServiceCtrlDispatcher(ServiceTableEntry);
return 0;
}

服务type加上0x100标志。

#36


你要写成 ATL Server exe 程序

#37


TO:fairyprince
按照您的方法
将代码修改如下,但是貌似还是MFC窗口还是没有显示出来

static UINT __stdcall ThreadFunc(LPVOID pParam)
{
    DWORD dwThreadId; 
    HWINSTA hwinstaSave; 
    HDESK hdeskSave; 
    HWINSTA hwinstaUser; 
    HDESK hdeskUser;  
 
    // Ensure connection to service window station and desktop, and 
    // save their handles. 
    GetDesktopWindow();
    hwinstaSave = GetProcessWindowStation(); 
    dwThreadId = GetCurrentThreadId(); 
    hdeskSave = GetThreadDesktop(dwThreadId); 
 
    // Impersonate the client and connect to the User's 
    // window station and desktop. 

    hwinstaUser = ::OpenWindowStation("WinSta0", FALSE, MAXIMUM_ALLOWED); 
    if (hwinstaUser == NULL) 
    { 
        return 0; 
    }

    SetProcessWindowStation(hwinstaUser); 
    hdeskUser = ::OpenDesktop("Default", 0, FALSE, MAXIMUM_ALLOWED); 
    if (hdeskUser == NULL) 
    { 
        SetProcessWindowStation(hwinstaSave); 
        CloseWindowStation(hwinstaUser); 
        return 0; 
    } 
    SetThreadDesktop(hdeskUser); 

    ::WinExec("C:\\Program Files\\aaaa.exe",SW_SHOWNORMAL);
    //Restore window station and desktop. 
    SetThreadDesktop(hdeskSave); 
    SetProcessWindowStation(hwinstaSave); 
    CloseDesktop(hdeskUser); 
    CloseWindowStation(hwinstaUser);
    return TRUE;
}

void WINAPI ServiceMain()
{
    status.dwCurrentState = SERVICE_START_PENDING;
    status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
    hServiceStatus = ::RegisterServiceCtrlHandler(csServerNameInner, ServiceStrl);
    if (hServiceStatus == NULL)
    {
        return;
    }
    ::SetServiceStatus(hServiceStatus, &status);
    status.dwWin32ExitCode = S_OK;
    status.dwCheckPoint = 0;
    status.dwWaitHint = 0;
    status.dwCurrentState = SERVICE_RUNNING;
    ::SetServiceStatus(hServiceStatus, &status);
    int nLpvoid = 1;
    DWORD dwThreadID;
    
    CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadFunc,(LPVOID)&nLpvoid,0,&dwThreadID);
    
    status.dwCurrentState = SERVICE_STOPPED;
    ::SetServiceStatus(hServiceStatus, &status);   
}


TO:cnzdgs
您是说在注册表中的type再加上0x100?
好像也没用的说。。。。

#38


学习

#39


继续自己顶

#40


呵呵

#41


Createservice的Service_own_process后面还要或一个允许交互的参数

#1


超时 ?什么意思?可以详细点么
RunServicesOnce注册键用来启动服务程序,启动时间在用户登录之前,而且先于其他通过注册键启动的程序。RunServicesOnce注册键的位置是:HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunServicesOnce,和HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunServicesOnce

#2


RunServices注册键指定的程序紧接RunServicesOnce指定的程序之后运行,但两者都在用户登录之前。RunServices的位置是:HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunServices,和HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunServices。

#3


一个服务程序还要 注册一个控制函数,和事年接收函数

onst char csServerNameInner[] = "xxxxxxxxxxx";

SERVICE_TABLE_ENTRY dispatchTable[] =
{
    { csServerNameInner, (LPSERVICE_MAIN_FUNCTION)ServiceMain},
    { NULL, NULL }
};

void winmain()
{
Init();
if (!::StartServiceCtrlDispatcher(dispatchTable))
{
return;
}
}



//初始化状态
void Init()
{
    hServiceStatus = NULL;
    status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
    status.dwCurrentState = SERVICE_STOPPED;
    status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
    status.dwWin32ExitCode = 0;
    status.dwServiceSpecificExitCode = 0;
    status.dwCheckPoint = 0;
    status.dwWaitHint = 0;
}

//服务主函数
void WINAPI ServiceMain()
{
    status.dwCurrentState = SERVICE_START_PENDING;
status.dwControlsAccepted = SERVICE_ACCEPT_STOP;

//注册服务控制
    hServiceStatus = ::RegisterServiceCtrlHandler(csServerNameInner, ServiceStrl);
    if (hServiceStatus == NULL)
    {
        return;
    }

    ::SetServiceStatus(hServiceStatus, &status);

    status.dwWin32ExitCode = S_OK;
    status.dwCheckPoint = 0;
    status.dwWaitHint = 0;
status.dwCurrentState = SERVICE_RUNNING;
::SetServiceStatus(hServiceStatus, &status);


if(g_hEvent != NULL)
{
//启动你的线程,并等待结束
}

    status.dwCurrentState = SERVICE_STOPPED;
    ::SetServiceStatus(hServiceStatus, &status);
}

//服务控制函数
void WINAPI ServiceStrl(DWORD dwOpcode)
{
    switch (dwOpcode)
    {
case SERVICE_CONTROL_STOP:
status.dwCurrentState = SERVICE_STOP_PENDING;
::SetServiceStatus(hServiceStatus, &status);
break;
case SERVICE_CONTROL_PAUSE:
break;
case SERVICE_CONTROL_CONTINUE:
break;
case SERVICE_CONTROL_INTERROGATE:
break;
case SERVICE_CONTROL_SHUTDOWN:
break;
default:
break;
    }
}




上面是大概的代码

#4


SERVICE_STATUS_HANDLE hServiceStatus;
SERVICE_STATUS status;

#5


关注。。。up

#6


先回1楼的

详细错误是
error 1053
没有在指定时间内应答

to:fairyprince
你说的这些代码,添加在哪里?
我写的是MFC的一个程序。。。。。。

#7


void winmain()
代表你的主函数,例:如果是对话框程序就将其中代码放到 InitInstance(),其它函数只要能放到能找到的地方就能

其实这段代码就是启动一个服务,你可以将它们放到你相放的任何地方
       Init();
        if (!::StartServiceCtrlDispatcher(dispatchTable))
        {
            return;
        }


最后建议最好用 win32 程序不要用 MFC 

#8


感谢fairyprince
我先去试试

不过基本框架肯定要用MFC的说
框架问题,没办法更改。。。。。。

#9


不好意思,再问一下fairyprince 
if(g_hEvent != NULL)
中的g_hEvent,什么类型?在哪里声明?

#10


那个去掉就行
,没用,是多写的

#11


3楼正解

#12


3楼正解,楼主应该在网上搜下怎样把可执行文件写成服务的文章。

#13


服务程序要做一些服务方面的处理,不是随便一个程序安装成服务就可以的。在初始化时需要调用StartServiceCtrlDispatcher函数,在ServiceMain中调用RegisterServiceCtrlHandler,并调用SetServiceStatus将服务状态设置为SERVICE_RUNNING。MFC修改成服务有点麻烦,建议你用一个Win32程序做服务,在该程序中加载MFC程序。

#14


按照楼上各位
新建了一个win32程序

但是运行到
StartServiceCtrlDispatcher(dispatchTable)
一直报错

用getlasterror得到error code 1063

继续发问。。。。。。

#15


代码怎么写的?

#16


基本就是和3楼一样

#17


是否正确的报告了service的状态
SetServiceStatus

#18


我的代码(基本就是3楼的copoy)

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
InitService();
if (!::StartServiceCtrlDispatcher(dispatchTable))
{
DWORD dwErrorCode = GetLastError();
return 0;
}
return 0;
}

void InitService()
{
    hServiceStatus = NULL;
    status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
    status.dwCurrentState = SERVICE_STOPPED;
    status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
    status.dwWin32ExitCode = 0;
    status.dwServiceSpecificExitCode = 0;
    status.dwCheckPoint = 0;
    status.dwWaitHint = 0;
}

void WINAPI ServiceMain()
{
    status.dwCurrentState = SERVICE_START_PENDING;
    status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
    hServiceStatus = ::RegisterServiceCtrlHandler(csServerNameInner, ServiceStrl);
    if (hServiceStatus == NULL)
    {
        return;
    }

    ::SetServiceStatus(hServiceStatus, &status);

    status.dwWin32ExitCode = S_OK;
    status.dwCheckPoint = 0;
    status.dwWaitHint = 0;
    status.dwCurrentState = SERVICE_RUNNING;
    ::SetServiceStatus(hServiceStatus, &status);
    
    ::WinExec("C:\\Program Files\\aaaa.exe",SW_SHOWNORMAL);
    
    status.dwCurrentState = SERVICE_STOPPED;
    ::SetServiceStatus(hServiceStatus, &status);
}

void WINAPI ServiceStrl(DWORD dwOpcode)
{
    switch (dwOpcode)
    {
        case SERVICE_CONTROL_STOP:
            status.dwCurrentState = SERVICE_STOP_PENDING;
            ::SetServiceStatus(hServiceStatus, &status);
            break;
        case SERVICE_CONTROL_PAUSE:
            break;
        case SERVICE_CONTROL_CONTINUE:
            break;
        case SERVICE_CONTROL_INTERROGATE:
            break;
        case SERVICE_CONTROL_SHUTDOWN:
            break;
        default:
            break;
    }
}

#19


dispatchTable怎么初始化的?服务名称与安装的服务一致吗?

#20


 ::WinExec("C:\\Program Files\\aaaa.exe",SW_SHOWNORMAL);  
//这里要自已做一个等待,待你目标程序完成,否则你的服务在启动上面程序后会立即结束(即出了 ServiceMain(),你的服务也就结束了)

dispatchTable 表中的名字和你注册表中的"程序名"要一致

#21


你是直接用VC调试运行的吧?服务程序不能直接运行,要通过服务管理器加载才行。

#22


TO:楼上的各位大侠

dispatchTable的初始化也和fairyprince写的一样

SERVICE_TABLE_ENTRY dispatchTable[] =
{
    { csServerNameInner, (LPSERVICE_MAIN_FUNCTION)ServiceMain},
    { NULL, NULL }
};


无论是用vc调试还是用通过控制面板里的service启动
都会启动失败

dispatchTable 表中的名字和注册表中的"程序名"也一样

等下确认一下,加一个等待是否能正常运行

还是多谢各位

#23


你的serviceMain中应该有一个无限循环... while(1)。只有到你退出的条件满足了
然后你才应该跳出while循环,服务也结束了

#24


你的serviceMain中应该有一个无限循环... while(1)。只有到你退出的条件满足了
然后你才应该跳出while循环,服务也结束了

#25


在::WinExec("C:\\Program Files\\aaaa.exe",SW_SHOWNORMAL)
之后加了一个sleep

果然可以成功启动服务了

不过又有了新的问题
通过服务所启动的那个mfc程序,也就是aaaa.exe
虽然在TaskManager里有
但没有显示界面......

#26


什么操作系统?注册表里添加与用户交互的键值了吗?

#27


因为不在一个"桌面上"   
你要切换到用户桌面

 DWORD dwThreadId; 
    HWINSTA hwinstaSave; 
    HDESK hdeskSave; 
    HWINSTA hwinstaUser; 
    HDESK hdeskUser;  
 
    // Ensure connection to service window station and desktop, and 
    // save their handles. 
    GetDesktopWindow();
    hwinstaSave = GetProcessWindowStation(); 
    dwThreadId = GetCurrentThreadId(); 
    hdeskSave = GetThreadDesktop(dwThreadId); 
 
    // Impersonate the client and connect to the User's 
    // window station and desktop. 

    hwinstaUser = ::OpenWindowStation("WinSta0", FALSE, MAXIMUM_ALLOWED); 
    if (hwinstaUser == NULL) 
    { 
        return 0; 
    }

    SetProcessWindowStation(hwinstaUser); 
    hdeskUser = ::OpenDesktop("Default", 0, FALSE, MAXIMUM_ALLOWED); 
    if (hdeskUser == NULL) 
    { 
        SetProcessWindowStation(hwinstaSave); 
        CloseWindowStation(hwinstaUser); 
        return 0; 
    } 
    SetThreadDesktop(hdeskUser); 

//你的代码

    //Restore window station and desktop. 
    SetThreadDesktop(hdeskSave); 
    SetProcessWindowStation(hwinstaSave); 
    CloseDesktop(hdeskUser); 
    CloseWindowStation(hwinstaUser);

#28


好象是type要“或”0x100。

#29


TO:fairyprince

也可能是我添加错误,
代码追加了还是没有用

确认一下,您的意思是

在winapi32的WinExc(。。。。)
前追加
    DWORD dwThreadId; 
    HWINSTA hwinstaSave; 
    HDESK hdeskSave; 
    HWINSTA hwinstaUser; 
    HDESK hdeskUser;  
 
    // Ensure connection to service window station and desktop, and 
    // save their handles. 
    GetDesktopWindow();
    hwinstaSave = GetProcessWindowStation(); 
    dwThreadId = GetCurrentThreadId(); 
    hdeskSave = GetThreadDesktop(dwThreadId); 
 
    // Impersonate the client and connect to the User's 
    // window station and desktop. 

    hwinstaUser = ::OpenWindowStation("WinSta0", FALSE, MAXIMUM_ALLOWED); 
    if (hwinstaUser == NULL) 
    { 
        return 0; 
    }

    SetProcessWindowStation(hwinstaUser); 
    hdeskUser = ::OpenDesktop("Default", 0, FALSE, MAXIMUM_ALLOWED); 
    if (hdeskUser == NULL) 
    { 
        SetProcessWindowStation(hwinstaSave); 
        CloseWindowStation(hwinstaUser); 
        return 0; 
    } 
    SetThreadDesktop(hdeskUser); 


然后在MFC程序里追加
    DWORD dwThreadId; 
    HWINSTA hwinstaSave; 
    HDESK hdeskSave; 
    HWINSTA hwinstaUser; 
    HDESK hdeskUser;  
 
    GetDesktopWindow();
    hwinstaSave = GetProcessWindowStation(); 
    dwThreadId = GetCurrentThreadId(); 
    hdeskSave = GetThreadDesktop(dwThreadId); 
 
    hwinstaUser = ::OpenWindowStation("WinSta0", FALSE, MAXIMUM_ALLOWED); 
    if (hwinstaUser == NULL) 
    { 
        return 0; 
    }

    SetProcessWindowStation(hwinstaUser); 
    hdeskUser = ::OpenDesktop("Default", 0, FALSE, MAXIMUM_ALLOWED); 
    if (hdeskUser == NULL) 
    { 
        SetProcessWindowStation(hwinstaSave); 
        CloseWindowStation(hwinstaUser); 
        return 0; 
    } 
    SetThreadDesktop(hdeskUser); 
    //Restore window station and desktop. 
    SetThreadDesktop(hdeskSave); 
    SetProcessWindowStation(hwinstaSave); 
    CloseDesktop(hdeskUser); 
    CloseWindowStation(hwinstaUser);


#估计是我理解错了,望指正

TO:cnzdgs
你说的是哪个type?
显示mode么?
貌似我或上了0x100也还是没有用处。。。。。

#30


先说说是什么操作系统。

#31


Windows XP

#32


Windows XP

#33


学习

#34


mfc 不用添代码
只在服务程序里加就行
以下代码应该在一个子线程中,独立于你的服务主线程

 DWORD dwThreadId; 
    HWINSTA hwinstaSave; 
    HDESK hdeskSave; 
    HWINSTA hwinstaUser; 
    HDESK hdeskUser;  
 
    // Ensure connection to service window station and desktop, and 
    // save their handles. 
    GetDesktopWindow();
    hwinstaSave = GetProcessWindowStation(); 
    dwThreadId = GetCurrentThreadId(); 
    hdeskSave = GetThreadDesktop(dwThreadId); 
 
    // Impersonate the client and connect to the User's 
    // window station and desktop. 

    hwinstaUser = ::OpenWindowStation("WinSta0", FALSE, MAXIMUM_ALLOWED); 
    if (hwinstaUser == NULL) 
    { 
        return 0; 
    }

    SetProcessWindowStation(hwinstaUser); 
    hdeskUser = ::OpenDesktop("Default", 0, FALSE, MAXIMUM_ALLOWED); 
    if (hdeskUser == NULL) 
    { 
        SetProcessWindowStation(hwinstaSave); 
        CloseWindowStation(hwinstaUser); 
        return 0; 
    } 
    SetThreadDesktop(hdeskUser); 
    
//你的代码 WinExc(。。。。) 
    
    //Restore window station and desktop. 
    SetThreadDesktop(hdeskSave); 
    SetProcessWindowStation(hwinstaSave); 
    CloseDesktop(hdeskUser); 
    CloseWindowStation(hwinstaUser);

#35


XP系统不必设置桌面,这样就可以:
void WINAPI ServiceMain(DWORD dwArgc, LPTSTR* lpszArgv)
{
WinExec("C:\\Program Files\\aaaa.exe", SW_SHOWNORMAL);
}

SERVICE_TABLE_ENTRY ServiceTableEntry[] = {
{"服务名称", ServiceMain},
{NULL, NULL}
};

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
StartServiceCtrlDispatcher(ServiceTableEntry);
return 0;
}

服务type加上0x100标志。

#36


你要写成 ATL Server exe 程序

#37


TO:fairyprince
按照您的方法
将代码修改如下,但是貌似还是MFC窗口还是没有显示出来

static UINT __stdcall ThreadFunc(LPVOID pParam)
{
    DWORD dwThreadId; 
    HWINSTA hwinstaSave; 
    HDESK hdeskSave; 
    HWINSTA hwinstaUser; 
    HDESK hdeskUser;  
 
    // Ensure connection to service window station and desktop, and 
    // save their handles. 
    GetDesktopWindow();
    hwinstaSave = GetProcessWindowStation(); 
    dwThreadId = GetCurrentThreadId(); 
    hdeskSave = GetThreadDesktop(dwThreadId); 
 
    // Impersonate the client and connect to the User's 
    // window station and desktop. 

    hwinstaUser = ::OpenWindowStation("WinSta0", FALSE, MAXIMUM_ALLOWED); 
    if (hwinstaUser == NULL) 
    { 
        return 0; 
    }

    SetProcessWindowStation(hwinstaUser); 
    hdeskUser = ::OpenDesktop("Default", 0, FALSE, MAXIMUM_ALLOWED); 
    if (hdeskUser == NULL) 
    { 
        SetProcessWindowStation(hwinstaSave); 
        CloseWindowStation(hwinstaUser); 
        return 0; 
    } 
    SetThreadDesktop(hdeskUser); 

    ::WinExec("C:\\Program Files\\aaaa.exe",SW_SHOWNORMAL);
    //Restore window station and desktop. 
    SetThreadDesktop(hdeskSave); 
    SetProcessWindowStation(hwinstaSave); 
    CloseDesktop(hdeskUser); 
    CloseWindowStation(hwinstaUser);
    return TRUE;
}

void WINAPI ServiceMain()
{
    status.dwCurrentState = SERVICE_START_PENDING;
    status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
    hServiceStatus = ::RegisterServiceCtrlHandler(csServerNameInner, ServiceStrl);
    if (hServiceStatus == NULL)
    {
        return;
    }
    ::SetServiceStatus(hServiceStatus, &status);
    status.dwWin32ExitCode = S_OK;
    status.dwCheckPoint = 0;
    status.dwWaitHint = 0;
    status.dwCurrentState = SERVICE_RUNNING;
    ::SetServiceStatus(hServiceStatus, &status);
    int nLpvoid = 1;
    DWORD dwThreadID;
    
    CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadFunc,(LPVOID)&nLpvoid,0,&dwThreadID);
    
    status.dwCurrentState = SERVICE_STOPPED;
    ::SetServiceStatus(hServiceStatus, &status);   
}


TO:cnzdgs
您是说在注册表中的type再加上0x100?
好像也没用的说。。。。

#38


学习

#39


继续自己顶

#40


呵呵

#41


Createservice的Service_own_process后面还要或一个允许交互的参数