一個winhttp的服務程式

來源:互聯網
上載者:User

 

    公司的考勤系統有兩套,一套是門卡打卡上班,另一套是電腦登陸考勤網站上班。像我這樣成天乘公交上班的人,不知道什麼時候一堵車就遲到了。因此無聊加無奈,才寫了下面的程式。。。。    首先考察一下門卡系統。因為要刷卡才能上班,刷卡資料儲存在公司linux伺服器上,沒啥手腳可以動。於是轉向網站考勤系統。這個網站是用jsp寫得,於是打算用EffeTech HTTP Sniffer偵查一下。本來以為需要很費勁的,其實嗅探下來結果非常簡單,登陸請求就是用URL rewrite技術封裝的。把這個url請求截獲之後,就可以開始類比請求了。用啥語言呢,java中可以直接用socket發請求,但是win32的Platform Sdk中有更高層的HTTP協議封裝——winhttp。於是就簡單地設計了下面的請求發送類 //-----------------------------------------------------------------------// Name: class CMyWinHttp// Desc: Connect to the web server, process the interaction based on http//-----------------------------------------------------------------------class CMyWinHttp{       HINTERNET m_hSession;       HINTERNET m_hConnect;       HINTERNET m_hRequest; public:       CMyWinHttp();        INT Init();       VOID Close();       BOOL ProcessOneRequest(LPCWSTR pwszObjectName); };     建構函式就不說了,反正是初始化成員變數為NULL。Init函數比較簡單,其中HOST和PORT就是伺服器IP和80連接埠。///---------------------------------------------------------------///    DESC: Init the connection///    Unless the host/port/user-agent changes...///---------------------------------------------------------------INT CMyWinHttp::Init(){       // Use WinHttpOpen to obtain a session handle.       m_hSession = WinHttpOpen( USER_AGENT,               WINHTTP_ACCESS_TYPE_NO_PROXY,              WINHTTP_NO_PROXY_NAME,               WINHTTP_NO_PROXY_BYPASS, 0 );        // Specify an HTTP server.       if( m_hSession )              m_hConnect = WinHttpConnect(      m_hSession,              HOST,              PORT, 0 );        if ( m_hConnect )               return 0;              return GetLastError();}     Close()函數也不說了,關閉一些控制代碼。對產生和發送Get請求的封裝處理如下:BOOL CMyWinHttp::ProcessOneRequest(LPCWSTR pwszObjectName){       DWORD dwSize          = 0;       DWORD dwDownloaded           = 0;       LPSTR pszOutBuffer;       BOOL bResults         = FALSE;        // Create an HTTP request handle.       if( m_hConnect )              m_hRequest = WinHttpOpenRequest(      m_hConnect,               L"GET",               pwszObjectName,              NULL,              WINHTTP_NO_REFERER,               WINHTTP_DEFAULT_ACCEPT_TYPES,               0 );        // Send a request.       if( m_hRequest )              bResults = WinHttpSendRequest( m_hRequest,              ADDITIONAL, -1L,              WINHTTP_NO_REQUEST_DATA, 0,               0, 0 );         // End the request.       if( bResults )              bResults = WinHttpReceiveResponse( m_hRequest, NULL );        // Keep checking for data until there is nothing left.       if( bResults )       {              do               {                     // Check for available data.                     dwSize = 0;                     if( !WinHttpQueryDataAvailable( m_hRequest, &dwSize ) )                            printf( "Error %u in WinHttpQueryDataAvailable./n",                            GetLastError( ) );                      // Allocate space for the buffer.                     pszOutBuffer = new char[dwSize+1];                     if( !pszOutBuffer )                     {                            printf( "Out of memory/n" );                            dwSize=0;                     }                     else                     {                            // Read the data.                            ZeroMemory( pszOutBuffer, dwSize+1 );                             if( !WinHttpReadData( m_hRequest, (LPVOID)pszOutBuffer,                                    dwSize, &dwDownloaded ) )                                   printf( "Error %u in WinHttpReadData./n",                                    GetLastError( ) );                            else                                   printf( "%s", pszOutBuffer );                             // Free the memory allocated to the buffer.                            delete [] pszOutBuffer;                     }              } while( dwSize > 0 );       }         // Report any errors.       if( !bResults )              printf( "Error %d has occurred./n", GetLastError( ) );        return bResults;}     主函數只要這麼寫就可以了,其中SUBMIT是解析出來的GET請求。int _tmain(int argc, _TCHAR* argv[]){        CMyWinHttp* myWinHttp = new CMyWinHttp();       if ( myWinHttp->Init() != 0 )               return -1;        if ( !myWinHttp->ProcessOneRequest(SUBMIT) )               return -1;        myWinHttp->Close();       return 0;}     到此九陽神功略有小成,下面要關注的就是怎麼讓它每天都可以自己跑。可以選擇放到計劃任務中,可是總有設定的麻煩。於是打算寫個服務,只有在系統開機的時候運行一次,然後再把機器BIOS設定為定時啟動就可以了(俺rp不錯,正好機器的BIOS中有這個功能,而且還能選擇autoboot only weekday,暈一個)。網上介紹編寫系統服務的鋪天蓋地,我把那個NTService修改了一下就可以用了。類設計如下://-----------------------------------------------------------------------------// Name: class CService// Desc: System service registration//-----------------------------------------------------------------------------class CService{       DWORD dwAttendantTime;       TCHAR* lpServiceName;public:       CService();       //~CService();       static void WINAPI ServiceMain( DWORD argc, TCHAR*      argv[] );       static void WINAPI ServiceControlHandler( DWORD controlCode );       void InstallService();       void UninstallService();       void RunService();        SERVICE_STATUS serviceStatus;       SERVICE_STATUS_HANDLE serviceStatusHandle;       static CService* m_This;       HANDLE stopServiceEvent; };    其中有兩個靜態成員函數,用來做win32api的回呼函數。哎,沒有c#的delegate爽。順便提一下,網上那篇高效能c++委託的實現看起來不太實用,如果不強調高效能的話使用靜態成員函數作Callback函數就可以了。注意有一個靜態成員指標m_This指向類執行個體,在回呼函數中可以使用它訪問類的成員(這個事情在java中是完全不可思議的,因為Java中沒有指標,所以Java只能使用內部類的技術來完成圖形介面的事件相應)。跑題了,下面回過來看ServiceMain()函數 

//-----------------------------------------------------------------------------/// @brief    Static Function ServiceMain for CallBack/// @note     Entry point of the service//-----------------------------------------------------------------------------void CService::ServiceMain( DWORD argc, TCHAR* argv[] ){       CService& ThisService = *m_This;       struct tm* tm;       time_t now;       DWORD minnow;       CMyWinHttp* myWinHttp;       ThisService.dwAttendantTime = GenerateRandomTime();       // initialise service status       ThisService.serviceStatus.dwServiceType = SERVICE_WIN32;       ThisService.serviceStatus.dwCurrentState = SERVICE_STOPPED;       ThisService.serviceStatus.dwControlsAccepted = 0;       ThisService.serviceStatus.dwWin32ExitCode = NO_ERROR;       ThisService.serviceStatus.dwServiceSpecificExitCode = NO_ERROR;       ThisService.serviceStatus.dwCheckPoint = 0;       ThisService.serviceStatus.dwWaitHint = 0;        ThisService.serviceStatusHandle = RegisterServiceCtrlHandler(               ThisService.lpServiceName,               ServiceControlHandler );        if ( ThisService.serviceStatusHandle )       {              // Service is starting               ThisService.serviceStatus.dwCurrentState = SERVICE_START_PENDING;              SetServiceStatus(    ThisService.serviceStatusHandle,                      &(ThisService.serviceStatus) );               // Do initialization              ThisService.stopServiceEvent = CreateEvent( 0, FALSE, FALSE, 0);               // Running               ThisService.serviceStatus.dwControlsAccepted |= (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN);              ThisService.serviceStatus.dwCurrentState = SERVICE_RUNNING;              SetServiceStatus(    ThisService.serviceStatusHandle,                      &(ThisService.serviceStatus) );               do              {                     //Beep( 1000, 100 );                     //Sleep(100);                     time(&now);                     tm = localtime(&now);                     minnow = tm->tm_min;                     // only exectue at 8:00~9:00 on weekday                     if ( (tm->tm_wday == 0) || (tm->tm_wday == 6) || (tm->tm_hour != 8) )                     {                            Sleep(2000);                            SetEvent( ThisService.stopServiceEvent );                            break;                     }                     if (ThisService.dwAttendantTime+38<minnow)                     {                            // for example: now is 8:45, min is 26, then do following:                            myWinHttp = new CMyWinHttp();                            myWinHttp->Init();                            myWinHttp->ProcessOneRequest(QIANZ_SUBMIT);                            myWinHttp->Close();                            SetEvent( ThisService.stopServiceEvent );                     }                     else                     {                            Sleep(1000);                     }              }              while ( WaitForSingleObject( ThisService.stopServiceEvent, 1000 ) == WAIT_TIMEOUT );               // Service was stopped              ThisService.serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;              SetServiceStatus(    ThisService.serviceStatusHandle,                      &(ThisService.serviceStatus) );               // do cleanup here              CloseHandle( ThisService.stopServiceEvent );              ThisService.stopServiceEvent = 0;               // service is now stopped              ThisService.serviceStatus.dwControlsAccepted &= ~(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN);              ThisService.serviceStatus.dwCurrentState = SERVICE_STOPPED;              SetServiceStatus(    ThisService.serviceStatusHandle,                      &(ThisService.serviceStatus) );       }}    看明白了嗎?使用引用CService& ThisService = *m_This來訪問成員變數,並且只有在早上八點到九點的時候向伺服器發送考勤上班請求,然後自動關閉服務。這樣以後就不會遲到了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.