Windows Mobile的遠端控制

來源:互聯網
上載者:User

程式碼

介紹:
這裡描述的是一個Windows Mobile 的案頭遠端控制程式。用這個程式,你可以通過鍵盤和滑鼠遠端控制你的Windows Mobile裝置。
背景:
代碼實在我以前的文章類曾經提到的:一個遠端Windows Mobile螢幕截取工具。除了調用RAPI,該軟體可以通過一個RAPI服務流,允許傳統型程式建立裝置之間不間斷的串連。當然,在該程式中。我放棄了GAPI和DirectDraw的螢幕截取方式,使用了一個簡單的基於GDI螢幕截取方式。為了曾強通訊能力,代碼在串連兩端使用了ZLIB的壓縮庫。
案頭代碼:
請在解壓該程式前建立一個CeRemoteClient的目錄來儲存案頭項目。
傳統型程式代碼的大部分包含在CeRemoteClientView.h中,事實上WTL 8.0架構子視窗實現了所有案頭用戶端的功能。
裝置的串連通過Connect() 和 Disconnect()方法實現。在菜單和工具條中可以使用該命令,這些都包含在主架構視窗類別中(MainFrm.h)。當案頭成功的串連到裝置,一個200微秒的時鐘被建立,用來壓縮螢幕位元影像。
螢幕裝置是由GetScreen()方法控制的。它先關掉計時器,然後發送資訊到服務裝置請求當前螢幕圖象:
KillTimer(SCREEN_TIMER);
hr = Write(RCM_GETSCREEN);

服務裝置返回一個資訊包含同樣的資訊代碼,螢幕緩衝的壓縮大小,然後解壓流資料。在讀取類三個字大小的資料後,代碼判斷壓縮和解壓緩衝的空間是否夠用,然後讀取壓縮的資料流:

//讀取壓縮緩衝區
hr = m_pStream->Read(m_pZipBuf, cbZipBuf, &ulRead);

如果一切順利,壓縮緩衝將被解壓,結果DIB是位元影像的大小。如果大小不一樣則再來一次,當非常接近時,螢幕裝置將被重新整理,這樣整個視窗被清空:
zr = uncompress(m_pScrBuf, &nDestLen, m_pZipBuf, cbZipBuf);
if(zr == Z_OK)
{
    DIBINFO* pDibInfo = (DIBINFO*)m_pScrBuf;
    BYTE*    pBmpData = (BYTE*)(m_pScrBuf + sizeof(DIBINFO));
    BOOL     bErase   = FALSE;

    if(m_xDevScr != pDibInfo->bmiHeader.biWidth ||
       m_yDevScr != pDibInfo->bmiHeader.biHeight)
    {
        m_xDevScr = pDibInfo->bmiHeader.biWidth;
        m_yDevScr = pDibInfo->bmiHeader.biHeight;

        SetScrollSize(m_xDevScr, m_yDevScr);

        bErase = TRUE;
    }

    m_dib.SetBitmap((BITMAPINFO*)pDibInfo, pBmpData);

    InvalidateRect(NULL, bErase);
    UpdateWindow();
}
在強制視窗更新後,計時器重新啟動,這樣我們就可以獲得下一張螢幕圖象。
發送輸入:
發送鍵盤和滑鼠的輸入資訊非常簡單:處理相應的視窗資訊,將其資料轉化為INPUT結構,將其發送到服務端處理。以下是對WM_KEYDOWN的處理:
LRESULT OnKeyDown(TCHAR vk, UINT cRepeat, UINT flags)
{
    HRESULT hr;
    INPUT   input;

    if(!m_bConnected)
        return 0;

    input.type           = INPUT_KEYBOARD;
    input.ki.wVk         = MapKey(vk);
    input.ki.wScan       = 0;
    input.ki.dwFlags     = 0;
    input.ki.time        = 0;
    input.ki.dwExtraInfo = 0;

    hr = Write(RCM_SETINPUT);
    if(SUCCEEDED(hr))
    {
        hr = Write(&input, sizeof(input));
        if(SUCCEEDED(hr))
            GetScreen();
    }

    return 0;
}
MapKey()函數在案頭和鍵盤裝置之間進行基本的安鍵索引。用F1鍵用來控制左,F2用來控制右。F3和F4自然的做為數字鍵。
LRESULT OnLButtonDown(UINT Flags, CPoint pt)
{
    HRESULT    hr;
    INPUT    input;

    if(!m_bConnected)
        return 0;

    m_bLeftBtn           = true;
    input.type           = INPUT_MOUSE;
    input.mi.dwFlags     = MOUSEEVENTF_ABSOLUTE |
                           MOUSEEVENTF_LEFTDOWN;
    input.mi.dx          = pt.x * 65536 / m_xDevScr;
    input.mi.dy          = pt.y * 65536 / m_yDevScr;
    input.mi.mouseData   = 0;
    input.mi.time        = 0;
    input.mi.dwExtraInfo = 0;

    hr = Write(RCM_SETINPUT);
    if(SUCCEEDED(hr))
    {
        hr = Write(&input, sizeof(input));
        if(SUCCEEDED(hr))
            hr = GetScreen();
    }

    return 0;
}
注意滑鼠的螢幕座標是可以被螢幕做參照的,SendInput API在伺服器上使用的原因。
現在注意,讓我們進一步看一下伺服器裝置的代碼。
裝置代碼:
請建立裝置項目的CeRemSrv路徑。
大部分裝置代碼是CRemoteControl類中執行的。所有由案頭客戶發送的資訊在迴圈啟動並執行方法中被處理。
裝置螢幕可以被SendScreen方法撲捉。它有一個和案頭副本很相似的結構。看一下螢幕裝置是怎麼被方便的撲捉的:
hDC = GetWindowDC(NULL);

當獲得了裝置螢幕的HDC後,你可以非常容易的拷貝到一個位元影像檔案中並和案頭聯絡。這裡不需要在懷念 GAPI或DirectDraw技術:
memcpy(m_pScrBuf + i, m_dib.GetBitmapInfo(), sizeof(DIBINFO));
i += sizeof(DIBINFO);

memcpy(m_pScrBuf + i, m_dib.GetDIBits(), m_dib.GetImageSize());
i += m_dib.GetImageSize();

ULONG len = m_cbZipBuf;
int   zr  = compress(m_pZipBuf, &len, m_pScrBuf, cbNew);

if(zr != Z_OK)
    len = 0;

hr = m_pStream->Write(&dwMsg,    sizeof(DWORD), &ulWritten);
hr = m_pStream->Write(&len,      sizeof(ULONG), &ulWritten);
hr = m_pStream->Write(&cbNew,    sizeof(DWORD), &ulWritten);
hr = m_pStream->Write(m_pZipBuf, len,           &ulWritten);

Handling input from the desktop is even simpler:

HRESULT CRemoteControl::GetInput()
{
    INPUT   input;
    HRESULT hr;
    DWORD   dwRead;

    hr = m_pStream->Read(&input, sizeof(input), &dwRead);
    if(FAILED(hr))
        return hr;

    if(dwRead != sizeof(input))
        return E_FAIL;

    SendInput(1, &input, sizeof(input));

    return S_OK;
}

一個非常簡單的方式。
感興趣的幾點:
這裡有兩件事比較有趣:這樣類比滑鼠的雙擊事件,為什麼代碼不會在WM5和WM6裝置上工作?
雙擊必鬚髮送訊息到裝置。這樣是因為視窗將合并四個滑鼠事件(down - up - down - up)到一個單一的資訊WM_LBUTTONDBLCLK中。如果你看了My Code,你就回知道這是怎樣失敗的。
在WM5和WM6裝置中,你可能必須用RAPI的連續性,以便服務裝置DLL響應用戶端。我一次寫了一個簡單的裝置工具以解決著類複雜問題。你在這就能找到,拷貝EXE檔案到裝置上然後運行它。 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.