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.