// MainDlg.cpp : implementation of the CMainDlg class
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "NaiveAlyViewer.h"
#include "MainDlg.h"
#include "aboutdlg.h"
/////////////////////////////////////////////////////////////////////////////
// Message handlers
BOOL CMainDlg::PreTranslateMessage ( MSG* pMsg )
{
return CWindow::IsDialogMessage ( pMsg );
}
BOOL CMainDlg::OnInitDialog ( HWND hwndFocus, LPARAM lParam )
{
// center the dialog on the screen
CenterWindow();
// set icons
HICON hIcon = AtlLoadIconImage ( IDR_MAINFRAME, LR_DEFAULTCOLOR, 32, 32 );
HICON hIconSmall = AtlLoadIconImage ( IDR_MAINFRAME, LR_DEFAULTCOLOR, 16, 16 );
SetIcon(hIcon, TRUE);
SetIcon(hIconSmall, FALSE);
// register object for message filtering and idle updates
CMessageLoop* pLoop = _Module.GetMessageLoop();
ATLASSERT(pLoop != NULL);
pLoop->AddMessageFilter(this);
DoDataExchange();
// Check the command line. If the first argument is a path to an .aly file, open it.
if ( __argc > 1 )
{
LPCTSTR szArg = __targv[1];
if ( PathMatchSpec ( szArg, _T("*.aly") ) && PathFileExists ( szArg ) )
ViewAlyFile ( szArg );
}
// Let the system set the focus.
return TRUE;
}
void CMainDlg::OnDestroy()
{
// unregister message filtering and idle updates
CMessageLoop* pLoop = _Module.GetMessageLoop();
ATLASSERT(pLoop != NULL);
pLoop->RemoveMessageFilter(this);
}
void CMainDlg::OnDropFiles ( HDROP hDrop )
{
TCHAR szFilePath[MAX_PATH] = {0};
// Get the full path of the first dragged file, and check that it's any .aly file.
if ( DragQueryFile ( hDrop, 0, szFilePath, _countof(szFilePath) ) > 0 &&
PathMatchSpec ( szFilePath, _T("*.aly") ))
{
ViewAlyFile ( szFilePath );
}
DragFinish ( hDrop );
}
/////////////////////////////////////////////////////////////////////////////
// Command handlers
void CMainDlg::OnCancel ( UINT nCode, int nID, HWND hwndCtrl )
{
DestroyWindow();
PostQuitMessage ( nID );
}
void CMainDlg::OnAppAbout ( UINT nCode, int nID, HWND hwndCtrl )
{
CAboutDlg dlg;
dlg.DoModal ( m_hWnd );
}
void CMainDlg::OnOpenAlyFile ( UINT uCode, int nID, HWND hwndCtl )
{
const COMDLG_FILTERSPEC aFilters[] =
{
{ L"Aly test files", L"*.aly" },
{ L"All files", L"*.*" }
};
HRESULT hr;
CString sSelectedFilePath;
CShellFileOpenDialog dlg ( L"test1.aly",
FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST,
L".aly", aFilters, _countof(aFilters) );
if ( IDOK != dlg.DoModal ( m_hWnd ) )
return;
hr = dlg.GetFilePath ( sSelectedFilePath );
// Show the selected file as the current file. The file open dialog automatically
// calls SHAddToRecentDocs for us because we didn't use the FOS_DONTADDTORECENT
// flag. As a result, the file shows up in our jump list.
if ( SUCCEEDED(hr) )
ViewAlyFile ( sSelectedFilePath );
}
void CMainDlg::OnRegisterAsHandler ( UINT uCode, int nID, HWND hwndCtl )
{
CString sCaption ( LPCTSTR(IDR_MAINFRAME) );
// Set this app as the one associated with *.aly files.
if ( RegisterAsHandler() )
{
// That succeeded, so tell the shell that a file association has changed.
SHChangeNotify ( SHCNE_ASSOCCHANGED, SHCNF_IDLIST, 0, 0 );
// Create a couple of test files for you to use with this app.
CreateTestFiles();
MessageBox ( _T("The file association was created successfully."),
sCaption, MB_ICONINFORMATION );
}
else
MessageBox ( _T("Error creating the file association"),
sCaption, MB_ICONERROR );
}
void CMainDlg::OnUnregisterAsHandler ( UINT uCode, int nID, HWND hwndCtl )
{
CString sCaption ( LPCTSTR(IDR_MAINFRAME) );
// Remove the association with *.aly files.
if ( UnregisterAsHandler() )
{
// Delete the test files that were created in OnRegisterAsHandler().
DeleteTestFiles();
// Tell the shell that a file association has changed.
SHChangeNotify ( SHCNE_ASSOCCHANGED, SHCNF_IDLIST, 0, 0 );
MessageBox ( _T("The file association was removed successfully."),
sCaption, MB_ICONINFORMATION );
}
else
MessageBox ( _T("Error removing the file association"),
sCaption, MB_ICONERROR );
}
/////////////////////////////////////////////////////////////////////////////
// Other methods
bool WriteRegString ( HKEY hkeyParent, LPCTSTR szSubkey, LPCTSTR szValueName,
LPCTSTR szData, HANDLE hTransaction )
{
HKEY hKey;
CRegKey reg;
LONG lRet;
lRet = RegCreateKeyTransacted (
hkeyParent, szSubkey, 0, REG_NONE,
REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hKey, NULL,
hTransaction, NULL );
if ( ERROR_SUCCESS != lRet )
return false;
reg.Attach ( hKey );
lRet = reg.SetStringValue ( szValueName, szData );
return ERROR_SUCCESS == lRet;
}
// This function registers this app as the default handler for *.aly files.
// The association is written to HKEY_CURRENT_USER instead of HKEY_CLASSES_ROOT
// so we can do this without requiring elevation. The jump list would work just
// as well if we did write to HKEY_CLASSES_ROOT, or if we had an installer that
// wrote the association there.
bool CMainDlg::RegisterAsHandler()
{
CHandle hTransaction;
CString sIconPath, sCommandLine;
TCHAR szModulePath[MAX_PATH] = {0};
GetModuleFileName ( NULL, szModulePath, _countof(szModulePath) );
sIconPath.Format ( _T("\"%s\",-%d"), szModulePath, IDI_ALY_FILETYPE );
sCommandLine.Format ( _T("\"%s\" \"%%1\""), szModulePath );
// Create a transaction for these registry changes.
hTransaction.Attach ( CreateTransaction ( NULL, 0, TRANSACTION_DO_NOT_PROMOTE,
0, 0, 0, NULL ) );
if ( hTransaction == NULL )
return false;
struct { LPCTSTR szKey, szValue, szData; } aEntries[] =
{
{ _T("software\\classes\\.aly"), NULL, _T("alyfile") },
{ _T("software\\classes\\alyfile"), NULL, _T("ALY test file type") },
{ _T("software\\classes\\alyfile\\DefaultIcon"), NULL, sIconPath },
{ _T("software\\classes\\alyfile\\shell\\open\\command"), NULL, sCommandLine }
};
for ( int i = 0; i < _countof(aEntries); i++ )
{
if ( !WriteRegString ( HKEY_CURRENT_USER, aEntries[i].szKey, aEntries[i].szValue,
aEntries[i].szData, hTransaction ) )
return false;
}
return 0 != CommitTransaction ( hTransaction );
}
// Remove the file association that was created in RegisterAsHandler().
bool CMainDlg::UnregisterAsHandler()
{
CHandle hTransaction;
LONG lRet;
HKEY hKey;
CRegKey rk;
// Create a transaction for these registry changes.
hTransaction.Attach ( CreateTransaction ( NULL, 0, TRANSACTION_DO_NOT_PROMOTE,
0, 0, 0, NULL ) );
if ( hTransaction == NULL )
return false;
// Delete the .aly key.
lRet = RegOpenKeyTransacted (
HKEY_CURRENT_USER, _T("software\\classes"), 0,
DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
&hKey, hTransaction, NULL );
if ( ERROR_SUCCESS != lRet )
return false;
rk.Attach ( hKey );
lRet = RegDeleteTree ( rk, _T(".aly") );
if ( ERROR_SUCCESS != lRet )
return false;
// Delete the alyfile key.
lRet = RegDeleteTree ( rk, _T("alyfile") );
if ( ERROR_SUCCESS != lRet )
return false;
return CommitTransaction ( hTransaction ) != 0;
}
LPWSTR g_awszTestFileNames[] = { L"test1.aly", L"willow.aly", L"buffy.aly" };
// Create some test files in the user's My Documents directory.
void CMainDlg::CreateTestFiles()
{
HRESULT hr;
LPWSTR pwszMyDocsPath = NULL;
hr = SHGetKnownFolderPath ( FOLDERID_Documents, 0, NULL, &pwszMyDocsPath );
if ( FAILED(hr) )
return;
for ( int i = 0; i < _countof(g_awszTestFileNames); i++ )
{
WCHAR wszTestFilePath[MAX_PATH] = {0};
CHandle hFile;
PathCombineW ( wszTestFilePath, pwszMyDocsPath, g_awszTestFileNames[i] );
hFile.Attach ( CreateFileW ( wszTestFilePath, GENERIC_WRITE, 0, NULL,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL ) );
if ( hFile != NULL )
{
LPCSTR szMsg = "Just a boring ol' test file.";
DWORD cbyToWrite = strlen ( szMsg ), cbyWritten = 0;
WriteFile ( hFile, szMsg, cbyToWrite, &cbyWritten, NULL );
}
}
CoTaskMemFree ( pwszMyDocsPath );
}
// Delete the test files that were created in CreateTestFiles().
void CMainDlg::DeleteTestFiles()
{
HRESULT hr;
LPWSTR pwszMyDocsPath = NULL;
hr = SHGetKnownFolderPath ( FOLDERID_Documents, 0, NULL, &pwszMyDocsPath );
if ( FAILED(hr) )
return;
for ( int i = 0; i < _countof(g_awszTestFileNames); i++ )
{
WCHAR wszTestFilePath[MAX_PATH] = {0};
PathCombineW ( wszTestFilePath, pwszMyDocsPath, g_awszTestFileNames[i] );
DeleteFileW ( wszTestFilePath );
}
CoTaskMemFree ( pwszMyDocsPath );
}
void CMainDlg::ViewAlyFile ( LPCTSTR szFilePath )
{
// Since this app doesn't do anything with its files, there isn't much here.
// In a more substantal app, this would be where you open and parse your
// documents.
// We'll just check that the file exists, and bail out if not.
if ( !PathFileExists ( szFilePath ) )
return;
// Show the file as the current file.
m_cCurrFilePath.SetWindowText ( szFilePath );
// Add it to the recent files list. This also makes Win 7 add it to the
// app's jump list.
SHAddToRecentDocs ( SHARD_PATH, szFilePath );
}