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; 
}