windows-nt/Source/XPSP1/NT/multimedia/directx/dinput/diconfig/uiglobals.cpp
2020-09-26 16:20:57 +08:00

772 lines
17 KiB
C++

//-----------------------------------------------------------------------------
// 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;
}