//-----------------------------------------------------------------------------
// File: uiglobals.cpp
//
// Desc: CUIGlobals is a class that packs and holds most information
//       relevent to a UI session.  Many classes make reference to
//       CUIGlobals all the time.
//
//       CPaintHelper encapsulates GDI calls, simplifying GDI operations.
//
// Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
//-----------------------------------------------------------------------------

#include "common.hpp"
#define __DEFINE_ELEMENT_STRUCTURES__
#include "uielements.h"


static const GUID GUID_DIConfigAppEditLayout = 
{ 0xfd4ace13, 0x7044, 0x4204, { 0x8b, 0x15, 0x9, 0x52, 0x86, 0xb1, 0x2e, 0xad } };


CUIGlobals::CUIGlobals(UIG_PARAMS_DEFINE) :

	// globals...
	m_hrInit(S_OK),

	m_hrFinalResult(S_OK),

	m_hInst(NULL),
	m_lpDI(NULL),

	m_dwFlags(0),
	m_wszUserNames(NULL),
	m_pSurface(NULL),
	m_pSurface3D(NULL),
	m_lpCallback(NULL),
	m_pvRefData(NULL),

	m_bAllowEditLayout(FALSE),

	m_bUseColorSet(FALSE),

	// ui...
	m_pElement(NULL),
	m_nElements(0),
	m_pFont(NULL),
	m_nFonts(0),
	m_pBrush(NULL),
	m_nBrushes(0),
	m_pPen(NULL),
	m_nPens(0),
	m_pColor(NULL),
	m_nColors(0)
{
	tracescope(__ts,_T("CUIGlobals::CUIGlobals()\n"));

	m_hrInit = Init(UIG_PARAMS_DEFINE_PASS);
}

void CUIGlobals::SetTableColor(UICOLOR uic, COLORREF c)
{
	UICOLORINFO *info = GetColorInfo(uic);
	assert(info != NULL);
	if (info == NULL)
		return;

	info->rgb = c;
}

HRESULT CUIGlobals::Init(UIG_PARAMS_DEFINE)
{tracescope(__ts,_T("CUIGlobals::Init(...)\n"));

	HRESULT hr = S_OK;

	// get instance handle
	m_hInst = (HINSTANCE)g_hModule;
	if (m_hInst == NULL)
	{
		etrace(_T("hInst NULL\n"));
		return E_FAIL;
	}

	// create direct input
	DWORD dwVer = DIRECTINPUT_VERSION;
	hr = DirectInput8Create(m_hInst, dwVer, IID_IDirectInput8W, (LPVOID *)&m_lpDI, NULL);
	if (FAILED(hr) || m_lpDI == NULL)
	{
		m_lpDI = NULL;
		etrace2(_T("Could not create DirectInput ver 0x%08x\n  -> DirectInputCreateEx() returned 0x%08x\n"), dwVer, hr);
		return hr;
	}

	// save flags
	m_dwFlags = dwFlags;
#ifdef CFGUI__FORCE_NON_NULL_WSZUSERNAMES
	if (wszUserNames == NULL)
		wszUserNames = _T("Forced Non-NULL Username");
#endif
	if (wszUserNames == NULL)
	{
		etrace(_T("wszUserNames was passed NULL\n"));
		return E_FAIL;
	}

	// save user names
	m_wszUserNames = DupSuperString(wszUserNames);
	if (m_wszUserNames == NULL)
	{
		etrace(_T("Could not duplicate user names\n"));
		return E_FAIL;
	}

	// make sure we were passed an action format
	if (lpAcFor == NULL)
	{
		etrace(_T("lpAcFor param NULL\n"));
		return E_INVALIDARG;
	}

	// copy the acfor to the master
	hr = InitMasterAcForArray(lpAcFor, int(dwNumAcFor));
	if (FAILED(hr))
	{
		etrace1(_T("InitMasterAcForArray() failed, returning 0x%08x\n"), hr);
		return hr;
	}

	// get surface
	if (lpSurface != NULL)
	{
		hr = lpSurface->QueryInterface(IID_IDirect3DSurface8, (void **)&m_pSurface3D);
		if (FAILED(hr) || m_pSurface3D == NULL)
		{
			m_pSurface3D = NULL;
		}

		hr = lpSurface->QueryInterface(IID_IDirectDrawSurface, (void **)&m_pSurface);
		if (FAILED(hr) || m_pSurface == NULL)
		{
			m_pSurface = NULL;
		}

		if (m_pSurface == NULL && m_pSurface3D == NULL)
			etrace(_T("lpSurface was non-NULL but could not get IDirect3DSurface8 or IID_IDirectDrawSurface from it"));
	}

	// save callback and ref data
	m_lpCallback = lpCallback;
	m_pvRefData = pvRefData;

	// see whether or not we're allowing edit layout mode
	m_bAllowEditLayout = IsEqualGUID(RefMasterAcFor(0).guidActionMap,
		GUID_DIConfigAppEditLayout);

	// init a bunch of stuff necessary for painting
	if (!InitColorsAndTablesAndObjects(lpDIColorSet))
		return E_FAIL;

	// dump info if debug
#ifdef DBG
	Dump();
#endif

	// return success if we got here
	return S_OK;
}

BOOL CUIGlobals::InitColorsAndTablesAndObjects(LPDICOLORSET lpDIColorSet)
{tracescope(__ts,_T("CUIGlobals::InitColorsAndTablesAndObjects()\n"));

	// init ui tables
	if (!InitTables())
	{
		etrace(_T("Could not initialize tables\n"));
		return FALSE;
	}

	// decide whether or not to use the passed colorset
	if (lpDIColorSet != NULL)
	{
		m_ColorSet = *lpDIColorSet;

		m_bUseColorSet = !IsZeroOrInvalidColorSet(m_ColorSet);
	}
	else
		m_bUseColorSet = FALSE;

	// use it, or use defaults
	if (m_bUseColorSet)
	{
		// transfer colors from passed colorset
		SetTableColor(UIC_TEXTFORE, D3DCOLOR2COLORREF(m_ColorSet.cTextFore));
		SetTableColor(UIC_TEXTHIGHLIGHT, D3DCOLOR2COLORREF(m_ColorSet.cTextHighlight));
		SetTableColor(UIC_CALLOUTLINE, D3DCOLOR2COLORREF(m_ColorSet.cCalloutLine));
		SetTableColor(UIC_CALLOUTHIGHLIGHT, D3DCOLOR2COLORREF(m_ColorSet.cCalloutHighlight));
		SetTableColor(UIC_BORDER, D3DCOLOR2COLORREF(m_ColorSet.cBorder));
		SetTableColor(UIC_CONTROLFILL, D3DCOLOR2COLORREF(m_ColorSet.cControlFill));
		SetTableColor(UIC_HIGHLIGHTFILL, D3DCOLOR2COLORREF(m_ColorSet.cHighlightFill));
		SetTableColor(UIC_AREAFILL, D3DCOLOR2COLORREF(m_ColorSet.cAreaFill));
	}
	else
	{
		// use default colors
		SetTableColor(UIC_TEXTFORE,				RGB(255, 255, 255));
		SetTableColor(UIC_TEXTHIGHLIGHT,		RGB(  0, 255,   0));
		SetTableColor(UIC_CALLOUTLINE,			RGB(255, 255, 255));
		SetTableColor(UIC_CALLOUTHIGHLIGHT,		RGB(  0, 255,   0));
		SetTableColor(UIC_BORDER,				RGB(255, 255,   0));
		SetTableColor(UIC_CONTROLFILL,			RGB(  0, 191,   0));
		SetTableColor(UIC_HIGHLIGHTFILL,		RGB(  0,   0,   0));
		SetTableColor(UIC_AREAFILL,				RGB(  0,   0,   0));
	}

	// create the table objects
	CreateObjects();

	return TRUE;
}

CUIGlobals::~CUIGlobals()
{
	tracescope(__ts,_T("CUIGlobals::~CUIGlobals()\n"));

	if (m_wszUserNames != NULL)
		free((LPVOID)m_wszUserNames);
	m_wszUserNames = NULL;

	if (m_lpDI != NULL)
		m_lpDI->Release();
	m_lpDI = NULL;

	if (m_pSurface != NULL)
		m_pSurface->Release();
	m_pSurface = NULL;

	if (m_pSurface3D != NULL)
		m_pSurface3D->Release();
	m_pSurface3D = NULL;

	ClearMasterAcForArray();

	ClearTables();
}

void CUIGlobals::Dump()
{
	tracescope(ts, _T("UIGlobals...\n\n"));

	traceHEXPTR(m_hInst);
	traceHEXPTR(m_lpDI);
	LPTSTR str = AllocConfigureFlagStr(m_dwFlags);
	trace1(_T("m_dwFlags = %s\n"), str);
	free(str);
	traceSUPERSTR(m_wszUserNames);
	traceHEXPTR(m_pSurface);
	traceHEXPTR(m_pSurface3D);
	traceHEXPTR(m_lpCallback);
	traceBOOL(m_bAllowEditLayout);
	{
		tracescope(__csts, _T("m_ColorSet...\n"));
		traceHEX(m_ColorSet.cTextFore);
		traceHEX(m_ColorSet.cTextHighlight);
		traceHEX(m_ColorSet.cCalloutLine);
		traceHEX(m_ColorSet.cCalloutHighlight);
		traceHEX(m_ColorSet.cBorder);
		traceHEX(m_ColorSet.cControlFill);
		traceHEX(m_ColorSet.cHighlightFill);
		traceHEX(m_ColorSet.cAreaFill);
	}
	traceBOOL(m_bUseColorSet);
	trace(_T("\n"));
	TraceActionFormat(_T("Master ActionFormat 0:"), RefMasterAcFor(0));
	trace(_T("\n\n"));
}

LPDIRECTINPUT8W CUIGlobals::GetDI()
{
	if (m_lpDI == NULL)
		return NULL;

	m_lpDI->AddRef();
	return m_lpDI;
}

IDirectDrawSurface *CUIGlobals::GetSurface()
{
	if (m_pSurface == NULL)
		return NULL;

	m_pSurface->AddRef();
	return m_pSurface;
}

IDirect3DSurface8 *CUIGlobals::GetSurface3D()
{
	if (m_pSurface3D == NULL)
		return NULL;

	m_pSurface3D->AddRef();
	return m_pSurface3D;
}

void CUIGlobals::DeleteObjects()
{
	// make sure all our gdi objects are deleted
	int i;
	if (m_pFont != NULL)
		for (i = 0; i <	m_nFonts; i++)
		{
			UIFONTINFO &info = m_pFont[i];
			if (info.hFont != NULL)
				DeleteObject(info.hFont);
			info.hFont = NULL;
		}
	if (m_pBrush != NULL)
		for (i = 0; i <	m_nBrushes; i++)
		{
			UIBRUSHINFO &info = m_pBrush[i];
			if (info.hBrush != NULL)
				DeleteObject(info.hBrush);
			info.hBrush = NULL;
			if (info.hPen != NULL)
				DeleteObject(info.hPen);
			info.hPen = NULL;
		}
	if (m_pPen != NULL)
		for (i = 0; i <	m_nPens; i++)
		{
			UIPENINFO &info = m_pPen[i];
			if (info.hPen != NULL)
				DeleteObject(info.hPen);
			info.hPen = NULL;
		}
}

void CUIGlobals::ClearTables()
{
	// make sure all our gdi objects are deleted
	DeleteObjects();

	// delete the tables, null the pointers, and zero the counters
#define FREETABLE(member, memnum) \
{ \
	if (member != NULL) \
		delete [] member; \
	member = NULL; \
	memnum = 0; \
}
	FREETABLE(m_pElement, m_nElements);
	FREETABLE(m_pFont, m_nFonts);
	FREETABLE(m_pBrush, m_nBrushes);
	FREETABLE(m_pPen, m_nPens);
	FREETABLE(m_pColor, m_nColors);
}

BOOL CUIGlobals::InitTables()
{
	BOOL bSuccess = TRUE;

	// make sure the tables have been cleared
	ClearTables();

	// allocate our own copies of all the tables
#define ALLOCTABLE(member, memnum, type, init, num) \
{ \
	member = new type [memnum = num]; \
	if (member == NULL) \
	{ \
		memnum = 0; \
		bSuccess = FALSE; \
	} \
	else \
		memcpy(member, init, sizeof(type) * memnum); \
}
	ALLOCTABLE(m_pElement, m_nElements, UIELEMENTINFO, uielement, NUMUIELEMENTS);
	ALLOCTABLE(m_pFont, m_nFonts, UIFONTINFO, uifont, NUMUIFONTS);
	ALLOCTABLE(m_pBrush, m_nBrushes, UIBRUSHINFO, uibrush, NUMUIBRUSHES);
	ALLOCTABLE(m_pPen, m_nPens, UIPENINFO, uipen, NUMUIPENS);
	ALLOCTABLE(m_pColor, m_nColors, UICOLORINFO, uicolor, NUMUICOLORS);

	return bSuccess;
}

void CUIGlobals::RecreateObjects()
{
	DeleteObjects();
	CreateObjects();
}

void CUIGlobals::CreateObjects()
{
	// make sure all our gdi objects are created
	int i;
	if (m_pFont != NULL)
	{
		HDC hDC = GetDC(NULL);
		for (i = 0; i <	m_nFonts; i++)
		{
			UIFONTINFO &info = m_pFont[i];
			if (info.hFont == NULL)
			{
				LOGFONT lf;
				lf.lfHeight = -MulDiv(info.nPointSize, GetDeviceCaps(hDC, LOGPIXELSY), 72);
				lf.lfWidth = 0;
				lf.lfEscapement = 0;
				lf.lfOrientation = 0;
				lf.lfWeight = info.bBold ? FW_BOLD : FW_NORMAL;
				lf.lfItalic = FALSE;
				lf.lfUnderline = FALSE;
				lf.lfStrikeOut = FALSE;
				lf.lfCharSet = DEFAULT_CHARSET;
				lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
				lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
				lf.lfQuality = PROOF_QUALITY;
				lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
				_tcscpy(lf.lfFaceName, info.lfFaceName);

				info.hFont = (HGDIOBJ)CreateFontIndirect(&lf);
			}
		}
		ReleaseDC(NULL, hDC);
	}
	if (m_pBrush != NULL)
		for (i = 0; i <	m_nBrushes; i++)
		{
			UIBRUSHINFO &info = m_pBrush[i];
			if (info.hBrush == NULL)
				info.hBrush = (HGDIOBJ)CreateSolidBrush(GetColor(info.eColor));
			if (info.hPen == NULL)
				info.hPen = (HGDIOBJ)CreatePen(PS_SOLID, 1, GetColor(info.eColor));
		}
	if (m_pPen != NULL)
		for (i = 0; i <	m_nPens; i++)
		{
			UIPENINFO &info = m_pPen[i];
			if (info.hPen == NULL)
				info.hPen = (HGDIOBJ)CreatePen(info.fnPenStyle, info.nWidth, GetColor(info.eColor));
		}
}


#define IMPLGETINFO(Type, TYPE, Types, t) \
UI##TYPE##INFO *CUIGlobals::Get##Type##Info(UI##TYPE t) \
{ \
	if (m_p##Type != NULL) \
		for (int i = 0; i < m_n##Types; i++) \
			if (m_p##Type[i].e##Type == t) \
				return &(m_p##Type[i]); \
	return NULL; \
}

IMPLGETINFO(Element, ELEMENT, Elements, e)
IMPLGETINFO(Font, FONT, Fonts, f)
IMPLGETINFO(Brush, BRUSH, Brushes, b)
IMPLGETINFO(Pen, PEN, Pens, p)
IMPLGETINFO(Color, COLOR, Colors, c)

#undef IMPLGETINFO


#define IMPLGET(T, Name, Type, TYPE, v, def, ret) \
T CUIGlobals::Get##Name(UI##TYPE ui##v) \
{ \
	UI##TYPE##INFO *v = Get##Type##Info(ui##v); \
	if (!v) \
		return def; \
	return ret; \
}

IMPLGET(HGDIOBJ, Font, Element, ELEMENT, e, NULL, GetFont(e->eFont))
IMPLGET(HGDIOBJ, Font, Font, FONT, f, NULL, f->hFont)
IMPLGET(HGDIOBJ, Brush, Element, ELEMENT, e, NULL, GetBrush(e->eBrush))
IMPLGET(HGDIOBJ, Brush, Brush, BRUSH, b, NULL, b->hBrush)
IMPLGET(HGDIOBJ, Pen, Element, ELEMENT, e, NULL, GetPen(e->ePen))
IMPLGET(HGDIOBJ, Pen, Brush, BRUSH, b, NULL, b->hPen)
IMPLGET(HGDIOBJ, Pen, Pen, PEN, p, NULL, p->hPen)
IMPLGET(COLORREF, BrushColor, Element, ELEMENT, e, RGB(255, 127, 127), GetColor(e->eBrush))
IMPLGET(COLORREF, PenColor, Element, ELEMENT, e, RGB(255, 127, 127), GetColor(e->ePen))
IMPLGET(COLORREF, TextColor, Element, ELEMENT, e, RGB(255, 127, 127), GetColor(e->eText))
IMPLGET(COLORREF, BkColor, Element, ELEMENT, e, RGB(255, 127, 127), GetColor(e->eBk))
IMPLGET(COLORREF, Color, Brush, BRUSH, b, RGB(255, 127, 127), GetColor(b->eColor))
IMPLGET(COLORREF, Color, Pen, PEN, p, RGB(255, 127, 127), GetColor(p->eColor))
IMPLGET(COLORREF, Color, Color, COLOR, c, RGB(255, 127, 127), c->rgb)

#undef IMPLGET


CPaintHelper::CPaintHelper(CUIGlobals &uig, HDC hDC) :
	m_uig(uig), m_priv_hDC(hDC), m_hDC(m_priv_hDC),
	m_eFont(UIF_VOID),
	m_eBrush(UIB_VOID),
	m_ePen(UIP_VOID),
	m_eText(UIC_VOID),
	m_eBk(UIC_VOID),
	m_hOldFont(NULL), m_hOldBrush(NULL), m_hOldPen(NULL),
	m_bOldFont(FALSE), m_bOldBrush(FALSE), m_bOldPen(FALSE)
{
	if (m_hDC != NULL)
	{
		m_oldtextcolor = GetTextColor(m_hDC);
		m_oldbkcolor = GetBkColor(m_hDC);
		m_oldbkmode = GetBkMode(m_hDC);
	}
}

CPaintHelper::~CPaintHelper()
{
	if (m_hDC != NULL)
	{
		if (m_bOldFont)
			SelectObject(m_hDC, m_hOldFont);
		if (m_bOldBrush)
			SelectObject(m_hDC, m_hOldBrush);
		if (m_bOldPen)
			SelectObject(m_hDC, m_hOldPen);

		SetTextColor(m_hDC, m_oldtextcolor);
		SetBkColor(m_hDC, m_oldbkcolor);
		SetBkMode(m_hDC, m_oldbkmode);
	}
}

void CPaintHelper::SetElement(UIELEMENT eElement)
{
	UIELEMENTINFO *info = m_uig.GetElementInfo(eElement);
	if (!info)
		return;

	if (info->eFont != UIF_LAST)
		SetFont(info->eFont);
	if (info->eBrush != UIB_LAST)
		SetBrush(info->eBrush);
	if (info->ePen != UIP_LAST)
		SetPen(info->ePen);
	SetText(info->eText, info->eBk);
}

void CPaintHelper::SetFont(UIFONT eFont)
{
	if (m_eFont == eFont || eFont == UIF_LAST)
		return;

	HGDIOBJ hObj = m_uig.GetFont(eFont);
	if (hObj == NULL)
		return;

	if (m_hDC != NULL)
	{
		HGDIOBJ hOld = NULL;
		hOld = SelectObject(m_hDC, hObj);
		if (!m_bOldFont)
			m_hOldFont = hOld;
		m_bOldFont = TRUE;
	}

	m_eFont = eFont;
}

void CPaintHelper::SetBrush(UIBRUSH eBrush)
{
	if (m_eBrush == eBrush || eBrush == UIB_LAST)
		return;

	HGDIOBJ hObj = eBrush == UIB_NULL ?
		GetStockObject(NULL_BRUSH) :
		m_uig.GetBrush(eBrush);
	if (hObj == NULL)
		return;

	if (m_hDC != NULL)
	{
		HGDIOBJ hOld = NULL;
		hOld = SelectObject(m_hDC, hObj);
		if (!m_bOldBrush)
			m_hOldBrush = hOld;
		m_bOldBrush = TRUE;
	}

	m_eBrush = eBrush;
}

void CPaintHelper::SetPen(UIPEN ePen)
{
	if (m_ePen == ePen || ePen == UIP_LAST)
		return;

	HGDIOBJ hObj = ePen == UIB_NULL ?
		GetStockObject(NULL_PEN) :
		m_uig.GetPen(ePen);
	if (hObj == NULL)
		return;

	if (m_hDC != NULL)
	{
		HGDIOBJ hOld = NULL;
		hOld = SelectObject(m_hDC, hObj);
		if (!m_bOldPen)
			m_hOldPen = hOld;
		m_bOldPen = TRUE;
	}

	m_ePen = ePen;
}

void CPaintHelper::SetText(UICOLOR eText, UICOLOR eBk)
{
	if (m_eText != eText && eText != UIC_LAST)
	{
		if (m_hDC != NULL)
			SetTextColor(m_hDC, m_uig.GetColor(eText));
		m_eText = eText;
	}
	if (m_eBk != eBk && eBk != UIC_LAST)
	{
		if (m_hDC != NULL)
		{
			if (eBk == UIC_NULL)
				SetBkMode(m_hDC, TRANSPARENT);
			else 
			{
				SetBkColor(m_hDC, m_uig.GetColor(eBk));
				SetBkMode(m_hDC, OPAQUE);
			}
		}
		m_eBk = eBk;
	}
}

BOOL CPaintHelper::LineTo(int x, int y)
{
	if (m_hDC == NULL)
		return FALSE;

	return ::LineTo(m_hDC, x, y);
}

BOOL CPaintHelper::MoveTo(int x, int y, SPOINT *last)
{
	if (m_hDC == NULL)
		return FALSE;

	POINT p;
	BOOL bRet = MoveToEx(m_hDC, x, y, &p);
	if (last)
		*last = p;
	return bRet;
}

BOOL CPaintHelper::Rectangle(SRECT r, UIRECTTYPE eType)
{
	// fail on no dc
	if (m_hDC == NULL)
		return FALSE;

	// see if we lack a pen or brush (might add more checks later)
	BOOL bNoPen = m_ePen == UIP_NULL;
	BOOL bNoBrush = m_eBrush == UIB_NULL;

	// fail if trying to do an outline without a pen
	if (eType == UIR_OUTLINE && bNoPen)
		return FALSE;

	// fail if trying to do a solid without a brush
	if (eType == UIR_SOLID && bNoBrush)
		return FALSE;

	// save old objects if we change anything...
	HGDIOBJ hOldBrush = NULL, hOldPen = NULL;

	// select a null brush if we're doing an outline and we're not already null brushed
	if (eType == UIR_OUTLINE && m_eBrush != UIB_NULL)
		hOldBrush = SelectObject(m_hDC, GetStockObject(NULL_BRUSH));

	// select a pen the same color as the current brush if doing solid
	if (eType == UIR_SOLID || m_ePen == UIP_NULL)
	{
		HGDIOBJ hPen = m_uig.GetPen(m_eBrush);
		if (hPen == NULL)
			return FALSE;
		hOldPen = SelectObject(m_hDC, hPen);
	}

	// draw the rect
	BOOL bRet = ::Rectangle(m_hDC, r.left, r.top, r.right, r.bottom);

	// restore whatever changed
	if (eType == UIR_OUTLINE && m_eBrush != UIB_NULL)
		SelectObject(m_hDC, hOldBrush);
	if (eType == UIR_SOLID || m_ePen == UIP_NULL)
		SelectObject(m_hDC, hOldPen);

	return bRet;
}

const DIACTIONFORMATW &CUIGlobals::RefMasterAcFor(int i)
{
	assert(IsValidMasterAcForIndex(i));
	return m_MasterAcForArray[i];
}

BOOL CUIGlobals::IsValidMasterAcForIndex(int i)
{
	if (i < 0 || i >= m_MasterAcForArray.GetSize())
		return FALSE;

	return TRUE;
}

HRESULT CUIGlobals::InitMasterAcForArray(const DIACTIONFORMATW *af, int n)
{
	if (n < 1)
		return E_FAIL;

	ClearMasterAcForArray();

	m_MasterAcForArray.SetSize(n);

	for (int i = 0; i < n; i++)
	{
		HRESULT hr = CopyActionFormat(m_MasterAcForArray[i], af[i]);
		if (FAILED(hr))
		{
			m_MasterAcForArray.SetSize(i);
			ClearMasterAcForArray();

			return hr;
		}
	}

	return S_OK;
}

void CUIGlobals::ClearMasterAcForArray()
{
	int s = m_MasterAcForArray.GetSize();

	for (int i = 0; i < s; i++)
		CleanupActionFormatCopy(m_MasterAcForArray[i]);

	m_MasterAcForArray.RemoveAll();
	assert(m_MasterAcForArray.GetSize() == 0);
}

LPCWSTR CUIGlobals::GetUserName(int i)
{
	return GetSubString(m_wszUserNames, i);
}

int CUIGlobals::GetNumUserNames()
{
	return CountSubStrings(m_wszUserNames);
}

void CUIGlobals::SetFinalResult(HRESULT hr)
{
	m_hrFinalResult = hr;
}

HRESULT CUIGlobals::GetFinalResult()
{
	return m_hrFinalResult;
}

int CUIGlobals::GetUserNameIndex(LPCWSTR wsz)
{
	for (int i = 0; i < GetNumUserNames(); i++)
		if (_wcsicmp(wsz, GetUserName(i)) == 0)
			return i;

	return -1;
}