Pocket PC WTL 图片查看器






4.80/5 (17投票s)
正在使用的一些 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.h 和 zoomscrl.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
派生一个属性页类,如 ImageView 的 CImageProperties
。
// 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) //...
类用法
从 CDialogImpl
和 CStdDialog
派生一个对话框类,并通过对话框类消息映射连接所需的功能。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
派生一个对话框类,并像 ImageView 的 CMoveDlg
和 CRegisterDlg
一样链接消息映射。
// 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
注册表项。Save
和 Restore
成员将程序变量传输到该项。
//... 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
类型的专用 Save
和 Restore
成员。在您的派生类中添加其他所需的专用化。
//... #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
类描述
CAppInfoBase
与 CAppWindow<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
成员定义, - 定义
AppHibernate
、AppNewInstance
和AppSave
成员的全部或部分, - 在
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
,然后调用基类UpdateLayout
的UpdateLayout
成员。// ... 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
,然后调用基类UpdateLayout
的UpdateLayout
成员。 - 将
CFullScreenFrame
添加到您的主窗口继承列表, - 实现对
SetFullScreen
的调用, - 如果需要,检查
m_bFullScreen
, - 通过
FSDoModal
调用模态对话框和属性页。
- 对于 WTL 7.1(以及目前的 7.5),定义一个调用
// 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
的压缩DIBINFO16
或DDB
,具体取决于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; } //...
AtlCopyBitmap
在 ImageView 的 CImagePage
和 CViewPage
中用于填充 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){} //...
CImagePage
和 CViewPage
使用 AtlCopyBitmap
显示图像的小副本。
剪贴板复制和粘贴
ImageView 直接使用 DIB 支持函数。
可选标题栏
CImageViewview::m_TitleBar
是一个带有 CCS_TOP
样式的 CStatusBarCtrl
,CFrameWindowImplBase::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::SetScrollOffset
和CZoomScrollImpl::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 应用程序。