WM6SDK例子学习笔记(一)(zhuan)

在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. }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值