⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 systemiconlibrary.cpp

📁 c++系统开发实例精粹内附的80例源代码 环境:windows2000,c++6.0
💻 CPP
字号:
//////////////////////////////////////////////////////////////////////
// FileFury
// Copyright (c) 2000 Tenebril Incorporated
// All rights reserved.
//
// This source code is governed by the Tenebril open source
// license (http://www.tenebril.com/developers/opensource/license.html)
//
// For more information on this and other open source applications,
// visit the Tenebril OpenSource page:
//       http://www.tenebril.com/developers/opensource
//
//////////////////////////////////////////////////////////////////////

// SystemIconLibrary.cpp: implementation of the CSystemIconLibrary class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Oscar.h"
#include "SystemIconLibrary.h"
#include "IconLibraryDlg.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CSystemIconLibrary::CSystemIconLibrary()
{
	m_bContinueRefresh = TRUE;
	
	m_pTrieRoot = new TrieNode;
	memset((void *)m_pTrieRoot, 0, sizeof(TrieNode));
	m_pTrieRoot->nIndex[0] = m_pTrieRoot->nIndex[1] = m_pTrieRoot->nIndex[2] = -1;

	memset((void *)m_nSpecialIcon, 0, sizeof(m_nSpecialIcon));

	UpdateSpecialIcons();
}

CSystemIconLibrary::~CSystemIconLibrary()
{
	// Delete the entire trie.
	PostDeleteEntries(m_pTrieRoot);
}

BOOL CSystemIconLibrary::Refresh(CFileSystem *pFS, CWnd *pStatusWnd)
{
	// Recursively traverse the entire local filesystem, adding all
	// icons.  This procedure can be stopped at any time by calling the
	// StopRefresh function.

	TCHAR  szDrives[512];
	TCHAR *pDrive;
	BOOL bHasSelected = FALSE;

	m_cRefMutex.Lock();          // Don't walk over memory.
	m_bContinueRefresh = TRUE;
	m_cRefMutex.Unlock();

	if ( !pFS->GetLogicalDriveStrings( sizeof(szDrives), szDrives ) )
	{
		ASSERT(0);
		return FALSE;
	}

	pDrive = szDrives;
	while( *pDrive )
	{
		// Check to see if we should break.
		m_cRefMutex.Lock();
		if(!m_bContinueRefresh) { m_cRefMutex.Unlock(); return TRUE; };
		m_cRefMutex.Unlock();

		// Ping only non-removable disks; we don't want to have drives spin
		if(pFS->GetDriveType(pDrive) != DRIVE_REMOVABLE)
		{
			CString cszDrivePath;

			cszDrivePath = pDrive;
			RefreshPath(cszDrivePath, pStatusWnd);
		}

		pDrive += strlen( pDrive ) + 1;
	}

	return TRUE;
}

int CSystemIconLibrary::FindIcon(LPCTSTR czFileName, int nType)
{
	TrieNode *pEntry = m_pTrieRoot;
	CString cszName = czFileName;

	ASSERT(sizeof(TCHAR) == 1);    // Our trie only has 256 entries.
	ASSERT(pEntry);
	ASSERT(nType >= 0 && nType < 3);

	cszName.MakeLower();

	// Get the extension only.
	if(cszName.ReverseFind(_T('.')) >= 0)
		cszName = cszName.Right(cszName.GetLength() - 
			cszName.ReverseFind(_T('.')) - 1);
	else
		return UnknownIcon(nType);

	if(cszName.GetLength() > 3)
		return UnknownIcon(nType);

	// Get the icon out of the trie.
	for(int i = 0; i < cszName.GetLength(); i++)
	{
		TCHAR tc = cszName.GetAt(i);

		int nCharID = (int)tc;
		ASSERT(nCharID >= 0 && nCharID < 256);
		pEntry = (TrieNode *)pEntry->Next[nCharID];

		if(!pEntry) return UnknownIcon(nType);      // No trie entry.
	}

	if(pEntry->nIndex[nType] < 0)
		return UnknownIcon(nType);

	return pEntry->nIndex[nType];
}

BOOL CSystemIconLibrary::UpdateIcon(LPCTSTR czFileName, UINT nID, int nType,
									CWnd *pStatusWnd)
{
	TrieNode *pEntry = m_pTrieRoot;
	TrieNode *pNewEntry;
	CString cszName = czFileName;

	ASSERT(sizeof(TCHAR) == 1);    // Our trie only has 256 entries.
	ASSERT(pEntry);
	ASSERT(nType >= 0 && nType < 3);

	// Not case-sensitive.
	cszName.MakeLower();

	// Get the extension only.
	if(cszName.ReverseFind(_T('.')) >= 0)
		cszName = cszName.Right(cszName.GetLength() - 
			cszName.ReverseFind(_T('.')) - 1);
	else
		return FALSE;             // Unknown icon

	// Only standard extensions.
	if(cszName.GetLength() > 3)
		return FALSE;

	// Make sure we don't add disallowed extensions.
	if(cszName.CompareNoCase(_T("exe")) == 0)
		return FALSE;

	// Get to the correct trie entry.
	for(int i = 0; i < cszName.GetLength(); i++)
	{
		TCHAR tc = cszName.GetAt(i);

		int nCharID = (int)tc;
		ASSERT(nCharID >= 0 && nCharID < 256);
		pNewEntry = (TrieNode *)pEntry->Next[nCharID];

		if(!pNewEntry)
		{
			// Allocate a new branch.

			pEntry->Next[nCharID] = (char *)(new TrieNode);
			memset((void *)pEntry->Next[nCharID], 0, sizeof(TrieNode));
			pEntry->nIndex[0] = pEntry->nIndex[1] = pEntry->nIndex[2] = -1;

			pNewEntry = (TrieNode *)pEntry->Next[nCharID];
			ASSERT(pNewEntry);

			if(pStatusWnd)
			{
				// Cast it.
				CIconLibraryDlg *pIconDlg = (CIconLibraryDlg *)pStatusWnd;

				pIconDlg->UpdateStatus(cszName);
			}

			TRACE(cszName + CString("\n"));
		}

		pEntry = pNewEntry;
	}

	// Set the information.
	pEntry->nIndex[nType] = nID;
	return TRUE;
}

BOOL CSystemIconLibrary::StopRefresh()
{
	m_cRefMutex.Lock();          // Don't walk over memory.
	m_bContinueRefresh = FALSE;
	m_cRefMutex.Unlock();

	return TRUE;
}

BOOL CSystemIconLibrary::RefreshPath(LPCTSTR czPath, CWnd *pStatusWnd)
{
	// Search this path, and recurse downwards.

	// We need to create our own file system handle to ensure
	// that FindFile's don't hit.  This isn't perfect; refresh
	// took a CFileSystem parameter, which tends to imply that
	// that is the file system we should be using here.
	CFileSystem cFS;
	CString cszPath = czPath;

	cszPath += CString(_T("*.*"));

	BOOL bFind = cFS.FindFile(cszPath);

	while ( bFind )
	{
		// Check to see if we should break.
		m_cRefMutex.Lock();
		if(!m_bContinueRefresh) { m_cRefMutex.Unlock(); return TRUE; };
		m_cRefMutex.Unlock();

		bFind = cFS.FindNextFile();

		if(cFS.IsDots())
			continue;

		if(cFS.IsDirectory())
		{
			// Recurse downwards.
			CString cszNewPath = cFS.GetFilePath();
			cszNewPath += CString(_T("\\"));

			RefreshPath(cszNewPath, pStatusWnd);
		}

		// Add the icon.
		UINT nIconID[3];
		CString cszFilePath = cFS.GetFilePath();
		SHFILEINFO shInfo;

		// TODO: Handle cross-icons.
		// Skip this if we've already added it.
		if(FindIcon(cszFilePath, 0) >= 0)
			continue;

		// Get the icon id's.
		cFS.FillFileInfo(cszFilePath, &shInfo, SHGFI_ICON | SHGFI_SMALLICON);
		nIconID[SMALL_ICON] = shInfo.iIcon;
		cFS.FillFileInfo(cszFilePath, &shInfo, SHGFI_ICON | SHGFI_LARGEICON);
		nIconID[LARGE_ICON] = shInfo.iIcon;

//      Can't do this; crashes some (poorly-written) callback DLLs.
//		cFS.FillFileInfo(cszFilePath, &shInfo, SHGFI_ICON | SHGFI_OPENICON);
//		nIconID[OPEN_ICON] = shInfo.iIcon;

		// Store the icon information.
		for(int i = 0; i < 3; i++)
			UpdateIcon(cszFilePath, nIconID[i], i, pStatusWnd);
	}

	return TRUE;
}

BOOL CSystemIconLibrary::PostDeleteEntries(TrieNode *pEntry)
{
	if(!pEntry) return FALSE;

	for(int i = 0; i < 256; i++)
	{
		if(pEntry->Next[i]) 
			PostDeleteEntries((TrieNode *)pEntry->Next[i]);
	}

	// Now do the post-delete.
	delete pEntry;

	return TRUE;
}

char *CSystemIconLibrary::ToBuffer(UINT &nSize)
{
	int nAlloc = 1024;
	UINT nEntries = 0;
	nSize = 0;
	SerialTrieNode *pSNode = new SerialTrieNode[nAlloc];

	ASSERT(pSNode);

	// Recursively serialize the trie.
	TCHAR tcBuffer[3];
	memset((void *)tcBuffer, 0, sizeof(tcBuffer));

	SerializeEntries(m_pTrieRoot, &pSNode,
		nAlloc, nEntries, tcBuffer);

	// Allocate memory for an end-of-stream entry.
	nEntries += 1;
	if((int)nEntries == nAlloc)
	{
		nAlloc += 1;

		SerialTrieNode *pNewSNode = new SerialTrieNode[nAlloc];
		ASSERT(pNewSNode);

		memcpy((void *)pNewSNode, (void *)pSNode, 
			sizeof(SerialTrieNode) * (nAlloc - 1));

		delete pSNode;
		pSNode = pNewSNode;
	}

	// Append an end-of-stream entry.
	memset((void *)&pSNode[nEntries - 1], 0, sizeof(SerialTrieNode));
	pSNode[nEntries - 1].nIndex[0] = 
		pSNode[nEntries - 1].nIndex[1] = pSNode[nEntries - 1].nIndex[2] = -5;

	nSize = nEntries * sizeof(SerialTrieNode);

	char *pMemPtr = (char *)pSNode;
	return (char *)pSNode;
}

BOOL CSystemIconLibrary::SerializeEntries(TrieNode *pEntry,
										  SerialTrieNode **ppSNode,
										  int &nAlloc,
										  UINT &nSize,
										  TCHAR tcSoFar[3])
{
	SerialTrieNode *pSNode = *ppSNode;

	// TODO: Add failure memory deletion.

	if(!pEntry || !pSNode)
		return FALSE;

	// Add the current entry.
	SerialTrieNode stNode;

	memcpy((void *)stNode.nIndex, (void *)pEntry->nIndex, sizeof(UINT) * 3);
	memcpy((void *)stNode.Ext, (void *)tcSoFar, sizeof(TCHAR) * 3);

	// Allocate more memory if necessary.
	nSize += 1;
	if((int)nSize == nAlloc)
	{
		nAlloc += 1024;

		SerialTrieNode *pNewSNode = new SerialTrieNode[nAlloc];
		ASSERT(pNewSNode);

		memcpy((void *)pNewSNode, (void *)pSNode, 
			sizeof(SerialTrieNode) * (nAlloc - 1024));

		delete pSNode;
		pSNode = pNewSNode;

		*ppSNode = pNewSNode;
	}

	// Push the new entry in.
	memcpy((void *)&pSNode[nSize - 1], (void *)&stNode, sizeof(SerialTrieNode));

	// Now add children.
	for(int i = 0; i < 256; i++)
	{
		if(!pEntry->Next[i]) continue;

		TCHAR tcBelow[3];
		memcpy((void *)tcBelow, tcSoFar, sizeof(TCHAR) * 3);

		// Presumes spaces after the '\0' are also '\0'.
		if(tcBelow[0] == _T('\0'))
			tcBelow[0] = (TCHAR)i;
		else if(tcBelow[1] == _T('\0'))
			tcBelow[1] = (TCHAR)i;
		else if(tcBelow[2] == _T('\0'))
			tcBelow[2] = (TCHAR)i;

		SerializeEntries((TrieNode *)pEntry->Next[i],
			ppSNode, nAlloc, nSize, tcBelow);
	}

	return TRUE;
}

int CSystemIconLibrary::FromBuffer(char *cBuffer)
{
	ASSERT(cBuffer != NULL);

	if(!cBuffer) return 0;

	// We don't store the special entries; these are recomputed
	// each time the program is run.

	// Clear the trie.
	PostDeleteEntries(m_pTrieRoot);
	m_pTrieRoot = new TrieNode;
	memset((void *)m_pTrieRoot, 0, sizeof(TrieNode));

	// Loop over the entries, adding each.
	int i = 0, j;
	SerialTrieNode *pSNode = (SerialTrieNode *)cBuffer;
	while(1)
	{
		// Break when we hit the end.
		if(pSNode[i].Ext[0] == _T('\0') &&
			pSNode[i].Ext[1] == _T('\0') &&
			pSNode[i].Ext[2] == _T('\0') &&
			pSNode[i].nIndex[0] == -5 &&
			pSNode[i].nIndex[1] == -5 &&
			pSNode[i].nIndex[2] == -5)
		{
			break;
		}

		// Add the current item.
		CString cszFakeName;
		cszFakeName = CString(_T("a.")) + pSNode[i].Ext;

		for(j = 0; j < 3; j++)
			UpdateIcon(cszFakeName, pSNode[i].nIndex[j], j);

		i++;
	}

	return i;
}

BOOL CSystemIconLibrary::UpdateSpecialIcon(int nSpecial, int nIcon, int nType)
{
	ASSERT(nSpecial >= 0 && nSpecial < 2);
	ASSERT(nType >= 0 && nType < 3);

	m_nSpecialIcon[nSpecial][nType] = nIcon;
	return TRUE;
}

int CSystemIconLibrary::FindSpecialIcon(int nSpecial, int nType)
{
	ASSERT(nSpecial >= 0 && nSpecial < 2);
	ASSERT(nType >= 0 && nType < 3);

	return m_nSpecialIcon[nSpecial][nType];
}

BOOL CSystemIconLibrary::UpdateSpecialIcons()
{
	// Use the local file system to find the sought icons.
	CFileSystem cFS;
	TCHAR  szDrives[512];
	TCHAR *pDrive;

	if ( !cFS.GetLogicalDriveStrings( sizeof(szDrives), szDrives ) )
		return FALSE;

	pDrive = szDrives;
	while( *pDrive )
	{
		// Search only non-removable disks; we don't want to have drives spin
		if(cFS.GetDriveType(pDrive) != DRIVE_REMOVABLE)
		{
			// We need to find the icons for a small drive, small folder,
			// small open folder, and large folder.

			CString cszDriveRoot = pDrive;
			SHFILEINFO shFinfo;

			// First, the drive.
			if ( !cFS.FillFileInfo( cszDriveRoot,
					&shFinfo,
					SHGFI_ICON | SHGFI_SMALLICON ) )
					return FALSE;

			UpdateSpecialIcon(SPECIALICON_DRIVE, shFinfo.iIcon, SMALL_ICON);
			UpdateSpecialIcon(SPECIALICON_DRIVE, shFinfo.iIcon, OPEN_ICON);

			// Second, the folders.
			// We need to find a folder.
			CString cszRootSearch = cszDriveRoot;
			cszRootSearch += _T("*.*");

			BOOL bFind = cFS.FindFile(cszRootSearch);

			while(bFind)
			{
				bFind = cFS.FindNextFile();
				if(cFS.IsDirectory())
				{
					// We found it.  Get the icons.

					CString cszDirName = cFS.GetFilePath();

					if ( !cFS.FillFileInfo( cszDirName,
							&shFinfo,
							SHGFI_ICON | SHGFI_SMALLICON ) )
							return FALSE;
					UpdateSpecialIcon(SPECIALICON_FOLDER, shFinfo.iIcon, SMALL_ICON);
					if ( !cFS.FillFileInfo( cszDirName,
							&shFinfo,
							SHGFI_ICON | SHGFI_OPENICON | SHGFI_SMALLICON ) )
							return FALSE;
					UpdateSpecialIcon(SPECIALICON_FOLDER, shFinfo.iIcon, OPEN_ICON);
					if ( !cFS.FillFileInfo( cszDirName,
							&shFinfo,
							SHGFI_ICON | SHGFI_LARGEICON ) )
							return FALSE;
					UpdateSpecialIcon(SPECIALICON_FOLDER, shFinfo.iIcon, LARGE_ICON);

					// Now we're done.
					return TRUE;
				}
			}
		}

		pDrive += strlen( pDrive ) + 1;      // Search all non-removable drives.
	}

	return FALSE;
}

int CSystemIconLibrary::UnknownIcon(int nType)
{
	// Get the app.
	COscarApp *pApp = (COscarApp *)AfxGetApp();
	ASSERT(pApp);

	ASSERT(nType >= 0 && nType < 2);
	if(nType < 0 || nType > 1) nType = 0;

	return pApp->m_nUnknownIcon[nType];
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -