/*++ 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); }