eMbedded VC++入門

<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 

 

 

1.gif

 

 

你好暈倒的蜥蜴!

任何一個學過編程的朋友都對HELLO不會陌生,但這次的這個和以前的不太一樣,它是一個特別的程序,不是在功能上,是在思想上。

這是一個非常經典的程序,本不想列出這個程序,但這是WINCE編程的典型框架,寫出它可以讓我們對WINCE的程序有一個很直觀的認識。還有一個重要的原因是,這個例子程序給出了一個新的代碼風格,和以前的WIN32程序有所不同,我十分欣賞這種代碼的或者說程序結構,因此便再一次將這個程序寫出。不過我做了一些小小的變動。主要的目的:

l         瞭解WINCE程序的結構和原理。

l         欣賞並學習一種非常優美的代碼風格。

l         瞭解使用EVC編寫WINCE程序的方法(介紹IDE)。

 

打開eMbedded VC++選擇新建。

2.gif

 

怎麼樣界面和VC6差不多吧。我們選擇WCE Pocket PC 2002 Application,在項目名稱處輸入HelloCE,檢查CPUS是否選中了ARMX86。這個應該根據你的開發環境有所不同。就我而言,首先要在PC機上進行調試,然後編譯成適合我使的應用程序,我的PPCARM CPU所以我需要WCE X86WCE ARM,至於其它的例如MIPSSH我並沒有考慮。(如果你要開發商用軟件或者想讓更多的人使用你的程序,你應該考慮更多種類的CPU。)好進行下一步:

3.gif

 

我們選擇一個空的項目。單擊完成。好了我們看到EVC已經爲我們建立了一個應用程序框架,當然在這個例子,它是空的。不過我們也可以在目錄下找到下圖顯示的幾個文件。

4.gif

好我們向我們的項目中添加一個頭文件HelloCE.h和一個HelloCE.c文件。它們被我列在下面:你可以直接拷貝,不過需要注意一些討厭的格式(例如空格)造成的編譯錯誤。不過最好的辦法是手工的輸入,它們並不算長。

//======================================================================

// Header filehelloce.h

//======================================================================

// 返回元素的數量,主要用於搜索消息列表

#define dim(x) (sizeof(x) / sizeof(x[0]))

//----------------------------------------------------------------------

//數據類型定義

//

struct decodeUINT {                            //消息和消息函數的關聯結構

    UINT Code;

    LRESULT (*Fxn)(HWND, UINT, WPARAM, LPARAM); //這裏用到了函數指針

};

struct decodeCMD {                             //菜單和處理函數的關聯結構

    UINT Code;                                 

    LRESULT (*Fxn)(HWND, WORD, HWND, WORD); //這裏用到了函數指針

};

 

//----------------------------------------------------------------------

#define  IDC_CMDBAR 1                          // 命令條ID

 

//----------------------------------------------------------------------

// 函數原型

//

int InitApp (HINSTANCE);  //初始化應用函數原型

HWND InitInstance (HINSTANCE, LPWSTR, int);  //初始化實例函數原型

int TermInstance (HINSTANCE, int);  //實例終止函數原型

// 窗口處理函數原型

LRESULT CALLBACK MainWndProc (HWND, UINT, WPARAM, LPARAM);

// 消息句柄

LRESULT DoCreateMain (HWND, UINT, WPARAM, LPARAM);

LRESULT DoPaintMain (HWND, UINT, WPARAM, LPARAM);

LRESULT DoHibernateMain (HWND, UINT, WPARAM, LPARAM);

LRESULT DoActivateMain (HWND, UINT, WPARAM, LPARAM);

LRESULT DoDestroyMain (HWND, UINT, WPARAM, LPARAM);

 

 

//======================================================================

// HelloCE – helloce.c

//======================================================================

#include <windows.h>                

#include <commctrl.h>

#include "helloce.h"

//----------------------------------------------------------------------

// 全局數據

//

const TCHAR szAppName[] = TEXT ("HelloCE");

HINSTANCE hInst;                     // 程序的實例句柄

//主窗口過程函數的消息映射表用到decodeUINT結構

const struct decodeUINT MainMessages[] = {

    WM_CREATE, DoCreateMain,

    WM_PAINT, DoPaintMain,

    WM_HIBERNATE, DoHibernateMain,

    WM_ACTIVATE, DoActivateMain,

    WM_DESTROY, DoDestroyMain,

};

 

//======================================================================

// 程序的入口

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,

                    LPWSTR lpCmdLine, int nCmdShow) {

    MSG msg;

    int rc = 0;

    HWND hwndMain;

    // 初始應用

    rc = InitApp (hInstance);

    if (rc) return rc;

    // 初始化實例

    hwndMain = InitInstance (hInstance, lpCmdLine, nCmdShow);

    if (hwndMain == 0)

        return 0x10;

    // 應用程序消息循環

    while (GetMessage (&msg, NULL, 0, 0)) {

        TranslateMessage (&msg);

        DispatchMessage (&msg);

    }

    //實例清除

    return TermInstance (hInstance, msg.wParam);

}

//----------------------------------------------------------------------

// 應用程序初始化函數

//

int InitApp (HINSTANCE hInstance) {

    WNDCLASS wc;

    //註冊應用程序的主窗口類

    wc.style = 0;                             // 窗口樣式

    wc.lpfnWndProc = MainWndProc;             // 回調函數

    wc.cbClsExtra = 0;                        // 擴展的類數據

    wc.cbWndExtra = 0;                        // 擴展的窗口數據

    wc.hInstance = hInstance;                 //實例句柄

    wc.hIcon = NULL,                          // 圖標

    wc.hCursor = NULL;                        // 鼠標

    wc.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);

    wc.lpszMenuName =  NULL;                  //菜單

    wc.lpszClassName = szAppName;             //窗口類的名字

 

    if (RegisterClass (&wc) == 0) return 1;

 

    return 0;

}

//----------------------------------------------------------------------

//初始化實例

//

HWND InitInstance (HINSTANCE hInstance, LPWSTR lpCmdLine,

                   int nCmdShow) {

    HWND hWnd;

    // 存儲程序實例句柄到全局變量

    hInst = hInstance;

    // 建立主窗口

    hWnd = CreateWindow (szAppName,           // 窗口類

                         TEXT("你好蜥蜴"),       //窗口標題

                         WS_VISIBLE,          //樣式

                         CW_USEDEFAULT,       // x座標

                         CW_USEDEFAULT,       // y 座標

                         CW_USEDEFAULT,       // 初始寬度

                         CW_USEDEFAULT,       // 初始高度

                         NULL,                // 父窗口

                         NULL,                //菜單,必須爲NULLWINCE窗口不支持菜單。

                         hInstance,           // 實例

                         NULL);               //建立參數的指針,用於WM_CRATE消息期間。

    // 如果不能建立主窗口返回失敗

    if (!IsWindow (hWnd)) return 0;

    // 顯示和更新窗口函數

    ShowWindow (hWnd, nCmdShow);

    UpdateWindow (hWnd);

    return hWnd;

}

//----------------------------------------------------------------------

// TermInstance –程序清除

//

int TermInstance (HINSTANCE hInstance, int nDefRC) {

 

    return nDefRC;

}

//======================================================================

// 下面是主窗口的消息處理函數

//

//----------------------------------------------------------------------

// MainWndProc – 主過程函數,這是一個回調函數

//

LRESULT CALLBACK MainWndProc (HWND hWnd, UINT wMsg, WPARAM wParam,

                              LPARAM lParam) {

    INT i;

    //搜索消息列表,如果編寫了對應的函數來處理這個消息則調用這個函數

    for (i = 0; i < dim(MainMessages); i++) {

        if (wMsg == MainMessages[i].Code)

            return (*MainMessages[i].Fxn)(hWnd, wMsg, wParam, lParam);

    }

    return DefWindowProc (hWnd, wMsg, wParam, lParam);  //沒有編寫對應的函數則調用默認的

}

//----------------------------------------------------------------------

// DoCreateMain – 處理窗口建立(WM_CREATE)消息的函數.

//

LRESULT DoCreateMain (HWND hWnd, UINT wMsg, WPARAM wParam,

                      LPARAM lParam) {

    HWND hwndCB;

    // 建立命令條.

    hwndCB = CommandBar_Create (hInst, hWnd, IDC_CMDBAR);

    // 添加退出按鈕到命令條上

    CommandBar_AddAdornments (hwndCB, 0, 0);

    return 0;

}

//----------------------------------------------------------------------

// DoPaintMain – 處理窗口重畫(WM_PAINT)消息的函數

//

LRESULT DoPaintMain (HWND hWnd, UINT wMsg, WPARAM wParam,

                     LPARAM lParam) {

    PAINTSTRUCT ps;

    RECT rect;

    HDC hdc;

    // 調整客戶區域的大小並考慮命令條的高度

    GetClientRect (hWnd, &rect);

    rect.top += CommandBar_Height (GetDlgItem (hWnd, IDC_CMDBAR));

    hdc = BeginPaint (hWnd, &ps);

    DrawText (hdc, TEXT ("你好暈倒的蜥蜴!"), -1, &rect,  //被改成了中文

              DT_CENTER | DT_VCENTER | DT_SINGLELINE);

    EndPaint (hWnd, &ps);

    return 0;

}

//----------------------------------------------------------------------

// DoHibernateMain – 處理窗口掛起消息(WM_HIBERNATE)的函數,這是WINCE獨有的消息,目的//是將內存的使用量將到最小.

//

LRESULT DoHibernateMain (HWND hWnd, UINT wMsg, WPARAM wParam,

                         LPARAM lParam) {

    // 如果窗口不是活動的,則取消命令條,釋放內存

    if (GetActiveWindow () != hWnd)

        CommandBar_Destroy (GetDlgItem (hWnd, IDC_CMDBAR));

    return 0;

}

//----------------------------------------------------------------------

// DoActivateMain – 處理窗口激活(WM_ACTIVATE)消息的函數

//

LRESULT DoActivateMain (HWND hWnd, UINT wMsg, WPARAM wParam,

                        LPARAM lParam) {

    HWND hwndCB;

    // 如果窗口正處在活動狀態而沒有命令條則建立它

    if ((LOWORD (wParam) != WA_INACTIVE) &&

        (GetDlgItem (hWnd, IDC_CMDBAR) == 0)) {

        // 建立命令條

        hwndCB = CommandBar_Create (hInst, hWnd, IDC_CMDBAR);

        // 添加退出按鈕到命令條

        CommandBar_AddAdornments (hwndCB, 0, 0);

    }

    return 0;

}

//----------------------------------------------------------------------

// DoDestroyMain – 處理窗口銷燬(WM_DESTROY)消息函數.

//

LRESULT DoDestroyMain (HWND hWnd, UINT wMsg, WPARAM wParam,

                       LPARAM lParam) {

    PostQuitMessage (0);

    return 0;

}

 

5.gif

 

在編譯程序之前還需要做一些工作,當然這不是完全必須的,它是需要根據你的開發環境來進行的一系列設置工作,我的環境是,我需要編譯Pocket PC 2002下的,而且是中文的環境,因爲我裝了Pocket PC 2002 SDK的中文IMAGE。因此首先我需要改變Download directory,因爲中文的默認目錄已經不是/Windows/Start Menu,我個人習慣改爲My Documents,當然你也可以設成其他的你願意的目錄,不過要注意的是如果不使用/Windows/Start Menu(默認的目錄)你需要通過資源管理器來運行它。

6.gif

另外一個需要修改的地方是修改Project Setings對話框的資源選項卡,將語言選項設爲中文。如下圖:

7.gif

 

好了編譯執行,我們便完成了第一個WINCE程序,當我把它裝到我的568上時,運行成功後,心情和第一次編程序調試通過的感覺一樣。不過真正的收穫不再此,雖然這是一個非常簡單的程序,但是我們可以學到一些好的編程思路。下面纔是真正的開始,我們來“解剖”一下這個簡單的程序。

 

收穫一:全部程序代碼均依照匈牙利命名法,我們幾乎不用看註釋便可以知道代碼的作用。

收穫二:改變了我們一直使用的窗口過程函數用大量的Switch語句來分列窗口消息的方法。而採用把窗口過程分解成單個過程,每個過程處理一個特定的消息,餘下的窗口過程是一個代碼片段,這段代碼用來檢查是否編寫了對應的過程來處理消息,如果有就調用該過程,沒有則將消息傳遞給默認的窗口過程。這種結構的優勢是將消息處理分成獨立的塊,一是避免了所有的窗口過程的變量都混雜的出現在過程的頂部;二是便於理解,我們可以很清楚的理解處理特定消息的代碼,最重要的是這樣的結構便於代碼移植,每一個獨立的消息處理函數如果需要,都可以幾乎不用修改而直接拷貝過去用。我記不清在那裏看到過,如果一段代碼的功能有可能被重複使用超過三次,便應該將它進行封裝。函數也許是封裝代碼的最小形式。收穫三:從頭文件的消息句柄、結構定義和程序文件的全局消息映射,主窗口過程函數的消息映射表我們可以看到和一個簡單的框架,也許通過這些我們對MFC的消息映射機制理解有所幫助。

 

好了這次我們看了一個非常簡單的,但是我認爲是非常優美的WINCE應用程序代碼(好的代碼讀起來也是享受)。並且掌握了用eMbedded VC++編寫應用程序的一般步驟。很有收穫吧,不過我們還有很多的東西要學,別鬆勁,繼續努力吧,你和我都是。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章