#include <stdio.h>
#include <time.h>
#include <assert.h>
#include <tchar.h>
#include "svchosttest.h"
#define DEFAULT_SERVICE_NAME TEXT("SvchostTest")
#define DEFAULT_SERVICE_GROUP TEXT("NeoTest")
#define SERVICE_START_CMD TEXT("%SystemRoot%\\System32\\svchost.exe -k NeoTest")
#define SERVICE_DLL TEXT("ServiceDll")
#define MY_EXECUTE_NAME TEXT("Notepad.exe")
#define WAIT_INTERVAL (100)
HANDLE
hDll = NULL;
SERVICE_STATUS_HANDLE
hSrv;
DWORD
dwCurrState;
CRITICAL_SECTION criticalStatus;
BOOL
APIENTRY DllMain(
HANDLE
hModule,
DWORD
ul_reason_for_call,
LPVOID
lpReserved
)
{
switch
(ul_reason_for_call)
{
case
DLL_PROCESS_ATTACH:
hDll = hModule;
#ifdef _DEBUG
AllocConsole();
OutputString(TEXT(
"SvcHostDLL: DllMain called DLL_PROCESS_ATTACH"
));
break
;
case
DLL_THREAD_ATTACH:
OutputString(TEXT(
"SvcHostDLL: DllMain called DLL_THREAD_ATTACH"
));
break
;
case
DLL_THREAD_DETACH:
OutputString(TEXT(
"SvcHostDLL: DllMain called DLL_THREAD_DETACH"
));
break
;
case
DLL_PROCESS_DETACH:
UpdateSvcStatus( SERVICE_STOP_PENDING, 0, 0 );
Sleep(WAIT_INTERVAL);
UpdateSvcStatus( SERVICE_STOPPED, 0, 0 );
OutputString(TEXT(
"SvcHostDLL: DllMain called DLL_PROCESS_DETACH"
));
#endif
break
;
}
return
TRUE;
}
void
WINAPI ServiceMain(
DWORD
dwArgc,
LPTSTR
*lpszArgv)
{
#ifdef _DEBUG
while
(!IsDebuggerPresent())
{
Sleep(WAIT_INTERVAL);
}
DebugBreak();
#endif
TCHAR
svcname[256];
_tcsncpy(svcname, DEFAULT_SERVICE_NAME, _countof(svcname));
hSrv = RegisterServiceCtrlHandlerEx(svcname, (LPHANDLER_FUNCTION_EX)ServiceHandlerEx, NULL );
if
( hSrv == NULL )
{
OutputString(TEXT(
"SvcHostDLL: RegisterServiceCtrlHandler %S failed"
), lpszArgv[0]);
#ifdef _DEBUG
FreeConsole();
#endif
return
;
}
InitializeCriticalSection(&criticalStatus);
UpdateSvcStatus( SERVICE_START_PENDING, 0, 0 );
OutputString(TEXT(
"SvcHostDLL: ServiceMain() Start Pending"
));
Sleep(WAIT_INTERVAL);
UpdateSvcStatus( SERVICE_RUNNING, 0, 0 );
OutputString(TEXT(
"SvcHostDLL: ServiceMain() Running"
));
TCHAR
svccmd[256];
if
(dwArgc > 1)
{
_tcsncpy(svccmd, (
TCHAR
*)lpszArgv[1], _countof(svccmd));
}
else
{
_tcsncpy(svccmd, MY_EXECUTE_NAME, _countof(svccmd));
}
int
bInteract = dwArgc > 2 ? 1 : 0;
StartProcessing(svccmd, bInteract);
do
{
Sleep(WAIT_INTERVAL);
}
while
(dwCurrState != SERVICE_STOP_PENDING && dwCurrState != SERVICE_STOPPED);
OutputString(TEXT(
"SvcHostDLL: ServiceMain done"
));
#ifdef _DEBUG
FreeConsole();
#endif
return
;
}
int
UpdateSvcStatus(
DWORD
dwState,
DWORD
dwExitCode,
DWORD
dwProgress )
{
EnterCriticalSection(&criticalStatus);
SERVICE_STATUS srvStatus;
srvStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
srvStatus.dwCurrentState = dwCurrState = dwState;
srvStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_SHUTDOWN;
srvStatus.dwWin32ExitCode = dwExitCode;
srvStatus.dwServiceSpecificExitCode = NO_ERROR;
srvStatus.dwCheckPoint = dwProgress;
srvStatus.dwWaitHint = 3000;
BOOL
bRet = SetServiceStatus( hSrv, &srvStatus );
LeaveCriticalSection(&criticalStatus);
return
bRet;
}
void
WINAPI ServiceHandlerEx(
DWORD
dwControl,
DWORD
dwEventType,
LPVOID
lpEventData,
LPVOID
lpContext)
{
switch
( dwControl )
{
case
SERVICE_CONTROL_STOP:
UpdateSvcStatus( SERVICE_STOP_PENDING, 0, 1 );
OutputString(TEXT(
"SvcHostDLL: ServiceHandler called SERVICE_CONTROL_STOP"
));
Sleep(WAIT_INTERVAL);
UpdateSvcStatus( SERVICE_STOPPED, 0, 0 );
break
;
case
SERVICE_CONTROL_PAUSE:
UpdateSvcStatus( SERVICE_PAUSE_PENDING, 0, 1 );
OutputString(TEXT(
"SvcHostDLL: ServiceHandler called SERVICE_CONTROL_PAUSE"
));
UpdateSvcStatus( SERVICE_PAUSED, 0, 0 );
break
;
case
SERVICE_CONTROL_CONTINUE:
UpdateSvcStatus( SERVICE_CONTINUE_PENDING, 0, 1 );
OutputString(TEXT(
"SvcHostDLL: ServiceHandler called SERVICE_CONTROL_CONTINUE"
));
UpdateSvcStatus( SERVICE_RUNNING, 0, 0 );
break
;
case
SERVICE_CONTROL_INTERROGATE:
OutputString(TEXT(
"SvcHostDLL: ServiceHandler called SERVICE_CONTROL_INTERROGATE"
));
UpdateSvcStatus( dwCurrState, 0, 0 );
break
;
case
SERVICE_CONTROL_SHUTDOWN:
OutputString(TEXT(
"SvcHostDLL: ServiceHandler called SERVICE_CONTROL_SHUTDOWN"
));
UpdateSvcStatus( SERVICE_STOPPED, 0, 0 );
break
;
}
}
int
StartProcessing(
TCHAR
*cmd,
int
bInteract)
{
OutputString(TEXT(
"SvcHostDLL: RealService called '%s' %s"
), cmd, bInteract ?
"Interact"
:
""
);
STARTUPINFO si = {0};
si.cb =
sizeof
(si);
if
(bInteract) si.lpDesktop = TEXT(
"WinSta0\\Default"
);
PROCESS_INFORMATION pi;
if
(!CreateProcess(NULL, cmd, NULL, NULL,
false
, 0, NULL, NULL, &si, &pi))
{
OutputString(TEXT(
"SvcHostDLL: CreateProcess(%s) error:%d"
), cmd, GetLastError());
}
else
{
OutputString(TEXT(
"SvcHostDLL: CreateProcess(%s) to %d"
), cmd, pi.dwProcessId);
}
return
0;
}
int
InstallService(
TCHAR
*newName)
{
int
rc = 0;
HKEY
hkRoot = HKEY_LOCAL_MACHINE, hkParam = 0;
SC_HANDLE
hscm = NULL, schService = NULL;
try
{
TCHAR
buff[500];
TCHAR
*svcname = DEFAULT_SERVICE_NAME;
if
(newName && newName[0]) svcname = newName;
hscm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if
(hscm == NULL)
{
throw
"OpenSCManager()"
;
}
TCHAR
*svhostStartCmd = SERVICE_START_CMD;
schService = CreateService(
hscm,
svcname,
NULL,
SERVICE_ALL_ACCESS,
SERVICE_WIN32_SHARE_PROCESS,
SERVICE_AUTO_START,
SERVICE_ERROR_NORMAL,
svhostStartCmd,
NULL,
NULL,
NULL,
NULL,
NULL);
if
(schService == NULL)
{
OutputString(TEXT(
"CreateService(%s) error %d"
), svcname, rc = GetLastError());
throw
""
;
}
OutputString(TEXT(
"CreateService(%s) SUCCESS. Config it"
), svcname);
CloseServiceHandle(schService);
CloseServiceHandle(hscm);
hkRoot = HKEY_LOCAL_MACHINE;
_tcsncpy(buff, TEXT(
"SYSTEM\\CurrentControlSet\\Services\\"
), _countof(buff));
_tcsnccat(buff, svcname, 100);
rc = RegOpenKeyEx(hkRoot, buff, 0, KEY_ALL_ACCESS, &hkRoot);
if
(ERROR_SUCCESS != rc)
{
OutputString(TEXT(
"RegOpenKeyEx(%s) KEY_SET_VALUE error %d."
), svcname, rc);
throw
""
;
}
rc = RegCreateKey(hkRoot, TEXT(
"Parameters"
), &hkParam);
SetLastError(rc);
if
(ERROR_SUCCESS != rc)
{
throw
"RegCreateKey(Parameters)"
;
}
if
(!GetModuleFileName(
HMODULE
(hDll), buff, _countof(buff)))
{
throw
"GetModuleFileName() get dll path"
;
}
rc = RegSetValueEx(hkParam, TEXT(
"ServiceDll"
), 0, REG_EXPAND_SZ, (
BYTE
*)buff, _tcsclen(buff)+1);
SetLastError(rc);
if
(ERROR_SUCCESS != rc)
{
throw
"RegSetValueEx(ServiceDll)"
;
}
OutputString(TEXT(
"Config service %s ok."
), svcname);
}
catch
(
TCHAR
*ex)
{
if
(ex && ex[0])
{
rc = GetLastError();
OutputString(TEXT(
"%s error %d"
), ex, rc);
}
}
if
(hkRoot)
{
RegCloseKey(hkRoot);
}
if
(hkParam)
{
RegCloseKey(hkParam);
}
if
(schService)
{
CloseServiceHandle(schService);
}
if
(hscm)
{
CloseServiceHandle(hscm);
}
return
rc;
}
void
CALLBACK RundllInstall(
HWND
hwnd,
HINSTANCE
hinst,
TCHAR
*param,
int
nCmdShow
)
{
InstallService(param);
}
int
UninstallService(
TCHAR
*newName)
{
int
rc = 0;
SC_HANDLE
schService;
SC_HANDLE
hscm;
try
{
hscm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if
(hscm == NULL)
{
OutputString(TEXT(
"OpenSCManager() error %d"
), rc = GetLastError() );
return
rc;
}
TCHAR
*svcname = DEFAULT_SERVICE_NAME;
if
(newName && newName[0]) svcname = newName;
schService = OpenService(hscm, svcname, DELETE);
if
(schService == NULL)
{
OutputString(TEXT(
"OpenService(%s) error %d"
), svcname, rc = GetLastError() );
return
rc;
}
if
(!DeleteService(schService) )
{
OutputString(TEXT(
"OpenService(%s) error %d"
), svcname, rc = GetLastError() );
return
rc;
}
OutputString(TEXT(
"DeleteService(%s) SUCCESS."
), svcname);
}
catch
(
TCHAR
* ex)
{
rc = GetLastError();
OutputString(TEXT(
"Exception Catched 0x%X"
), rc);
}
CloseServiceHandle(schService);
CloseServiceHandle(hscm);
return
rc;
}
void
CALLBACK RundllUninstall(
HWND
hwnd,
HINSTANCE
hinst,
TCHAR
*param,
int
nCmdShow
)
{
UninstallService(param);
}
void
OutputString(
TCHAR
*lpFmt, ... )
{
TCHAR
buff[1024];
va_list
arglist;
va_start
( arglist, lpFmt );
_vsntprintf( buff, _countof(buff), lpFmt, arglist );
va_end
( arglist );
DWORD
len;
HANDLE
herr = GetStdHandle(STD_OUTPUT_HANDLE);
if
(herr != INVALID_HANDLE_VALUE)
{
WriteFile(herr, buff, _tcslen(buff), &len, NULL);
WriteFile(herr,
"\r\n"
, 2, &len, NULL);
}
else
{
FILE
*fp =
fopen
(
"SvcHost.DLL.log"
,
"a"
);
if
(fp)
{
TCHAR
date[20],
time
[20];
fprintf
(fp,
"%s %s - %s\n"
, _tstrdate(date), _tstrtime(
time
), buff);
if
(!stderr)
fclose
(fp);
}
}
OutputDebugString(buff);
return
;
}