ImageView is a PPC application written with WTL.
From WTL 7.1, WTL officially supports PPC 2002 and 2003. This support is continued in the forthcoming OpenSource WTL 7.5 release. However, PPC systems require from applications behaviors that are not, and should not be, included in generic WTL classes.
ImageView puts at work atlppc.h, a limited set of PPC WTL classes and functions which have been submitted for inclusion in WTL 7.5. ImageView makes use of class CZoomScrollImpl described in CodeProject: Add zooming to WTL CScrollImpl.
The ImageViewPPC project, atlppc.h and zoomscrl.h compile with WTL 7.1 and current 7.5 distribution with EVC 3.0 to 4.2 and PPC 2002/2003 SDK.
With WTL comes a very rich sample, BmpView written with code compatibility between desktop and Pocket PC devices. With BmpZoom, I have extended its functionality to continuous zooming.
João Paulo Figueira has given PicView, a nice MFC picture viewer for PPC 2002.
ImageView is inspired from these two models and aims to be (if possible) a better image viewer.
|
Feature
|
ImageView
|
BmpZoom
|
PicView
|
|
Zoom
|
Continuous |
Continuous |
Integer steps |
|
Zoom UI
|
Trackbar in menu, keys |
Trackbar in menu |
Menu buttons (in - out) |
|
Well behaved
|
Yes |
No |
MFC behavior |
|
Image property sheet
|
Yes |
Yes |
No |
|
Clipboard copy and paste
|
Yes |
Not completed |
No |
|
Title Bar
|
Yes |
No |
Yes |
|
Full screen view
|
Yes |
No |
Yes |
|
Tap-and-scroll
|
Yes |
No |
Yes |
|
Show/hide scroll bars
|
Yes |
No |
No |
|
System registration
|
Yes |
No |
No |
PPC WTL classes and functions
Standard property sheet and dialogs
CStdPropertySheet
template <class T, bool t_bShowSip = true>
class CStdPropertySheet : public CPropertySheetImpl<T>
Class description
Standard PPC property sheet with title, empty menubar with SIP depending on t_bShowSip.
Derive a property sheet class from CStdPropertySheet as ImageView CImageProperties.
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);
}
};

template <class T, bool t_bModal = true>
class CStdDialog
Class description
Base class for standard PPC dialogs featuring:
- PPC dialog title display, and dialog title preparation routine
LRESULT OnPaintTitle(UINT , WPARAM ,
LPARAM , BOOL& bHandled)
LRESULT OnInitStdDialog(UINT , WPARAM ,
LPARAM , BOOL& bHandled)
void StdDialogTitleInit()
- Close command handler, calling
EndDialog( wID) or DestroyWindow() depending on the value of t_bModal.
LRESULT OnCloseCmd(WORD , WORD wID,
HWND , BOOL& )
- Background
COLOR_INFOBK setting for static controls of ID: IDC_INFOSTATIC // == IDC_STATIC -1 .
LRESULT OnColorStatic(UINT , WPARAM wParam,
LPARAM lParam, BOOL& bHandled)
Class usage
Derive a dialog class from both CDialogImpl and CStdDialog and connect the wanted features through the dialog class message map. CStdDialogImpl does that for all features.
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()
};
template <class T, bool t_bModal = true>
class CStdDialogImpl : public CDialogImpl<T> , public CStdDialog<T, t_bModal>
Class description
Standard PPC dialog implementation for derivation.
Class usage
Derive a dialog class from CStdDialogImpl, and chain the message map as ImageView CMoveDlg and CRegisterDlg.
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()
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> >
Class description
Standard CSimpleDialog (modal only) with initial settings t_shidiFlags which default to CSimpleDialog settings.
Class usage
Instantiate as in ImageView OnAppAbout handler.
LRESULT OnAppAbout(WORD , WORD ,
HWND , BOOL& )
{
CStdSimpleDialog<IDD_ABOUTBOX,
SHIDIF_DONEBUTTON | SHIDIF_FULLSCREENNOMENUBAR> dlg;
return FSDoModal( dlg);
}

Application behavior
CAppInfoBase
class CAppInfoBase
Class description
Helper for application state save/restore to registry. Opens or creates a sAppKey registry key under HKEY_CURRENT_USER. Save and Restore members transfer program variables to that key.
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);
}
Class usage
Derive from CAppInfoBase if you need to save/restore nested variables. CAppInfoBase has specialized Save and Restore members for CString type. Add other needed specializations in your derived class.
#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
Class description
CAppInfoBase associated with CAppWindow<T>.
template < class T >
class CAppInfoT : public CAppInfoBase
{
public:
CAppInfoT() : CAppInfoBase( T::m_szAppKey){}
};
Class usage
CAppWindow<T> defines its CAppInfo type as CAppInfoT<T>.
template <class T>
class CAppWindow
{
public:
typedef class CAppInfoT<T> CAppInfo;
Instantiate CAppInfoT as in CRegisterDlg::Register.
class CRegisterDlg : public CStdDialogImpl<CRegisterDlg>
{
public:
void Register( ImageType typ, BOOL bRegister)
{
CAppInfoT<CMainFrame> info;
CAppWindow
template <class T>
class CAppWindow
Class description
Base class for PPC application frame window featuring:
- Command line parameters transmission to
OnCreate handler and to previous instance:
template <class T>
class CAppWindow
{
public:
static int AppRun(LPTSTR lpstrCmdLine = NULL,
int nCmdShow = SW_SHOWNORMAL)
static HRESULT ActivatePreviousInstance(HINSTANCE hInstance,
LPCTSTR lpstrCmdLine )
bool AppNewInstance( LPCTSTR lpstrCmdLine)
MESSAGE_HANDLER( WM_COPYDATA, OnNewInstance)
LRESULT OnNewInstance(UINT , WPARAM ,
LPARAM lParam, BOOL& )
{
T* pT = static_cast<T*>(this);
PCOPYDATASTRUCT pcds = (PCOPYDATASTRUCT) lParam;
return pT->AppNewInstance((LPCTSTR)pcds->lpData);
}
WM_HIBERNATE message support:
template <class T>
class CAppWindow
{
public:
bool m_bHibernate;
bool AppHibernate( bool bHibernate)
MESSAGE_HANDLER( WM_HIBERNATE, OnHibernate)
MESSAGE_HANDLER( WM_ACTIVATE, OnActivate)
LRESULT OnHibernate(UINT , WPARAM ,
LPARAM , BOOL& )
{
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);
- Activation deactivation and setting change support through relevant system calls:
template <class T>
class CAppWindow
{
public:
SHACTIVATEINFO m_sai;
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);
}
- Application state persistence support.
template <class T>
class CAppWindow
{
public:
typedef class CAppInfoT<T> CAppInfo;
static LPCTSTR m_szAppKey;
void AppSave()
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;
}
Class usage
- In your AppWizard generated application
::_tWinMain
- define
LPCTSTR CMainFrame::m_szAppKey,
- call
CMainFrame::ActivatePreviousInstance with two parameters,
- change the call to
Run into CMainFrame::AppRun and
- delete the
Run function.
LPCTSTR CMainFrame::m_szAppKey = L"Software\\CodeProject\\ImageView";
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE ,
LPTSTR lpstrCmdLine, int nCmdShow)
{
HRESULT hRes = CMainFrame::ActivatePreviousInstance(hInstance, lpstrCmdLine );
int nRet = CMainFrame::AppRun(lpstrCmdLine, nCmdShow);
}
- In your frame definition
- Add
CAppWindow to your main window inheritance list,
- chain the message map,
- delete
ActivatePreviousInstance member definition,
- define all or part of
AppHibernate, AppNewInstance and AppSave members,
- process the command line parameters, and/or restore the application status and data in the
OnCreate handler.
// 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
{
//...
Frame size and position
AtlFixUpdateLayout
void AtlFixUpdateLayout( HWND hWndFrame, HWND hWndMenuBar)
Function description
Frame positioning fix for WTL 7.1 (today still needed with 7.5).
Function usage
- If you do not use
CFullScreenFrame, in your AppWizard generated CMainFrame::OnCreate, call AtlFixUpdateLayout after menubar creation:
LRESULT OnCreate(UINT , WPARAM ,
LPARAM , BOOL& )
{
CreateSimpleCEMenuBar(IDR_MAINFRAME, SHCMBF_HMENU);
AtlFixUpdateLayout( m_hWnd, m_hWndCECommandBar);
- If you want to use
CFullScreenFrame, define a UpdateLayout member that calls AtlFixUpdateLayout and then the base class 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
Class description
Full screen enabled frame window class:
bool m_bFullScreen holds the current state;
void SetFullScreen( bool bFull) sets the requested state.
template <class D> int FSDoModal( D& dlg) restores the taskbar if hidden, calls dlg.DoModal(), hides the taskbar if it was restored, and returns dlg.DoModal() return value.
- In your frame definition
- For WTL 7.1 (and presently 7.5), define a
UpdateLayout member that calls AtlFixUpdateLayout and then the base class UpdateLayout.
- Add
CFullScreenFrame to your main window inheritance list,
- implement calls to
SetFullScreen,
- check
m_bFullScreen if required,
- call modal dialogs and property sheets through
FSDoModal.
class CMainFrame :
public CFullScreenFrame<CMainFrame, false>,
{
void UpdateLayout(BOOL bResizeBars = TRUE)
{
CRect rectWnd, rectTool;
#if _WTL_VER <= 0x0710 || defined(_WTL_NO_PPC_FRAME_POSITION)
AtlFixUpdateLayout( m_hWnd, m_hWndCECommandBar);
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)
LRESULT OnFileOpen(WORD , WORD ,
HWND , BOOL& )
{
CFileDialog dlg( TRUE, NULL, NULL, OFN_HIDEREADONLY |
OFN_OVERWRITEPROMPT, sFiles);
if( FSDoModal( dlg) == IDOK)
SetImageFile( dlg.m_szFileName);
LRESULT OnAppAbout(WORD , WORD ,
HWND , BOOL& )
{
CStdSimpleDialog<IDD_ABOUTBOX,
SHIDIF_DONEBUTTON | SHIDIF_FULLSCREENNOMENUBAR> dlg;
return FSDoModal( dlg);
}
LRESULT OnRegister(WORD , WORD ,
HWND , BOOL& )
{
CRegisterDlg dlg;
return FSDoModal( dlg);
}
LRESULT OnProperties(WORD , WORD ,
HWND , BOOL& )
{
CImageProperties prop( m_sFile, m_view);
return FSDoModal( prop);
}
LRESULT OnFullScreen(WORD , WORD ,
HWND , BOOL& )
{
SetFullScreen( !m_bFullScreen );
UISetCheck( ID_VIEW_TOOLBAR, m_bFullScreen);
return TRUE;
}
DIB structure
struct DIBINFO16 creates descriptors for sized 16 bits DIB with BI_BITFIELDS.
DIB functions description
HBITMAP AtlGetDibBitmap( LPBITMAPINFO pbmi) builds a HBITMAP from a packed DIB.
HBITMAP AtlCopyBitmap( HBITMAP hbm , SIZE size, bool bAsBitmap = false) copies a HBITMAP to a size dimensioned packed DIBINFO16 or DDB depending on bAsBitmap.
HLOCAL AtlCreatePackedDib16( HBITMAP hbm, SIZE size) creates a packed DIBINFO16 of size size from a given HBITMAP.
bool AtlSetClipboardDib16( HBITMAP hbm, SIZE size, HWND hWnd) sets the clipboard CF_DIB format to a sized DIBINFO16 copied from a HBITMAP.
HBITMAP AtlGetClipboardDib( HWND hWnd) returns a HBITMAP from the clipboard CF_DIB format.
Use this set of functions to support the CF_DIB clipboard format, CF_BITMAP clipboard objects are not inter-process enabled in PPC.
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)
BEGIN_MSG_MAP(CMainFrame)
COMMAND_ID_HANDLER(ID_EDIT_PASTE, OnPaste)
CHAIN_MSG_MAP_ALT_MEMBER(m_view, 1)
LRESULT OnPaste(WORD , WORD ,
HWND , BOOL& )
{
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;
}
BEGIN_MSG_MAP(CImageViewView)
ALT_MSG_MAP( 1 ) COMMAND_ID_HANDLER(ID_EDIT_COPY, OnCopy)
LRESULT OnCopy(WORD , WORD ,
HWND , BOOL& )
{
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 is used in ImageView CImagePage and CViewPage to fill-up CStatic controls bitmaps.
class CImagePage : public CPropertyPageImpl<CImagePage>
{
CBitmapHandle m_bmp;
BEGIN_MSG_MAP(CImagePage)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
LRESULT OnInitDialog(UINT , WPARAM ,
LPARAM , BOOL& )
{
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);
CImageViewView derives from CZoomScrollImpl which implements the feature. This class is fully described in CodeProject: Add zooming to WTL CScrollImpl.
This feature requires some steps:
- Create a menu bar button of ID:
ID_ZOOM in the resource editor
- Declare a
CTrackbarCtrl member in CImageViewView.
class CImageViewView :
public CWindowImpl< CImageViewView > ,
public CZoomScrollImpl< CImageViewView >
{
public:
DECLARE_WND_CLASS(NULL)
CTrackBarCtrl m_ZoomCtrl;
- Subclass the menubar to forward trackbar messages
- Create
CImageViewView::m_ZoomCtrl in place of the ID_ZOOM button.
// 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);
//...
- Set the trackbar range for the current image.
void SetImage( HBITMAP hBitmap, LPCTSTR sname = NULL,
double fZoom = 1.0, POINT pScroll = CPoint( -1,-1))
{
CSize sizeImage( 1, 1);
m_bmp.Attach( hBitmap );
if( m_bmp.IsNull())
else
{
m_bmp.GetSize( sizeImage);
}
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 ));
}
- Manage the trackbar state
// 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);
//...
void SetImage( HBITMAP hBitmap, LPCTSTR sname = NULL,
double fZoom = 1.0, POINT pScroll = CPoint( -1,-1))
{
CSize sizeImage( 1, 1);
m_bmp.Attach( hBitmap );
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);
}
BEGIN_MSG_MAP(CImageViewView)
ALT_MSG_MAP( 1 ) MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnZoomColor)
LRESULT OnZoomColor(UINT , WPARAM ,
LPARAM , BOOL& )
{
return (LRESULT)::GetSysColorBrush( m_bmp.IsNull() ?
COLOR_BTNFACE : COLOR_BTNHIGHLIGHT );
}
- Forward the keyboard messages to the trackbar
- Set zoom on trackbar move
BEGIN_MSG_MAP(CImageViewView)
MESSAGE_RANGE_HANDLER( WM_KEYFIRST, WM_KEYLAST, OnKey)
ALT_MSG_MAP( 1 ) MESSAGE_HANDLER(WM_HSCROLL, OnZoom)
LRESULT OnKey(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& )
{
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 , WPARAM wParam,
LPARAM , BOOL& )
{
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 derives from CAppWindow which implements the feature. See CAppWindow class usage.
CMainFrame derives from CStdPropertySheet (see class usage) and is activated through FSDoModal.
LRESULT OnProperties(WORD , WORD ,
HWND , BOOL& )
{
CImageProperties prop( m_sFile, m_view);
return FSDoModal( prop);
}
The three property pages are supplied at creation with relevant data.
class CFilePage : public CPropertyPageImpl<CFilePage>
{
public:
enum { IDD = IDD_PROP_FILE };
CString m_sPath;
CFilePage( LPCTSTR sPath) : m_sPath( sPath) { }
class CImagePage : public CPropertyPageImpl<CImagePage>
{
public:
enum { IDD = IDD_PROP_IMAGE };
CBitmapHandle m_bmp;
CImagePage(HBITMAP hbmp) : m_bmp(hbmp) {}
class CViewPage : public CPropertyPageImpl<CViewPage>
{
public:
CImageViewView& m_rview;
CViewPage( CImageViewView& rview) : m_rview( rview){}
CImagePage and CViewPage use AtlCopyBitmap to display a small copy of the image.
ImageView makes direct use of the DIB support functions.
CImageViewview::m_TitleBar is a CStatusBarCtrl with CCS_TOP style, which CFrameWindowImplBase::UpdateLayout presently ignores. This is addressed in CMainFrame::UpdateLayout.
Title bar visibility is saved in CMainFrame::AppSave and restored at creation.
class CImageViewView :
public CWindowImpl< CImageViewView > ,
public CZoomScrollImpl< CImageViewView >
{
public:
DECLARE_WND_CLASS(NULL)
CTrackBarCtrl m_ZoomCtrl;
CStatusBarCtrl m_TitleBar;
class CMainFrame :
public CFrameWindowImpl<CMainFrame,CWindow,CCeFrameTraits>,
public CUpdateUI<CMainFrame>,
public CMessageFilter, public CIdleHandler,
public CFullScreenFrame<CMainFrame, false>,
public CAppWindow<CMainFrame>
{
void UpdateLayout(BOOL bResizeBars = TRUE)
{
CRect rectWnd, rectTool;
#if _WTL_VER <= 0x0710 || defined(_WTL_NO_PPC_FRAME_POSITION)
AtlFixUpdateLayout( m_hWnd, m_hWndCECommandBar);
#else
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
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;
}
ATLASSERT( m_view.IsWindow());
m_view.GetWindowRect( rectTool);
if ( rectTool != rectWnd)
m_view.SetWindowPos( NULL, rectWnd, SWP_NOZORDER | SWP_NOACTIVATE);
}
void AppSave()
{
CAppInfo info;
BOOL bTitle = m_view.m_TitleBar.IsWindowVisible();
info.Save( bTitle, L"TitleBar");
LRESULT OnCreate(UINT , WPARAM ,
LPARAM lParam, BOOL& )
{
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);
Setting SBT_OWNERDRAW flagged text when zoom or image name has changed triggers CImageViewview::OnDrawTitle.
void SetImage( HBITMAP hBitmap, LPCTSTR sname = NULL,
double fZoom = 1.0, POINT pScroll = CPoint( -1,-1))
{
CSize sizeImage( 1, 1);
m_bmp.Attach( hBitmap );
if( m_bmp.IsNull())
m_TitleBar.SetText( 0, L"No image");
else
m_TitleBar.SetText( 0, NULL, SBT_OWNERDRAW);
BEGIN_MSG_MAP(CImageViewView)
ALT_MSG_MAP( 1 ) MESSAGE_HANDLER(WM_HSCROLL, OnZoom)
MESSAGE_HANDLER(WM_DRAWITEM, OnDrawTitle)
LRESULT OnDrawTitle(UINT , WPARAM ,
LPARAM lParam, BOOL& )
{
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;
}
LRESULT OnZoom(UINT , WPARAM wParam,
LPARAM , BOOL& )
{
ATLASSERT( !m_bmp.IsNull());
double fzoom;
if ( fzoom != m_fzoom)
{
SetZoom( fzoom);
m_TitleBar.SetText( 0, NULL, SBT_OWNERDRAW);
}
CMainFrame derives from CFullScreenFrame which implements the feature. See CFullScreenFrame class usage.
The last stylus position is kept in CImageViewView::m_ptMouse and the view offset is changed on WM_MOUSEMOVE message.
class CImageViewView :
public CWindowImpl< CImageViewView > ,
public CZoomScrollImpl< CImageViewView >
{
public:
CPoint m_ptMouse;
BEGIN_MSG_MAP(CImageViewView)
MESSAGE_HANDLER(WM_SIZE, OnSize)
MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
LRESULT OnLButtonDown(UINT , WPARAM ,
LPARAM lParam, BOOL& )
{
m_ptMouse = CPoint( GET_X_LPARAM( lParam), GET_Y_LPARAM( lParam));
}
LRESULT OnMouseMove(UINT , WPARAM wParam,
LPARAM lParam, BOOL& )
{
if (
#ifdef _X86_
(wParam & MK_LBUTTON) &&
#endif !m_bmp.IsNull())
{
CPoint ptNew( GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
SetScrollOffset( GetScrollOffset() +
(( m_ptMouse - ptNew) * GetZoom()));
m_ptMouse = ptNew;
}
return 0;
}
As Windows CE does not support the handy ::ShowScrollBar(), implementing this feature requires some work:
- Declare
CImageViewView::m_bShowScroll to hold the scrollbar visibility.
- Implement
CImageViewView::ShowScrollBars function and CImageViewView::OnShowScrollBars command handler.
- Override
CZoomScrollImpl::SetScrollOffset and CZoomScrollImpl::SetZoom which are called by CImageViewView.
- Override
CZoomScrollImpl::OnSize handler.
class CImageViewView :
public CWindowImpl< CImageViewView > ,
public CZoomScrollImpl< CImageViewView >
{
public:
bool m_bShowScroll;
CImageViewView() : m_bShowScroll( true) {}
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();
}
void SetScrollOffset( POINT ptOffset, BOOL bRedraw = TRUE )
{
if ( m_bShowScroll)
CZoomScrollImpl<CImageViewView>::SetScrollOffset( ptOffset, bRedraw);
else
{
AdjustOffset( CSize( ptOffset) / m_fzoom);
if ( bRedraw)
Invalidate();
}
}
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();
}
}
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;
}
}
BEGIN_MSG_MAP(CImageViewView)
MESSAGE_HANDLER(WM_SIZE, OnSize)
ALT_MSG_MAP( 1 )
COMMAND_ID_HANDLER(ID_VIEW_SCROLLBARS, OnShowScrollBars)
LRESULT OnSize(UINT , 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;
}
LRESULT OnShowScrollBars(WORD , WORD ,
HWND , BOOL& )
{
ShowScrollBars( !m_bShowScroll);
return TRUE;
}
- Implement the scrollbar visibility persistence
- Update menu item check
class CMainFrame :
{
void AppSave()
{
CAppInfo info;
info.Save( m_view.m_bShowScroll, L"ScrollBars");
BEGIN_UPDATE_UI_MAP(CMainFrame)
UPDATE_ELEMENT(ID_VIEW_SCROLLBARS, UPDUI_MENUPOPUP)
BEGIN_MSG_MAP(CMainFrame)
COMMAND_ID_HANDLER(ID_VIEW_SCROLLBARS, OnScrollBars)
LRESULT OnCreate(UINT , WPARAM ,
LPARAM lParam, BOOL& )
{
CAppInfo info;
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);
LRESULT OnScrollBars(WORD , WORD ,
HWND , BOOL& bHandled)
{
UISetCheck( ID_VIEW_SCROLLBARS, !m_view.m_bShowScroll);
return bHandled = FALSE; }
This feature is handled by CRegisterDlg.
Image files are associated to a default program through the HKEY_CLASSES_ROOT\xxxxxx\Shell\Open\Command registry key default string value, where xxxxx depends on the file type. When a user taps a file name, the shell executes the command found there. However, only \Windows located programs are executed.
CRegisterDlg::InitDialog checks the current ImageView location and calls CMoveDlg::DoModal if the location is not \Windows.
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)
LRESULT OnInitDialog(UINT , WPARAM ,
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);
if( CString(L"\\Windows\\") + m_sApp != m_sAppPath)
{
CMoveDlg dlg;
if ( dlg.DoModal() == IDCANCEL)
EndDialog( IDCANCEL);
//...
CMoveDlg moves ImageView.exe if allowed by user, and creates, if requested, a shortcut at the old program location.
// 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
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;
}
};

On IDOK return, or if ImageView is correctly located, CRegisterDlg::InitDialog initializes the registration status of the image file types. A helper class CImageTypeKey : public CRegKey provides the registry access.
class CRegisterDlg : public CStdDialogImpl<CRegisterDlg>
{
public:
enum ImageType { BMP = IDC_BMP, JPG, PNG, GIF } ;
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"");
}
};
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;
}
}
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)
LRESULT OnInitDialog(UINT , WPARAM ,
LPARAM , BOOL& bHandled)
{
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 uses CAppInfoT<CMainFrame> to save the existing key on registration and restore it on 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()
LRESULT OnCheckType(WORD , WORD wID,
HWND , BOOL& )
{
Register( (ImageType)wID, IsDlgButtonChecked( wID));
return 0;
}
With WTL 7.1 or 7.5 and the limited set of PPC specific classes and functions in atlppc.h, you (and I) can easily write nice real life Pocket PC applications.