现在的位置: 首页 > 综合 > 正文

WM6SDK例子学习笔记(一)

2013年04月18日 ⁄ 综合 ⁄ 共 12512字 ⁄ 字号 评论关闭
    在WM6 SDK的通用例子中有一个basicapp的例子。运行的效果就是在WM上出现一个窗口,显示一幅图片,下面左软按键可以切换图片。例子的功能很简单,作为入门学习很好。
    下面,我按照自己的理解将这个例子详细分析。
    这个例子属于Native的方式,其含义是基本使用的是API编程,而不是基于其他框架开发。也可以叫做“原生态”开发方式。因此有自己的特殊宏定义:
  1. #define WIN32_LEAN_AND_MEAN

    接下来就是包含的头文件声明:

  1. #include <windows.h>
  2. #include <aygshell.h>
  3. #include "resource.h"

    第一个头文件很好理解,是为了处理基本类型及基本操作而用到,第三个头文件则包含的是一些资源相关的定义。第二个头文件需要好好了解一下用途。这里暂且跳过,不表。

    下面定义了一个用于处理计算数组元素个数的宏:

  1. #define ARRAYSIZE(a) (UINT_PTR)(sizeof(a)/sizeof((a)[0]))

    紧接着是应用的名称说明:

  1. static const TCHAR g_szClassName[] = TEXT("ClassName");

    后面是函数声明和全局变量:

  1. // function declarations
  2. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd);
  3. HANDLE FindPrevInstance();
  4. HWND CreateMainWindow(int nShowCmd);
  5. BOOL OnCreateMainWindow(HWND hwnd);
  6. void PaintMainWindow(HWND hwnd);
  7. LRESULT CALLBACK MainWindowProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp);
  8. HBITMAP LoadPaintImage(LPTSTR pszLabel, UINT_PTR cchLabel);
  9. HFONT LoadPaintFont();
  10. void FreePaintImage();
  11. void FreePaintFont();
  12. // global variables
  13. HINSTANCE g_hInstance;
  14. HBITMAP   g_hBitmapPaint = NULL;
  15. HFONT     g_hFontPaint = NULL;
  16. DWORD     g_dwFontSize;
  17. DWORD     g_dwCurrentImage = 0;
  18. UINT      g_uMsgMetricChange = RegisterWindowMessage(SH_UIMETRIC_CHANGE);

    好戏要开始了。
    首先是程序的主函数,即程序的入口。如果是基于MFC、ATL或者是C#开发的话,一般是看不到这个冬冬的。这个是专门留给操作系统调用的。

  1. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd)
  2. {
  3.     HANDLE hEvent;
  4.     HWND   hwnd;
  5.     MSG    msg;
  6.     // Save the instance handle so we can access it later
  7.     g_hInstance = hInstance;
  8.     // Check to see if this application is already running
  9.     hEvent = FindPrevInstance();
  10.     if (hEvent == NULL)
  11.     {
  12.         // We found another instance
  13.         return -1;
  14.     }
  15.     // Create our main application window
  16.     hwnd = CreateMainWindow(nShowCmd);
  17.     if (hwnd == NULL)
  18.     {
  19.         // Failed to initialize
  20.         CloseHandle(hEvent);
  21.         return GetLastError();
  22.     }
  23.     // Run the message loop (note that GetMessage() returns -1 for error)
  24.     while (GetMessage(&msg, NULL, 0, 0) > 0)
  25.     {
  26.         TranslateMessage(&msg);
  27.         DispatchMessage(&msg);
  28.     }
  29.     // Clean up
  30.     FreePaintImage();
  31.     FreePaintFont();
  32.     // This is the value we passed to PostQuitMessage()
  33.     CloseHandle(hEvent);
  34.     return msg.wParam;
  35. }

    代码本身的注释应该算比较详细了。简单说明一下。先是判断一下该程序是否已经有一个在运行,如果有,则不再运行。这是为了保证该应用在一台设备上一次只能运行一个。如果你做的程序有需要可以同时运行多个的话,就不要加上这样的处理。个人建议,为了安全有效,还是做这样的限制吧。然后用CreateMainWindow(nShowCmd)来注册窗口,并创建该窗口。接下来的while循环用来处理消息。如果你看过windows SDK的资料应该不会陌生。FreePaintImage()和FreePaintFont()是用来施放已分配的资源。最后关闭句柄,返回消息参数。主流程就是这些,后面说明具体每个部分。
    先说明保证同时只有一个该应用运行的部分:

  1. HANDLE FindPrevInstance()
  2. {
  3.     HANDLE hEvent;
  4.     HWND   hwnd;
  5.     UINT   cTries = 0;
  6.     // Create a named event
  7.     hEvent = CreateEvent(NULL, TRUE, FALSE, g_szClassName);
  8.     if (hEvent != NULL)
  9.     {
  10.         // If the event already existed, that means there's another copy of our app
  11.         // already running
  12.         if (GetLastError() == ERROR_ALREADY_EXISTS)
  13.         {
  14.             do
  15.             {
  16.                 // Just in case the other window needs to finish initialization
  17.                 Sleep(cTries ? 250 : 0);
  18.                 // Try to find the other application window
  19.                 hwnd = FindWindow(g_szClassName, NULL);
  20.                 if (hwnd != NULL)
  21.                 {
  22.                     SetForegroundWindow((HWND)((UINT_PTR)hwnd | 0x01));
  23.                     CloseHandle(hEvent);
  24.                     return NULL;
  25.                 }
  26.             }
  27.             while (++cTries < 2);  // only try twice
  28.             // If we didn't find the window, the other application was probably
  29.             // shutting down, so we'll just continue
  30.         }
  31.     }
  32.     // Done
  33.     return hEvent;
  34. }

里面判断了两次,如果两次都找到该应用的另一个实例才退出。SetForegroundWindow是为了将已经运行的该应用实例窗口切换到前台,并激活该窗口。

    后面注册并创建主窗口:

  1. HWND CreateMainWindow(int nShowCmd)
  2. {
  3.     WNDCLASS wc;
  4.     ATOM     atm;
  5.     TCHAR    szTitle[128];
  6.     HWND     hwnd;
  7.     // Set up the window class description
  8.     ZeroMemory(&wc, sizeof(wc));
  9.     wc.lpfnWndProc = MainWindowProc;    // 设置该窗口的回调函数,用于处理消息
  10.     wc.hInstance = g_hInstance;
  11.     wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  12.     wc.lpszClassName = g_szClassName;
  13.     // We want to redraw the window contents anytime we get resized. That way
  14.     // we'll respond appropriately when the user switches between portrait and
  15.     // landscape. If we had any child windows or controls, we'd need to
  16.     // reposition or resize them when we get a WM_SIZE message.
  17.     wc.style = CS_HREDRAW | CS_VREDRAW;
  18.     // Register the window class
  19.     atm = RegisterClass(&wc);      // 注册窗口类
  20.     if (atm == 0)
  21.     {
  22.         // Failed!!
  23.         return NULL;
  24.     }
  25.     // Load the window title string resource
  26.     if (!LoadString(g_hInstance, IDS_APPTITLE, szTitle, ARRAYSIZE(szTitle)))
  27.     {
  28.         // Failed!!
  29.         return NULL;
  30.     }
  31.     // Create a window using the class we just registered. Note that the
  32.     // initial size and position don't matter, because we're going to make it
  33.     // fullscreen when we get WM_CREATE, before it's ever displayed.
  34.     hwnd = CreateWindow((LPCTSTR)atm, szTitle, WS_OVERLAPPED | WS_SYSMENU,
  35.         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  36.         NULL, NULL, g_hInstance, NULL);
  37.     if (hwnd == NULL)
  38.     {
  39.         // Failed!!
  40.         return NULL;
  41.     }
  42.     // Make the window visible and paint before returning
  43.     ShowWindow(hwnd, nShowCmd);
  44.     UpdateWindow(hwnd);
  45.     return hwnd;
  46. }

    下面设置窗口类型和风格:

  1. BOOL OnCreateMainWindow(HWND hwnd)
  2. {
  3.     SHMENUBARINFO shmbi;
  4.     SHINITDLGINFO shidi;
  5.     // Create our softkey bar
  6.     ZeroMemory(&shmbi, sizeof(shmbi));
  7.     shmbi.cbSize = sizeof(shmbi);
  8.     shmbi.hwndParent = hwnd;
  9.     shmbi.dwFlags = SHCMBF_HMENU;
  10.     shmbi.nToolBarId = IDM_MAIN;
  11.     shmbi.hInstRes = g_hInstance;
  12.     if (!SHCreateMenuBar(&shmbi))
  13.     {
  14.         // Failed!!
  15.         return FALSE;
  16.     }
  17.     // Windows Mobile applications should always display their main window
  18.     // full-screen. We're going to let the OS do this for us by calling
  19.     // SHInitDialog, even though technically this window isn't a dialog window.
  20.     shidi.dwMask = SHIDIM_FLAGS;
  21.     shidi.hDlg = hwnd;
  22.     shidi.dwFlags = SHIDIF_SIZEDLGFULLSCREEN | SHIDIF_SIPDOWN;
  23.     if (!SHInitDialog(&shidi))
  24.     {
  25.         // Failed!!
  26.         return FALSE;
  27.     }
  28.     // Get the current user preference for text size
  29.     SHGetUIMetrics(SHUIM_FONTSIZE_PIXEL,
  30.         &g_dwFontSize, sizeof(g_dwFontSize), NULL);
  31.     // Success
  32.     return TRUE;
  33. }

    接着绘制该窗口(设置字体,加载图片等):

  1. void PaintMainWindow(HWND hwnd)
  2. {
  3.     PAINTSTRUCT ps;
  4.     int         nSavedDC;
  5.     HBITMAP     hBitmap, hOldBitmap;
  6.     TCHAR       szLabel[64];
  7.     HFONT       hFont;
  8.     RECT        rect;
  9.     BITMAP      bm;
  10.     int         cy;
  11.     HDC         hMemDC;
  12.     // Start the paint operation
  13.     if (!GetUpdateRect(hwnd, NULL, FALSE) ||
  14.         BeginPaint(hwnd, &ps) == NULL)
  15.     {
  16.         return;
  17.     }
  18.     // Load the correct image and get its label
  19.     hBitmap = LoadPaintImage(szLabel, ARRAYSIZE(szLabel));
  20.     if (hBitmap != NULL)
  21.     {
  22.         // Load the display font
  23.         hFont = LoadPaintFont();
  24.         if (hFont != NULL)
  25.         {
  26.             // Save the device context state
  27.             nSavedDC = SaveDC(ps.hdc);
  28.             // Calculate the height of our display image and text
  29.             GetObject(hBitmap, sizeof(bm), &bm);
  30.             cy = bm.bmHeight;
  31.             SelectObject(ps.hdc, hFont);
  32.             GetClientRect(hwnd, &rect);
  33.             cy += DrawText(ps.hdc, szLabel, -1, &rect,
  34.                 DT_CALCRECT | DT_CENTER | DT_NOPREFIX | DT_WORDBREAK);
  35.             // Draw the image
  36.             GetClientRect(hwnd, &rect);
  37.             hMemDC = CreateCompatibleDC(ps.hdc);
  38.             if (hMemDC != NULL)
  39.             {
  40.                 hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap);
  41.                 BitBlt(ps.hdc, (rect.right - bm.bmWidth) / 2,
  42.                     (rect.bottom - cy) / 2, bm.bmWidth, bm.bmHeight,
  43.                     hMemDC, 0, 0, SRCCOPY);
  44.                 SelectObject(hMemDC, hOldBitmap);
  45.                 DeleteDC(hMemDC);
  46.             }
  47.             // Draw the text
  48.             rect.top = (rect.bottom - cy) / 2 + bm.bmHeight;
  49.             DrawText(ps.hdc, szLabel, -1, &rect,
  50.                 DT_CENTER | DT_NOPREFIX | DT_WORDBREAK);
  51.             // Restore the device context
  52.             RestoreDC(ps.hdc, nSavedDC);
  53.         }
  54.     }
  55.     // Always need to finish!!
  56.     EndPaint(hwnd, &ps);
  57. }

        消息处理的回调函数:

  1. LRESULT CALLBACK MainWindowProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
  2. {
  3.     static SHACTIVATEINFO sai;
  4.     switch (msg)
  5.     {
  6.     case WM_CREATE:
  7.         // Initialize the static window state information. The shell helper functions
  8.         // will use this buffer to store their state.
  9.         ZeroMemory(&sai, sizeof(sai));
  10.         sai.cbSize = sizeof(sai);
  11.         // Initialize the window (if we fail, return -1)
  12.         return (OnCreateMainWindow(hwnd) ? 0 : -1);
  13.     case WM_ACTIVATE:
  14.         // Calling this function when we get WM_ACTIVATE ensures that our
  15.         // application will handle the SIP properly. This function does
  16.         // nothing when we're running on Smartphone.
  17.         SHHandleWMActivate(hwnd, wp, lp, &sai, 0);
  18.         break;
  19.     case WM_SETTINGCHANGE:
  20.         // This helper function will resize our main application window when the SIP
  21.         // goes up and down. Try commenting out this function and see how it affects
  22.         // our drawing code. This function is optional, so choose whichever behavior
  23.         // you prefer. Again, this function does nothing on Smartphone.
  24.         SHHandleWMSettingChange(hwnd, wp, lp, &sai);
  25.         break;
  26.     case WM_HIBERNATE:
  27.         // We get this message when the device is running low on memory. All
  28.         // applications should free any memory and resources that they can. We'll
  29.         // free our cached bitmap and font, since we can just re-create them the next
  30.         // time we need them.
  31.         FreePaintImage();
  32.         FreePaintFont();
  33.         return TRUE;
  34.     case WM_COMMAND:
  35.         if (LOWORD(wp) == ID_SWITCH)
  36.         {
  37.             // Switch to our next image
  38.             g_dwCurrentImage = !g_dwCurrentImage;
  39.             FreePaintImage();
  40.             InvalidateRect(hwnd, NULL, TRUE);
  41.         }
  42.         break;
  43.     case WM_KEYDOWN:
  44.         // Allow Ctrl+Q to quit the application. Most users won't ever see
  45.         // this, but it's handy for debugging.
  46.         if (wp == 'Q' &&
  47.             GetKeyState(VK_CONTROL) < 0)
  48.         {
  49.             SendMessage(hwnd, WM_CLOSE, 0, 0);
  50.         }
  51.         break;
  52.     case WM_PAINT:
  53.         PaintMainWindow(hwnd);
  54.         return 0;
  55.     case WM_DESTROY:
  56.         // When this window is destroyed, it's time to quit the application
  57.         PostQuitMessage(0);
  58.         break;
  59.     }
  60.     if (msg == g_uMsgMetricChange)
  61.     {
  62.         DWORD dwFontSize;
  63.         // The UI metrics have changed. This is how we get notified when the
  64.         // user changes their preferred font size (PPC only). We free our
  65.         // cached font and save the new size for the next time we paint.
  66.         if (SUCCEEDED(SHGetUIMetrics(SHUIM_FONTSIZE_PIXEL,
  67.             &dwFontSize, sizeof(dwFontSize), NULL)) &&
  68.             dwFontSize != g_dwFontSize)
  69.         {
  70.             g_dwFontSize = dwFontSize;
  71.             FreePaintFont();
  72.             InvalidateRect(hwnd, NULL, TRUE);
  73.         }
  74.     }
  75.     return DefWindowProc(hwnd, msg, wp, lp);
  76. }

    加载图片的函数:

  1. HBITMAP LoadPaintImage(LPTSTR pszLabel, UINT_PTR cchLabel)
  2. {
  3.     // Load the current label string
  4.     pszLabel[0] = 0;
  5.     LoadString(g_hInstance, IDS_LABEL1 + g_dwCurrentImage,
  6.         pszLabel, cchLabel);
  7.     // Load the current image
  8.     if (g_hBitmapPaint == NULL)
  9.     {
  10.         // Note that the resource type must be "GIF", but actually the resource
  11.         // data can contain a BMP, GIF, JPG, or PNG image. This enables us to
  12.         // pick the best image format for our purposes (quality, size, etc).
  13.         g_hBitmapPaint = SHLoadImageResource(g_hInstance,
  14.             IDR_IMAGE1 + g_dwCurrentImage);
  15.     }
  16.     // Return the cached image handle
  17.     return g_hBitmapPaint;
  18. }

    加载字体的函数:

  1. HFONT LoadPaintFont()
  2. {
  3.     LOGFONT lf;
  4.     if (g_hFontPaint == NULL)
  5.     {
  6.         // Create the font handle
  7.         ZeroMemory(&lf, sizeof(lf));
  8.         lf.lfHeight = -(LONG)g_dwFontSize;
  9.         lf.lfWeight = FW_NORMAL;
  10.         lf.lfCharSet = DEFAULT_CHARSET;
  11.         lf.lfPitchAndFamily = VARIABLE_PITCH | FF_SWISS;
  12.         g_hFontPaint = CreateFontIndirect(&lf);
  13.     }
  14.     // Return the cached font handle
  15.     return g_hFontPaint;
  16. }

    最后别忘了,释放图片和释放字体资源:

  1. void FreePaintImage()
  2. {
  3.     if (g_hBitmapPaint != NULL)
  4.     {
  5.         DeleteObject(g_hBitmapPaint);
  6.         g_hBitmapPaint = NULL;
  7.     }
  8. }
  9. void FreePaintFont()
  10. {
  11.     if (g_hFontPaint != NULL)
  12.     {
  13.         DeleteObject(g_hFontPaint);
  14.         g_hFontPaint = NULL;
  15.     }
  16. }

抱歉!评论已关闭.