📄 filetreectrl.cpp
字号:
/*
Module : FileTreeCtrl.cpp
Purpose: Implementation for an MFC class which provides a tree control similiar
to the left hand side of explorer
Created: PJN / 25-12-1999
History: PJN / 11-01-2000 1. Added some asserts to HasGotSubEntries
2. Fixed a problem with calling OnDblclk when no tree item is selected
3. Removed an unused variable from SetSelectedPath
PJN / 25-01-2000 1. Minor update to the code in CTreeFileCtrl::OnDblclk to only allow
selected items to be opened.
PJN / 31-01-2000 1. Fixed a problem when you right mouse click over a non - selected item.
The control now implements the same behavior as Explorer for this.
2. Removed check for keyboard invocation of the context menu in OnContextMenu
3. Now displays the context menu over the selected item when invoked via
the keyboard. Again this is the same bahavior as Explorer has.
4. Optimized the code in PreTranslateMessage
5. Fixed a bug in CTreeFileCtrl::OnEndlabeledit
PJN / 02-04-2000 1. Fixed a small bug in CTreeFileCtrl::SetRootFolder
2. Fixed the problem with initialisation errors in the code. Client code must not
explicitly call PopulateTree when the window is created. When used in a dialog
resource this is not necessary as it is called for you in the DDX functions.
PJN / 13-05-2000 1. Fixed a problem where items on the context menu were being invoked for the
wrong item when you right mouse click over an item that is not the selected item.
Behaviour now is that the item is selected prior to showing the context menu.
Now, this is same behaviour as Explorer.
PJN / 12-07-2000 1. Now uses ON_NOTIFY_REFLECT_EX instead of ON_NOTIFY_REFLECT for handling reflected
messages. This allows derived classes to handle these messages also. Thanks to
Christian Dahl for this.
2. Sample app now allows drag drop behaviour to be toggled
3. Fixed a problem whereby two items were left selected after you did a drap /
drop operation. Thanks to Jonathon Ralston for this.
4. Removed function declaration for unused function "InsertDriveItem".
5. Removed an unreferenced variable in InsertFileItem.
6. Tidied up the UpOneLevel functions and made it public.
7. Removed all the message handlers in the sample code which reflect straight
down to the tree control. Instead the OnCmdMsg first routes the message to this
class.
8. Renamed all menu items which CTreeFileCtrl uses to include the prefix TREEFILECTRL
9. Renamed all the methods to more generic names
10. PreTranslateMessage now uses PostMessage instead of calling functions directly.
This allows up to function correctly for derived classes in addition to correctly
disabling items through the OnUpdate mechanism
11. Removed an unreferrenced variable in OnRclick
12. Removed the unreferrenced variable m_hSelItem
13. Optimized a number of expressions by putting the boolean comparisons first
14. m_bAllowRename parameter is now observed for in place editing of an item
15. Now supports hiding of Drive types via the SetDriveHideFlags function. See the
menu options on the Tools menu in the sample program for its usage.
16. Filename masks can now be specifed via the SetFileNameMask method. See the
menu options on the Tools menu in the sample program for its usage.
17. File types can now be specified via the GetFileHideFlags function. See the
menu options on the Tools menu in the sample program for its usage.
18. Fixed a small issue in one of my calls to ::GetKeyState
19. Fixed a bug where programs was crashing if an icon index for it could not
be found.
20. Made many of the methods of CTreeFileCtrl virtual, thus allowable better
use in end user derived classes.
21. Fixed problem where SetSelectedPath(_T("C:\\"), FALSE) was resulting
in the drive being expanded even through FALSE was being sent in to specify
that the item should not be expanded.
22. A virtual "CanDisplayFile" has been added to allow you to decide at runtime
whether or not a certain file is to be displayed.
23. A virtual "CanDisplayFolder" has been added to allow you to decide at
runtime whether or not a certain folder is to be displayed
24. Now optionally displays compressed files in a different color, similiar to
explorer. The color is customizable through the class API.
25. Code has been made smarter so that it does not have to spin up the floppy
disk to determine if there are files on it. It now initially displays a "+"
and only when you try to expand it will it do the actual scan.
PJN / 23-07-2000 1. Fixed a bug where the expansion state of the selected item was not being
preserved across refreshes.
2. Now includes full support for Next / Prev support similiar to Windows
Explorer with the Desktop Update.
3. Updated sample app to have some useful toolbars.
4. Changing any tree settings which can affect its appearance now force
a refresh of its contents.
5. ItemToPath method has been made const.
6. Addition of PathToItem method
7. Auto refresh of items is now provided for by means of change notification
threads. This is configurable via the SetAutoRefresh method.
8. The root folder of the tree control can now be changed from the sample app
9. Fixed a bug in SetRootFolder when passed an empty folder
10. Fixed a bug where the system image list was not being initialized correctly
if the user did not have a "C:\\" drive. This could occur on NT/Windows2000
11. Fixed a bug in IsFile and IsFolder which was causing invalid files or folders
to appear valid.
12. Deleted items are now removed upon expansion. Also if the item being expanded was
deleted and it was the only child, then its parent has the "-" expansion button removed
13. Removable drive nodes are collapsed back to their root nodes if their media is
changed in the intervening time when a node expansion occurs.
14. Wait cursor is now displayed while a refresh is taking place.
15. A "OnSelectionChanged" virtual function has now been provided
16. Sample app's icon has been made the same as Explorers.
17. Sample app now displays the path name of the currently selected item in the tree control.
18. Fixed a bug in IsCompressed
19. items are now deleted when selected if they do not exist.
PJN / 05-09-2000 1. Fixed a bug in CTreeFileCtrl::IsFile and CTreeFileCtrl::IsFolder
PJN / 20-09-2000 1. Control now includes DECLARE_DYNCREATE thereby allowing it to be used
in code which requires this such as Stingray's SEC3DTabWnd. Thanks to Petter Nilsen for
pointing out this omission
PJN / 02-10-2000 1. Fixed a stack overwrite problem in CSystemImageList::CSystemImageList
2. Removed an unreferrenced variable in CTreeFileCtrl::OnSelChanged
3. Removed an unreferrenced variable in CTreeFileCtrl::OnItemExpanding
4. Changed the SendMessage in CTreeFileCtrl::OnDblClk to prevent a crash
which was occurring when the open call sometimes caused a refresh call
which changed the tree items at times. When the double click message handler
continued it then caused item expand notifications for items already deleted
and of course crashes.
5. Removed an unreferrenced variable in CTreeFileCtrl::EndDragging
6. Removed an unreferrenced variable in CTreeFileCtrl::KillNotificationThread
7. Sample app now remembers the selected path and its expansion state across
invocations.
PJN / 05-05-2001 1. Updated copright message.
2. Fixed a resource leak where icon resources were not being released. Thanks to Jay Kohler for
spotting this problem
PJN / 05-08-2001 1. You can now optionally display Network Neighborhood
2. You can now turn on / off display of file extensions.
3. You can now display shared items with a different icon
4. Friendly names can now be displayed for drives.
PJN / 11-08-2001 1. Improved checking to see if action is allowed in Rename and Delete
2. Fixed a bug in OnBeginLabelEdit
3. Fixed a problem in OnEndLabelEdit which was causing renames to fail when filename extensions
were not being shown.
PJN / 11-08-2001 1. Fixed a bug in OnSelChanged which was causing a crash when you right click on an empty area of the control.
Thanks to Eli Fenton for spotting this one.
2. The control now by default shows drives as children of "My Computer" just like in Explorer.
3. When you display a rooted directory in the control, you now have the option of displaying the root
folder in the control as the root item. Thanks to Eli Fenton for suggesting this.
PJN / 26-10-2001 1. Fixed some stability problems with the code. This was due to adding items to the system image list.
This is normally a very bad thing. Instead now the code uses TreeView custom draw (just like the blue color
for compresed items) to draw the icons for the Network Neighborhood items. Thanks to Darken Screamer and
Timo Haberkern for spotting this problem.
PJN / 24-12-2001 1. Fixed a copy and paste bug in GoForward. Thanks to Michael T. Luongo for this fix.
2. Now allows encrypted files to be displayed in a different color
3. Fixed memory leak which was occuring when control was being used in a dialog
4. Fixed a problem with the calculation of idents when the style "TVS_LINESATROOT" is used.
PJN / 16-02-2002 1. Updated copyright message
2. Fixed a drag/drop problem which caused the tree state to be inconsistent after the file was dropped.
3. Fixed a bug in the refresh code which was causing it to not reselect the selected node
after the refresh occurs. Thanks to John No雔 for this fix.
4. Fixed a problem where the custom draw icons for network nodes were not being drawn in the correct
positions when scrollbars were present in the control. Again thanks to John No雔 for this fix.
5. Fixed a bug in SetSelectedPath which would not display the correct selection if the node we
want to select has been deleted due to the node becoming deleted when it was previously collapsed.
Thanks to Franz Fackelmann and John No雔 for spotting this problem.
PJN / 05-06-2002 1. Implemented function "SetUsingDifferentColorForEncrypted" which was declared but had no
implementation.
2. Fixed report of uninitialized member variable "m_nTimerID". Thanks to Emil Isberg for spoting this.
PJN / 07-08-2002 1. Fixed a bug in the sample app which ships with the class which was occuring when you compiled
the code in Visual Studio.Net. This was due to MS changing the location oleimpl2.h header file. Thanks
to Darren Schroeder for spotting this problem.
PJN / 22-09-2002 1. Removed a number of unreferrenced variables from the code, as highlighted by Visual Studio.Net. Thanks
to Bill Johnson for spotting this.
Copyright (c) 1999 - 2002 by PJ Naughter. (Web: www.naughter.com, Email: pjna@naughter.com)
All rights reserved.
Copyright / Usage Details:
You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
when your product is released in binary form. You are allowed to modify the source code in any way you want
except you cannot modify the copyright details at the top of each module. If you want to distribute source
code with your application, then you are only allowed to distribute versions released by the author. This is
to maintain a single distribution point for the source code.
*/
///////////////////////////////// Includes //////////////////////////////////
#include "stdafx.h"
#include "resource.h"
#include "FileTreeCtrl.h"
#include <afxpriv.h>
#include "SortedArray.h"
//////////////////////////////// Defines / Locals /////////////////////////////
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define WM_TREEUPDATE_CHANGE WM_USER
//To avoid having to have the latest Platform SDK installed to compile CTreeFileCtrl
#ifndef FILE_ATTRIBUTE_ENCRYPTED
#define FILE_ATTRIBUTE_ENCRYPTED 0x00004000
#endif
int CSystemImageList::sm_nRefCount = 0; //Initialise the reference count
CSystemImageList theSystemImageList; //The one and only system image list instance
CShareEnumerator theSharedEnumerator; //The one and only share enumerator
//Pull in the WNet Lib automatically
#pragma comment(lib, "mpr.lib")
////////////////////////////// Implementation /////////////////////////////////
CTreeFileCtrlItemInfo::CTreeFileCtrlItemInfo()
{
m_pNetResource = NULL;
m_bNetworkNode = FALSE;
m_bExtensionHidden = FALSE;
}
CTreeFileCtrlItemInfo::CTreeFileCtrlItemInfo(const CTreeFileCtrlItemInfo& ItemInfo)
{
m_sFQPath = ItemInfo.m_sFQPath;
m_sRelativePath = ItemInfo.m_sRelativePath;
m_bNetworkNode = ItemInfo.m_bNetworkNode;
m_pNetResource = new NETRESOURCE;
if (ItemInfo.m_pNetResource)
{
//Copy the direct member variables of NETRESOURCE
CopyMemory(m_pNetResource, ItemInfo.m_pNetResource, sizeof(NETRESOURCE));
//Duplicate the strings which are stored in NETRESOURCE as pointers
if (ItemInfo.m_pNetResource->lpLocalName)
m_pNetResource->lpLocalName = _tcsdup(ItemInfo.m_pNetResource->lpLocalName);
if (ItemInfo.m_pNetResource->lpRemoteName)
m_pNetResource->lpRemoteName = _tcsdup(ItemInfo.m_pNetResource->lpRemoteName);
if (ItemInfo.m_pNetResource->lpComment)
m_pNetResource->lpComment = _tcsdup(ItemInfo.m_pNetResource->lpComment);
if (ItemInfo.m_pNetResource->lpProvider)
m_pNetResource->lpProvider = _tcsdup(ItemInfo.m_pNetResource->lpProvider);
}
else
ZeroMemory(m_pNetResource, sizeof(NETRESOURCE));
}
CTreeFileCtrlItemInfo::~CTreeFileCtrlItemInfo()
{
}
CSystemImageList::CSystemImageList()
{
ASSERT(sm_nRefCount == 0); //Should only every be one instance of CSystemImageList declared
++sm_nRefCount;
//Get the temp directory. This is used to then bring back the system image list
TCHAR pszTempDir[_MAX_PATH];
VERIFY(GetTempPath(_MAX_PATH, pszTempDir));
TCHAR pszDrive[_MAX_DRIVE + 1];
_tsplitpath(pszTempDir, pszDrive, NULL, NULL, NULL);
int nLen = _tcslen(pszDrive);
if (pszDrive[nLen-1] != _T('\\'))
_tcscat(pszDrive, _T("\\"));
//Attach to the system image list
SHFILEINFO sfi;
HIMAGELIST hSystemImageList = (HIMAGELIST) SHGetFileInfo(pszTempDir, 0, &sfi, sizeof(SHFILEINFO),
SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
VERIFY(m_ImageList.Attach(hSystemImageList));
}
CSystemImageList::~CSystemImageList()
{
//Decrement the reference count
--sm_nRefCount;
//Detach from the image list to prevent problems on 95/98 where
//the system image list is shared across processes
m_ImageList.Detach();
}
CShareEnumerator::CShareEnumerator()
{
//Set out member variables to defaults
m_pNTShareEnum = NULL;
m_pWin9xShareEnum = NULL;
m_pNTBufferFree = NULL;
m_pNTShareInfo = NULL;
m_pWin9xShareInfo = NULL;
m_pWin9xShareInfo = NULL;
m_hNetApi = NULL;
m_dwShares = 0;
//Determine if we are running Windows NT or Win9x
OSVERSIONINFO osvi;
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
m_bWinNT = (GetVersionEx(&osvi) && osvi.dwPlatformId == VER_PLATFORM_WIN32_NT);
if (m_bWinNT)
{
//Load up the NETAPI dll
m_hNetApi = LoadLibrary(_T("NETAPI32.dll"));
if (m_hNetApi)
{
//Get the required function pointers
m_pNTShareEnum = (NT_NETSHAREENUM*) GetProcAddress(m_hNetApi, "NetShareEnum");
m_pNTBufferFree = (NT_NETAPIBUFFERFREE*) GetProcAddress(m_hNetApi, "NetApiBufferFree");
}
}
else
{
//Load up the NETAPI dll
m_hNetApi = LoadLibrary(_T("SVRAPI.dll"));
if (m_hNetApi)
{
//Get the required function pointer
m_pWin9xShareEnum = (WIN9X_NETSHAREENUM*) GetProcAddress(m_hNetApi, "NetShareEnum");
}
}
//Update the array of shares we know about
Refresh();
}
CShareEnumerator::~CShareEnumerator()
{
if (m_bWinNT)
{
//Free the buffer if valid
if (m_pNTShareInfo)
m_pNTBufferFree(m_pNTShareInfo);
}
else
//Free up the heap memory we have used
delete [] m_pWin9xShareInfo;
//Free the dll now that we are finished with it
if (m_hNetApi)
{
FreeLibrary(m_hNetApi);
m_hNetApi = NULL;
}
}
void CShareEnumerator::Refresh()
{
m_dwShares = 0;
if (m_bWinNT)
{
//Free the buffer if valid
if (m_pNTShareInfo)
m_pNTBufferFree(m_pNTShareInfo);
//Call the function to enumerate the shares
if (m_pNTShareEnum)
{
DWORD dwEntriesRead = 0;
m_pNTShareEnum(NULL, 502, (LPBYTE*) &m_pNTShareInfo, MAX_PREFERRED_LENGTH, &dwEntriesRead, &m_dwShares, NULL);
}
}
else
{
//Free the buffer if valid
if (m_pWin9xShareInfo)
delete [] m_pWin9xShareInfo;
//Call the function to enumerate the shares
if (m_pWin9xShareEnum)
{
//Start with a reasonably sized buffer
unsigned short cbBuffer = 1024;
BOOL bNeedMoreMemory = TRUE;
BOOL bSuccess = FALSE;
while (bNeedMoreMemory && !bSuccess)
{
unsigned short nTotalRead = 0;
m_pWin9xShareInfo = (CTreeFile_share_info_50*) new BYTE[cbBuffer];
ZeroMemory(m_pWin9xShareInfo, cbBuffer);
unsigned short nShares = 0;
NET_API_STATUS nStatus = m_pWin9xShareEnum(NULL, 50, (char FAR *)m_pWin9xShareInfo, cbBuffer, (unsigned short FAR *)&nShares, (unsigned short FAR *)&nTotalRead);
if (nStatus == ERROR_MORE_DATA)
{
//Free up the heap memory we have used
delete [] m_pWin9xShareInfo;
//And double the size, ready for the next loop around
cbBuffer *= 2;
}
else if (nStatus == NERR_Success)
{
m_dwShares = nShares;
bSuccess = TRUE;
}
else
bNeedMoreMemory = FALSE;
}
}
}
}
BOOL CShareEnumerator::IsShared(const CString& sPath)
{
//Assume the item is not shared
BOOL bShared = FALSE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -