638 lines
16 KiB
C
638 lines
16 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
ts3.c
|
||
|
||
Abstract:
|
||
|
||
This is a test program for exercising the service controller. This
|
||
program acts like a service and exercises the Service Controller API
|
||
that can be called from a service:
|
||
SetServiceStatus
|
||
StartServiceCtrlDispatcher
|
||
RegisterServiceCtrlHandler
|
||
|
||
Author:
|
||
|
||
Dan Lafferty (danl) 2 Apr-1992
|
||
|
||
Environment:
|
||
|
||
User Mode -Win32
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
//
|
||
// Includes
|
||
//
|
||
|
||
#include <nt.h> // DbgPrint prototype
|
||
#include <ntrtl.h> // DbgPrint prototype
|
||
#include <nturtl.h> // needed for winbase.h
|
||
|
||
#include <windows.h>
|
||
|
||
#include <winsvc.h>
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <fcntl.h> // OpenFile
|
||
#include <sys\types.h> // OpenFile
|
||
#include <sys\stat.h> // OpenFile
|
||
#include <io.h> // OpenFile
|
||
|
||
#include <tstr.h> // Unicode string macros
|
||
#include <rpc.h>
|
||
|
||
//
|
||
// Defines
|
||
//
|
||
|
||
#define INFINITE_WAIT_TIME 0xffffffff
|
||
|
||
#define NULL_STRING TEXT("");
|
||
|
||
|
||
//
|
||
// Globals
|
||
//
|
||
|
||
SERVICE_STATUS SingleStatus;
|
||
|
||
HANDLE SingleDoneEvent;
|
||
|
||
SERVICE_STATUS_HANDLE SingleStatusHandle;
|
||
|
||
//
|
||
// Function Prototypes
|
||
//
|
||
|
||
VOID
|
||
SingleStart (
|
||
DWORD argc,
|
||
LPTSTR *argv
|
||
);
|
||
|
||
|
||
VOID
|
||
SingleCtrlHandler (
|
||
IN DWORD opcode
|
||
);
|
||
|
||
DWORD
|
||
GetIntlFormat(
|
||
LPWSTR type,
|
||
LPWSTR string,
|
||
DWORD numChars);
|
||
|
||
VOID
|
||
GetTime(
|
||
LPWSTR *time
|
||
);
|
||
|
||
|
||
/****************************************************************************/
|
||
VOID __cdecl
|
||
main(void)
|
||
{
|
||
DWORD status;
|
||
|
||
SERVICE_TABLE_ENTRY DispatchTable[] = {
|
||
{ TEXT("single"), SingleStart },
|
||
{ TEXT("single1"), SingleStart }, // this entry should be ignored.
|
||
{ NULL, NULL }
|
||
};
|
||
|
||
if (!StartServiceCtrlDispatcher( DispatchTable)) {
|
||
status = GetLastError();
|
||
DbgPrint("[ts3]StartServiceCtrlDispatcher failed %d \n",status);
|
||
if (status = ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
|
||
printf("Failed to connect to service controller, this "
|
||
"program should be started with the Services Control Panel Applet, "
|
||
"or at the command line with Net Start <ServiceName>");
|
||
}
|
||
}
|
||
|
||
DbgPrint("[ts3]The Service Process is Terminating....)\n");
|
||
|
||
ExitProcess(0);
|
||
|
||
}
|
||
|
||
|
||
/****************************************************************************/
|
||
|
||
//
|
||
// Single will take a long time to respond to pause
|
||
//
|
||
//
|
||
|
||
VOID
|
||
SingleStart (
|
||
DWORD argc,
|
||
LPTSTR *argv
|
||
)
|
||
{
|
||
DWORD status;
|
||
DWORD i;
|
||
NETRESOURCEW netResource;
|
||
|
||
DbgPrint(" [SINGLE] Inside the Single Service Thread\n");
|
||
|
||
for (i=0; i<argc; i++) {
|
||
DbgPrint(" [SINGLE] CommandArg%d = %s\n", i,argv[i]);
|
||
}
|
||
|
||
|
||
SingleDoneEvent = CreateEvent (NULL, TRUE, FALSE,NULL);
|
||
|
||
//
|
||
// Fill in this services status structure
|
||
//
|
||
DbgPrint(" [SINGLE] Send status with ServiceType = SERVICE_WIN32\n"
|
||
" This should not overwrite the copy that SC maintains\n"
|
||
" which should be SERVICE_WIN32_OWN_PROCESS\n");
|
||
|
||
SingleStatus.dwServiceType = SERVICE_WIN32;
|
||
SingleStatus.dwCurrentState = SERVICE_RUNNING;
|
||
SingleStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
|
||
SERVICE_ACCEPT_PAUSE_CONTINUE;
|
||
SingleStatus.dwWin32ExitCode = 0;
|
||
SingleStatus.dwServiceSpecificExitCode = 0;
|
||
SingleStatus.dwCheckPoint = 0;
|
||
SingleStatus.dwWaitHint = 0;
|
||
|
||
//
|
||
// Register the Control Handler routine.
|
||
//
|
||
|
||
DbgPrint(" [SINGLE] Getting Ready to call RegisterServiceCtrlHandler\n");
|
||
|
||
SingleStatusHandle = RegisterServiceCtrlHandler(
|
||
TEXT("single"),
|
||
SingleCtrlHandler);
|
||
|
||
if (SingleStatusHandle == (SERVICE_STATUS_HANDLE)0) {
|
||
DbgPrint(" [SINGLE] RegisterServiceCtrlHandler failed %d\n", GetLastError());
|
||
}
|
||
|
||
//
|
||
// Return the status
|
||
//
|
||
|
||
if (!SetServiceStatus (SingleStatusHandle, &SingleStatus)) {
|
||
status = GetLastError();
|
||
DbgPrint(" [SINGLE] SetServiceStatus error %ld\n",status);
|
||
}
|
||
|
||
//================================
|
||
// SPECIAL TEST GOES HERE.
|
||
//================================
|
||
|
||
#define TEST_USE_ADD
|
||
#ifdef TEST_USE_ADD
|
||
|
||
netResource.lpRemoteName = L"\\\\Kernel\\scratch";
|
||
netResource.lpLocalName = L"z:";
|
||
netResource.lpProvider = NULL;
|
||
netResource.dwType = RESOURCETYPE_DISK;
|
||
|
||
status = WNetAddConnection2W(&netResource, NULL, NULL, 0L);
|
||
if (status != NO_ERROR) {
|
||
DbgPrint("WNetAddConnection (z:) Failed %d\n",status);
|
||
}
|
||
|
||
netResource.lpRemoteName = L"\\\\popcorn\\public";
|
||
netResource.lpLocalName = L"p:";
|
||
netResource.lpProvider = NULL;
|
||
netResource.dwType = RESOURCETYPE_DISK;
|
||
|
||
status = WNetAddConnection2W(&netResource, NULL, NULL, 0L);
|
||
if (status != NO_ERROR) {
|
||
DbgPrint("WNetAddConnection (p:) Failed %d\n",status);
|
||
}
|
||
#endif
|
||
|
||
{
|
||
UUID Uuid;
|
||
RPC_STATUS rpcstatus;
|
||
|
||
rpcstatus = UuidCreate(&Uuid);
|
||
if (rpcstatus != NO_ERROR) {
|
||
DbgPrint("UuidCreate Failed %d \n",rpcstatus);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Wait forever until we are told to terminate.
|
||
//
|
||
{
|
||
|
||
//
|
||
// This portion of the code determines that the working directory
|
||
// is the system32 directory.
|
||
//
|
||
LPSTR String = GetEnvironmentStrings();
|
||
DWORD rc;
|
||
|
||
Sleep(1000);
|
||
while (*String != 0) {
|
||
DbgPrint("%s\n",String);
|
||
String += (strlen(String) + 1);
|
||
}
|
||
rc = _open("DansFile.txt",O_CREAT | O_BINARY,S_IREAD | S_IWRITE);
|
||
if (rc == -1) {
|
||
DbgPrint("OpenFile Failed\n");
|
||
}
|
||
|
||
}
|
||
|
||
status = WaitForSingleObject (
|
||
SingleDoneEvent,
|
||
INFINITE_WAIT_TIME);
|
||
|
||
status = WNetCancelConnectionW(L"z:",FALSE);
|
||
if (status != NO_ERROR) {
|
||
DbgPrint("WNetCancelConnection (z:) Failed %d\n",status);
|
||
}
|
||
status = WNetCancelConnectionW(L"p:",FALSE);
|
||
if (status != NO_ERROR) {
|
||
DbgPrint("WNetCancelConnection (p:) Failed %d\n",status);
|
||
}
|
||
|
||
DbgPrint(" [SINGLE] Leaving the single service\n");
|
||
|
||
ExitThread(NO_ERROR);
|
||
return;
|
||
}
|
||
|
||
|
||
/****************************************************************************/
|
||
VOID
|
||
SingleCtrlHandler (
|
||
IN DWORD Opcode
|
||
)
|
||
{
|
||
|
||
DWORD status;
|
||
LPWSTR time;
|
||
|
||
HANDLE enumHandle;
|
||
DWORD numElements;
|
||
DWORD bufferSize;
|
||
LPNETRESOURCE pNetResource;
|
||
DWORD i;
|
||
|
||
DbgPrint(" [SINGLE] opcode = %ld\n", Opcode);
|
||
|
||
//
|
||
// Find and operate on the request.
|
||
//
|
||
|
||
switch(Opcode) {
|
||
case SERVICE_CONTROL_PAUSE:
|
||
|
||
DbgPrint("[SINGLE] Sleep 1 minute before responding to pause request\n");
|
||
Sleep(60000); // 1 minute
|
||
|
||
SingleStatus.dwCurrentState = SERVICE_PAUSED;
|
||
break;
|
||
|
||
case SERVICE_CONTROL_CONTINUE:
|
||
|
||
SingleStatus.dwCurrentState = SERVICE_RUNNING;
|
||
break;
|
||
|
||
case SERVICE_CONTROL_STOP:
|
||
|
||
SingleStatus.dwWin32ExitCode = 0;
|
||
SingleStatus.dwCurrentState = SERVICE_STOPPED;
|
||
|
||
SetEvent(SingleDoneEvent);
|
||
break;
|
||
|
||
case SERVICE_CONTROL_INTERROGATE:
|
||
status = WNetOpenEnumW(
|
||
RESOURCE_CONNECTED,
|
||
RESOURCETYPE_DISK,
|
||
0,
|
||
NULL,
|
||
&enumHandle);
|
||
|
||
if (status != WN_SUCCESS) {
|
||
DbgPrint("WNetOpenEnum failed %d\n",status);
|
||
}
|
||
else {
|
||
//
|
||
// Attempt to allow for 10 connections
|
||
//
|
||
bufferSize = (10*sizeof(NETRESOURCE))+1024;
|
||
|
||
pNetResource = (LPNETRESOURCE) LocalAlloc(LPTR, bufferSize);
|
||
|
||
if (pNetResource == NULL) {
|
||
DbgPrint("TestEnum:LocalAlloc Failed %d\n",GetLastError);
|
||
break;
|
||
}
|
||
numElements = 0xffffffff;
|
||
status = WNetEnumResourceW(
|
||
enumHandle,
|
||
&numElements,
|
||
pNetResource,
|
||
&bufferSize);
|
||
|
||
if ( status != WN_SUCCESS) {
|
||
DbgPrint("WNetEnumResource failed %d\n",status);
|
||
|
||
//
|
||
// If there is an extended error, display it.
|
||
//
|
||
if (status == WN_EXTENDED_ERROR) {
|
||
DbgPrint("Extended Error\n");
|
||
}
|
||
WNetCloseEnum(enumHandle);
|
||
LocalFree(pNetResource);
|
||
}
|
||
else {
|
||
if (numElements == 0) {
|
||
DbgPrint("No Connections to Enumerate\n");
|
||
}
|
||
for (i=0; i < numElements ;i++ ) {
|
||
DbgPrint("%ws is connected to %ws\n",
|
||
pNetResource[i].lpLocalName,
|
||
pNetResource[i].lpRemoteName);
|
||
|
||
}
|
||
WNetCloseEnum(enumHandle);
|
||
LocalFree(pNetResource);
|
||
}
|
||
}
|
||
GetTime(&time);
|
||
DbgPrint(" [SINGLE] time = %ws\n",time);
|
||
break;
|
||
|
||
default:
|
||
DbgPrint(" [SINGLE] Unrecognized opcode %ld\n", Opcode);
|
||
}
|
||
|
||
//
|
||
// Send a status response.
|
||
//
|
||
|
||
if (!SetServiceStatus (SingleStatusHandle, &SingleStatus)) {
|
||
status = GetLastError();
|
||
DbgPrint(" [SINGLE] SetServiceStatus error %ld\n",status);
|
||
}
|
||
return;
|
||
}
|
||
|
||
//************************************************************************
|
||
//
|
||
// TEST CODE
|
||
//
|
||
//************************************************************************
|
||
#define PARSE_SIZE 80
|
||
#define TIME_SEP_SIZE 2
|
||
|
||
VOID
|
||
GetTime(
|
||
LPWSTR *time
|
||
)
|
||
{
|
||
WCHAR czParseString[PARSE_SIZE];
|
||
WCHAR czTimeString[PARSE_SIZE];
|
||
LPWSTR pCurLoc;
|
||
LPWSTR pTime;
|
||
DWORD numChars;
|
||
SYSTEMTIME SysTime;
|
||
LPWSTR AMPMString=L"";
|
||
WCHAR TimeSep[TIME_SEP_SIZE];
|
||
BOOL TwelveHour=TRUE;
|
||
BOOL LeadingZero=FALSE;
|
||
DWORD i,dateType;
|
||
DWORD numSame;
|
||
|
||
//-----------------------------------------
|
||
// Get the Current Time and Date.
|
||
//-----------------------------------------
|
||
GetLocalTime(&SysTime);
|
||
|
||
#ifdef CL_DEBUG
|
||
printf("Year=%d,Month=%d,Day=%d,Hour=%d,Minute=%d\n",
|
||
SysTime.wYear,
|
||
SysTime.wMonth,
|
||
SysTime.wDay,
|
||
SysTime.wHour,
|
||
SysTime.wMinute);
|
||
#endif
|
||
//-----------------------------------------
|
||
// Get the Date Format (M/d/yy)
|
||
//-----------------------------------------
|
||
numChars = GetIntlFormat(L"sShortDate",czParseString,PARSE_SIZE);
|
||
if (numChars == 0) {
|
||
//
|
||
// No data, use the default.
|
||
//
|
||
wcscpy(czParseString, L"M/d/yy");
|
||
}
|
||
|
||
//-----------------------------------------
|
||
// Fill in the date string
|
||
//-----------------------------------------
|
||
pCurLoc = czTimeString;
|
||
|
||
for (i=0; i<numChars; i++ ) {
|
||
|
||
dateType = i;
|
||
numSame = 1;
|
||
|
||
//
|
||
// Find out how many characters are the same.
|
||
// (MM or M, dd or d, yy or yyyy)
|
||
//
|
||
while (czParseString[i] == czParseString[i+1]) {
|
||
numSame++;
|
||
i++;
|
||
}
|
||
|
||
//
|
||
// i is the offset to the last character in the date type.
|
||
//
|
||
|
||
switch (czParseString[dateType]) {
|
||
case L'M':
|
||
case L'm':
|
||
//
|
||
// If we have a single digit month, but require 2 digits,
|
||
// then add a leading zero.
|
||
//
|
||
if ((numSame == 2) && (SysTime.wMonth < 10)) {
|
||
*pCurLoc = L'0';
|
||
pCurLoc++;
|
||
}
|
||
ultow(SysTime.wMonth, pCurLoc, 10);
|
||
pCurLoc += wcslen(pCurLoc);
|
||
break;
|
||
|
||
case L'D':
|
||
case L'd':
|
||
|
||
//
|
||
// If we have a single digit day, but require 2 digits,
|
||
// then add a leading zero.
|
||
//
|
||
if ((numSame == 2) && (SysTime.wDay < 10)) {
|
||
*pCurLoc = L'0';
|
||
pCurLoc++;
|
||
}
|
||
ultow(SysTime.wDay, pCurLoc, 10);
|
||
pCurLoc += wcslen(pCurLoc);
|
||
break;
|
||
|
||
case L'Y':
|
||
case L'y':
|
||
|
||
ultow(SysTime.wYear, pCurLoc, 10);
|
||
//
|
||
// If we are only to show 2 digits, take the
|
||
// 3rd and 4th, and move them into the first two
|
||
// locations.
|
||
//
|
||
if (numSame == 2) {
|
||
pCurLoc[0] = pCurLoc[2];
|
||
pCurLoc[1] = pCurLoc[3];
|
||
pCurLoc[2] = L'\0';
|
||
}
|
||
pCurLoc += wcslen(pCurLoc);
|
||
break;
|
||
|
||
default:
|
||
printf("Default case: Unrecognized time character - "
|
||
"We Should never get here\n");
|
||
break;
|
||
}
|
||
//
|
||
// Increment the index beyond the last character in the data type.
|
||
// If not at the end of the buffer, add the separator character.
|
||
// Otherwise, add the trailing NUL.
|
||
//
|
||
i++;
|
||
if ( i<numChars ) {
|
||
*pCurLoc = czParseString[i];
|
||
pCurLoc++;
|
||
}
|
||
else {
|
||
*pCurLoc='\0';
|
||
}
|
||
}
|
||
|
||
//-----------------------------------------
|
||
// 12 or 24 hour format?
|
||
//-----------------------------------------
|
||
numChars = GetIntlFormat(L"iTime",czParseString,PARSE_SIZE);
|
||
if (numChars > 0) {
|
||
if (*czParseString == L'1'){
|
||
TwelveHour = FALSE;
|
||
}
|
||
}
|
||
|
||
//-----------------------------------------
|
||
// Is there a Leading Zero?
|
||
//-----------------------------------------
|
||
if (GetProfileIntW(L"intl",L"iTLZero",0) == 1) {
|
||
LeadingZero = TRUE;
|
||
}
|
||
|
||
//-----------------------------------------
|
||
// Get the Time Separator character.
|
||
//-----------------------------------------
|
||
numChars = GetIntlFormat(L"sTime",TimeSep,TIME_SEP_SIZE);
|
||
if (numChars == 0) {
|
||
//
|
||
// No data, use the default.
|
||
//
|
||
TimeSep[0] = L':';
|
||
TimeSep[1] = L'\0';
|
||
}
|
||
|
||
//-------------------------------------------------
|
||
// If running a 12 hour clock, Get the AMPM string.
|
||
//-------------------------------------------------
|
||
if (TwelveHour) {
|
||
if (SysTime.wHour > 11) {
|
||
numChars = GetIntlFormat(L"s2359",czParseString,PARSE_SIZE);
|
||
}
|
||
else {
|
||
numChars = GetIntlFormat(L"s1159",czParseString,PARSE_SIZE);
|
||
}
|
||
if (numChars > 0) {
|
||
AMPMString = LocalAlloc(LMEM_FIXED,wcslen(czParseString)+sizeof(WCHAR));
|
||
if (AMPMString != NULL) {
|
||
wcscpy(AMPMString,czParseString);
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Build the time string
|
||
//
|
||
pTime = czTimeString + (wcslen(czTimeString) + 1);
|
||
|
||
if ((TwelveHour) && (SysTime.wHour > 12)) {
|
||
SysTime.wHour -= 12;
|
||
}
|
||
//
|
||
// If the time is a single digit, and we need a leading zero,
|
||
// than add the leading zero.
|
||
//
|
||
if ((SysTime.wHour < 10) && (LeadingZero)) {
|
||
*pTime = L'0';
|
||
pTime++;
|
||
}
|
||
ultow(SysTime.wHour, pTime, 10);
|
||
pTime += wcslen(pTime);
|
||
*pTime = *TimeSep;
|
||
pTime++;
|
||
if (SysTime.wMinute < 10) {
|
||
*pTime = L'0';
|
||
pTime++;
|
||
}
|
||
ultow(SysTime.wMinute, pTime, 10);
|
||
wcscat(pTime,AMPMString);
|
||
|
||
pTime = czTimeString + (wcslen(czTimeString) + 1);
|
||
|
||
#ifdef CL_DEBUG
|
||
printf("Time = %ws, Date = %ws\n",pTime,czTimeString);
|
||
#endif
|
||
|
||
*(--pTime) = L' ';
|
||
printf("\n %ws\n", czTimeString);
|
||
*time = czTimeString;
|
||
}
|
||
|
||
DWORD
|
||
GetIntlFormat(
|
||
LPWSTR type,
|
||
LPWSTR string,
|
||
DWORD numChars)
|
||
{
|
||
DWORD num;
|
||
|
||
num = GetProfileStringW(L"intl",type,L"",string,numChars);
|
||
|
||
#ifdef CL_DEBUG
|
||
if (num > 0) {
|
||
printf("%ws string from ini file = %ws\n",type, string);
|
||
}
|
||
else {
|
||
printf("%ws string from ini file = (empty)\n",type);
|
||
}
|
||
#endif
|
||
return(num);
|
||
}
|