Click here to Skip to main content
15,896,111 members
Articles / Desktop Programming / MFC

Resource ID Organiser Add-In for Visual C++ 5.0/6.0/.NET

Rate me:
Please Sign up or sign in to vote.
4.98/5 (71 votes)
10 Jan 2005CPOL25 min read 533.6K   12.1K   201  
An application/add-in to organise and renumber resource symbol IDs
//////////////////////////////////////////////////////////////////////////
// BXFileDialog.cpp : implementation file
// 
// Windows 2000 / Office 2000 style file dialog.
// 
// This WILL work on Win 95 / 98 / NT 4 / NT 5 (2000) / WinME
// 
// Original code by Norm Almond []
//					David Wulff [dwulff@battleaxesoftware.com]
// 
// Update History:
//    07 Sep 2000 - David Wulff, Opps, I lost the previous update history.
//    08 Sep 2000 - David Wulff, Lots of changes, most significant is the
//                  .. addition of an optional preview panel, allowing you
//                  .. to preview bitmap images before opening/saving.
//    14 Oct 2000 - Joel Bernard, Provided a better CenterWindow function.
//                  David Wulff, Fixed memory leaks, added support for
//                  .. previewing non-bitmap images. (code by Wes Rogers)
//                  Other misc. changes.
//                  Anatoly Danekin, Shortcut path resolution.
//    13 Dec 2000 - David Wulff, Added Visual Studio .NET look
//    24 Mar 2001 - David Wulff, miscellaneous drawing updates
//                  Tak^Shoran, working sizing support for Win 98/2000
//                  Identified very bad flickering problem
//    31 Mar 2001 - David Wulff, Fixed resizing so it will work for dialogs
//                  .. with preview panels.  Tidied up all of the code (it
//                  .. was a big mess) and added standard function headers.
//                  .. Removed compile-time only modification of sizing
//                  .. support and VS.NET style
//    27 Jul 2001 - David Wulff, now when you select a non-image file, or
//                  .. a folder, the preview pane is cleared.  Added a
//                  .. handler for the CDN_TYPECHANGE message, so you can
//                  .. customise the OK button's drop-down menu.
//    03 Aug 2001 - David Wulff, added new functions to allow you to modify
//                  .. the listctrl view type during runtime.
//    04 Aug 2001 - David Wulff, only selects a sidebar button if the
//                  .. directory is selected.  Misc changes.
//////////////////////////////////////////////////////////////////////////
// Note, all dates given in this file are in the standard UK format (D:M:Y)

#include "stdafx.h"
#include <winuser.h>
#include <dlgs.h>
#include "BXFileDialog_Priv.h"

#include "BXFileDialog.h"
#include "BXFileDialog_Res.h"


//define _USE_HTMLHELP		// uncomment to have context help for the sidebar.
#define CONTROL_GAP		5	// the default 'gap' between controls

#ifdef _USE_HTMLHELP
	#include <htmlhelp.h>
	#pragma comment ( lib, "htmlhelp.lib" )
	#pragma message ("  NOTE: HTMLHelp support is included.")
#endif

#define ID_SHOW_PREVIEW		3420 // this is the ID for the "preview?" checkbox

BOOL BXFileDialog::m_bClear = FALSE;
TCHAR BXFileDialog::m_szFile[] = {"\0"};

BOOL bDotNetUI = FALSE;

#pragma warning ( disable : 4244 ) // float -> int conversion warnings

/////////////////////////////////////////////////////////////////////////////
// BXFileDialog

IMPLEMENT_DYNAMIC(BXFileDialog, CFileDialog)
BEGIN_MESSAGE_MAP(BXFileDialog, CFileDialog)
//{{AFX_MSG_MAP(BXFileDialog)
ON_WM_SIZE()
ON_WM_HELPINFO()
ON_WM_MEASUREITEM()
ON_BN_CLICKED(IDC_CHECK_PREVIEW, OnClickedPreview)
ON_BN_CLICKED(ID_SHOW_PREVIEW, OnShowPreview)
ON_WM_PAINT()
//}}AFX_MSG_MAP
ON_COMMAND(ID_BTN_HISTORY, OnHistoryClicked)
ON_COMMAND(ID_BTN_PERSONAL, OnPersonalClicked)
ON_COMMAND(ID_BTN_DESKTOP, OnDesktopClicked)
ON_COMMAND(ID_BTN_FAVORITES, OnFavoritesClicked)
ON_COMMAND(ID_BTN_WEBFOLDERS, OnWebFoldersClicked)
ON_COMMAND_RANGE(ID_START, ID_END, OnMyOk)
ON_COMMAND(IDOK, OnOk)
END_MESSAGE_MAP()

/************************************************************************/
/*  BXFileDialog														*/
/*																		*/
/*  Created:     31:3:2001												*/
/*  Author:      David Wulff, Norm Almond								*/
/*  Description: Class constructor										*/
/*	Revisions:	 														*/
/************************************************************************/
BXFileDialog::BXFileDialog(BOOL bOpenFileDialog, BOOL bPreview, BOOL bSizing,
						   LPCTSTR lpszDefExt, LPCTSTR lpszFileName,
						   DWORD dwFlags, LPCTSTR lpszFilter,
						   CWnd* pParentWnd) :
CFileDialog(bOpenFileDialog, lpszDefExt, lpszFileName, dwFlags,
			lpszFilter, pParentWnd)
{
	m_IsOpen = bOpenFileDialog;
	m_bShowPreview = m_bPreview = bPreview;
	m_bFirst = TRUE;

	m_ofn.hInstance         = GetBXFileDialogDll()->hModule;
	m_ofn.lpTemplateName    = MAKEINTRESOURCE(IDD_WIN2K_FILEDIALOG);
	m_ofn.Flags             = dwFlags | OFN_EXPLORER | OFN_ENABLETEMPLATE |
								OFN_ENABLEHOOK | OFN_HIDEREADONLY |
								(bSizing ? OFN_ENABLESIZING : 0);
}

/************************************************************************/
/*  ~BXFileDialog														*/
/*																		*/
/*  Created:     31:3:2001												*/
/*  Author:      David Wulff, Norm Almond								*/
/*  Description: Class destructor										*/
/*	Revisions:	 														*/
/************************************************************************/
BXFileDialog::~BXFileDialog()
{
}

/************************************************************************/
/*  OnInitDialog														*/
/*																		*/
/*  Created:     31:3:2001												*/
/*  Author:      David Wulff, Norm Almond								*/
/*  Description: WM_INITDIALOG handler									*/
/*	Revisions:	 														*/
/************************************************************************/
BOOL BXFileDialog::OnInitDialog() 
{
	CFileDialog::OnInitDialog();
	
	// create the imagelist and load the sidebar icons
	m_IL.Create(IDB_ICONS, 32, 1, RGB(255, 0, 255));
	
	// center this dialog on the main window
	CWnd* pMainWnd = AfxGetMainWnd();
	CenterWindowOnOwner(pMainWnd);
	
	// store the width of the static control (set it via the dialog editor)
	CWnd* pWndOutLookBar = GetDlgItem(IDC_OUTLOOK_BAR_PLACEHOLDER);
	CRect rcOLBClient;
	pWndOutLookBar->GetClientRect(rcOLBClient);
	m_SBWidth = rcOLBClient.Width();
	
	return TRUE;
}

/************************************************************************/
/*  OnNotify															*/
/*																		*/
/*  Created:     31:3:2001												*/
/*  Author:      David Wulff, Norm Almond								*/
/*  Description: WM_NOTIFY handler										*/
/*	Revisions:															*/
/************************************************************************/
BOOL BXFileDialog::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
	OFNOTIFY* pNotify = (OFNOTIFY*)lParam;
	
	switch(pNotify->hdr.code)
	{
	case CDN_INITDONE:
		{
			SetActiveButton(&m_btnPersonal);
			m_edtFile.SubclassDlgItem(edt1,GetParent());

			OnFileTypeChange(m_ofn.nFilterIndex);

			return TRUE;
		}
		
		// [DW]: Remind me why we need these again?  CFileDialog already
		// .. provides these handlers, so why replace them? [4/8/2001]
	case CDN_SELCHANGE:
		{
			// the listctrl selection has changed
			OnFileNameChange();
			return TRUE;
		}
		
	case CDN_FOLDERCHANGE:
		{
			// the 'root' folder has changed
			OnFolderChange();
			return TRUE;
		}
		
	case CDN_TYPECHANGE:
		{
			// the file type/s to view has changed
			OnFileTypeChange(pNotify->lpOFN->nFilterIndex);
			return TRUE;
		}
	}
	
	return FALSE;
}

/************************************************************************/
/*  GetListCtrl															*/
/*																		*/
/*  Created:     03:8:2001												*/
/*  Author:      David Wulff											*/
/*  Description: Helper function to return the listctrl					*/
/*	Revisions:	 														*/
/************************************************************************/
CListCtrl* BXFileDialog::GetListCtrl()
{
	CListCtrl* pLCtrl;
	BOOL bWin2k = FALSE;
	OSVERSIONINFO osvi;
	osvi.dwOSVersionInfoSize = sizeof(osvi);
	
	::GetVersionEx(&osvi);
	
	// TODO [DW]: Check to see which one is needed for Windows ME [3/8/2001]
	
	if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT &&
		osvi.dwMajorVersion == 5)
		bWin2k = TRUE;
	
	// ok, here's the deal:  On Windows 2000, the listctrl we want is a child
	// .. of another, custom, control.  So, if we are running on Windows 2000,
	// .. we will need to take this into account.
	
	// THIS TOOK ME FOUR DAYS TO FIND!  Dammit Microsoft - why can't you stick
	// .. to your own guidelines?  Thank God for Spy++!
	
	if (bWin2k)
	{
		CWnd *pWnd = GetParent()->GetDlgItem(lst2);
		pLCtrl = (CListCtrl*)pWnd->GetDlgItem(1);
	}
	else
		pLCtrl = (CListCtrl*)GetParent()->GetDlgItem(lst1);
	
	return pLCtrl;
}

/************************************************************************/
/*  SetListCtrlView														*/
/*																		*/
/*  Created:     03:8:2001												*/
/*  Author:      David Wulff											*/
/*  Description: Set the listctrl style during runtime					*/
/*	Revisions:	 														*/
/************************************************************************/
void BXFileDialog::SetListCtrlView(DWORD dwNewStyle)
{
	CListCtrl* pLCtrl = GetListCtrl();
	DWORD dwStyle = GetWindowLong (pLCtrl->GetSafeHwnd(), GWL_STYLE);
	
	// TODO [DW]: LVS_REPORT doesn't work properly! [3/8/2001]
	if ((dwStyle & LVS_TYPEMASK) != dwNewStyle)
		SetWindowLong (pLCtrl->GetSafeHwnd(), GWL_STYLE,
		(dwStyle & ~LVS_TYPEMASK) | dwNewStyle);
}

/************************************************************************/
/*  GetActiveButton														*/
/*																		*/
/*  Created:     07:8:2001												*/
/*  Author:      David Wulff											*/
/*  Description: Returns a pointer to the acitve sidebar button			*/
/*	Revisions:	 														*/
/************************************************************************/
BXSelBtn* BXFileDialog::GetActiveButton()
{
	static TCHAR szPath[MAX_PATH];
	LPITEMIDLIST lpIDList;
	
	// "History"
	SHGetSpecialFolderLocation(0, CSIDL_RECENT, &lpIDList);
	SHGetPathFromIDList(lpIDList, szPath);
	
	if (GetFolderPath().CompareNoCase(CString(szPath)) == 0)
		return &m_btnHistory;
	
	// "Favourites"
	SHGetSpecialFolderLocation(0, CSIDL_FAVORITES, &lpIDList);
	SHGetPathFromIDList(lpIDList, szPath);
	
	if (GetFolderPath().CompareNoCase(CString(szPath)) == 0)
		return &m_btnFavourites;
	
	// "My Documents"
	SHGetSpecialFolderLocation(0, CSIDL_PERSONAL, &lpIDList);
	SHGetPathFromIDList(lpIDList, szPath);
	
	if (GetFolderPath().CompareNoCase(CString(szPath)) == 0)
		return &m_btnPersonal;
	
	// "Desktop"
	SHGetSpecialFolderLocation(0, CSIDL_DESKTOP, &lpIDList);
	SHGetPathFromIDList(lpIDList, szPath);
	
	if (GetFolderPath().CompareNoCase(CString(szPath)) == 0)
		return &m_btnDeskTop;
	
	// "Network Neighbourhood"
	SHGetSpecialFolderLocation(0, CSIDL_NETHOOD, &lpIDList);
	SHGetPathFromIDList(lpIDList, szPath);
	
	if (GetFolderPath().CompareNoCase(CString(szPath)) == 0)
		return &m_btnWebFolders;

	return NULL; // we are not in a 'default' directory
}

/************************************************************************/
/*  OnFileNameChange													*/
/*																		*/
/*  Created:     31:3:2001												*/
/*  Author:      David Wulff											*/
/*  Description: Called when the file name is changed or a new file is	*/
/*				 .. selected.											*/
/*	Revisions:	 27:7:2001 - David Wulff, Clears the preview panel when	*/
/*				 .. the selection changes								*/
/************************************************************************/
void BXFileDialog::OnFileNameChange()
{
	CString strFilePath = (LPCSTR)GetPathName();
	SHFILEINFO shfi;
	CListCtrl* pLCtrl = GetListCtrl();
	POSITION pos = pLCtrl->GetFirstSelectedItemPosition();

	// we wont bother checking for multiple selections, as we can't preview
	// .. mulitple files!
	if (pos != NULL)
	{
		CString strSelName = pLCtrl->GetItemText(pLCtrl->GetNextSelectedItem(pos), 0);
		
		// HACK [DW]: Not the best way to do this! [3/8/2001]
		if (strSelName.Find(_T(".")) == -1)
		{
			if(m_bPreview)
				m_strPreviewPath = _T("\0"); // set image file to null
			
			InvalidateRect(PreviewRect);

			return;
		}
	}
	
	if (!GetFileName().IsEmpty())
	{
		// if we have selected a shortcut, we must resolve it first
		if (SHGetFileInfo((LPCSTR)strFilePath, 0, &shfi, sizeof(shfi),
			SHGFI_DISPLAYNAME | SHGFI_TYPENAME) &&
			!lstrcmp(shfi.szTypeName, "Shortcut"))
		{
			ResolveShortcut(strFilePath);
		}
		
		if(m_bPreview)
			m_strPreviewPath = strFilePath;
		
		InvalidateRect(PreviewRect);
	}
}

/************************************************************************/
/*  OnFolderChange														*/
/*																		*/
/*  Created:     31:3:2001												*/
/*  Author:      David Wulff											*/
/*  Description: Called when the folder is changed						*/
/*	Revisions:	 04:8:2001 - David Wulff, only select a sidebar button	*/
/*				 .. after initialisation if the directory is selected	*/
/************************************************************************/
void BXFileDialog::OnFolderChange()
{
	// if a 'default' directory is selected, activate the appropriate
	// .. sidebar button
	SetActiveButton(GetActiveButton());
}

/************************************************************************/
/*  OnClickedPreview													*/
/*																		*/
/*  Created:     31:3:2001												*/
/*  Author:      David Wulff											*/
/*  Description: Called when the 'Preview'	checkbox is clicked			*/
/*	Revisions:	 														*/
/************************************************************************/
void BXFileDialog::OnClickedPreview()
{
	m_bPreview = checkBox.GetCheck() == 1 ? TRUE : FALSE;
}

/************************************************************************/
/*  OnPaint																*/
/*																		*/
/*  Created:     31:3:2001												*/
/*  Author:      David Wulff											*/
/*  Description: WM_PAINT handler										*/
/*	Revisions:	 														*/
/************************************************************************/
void BXFileDialog::OnPaint() 
{
	CPaintDC dc(this);
	
	// if we are drawing the image preview, draw a 3D border to simulate
	// .. a preview control, and render the image within in
	if (m_bShowPreview)
	{
		// deflate rect to include border
		CRect rect(PreviewRect.left + 1, PreviewRect.top + 1,
			PreviewRect.right - 1, PreviewRect.bottom - 1);
		
		dc.Draw3dRect(&PreviewRect,::GetSysColor(COLOR_BTNSHADOW),
			::GetSysColor(COLOR_BTNHILIGHT));
		
		if(m_bPreview)
			DrawImage(&dc, m_strPreviewPath, PreviewRect.CenterPoint(),
			GetParent()->m_hWnd, rect);
	}
	
	// if we are using the VS.NET UI style, we must draw the sidebar
	// .. border ourselves
	if (!bDotNetUI)
	{
		CRect rcWnd;
		CWnd* pWndOutLookBar = GetDlgItem(IDC_OUTLOOK_BAR_PLACEHOLDER);
		
		pWndOutLookBar->GetWindowRect(&rcWnd);
		ScreenToClient(&rcWnd);
		rcWnd.top += (m_btnHeight * 5);
		
		dc.Draw3dRect(&rcWnd, ::GetSysColor(COLOR_BTNSHADOW),
			::GetSysColor(COLOR_BTNHILIGHT));
		dc.FillRect(&rcWnd, &CBrush(::GetSysColor(COLOR_APPWORKSPACE)));
	}
}

/************************************************************************/
/*  OnHistoryClicked													*/
/*																		*/
/*  Created:     31:3:2001												*/
/*  Author:      David Wulff											*/
/*  Description: Called when the specified side bar button is clicked	*/
/*	Revisions:	 														*/
/************************************************************************/
void BXFileDialog::OnHistoryClicked()
{
	SetSpecialDirectory(CSIDL_RECENT);
	SetActiveButton(&m_btnHistory);
}

/************************************************************************/
/*  OnPersonalClicked													*/
/*																		*/
/*  Created:     31:3:2001												*/
/*  Author:      David Wulff											*/
/*  Description: Called when the specified side bar button is clicked	*/
/*	Revisions:	 														*/
/************************************************************************/
void BXFileDialog::OnPersonalClicked()
{
	SetSpecialDirectory(CSIDL_PERSONAL);
	SetActiveButton(&m_btnPersonal);
}

/************************************************************************/
/*  OnDesktopClicked													*/
/*																		*/
/*  Created:     31:3:2001												*/
/*  Author:      David Wulff											*/
/*  Description: Called when the specified side bar button is clicked	*/
/*	Revisions:	 														*/
/************************************************************************/
void BXFileDialog::OnDesktopClicked()
{
	SetSpecialDirectory(CSIDL_DESKTOP);
	SetActiveButton(&m_btnDeskTop);
}

/************************************************************************/
/*  OnFavoritesClicked													*/
/*																		*/
/*  Created:     31:3:2001												*/
/*  Author:      David Wulff											*/
/*  Description: Called when the specified side bar button is clicked	*/
/*	Revisions:	 														*/
/************************************************************************/
void BXFileDialog::OnFavoritesClicked()
{
	SetSpecialDirectory(CSIDL_FAVORITES);
	SetActiveButton(&m_btnFavourites);
}

/************************************************************************/
/*  OnWebFoldersClicked													*/
/*																		*/
/*  Created:     31:3:2001												*/
/*  Author:      David Wulff											*/
/*  Description: Called when the specified side bar button is clicked	*/
/*	Revisions:	 														*/
/************************************************************************/
void BXFileDialog::OnWebFoldersClicked()
{
	SetSpecialDirectory(CSIDL_NETHOOD);
	SetActiveButton(&m_btnWebFolders);
}

/************************************************************************/
/*  SetSpecialDirectory													*/
/*																		*/
/*  Created:     31:3:2001												*/
/*  Author:      David Wulff											*/
/*  Description: Navigates to a passed shell director based on the side */
/*				 .. bar button pressed.									*/
/*	Revisions:	 														*/
/************************************************************************/
void BXFileDialog::SetSpecialDirectory(int nFolder)
{
	LPITEMIDLIST lpIDList;
	
	// get the "special folder" path for the passed folder
	SHGetSpecialFolderLocation(0, nFolder, &lpIDList);
	SHGetPathFromIDList(lpIDList, m_szFile);
	
	CWnd* pWnd = GetParent()->GetDlgItem(edt1);
	CListCtrl* pLCtrl = (CListCtrl*)GetParent()->GetDlgItem(lst1);
	
	// Simulate a refresh to clear the current file name
	// .. this can take a LONG time if the history folder is selected!
	//
	// If you find a better way of doing this, please let me know.
	pLCtrl->PostMessage(WM_KEYDOWN,VK_F5,0x0020001);
	pLCtrl->PostMessage(WM_KEYUP,VK_F5,0xC0020001);
	
	// Add selection to edit box
	pWnd->SetWindowText(m_szFile);
	
	// Simulate a 'Return' key to make selection
	m_bClear = TRUE;
	pWnd->PostMessage(WM_KEYDOWN,VK_RETURN,0x0020001);
	pWnd->PostMessage(WM_KEYUP,VK_RETURN,0xC0020001);
}

/************************************************************************/
/*  SetActiveButton														*/
/*																		*/
/*  Created:     31:3:2001												*/
/*  Author:      Norm Almond											*/
/*  Description: Sets the currently active side bar button				*/
/*	Revisions:	 														*/
/************************************************************************/
void BXFileDialog::SetActiveButton(BXSelBtn* btn)
{
	m_btnHistory.SetState(FALSE);
	m_btnPersonal.SetState(FALSE);
	m_btnDeskTop.SetState(FALSE);
	m_btnFavourites.SetState(FALSE);
	m_btnWebFolders.SetState(FALSE);
	
	// if we don't have a valid button, don't select any of them
	if (btn != NULL)
		btn->SetState(TRUE);
}

/************************************************************************/
/*  OnSize																*/
/*																		*/
/*  Created:     31:3:2001												*/
/*  Author:      David Wulff, Norm Almond, Tak^Shoran					*/
/*  Description: WM_SIZE handler.										*/
/*	Revisions:	 														*/
/************************************************************************/
void BXFileDialog::OnSize(UINT nType, int cx, int cy) 
{	
	CRect rc;	
	
	CFileDialog::OnSize(nType, cx, cy);
	
	GetWindowRect(&rc);
	
	// The first time the dialog is sized needs special handling (we set
	// .. up the new OK button here, for example.
	if (m_bFirst)
	{	
		InitialReSize(0, 0, cx, cy);
		m_bFirst = false;		
	}
	else if (m_bSizing)
		ReSize(rc.left, rc.top, cx, cy);
}

/************************************************************************/
/*  InitialReSize														*/
/*																		*/
/*  Created:     31:3:2001												*/
/*  Author:      David Wulff, Norm Almond								*/
/*  Description: Repositions and subclasses, etc, the dialog controls	*/
/*				 .. when the dialog is first intialised.				*/
/*	Revisions:	 														*/
/************************************************************************/
void BXFileDialog::InitialReSize(int x, int y, int cx, int cy) 
{
	// position "Look In" label and combo, and the toolbar
	CRect rcDlgCl;
	GetClientRect(&rcDlgCl);
	
	CWnd* pWndOutLookBar = GetDlgItem(IDC_OUTLOOK_BAR_PLACEHOLDER);
	CRect rcOLBClient, rcOLBWindow, rcWnd;
	pWndOutLookBar->GetClientRect(rcOLBClient);
	pWndOutLookBar->GetWindowRect(rcOLBWindow);
	
	int eRight = rcDlgCl.right - CONTROL_GAP;
	int eLeft = rcDlgCl.left + CONTROL_GAP;
	int eTop = rcDlgCl.top + CONTROL_GAP;
	int eBot = rcDlgCl.bottom - CONTROL_GAP;
	int iTmp;
	
	CRect rcWin;
	GetWindowRect(&rcWin);
	
	iTmp = eLeft + m_SBWidth + CONTROL_GAP;
	
	CWnd* pListCtrl = GetParent()->GetDlgItem(lst1);
	CWnd* pComboCtrl = GetParent()->GetDlgItem(cmb2);
	CWnd* pLabel = GetParent()->GetDlgItem(stc4);	
	
	pLabel = GetParent()->GetDlgItem(stc4);
	pLabel->SetWindowPos(0, 40, eTop + 3, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
	
	// TODO [DW]: Replace this toolbar with our own, as differnt OS versions
	// .. have different command available. [4/8/2001]
	HWND hWnd = FindWindowEx(GetParent()->m_hWnd, NULL,
		"ToolbarWindow32", NULL);
	CWnd wndToolbar;
	wndToolbar.Attach(hWnd);
	
	pComboCtrl->SetWindowPos(0, iTmp, eTop, 250, 180, SWP_NOZORDER);
	
	wndToolbar.SetWindowPos(0, iTmp + CONTROL_GAP + 250, eTop, 0, 0,
		SWP_NOSIZE | SWP_NOZORDER);
	wndToolbar.Detach();

	// Offset controls
	CWnd* pWnd;
	CWnd* pBar = GetDlgItem(IDC_OUTLOOK_BAR_PLACEHOLDER);
	CRect rcBar;
	pBar->GetWindowRect(rcBar);
	
	if (m_bShowPreview)
		pListCtrl->SetWindowPos(0, iTmp, eTop + 22 + CONTROL_GAP,
		eLeft + 250 - CONTROL_GAP,
		eBot - (CONTROL_GAP * 3) - (22 * 2) - eTop - 22, SWP_NOZORDER);
	else
		pListCtrl->SetWindowPos(0, iTmp, eTop + 22 + CONTROL_GAP,
		eRight - iTmp, eBot - (CONTROL_GAP * 3) - (22 * 2) - eTop - 22,
		SWP_NOZORDER);
	
	pWnd = GetParent()->GetDlgItem(stc3); // File Name label
	pWnd->SetWindowPos(0, iTmp, eBot - (CONTROL_GAP * 2) - (18 * 2), 60,
		15, SWP_NOZORDER);
	
	pWnd = GetParent()->GetDlgItem(stc2); // File type label
	pWnd->SetWindowPos(0, iTmp, eBot - 18, 60, 15, SWP_NOZORDER);
	
	iTmp += 70;
	
	pWnd = GetParent()->GetDlgItem(edt1); // File Name
	pWnd->SetWindowPos(0, iTmp, eBot - CONTROL_GAP - (22 * 2),
		(eRight - 90 - 30 - iTmp), 22, SWP_NOZORDER);
	
	pWnd = GetParent()->GetDlgItem(cmb1); // File Type
	pWnd->SetWindowPos(0, iTmp, eBot - 22, (eRight - 90 - 30 - iTmp), 150,
		SWP_NOZORDER);
	
	// Add our bitmap menu button
	HideControl(IDOK); // undocumented CFileDialog function
	
	if (m_IsOpen)
	{
		m_btn.Create("&Open",WS_TABSTOP | WS_CHILD | BS_DEFPUSHBUTTON,
			CRect(0, 0, 0, 0), this, ID_START);
		m_btn.SetButtonImage(IDB_FILEOPEN, RGB(255,0,255));
	}
	else
	{
		m_btn.Create("&Save",WS_TABSTOP | WS_CHILD | BS_DEFPUSHBUTTON,
			CRect(0, 0, 0, 0), this, ID_START);
		m_btn.SetButtonImage(IDB_FILESAVE, RGB(255,0,255));
	}		
	
	m_btn.SetWindowPos(0, eRight - 90, eBot - CONTROL_GAP - (22 * 2), 90,
		22, SWP_NOZORDER);
	m_btn.ShowWindow(SW_SHOW);
	
	
	pWnd = GetParent()->GetDlgItem(IDCANCEL);
	pWnd->SetWindowPos(0, eRight - 90, eBot - 22, 90, 22, SWP_NOZORDER);

	// Add outlook style directory selection buttons
	pWndOutLookBar->SetWindowPos(0, eLeft, eTop + 22 + CONTROL_GAP,
		m_SBWidth, eBot - eTop - CONTROL_GAP - 22, SWP_NOZORDER);
	
	iTmp = rcOLBClient.Width();
	pWndOutLookBar->GetClientRect(rcOLBClient);
	
	m_btnHeight = rcOLBClient.Height() /  5;
	
	rcWnd.SetRect(0, 0, iTmp, m_btnHeight);
	
	if (!m_btnHistory)
	{
		m_btnHistory.Create("History", WS_CHILD | WS_VISIBLE, rcWnd,
			pWndOutLookBar, ID_BTN_HISTORY, &m_IL,0);  
		m_btnHistory.m_Enabled = TRUE;
	}
	
	rcWnd.OffsetRect(0, m_btnHeight);
	
	if (!m_btnPersonal)
	{
		m_btnPersonal.Create("My Documents", WS_CHILD | WS_VISIBLE, rcWnd,
			pWndOutLookBar, ID_BTN_PERSONAL, &m_IL,2);
		m_btnPersonal.m_Enabled = TRUE;
	}
	
	rcWnd.OffsetRect(0, m_btnHeight);
	
	if (!m_btnDeskTop)
	{
		m_btnDeskTop.Create("Desktop", WS_CHILD | WS_VISIBLE, rcWnd,
			pWndOutLookBar, ID_BTN_DESKTOP, &m_IL,1);
		m_btnDeskTop.m_Enabled = TRUE;
	}
	
	rcWnd.OffsetRect(0, m_btnHeight);
	
	if (!m_btnFavourites)
	{
		m_btnFavourites.Create("Favourites", WS_CHILD | WS_VISIBLE, rcWnd,
			pWndOutLookBar, ID_BTN_FAVORITES, &m_IL,3);
		m_btnFavourites.m_Enabled = TRUE;
	}
	
	rcWnd.OffsetRect(0, m_btnHeight);
	if (!m_btnWebFolders)
	{
		m_btnWebFolders.Create("Web Folders", WS_CHILD | WS_VISIBLE, rcWnd,
			pWndOutLookBar, ID_BTN_WEBFOLDERS, &m_IL,4);
		m_btnWebFolders.m_Enabled = TRUE;
	}
	
	// Added for preview
	checkBox.Create("&Preview",
		(m_bShowPreview ? WS_CHILD|WS_VISIBLE : WS_CHILD) | WS_TABSTOP |
		BS_AUTOCHECKBOX, CRect(0,0,0,0), this, IDC_CHECK_PREVIEW);
	checkBox.SetWindowPos(0,eRight - 90,
		eBot - (CONTROL_GAP * 3) - (22 * 2) - 22, 90, 22, SWP_NOZORDER);
	checkBox.SetFont(GetFont());
	checkBox.SetCheck(m_bPreview);
	
	PreviewRect = CRect(
		(eLeft * 2) + m_SBWidth + 250 + CONTROL_GAP,
		eTop + 22 + CONTROL_GAP,
		eRight,
		eBot - (CONTROL_GAP * 4) - (22 * 3)
		);
	
	m_nPreviewBoxWidth = PreviewRect.Width();
}

/************************************************************************/
/*  OnHelpInfo															*/
/*																		*/
/*  Created:     31:3:2001												*/
/*  Author:      David Wulff											*/
/*  Description: WM_HELPINFO handler.									*/
/*	Revisions:	 														*/
/************************************************************************/
BOOL BXFileDialog::OnHelpInfo(HELPINFO* pHelpInfo) 
{
#ifdef _USE_HTMLHELP
	if (pHelpInfo->iCtrlId == IDC_CHECK_PREVIEW ||
		pHelpInfo->iCtrlId == ID_BTN_HISTORY ||
		pHelpInfo->iCtrlId == ID_BTN_PERSONAL ||
		pHelpInfo->iCtrlId == ID_BTN_DESKTOP ||
		pHelpInfo->iCtrlId == ID_BTN_FAVORITES ||
		pHelpInfo->iCtrlId == ID_BTN_WEBFOLDERS)
		DoPopupHelp(pHelpInfo->iCtrlId, pHelpInfo->MousePos);
	else
		CFileDialog::OnHelpInfo(pHelpInfo);
#else
	
	CFileDialog::OnHelpInfo(pHelpInfo);
#endif
	
	return TRUE;
}

/************************************************************************/
/*  DoPopupHelp															*/
/*																		*/
/*  Created:     31:3:2001												*/
/*  Author:      David Wulff											*/
/*  Description: If applicable, will show a popup help window for the 	*/
/*				 .. non-standard controls this dialog adds.				*/
/*	Revisions:	 														*/
/************************************************************************/
void BXFileDialog::DoPopupHelp(int nID, CPoint pt)
{
	if (nID != IDC_STATIC) // Don't show help for un-named controls
	{
		CString strString;
		
		strString.LoadString(nID);
		DoPopupHelp(strString, pt);
	}
}

/************************************************************************/
/*  DoPopupHelp															*/
/*																		*/
/*  Created:     31:3:2001												*/
/*  Author:      David Wulff											*/
/*  Description: If applicable, will show a popup help window for the 	*/
/*				 .. non-standard controls this dialog adds.				*/
/*	Revisions:	 														*/
/************************************************************************/
void BXFileDialog::DoPopupHelp(CString strString, CPoint pt)
{
#ifdef _USE_HTMLHELP
	HH_POPUP hPop;
	CString str;
	
	hPop.cbStruct = sizeof(HH_POPUP);
	hPop.hinst = 0;
	
	hPop.idString = 0;
	
	if (strString == _T(""))
		hPop.pszText = "No help topic is associated with this item";
	else
		hPop.pszText = strString;
	
	hPop.pt = pt;
	hPop.clrForeground = GetSysColor(COLOR_INFOTEXT);
	hPop.clrBackground = GetSysColor(COLOR_INFOBK);
	hPop.rcMargins = CRect(-1, -1, -1, -1);
	hPop.pszFont = "Arial, 8, , ";
	
	HtmlHelp(NULL, NULL, HH_DISPLAY_TEXT_POPUP, (DWORD) (HH_POPUP*) &hPop);
#endif
}

void BXFileDialog::OnOk()
{
}

void BXFileDialog::OnMyOk(UINT nID)
{
	// Simulate the user hiting the enter key
	PostMessage(WM_KEYDOWN,VK_RETURN,0x0020001);
	PostMessage(WM_KEYUP,VK_RETURN,0xC0020001);

	EndDialog(nID);
}

void BXFileDialog::OnShowPreview()
{
	m_bShowPreview = !m_bShowPreview;
	
	CRect rcDlg;
	GetWindowRect(rcDlg);
	
	ReSize(rcDlg.left, rcDlg.top, rcDlg.Width(), rcDlg.Height());
}

/************************************************************************/
/*  CenterWindowOnOwner													*/
/*																		*/
/*  Created:     31:3:2001												*/
/*  Author:      Joel Bernard											*/
/*  Description: A better center window function						*/
/*	Revisions:	 														*/
/************************************************************************/
void BXFileDialog::CenterWindowOnOwner(CWnd *pWndToCenterOn)
{
	// Get the client rectangle of the window on which we want to center
	// Make sure the pointer is not NULL first
	if (pWndToCenterOn == NULL)
		return;
	
	CRect rectToCenterOn;
	pWndToCenterOn->GetWindowRect(&rectToCenterOn);
	
	// Get this window's area
	CRect rectSubDialog;
	GetWindowRect(&rectSubDialog);
	
	// Now rectWndToCenterOn contains the screen rectangle of the window
	// .. pointed to by pWndToCenterOn.  Next, we apply the same centering
	// .. algorithm as does CenterWindow()
	
	// find the upper left of where we should center to
	int xLeft = (rectToCenterOn.left + rectToCenterOn.right) / 2 -
		rectSubDialog.Width() / 2;
	int yTop = (rectToCenterOn.top + rectToCenterOn.bottom) / 2 -
		rectSubDialog.Height() / 2;
	
	// Move the window to the correct coordinates with SetWindowPos()
	GetParent()->SetWindowPos(NULL, xLeft, yTop, -1, -1,
		SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
}

/************************************************************************/
/*  ResolveShortcut														*/
/*																		*/
/*  Created:     31:3:2001												*/
/*  Author:      Anatoly Danekin										*/
/*  Description: Resolves the passed shortcut							*/
/*	Revisions:	 														*/
/************************************************************************/
BOOL BXFileDialog::ResolveShortcut(CString& strFile)
{
	HRESULT         hres;
	IShellLink*     psl;
	char            szGotPath[MAX_PATH];
	WIN32_FIND_DATA wfd;
	
	// Get a pointer to the IShellLink interface.
	hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
		IID_IShellLink, (void**)&psl);
	
	if (SUCCEEDED(hres))
	{
		IPersistFile* ppf;
		
		// Get a pointer to the IPersistFile interface.
		hres = psl->QueryInterface(IID_IPersistFile, (void**)&ppf);
		
		if (SUCCEEDED(hres))
		{
			WORD wsz[MAX_PATH];
			
			// Ensure that the string is Unicode.
			MultiByteToWideChar(CP_ACP, 0, (LPCSTR)strFile, -1, wsz,
				MAX_PATH);
			
			// Load the shortcut.
			hres = ppf->Load(wsz, STGM_READ);
			if (SUCCEEDED(hres))
			{
				// Resolve the link.
				hres = psl->Resolve(GetParent()->m_hWnd, SLR_ANY_MATCH);
				if (SUCCEEDED(hres))
				{
					// Get the path to the link target.
					hres = psl->GetPath(szGotPath, MAX_PATH,
						(WIN32_FIND_DATA*)&wfd, SLGP_SHORTPATH );
					if (SUCCEEDED(hres))
						strFile = szGotPath;
				}
			}
			// Release the pointer to the IPersistFile interface.
			ppf->Release();
		}
		
		// Release the pointer to the IShellLink interface.
		psl->Release();
	}
	
	return SUCCEEDED(hres);
}

// a couple of helper functions:
int GetBiggest(int n1, int n2)
{
	if (n1 > n2)	return n1;
	if (n2 > n1)	return n2;
	return -1; // equal
}

float GetSmallestF(float f1, float f2)
{
	if (f1 < f2)	return f1;
	if (f2 < f1)	return f2;
	return -1.0f; // equal
}

/************************************************************************/
/*  DrawImage															*/
/*																		*/
/*  Created:     31:3:2001												*/
/*  Author:      Wes Rogers, David Wulff								*/
/*  Description: Draws the specified image in the specified rectangle	*/
/*	Revisions:	 27:7:2001 - David Wulff, image now resizes properly and*/
/*				 .. centers												*/
/************************************************************************/
BOOL BXFileDialog::DrawImage(CDC* pDC, CString csFile, CPoint ptCenter,
							 HWND hWnd, CRect rectImage)
{
    if (pDC == NULL || csFile.IsEmpty() || hWnd == NULL)
        return FALSE;
	
    LPPICTURE gpPicture = NULL;
	
    if (LoadPictureFile((LPCTSTR)csFile, &gpPicture))
    {
        //Get width and height of picture
        long hmWidth  = 0;
        long hmHeight = 0;
		
        gpPicture->get_Width(&hmWidth);
        gpPicture->get_Height(&hmHeight);
		
		// [DW - 27:7:2001]
		CSize szImg(hmWidth, hmHeight);
		pDC->HIMETRICtoLP(&szImg);
		
		rectImage.DeflateRect(0, 0, 1, 1);
		
		int nLeft, nTop, nRight, nBottom;
		CRect rcDest = rectImage, rcSrc = CRect(0, 0, szImg.cx, szImg.cy);
		
		// if the image wont fit without being shrunk...
		if (GetBiggest(rcDest.Width(), rcSrc.Width()) == rcSrc.Width() ||
			GetBiggest(rcDest.Height(), rcSrc.Height()) == rcSrc.Height())
		{
			float nDX = rcDest.Width(), nDY = rcDest.Height(),
				nSX = rcSrc.Width(), nSY = rcSrc.Height();
			float nModX = nDX / nSX;
			float nModY = nDY / nSY;
			float nMod = GetSmallestF(nModX, nModY);
			
			// float -> int conversion
			nRight = rcSrc.Width() * nMod;
			nBottom = -(rcSrc.Height() * nMod);
			nLeft = rcDest.left + (rcDest.Width() / 2) - (nRight / 2);
			nTop = rcDest.top + (rcDest.Height() / 2) - (nBottom / 2);
		}
		else
		{
			// center the image
			nLeft = rcDest.left + (rcDest.Width() / 2) - (szImg.cx / 2);
			nTop = rcDest.top + (rcDest.Height() / 2) - (szImg.cy / 2) + szImg.cy;
			nRight = szImg.cx;
			nBottom = -(szImg.cy);
		}
		// [/DW - 27:7:2001]
		
        HRESULT hrP = gpPicture->Render(pDC->m_hDC, nLeft, nTop, nRight, nBottom,
			0, 0, hmWidth, hmHeight, NULL);
		
        gpPicture->Release();
		
        if (SUCCEEDED(hrP))
            return TRUE;
    }
	
    return FALSE;
}

/************************************************************************/
/*  LoadPictureFile														*/
/*																		*/
/*  Created:     31:3:2001												*/
/*  Author:      Wes Rogers												*/
/*  Description: Loads the specified picture into the passed LPPICTURE	*/
/*	Revisions:	 														*/
/************************************************************************/
BOOL BXFileDialog::LoadPictureFile(LPCTSTR szFile, LPPICTURE* pgpPicture)
{
    // open file
    HANDLE hFile = CreateFile(szFile, GENERIC_READ, 0, NULL, OPEN_EXISTING,
		0, NULL);
	
    if (hFile == INVALID_HANDLE_VALUE)
        return FALSE;
	
    // get file size
    DWORD dwFileSize = GetFileSize(hFile, NULL);
	
    if (dwFileSize == (DWORD)-1)
    {
        CloseHandle(hFile);
        return FALSE;
    }
	
    LPVOID pvData = NULL;
	
    // alloc memory based on file size
    HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, dwFileSize);
	
    if (hGlobal == NULL)
    {
        CloseHandle(hFile);
        return FALSE;
    }
	
    pvData = GlobalLock(hGlobal);
	
    if (pvData == NULL)
    {
        GlobalUnlock(hGlobal);
        CloseHandle(hFile);
        return FALSE;
    }
	
    DWORD dwBytesRead = 0;
	
    // read file and store in global memory
    BOOL bRead = ReadFile(hFile,
		pvData,
		dwFileSize,
		&dwBytesRead,
		NULL);
	
    GlobalUnlock(hGlobal);
    CloseHandle(hFile);
	
    if (!bRead)
        return FALSE;
	
    LPSTREAM pstm = NULL;
	
    // create IStream* from global memory
    HRESULT hr = CreateStreamOnHGlobal(hGlobal, TRUE, &pstm);
	
    if (!(SUCCEEDED(hr)))
    {
        if (pstm != NULL)
            pstm->Release();
		
        return FALSE;
    }
	
    else if (pstm == NULL)
        return FALSE;
	
	// Create IPicture from image file
	if (*pgpPicture)
		(*pgpPicture)->Release();
	
    hr = ::OleLoadPicture(pstm,
		dwFileSize,
		FALSE,
		IID_IPicture,
		(LPVOID *)&(*pgpPicture));
	
    if (!(SUCCEEDED(hr)))
    {
		pstm->Release();
        return FALSE;
    }
	
    else if (*pgpPicture == NULL)
    {
		pstm->Release();
        return FALSE;
    }
	
    pstm->Release();
	
    return TRUE;
}

/************************************************************************/
/*  ReSize																*/
/*																		*/
/*  Created:     31:3:2001												*/
/*  Author:      David Wulff, Tak^Shoran								*/
/*  Description: Called by the WM_SIZING override to reposition the		*/
/*				 .. dialog's controls.									*/
/*	Revisions:	 														*/
/************************************************************************/
void BXFileDialog::ReSize(int x, int y, int cx, int cy)
{
	// note: the listctrl is automatically resized by the underlying class
	CWnd* pWnd;
	CRect rcDlgCl, rcWin, rc1, rc2, rcLoc;
	
	GetClientRect(&rcDlgCl);
	GetWindowRect(&rcWin);
	
	int eRight = rcDlgCl.right - CONTROL_GAP;
	int eLeft = rcDlgCl.left + CONTROL_GAP;
	int eTop = rcDlgCl.top + CONTROL_GAP;
	int eBot = rcDlgCl.bottom - CONTROL_GAP;
	
	// Move preview box
	if (m_bShowPreview)
	{
		CWnd* pListCtrl = GetParent()->GetDlgItem(lst1);
		CRect rcList;
		pListCtrl->GetClientRect(&rcList);
		
		checkBox.SetWindowPos(0, eRight - 98,
			eBot - (CONTROL_GAP * 4) - (22 * 4), 90, 22, SWP_NOZORDER);
		
		PreviewRect.bottom = eBot - (CONTROL_GAP * 5) - (22 * 4);
		PreviewRect.right = eRight - CONTROL_GAP - 3;
		PreviewRect.left = PreviewRect.right - m_nPreviewBoxWidth;
	}
	
	// Move button
	m_btn.GetWindowRect(&rc1);
	ScreenToClient(&rc1);
	
	pWnd = GetParent()->GetDlgItem(IDCANCEL);
	pWnd->GetWindowRect(&rc2);
	ScreenToClient(&rc2);
	
	rc1.left  = rc2.left;
	rc1.right = rc2.right;
	
	m_btn.SetWindowPos(0, rc1.left, rc1.top, rc1.Width(), rc1.Height(),
		SWP_NOZORDER);
	
	// Move outbar
	CWnd* pWndOutLookBar = GetDlgItem(IDC_OUTLOOK_BAR_PLACEHOLDER);
	pWndOutLookBar->GetWindowRect(&rc1);
	ScreenToClient(&rc1);
	
	rc1.bottom = rcDlgCl.Height() - rc1.top;
	
	pWndOutLookBar->SetWindowPos(0, rc1.left, rc1.top, rc1.Width(),
		rc1.Height(), SWP_NOZORDER);
	
	Invalidate();
}

/************************************************************************/
/*  SetAppearance														*/
/*																		*/
/*  Created:     31:3:2001												*/
/*  Author:      David Wulff											*/
/*  Description: Pass in the eAppearance to use	when drawing the dialog	*/
/*				 .. and buttons, etc.									*/
/*	Revisions:	 														*/
/************************************************************************/
void BXFileDialog::SetAppearance(eAppearance eApp)
{
	m_eAppearance = eApp;
	bDotNetUI = (m_eAppearance == eAppearance::APPEARANCE_VSDOTNET);
}

/************************************************************************/
/*  OnFileTypeChange													*/
/*																		*/
/*  Created:     27:7:2001												*/
/*  Author:      David Wulff											*/
/*  Description: Handler for the CDN_TYPECHANGE message					*/
/*	Revisions:	 														*/
/************************************************************************/
void BXFileDialog::OnFileTypeChange(DWORD dwNewFilterIndex)
{
	// you can override this function to provide custom control over
	// .. the OK button's drop-down menu, depending on the file type
	// .. selected.
	
	// E.G:
#if 0
	// destroy the current menu (remove all items)
	m_btn.m_menu.DestroyMenu();
	
	// recreate the popup menu
	m_btn.m_menu.CreatePopupMenu();
	
	// add the new items, depending on the file type selected
	switch(dwNewFilterIndex)
	{
	case 0:
		m_btn.AddMenuItem(ID_START,"&Open",0);
		m_btn.AddMenuItem(ID_START+1,"Open with &Filter",0);
		break;
	case 1:
		m_btn.AddMenuItem(ID_START,"&Open",0);
		break;
	case 2:
		m_btn.AddMenuItem(ID_START,"&Open",0);
		m_btn.AddMenuItem(ID_START+1,"Open As &HTML",0);
		break;
	default:
		break; // do nothing
	}
#endif
}

//////////////////////////////////////////////////////////////////////////
// BXFileEdit (public CEdit)
//////////////////////////////////////////////////////////////////////////

/************************************************************************/
/*  BXFileEdit															*/
/*																		*/
/*  Created:     31:3:2001												*/
/*  Author:      David Wulff											*/
/*  Description: Class constructor										*/
/*	Revisions:	 														*/
/************************************************************************/
BXFileEdit::BXFileEdit()
{
}


/************************************************************************/
/*  ~BXFileEdit															*/
/*																		*/
/*  Created:     31:3:2001												*/
/*  Author:      David Wulff											*/
/*  Description: Class destructor										*/
/*	Revisions:	 														*/
/************************************************************************/
BXFileEdit::~BXFileEdit()
{
}

BEGIN_MESSAGE_MAP(BXFileEdit, CEdit)
//{{AFX_MSG_MAP(BXFileEdit)
ON_WM_KEYUP()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/************************************************************************/
/*  OnKeyUp																*/
/*																		*/
/*  Created:     31:3:2001												*/
/*  Author:      David Wulff											*/
/*  Description: WM_KEYUP handler for the new edit control				*/
/*	Revisions:	 														*/
/************************************************************************/
void BXFileEdit::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	if (BXFileDialog::m_bClear)
	{
		SetWindowText("");
		BXFileDialog::m_bClear = FALSE;
		SetSel(0,-1);
	}
	
	CEdit::OnKeyUp(nChar, nRepCnt, nFlags);
}

#pragma warning ( default : 4244 ) // float -> int conversion warnings

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Founder Riverblade Limited
United Kingdom United Kingdom
I haven't always written software for a living. When I graduated from Surrey University in 1989, it was with an Electronic Engineering degree, but unfortunately that never really gave me the opportunity to do anything particularly interesting (with the possible exception of designing Darth Vader's Codpiece * for the UK Army in 1990).
    * Also known as the Standard Army Bootswitch. But that's another story...
Since the opportunity arose to lead a software team developing C++ software for Avionic Test Systems in 1996, I've not looked back. More recently I've been involved in the development of subsea acoustic navigation systems, digital TV broadcast systems, port security/tracking systems, and most recently software development tools with my own company, Riverblade Ltd.

One of my personal specialities is IDE plug-in development. ResOrg was my first attempt at a plug-in, but my day to day work is with Visual Lint, an interactive code analysis tool environment with works within the Visual Studio and Eclipse IDEs or on build servers.

I love lots of things, but particularly music, photography and anything connected with history or engineering. I despise ignorant, intolerant and obstructive people - and it shows...I can be a bolshy cow if you wind me up the wrong way...Laugh | :laugh:

I'm currently based 15 minutes walk from the beach in Bournemouth on the south coast of England. Since I moved here I've grown to love the place - even if it is full of grockles in Summer!

Comments and Discussions