65.9K
CodeProject 正在变化。 阅读更多。
Home

Pocket PC WTL 图片查看器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.80/5 (17投票s)

2004年12月13日

CPL

7分钟阅读

viewsIcon

179120

downloadIcon

557

正在使用的一些 WTL 类和函数:CAppWindow、CFullScreenFrame、CStdDialog、CF_DIB 剪贴板支持等等……

引言

ImageView 是一个用 WTL 编写的 PPC 应用程序。

WTL 7.1 开始,WTL 正式支持 PPC 2002 和 2003。这种支持在即将发布的 OpenSource WTL 7.5 版本中继续。然而,PPC 系统要求应用程序具有某些行为,这些行为不应包含在通用 WTL 类中。

ImageView 使用了 atlppc.h,这是一组有限的 PPC WTL 类和函数,已提交包含在 WTL 7.5 中。ImageView 使用了 CodeProject 中描述的类 CZoomScrollImpl将缩放添加到 WTL CScrollImpl

ImageViewPPC 项目、atlppc.hzoomscrl.h 使用 WTL 7.1 和当前的 7.5 分发版本,通过 EVC 3.0 到 4.2 和 PPC 2002/2003 SDK 进行编译。

背景

WTL 带有一个非常丰富的示例,BmpView,它在桌面和 Pocket PC 设备之间具有代码兼容性。通过 BmpZoom,我将其功能扩展到连续缩放。

João Paulo Figueira 提供了 PicView,一个适用于 PPC 2002 的优秀 MFC 图片查看器。

ImageView 受这两个模型的启发,旨在成为(如果可能的话)一个更好的图像查看器。

功能

ImageView

BmpZoom

PicView

缩放

连续 连续 整数步长

缩放 UI

菜单中的跟踪条,按键 菜单中的跟踪条 菜单按钮(放大 - 缩小)

表现良好

MFC 行为

图像属性页

剪贴板复制和粘贴

未完成

标题栏

全屏视图

点按和滚动

显示/隐藏滚动条

系统注册


PPC WTL 和函数

标准属性页和对话框

CStdPropertySheet

template <class T, bool t_bShowSip = true> 
class CStdPropertySheet : public CPropertySheetImpl<T>
类描述

标准的 PPC 属性页,带有标题、空菜单栏和 SIP,具体取决于 t_bShowSip

类用法

CStdPropertySheet 派生一个属性页类,如 ImageViewCImageProperties

// ImageViewdlg.h
//...
class CImageProperties : public CStdPropertySheet<CImageProperties, false>
{
public:
 CFilePage m_FilePage;
 CImagePage m_ImagePage;
 CViewPage m_ViewPage;
 CImageProperties( LPCTSTR sname, CImageViewView & rview) :
     m_FilePage(sname), m_ImagePage( rview.m_bmp), m_ViewPage( rview) 
 {
     SetTitle( rview.m_sImageName);
     if ( *sname )
         AddPage( m_FilePage);
     AddPage( m_ImagePage);
     AddPage( m_ViewPage);
 }
};

CStdDialog

template <class T, bool t_bModal = true> 
class CStdDialog
类描述

标准 PPC 对话框的基类,具有以下特性:

  • PPC 对话框标题显示和对话框标题准备例程
    //...
    // Title painting
     LRESULT OnPaintTitle(UINT /*uMsg*/, WPARAM /*wParam*/, 
                          LPARAM /*lParam*/, BOOL& bHandled)
    //...
     LRESULT OnInitStdDialog(UINT /*uMsg*/, WPARAM /*wParam*/, 
                             LPARAM /*lParam*/, BOOL& bHandled)
    // Title preparation: move the dialog controls down to make room for title
     void StdDialogTitleInit()
    // ...
  • 关闭命令处理程序,根据 t_bModal 的值调用 EndDialog( wID)DestroyWindow()
     //...
     // Standard dialog ending: may be used with any command
     LRESULT OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, 
                        HWND /*hWndCtl*/, BOOL& /*bHandled*/)
     //...
  • ID 为 IDC_INFOSTATIC // == IDC_STATIC -1 的静态控件的背景 COLOR_INFOBK 设置。
     //...
     // IDC_INFOSTATIC background setting
     LRESULT OnColorStatic(UINT /*uMsg*/, WPARAM wParam, 
                           LPARAM lParam, BOOL& bHandled)
     //...
类用法

CDialogImplCStdDialog 派生一个对话框类,并通过对话框类消息映射连接所需的功能。CStdDialogImpl 为所有功能完成了此操作。

///////////////////////////////////////////////////////////////////////////////
// CStdDialogImpl - implementation of standard PPC dialog

  
template <class T, bool t_bModal = true>  
class CStdDialogImpl : public CDialogImpl<T> , 
                       public CStdDialog<T, t_bModal>
{
public:
 BEGIN_MSG_MAP(CStdDialogImpl)
  MESSAGE_HANDLER(WM_PAINT, OnPaintTitle)
  MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorStatic)
  MESSAGE_HANDLER(WM_INITDIALOG, OnInitStdDialog)
  COMMAND_RANGE_HANDLER(IDOK, IDCANCEL, OnCloseCmd)
 END_MSG_MAP()
};

CStdDialogImpl

template <class T, bool t_bModal = true>
class CStdDialogImpl : public CDialogImpl<T> , public CStdDialog<T, t_bModal>
类描述

用于派生的标准 PPC 对话框实现。

类用法

CStdDialogImpl 派生一个对话框类,并像 ImageViewCMoveDlgCRegisterDlg 一样链接消息映射。

// ImageViewdlg.h
//... 
 
/////////////////////
// CMoveDlg :  Called by CRegisterDlg to move ImageView.exe to \Windows folder
 
class CMoveDlg : public  CStdDialogImpl<CMoveDlg>
{
public:
 CString m_sAppPath;
 CString m_sApp;
 
 enum { IDD = IDD_MOVE };
 
 BEGIN_MSG_MAP(CMoveDlg)
  MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
  COMMAND_HANDLER(IDC_MOVE, BN_CLICKED, OnMove)
  CHAIN_MSG_MAP(CStdDialogImpl<CMoveDlg>)
 END_MSG_MAP()
//...

CStdSimpleDialog

template< WORD t_wDlgTemplateID,
 UINT t_shidiFlags = SHIDIF_DONEBUTTON | SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN>
class CStdSimpleDialog :
 public CSimpleDialog< t_wDlgTemplateID, FALSE>,
 public CStdDialog< CStdSimpleDialog< t_wDlgTemplateID, t_shidiFlags> >
类描述

标准 CSimpleDialog(仅限模态)具有初始设置 t_shidiFlags,默认值为 CSimpleDialog 设置。

类用法

ImageView OnAppAbout 处理程序中实例化。

// mainfrm.h
//...


LRESULT OnAppAbout(WORD /*wNotifyCode*/, WORD /*wID*/, 
                   HWND /*hWndCtl*/, BOOL& /*bHandled*/)
 {
  CStdSimpleDialog<IDD_ABOUTBOX, 
               SHIDIF_DONEBUTTON | SHIDIF_FULLSCREENNOMENUBAR> dlg;
  return FSDoModal( dlg);
 }

//...


应用程序行为

CAppInfoBase

class CAppInfoBase
类描述

用于应用程序状态保存/恢复到注册表的帮助程序。在 HKEY_CURRENT_USER 下打开或创建一个 sAppKey 注册表项。SaveRestore 成员将程序变量传输到该项。

//...

class CAppInfoBase
{
public:
 CRegKey m_Key;

 CAppInfoBase( _U_STRINGorID sAppKey) 
 {
  m_Key.Create( HKEY_CURRENT_USER, sAppKey.m_lpstr);
  ATLASSERT( m_Key.m_hKey);
 }

 template< class V>
 LONG Save( V& val, _U_STRINGorID sName)
 {
  return ::RegSetValueEx( m_Key, sName.m_lpstr, 0, REG_BINARY, 
                         (LPBYTE) &val, sizeof(V));
 }

 template< class V>
 LONG Restore( V& val, _U_STRINGorID sName)
 {
  DWORD valtype;
  DWORD bufSize = sizeof(V);
  return ::RegQueryValueEx( m_Key, sName.m_lpstr, 0, &valtype, 
                           (LPBYTE)&val, &bufSize); 
 }
//...
类用法

如果需要保存/恢复嵌套变量,请从 CAppInfoBase 派生。CAppInfoBase 具有用于 CString 类型的专用 SaveRestore 成员。在您的派生类中添加其他所需的专用化。

//...
#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
 
 LONG Save( CString& sval, _U_STRINGorID sName)
 {
   return m_Key.SetValue( sval, sName.m_lpstr);
 }

 LONG Restore( CString& sval, _U_STRINGorID sName)
 {
  DWORD size = MAX_PATH;
  LONG res = m_Key.QueryValue( sval.GetBuffer( size), sName.m_lpstr, &size);
  sval.ReleaseBuffer();
  return res;
 }
//...

CAppInfoT

template < class T >
class CAppInfoT : public CAppInfoBase
类描述

CAppInfoBaseCAppWindow<T> 相关联。

template < class T >
class CAppInfoT : public CAppInfoBase
{
public:
 CAppInfoT() : CAppInfoBase( T::m_szAppKey){}
};
类用法

CAppWindow<T> 将其 CAppInfo 类型定义为 CAppInfoT<T>

//...
template <class T>
class CAppWindow
{
public:
 typedef class CAppInfoT<T> CAppInfo;
//...

CRegisterDlg::Register 中实例化 CAppInfoT

// ImageViewdlg.h
//...
class CRegisterDlg : public CStdDialogImpl<CRegisterDlg>
{
public:
//...
 void Register( ImageType typ, BOOL bRegister)
 {
  CAppInfoT<CMainFrame> info;
//...

CAppWindow

template <class T>
class CAppWindow
类描述

PPC 应用程序框架窗口的基类,具有以下特性:

  • 命令行参数传输到 OnCreate 处理程序和上一个实例
    //...
    template <class T>
    class CAppWindow
    {
    public:
    //...
    // Same as AppWizard generated Run + lpstrCmdLine in CreateEx
     static int AppRun(LPTSTR lpstrCmdLine = NULL, 
                       int nCmdShow = SW_SHOWNORMAL)
    //... 
    // Same as AppWizard generated ActivatePreviousInstance
    // + SendMessage WM_COPYDATA
     static HRESULT ActivatePreviousInstance(HINSTANCE hInstance, 
                                             LPCTSTR  lpstrCmdLine ) 
    //...
    // Operations overriden in derived class
     bool AppNewInstance( LPCTSTR lpstrCmdLine)
    //...
    // Message map and handlers
     MESSAGE_HANDLER( WM_COPYDATA, OnNewInstance)
    //...
     LRESULT OnNewInstance(UINT /*uMsg*/, WPARAM /*wParam*/, 
             LPARAM lParam, BOOL& /*bHandled*/)
     {
      T* pT = static_cast<T*>(this);
      PCOPYDATASTRUCT pcds = (PCOPYDATASTRUCT) lParam;
      return pT->AppNewInstance((LPCTSTR)pcds->lpData);
     }
    //...
  • WM_HIBERNATE 消息支持
    //...
    template <class T> 
    class CAppWindow 
    { 
    public: 
    //... 
     bool m_bHibernate;
    //... 
    // Operations overriden in derived class 
     bool AppHibernate( bool bHibernate) 
    //... 
    // Message map and handlers  
     MESSAGE_HANDLER( WM_HIBERNATE, OnHibernate) 
     MESSAGE_HANDLER( WM_ACTIVATE, OnActivate) 
    //... 
     LRESULT OnHibernate(UINT /*uMsg*/, WPARAM /*wParam*/, 
             LPARAM /*lParam*/, BOOL& /*bHandled*/) 
     {  
      T* pT = static_cast<T*>(this);  
      return m_bHibernate = pT->AppHibernate( true);  
     } 
    //... 
     LRESULT OnActivate(UINT uMsg, WPARAM wParam, 
             LPARAM lParam, BOOL& bHandled)  
     { 
      T* pT = static_cast<T*>(this);
      if ( m_bHibernate)
        m_bHibernate = pT->AppHibernate( false); 
    //...
  • 通过相关系统调用支持激活、停用和设置更改
    //...
    template <class T> 
    class CAppWindow 
    { 
    public: 
    //...
     SHACTIVATEINFO m_sai;
    //... 
    // Message map and handlers  
      MESSAGE_HANDLER( WM_ACTIVATE, OnActivate)
      MESSAGE_HANDLER( WM_SETTINGCHANGE, OnSettingChange)
    //... 
     LRESULT OnActivate(UINT uMsg, WPARAM wParam, 
                        LPARAM lParam, BOOL& bHandled)
     {
      T* pT = static_cast<T*>(this);
    //...
      return SHHandleWMActivate( pT->m_hWnd, wParam, lParam, &m_sai, 0);
     }
     LRESULT OnSettingChange(UINT uMsg, WPARAM wParam, 
                             LPARAM lParam, BOOL& bHandled)
     {
      T* pT = static_cast<T*>(this);
      bHandled = FALSE;
      return SHHandleWMSettingChange( pT->m_hWnd, wParam, lParam, &m_sai);
     }
    //...
  • 应用程序状态持久性支持。
    //...
    template <class T> 
    class CAppWindow 
    { 
    public: 
    //...
      typedef class CAppInfoT<T> CAppInfo;
    
      static LPCTSTR m_szAppKey;
    // Operations overriden in derived class
    //...  
     void AppSave() 
    //... 
    // Message map and handlers
       MESSAGE_HANDLER( WM_CLOSE, OnClose)
    //... 
     LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     {
      T* pT = static_cast<T*>(this);
      pT->AppSave();
      return bHandled = FALSE;
     }
    //...
类用法
  • 在您的 AppWizard 生成的应用程序 ::_tWinMain
    • 定义 LPCTSTR CMainFrame::m_szAppKey
    • 调用带两个参数的 CMainFrame::ActivatePreviousInstance
    • 将对 Run 的调用更改为 CMainFrame::AppRun,并且
    • 删除 Run 函数。
// ImageView.cpp
//...

LPCTSTR CMainFrame::m_szAppKey = L"Software\\CodeProject\\ImageView";

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, 
                     LPTSTR lpstrCmdLine, int nCmdShow)
{
 
 HRESULT hRes = CMainFrame::ActivatePreviousInstance(hInstance, lpstrCmdLine ); 
//...
 int nRet = CMainFrame::AppRun(lpstrCmdLine, nCmdShow);
//...
}
  • 在您的框架定义中
    • CAppWindow 添加到您的主窗口继承列表,
    • 链接消息映射,
    • 删除 ActivatePreviousInstance 成员定义,
    • 定义 AppHibernateAppNewInstanceAppSave 成员的全部或部分,
    • OnCreate 处理程序中处理命令行参数,和/或恢复应用程序状态和数据。
// mainfrm.h
//...

class CMainFrame : 
//...
  public CAppWindow<CMainFrame>
{
//...
// CAppWindow operations
 bool AppHibernate( bool bHibernate)
 {
  if ( bHibernate) // go to sleep
   if ( m_sFile.IsEmpty()) // clipboard or no image
    return false;
   else
    m_view.m_bmp.DeleteObject();  
  else // wake up 
   if ( HBITMAP hbm = LoadImageFile( m_sFile))
    m_view.m_bmp.Attach( hbm);
   else // file was moved or deleted during hibernation
    CloseImage();
  return bHibernate;
 }

 bool AppNewInstance( LPCTSTR lpstrCmdLine)
 {
  return SetImageFile( lpstrCmdLine) != NULL;
 }

 void AppSave()
 {
  CAppInfo info;
  BOOL bTitle = m_view.m_TitleBar.IsWindowVisible();
  info.Save( bTitle, L"TitleBar");
  info.Save( m_view.m_bShowScroll, L"ScrollBars");
  info.Save( m_bFullScreen, L"Full");
  info.Save( m_sFile, L"Image");
  info.Save( m_view.GetScrollOffset(), L"Scroll");
  info.Save( m_view.m_fzoom, L"Zoom");
 }
//...
// Message map and handlers
 BEGIN_MSG_MAP(CMainFrame)
//...
  CHAIN_MSG_MAP(CAppWindow<CMainFrame>)
//...
 LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, 
                  LPARAM lParam, BOOL& /*bHandled*/)
 {
  CAppInfo info;

  // Full screen delayed restoration 
  bool bFull = false;
  info.Restore( bFull, L"Full");
  if ( bFull)
   PostMessage( WM_COMMAND, ID_VIEW_TOOLBAR);
//...   
  // TitleBar creation
  BOOL bTitle = TRUE;
  info.Restore( bTitle, L"TitleBar");
  DWORD dwStyle = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_TOP;
  if ( bTitle)
   dwStyle |= WS_VISIBLE;
  CreateSimpleStatusBar( L"", dwStyle);
//...

  // Image initialization 

 
  LPCTSTR pCmdLine = (LPCTSTR)((LPCREATESTRUCT)lParam)->lpCreateParams;
  if ( *pCmdLine )// open the command line file
   SetImageFile( pCmdLine);
  else   // restore previous image if existing
  {
//...

帧大小和位置

AtlFixUpdateLayout

void AtlFixUpdateLayout( HWND hWndFrame, HWND hWndMenuBar)
函数描述

WTL 7.1 的框架定位修复(目前 7.5 仍然需要)。

函数用法
  • 如果您不使用 CFullScreenFrame,在您的 AppWizard 生成的 CMainFrame::OnCreate 中,在菜单栏创建后调用 AtlFixUpdateLayout
    //...
    
    LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, 
                     LPARAM /*lParam*/, BOOL& /*bHandled*/)
    {
       CreateSimpleCEMenuBar(IDR_MAINFRAME, SHCMBF_HMENU);
       AtlFixUpdateLayout( m_hWnd, m_hWndCECommandBar);
       //...
  • 如果您想使用 CFullScreenFrame,定义一个调用 AtlFixUpdateLayout,然后调用基类 UpdateLayoutUpdateLayout 成员。
    // ...
        void CMainFrame::UpdateLayout(BOOL bResizeBars = TRUE)
        {
        AtlFixUpdateLayout( m_hWnd, m_hWndCECommandBar);
        CFrameWindowImplBase<CMainFrame>::UpdateLayout( bResizeBars)
        }
    // ...

CFullScreenFrame

template < class T, bool t_bHasSip = true>
class CFullScreenFrame
类描述

启用全屏的框架窗口类

  • bool m_bFullScreen 保存当前状态;
  • void SetFullScreen( bool bFull) 设置请求的状态。
  • template <class D> int FSDoModal( D& dlg) 恢复任务栏(如果已隐藏),调用 dlg.DoModal(),隐藏任务栏(如果已恢复),并返回 dlg.DoModal() 的返回值。
类用法
  • 在您的框架定义中
    • 对于 WTL 7.1(以及目前的 7.5),定义一个调用 AtlFixUpdateLayout,然后调用基类 UpdateLayoutUpdateLayout 成员。
    • CFullScreenFrame 添加到您的主窗口继承列表,
    • 实现对 SetFullScreen 的调用,
    • 如果需要,检查 m_bFullScreen
    • 通过 FSDoModal 调用模态对话框和属性页。
// mainfrm.h
//...

class CMainFrame : 
//... 
  public CFullScreenFrame<CMainFrame, false>,
//...
{
//...

// CFrameWindowImplBase::UpdateLayout override
 void UpdateLayout(BOOL bResizeBars = TRUE)
 {

  CRect rectWnd, rectTool;
 
#if _WTL_VER <= 0x0710 || defined(_WTL_NO_PPC_FRAME_POSITION)
 
  AtlFixUpdateLayout( m_hWnd, m_hWndCECommandBar);
//...

 // Message map and handlers
 BEGIN_MSG_MAP(CMainFrame)
//...
  COMMAND_ID_HANDLER(ID_FILE_OPEN, OnFileOpen)
//...
  COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)
  COMMAND_ID_HANDLER(ID_FILE_REGISTER, OnRegister)
  COMMAND_ID_HANDLER(ID_VIEW_PROPERTIES, OnProperties)
//...
  COMMAND_ID_HANDLER(ID_VIEW_TOOLBAR, OnFullScreen)
//...

 
// File and image transfers
 LRESULT OnFileOpen(WORD /*wNotifyCode*/, WORD /*wID*/, 
                    HWND /*hWndCtl*/, BOOL& /*bHandled*/)
 {
//...
  CFileDialog dlg( TRUE, NULL, NULL, OFN_HIDEREADONLY | 
                  OFN_OVERWRITEPROMPT, sFiles);
 
 if( FSDoModal( dlg) == IDOK)
   SetImageFile( dlg.m_szFileName);
//...

// Dialogs and property sheet activation
 LRESULT OnAppAbout(WORD /*wNotifyCode*/, WORD /*wID*/, 
                    HWND /*hWndCtl*/, BOOL& /*bHandled*/)
 {
  CStdSimpleDialog<IDD_ABOUTBOX, 
             SHIDIF_DONEBUTTON | SHIDIF_FULLSCREENNOMENUBAR> dlg;
  return FSDoModal( dlg);
 }

 LRESULT OnRegister(WORD /*wNotifyCode*/, WORD /*wID*/, 
                    HWND /*hWndCtl*/, BOOL& /*bHandled*/)
 {
  CRegisterDlg dlg;
  return FSDoModal( dlg);
 }

 LRESULT OnProperties(WORD /*wNotifyCode*/, WORD /*wID*/, 
                      HWND /*hWndCtl*/, BOOL& /*bHandled*/)
 {
  CImageProperties prop( m_sFile, m_view);
  return FSDoModal( prop);
 }
//...

 LRESULT OnFullScreen(WORD /*wNotifyCode*/, WORD /*wID*/, 
                      HWND /*hWndCtl*/, BOOL& /*bHandled*/)
 {
  SetFullScreen( !m_bFullScreen );
  UISetCheck( ID_VIEW_TOOLBAR, m_bFullScreen);
  return TRUE;
 }
//...

DIB 支持

DIB 结构

  • struct DIBINFO16 创建大小为 16 位的 DIB 描述符,带有 BI_BITFIELDS

DIB 函数描述

  • HBITMAP AtlGetDibBitmap( LPBITMAPINFO pbmi) 从压缩的 DIB 构建一个 HBITMAP
  • HBITMAP AtlCopyBitmap( HBITMAP hbm , SIZE size, bool bAsBitmap = false)HBITMAP 复制到尺寸为 size 的压缩 DIBINFO16DDB,具体取决于 bAsBitmap
  • HLOCAL AtlCreatePackedDib16( HBITMAP hbm, SIZE size) 从给定的 HBITMAP 创建一个大小为 size 的压缩 DIBINFO16
  • bool AtlSetClipboardDib16( HBITMAP hbm, SIZE size, HWND hWnd) 将剪贴板 CF_DIB 格式设置为从 HBITMAP 复制的大小为 DIBINFO16
  • HBITMAP AtlGetClipboardDib( HWND hWnd) 从剪贴板 CF_DIB 格式返回一个 HBITMAP

DIB 函数用法

使用这组函数来支持 CF_DIB 剪贴板格式,PPC 中不支持进程间 CF_BITMAP 剪贴板对象。

// mainfrm.h
//...

// UpdateUI operations and map
 virtual BOOL OnIdle()
 {
  UIEnable( ID_EDIT_PASTE, IsClipboardFormatAvailable( CF_DIB));

//...
 BEGIN_UPDATE_UI_MAP(CMainFrame)
  UPDATE_ELEMENT(ID_EDIT_COPY, UPDUI_MENUPOPUP | UPDUI_TOOLBAR)
  UPDATE_ELEMENT(ID_EDIT_PASTE, UPDUI_MENUPOPUP | UPDUI_TOOLBAR)
//...
// Message map and handlers
 BEGIN_MSG_MAP(CMainFrame)
//...
  COMMAND_ID_HANDLER(ID_EDIT_PASTE, OnPaste)
//...
  CHAIN_MSG_MAP_ALT_MEMBER(m_view, 1)
//... 
 LRESULT OnPaste(WORD /*wNotifyCode*/, WORD /*wID*/, 
                 HWND /*hWndCtl*/, BOOL& /*bHandled*/)
 {
  if ( CBitmapHandle hbm = AtlGetClipboardDib( m_hWnd))
  {
   m_sFile.Empty();
   m_view.SetImage( hbm, L"pasted");
   UIEnable(ID_ZOOM, true);
   UIEnable(ID_FILE_CLOSE, true);
   UIEnable(ID_EDIT_COPY, true);
   UIEnable(ID_VIEW_PROPERTIES, true);
  }
  else
   AtlMessageBox( m_hWnd, L"Could not paste image from clipboard", 
                 IDR_MAINFRAME, MB_OK | MB_ICONERROR);
  return 0;
 }
//...
// ImageViewview.h
//...
// Message map and handlers

 BEGIN_MSG_MAP(CImageViewView)
//... 
 ALT_MSG_MAP( 1 ) // Forwarded by frame
//...
  COMMAND_ID_HANDLER(ID_EDIT_COPY, OnCopy)
//...
//  Clipboard copy 
 LRESULT OnCopy(WORD /*wNotifyCode*/, WORD /*wID*/, 
                HWND /*hWndCtl*/, BOOL& /*bHandled*/)
 {
  if ( !AtlSetClipboardDib16( m_bmp , m_sizeAll, m_hWnd))
   AtlMessageBox( m_hWnd, L"Could not copy image to clipboard", 
                 IDR_MAINFRAME, MB_OK | MB_ICONWARNING);
  return 0;
 }
//...

AtlCopyBitmapImageViewCImagePageCViewPage 中用于填充 CStatic 控件位图。

// ImageViewdlg.h
//...


class CImagePage : public CPropertyPageImpl<CImagePage>
{
//...
 CBitmapHandle m_bmp;
//...
 BEGIN_MSG_MAP(CImagePage)
  MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
//...
 LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, 
         LPARAM /*lParam*/, BOOL& /*bHandled*/)
 {
//...
  DIBSECTION ds;
  bool bOK = ::GetObject( m_bmp, sizeof(DIBSECTION), &ds) == sizeof(DIBSECTION);
//...
  CStatic sImg = GetDlgItem( IDC_IMAGE);
  CRect rectImg;
  sImg.GetWindowRect( rectImg);
  CSize sizeImg( ds.dsBmih.biWidth, ds.dsBmih.biHeight);
  double fzoom = max( (double)sizeImg.cx / rectImg.Width(),
      (double)sizeImg.cy / rectImg.Height());
  CBitmapHandle hbm = AtlCopyBitmap( m_bmp, sizeImg / fzoom, true);
  sImg.SetBitmap( hbm);
//...

ImageView 功能

连续缩放功能

CImageViewView 派生自 CZoomScrollImpl,后者实现了该功能。此类的完整描述在 CodeProject 中:将缩放添加到 WTL CScrollImpl

使用方向键和菜单栏中的跟踪条进行缩放的用户界面

此功能需要一些步骤

  • 在资源编辑器中创建一个 ID 为 ID_ZOOM 的菜单栏按钮
  • CImageViewView 中声明一个 CTrackbarCtrl 成员。
// ImageViewview.h
//...

class CImageViewView : 
 public CWindowImpl< CImageViewView > ,
 public CZoomScrollImpl< CImageViewView > 
{
public:
 DECLARE_WND_CLASS(NULL)

 CTrackBarCtrl m_ZoomCtrl;
//...
  • 子类化菜单栏以转发跟踪条消息
  • ID_ZOOM 按钮的位置创建 CImageViewView::m_ZoomCtrl
// mainframe.h
//... 
// Selective message forwarding macros

#define FORWARD_MSG(msg) if ( uMsg == msg ) \
 { lResult = ::SendMessage( GetParent(), uMsg, 
               wParam, lParam ); return bHandled = TRUE;}
#define FORWARD_NOTIFICATION_ID(uID) 
        if (( uMsg == WM_NOTIFY) && ( wParam == uID)) \
 { lResult = ::SendMessage( GetParent(), uMsg, wParam, lParam ); 
   return bHandled = TRUE;}
 

class CMainFrame :
//... 
{

 
// CZoomMenuBar: MenuBar forwarding trackbar messages
 
 class CZoomMenuBar : public CWindowImpl< CZoomMenuBar, 
                      CCECommandBarCtrlT<CToolBarCtrl> >
 {
 public:
  DECLARE_WND_SUPERCLASS( L"ZoomMenuBar", L"ToolbarWindow32");

  BEGIN_MSG_MAP(CZoomMenuBar)
   FORWARD_MSG(WM_HSCROLL)
   FORWARD_MSG(WM_CTLCOLORSTATIC)
   FORWARD_NOTIFICATION_ID(ID_ZOOM)
  END_MSG_MAP()
 };

// Data and declarations
public:
//...
 CZoomMenuBar m_MenuBar;
//...
// Creation and destruction
 LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, 
                  LPARAM lParam, BOOL& /*bHandled*/)
 {
//...
  // MenuBar creation
  CreateSimpleCEMenuBar( IDR_MAINFRAME, SHCMBF_HIDESIPBUTTON);
  m_MenuBar.SubclassWindow( m_hWndCECommandBar);
  m_MenuBar.LoadStdImages( IDB_STD_SMALL_COLOR);
  UIAddToolBar( m_hWndCECommandBar);
  
  // Trackbar creation
  CRect rZoom;
  m_MenuBar.GetRect( ID_ZOOM, rZoom);
  rZoom.top -= 1;
  m_view.m_ZoomCtrl.Create( m_hWndCECommandBar, rZoom, 
                   NULL ,WS_CHILD | TBS_TOP | TBS_FIXEDLENGTH, 0, 
   ID_ZOOM );
  m_view.m_ZoomCtrl.SetThumbLength( 9); 
  rZoom.DeflateRect( 1, 1);
  m_view.m_ZoomCtrl.SetWindowPos( HWND_TOP, rZoom.left, rZoom.top + 1, 
   rZoom.Width(), rZoom.Height(), SWP_SHOWWINDOW); 
  UIAddChildWindowContainer( m_hWndCECommandBar);
//...
  • 为当前图像设置跟踪条范围。
// ImageViewview.h
//...

// Image operation
 void SetImage( HBITMAP hBitmap, LPCTSTR sname = NULL, 
                double fZoom = 1.0, POINT pScroll = CPoint( -1,-1))
 {
  CSize sizeImage( 1, 1);
  m_bmp.Attach( hBitmap ); // will delete existing if necessary

  if( m_bmp.IsNull())
//...
  else
  {
//...
   m_bmp.GetSize( sizeImage);
//...
  }
//...
  // Set trackbar range and position
  sizeImage *= 100;
  CRect rect;
  SystemParametersInfo( SPI_GETWORKAREA, NULL, rect, FALSE);
  m_ZoomCtrl.SetRange( 100, max( sizeImage.cx / rect.Size().cx , 
                      sizeImage.cy / rect.Size().cy));
  m_ZoomCtrl.SetPageSize(100);
  m_ZoomCtrl.SetPos( (int)(100 * fZoom ));
 }
  • 管理跟踪条状态
    • 启用/禁用
// mainframe.h
//... 

class CMainFrame :
//... 
{
//...


// Data and declarations
public:
//...
 CZoomMenuBar m_MenuBar;
//...
// File and image operations
//...

 bool SetImageFile( LPCTSTR szFileName, double fZoom = 1.0 , 
                    POINT ptScroll= CPoint( -1, -1))
 {
  CBitmapHandle hBmp;
  if ( szFileName && *szFileName)
   hBmp = LoadImageFile( szFileName);
  bool bOK = !hBmp.IsNull();
//...
  UIEnable(ID_ZOOM, bOK);
//...
 } 

// UpdateUI operations and map
 virtual BOOL OnIdle()
 {
//...
  UIUpdateChildWindows();
//...
  }
  BEGIN_UPDATE_UI_MAP(CMainFrame)
//...
  UPDATE_ELEMENT(ID_ZOOM, UPDUI_CHILDWINDOW)
//...
// Creation and destruction
 LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, 
                  LPARAM lParam, BOOL& /*bHandled*/)
 {
//...
  
  // Trackbar creation
//...
  m_view.m_ZoomCtrl.Create( m_hWndCECommandBar, rZoom, 
                   NULL ,WS_CHILD | TBS_TOP | TBS_FIXEDLENGTH, 0, 
   ID_ZOOM );
//...
  UIAddChildWindowContainer( m_hWndCECommandBar);
//...
    • Frame
    • 背景
// ImageViewview.h
//...


// Image operation
 void SetImage( HBITMAP hBitmap, LPCTSTR sname = NULL, 
                double fZoom = 1.0, POINT pScroll = CPoint( -1,-1))
 {
  CSize sizeImage( 1, 1);
  m_bmp.Attach( hBitmap ); // will delete existing if necessary

  if( m_bmp.IsNull())
  {
   m_sImageName.Empty();
   m_ZoomCtrl.ModifyStyle( WS_BORDER, NULL, SWP_DRAWFRAME);
   m_TitleBar.SetText( 0, L"No image");
  }
  else
  {
   m_sImageName = sname;
   m_bmp.GetSize( sizeImage);
   m_ZoomCtrl.ModifyStyle( NULL, WS_BORDER, SWP_DRAWFRAME);
   m_TitleBar.SetText( 0, NULL, SBT_OWNERDRAW);
  }
//...
// Message map and handlers
 BEGIN_MSG_MAP(CImageViewView)
//...
 ALT_MSG_MAP( 1 ) // Forwarded by frame
  MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnZoomColor)
//...
//  Zoom trackbar interaction
 LRESULT OnZoomColor(UINT /*uMsg*/, WPARAM /*wParam*/, 
                     LPARAM /*lParam*/, BOOL& /*bHandled*/)
 {
  return (LRESULT)::GetSysColorBrush( m_bmp.IsNull() ? 
                   COLOR_BTNFACE : COLOR_BTNHIGHLIGHT );
 }
  • 将键盘消息转发到跟踪条
  • 在跟踪条移动时设置缩放
// ImageViewview.h
//...

// Message map and handlers
 BEGIN_MSG_MAP(CImageViewView)
 MESSAGE_RANGE_HANDLER( WM_KEYFIRST, WM_KEYLAST, OnKey)

//...
 ALT_MSG_MAP( 1 ) // Forwarded by frame
  MESSAGE_HANDLER(WM_HSCROLL, OnZoom)
//...
// Key translation and forwarding
 LRESULT OnKey(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
 {
  switch ( wParam )
  {
   case VK_UP : 
    wParam = VK_PRIOR;
    break;
   case VK_DOWN :
    wParam = VK_NEXT;
    break;
  }
  return m_ZoomCtrl.SendMessage( uMsg, wParam, lParam);
 }
//...
 
 LRESULT OnZoom(UINT /*uMsg*/, WPARAM wParam, 
                LPARAM /*lParam*/, BOOL& /*bHandled*/)
 {
  ATLASSERT( !m_bmp.IsNull());
  double fzoom;
 
  switch LOWORD(wParam)
  {
  case SB_THUMBTRACK :
  case SB_THUMBPOSITION :
   fzoom = (short int)HIWORD(wParam) / 100.0; 
   break;
  default : 
   fzoom = m_ZoomCtrl.GetPos() / 100.0;
  }
  if ( fzoom != m_fzoom)
  {
   SetZoom( fzoom);
   m_TitleBar.SetText( 0, NULL, SBT_OWNERDRAW);
  }
  return TRUE;
 }
//...

表现良好的系统交互

CMainFrame 派生自 CAppWindow,后者实现了该功能。请参阅 CAppWindow 类用法

图像属性页

CMainFrame 派生自 CStdPropertySheet(请参阅 类用法)并通过 FSDoModal 激活。

// mainfrm.h
//...

 LRESULT OnProperties(WORD /*wNotifyCode*/, WORD /*wID*/, 
                      HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  {
   CImageProperties prop( m_sFile, m_view);
   return FSDoModal( prop);
  }
//...

创建时会提供三个属性页的相关数据。

// ImageViewdlg.h
//...

/////////////////////
// CFilePage: Current image file propertes 

class CFilePage : public CPropertyPageImpl<CFilePage>
{
public:
 enum { IDD = IDD_PROP_FILE };

 CString m_sPath;

 CFilePage( LPCTSTR sPath) : m_sPath( sPath) { }
//...

/////////////////////
// CImagePage: Current image properties 

class CImagePage : public CPropertyPageImpl<CImagePage>
{
public:
 enum { IDD = IDD_PROP_IMAGE };
 CBitmapHandle m_bmp;

 CImagePage(HBITMAP hbmp) : m_bmp(hbmp) {}
//...

/////////////////////
// CViewPage: Current view properties 

class CViewPage : public CPropertyPageImpl<CViewPage>
{
 public:

 CImageViewView& m_rview;

 CViewPage( CImageViewView& rview) : m_rview( rview){}
//...

CImagePageCViewPage 使用 AtlCopyBitmap 显示图像的小副本。

剪贴板复制和粘贴

ImageView 直接使用 DIB 支持函数

可选标题栏

CImageViewview::m_TitleBar 是一个带有 CCS_TOP 样式的 CStatusBarCtrlCFrameWindowImplBase::UpdateLayout 目前忽略它。这在 CMainFrame::UpdateLayout 中处理。

标题栏可见性在 CMainFrame::AppSave 中保存并在创建时恢复。

//
//... 

class CImageViewView : 
 public CWindowImpl< CImageViewView > ,
 public CZoomScrollImpl< CImageViewView > 
{
public:
 DECLARE_WND_CLASS(NULL)

 CTrackBarCtrl m_ZoomCtrl;
 CStatusBarCtrl m_TitleBar;
//...
// mainfrm.h
//...

 
class CMainFrame : 
  public CFrameWindowImpl<CMainFrame,CWindow,CCeFrameTraits>, 
  public CUpdateUI<CMainFrame>,
  public CMessageFilter, public CIdleHandler, 
  public CFullScreenFrame<CMainFrame, false>,
  public CAppWindow<CMainFrame>
{
//... 

//#if _WTL_VER <= 0x0710 
// Uncomment when WTL supports CCS_TOP status bars ( see #1039656).


// CFrameWindowImplBase::UpdateLayout override
 void UpdateLayout(BOOL bResizeBars = TRUE)
 {
  CRect rectWnd, rectTool;
#if _WTL_VER <= 0x0710 || defined(_WTL_NO_PPC_FRAME_POSITION)
  AtlFixUpdateLayout( m_hWnd, m_hWndCECommandBar);
#else 
// No support of CCS_TOP status bar(#1039656)
// && AtlFixUpdateLayout not compiled
 
  // resize frame 
  ATLASSERT( m_MenuBar.IsWindow());
  GetWindowRect( rectWnd);
  m_MenuBar.GetWindowRect( rectTool); 
  int bottom = m_MenuBar.IsVisible() ? rectTool.top : rectTool.bottom;
  if ( bottom != rectWnd.bottom)
  { 
   rectWnd.bottom = bottom;
   MoveWindow( rectWnd, FALSE);
  }
#endif
  // resize title bar
  ATLASSERT( m_view.m_TitleBar.IsWindow());
  GetClientRect( rectWnd);
  if( m_view.m_TitleBar.GetStyle() & WS_VISIBLE)
  {
   if(bResizeBars)
    m_view.m_TitleBar.SendMessage( WM_SIZE);
   m_view.m_TitleBar.GetWindowRect( rectTool);
   rectWnd.top += rectTool.Size().cy;
  }
  // resize view
  ATLASSERT( m_view.IsWindow());
  m_view.GetWindowRect( rectTool);
  if ( rectTool != rectWnd)
   m_view.SetWindowPos( NULL, rectWnd, SWP_NOZORDER | SWP_NOACTIVATE);
 }
//#endif // _WTL_VER <= 0x0710
         // Uncomment when WTL supports
         // CCS_TOP status bars ( see #1039656).

 
// CAppWindow operations
 
 void AppSave()
 {
  CAppInfo info;
  BOOL bTitle = m_view.m_TitleBar.IsWindowVisible();
  info.Save( bTitle, L"TitleBar");
//...
 
 // Creation and destruction 
 LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, 
                  LPARAM lParam, BOOL& /*bHandled*/)
 {
//...
   // TitleBar creation
  BOOL bTitle = TRUE;
  info.Restore( bTitle, L"TitleBar");
  DWORD dwStyle = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_TOP;
  if ( bTitle)
   dwStyle |= WS_VISIBLE;
  CreateSimpleStatusBar( L"", dwStyle);
   m_view.m_TitleBar.Attach( m_hWndStatusBar);
  UISetCheck( ID_VIEW_STATUS_BAR, bTitle);
//...

当缩放或图像名称更改时,设置带有 SBT_OWNERDRAW 标志的文本会触发 CImageViewview::OnDrawTitle

// ImageViewview.h
//...


// Image operation
 

 
void SetImage( HBITMAP hBitmap, LPCTSTR sname = NULL, 
               double fZoom = 1.0, POINT pScroll = CPoint( -1,-1))
 {
  CSize sizeImage( 1, 1);
  m_bmp.Attach( hBitmap ); // will delete existing if necessary

  if( m_bmp.IsNull())
//...
   m_TitleBar.SetText( 0, L"No image");
  else
//...
   m_TitleBar.SetText( 0, NULL, SBT_OWNERDRAW);

//...

 

// Message map and handlers
 BEGIN_MSG_MAP(CImageViewView)
//...

 ALT_MSG_MAP( 1 ) // Forwarded by frame
//...
  MESSAGE_HANDLER(WM_HSCROLL, OnZoom)
  MESSAGE_HANDLER(WM_DRAWITEM, OnDrawTitle)
//...
 

////////////////////////////////////////////////////////////////
// ALT_MSG_MAP( 1 )  Handlers for forwarded messages
 
//  Title bar drawing
 LRESULT OnDrawTitle(UINT /*uMsg*/, WPARAM /*wParam*/, 
                     LPARAM lParam, BOOL& /*bHandled*/)
 {
  CDCHandle dc = ((LPDRAWITEMSTRUCT)lParam)->hDC;
  CRect rectTitle = ((LPDRAWITEMSTRUCT)lParam)->rcItem;
  dc.FillRect( rectTitle, AtlGetStockBrush( WHITE_BRUSH));
  rectTitle.DeflateRect( 2, 0);
  dc.SetTextColor( RGB( 0, 0, 156));
  CString sTitle = _T("Image: ") + m_sImageName;
  dc.DrawText( sTitle, -1, rectTitle, DT_LEFT | DT_SINGLELINE);
  sTitle.Format( _T("Zoom: %.2f"), GetZoom());
  dc.DrawText( sTitle, -1, rectTitle, DT_RIGHT | DT_SINGLELINE);
  return TRUE;
 }

 
//  Zoom trackbar interaction
//...
 LRESULT OnZoom(UINT /*uMsg*/, WPARAM wParam, 
                LPARAM /*lParam*/, BOOL& /*bHandled*/)
 {
  ATLASSERT( !m_bmp.IsNull());
  double fzoom;
//...

  if ( fzoom != m_fzoom)
  {
   SetZoom( fzoom);
   m_TitleBar.SetText( 0, NULL, SBT_OWNERDRAW);
  }

全屏视图

CMainFrame 派生自 CFullScreenFrame,后者实现了该功能。请参阅 CFullScreenFrame 类用法

点按和滚动图像移动

上次触控笔位置保存在 CImageViewView::m_ptMouse 中,并且视图偏移量在 WM_MOUSEMOVE 消息上更改。

// ImageViewview.h
//...

 
class CImageViewView : 
 public CWindowImpl< CImageViewView > ,
 public CZoomScrollImpl< CImageViewView > 
{
public:
//...

 

 CPoint m_ptMouse;
//... 

 

// Message map and handlers
 BEGIN_MSG_MAP(CImageViewView)
  MESSAGE_HANDLER(WM_SIZE, OnSize)
  MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
  MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
//...
 

// Stylus interaction: tap-and-scroll and context menu
 LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, 
                       LPARAM lParam, BOOL& /*bHandled*/)
 {
  m_ptMouse = CPoint( GET_X_LPARAM( lParam), GET_Y_LPARAM( lParam));
//...
 }

 
 LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM wParam, 
                     LPARAM lParam, BOOL& /*bHandled*/)
 {
  if ( 
#ifdef _X86_
    (wParam & MK_LBUTTON) && 
#endif // _X86_
    !m_bmp.IsNull())
  {
   CPoint ptNew( GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
   SetScrollOffset( GetScrollOffset() + 
                   (( m_ptMouse - ptNew) * GetZoom()));
   m_ptMouse = ptNew;
  }
  return 0;
 }
//...

可选滚动条

由于 Windows CE 不支持方便的 ::ShowScrollBar(),实现此功能需要一些工作:

  • 声明 CImageViewView::m_bShowScroll 以保存滚动条可见性。
  • 实现 CImageViewView::ShowScrollBars 函数和 CImageViewView::OnShowScrollBars 命令处理程序。
  • 覆盖 CZoomScrollImpl::SetScrollOffsetCZoomScrollImpl::SetZoom,这些函数由 CImageViewView 调用。
  • 覆盖 CZoomScrollImpl::OnSize 处理程序。
// ImageViewview.h
//...

 
class CImageViewView : 
 public CWindowImpl< CImageViewView > ,
 public CZoomScrollImpl< CImageViewView > 
{
public:
 
 bool m_bShowScroll;

 CImageViewView() : m_bShowScroll( true) {}
 
//...
 

// Show/hide scrollbars operation
 void ShowScrollBars( bool bShow)
 {
  m_bShowScroll = bShow;

  if (bShow)
  {
   SCROLLINFO si = { sizeof(si), SIF_PAGE | SIF_RANGE | SIF_POS};

   si.nMax = m_sizeAll.cx - 1;
   si.nPage = m_sizeClient.cx;
   si.nPos = m_ptOffset.x;
   SetScrollInfo(SB_HORZ, &si);

   si.nMax = m_sizeAll.cy - 1;
   si.nPage = m_sizeClient.cy;
   si.nPos = m_ptOffset.y;
   SetScrollInfo(SB_VERT, &si);
  }
  else
  {
   SCROLLINFO si = { sizeof(si), SIF_RANGE, 0, 0};

   SetScrollInfo(SB_HORZ, &si);
   SetScrollInfo(SB_VERT, &si);
  }
  Invalidate();
 }

// CZoomScrollImpl::SetScrollOffset  override for hidden scrollbars
 void SetScrollOffset( POINT ptOffset, BOOL bRedraw = TRUE )
 {
  if ( m_bShowScroll)
   CZoomScrollImpl<CImageViewView>::SetScrollOffset( ptOffset, bRedraw);
  else
  {
   AdjustOffset( CSize( ptOffset) / m_fzoom);
   if ( bRedraw)
    Invalidate();
  }
 }

// CZoomScrollImpl::SetZoom  override for hidden scrollbars
 void SetZoom( double fzoom, BOOL bRedraw = TRUE )
 {
  if ( m_bShowScroll)
   CZoomScrollImpl<CImageViewView>::SetZoom( fzoom, bRedraw);
  else
  {
   CPoint ptCenter = WndtoTrue( m_sizeClient / 2 );
   m_sizeAll = m_sizeTrue / fzoom;
   m_fzoom = fzoom;
   CPoint ptOffset= TruetoWnd(ptCenter) + m_ptOffset - m_sizeClient/ 2;
   AdjustOffset( ptOffset);
   if ( bRedraw)
    Invalidate();
  }
 }
 
//Implementation: hidden scrollbars helper
 void AdjustOffset( CPoint ptNew, bool bScroll = false)
 {
  CSize sizeMax = CSize( m_sizeAll) - m_sizeClient;
  int x = max ( min( ptNew.x, sizeMax.cx), 0 );
  int y = max ( min( ptNew.y, sizeMax.cy), 0 );

  CPoint ptOffset( x, y);

  if ( ptOffset != m_ptOffset)
  {
   if ( bScroll)
    ScrollWindowEx( m_ptOffset.x - x, m_ptOffset.y - y, m_uScrollFlags);
   m_ptOffset = ptOffset;
  }
 }

// Message map and handlers
 BEGIN_MSG_MAP(CImageViewView)
  MESSAGE_HANDLER(WM_SIZE, OnSize)

 ALT_MSG_MAP( 1 ) // Forwarded by frame
//...

  COMMAND_ID_HANDLER(ID_VIEW_SCROLLBARS, OnShowScrollBars)
//...
 

// CZoomScrollImpl::OnSize  override for hidden scrollbars
 LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, 
                LPARAM lParam, BOOL& bHandled)
 {
  if ( m_bShowScroll)
   bHandled = FALSE;
  else
  {
   m_sizeClient = CSize( GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
   AdjustOffset( m_ptOffset, true);
  }
  return bHandled;
 }
 
//  Scroll bars show-hide
 LRESULT OnShowScrollBars(WORD /*wNotifyCode*/, WORD /*wID*/, 
                         HWND /*hWndCtl*/, BOOL& /*bHandled*/)
 {
  ShowScrollBars( !m_bShowScroll);
  return TRUE;
 }
  • 实现滚动条可见性持久化
  • 更新菜单项检查
// mainfrm.h
//...

 
class CMainFrame :
///... 
{
//... 


// CAppWindow operations
 void AppSave()
 {
  CAppInfo info;
//...
  info.Save( m_view.m_bShowScroll, L"ScrollBars");
//...

// UpdateUI operations and map
//...
 
 BEGIN_UPDATE_UI_MAP(CMainFrame)
//...

  UPDATE_ELEMENT(ID_VIEW_SCROLLBARS, UPDUI_MENUPOPUP)
//...
 
// Message map and handlers
 BEGIN_MSG_MAP(CMainFrame)

//...

  COMMAND_ID_HANDLER(ID_VIEW_SCROLLBARS, OnScrollBars)
//...
 
// Creation and destruction
 LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, 
                 LPARAM lParam, BOOL& /*bHandled*/)
 {
  CAppInfo info;
//...

  // View creation
 
  info.Restore( m_view.m_bShowScroll, L"ScrollBars");
  m_hWndClient = m_view.Create(m_hWnd, rcDefault, NULL, 
                WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
  UISetCheck( ID_VIEW_SCROLLBARS, m_view.m_bShowScroll);
//...
 
// User interface settings
//...

 
 LRESULT OnScrollBars(WORD /*wNotifyCode*/, WORD /*wID*/, 
                     HWND /*hWndCtl*/, BOOL& bHandled)
 {
  UISetCheck( ID_VIEW_SCROLLBARS, !m_view.m_bShowScroll);
  return bHandled = FALSE; // real processing is in m_view
 }
//...

系统注册为图像文件默认程序

此功能由 CRegisterDlg 处理。

图像文件通过 HKEY_CLASSES_ROOT\xxxxxx\Shell\Open\Command 注册表项的默认字符串值与默认程序关联,其中 xxxxx 取决于文件类型。当用户点击文件名时,shell 会执行在那里找到的命令。但是,只执行位于 \Windows 的程序。

CRegisterDlg::InitDialog 检查当前的 ImageView 位置,如果位置不在 \Windows,则调用 CMoveDlg::DoModal

// ImageViewdlg.h
//...


/////////////////////
// CRegisterDlg: Register ImageView.exe
// as standard program for image files 

class CRegisterDlg : public CStdDialogImpl<CRegisterDlg>
{
public:

 enum { IDD = IDD_REGISTER };
 CString m_sAppPath;
 CString m_sApp;
//...
 
 BEGIN_MSG_MAP(CRegisterDlg)
  MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
//...
 
// Dialog initialization
 

 LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, 
                      LPARAM /*lParam*/, BOOL& bHandled)
 {
//...
 

  ::GetModuleFileName( NULL, m_sAppPath.GetBuffer( MAX_PATH + 1), MAX_PATH);
  m_sAppPath.ReleaseBuffer();
  m_sApp = m_sAppPath.Mid( m_sAppPath.ReverseFind(L'\\') + 1);
// Call CMoveDlg if ImageView.exe is not located in \Windows folder
 

  if( CString(L"\\Windows\\") + m_sApp != m_sAppPath)
  {
   CMoveDlg dlg;
   if ( dlg.DoModal() == IDCANCEL)
    EndDialog( IDCANCEL);

//...

CMoveDlg 如果用户允许,则移动 ImageView.exe,并根据请求在旧程序位置创建快捷方式。

// ImageViewdlg.h
//...

/////////////////////
// CMoveDlg : Called by CRegisterDlg to move ImageView.exe to \Windows folder



class CMoveDlg : public  CStdDialogImpl<CMoveDlg>
{
public:
 CString m_sAppPath;
 CString m_sApp;

 enum { IDD = IDD_MOVE };

 BEGIN_MSG_MAP(CMoveDlg)
  MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
  COMMAND_HANDLER(IDC_MOVE, BN_CLICKED, OnMove)
  CHAIN_MSG_MAP(CStdDialogImpl<CMoveDlg>)
 END_MSG_MAP()
  
// Dialog initialization
 LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, 
                      LPARAM /*lParam*/, BOOL& bHandled)
 {
  SHINITDLGINFO shidi = { SHIDIM_FLAGS, m_hWnd, SHIDIF_FULLSCREENNOMENUBAR};
  SHInitDialog( &shidi);
  SHDoneButton( m_hWnd, SHDB_HIDE);

  GetModuleFileName( NULL, m_sAppPath.GetBuffer(MAX_PATH+1), MAX_PATH);
  m_sAppPath.ReleaseBuffer();

  SetDlgItemText( IDC_FILELOCATION, m_sAppPath);
  m_sApp = m_sAppPath.Mid( m_sAppPath.ReverseFind(L'\\') + 1);
  
  CheckDlgButton( IDC_SHORTCUT, TRUE);

  return bHandled=FALSE;
 // to prevent CDialogImplBaseT< TBase >::DialogProc settings
 }

// Move operation
 LRESULT OnMove(WORD /*wNotifyCode*/, WORD /*wID*/, 
                HWND /*hWndCtl*/, BOOL& /*bHandled*/)
 {
  CString sDest = L"\\Windows\\" + m_sApp;
  if ( ::MoveFile( m_sAppPath, sDest))
  {
   if ( IsDlgButtonChecked( IDC_SHORTCUT))
   {
    m_sAppPath.Replace( L".exe", L".lnk");
    if ( !::SHCreateShortcut( (LPTSTR)(LPCTSTR)m_sAppPath, 
                            (LPTSTR)(LPCTSTR)sDest))
     AtlMessageBox( m_hWnd, L"Cannot create shortcut to ImageView.", 
      IDR_MAINFRAME, MB_OK | MB_ICONWARNING);
   }
   EndDialog(IDOK);
  }
  else
   AtlMessageBox( m_hWnd, L"Cannot move ImageView.exe to \\Windows\\ folder.", 
    IDR_MAINFRAME, MB_OK | MB_ICONERROR);
  return 0;
 }
};

IDOK 返回时,或者如果 ImageView 位置正确,CRegisterDlg::InitDialog 初始化图像文件类型的注册状态。一个帮助类 CImageTypeKey : public CRegKey 提供注册表访问。

// ImageViewdlg.h
//...

class CRegisterDlg : public CStdDialogImpl<CRegisterDlg>
{
public:
//...
 


// Image type enumeration
 
 enum ImageType { BMP = IDC_BMP, JPG, PNG, GIF } ;
 

// Implementation
// Helper class: image command registry key
 class CImageTypeKey : public CRegKey
 {
 public:
  CString m_sCmd;
  DWORD size;

  CImageTypeKey( ImageType typ) : size( MAX_PATH)
  {
   CString sKey = GetTypeString( typ);
   sKey += L"\\Shell\\Open\\Command";
   Open( HKEY_CLASSES_ROOT, sKey);
  }

  LPCTSTR GetTypeString( ImageType typ)
  {
   switch ( typ)
   {
   case BMP : return L"bmpimage"; 
   case JPG : return L"jpegimage"; 
   case PNG : return L"pngimage"; 
   case GIF : return L"gifimage"; 
   default : ATLASSERT( FALSE); return NULL;
   }
  }

  LPCTSTR GetCmd()
  {
   QueryValue( m_sCmd.GetBuffer( size), L"", &size);
   m_sCmd.ReleaseBuffer();
   return m_sCmd;
  }

  void SetCmd(LPCTSTR sCmd)
  {
   SetValue( sCmd, L"");
  }
 };

// Image type file extension
  LPCTSTR GetExtString( ImageType typ)
 {
  switch ( typ)
  {
  case BMP : return L".bmp"; ;
  case JPG : return L".jpg"; 
  case PNG : return L".png"; 
  case GIF : return L".gif"; 
  default : ATLASSERT( FALSE); return NULL;
  }
 }

// Image type registration status
 bool IsRegistered( ImageType typ)
 {
  CImageTypeKey key( typ);
  CString sCmd = key.GetCmd();
  return sCmd.Find( m_sApp) != -1 ;  
 }
//... 
 
 BEGIN_MSG_MAP(CRegisterDlg)
  MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
//...
 
// Dialog initialization
 LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, 
                      LPARAM /*lParam*/, BOOL& bHandled)
 {
//...
 
// Call CMoveDlg if ImageView.exe is not located in \Windows folder
  if( CString(L"\\Windows\\") + m_sApp != m_sAppPath)
  {
   CMoveDlg dlg;
   if ( dlg.DoModal() == IDCANCEL)
    EndDialog( IDCANCEL);
 
   ::GetModuleFileName( NULL, m_sAppPath.GetBuffer( MAX_PATH + 1), MAX_PATH);
   m_sAppPath.ReleaseBuffer();
  }
 
 // Controls initialization: IDC_BMP, IDC_JPG etc... MUST be in sequence.
  for( int iBtn = IDC_BMP, iIcon = IDC_IBMP ; 
      iBtn <= IDC_GIF ; iBtn++, iIcon++)
  {
   SHFILEINFO sfi;
   ::SHGetFileInfo( GetExtString( (ImageType)iBtn), 
                   FILE_ATTRIBUTE_NORMAL, &sfi, sizeof(sfi), 
    SHGFI_USEFILEATTRIBUTES | SHGFI_ICON | SHGFI_TYPENAME );
   SendDlgItemMessage( iIcon, STM_SETIMAGE, IMAGE_ICON, (LPARAM)sfi.hIcon);
   SetDlgItemText( iBtn, sfi.szTypeName);
   CheckDlgButton( iBtn, IsRegistered( (ImageType)iBtn));
  }
 
 return bHandled = FALSE;
 // to prevent CDialogImplBaseT< TBase >::DialogProc settings
 }

CRegisterDlg::Register 使用 CAppInfoT<CMainFrame> 在注册时保存现有键,并在注销时恢复它。

// ImageViewdlg.h
//...



// Image type registration-deregistration
 void Register( ImageType typ, BOOL bRegister)
 {
  CImageTypeKey key( typ);
  CString sOldCmd = key.GetCmd();
  CString sNewCmd = m_sAppPath;
  CAppInfoT<CMainFrame> info;

  if ( bRegister)
   sNewCmd += L" %1";
  else
   info.Restore( sNewCmd, key.GetTypeString( typ));
  
  key.SetCmd( sNewCmd);
  
  if ( bRegister)
   info.Save( sOldCmd, key.GetTypeString( typ));
  else 
   info.Delete( key.GetTypeString( typ));
 }
 
 BEGIN_MSG_MAP(CRegisterDlg)
  MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
  COMMAND_RANGE_HANDLER(IDC_BMP, IDC_GIF, OnCheckType)
  CHAIN_MSG_MAP(CStdDialogImpl<CRegisterDlg>)
 END_MSG_MAP()

//...
 


// Operation
 LRESULT OnCheckType(WORD /*wNotifyCode*/, WORD wID, 
                     HWND /*hWndCtl*/, BOOL& /*bHandled*/)
 {
  Register( (ImageType)wID, IsDlgButtonChecked( wID));
  return 0;
 }

结论

通过 WTL 7.1 或 7.5 以及 atlppc.h 中有限的 PPC 特定类和函数集,您(和我)可以轻松编写出色的真实 Pocket PC 应用程序。

© . All rights reserved.