Click here to Skip to main content
15,885,365 members
Articles / Desktop Programming / MFC

XTrueColorToolBar - True-color toolbar with support for Office-style color button

Rate me:
Please Sign up or sign in to vote.
4.69/5 (20 votes)
10 Jan 2008CPOL5 min read 72.7K   4.2K   63  
XTrueColorToolBar is an MFC class based on CToolBar that provides support for true-color bitmaps, with optional support for an Office-style color picker button.
// convert.cpp : implementation file
//
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1998 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.

#include "stdafx.h"
#include "wordpad.h"
#include "multconv.h"
#include "mswd6_32.h"

#pragma warning(disable : 4996)	// disable bogus deprecation warning

#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif

#ifdef CONVERTERS
CConverter* CConverter::m_pThis = NULL;
#endif

#define BUFFSIZE 4096

CTrackFile::CTrackFile(CFrameWnd* pWnd) : CFile()
{
	m_nLastPercent = -1;
	m_dwLength = 0;
	m_pFrameWnd = pWnd;
	VERIFY(m_strComplete.LoadString(IDS_COMPLETE));
	VERIFY(m_strWait.LoadString(IDS_PLEASE_WAIT));
	VERIFY(m_strSaving.LoadString(IDS_SAVING));
//  OutputPercent(0);
}

CTrackFile::~CTrackFile()
{
	OutputPercent(100);
	if (m_pFrameWnd != NULL)
		m_pFrameWnd->SetMessageText(AFX_IDS_IDLEMESSAGE);
}

UINT CTrackFile::Read(void FAR* lpBuf, UINT nCount)
{
	UINT n = CFile::Read(lpBuf, nCount);
	if (m_dwLength != 0)
		OutputPercent((int)((GetPosition()*100)/m_dwLength));
	return n;
}

void CTrackFile::Write(const void FAR* lpBuf, UINT nCount)
{
	CFile::Write(lpBuf, nCount);
	OutputString(m_strSaving);
//  if (m_dwLength != 0)
//      OutputPercent((int)((GetPosition()*100)/m_dwLength));
}

void CTrackFile::OutputString(LPCTSTR lpsz)
{
	if (m_pFrameWnd != NULL)
	{
		m_pFrameWnd->SetMessageText(lpsz);
		CWnd* pBarWnd = m_pFrameWnd->GetMessageBar();
		if (pBarWnd != NULL)
			pBarWnd->UpdateWindow();
	}
}

void CTrackFile::OutputPercent(int nPercentComplete)
{
	if (m_pFrameWnd != NULL && m_nLastPercent != nPercentComplete)
	{
		m_nLastPercent = nPercentComplete;
		TCHAR buf[64];
		int n = nPercentComplete;
		wsprintf(buf, (n==100) ? m_strWait : m_strComplete, n);
		OutputString(buf);
	}
}

COEMFile::COEMFile(CFrameWnd* pWnd) : CTrackFile(pWnd)
{
}

UINT COEMFile::Read(void FAR* lpBuf, UINT nCount)
{
	UINT n = CTrackFile::Read(lpBuf, nCount);
	OemToCharBuffA((const char*)lpBuf, (char*)lpBuf, n);
	return n;
}

void COEMFile::Write(const void FAR* lpBuf, UINT nCount)
{
	CharToOemBuffA((const char*)lpBuf, (char*)lpBuf, nCount);
	CTrackFile::Write(lpBuf, nCount);
}

#ifdef CONVERTERS

HGLOBAL CConverter::StringToHGLOBAL(LPCSTR pstr)
{
	HGLOBAL hMem = NULL;
	if (pstr != NULL)
	{
		hMem = GlobalAlloc(GHND, (lstrlenA(pstr)*2)+1);
		char* p = (char*) GlobalLock(hMem);
		ASSERT(p != NULL);
		if (p != NULL)
			lstrcpyA(p, pstr);
		GlobalUnlock(hMem);
	}
	return hMem;
}

CConverter::CConverter(LPCSTR pszLibName, CFrameWnd* pWnd) : CTrackFile(pWnd)
{
	USES_CONVERSION;
	m_hBuff = NULL;
	m_pBuf = NULL;
	m_nBytesAvail = 0;
	m_nBytesWritten = 0;
	m_nPercent = 0;
	m_hEventFile = NULL;
	m_hEventConv = NULL;
	m_bDone = TRUE;
	m_bConvErr = FALSE;
	m_hFileName = NULL;
	OFSTRUCT ofs;
	if (OpenFile(pszLibName, &ofs, OF_EXIST) == HFILE_ERROR)
	{
		m_hLibCnv = NULL;
		return;
	}
	m_hLibCnv = LoadLibraryA(pszLibName);
	if (m_hLibCnv < (HINSTANCE)HINSTANCE_ERROR)
		m_hLibCnv = NULL;
	else
	{
		LoadFunctions();
		ASSERT(m_pInitConverter != NULL);
		if (m_pInitConverter != NULL)
		{
			CString str = AfxGetAppName();
			str.MakeUpper();
			VERIFY(m_pInitConverter(AfxGetMainWnd()->GetSafeHwnd(), T2CA(str)));
		}
	}
}

CConverter::CConverter(CFrameWnd* pWnd) : CTrackFile(pWnd)
{
	m_pInitConverter = NULL;
	m_pIsFormatCorrect = NULL;
	m_pForeignToRtf = NULL;
	m_pRtfToForeign = NULL;
	m_bConvErr = FALSE;
	m_hFileName = NULL;
}

CConverter::~CConverter()
{
	if (!m_bDone) // converter thread hasn't exited
	{
		WaitForConverter();
		m_nBytesAvail = 0;
		VERIFY(ResetEvent(m_hEventFile));
		m_nBytesAvail = 0;
		SetEvent(m_hEventConv);
		WaitForConverter();// wait for DoConversion exit
		VERIFY(ResetEvent(m_hEventFile));
	}

	if (m_hEventFile != NULL)
		VERIFY(CloseHandle(m_hEventFile));
	if (m_hEventConv != NULL)
		VERIFY(CloseHandle(m_hEventConv));
	if (m_hLibCnv != NULL)
		FreeLibrary(m_hLibCnv);
	if (m_hFileName != NULL)
		GlobalFree(m_hFileName);
}

void CConverter::WaitForConverter()
{
	// while event not signalled -- process messages
	while (MsgWaitForMultipleObjects(1, &m_hEventFile, FALSE, INFINITE,
		QS_SENDMESSAGE) != WAIT_OBJECT_0)
	{
		MSG msg;
		PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE);
	}
}

void CConverter::WaitForBuffer()
{
	// while event not signalled -- process messages
	while (MsgWaitForMultipleObjects(1, &m_hEventConv, FALSE, INFINITE,
		QS_SENDMESSAGE) != WAIT_OBJECT_0)
	{
		MSG msg;
		PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE);
	}
}

UINT CConverter::ConverterThread(LPVOID)
{
	ASSERT(m_pThis != NULL);

	HRESULT hRes = OleInitialize(NULL);
	ASSERT(hRes == S_OK || hRes == S_FALSE);
	m_pThis->DoConversion();
	OleUninitialize();

	return 0;
}

BOOL CConverter::IsFormatCorrect(LPCTSTR pszFileName)
{
	USES_CONVERSION;
	int nRet;
	if (m_hLibCnv == NULL || m_pIsFormatCorrect == NULL)
		return FALSE;

	char buf[_MAX_PATH];
	strcpy(buf, T2CA(pszFileName));

	CharToOemA(buf, buf);

	HGLOBAL hFileName = StringToHGLOBAL(buf);
	HGLOBAL hDesc = GlobalAlloc(GHND, 256);
	ASSERT(hDesc != NULL);
	nRet = m_pIsFormatCorrect(hFileName, hDesc);
	GlobalFree(hDesc);
	GlobalFree(hFileName);
	return (nRet == 1) ? TRUE : FALSE;
}

// static callback function
int CALLBACK CConverter::WriteOutStatic(int cch, int nPercentComplete)
{
	ASSERT(m_pThis != NULL);
	return m_pThis->WriteOut(cch, nPercentComplete);
}

int CALLBACK CConverter::WriteOut(int cch, int nPercentComplete)
{
	ASSERT(m_hBuff != NULL);
	m_nPercent = nPercentComplete;
	if (m_hBuff == NULL)
		return -9;
	if (cch != 0)
	{
		WaitForBuffer();
		VERIFY(ResetEvent(m_hEventConv));
		m_nBytesAvail = cch;
		SetEvent(m_hEventFile);
		WaitForBuffer();
	}
	return 0; //everything OK
}

int CALLBACK CConverter::ReadInStatic(int /*flags*/, int nPercentComplete)
{
	ASSERT(m_pThis != NULL);
	return m_pThis->ReadIn(nPercentComplete);
}

int CALLBACK CConverter::ReadIn(int /*nPercentComplete*/)
{
	ASSERT(m_hBuff != NULL);
	if (m_hBuff == NULL)
		return -8;

	SetEvent(m_hEventFile);
	WaitForBuffer();
	VERIFY(ResetEvent(m_hEventConv));

	return m_nBytesAvail;
}

BOOL CConverter::DoConversion()
{
	USES_CONVERSION;
	m_nLastPercent = -1;
//  m_dwLength = 0; // prevent Read/Write from displaying
	m_nPercent = 0;

	ASSERT(m_hBuff != NULL);
	ASSERT(m_pThis != NULL);
	HGLOBAL hDesc = StringToHGLOBAL("");
	HGLOBAL hSubset = StringToHGLOBAL("");

	int nRet = 0;
	if (m_bForeignToRtf)
	{
		ASSERT(m_pForeignToRtf != NULL);
		ASSERT(m_hFileName != NULL);
		nRet = m_pForeignToRtf(m_hFileName, NULL, m_hBuff, hDesc, hSubset,
			(LPFNOUT)WriteOutStatic);
		// wait for next CConverter::Read to come through
		WaitForBuffer();
		VERIFY(ResetEvent(m_hEventConv));
	}
	else if (!m_bForeignToRtf)
	{
		ASSERT(m_pRtfToForeign != NULL);
		ASSERT(m_hFileName != NULL);
		nRet = m_pRtfToForeign(m_hFileName, NULL, m_hBuff, hDesc,
			(LPFNIN)ReadInStatic);
		// don't need to wait for m_hEventConv
	}

	GlobalFree(hDesc);
	GlobalFree(hSubset);
	if (m_pBuf != NULL)
		GlobalUnlock(m_hBuff);
	GlobalFree(m_hBuff);

	if (nRet != 0)
		m_bConvErr = TRUE;

	m_bDone = TRUE;
	m_nPercent = 100;
	m_nLastPercent = -1;

	SetEvent(m_hEventFile);

	return (nRet == 0);
}

void CConverter::LoadFunctions()
{
	m_pInitConverter = (PINITCONVERTER)GetProcAddress(m_hLibCnv, "InitConverter32");
	m_pIsFormatCorrect = (PISFORMATCORRECT)GetProcAddress(m_hLibCnv, "IsFormatCorrect32");
	m_pForeignToRtf = (PFOREIGNTORTF)GetProcAddress(m_hLibCnv, "ForeignToRtf32");
	m_pRtfToForeign = (PRTFTOFOREIGN)GetProcAddress(m_hLibCnv, "RtfToForeign32");
}
#endif

///////////////////////////////////////////////////////////////////////////////

BOOL CConverter::Open(LPCTSTR pszFileName, UINT nOpenFlags,
	CFileException* pException)
{
	USES_CONVERSION;
	// we convert to oem and back because of the following case
	// test(c).txt becomes testc.txt in OEM and stays testc.txt to Ansi
	char buf[_MAX_PATH];
	strcpy(buf, T2CA(pszFileName));
	CharToOemA(buf, buf);
	OemToCharA(buf, buf);

	LPTSTR lpszFileNameT = A2T(buf);

	// let's make sure we could do what is wanted directly even though we aren't
	m_bCloseOnDelete = FALSE;
#if _MSC_VER >= 1400
	m_hFile = hFileNull;
#else
	m_hFile = (UINT)hFileNull;
#endif

	BOOL bOpen = CFile::Open(lpszFileNameT, nOpenFlags, pException);
	CFile::Close();
	if (!bOpen)
		return FALSE;

	m_bForeignToRtf = !(nOpenFlags & (CFile::modeReadWrite | CFile::modeWrite));

	// check for reading empty file
	if (m_bForeignToRtf)
	{
		CFileStatus stat;
		if (CFile::GetStatus(lpszFileNameT, stat) && stat.m_size == 0)
			return TRUE;
	}

	//set security attributes to inherit handle
	SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
	//create the events
	m_hEventFile = CreateEvent(&sa, TRUE, FALSE, NULL);
	m_hEventConv = CreateEvent(&sa, TRUE, FALSE, NULL);
	//create the converter thread and create the events

	CharToOemA(buf, buf);
	ASSERT(m_hFileName == NULL);
	m_hFileName = StringToHGLOBAL(buf);

	m_pThis = this;
	m_bDone = FALSE;
	m_hBuff = GlobalAlloc(GHND, BUFFSIZE);
	ASSERT(m_hBuff != NULL);

	AfxBeginThread(ConverterThread, this, THREAD_PRIORITY_NORMAL, 0, 0, &sa);

	return TRUE;
}

// m_hEventConv -- the main thread signals this event when ready for more data
// m_hEventFile -- the converter signals this event when data is ready

UINT CConverter::Read(void FAR* lpBuf, UINT nCount)
{
	ASSERT(m_bForeignToRtf);
	if (m_bDone)
		return 0;
	// if converter is done
	int cch = nCount;
	BYTE* pBuf = (BYTE*)lpBuf;
	while (cch != 0)
	{
		if (m_nBytesAvail == 0)
		{
			if (m_pBuf != NULL)
				GlobalUnlock(m_hBuff);
			m_pBuf = NULL;
			SetEvent(m_hEventConv);
			WaitForConverter();
			VERIFY(ResetEvent(m_hEventFile));
			if (m_bConvErr)
				AfxThrowFileException(CFileException::generic);
			if (m_bDone)
				return nCount - cch;
			m_pBuf = (BYTE*)GlobalLock(m_hBuff);
			ASSERT(m_pBuf != NULL);
		}
		int nBytes = min(cch, m_nBytesAvail);
		memcpy(pBuf, m_pBuf, nBytes);
		pBuf += nBytes;
		m_pBuf += nBytes;
		m_nBytesAvail -= nBytes;
		cch -= nBytes;
		OutputPercent(m_nPercent);
	}
	return nCount - cch;
}

void CConverter::Write(const void FAR* lpBuf, UINT nCount)
{
	ASSERT(!m_bForeignToRtf);

	m_nBytesWritten += nCount;
	while (nCount != 0)
	{
		WaitForConverter();
		VERIFY(ResetEvent(m_hEventFile));
		if (m_bConvErr)
			AfxThrowFileException(CFileException::generic);
		m_nBytesAvail = min(nCount, BUFFSIZE);
		nCount -= m_nBytesAvail;
		BYTE* pBuf = (BYTE*)GlobalLock(m_hBuff);
		ASSERT(pBuf != NULL);
		memcpy(pBuf, lpBuf, m_nBytesAvail);
		GlobalUnlock(m_hBuff);
		SetEvent(m_hEventConv);
	}
	OutputString(m_strSaving);
}

LONG CConverter::Seek(LONG lOff, UINT nFrom)
{
	if (lOff != 0 && nFrom != current)
		AfxThrowNotSupportedException();
	return 0;
}

#if _MSC_VER >= 1400
ULONGLONG 
#else
DWORD
#endif
CConverter::GetPosition() const
{
	return 0;
}

void CConverter::Flush()
{
}

void CConverter::Close()
{
}

void CConverter::Abort()
{
}

#if _MSC_VER >= 1400
ULONGLONG 
#else
DWORD
#endif
CConverter::GetLength() const
{
	ASSERT_VALID(this);
	return 1;
}

CFile* CConverter::Duplicate() const
{
	AfxThrowNotSupportedException();
#if _MSC_VER < 1400
	return NULL;
#endif
}

void CConverter::LockRange(DWORD, DWORD)
{
	AfxThrowNotSupportedException();
}

void CConverter::UnlockRange(DWORD, DWORD)
{
	AfxThrowNotSupportedException();
}

void CConverter::SetLength(DWORD)
{
	AfxThrowNotSupportedException();
}

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
Software Developer (Senior) Hans Dietrich Software
United States United States
I attended St. Michael's College of the University of Toronto, with the intention of becoming a priest. A friend in the University's Computer Science Department got me interested in programming, and I have been hooked ever since.

Recently, I have moved to Los Angeles where I am doing consulting and development work.

For consulting and custom software development, please see www.hdsoft.org.






Comments and Discussions