1000 lines
30 KiB
C++
1000 lines
30 KiB
C++
// ==========================================================================
|
|
// Class Implementation : COXNetBrowseTree
|
|
// ==========================================================================
|
|
|
|
// Source file : OXNetBrowseTree.cpp
|
|
|
|
// Version: 9.3
|
|
|
|
// This software along with its related components, documentation and files ("The Libraries")
|
|
// is © 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
|
|
// governed by a software license agreement ("Agreement"). Copies of the Agreement are
|
|
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
|
|
// to obtain this file, or directly from our office. For a copy of the license governing
|
|
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.
|
|
|
|
// //////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
#include "OXNetBrowseTree.h"
|
|
#include "OXMainRes.h"
|
|
|
|
#include "UTBStrOp.h"
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char BASED_CODE THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
IMPLEMENT_DYNAMIC(COXNetBrowseTree, CTreeCtrl)
|
|
|
|
#define new DEBUG_NEW
|
|
|
|
// Images in the small image list for this network tree
|
|
#define NET_IMAGE_UNKNOWN 0
|
|
#define NET_IMAGE_UNKNWON_EXPANDED 1
|
|
#define NET_IMAGE_DOMAIN 2
|
|
#define NET_IMAGE_DOMAIN_EXPANDED 3
|
|
#define NET_IMAGE_SERVER 4
|
|
#define NET_IMAGE_SERVER_EXPANDED 5
|
|
#define NET_IMAGE_DISK_SHARE 6
|
|
#define NET_IMAGE_DISK_SHARE_EXPANDED 7
|
|
#define NET_IMAGE_PRINTER_SHARE 8
|
|
#define NET_IMAGE_PRINTER_SHARE_EXPANDED 9
|
|
#define NET_IMAGE_OTHER_SHARE 10
|
|
#define NET_IMAGE_OTHER_SHARE_EXPANDED 11
|
|
#define NET_IMAGE_FILE 12
|
|
#define NET_IMAGE_FILE_EXPANDED 13
|
|
#define NET_IMAGE_GROUP 14
|
|
#define NET_IMAGE_GROUP_EXPANDED 15
|
|
#define NET_IMAGE_NETWORK 16
|
|
#define NET_IMAGE_NETWORK_EXPANDED 17
|
|
#define NET_IMAGE_ROOT 18
|
|
#define NET_IMAGE_ROOT_EXPANDED 19
|
|
#define NET_IMAGE_SHARADMIN 20
|
|
#define NET_IMAGE_SHAREADMIN_EXPANDED 21
|
|
#define NET_IMAGE_DIRECTORY 22
|
|
#define NET_IMAGE_DIRECTORY_EXPANDED 23
|
|
#define NET_IMAGE_TREE 24
|
|
#define NET_IMAGE_TREE_EXPANDED 25
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Definition of static members
|
|
static TCHAR szUnknownError[] = _T("*** Unknown Error ***");
|
|
|
|
static OSVERSIONINFO OSVersion;
|
|
struct _OX_WINDOWS_VERSION
|
|
{
|
|
_OX_WINDOWS_VERSION()
|
|
{
|
|
OSVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
VERIFY(::GetVersionEx(&OSVersion));
|
|
}
|
|
};
|
|
static const _OX_WINDOWS_VERSION windowsVersion;
|
|
|
|
|
|
// Data members -------------------------------------------------------------
|
|
// protected:
|
|
// BOOL m_bInitialized;
|
|
// --- Whether the control has been properly initialized
|
|
// This is done by posting the message WM_POST_INIT
|
|
|
|
// BOOL m_bShowCommentName;
|
|
// --- Whether the comment should be shown for each net resource
|
|
|
|
// BOOL m_bShowDisks;
|
|
// --- Whether disk resources should be shown
|
|
|
|
// BOOL m_bShowPrinters;
|
|
// ---- Whether printer resources should be shown
|
|
|
|
// int m_nResourceScope;
|
|
// ---- The scope of the resources that are show in the tree control
|
|
|
|
// int m_nMaxNumLevels;
|
|
// --- The last lvel in the tree that will be shown
|
|
// Deeper levels are hidden for the user
|
|
|
|
// int m_nInitialExpandLevel;
|
|
// --- The number levels that should be initially expanded wqhen the control
|
|
// becomes visisble for the first time
|
|
|
|
// BOOL m_bReport;
|
|
// --- Whether network errors should be shown in an message box to the user
|
|
|
|
// NETRESOURCE* m_pCurrentNetResource;
|
|
// --- The net resource associated with the last selected item
|
|
|
|
// CImageList m_netImages;
|
|
// --- The image list used by this control
|
|
|
|
// CMap<HTREEITEM, HTREEITEM, NETRESOURCE*, NETRESOURCE*> m_resourceMap;
|
|
// --- The mapping between the handle of the tree item and its associated net resource info
|
|
|
|
// private:
|
|
|
|
// Member functions ---------------------------------------------------------
|
|
// public:
|
|
|
|
BEGIN_MESSAGE_MAP(COXNetBrowseTree, CTreeCtrl)
|
|
//{{AFX_MSG_MAP(COXNetBrowseTree)
|
|
ON_WM_CREATE()
|
|
ON_NOTIFY_REFLECT_EX(TVN_ITEMEXPANDING, OnItemexpanding)
|
|
ON_NOTIFY_REFLECT_EX(TVN_SELCHANGED, OnSelchanged)
|
|
ON_NOTIFY_REFLECT(TVN_GETDISPINFO, OnGetDispInfo)
|
|
//}}AFX_MSG_MAP
|
|
ON_MESSAGE(WM_POST_INIT, OnPostInit)
|
|
END_MESSAGE_MAP()
|
|
|
|
COXNetBrowseTree::COXNetBrowseTree()
|
|
:
|
|
m_bInitialized(FALSE),
|
|
m_bShowCommentName(TRUE),
|
|
m_bShowDisks(TRUE),
|
|
m_bShowPrinters(FALSE),
|
|
m_nResourceScope(RESOURCE_GLOBALNET),
|
|
m_nMaxNumLevels(100),
|
|
m_nInitialExpandLevel(0),
|
|
m_bReport(TRUE),
|
|
m_pCurrentNetResource(NULL),
|
|
m_netImages()
|
|
{
|
|
ASSERT_VALID(this);
|
|
}
|
|
|
|
BOOL COXNetBrowseTree::IsInitialized() const
|
|
{
|
|
return m_bInitialized;
|
|
}
|
|
|
|
BOOL COXNetBrowseTree::Initialize()
|
|
{
|
|
// Create the small icon image list for context list
|
|
// ... The bitmap resource IDB_NET_IMAGELIST should contain the images
|
|
// ... Must find the resource
|
|
// (Make sure OXNetBrowseTree.rc is included in your resource file)
|
|
ASSERT(AfxFindResourceHandle(MAKEINTRESOURCE(IDB_OX_NET_IMAGELIST), RT_BITMAP) != NULL);
|
|
VERIFY(m_netImages.Create(IDB_OX_NET_IMAGELIST,16,0,RGB(255,0,255)));
|
|
// m_netImages.SetBkColor(GetSysColor(COLOR_WINDOW));
|
|
m_netImages.SetBkColor(CLR_NONE);
|
|
// ... Associate the image lists with the context list
|
|
SetImageList(&m_netImages, TVSIL_NORMAL);
|
|
|
|
// Build the tree contents for the first time
|
|
BuildTreeContents();
|
|
|
|
m_bInitialized = TRUE;
|
|
return m_bInitialized;
|
|
}
|
|
|
|
BOOL COXNetBrowseTree::ShowCommentName(BOOL bShow)
|
|
{
|
|
BOOL bPrevShow = m_bShowCommentName;
|
|
m_bShowCommentName = bShow;
|
|
return bPrevShow;
|
|
}
|
|
|
|
BOOL COXNetBrowseTree::ShowDisks(BOOL bShow)
|
|
{
|
|
BOOL bPrevShow = m_bShowDisks;
|
|
m_bShowDisks = bShow;
|
|
return bPrevShow;
|
|
}
|
|
|
|
BOOL COXNetBrowseTree::ShowPrinters(BOOL bShow)
|
|
{
|
|
BOOL bPrevShow = m_bShowPrinters;
|
|
m_bShowPrinters = bShow;
|
|
return bPrevShow;
|
|
}
|
|
|
|
int COXNetBrowseTree::SetResourceScope(int nScope)
|
|
{
|
|
ASSERT(0 <= nScope);
|
|
int nPrevScope = m_nResourceScope;
|
|
m_nResourceScope = nScope;
|
|
return nPrevScope;
|
|
}
|
|
|
|
int COXNetBrowseTree::SetMaxNumLevels(int nMaxNumLevels)
|
|
{
|
|
ASSERT(0 <= nMaxNumLevels);
|
|
int nPrevMaxNumLevels = m_nMaxNumLevels;
|
|
m_nMaxNumLevels = nMaxNumLevels;
|
|
return nPrevMaxNumLevels;
|
|
}
|
|
|
|
int COXNetBrowseTree::SetInitialExpandLevel(int nLevel)
|
|
{
|
|
int nPrevLevel = m_nInitialExpandLevel;
|
|
m_nInitialExpandLevel = nLevel;
|
|
return nPrevLevel;
|
|
}
|
|
|
|
BOOL COXNetBrowseTree::ReportErrors(BOOL bReport)
|
|
{
|
|
BOOL bPrevReport = bReport;
|
|
m_bReport = bReport;
|
|
return bPrevReport;
|
|
}
|
|
|
|
BOOL COXNetBrowseTree::BuildTreeContents()
|
|
{
|
|
|
|
SetRedraw(FALSE);
|
|
|
|
// If the tree till contains nodes, remove them all
|
|
DeleteAllItems();
|
|
|
|
// Cleanup data members
|
|
Cleanup();
|
|
|
|
// Create the root node
|
|
if (0 < m_nMaxNumLevels)
|
|
ExpandNode(NULL);
|
|
|
|
// Expand all top level items
|
|
HTREEITEM hTopItem = NULL;
|
|
hTopItem = GetRootItem();
|
|
while (hTopItem != NULL)
|
|
{
|
|
ExpandBranch(hTopItem, m_nInitialExpandLevel);
|
|
hTopItem = GetNextSiblingItem(hTopItem);
|
|
}
|
|
|
|
// If at least one top level item is expandable, connect lines to
|
|
// the root of the control otherwise do not
|
|
BOOL bLinesAtRoot = FALSE;
|
|
hTopItem = GetRootItem();
|
|
while(!bLinesAtRoot && (hTopItem != NULL))
|
|
{
|
|
bLinesAtRoot = ItemHasChildren(hTopItem);
|
|
hTopItem = GetNextSiblingItem(hTopItem);
|
|
}
|
|
if (bLinesAtRoot)
|
|
ModifyStyle(0, TVS_LINESATROOT /* add */);
|
|
else
|
|
ModifyStyle(TVS_LINESATROOT /* remove */, 0);
|
|
|
|
SetRedraw(TRUE);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
const NETRESOURCE* COXNetBrowseTree::GetCurrentNetResource() const
|
|
{
|
|
return m_pCurrentNetResource;
|
|
}
|
|
|
|
const NETRESOURCE* COXNetBrowseTree::GetAssocNetResource(HTREEITEM hTreeItem) const
|
|
{
|
|
return GetAssocNetResourceEx(hTreeItem);
|
|
}
|
|
|
|
void COXNetBrowseTree::ExpandBranch(HTREEITEM hParentItem, int nLevels)
|
|
{
|
|
if (nLevels <= 0)
|
|
return;
|
|
|
|
ASSERT(hParentItem != NULL);
|
|
|
|
// First expand the parent itself
|
|
if (!Expand(hParentItem, TVE_EXPAND))
|
|
// ... Expand failed (the network resource probably produced an error)
|
|
return;
|
|
|
|
// Then expand all its children
|
|
HTREEITEM hChildItem = GetChildItem(hParentItem);
|
|
while (hChildItem != NULL)
|
|
{
|
|
ExpandBranch(hChildItem, nLevels - 1);
|
|
hChildItem = GetNextSiblingItem(hChildItem);
|
|
}
|
|
}
|
|
|
|
int COXNetBrowseTree::GetItemLevel(HTREEITEM hTreeItem)
|
|
{
|
|
int nLevel = -1;
|
|
HTREEITEM hParentItem = hTreeItem;
|
|
while (hParentItem != NULL)
|
|
{
|
|
hParentItem = GetParentItem(hParentItem);
|
|
nLevel++;
|
|
}
|
|
return nLevel;
|
|
}
|
|
|
|
BOOL COXNetBrowseTree::Uninitialize()
|
|
{
|
|
ASSERT(IsInitialized());
|
|
|
|
// Destroy the the small icon image list
|
|
VERIFY(m_netImages.DeleteImageList());
|
|
|
|
m_bInitialized = FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
void COXNetBrowseTree::AssertValid() const
|
|
{
|
|
CTreeCtrl::AssertValid();
|
|
}
|
|
|
|
void COXNetBrowseTree::Dump(CDumpContext& dc) const
|
|
{
|
|
CTreeCtrl::Dump(dc);
|
|
dc << "\nm_bInitialized : " << m_bInitialized;
|
|
dc << "\nm_bShowCommentName : " << m_bShowCommentName;
|
|
dc << "\nm_bShowDisks : " << m_bShowDisks;
|
|
dc << "\nm_bShowPrinters : " << m_bShowPrinters;
|
|
dc << "\nm_nResourceScope : " << m_nResourceScope;
|
|
dc << "\nm_nMaxNumLevels : " << m_nMaxNumLevels;
|
|
dc << "\nm_nInitialExpandLevel : " << m_nInitialExpandLevel;
|
|
dc << "\nm_bReport : " << m_bReport;
|
|
dc << "\nm_pCurrentNetResource : " << m_pCurrentNetResource;
|
|
dc << "\nm_netImages : " << &m_netImages;
|
|
dc << "\n";
|
|
}
|
|
#endif //_DEBUG
|
|
|
|
COXNetBrowseTree::~COXNetBrowseTree()
|
|
{
|
|
Cleanup();
|
|
}
|
|
|
|
// protected:
|
|
NETRESOURCE* COXNetBrowseTree::GetAssocNetResourceEx(HTREEITEM hTreeItem) const
|
|
// --- In : hTreeItem : Node of which the associated net resource is requested
|
|
// --- Out :
|
|
// --- Returns : The net resource associated with the specified node
|
|
// Notice that this return value is not const
|
|
// --- Effect : Should only be called for valid tree items
|
|
{
|
|
NETRESOURCE* pNetResource = NULL;
|
|
if (!m_resourceMap.Lookup(hTreeItem, pNetResource))
|
|
pNetResource = NULL;
|
|
#ifdef _DEBUG
|
|
// ... No associated net resource found, may be a dangerous situation
|
|
if (pNetResource == NULL)
|
|
{
|
|
TRACE1("COXNetBrowseTree::GetAssocNetResourceEx : No associated net resource found for tree item 0x%X, returning NULL pointer\n",
|
|
hTreeItem);
|
|
// ASSERT(FALSE);
|
|
}
|
|
#endif
|
|
return pNetResource;
|
|
}
|
|
|
|
BOOL COXNetBrowseTree::ExpandNode(HTREEITEM hTreeItem)
|
|
// --- In : hTreeItem : Node to expand (NULL is top level)
|
|
// --- Out :
|
|
// --- Returns :
|
|
// --- Effect : Expands the specified node
|
|
{
|
|
// If hTreeItem == NULL we have to have an empty tree
|
|
ASSERT((hTreeItem != NULL) || (GetRootItem() == NULL));
|
|
|
|
// Get the net resource of the parent item
|
|
NETRESOURCE* pNetResources = NULL;
|
|
if (hTreeItem != NULL)
|
|
{
|
|
pNetResources = GetAssocNetResourceEx(hTreeItem);
|
|
ASSERT(pNetResources != NULL);
|
|
}
|
|
else
|
|
pNetResources = NULL;
|
|
|
|
if ((pNetResources != NULL) && ((pNetResources->dwUsage & RESOURCEUSAGE_CONTAINER) != RESOURCEUSAGE_CONTAINER))
|
|
// Net resource exists, but is not a container and thus cannot be enumerated
|
|
return FALSE;
|
|
|
|
// Expand the node (may take a while)
|
|
CWaitCursor wc;
|
|
return CreateChildren(hTreeItem, pNetResources);
|
|
}
|
|
|
|
BOOL COXNetBrowseTree::CreateChildren(HTREEITEM hParentItem, NETRESOURCE* pParentNetResources)
|
|
// --- In : hParentItem : Node of which the children nodes have to be created
|
|
// pParentNetResources : Net resource of this parent node
|
|
// --- Out :
|
|
// --- Returns :
|
|
// --- Effect : Computes the netresources of the children and creates the child nodes
|
|
{
|
|
HANDLE hEnum = NULL;
|
|
DWORD dwScope = pParentNetResources == NULL ? m_nResourceScope : pParentNetResources->dwScope;
|
|
DWORD nResult = WNetOpenEnum(
|
|
dwScope, // scope of enumeration
|
|
RESOURCETYPE_ANY, // resource types to list
|
|
0, // resource usage to list
|
|
pParentNetResources, // pointer to resource structure
|
|
&hEnum); // pointer to enumeration handle buffer
|
|
if (nResult != NO_ERROR)
|
|
{
|
|
TRACE2("COXNetBrowseTree::CreateChildren : WNetOpenEnum failed with error code %i == 0x%X\n",
|
|
nResult, nResult);
|
|
ReportNetError(nResult, pParentNetResources == NULL ? NULL : pParentNetResources->lpRemoteName);
|
|
return FALSE;
|
|
}
|
|
|
|
DWORD nCurrentCount(0);
|
|
DWORD nCurrentSkipCount(0);
|
|
/* =============================================================================== */
|
|
|
|
// The problem with the WNetEnumResoiurce fuction is that allthough you use
|
|
// 0xFFFFFFFF as requested resource count (this means everything) the function
|
|
// does NOT return ERROR_MORE_DATA if the buffer is too small. It only returns
|
|
// this value if the buffer supplied is too small even for one value, in this
|
|
// case the space needed to hold the first resource found in the enumeration
|
|
// Normally the size of this resource should be sizeof(NETRESOURCE) which is
|
|
// 32 bytes but experience learned that this fluctuates between 32 bytes and
|
|
// more than 1000 bytes. This is probably due to the fact that WNetEnumResource
|
|
// also needs allocated memory for the strings inside the NETRESOURCE struct.
|
|
// This leads to the conclusion that we cannot calculate with certainty the size
|
|
// of the buffer we need for a certain number of resources. The most robust
|
|
// solution to this problem is to request a absolute number of resources, make
|
|
// an serious and realistic estimation of the maximum amount of memory needed
|
|
// to hold ALL requested resources and then test to see whether you have retrieved
|
|
// all requested resources. If this is TRUE then again enumerate the resources
|
|
// to determine whether there aren't any left and so on until the returned
|
|
// number of resources is smaller than the requested number. This last remark
|
|
// explains why we need to be sure that the requested number of resources
|
|
// allways fit in the amount of memory we allocated for the buffer. We could
|
|
// alocated a very big buffer but we prefer the loop.
|
|
|
|
// Also note that we don't use NETRESOURCE* pRes = new NETRESOURCE[Count]
|
|
// because the array allocated will be an array of structs of size sizeof(NETRESOURCE)
|
|
// and that's just not correct to hold one netresource. That's why we use
|
|
// GlobalAlloc.
|
|
|
|
// USERS WHO WANT TO TUNE THE PERFORMANCE OF THIS FUNCTION CAN PLAY WITH THE
|
|
// NUMBER OF NETRESOURCES VIA THE nCOUNT VARIABLE AND WITH THE SIZE OF THE
|
|
// ALLOCATED BUFFER VIA THE nBUFFERSIZE VARIABLE BUT KEEP THE REMARKS ABOVE
|
|
// IN MIND.
|
|
/* =============================================================================== */
|
|
// Start with a reasonable buffer size
|
|
DWORD nCount = 5;
|
|
DWORD nBufferSize = 5000;
|
|
LPNETRESOURCE rgpNetResources = (LPNETRESOURCE)GlobalAlloc(GPTR, nBufferSize);
|
|
|
|
while (TRUE)
|
|
{
|
|
DWORD nTempCount = nCount;
|
|
DWORD nTempBufferSize = nBufferSize;
|
|
memset(rgpNetResources, 0, nBufferSize);
|
|
DWORD nResult2 = WNetEnumResource(
|
|
hEnum, // handle to enumeration
|
|
&nTempCount, // pointer to entries to list
|
|
(LPVOID)rgpNetResources, // pointer to buffer for results
|
|
&nTempBufferSize); // pointer to buffer size variable
|
|
TRACE2("COXNetBrowseTree::WNetEnumResource : Number of Netresources (%i), in buffersize (0x%X)\n", nTempCount, nTempBufferSize);
|
|
|
|
if ((nResult2 != NO_ERROR) && (nResult2 != ERROR_NO_MORE_ITEMS) &&
|
|
(nResult2 != ERROR_MORE_DATA))
|
|
{
|
|
TRACE2("COXNetBrowseTree::CreateChildren : WNetEnumResource failed with error code %i == 0x%X\n",
|
|
nResult2, nResult2);
|
|
ReportNetError(nResult2, pParentNetResources == NULL ? NULL : pParentNetResources->lpRemoteName);
|
|
// ... Cleanup the handle and memeory allocated
|
|
VERIFY(WNetCloseEnum(hEnum) == NO_ERROR);
|
|
GlobalFree((HGLOBAL)rgpNetResources);
|
|
return FALSE;
|
|
}
|
|
|
|
if (nResult2 == ERROR_NO_MORE_ITEMS)
|
|
nTempCount = 0;
|
|
|
|
// Loop the requested number of NetResources and make tree item nodes
|
|
{
|
|
HTREEITEM hNewItem;
|
|
NETRESOURCE* pSourceNetResource = NULL;
|
|
NETRESOURCE* pCopyNetResource = NULL;
|
|
DWORD nIndex;
|
|
DWORD nSkipCount = 0;
|
|
for (nIndex = 0; nIndex < nTempCount; nIndex++)
|
|
{
|
|
pSourceNetResource = &rgpNetResources[nIndex];
|
|
|
|
// Check special case for disks and printers
|
|
if ((pSourceNetResource->dwType == RESOURCETYPE_DISK) && !m_bShowDisks)
|
|
{
|
|
// Skip this item
|
|
nSkipCount++;
|
|
continue;
|
|
}
|
|
if ((pSourceNetResource->dwType == RESOURCETYPE_PRINT) && !m_bShowPrinters)
|
|
{
|
|
// Skip this item
|
|
nSkipCount++;
|
|
continue;
|
|
}
|
|
|
|
// ... Create a new item
|
|
hNewItem = InsertResourceItem(pSourceNetResource, hParentItem);
|
|
if (hNewItem == NULL)
|
|
{
|
|
TRACE0("COXNetBrowseTree::InsertResourceItem returned NULL\n");
|
|
// Skip this item
|
|
nSkipCount++;
|
|
continue;
|
|
}
|
|
|
|
// Add a copy to the map
|
|
// ... Should not yet be in map
|
|
#ifdef _DEBUG
|
|
NETRESOURCE* pCheckNetResource = NULL;
|
|
ASSERT(!m_resourceMap.Lookup(hNewItem, pCheckNetResource));
|
|
#endif // _DEBUG
|
|
pCopyNetResource = new NETRESOURCE;
|
|
// ... Copy the struct itself
|
|
memcpy(pCopyNetResource, pSourceNetResource, sizeof(NETRESOURCE));
|
|
// ... Make a copy of all the string members
|
|
if (pSourceNetResource->lpLocalName != NULL)
|
|
{
|
|
size_t len = _tcslen(pSourceNetResource->lpLocalName) + 1;
|
|
pCopyNetResource->lpLocalName = new TCHAR[len];
|
|
UTBStr::tcscpy(pCopyNetResource->lpLocalName, len, pSourceNetResource->lpLocalName);
|
|
}
|
|
else
|
|
{
|
|
pCopyNetResource->lpLocalName = new TCHAR[1];
|
|
*pCopyNetResource->lpLocalName = _T('\0');
|
|
}
|
|
|
|
if (pSourceNetResource->lpRemoteName != NULL)
|
|
{
|
|
size_t len = _tcslen(pSourceNetResource->lpRemoteName) + 1;
|
|
pCopyNetResource->lpRemoteName = new TCHAR[len];
|
|
UTBStr::tcscpy(pCopyNetResource->lpRemoteName, len, pSourceNetResource->lpRemoteName);
|
|
}
|
|
else
|
|
{
|
|
pCopyNetResource->lpRemoteName = new TCHAR[1];
|
|
*pCopyNetResource->lpRemoteName = _T('\0');
|
|
}
|
|
|
|
if (pSourceNetResource->lpComment != NULL)
|
|
{
|
|
size_t len = _tcslen(pSourceNetResource->lpComment) + 1;
|
|
pCopyNetResource->lpComment = new TCHAR[len];
|
|
UTBStr::tcscpy(pCopyNetResource->lpComment, len, pSourceNetResource->lpComment);
|
|
}
|
|
else
|
|
{
|
|
pCopyNetResource->lpComment = new TCHAR[1];
|
|
*pCopyNetResource->lpComment = _T('\0');
|
|
}
|
|
|
|
if (pSourceNetResource->lpProvider != NULL)
|
|
{
|
|
size_t len = _tcslen(pSourceNetResource->lpProvider) + 1;
|
|
pCopyNetResource->lpProvider = new TCHAR[len];
|
|
UTBStr::tcscpy(pCopyNetResource->lpProvider, len, pSourceNetResource->lpProvider);
|
|
}
|
|
else
|
|
{
|
|
pCopyNetResource->lpProvider = new TCHAR[1];
|
|
*pCopyNetResource->lpProvider = _T('\0');
|
|
}
|
|
|
|
// ... Add to map
|
|
m_resourceMap.SetAt(hNewItem, pCopyNetResource);
|
|
}
|
|
|
|
// we need to keep track of the real number of nodes because we
|
|
// need it to set the correct treeitem number for the parent node
|
|
nCurrentCount += nTempCount;
|
|
nCurrentSkipCount += nSkipCount;
|
|
|
|
if (hParentItem != NULL)
|
|
{
|
|
// Mark the parent node as expanded at least once
|
|
VERIFY(SetItemState(hParentItem, TVIS_EXPANDEDONCE, TVIS_EXPANDEDONCE));
|
|
|
|
// Set the number of child items to the correct value
|
|
TV_ITEM item;
|
|
item.hItem = hParentItem;
|
|
item.mask = TVIF_CHILDREN;
|
|
ASSERT(nSkipCount <= nTempCount);
|
|
item.cChildren = nCurrentCount - nCurrentSkipCount;
|
|
VERIFY(SetItem(&item));
|
|
}
|
|
}
|
|
|
|
if (nResult2 == ERROR_MORE_DATA || nTempCount == nCount)
|
|
// Possibly there is more data to retrieve
|
|
{
|
|
nTempCount = nCount;
|
|
continue;
|
|
}
|
|
else
|
|
// There was no error and there isn't anymore data to retrieve
|
|
break;
|
|
}
|
|
|
|
// Cleanup the handle and allocated memory
|
|
VERIFY(WNetCloseEnum(hEnum) == NO_ERROR);
|
|
GlobalFree((HGLOBAL)rgpNetResources);
|
|
return TRUE;
|
|
}
|
|
|
|
HTREEITEM COXNetBrowseTree::InsertResourceItem(const NETRESOURCE* pNetResources, HTREEITEM hParentItem)
|
|
// --- In : pNetResources : The net resource
|
|
// hParentItem : The perant node
|
|
// --- Out :
|
|
// --- Returns : The handle of the new node
|
|
// --- Effect : Creates a new node as child of the specified parent
|
|
// The net resource of the child is provided
|
|
{
|
|
HTREEITEM hNewItem = NULL;
|
|
CString sLabel;
|
|
|
|
// Start with remote net name
|
|
sLabel = pNetResources->lpRemoteName;
|
|
// ... Remove leading back slashes
|
|
while ((0 < sLabel.GetLength()) && (sLabel[0] == _T('\\')))
|
|
sLabel = sLabel.Mid(1);
|
|
// ... Remove everything in front of (and including) the last back slash
|
|
int nBackSlashPos = sLabel.ReverseFind(_T('\\'));
|
|
if (0 <= nBackSlashPos)
|
|
sLabel = sLabel.Mid(nBackSlashPos + 1);
|
|
|
|
// Add the comment name if necessary
|
|
if (m_bShowCommentName)
|
|
{
|
|
CString sComment = pNetResources->lpComment;
|
|
if (!sComment.IsEmpty())
|
|
sLabel += _T(" (") + sComment + _T(")");
|
|
}
|
|
|
|
// Check whether the node can be further expanded
|
|
// ... It must be a container to be expandable
|
|
BOOL bExpandable = ((pNetResources->dwUsage & RESOURCEUSAGE_CONTAINER) == RESOURCEUSAGE_CONTAINER);
|
|
// ... The maximum level should not be exceeded
|
|
// ... We substract 3 because :
|
|
// The level of the parent item is one less than the item that will be added here
|
|
// The level number of the last item is one less than the totel number of levels
|
|
// bExpandable means thet this item has further children
|
|
bExpandable = bExpandable && (GetItemLevel(hParentItem) <= m_nMaxNumLevels - 3);
|
|
|
|
// Add the new item to the tree control
|
|
TV_INSERTSTRUCT insertStruct;
|
|
memset(&insertStruct, 0, sizeof(insertStruct));
|
|
|
|
insertStruct.hParent = hParentItem;
|
|
insertStruct.hInsertAfter = TVI_SORT;
|
|
insertStruct.item.mask = TVIF_CHILDREN | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
|
|
insertStruct.item.iImage = I_IMAGECALLBACK;
|
|
insertStruct.item.iSelectedImage = I_IMAGECALLBACK;
|
|
insertStruct.item.pszText = sLabel.GetBuffer(0);
|
|
// ... If this item is expandable set the children count to non-zero
|
|
// so that + button is shown in front of item
|
|
// This will be set to the correct value upon expanding
|
|
insertStruct.item.cChildren = bExpandable ? 1 : 0;
|
|
// ... Not yet expanded
|
|
ASSERT((insertStruct.item.state & TVIS_EXPANDEDONCE) == 0);
|
|
BOOL bPreInsert = PreInsertResourceItem(pNetResources, &insertStruct);
|
|
if (bPreInsert)
|
|
hNewItem = InsertItem(&insertStruct);
|
|
sLabel.ReleaseBuffer();
|
|
if (bPreInsert)
|
|
PostInsertResourceItem(pNetResources, &insertStruct, hNewItem);
|
|
|
|
return hNewItem;
|
|
}
|
|
|
|
void COXNetBrowseTree::Cleanup()
|
|
// --- In :
|
|
// --- Out :
|
|
// --- Returns :
|
|
// --- Effect : Clean up the internal structures
|
|
{
|
|
// Clean up the association map between tree item handles and net resource infos
|
|
POSITION pos;
|
|
HTREEITEM hTreeItem;
|
|
NETRESOURCE* pNetResource;
|
|
pos = m_resourceMap.GetStartPosition();
|
|
while (pos != NULL)
|
|
{
|
|
m_resourceMap.GetNextAssoc(pos, hTreeItem, pNetResource);
|
|
// ... First delete the strings
|
|
ASSERT(pNetResource->lpLocalName == NULL || AfxIsValidString(pNetResource->lpLocalName));
|
|
ASSERT(pNetResource->lpRemoteName == NULL || AfxIsValidString(pNetResource->lpRemoteName));
|
|
ASSERT(pNetResource->lpComment == NULL || AfxIsValidString(pNetResource->lpComment));
|
|
ASSERT(pNetResource->lpProvider == NULL || AfxIsValidString(pNetResource->lpProvider));
|
|
delete[] pNetResource->lpLocalName;
|
|
delete[] pNetResource->lpRemoteName;
|
|
delete[] pNetResource->lpComment;
|
|
delete[] pNetResource->lpProvider;
|
|
ASSERT(AfxIsValidAddress(pNetResource, sizeof(NETRESOURCE)));
|
|
delete pNetResource;
|
|
}
|
|
m_resourceMap.RemoveAll();
|
|
}
|
|
|
|
void COXNetBrowseTree::ReportNetError(DWORD nResult, LPCTSTR pszResource)
|
|
{
|
|
// ... pszResource may be NULL
|
|
CString sNetResource(pszResource);
|
|
CString sErrorMsg;
|
|
sErrorMsg = GetResultMessage(nResult);
|
|
CString sPrompt;
|
|
AfxFormatString2(sPrompt, IDS_OX_NET_BROWSE_ERROR, sNetResource, sErrorMsg);
|
|
if (m_bReport)
|
|
AfxMessageBox(sPrompt, MB_ICONEXCLAMATION | MB_OK, IDS_OX_NET_BROWSE_ERROR);
|
|
else
|
|
{
|
|
TRACE1("COXNetBrowseTree::ReportNetError : Not warning the user of the network error :\n\t%s",
|
|
sPrompt);
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
CString COXNetBrowseTree::GetResultMessage(HRESULT resultCode, ...)
|
|
{
|
|
CString sResultMessage;
|
|
BOOL bSuccess = FALSE;
|
|
|
|
va_list args;
|
|
va_start(args, resultCode);
|
|
bSuccess = RetrieveResultMessage(_T(""), resultCode, &args, sResultMessage);
|
|
va_end(args);
|
|
if (bSuccess)
|
|
return sResultMessage;
|
|
else
|
|
return _T("");
|
|
}
|
|
|
|
|
|
BOOL COXNetBrowseTree::RetrieveResultMessage(CString sModuleName, HRESULT resultCode,
|
|
va_list* pArgs, CString& sResultMessage)
|
|
// --- In : pszModuleName : Name of the module containing the message resource
|
|
// resultCode : Result code to use
|
|
// pARgs : Optional parameters used to build the message
|
|
// --- Out : sResultMessage : The resulting message
|
|
// --- Returns : Whether the message could be retrieved successfully
|
|
// --- Effect : Initializes a result item object with the specified
|
|
{
|
|
LPTSTR pszMsgBuf = NULL;
|
|
BOOL bUnknown = FALSE;
|
|
DWORD dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM;
|
|
HMODULE hModule = NULL;
|
|
|
|
// ... Get the module handle if a module name is specified
|
|
if (!sModuleName.IsEmpty())
|
|
{
|
|
hModule = ::GetModuleHandle(sModuleName);
|
|
dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE;
|
|
if (hModule == NULL)
|
|
TRACE(_T("COXResultItem::RetrieveResultMessage : Module '%s' not found\n"), (LPCTSTR)sModuleName);
|
|
}
|
|
|
|
// ... Get the actual message
|
|
if (::FormatMessage(dwFlags, hModule, resultCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
(LPTSTR)&pszMsgBuf, 0, pArgs) == 0)
|
|
{
|
|
TRACE2("COXResultItem::RetrieveResultMessage : No message was found for result code %i == 0x%8.8X\n",
|
|
resultCode, resultCode);
|
|
//pszMsgBuf = szUnknownError;
|
|
VERIFY(sResultMessage.LoadString(IDS_OX_NETBROWSEUNKERROR));
|
|
bUnknown = TRUE;
|
|
}
|
|
else
|
|
sResultMessage = pszMsgBuf;
|
|
|
|
// ... Clean up
|
|
if (!bUnknown)
|
|
LocalFree(pszMsgBuf);
|
|
|
|
return !bUnknown;
|
|
}
|
|
|
|
BOOL COXNetBrowseTree::PreInsertResourceItem(const NETRESOURCE* /* pNetResources */, TV_INSERTSTRUCT* /* pIinsertStruct */)
|
|
// --- In : pNetResources : The network resource info
|
|
// pIinsertStruct : The insert struct that is filled out
|
|
// --- Out : pIinsertStruct : The changed insert struct
|
|
// --- Returns : Whether this item may be inserted in the tree
|
|
// --- Effect : Intercept the addition of an item in the tree
|
|
{
|
|
// Nothing to do by default
|
|
// ... Let the insert be completed
|
|
return TRUE;
|
|
}
|
|
|
|
void COXNetBrowseTree::PostInsertResourceItem(const NETRESOURCE* /* pNetResources */, TV_INSERTSTRUCT* /* pInsertStruct */, HTREEITEM /* hNewItem */)
|
|
// --- In : pNetResources : The network resource info
|
|
// pIinsertStruct : The insert struct that is filled out
|
|
// hNewItem : The handle of the newly added item
|
|
// --- Out :
|
|
// --- Returns :
|
|
// --- Effect : Function that i scalled after an item has been added to the tree
|
|
{
|
|
// Nothing to do by default
|
|
}
|
|
|
|
// private:
|
|
|
|
// ==========================================================================
|
|
|
|
LRESULT COXNetBrowseTree::OnPostInit(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
// ... Parameters are not used (reserved for future extensions)
|
|
ASSERT(wParam == 0);
|
|
ASSERT(lParam == 0);
|
|
UNUSED(wParam);
|
|
UNUSED(lParam);
|
|
|
|
// ... Window must be valid
|
|
ASSERT(m_hWnd != NULL);
|
|
ASSERT(::IsWindow(m_hWnd));
|
|
|
|
// Perform first time initialization if necessary
|
|
if (!IsInitialized())
|
|
VERIFY(Initialize());
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void COXNetBrowseTree::PreSubclassWindow()
|
|
{
|
|
// ... Window must already be valid (although it has not yet been fully subclassed)
|
|
ASSERT(m_hWnd != NULL);
|
|
ASSERT(::IsWindow(m_hWnd));
|
|
|
|
PostMessage(WM_POST_INIT);
|
|
|
|
CTreeCtrl::PreSubclassWindow();
|
|
}
|
|
|
|
|
|
int COXNetBrowseTree::OnCreate(LPCREATESTRUCT lpCreateStruct)
|
|
{
|
|
if (CTreeCtrl::OnCreate(lpCreateStruct) == -1)
|
|
return -1;
|
|
|
|
// ... Window must already be valid (although it has not yet been fully subclassed)
|
|
ASSERT(m_hWnd != NULL);
|
|
ASSERT(::IsWindow(m_hWnd));
|
|
|
|
PostMessage(WM_POST_INIT);
|
|
|
|
return 0;
|
|
}
|
|
|
|
BOOL COXNetBrowseTree::OnItemexpanding(NMHDR* pNMHDR, LRESULT* pResult)
|
|
{
|
|
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
|
|
BOOL bEaten = FALSE;
|
|
*pResult = 0;
|
|
|
|
// If expanding and not yet expanded once : expand now
|
|
if ( ( (pNMTreeView->action == TVE_EXPAND) ||
|
|
((pNMTreeView->action == TVE_TOGGLE) &&
|
|
((pNMTreeView->itemNew.state & TVIS_EXPANDED) != 0)) ) &&
|
|
((pNMTreeView->itemNew.state & TVIS_EXPANDEDONCE) == 0) )
|
|
{
|
|
ExpandNode(pNMTreeView->itemNew.hItem);
|
|
}
|
|
return bEaten;
|
|
}
|
|
|
|
BOOL COXNetBrowseTree::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult)
|
|
{
|
|
UNREFERENCED_PARAMETER(pNMHDR);
|
|
|
|
BOOL bEaten = FALSE;
|
|
*pResult = 0;
|
|
|
|
// Get the net resource belonging to the currently selected item
|
|
HTREEITEM hTreeItem = GetSelectedItem();
|
|
if (hTreeItem != NULL)
|
|
{
|
|
m_pCurrentNetResource = GetAssocNetResource(hTreeItem);
|
|
ASSERT(m_pCurrentNetResource != NULL);
|
|
}
|
|
else
|
|
m_pCurrentNetResource = NULL;
|
|
ASSERT((m_pCurrentNetResource == NULL) ||
|
|
(AfxIsValidAddress(m_pCurrentNetResource, sizeof(NETRESOURCE))));
|
|
|
|
return bEaten;
|
|
}
|
|
|
|
void COXNetBrowseTree::OnGetDispInfo(NMHDR* pNMHDR, LRESULT* pResult)
|
|
{
|
|
TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
|
|
*pResult = 0;
|
|
|
|
if (((pTVDispInfo->item.mask & TVIF_IMAGE) == TVIF_IMAGE) ||
|
|
((pTVDispInfo->item.mask & TVIF_SELECTEDIMAGE) == TVIF_SELECTEDIMAGE))
|
|
{
|
|
// ... Start with unknown type
|
|
int nImage = NET_IMAGE_UNKNOWN;
|
|
// Get the associated net resource
|
|
const NETRESOURCE* pNetResource = NULL;
|
|
pNetResource = GetAssocNetResource(pTVDispInfo->item.hItem);
|
|
if (pNetResource == NULL)
|
|
return;
|
|
|
|
switch(pNetResource->dwDisplayType)
|
|
{
|
|
case RESOURCEDISPLAYTYPE_GENERIC:
|
|
nImage = NET_IMAGE_UNKNOWN;
|
|
break;
|
|
case RESOURCEDISPLAYTYPE_DOMAIN:
|
|
nImage = NET_IMAGE_DOMAIN;
|
|
break;
|
|
case RESOURCEDISPLAYTYPE_SERVER:
|
|
nImage = NET_IMAGE_SERVER;
|
|
break;
|
|
case RESOURCEDISPLAYTYPE_SHARE:
|
|
{
|
|
switch(pNetResource->dwType)
|
|
{
|
|
case RESOURCETYPE_DISK:
|
|
nImage = NET_IMAGE_DISK_SHARE;
|
|
break;
|
|
case RESOURCETYPE_PRINT:
|
|
nImage = NET_IMAGE_PRINTER_SHARE;
|
|
break;
|
|
default:
|
|
nImage = NET_IMAGE_OTHER_SHARE;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case RESOURCEDISPLAYTYPE_FILE:
|
|
nImage = NET_IMAGE_FILE;
|
|
break;
|
|
case RESOURCEDISPLAYTYPE_GROUP:
|
|
nImage = NET_IMAGE_GROUP;
|
|
break;
|
|
case RESOURCEDISPLAYTYPE_NETWORK:
|
|
nImage = NET_IMAGE_NETWORK;
|
|
break;
|
|
case RESOURCEDISPLAYTYPE_ROOT:
|
|
nImage = NET_IMAGE_ROOT;
|
|
break;
|
|
case RESOURCEDISPLAYTYPE_SHAREADMIN:
|
|
nImage = NET_IMAGE_SHARADMIN;
|
|
break;
|
|
case RESOURCEDISPLAYTYPE_DIRECTORY:
|
|
nImage = NET_IMAGE_DIRECTORY;
|
|
break;
|
|
case RESOURCEDISPLAYTYPE_TREE:
|
|
nImage = NET_IMAGE_TREE;
|
|
break;
|
|
}
|
|
|
|
// Under Windows NT 3.51 The root node of RESOURCE_GLOBALNET tree
|
|
// has display type RESOURCEDISPLAYTYPE_GENERIC instead of RESOURCEDISPLAYTYPE_NETWORK
|
|
// We will adjust for this here
|
|
if ((OSVersion.dwMajorVersion < 4) &&
|
|
(pNetResource->dwScope == RESOURCE_GLOBALNET) &&
|
|
(GetParentItem(pTVDispInfo->item.hItem) == NULL))
|
|
{
|
|
nImage = NET_IMAGE_NETWORK;
|
|
}
|
|
|
|
// If the item is expanded, use the next image
|
|
if ((GetItemState(pTVDispInfo->item.hItem, TVIS_EXPANDED) & TVIS_EXPANDED) == TVIS_EXPANDED)
|
|
nImage++;
|
|
|
|
// Return the result
|
|
pTVDispInfo->item.iImage = nImage;
|
|
pTVDispInfo->item.iSelectedImage = nImage;
|
|
}
|
|
}
|
|
|
|
|
|
void COXNetBrowseTree::PostNcDestroy()
|
|
{
|
|
// Unitialize the control
|
|
Uninitialize();
|
|
|
|
CTreeCtrl::PostNcDestroy();
|
|
}
|
|
|