www.pudn.com > liuqudong.zip > TickSrv.cpp
//====================================================================== // TickSrv - Simple example service for Windows CE // // Written for the book Programming Windows CE // Copyright (C) 2003 Douglas Boling //====================================================================== #include// For all that Windows stuff #include // Socket support #include "service.h" // Service includes #include "TickSrv.h" // Local program includes #define REGNAME TEXT("TickSrv") // Reg name under services key #define PORTNUM 1000 // Port number to monitor // // Globals // HINSTANCE hInst; // DLL instance handle // // Debug zone support // #ifdef DEBUG // Used as a prefix string for all debug zone messages. #define DTAG TEXT ("TickSrv: ") // Debug zone constants #define ZONE_ERROR DEBUGZONE(0) #define ZONE_WARNING DEBUGZONE(1) #define ZONE_FUNC DEBUGZONE(2) #define ZONE_INIT DEBUGZONE(3) #define ZONE_DRVCALLS DEBUGZONE(4) #define ZONE_IOCTLS DEBUGZONE(5) #define ZONE_THREAD DEBUGZONE(6) #define ZONE_EXENTRY (ZONE_FUNC | ZONE_DRVCALLS) // Debug zone structure DBGPARAM dpCurSettings = { TEXT("TickSrv"), { TEXT("Errors"),TEXT("Warnings"),TEXT("Functions"), TEXT("Init"),TEXT("Driver Calls"),TEXT("Undefined"), TEXT("IOCtls"),TEXT("Thread"), TEXT("Undefined"), TEXT("Undefined"),TEXT("Undefined"),TEXT("Undefined"), TEXT("Undefined"),TEXT("Undefined"),TEXT("Undefined"), TEXT("Undefined") }, 0x0003 }; #endif //DEBUG //====================================================================== // DllMain - DLL initialization entry point // BOOL WINAPI DllMain (HANDLE hinstDLL, DWORD dwReason, LPVOID lpvReserved) { hInst = (HINSTANCE)hinstDLL; switch (dwReason) { case DLL_PROCESS_ATTACH: DEBUGREGISTER(hInst); // Improve performance by passing on thread attach calls DisableThreadLibraryCalls (hInst); break; case DLL_PROCESS_DETACH: DEBUGMSG(ZONE_INIT, (DTAG TEXT("DLL_PROCESS_DETACH\r\n"))); break; } return TRUE; } //====================================================================== // TCK_Init - Driver initialization function // DWORD TCK_Init (DWORD dwContext) { PSRVCONTEXT pSrv; DEBUGMSG (ZONE_INIT | ZONE_EXENTRY, (DTAG TEXT("TCK_Init++ dwContext:%x\r\n"), dwContext)); // Init WinSock WSADATA wsaData; WSAStartup(0x101,&wsaData); // Allocate a drive instance structure. pSrv = (PSRVCONTEXT)LocalAlloc (LPTR, sizeof (SRVCONTEXT)); if (pSrv) { // Initialize structure. memset ((PBYTE) pSrv, 0, sizeof (SRVCONTEXT)); pSrv->dwSize = sizeof (SRVCONTEXT); pSrv->servState = SERVICE_STATE_UNKNOWN; InitializeCriticalSection (&pSrv->csData); switch (dwContext) { case SERVICE_INIT_STARTED: pSrv->servState = SERVICE_STATE_ON; break; case SERVICE_INIT_STOPPED: pSrv->servState = SERVICE_STATE_OFF; break; case SERVICE_INIT_STANDALONE: break; default: break; } } else DEBUGMSG (ZONE_INIT | ZONE_ERROR, (DTAG TEXT("TCK_Init failure. Out of memory\r\n"))); DEBUGMSG (ZONE_FUNC, (DTAG TEXT("TCK_Init-- pSrv: %x\r\n"), pSrv)); return (DWORD)pSrv; } //====================================================================== // TCK_Deinit - Driver de-initialization function // BOOL TCK_Deinit (DWORD dwContext) { PSRVCONTEXT pSrv = (PSRVCONTEXT) dwContext; DEBUGMSG (ZONE_EXENTRY, (DTAG TEXT("TCK_Deinit++ dwContex:%x\r\n"), dwContext)); if (pSrv && (pSrv->dwSize == sizeof (SRVCONTEXT))) { // Free the driver state buffer. LocalFree ((PBYTE)pSrv); } DEBUGMSG (ZONE_FUNC, (DTAG TEXT("TCK_Deinit--\r\n"))); return TRUE; } //====================================================================== // TCK_IOControl - Called when DeviceIOControl called // ServiceEnumInfo DWORD TCK_IOControl (DWORD dwOpen, DWORD dwCode, PBYTE pIn, DWORD dwIn, PBYTE pOut, DWORD dwOut, DWORD *pdwBytesWritten) { PSRVCONTEXT pSrv; DWORD err = ERROR_INVALID_PARAMETER; pSrv = (PSRVCONTEXT) dwOpen; DEBUGMSG (ZONE_EXENTRY, (DTAG TEXT("TCK_IOControl++ dwOpen: %x dwCode: %x %d\r\n"), dwOpen, dwCode, pSrv->servState)); switch (dwCode) { // ------------- // Commands // ------------- // Cmd to start service case IOCTL_SERVICE_START: DEBUGMSG (ZONE_IOCTLS, (DTAG TEXT("IOCTL_SERVICE_START\r\n"))); EnterCriticalSection (&pSrv->csData); if ((pSrv->servState == SERVICE_STATE_OFF) | (pSrv->servState == SERVICE_STATE_UNKNOWN)) { pSrv->servState = SERVICE_STATE_ON; err = 0; } else err = ERROR_SERVICE_ALREADY_RUNNING; LeaveCriticalSection (&pSrv->csData); break; // Cmd to stop service case IOCTL_SERVICE_STOP: DEBUGMSG (ZONE_IOCTLS, (DTAG TEXT("IOCTL_SERVICE_STOP\r\n"))); EnterCriticalSection (&pSrv->csData); if ((pSrv->servState == SERVICE_STATE_ON)) { pSrv->servState = SERVICE_STATE_SHUTTING_DOWN; } else err = ERROR_SERVICE_NOT_ACTIVE; LeaveCriticalSection (&pSrv->csData); break; //Reread service reg setting case IOCTL_SERVICE_REFRESH: DEBUGMSG (ZONE_IOCTLS, (DTAG TEXT("IOCTL_SERVICE_REFRESH\r\n"))); // No settings in example service to read break; //Config registry for auto load on boot case IOCTL_SERVICE_INSTALL: DEBUGMSG (ZONE_IOCTLS, (DTAG TEXT("IOCTL_SERVICE_INSTALL\r\n"))); err = RegisterService(); break; //Clear registry of auto load stuff case IOCTL_SERVICE_UNINSTALL: DEBUGMSG (ZONE_IOCTLS, (DTAG TEXT("IOCTL_SERVICE_UNINSTALL\r\n"))); err = DeregisterService(); break; //Clear registry of auto load stuff case IOCTL_SERVICE_CONTROL: DEBUGMSG (ZONE_IOCTLS, (DTAG TEXT("IOCTL_SERVICE_CONTROL\r\n"))); err = 0; break; #ifdef DEBUG // Set debug zones case IOCTL_SERVICE_DEBUG: DEBUGMSG (ZONE_IOCTLS, (DTAG TEXT("IOCTL_SERVICE_DEBUG\r\n"))); if (!pIn || (dwIn < sizeof (DWORD))) break; __try { dpCurSettings.ulZoneMask = *(DWORD *)pIn; err = 0; } __except (EXCEPTION_EXECUTE_HANDLER) { ; } #endif // ------------- // Queries // ------------- // Query for current service state case IOCTL_SERVICE_STATUS: DEBUGMSG (ZONE_IOCTLS, (DTAG TEXT("IOCTL_SERVICE_STATUS\r\n"))); if (!pOut || (dwOut < sizeof (DWORD))) break; __try { *(DWORD *)pOut = pSrv->servState; if (pdwBytesWritten) *pdwBytesWritten = sizeof (DWORD); err = 0; } __except (EXCEPTION_EXECUTE_HANDLER) { ; } break; // Query for unload. case IOCTL_SERVICE_QUERY_CAN_DEINIT: DEBUGMSG (ZONE_IOCTLS, (DTAG TEXT("IOCTL_SERVICE_QUERY_CAN_DEINIT\r\n"))); if (!pOut || (dwOut < sizeof (DWORD))) break; __try { *(DWORD *)pOut = 1; // non-zero == Yes, can be unloaded. if (pdwBytesWritten) *pdwBytesWritten = sizeof (DWORD); err = 0; } __except (EXCEPTION_EXECUTE_HANDLER) { ; } break; // Query to see if sock address okay for monitoring case IOCTL_SERVICE_REGISTER_SOCKADDR: DEBUGMSG (ZONE_IOCTLS, (DTAG TEXT("IOCTL_SERVICE_REGISTER_SOCKADDR\r\n"))); // Calling to see if service can accept super service help if (!pIn || (dwIn < sizeof (DWORD))) { if ((pSrv->servState == SERVICE_STATE_OFF) | (pSrv->servState == SERVICE_STATE_UNKNOWN)) pSrv->servState = SERVICE_STATE_STARTING_UP; err = 0; break; } // Confirming a specific sock address DEBUGMSG (ZONE_IOCTLS, (DTAG TEXT("Socket:%x\r\n"), *pIn)); err = 0; break; // ------------- // Notifications // ------------- // Notify that sock address going away case IOCTL_SERVICE_DEREGISTER_SOCKADDR: DEBUGMSG (ZONE_IOCTLS, (DTAG TEXT("IOCTL_SERVICE_DEREGISTER_SOCKADDR\r\n"))); EnterCriticalSection (&pSrv->csData); if (pSrv->servState == SERVICE_STATE_SHUTTING_DOWN) pSrv->servState = SERVICE_STATE_OFF; LeaveCriticalSection (&pSrv->csData); err = 0; break; // All super service ports open case IOCTL_SERVICE_STARTED: DEBUGMSG (ZONE_IOCTLS, (DTAG TEXT("IOCTL_SERVICE_STARTED\r\n"))); EnterCriticalSection (&pSrv->csData); if ((pSrv->servState == SERVICE_STATE_STARTING_UP) | (pSrv->servState == SERVICE_STATE_UNKNOWN)) pSrv->servState = SERVICE_STATE_ON; LeaveCriticalSection (&pSrv->csData); err = 0; break; // Notification that connect has occured case IOCTL_SERVICE_CONNECTION: DEBUGMSG (ZONE_IOCTLS, (DTAG TEXT("IOCTL_SERVICE_CONNECTION\r\n"))); if (!pIn || (dwIn < sizeof (DWORD))) break; // Create thread to handle the socket CreateThread (NULL, 0, AcceptThread, (PVOID)*(DWORD*)pIn, 0, NULL); err = 0; break; default: DEBUGMSG (ZONE_ERROR | ZONE_IOCTLS, (DTAG TEXT("Unsupported IOCTL code %x (%d)\r\n"), dwCode, (dwCode & 0x00ff) / 4)); return FALSE; } SetLastError (err); DEBUGMSG (ZONE_FUNC, (DTAG TEXT("TCK_IOControl-- %d\r\n"), err)); return (err == 0) ? TRUE : FALSE; } //====================================================================== // TCK_PowerDown - Called when system suspends // // NOTE: No kernel calls, including debug messages, can be made from // this call. // void TCK_PowerDown (DWORD dwContext) { return; } //====================================================================== // TCK_PowerUp - Called when resumes // // NOTE: No kernel calls, including debug messages, can be made from // this call. // void TCK_PowerUp (DWORD dwContext) { return; } //---------------------------------------------------------------------- // AddRegString - Helper routine // int AddRegString (HKEY hKey, LPTSTR lpName, LPTSTR lpStr) { return RegSetValueEx (hKey, lpName, 0, REG_SZ, (PBYTE)lpStr, (lstrlen (lpStr) + 1) * sizeof (TCHAR)); } //---------------------------------------------------------------------- // AddRegDW - Helper routine // int AddRegDW (HKEY hKey, LPTSTR lpName, DWORD dw) { return RegSetValueEx (hKey, lpName, 0, REG_DWORD, (PBYTE)&dw, 4); } //---------------------------------------------------------------------- // AddRegSuperServ - Helper routine // int AddRegSuperServ (HKEY hKey, WORD wPort) { SOCKADDR_IN sa; HKEY hSubKey; TCHAR szKeyName[128]; DWORD dw; int rc; DEBUGMSG (ZONE_FUNC, (DTAG TEXT("AddRegSuperServ++ %d\r\n"), wPort)); memset (&sa, 0, sizeof (sa)); sa.sin_family = AF_INET; sa.sin_port = htons(wPort); sa.sin_addr.s_addr = INADDR_ANY; // Create key for this service wsprintf (szKeyName, TEXT("Accept\\TCP-%d"), wPort); rc = RegCreateKeyEx (hKey, szKeyName, 0, NULL, 0, NULL, NULL, &hSubKey, &dw); DEBUGMSG (1, (TEXT("RegCreateKeyEx %d %d\r\n"), rc, GetLastError())); if (rc == ERROR_SUCCESS) rc = RegSetValueEx (hSubKey, TEXT("SockAddr"), 0, REG_BINARY, (PBYTE)&sa, sizeof (sa)); DEBUGMSG (ZONE_FUNC, (DTAG TEXT("AddRegSuperServ-- %d\r\n"),rc)); return rc; } //---------------------------------------------------------------------- // RegisterService - Add registery settings for auto load // int RegisterService () { HKEY hKey, hSubKey; TCHAR szModName[MAX_PATH], *pName; DWORD dw; int rc; // Open the Services key rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,TEXT("Services"),0, 0, &hKey); if (rc == ERROR_SUCCESS) { // Create key for this service rc = RegCreateKeyEx (hKey, REGNAME, 0, NULL, 0, NULL, NULL, &hSubKey, &dw); if (rc == ERROR_SUCCESS) { GetModuleFileName (hInst, szModName, dim (szModName)); // Scan to filename pName = szModName + lstrlen (szModName); while ((pName > szModName) && (*pName != TEXT('\\'))) pName--; if (*pName == TEXT('\\')) pName++; AddRegString (hSubKey, TEXT ("DLL"), pName); AddRegString (hSubKey, TEXT ("Prefix"), TEXT("TCK")); AddRegDW (hSubKey, TEXT("Index"), 0); AddRegDW (hSubKey, TEXT("Context"), SERVICE_INIT_STOPPED); AddRegString (hSubKey, TEXT("DisplayName"), TEXT("Tick Service")); AddRegString (hSubKey, TEXT("Description"), TEXT("Returns system tick cnt on Port 1000")); AddRegSuperServ (hSubKey, PORTNUM); } else DEBUGMSG (ZONE_ERROR, (TEXT("Error creating key\r\n"))); RegCloseKey(hKey); } else DEBUGMSG (ZONE_ERROR, (TEXT("Error opening key\r\n"))); return (rc == ERROR_SUCCESS) ? 0 : -1; } //---------------------------------------------------------------------- // DeregisterService - Remove auto load settings from registry // int DeregisterService () { HKEY hKey; int rc; // Open the Services key rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,TEXT("Services"),0, 0, &hKey); if (rc == ERROR_SUCCESS) { // Delete key for this service rc = RegDeleteKey (hKey, REGNAME); if (rc != ERROR_SUCCESS) DEBUGMSG(ZONE_ERROR, (DTAG TEXT("Error deleting key %d\r\n"), GetLastError())); RegCloseKey(hKey); } else DEBUGMSG (ZONE_ERROR, (TEXT("Error opening key\r\n"))); return (rc == ERROR_SUCCESS) ? 0 : -1; } //====================================================================== // AcceptThread - Thread for managing connected sockets // DWORD WINAPI AcceptThread (PVOID pArg) { SOCKET sock; int rc; DWORD dwCmd, dwTicks; sock = (SOCKET)pArg; DEBUGMSG (ZONE_THREAD, (TEXT("AcceptThread++ %x\r\n"), pArg)); // Simple task, for any non-zero received byte, sent tick count back rc = recv (sock, (char *)&dwCmd, sizeof (DWORD), 0); while ((rc != SOCKET_ERROR) && (dwCmd != 0)) { DEBUGMSG (ZONE_THREAD, (TEXT("Recv cmd %x\r\n"), dwCmd)); dwTicks = GetTickCount (); DEBUGMSG (ZONE_THREAD, (TEXT("sending %d\r\n"), dwTicks)); rc = send (sock, (char *)&dwTicks, 4, 0); // Read next cmd rc = recv (sock, (char *)&dwCmd, sizeof (DWORD), 0); } closesocket (sock); DEBUGMSG (ZONE_THREAD, (TEXT("AcceptThread-- %d %d\r\n"),rc, GetLastError())); return 0; }