Files
Client/Library/dxx8/samples/Multimedia/Demos/Duel/wizard.cpp
LGram16 e067522598 Initial commit: ROW Client source code
Game client codebase including:
- CharacterActionControl: Character and creature management
- GlobalScript: Network, items, skills, quests, utilities
- RYLClient: Main client application with GUI and event handlers
- Engine: 3D rendering engine (RYLGL)
- MemoryManager: Custom memory allocation
- Library: Third-party dependencies (DirectX, boost, etc.)
- Tools: Development utilities

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 16:24:34 +09:00

1296 lines
44 KiB
C++

//-----------------------------------------------------------------------------
// File: Wizard.cpp
//
// Desc: UI routines
//
// Copyright (C) 1995-2001 Microsoft Corporation. All Rights Reserved.
//-----------------------------------------------------------------------------
#include "duel.h"
#include "prsht.h"
#include "wizard.h"
#include "lobby.h"
#include "DPUtil.h"
#include "gameproc.h"
//-----------------------------------------------------------------------------
// Globals
//-----------------------------------------------------------------------------
extern HINSTANCE g_hInst; // Program instance
extern HWND g_hwndMain; // Main window
extern LPDIRECTPLAY4 g_pDP; // DPlay object pointer
extern BOOL g_bHostPlayer; // Is the user hosting/joining a game
extern DPID g_LocalPlayerDPID;// Player id
extern LPGUID g_pAppGUID; // Duel's guid
extern BOOL g_bUseProtocol; // DPlay Protocol messaging
static BOOL gbWaitForLobby; // We will Wait for Settings from Lobby
static HFONT ghTitleFont; // Font for titles on setup wizard
static HFONT ghHeadingFont; // Font for headings on setup wizard
static int gnSession; // Index for tree view images
static int gnPlayer; // Index for tree view images
static HKEY ghDuelKey = NULL; // Duel registry key handle
static DWORD gdwDuelDisp; // Key created or opened
static HTREEITEM ghtiSession; // Points to a visible session item in
// tree ctl used for inserting players
static HWND ghWndSPCtl; // Handle to service provider control
//-----------------------------------------------------------------------------
// Name: SetupFonts()
// Desc: Initializes font structures (used for wizard controls)
//-----------------------------------------------------------------------------
BOOL SetupFonts()
{
LOGFONT lf;
TCHAR strFontName[MAX_FONTNAME];
HDC hDC = GetDC(g_hwndMain);
if (!hDC)
return FALSE;
LoadString(g_hInst, IDS_WIZARD_FONTNAME, strFontName, MAX_FONTNAME);
ZeroMemory(&lf,sizeof(lf));
lf.lfHeight = -MulDiv(11,GetDeviceCaps(hDC, LOGPIXELSY),72);
lf.lfWeight = 500;
lf.lfItalic = TRUE;
_tcscpy( lf.lfFaceName, strFontName );
ghTitleFont = CreateFontIndirect(&lf);
ZeroMemory(&lf,sizeof(lf));
lf.lfHeight = -MulDiv(11,GetDeviceCaps(hDC, LOGPIXELSY),72);
lf.lfWeight = 500;
_tcscpy( lf.lfFaceName, strFontName );
ghHeadingFont = CreateFontIndirect(&lf);
ReleaseDC(g_hwndMain, hDC);
if (!ghTitleFont || !ghHeadingFont)
{
CleanupFonts();
return FALSE;
}
return TRUE;
}
//-----------------------------------------------------------------------------
// Name: CleanupFonts()
// Desc: Cleans up font structures
//-----------------------------------------------------------------------------
VOID CleanupFonts()
{
if (ghTitleFont)
DeleteObject(ghTitleFont);
if (ghHeadingFont)
DeleteObject(ghHeadingFont);
ghTitleFont = NULL;
ghHeadingFont = NULL;
}
//-----------------------------------------------------------------------------
// Name: RegSet()
// Desc: Stores a data value in the registry
//-----------------------------------------------------------------------------
LONG RegSet( const TCHAR* strName, const BYTE* pData, DWORD dwSize )
{
#ifdef UNICODE
dwSize *= 2; // calc number of bytes
#endif
return RegSetValueEx( ghDuelKey, strName, 0, REG_SZ, pData, dwSize );
}
//-----------------------------------------------------------------------------
// Name: RegGet()
// Desc: Queries a value from the registry
//-----------------------------------------------------------------------------
LONG RegGet( const TCHAR* strName, BYTE* pData, DWORD* pdwDataSize )
{
DWORD dwType;
return RegQueryValueEx( ghDuelKey, strName, NULL, &dwType, pData,
pdwDataSize );
}
//-----------------------------------------------------------------------------
// Name: DoWizard()
// Desc: Creates and launches a wizard (property sheets) for user input
//-----------------------------------------------------------------------------
DWORD WINAPI DoWizard(LPVOID pv)
{
PROPSHEETPAGE psp[4];
PROPSHEETHEADER psh;
TCHAR strTitle1[MAX_WINDOWTITLE];
TCHAR strTitle2[MAX_WINDOWTITLE];
TCHAR strTitle3[MAX_WINDOWTITLE];
TCHAR strTitle4[MAX_WINDOWTITLE];
TCHAR strTitle5[MAX_WINDOWTITLE];
CoInitialize(NULL);
// Setup the property pages
LoadString(g_hInst, IDS_WIZARD_TITLE_GS, strTitle1, MAX_WINDOWTITLE);
LoadString(g_hInst, IDS_WIZARD_TITLE_SP, strTitle2, MAX_WINDOWTITLE);
LoadString(g_hInst, IDS_WIZARD_TITLE_JS, strTitle3, MAX_WINDOWTITLE);
LoadString(g_hInst, IDS_WIZARD_TITLE_HS, strTitle4, MAX_WINDOWTITLE);
LoadString(g_hInst, IDS_WIZARD_TITLE, strTitle5, MAX_WINDOWTITLE);
psp[0].dwSize = sizeof(PROPSHEETPAGE);
psp[0].dwFlags = PSP_USETITLE;
psp[0].hInstance = g_hInst;
#ifdef NONAMELESSUNION
psp[0].u.pszTemplate = MAKEINTRESOURCE(IDD_GAMESETUP);
psp[0].u2.pszIcon = NULL;
#else
psp[0].pszTemplate = MAKEINTRESOURCE(IDD_GAMESETUP);
psp[0].pszIcon = NULL;
#endif
psp[0].pfnDlgProc = (DLGPROC)DlgProcGameSetup;
psp[0].pszTitle = strTitle1;
psp[0].lParam = 0;
psp[0].pfnCallback = NULL;
psp[1].dwSize = sizeof(PROPSHEETPAGE);
psp[1].dwFlags = PSP_USETITLE;
psp[1].hInstance = g_hInst;
#ifdef NONAMELESSUNION
psp[1].u.pszTemplate = MAKEINTRESOURCE(IDD_CHOOSEPROVIDER);
psp[1].u2.pszIcon = NULL;
#else
psp[1].pszTemplate = MAKEINTRESOURCE(IDD_CHOOSEPROVIDER);
psp[1].pszIcon = NULL;
#endif
psp[1].pfnDlgProc = (DLGPROC)DlgProcChooseProvider;
psp[1].pszTitle = strTitle2;
psp[1].lParam = 0;
psp[1].pfnCallback = NULL;
psp[2].dwSize = sizeof(PROPSHEETPAGE);
psp[2].dwFlags = PSP_USETITLE;
psp[2].hInstance = g_hInst;
#ifdef NONAMELESSUNION
psp[2].u.pszTemplate = MAKEINTRESOURCE(IDD_JOINSESSION);
psp[2].u2.pszIcon = NULL;
#else
psp[2].pszTemplate = MAKEINTRESOURCE(IDD_JOINSESSION);
psp[2].pszIcon = NULL;
#endif
psp[2].pfnDlgProc = (DLGPROC)DlgProcJoinSession;
psp[2].pszTitle = strTitle3;
psp[2].lParam = 0;
psp[2].pfnCallback = NULL;
psp[3].dwSize = sizeof(PROPSHEETPAGE);
psp[3].dwFlags = PSP_USETITLE;
psp[3].hInstance = g_hInst;
#ifdef NONAMELESSUNION
psp[3].u.pszTemplate = MAKEINTRESOURCE(IDD_HOSTSESSION);
psp[3].u2.pszIcon = NULL;
#else
psp[3].pszTemplate = MAKEINTRESOURCE(IDD_HOSTSESSION);
psp[3].pszIcon = NULL;
#endif
psp[3].pfnDlgProc = (DLGPROC)DlgProcHostSession;
psp[3].pszTitle = strTitle4;
psp[3].lParam = 0;
psp[3].pfnCallback = NULL;
psh.dwSize = sizeof(PROPSHEETHEADER);
psh.dwFlags = PSH_PROPSHEETPAGE | PSH_WIZARD;
psh.hwndParent = g_hwndMain;
psh.hInstance = g_hInst;
#ifdef NONAMELESSUNION
psh.u.pszIcon = NULL;
psh.u2.nStartPage = 0;
psh.u3.ppsp = (LPCPROPSHEETPAGE) &psp;
#else
psh.pszIcon = NULL;
psh.nStartPage = 0;
psh.ppsp = (LPCPROPSHEETPAGE) &psp;
#endif
psh.pszCaption = strTitle5;
psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE);
psh.pfnCallback = NULL;
// open/create duel registry key
if( ERROR_SUCCESS != RegCreateKeyEx( HKEY_CURRENT_USER, DUEL_KEY, 0, NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS, NULL, &ghDuelKey,
&gdwDuelDisp ) )
{
TRACE(_T("Failed to create/open registry key\n"));
ShowError(IDS_WIN_ERROR);
goto ABORT;
}
if (!SetupFonts())
{
TRACE(_T("Failed to create fonts\n"));
ShowError(IDS_WIN_ERROR);
goto ABORT;
}
// launch the wizard
if (PropertySheet(&psh) < 0)
{
TRACE(_T("PropertySheet failed (comctl32.dll)\n"));
ShowError(IDS_WIN_ERROR);
goto ABORT;
}
CleanupFonts();
// Are we going to wait for a lobby to connect to us?
if (gbWaitForLobby)
gbWaitForLobby = DPLobbyWait();
// gbWaitForLobby now means we successfully got our connection settings
// Do we have our settings or a game session?
if( gbWaitForLobby || DPUtil_IsDPlayInitialized() )
{
// success
CoUninitialize();
PostMessage(g_hwndMain, UM_LAUNCH, (WPARAM)gbWaitForLobby, 0);
gbWaitForLobby = FALSE; // done with this flag
return 0;
}
ABORT:
// failure
CoUninitialize();
PostMessage(g_hwndMain, UM_ABORT, 0, 0);
return 1;
}
//-----------------------------------------------------------------------------
// Name: DPEnumConnectionsCallback()
// Desc: Creates SP list box entries and associates connection data with them
//-----------------------------------------------------------------------------
BOOL FAR PASCAL DPEnumConnectionsCallback( const GUID* pguidSP,
VOID* pConnection, DWORD dwSize,
const DPNAME* pName, DWORD dwFlags,
VOID* pContext )
{
HWND hWnd = (HWND)pContext;
LRESULT iIndex;
VOID* pConnectionBuffer;
// Store service provider name in combo box
#ifdef UNICODE
iIndex = SendMessage( hWnd, LB_ADDSTRING, 0, (LPARAM)pName->lpszShortName );
#else
iIndex = SendMessage( hWnd, LB_ADDSTRING, 0, (LPARAM)pName->lpszShortNameA );
#endif
if( iIndex == CB_ERR )
return TRUE;
// Make space for Connection Shortcut
pConnectionBuffer = GlobalAllocPtr( GHND, dwSize );
if( pConnectionBuffer == NULL )
return TRUE;
// Store pointer to GUID in combo box
memcpy( pConnectionBuffer, pConnection, dwSize );
if( iIndex != LB_ERR )
SendMessage( hWnd, LB_SETITEMDATA, iIndex, (LPARAM)pConnectionBuffer );
return TRUE;
}
//-----------------------------------------------------------------------------
// Name: DlgProcChooseProvider()
// Desc: Dialog procedure for the choose service provider dialog
//-----------------------------------------------------------------------------
BOOL CALLBACK DlgProcChooseProvider( HWND hDlg, UINT msg, WPARAM wParam,
LPARAM lParam )
{
VOID* pCon = NULL;
static LONG iIndex;
static HWND hWndCtl;
HRESULT hr;
switch( msg )
{
case WM_NOTIFY:
switch( ((NMHDR FAR *)lParam)->code )
{
case PSN_SETACTIVE:
PropSheet_SetWizButtons( GetParent(hDlg),
PSWIZB_BACK | PSWIZB_NEXT );
return TRUE;
case PSN_WIZNEXT:
// Release previously selected DPlay object, if any.
DPUtil_Release();
if( iIndex != LB_ERR )
{
pCon = (VOID*)SendMessage( hWndCtl, LB_GETITEMDATA,
iIndex, 0 );
if( pCon )
{
// Create directplay object
if( SUCCEEDED( DPUtil_InitDirectPlay( pCon ) ) )
{
if( g_bHostPlayer ) // Skip to host page
SetWindowLong( hDlg, DWL_MSGRESULT,
IDD_HOSTSESSION );
return TRUE;
}
else
{
ShowError(IDS_DPLAY_ERROR_IDC);
}
}
}
SetWindowLong( hDlg, DWL_MSGRESULT, -1 );
return TRUE;
case PSN_QUERYCANCEL:
ReleaseSPData();
DPUtil_Release(); // Indicates no game session
return TRUE;
}
break;
case WM_INITDIALOG:
SendDlgItemMessage( hDlg, IDC_SP_TITLE, WM_SETFONT,
(WPARAM)ghTitleFont, MAKELPARAM(TRUE,0) );
hWndCtl = GetDlgItem( hDlg, IDC_SERVICEPROVIDERS );
if( hWndCtl == NULL )
return TRUE;
// Remember the service provider control. used later in freeing
// sp information.
ghWndSPCtl = hWndCtl;
if( FAILED( hr = DPUtil_InitDirectPlay( pCon ) ) )
{
// Class not available, so tell them to get DPlay 6 or later
if( (hr == REGDB_E_CLASSNOTREG) || (hr == REGDB_E_IIDNOTREG) ||
(hr == E_NOINTERFACE))
ShowError(IDS_DPLAY_ERROR_CLSID);
else
ShowError(IDS_DPLAY_ERROR_IDC);
SetWindowLong( hDlg, DWL_MSGRESULT, -1 );
PostQuitMessage( -1 );
return TRUE;
}
//Insert all available connections into the connection listbox.
g_pDP->EnumConnections( g_pAppGUID, DPEnumConnectionsCallback,
hWndCtl, 0 );
SetFocus( hWndCtl );
SendMessage( hWndCtl, LB_SETCURSEL, iIndex, 0 );
iIndex = SendMessage( hWndCtl, LB_GETCURSEL, 0, 0 );
return TRUE;
case WM_COMMAND:
if( HIWORD(wParam) == LBN_SELCHANGE )
{
iIndex = SendMessage( hWndCtl, LB_GETCURSEL, 0, 0 );
return TRUE;
}
break;
}
return FALSE;
}
//-----------------------------------------------------------------------------
// Name: DlgProcGameSetup()
// Desc: Dialog procedure for the Game Setup Dialog.
//-----------------------------------------------------------------------------
BOOL CALLBACK DlgProcGameSetup (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
static BOOL bWaitForLobby;
switch (msg)
{
case WM_NOTIFY:
switch (((NMHDR FAR *) lParam)->code)
{
case PSN_SETACTIVE:
if (bWaitForLobby)
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_FINISH);
else
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_NEXT);
return(TRUE);
case PSN_WIZNEXT:
if (g_bHostPlayer)
g_bUseProtocol = (SendDlgItemMessage(hDlg, IDC_USEPROTOCOL,
BM_GETCHECK, 0, 0)
== BST_CHECKED);
else
g_bUseProtocol = FALSE;
return(TRUE);
case PSN_WIZFINISH: // only if WaitForLobby selected
gbWaitForLobby = bWaitForLobby;
// fall thru
case PSN_QUERYCANCEL:
ReleaseSPData();
DPUtil_Release(); // Indicates no game session
return(TRUE);
}
break;
case WM_INITDIALOG:
// setup title fonts
SendDlgItemMessage(hDlg, IDC_GAMESETUP_TITLE, WM_SETFONT, (WPARAM)ghTitleFont, MAKELPARAM(TRUE,0));
SendDlgItemMessage(hDlg, IDC_JOINSESSION, WM_SETFONT, (WPARAM)ghHeadingFont, MAKELPARAM(TRUE,0));
SendDlgItemMessage(hDlg, IDC_HOSTSESSION, WM_SETFONT, (WPARAM)ghHeadingFont, MAKELPARAM(TRUE,0));
SendDlgItemMessage(hDlg, IDC_WAITFORLOBBY, WM_SETFONT, (WPARAM)ghHeadingFont, MAKELPARAM(TRUE,0));
SendDlgItemMessage(hDlg, IDC_USEPROTOCOL, WM_SETFONT, (WPARAM)ghHeadingFont, MAKELPARAM(TRUE,0));
// host by default
g_bHostPlayer = TRUE;
gbWaitForLobby = bWaitForLobby = FALSE;
SendDlgItemMessage(hDlg, IDC_HOSTSESSION, BM_SETCHECK, 1, 0);
SendDlgItemMessage(hDlg, IDC_JOINSESSION, BM_SETCHECK, 0, 0);
SendDlgItemMessage(hDlg, IDC_WAITFORLOBBY, BM_SETCHECK, 0, 0);
SendDlgItemMessage(hDlg, IDC_USEPROTOCOL, BM_SETCHECK, g_bUseProtocol, 0);
return(TRUE);
case WM_COMMAND:
if (HIWORD(wParam) == BN_CLICKED)
switch (LOWORD(wParam))
{
// Enable Use Protocol check box only if Hosting is selected
// Enable Finish Button only if WaitForLobby is selected
case IDC_HOSTSESSION:
g_bHostPlayer = TRUE;
EnableWindow(GetDlgItem(hDlg, IDC_USEPROTOCOL), TRUE);
if (bWaitForLobby)
{
bWaitForLobby = FALSE;
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_NEXT);
}
return(TRUE);
case IDC_JOINSESSION:
if (g_bHostPlayer)
{
g_bHostPlayer = FALSE;
EnableWindow(GetDlgItem(hDlg, IDC_USEPROTOCOL), FALSE);
}
if (bWaitForLobby)
{
bWaitForLobby = FALSE;
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_NEXT);
}
return(TRUE);
case IDC_WAITFORLOBBY:
bWaitForLobby = TRUE;
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_FINISH);
if (g_bHostPlayer)
{
g_bHostPlayer = FALSE;
EnableWindow(GetDlgItem(hDlg, IDC_USEPROTOCOL), FALSE);
}
return(TRUE);
}
break;
}
return(FALSE);
}
//-----------------------------------------------------------------------------
// Name: EnumPlayer()
// Desc: EnumeratePlayer callback. Inserts player information into the passed
// in tree view control.
//-----------------------------------------------------------------------------
BOOL WINAPI EnumPlayer( DPID pidID, DWORD dwPlayerType, const DPNAME* pName,
DWORD dwFlags, VOID* pContext )
{
HWND hWnd = (HWND)pContext;
HTREEITEM hItem;
#ifdef UNICODE
hItem = AddItemToTree( hWnd, pName->lpszShortName, 0, -1 );
#else
hItem = AddItemToTree( hWnd, pName->lpszShortNameA, 0, -1 );
#endif
return TRUE;
}
//-----------------------------------------------------------------------------
// Name: EnumSession()
// Desc: EnumSessions callback. Inserts session description information in the
// passed in tree view control.
//-----------------------------------------------------------------------------
BOOL WINAPI EnumSession( const DPSESSIONDESC2* pDPSessionDesc,
DWORD* pdwTimeOut, DWORD dwFlags, VOID* pContext )
{
HWND hWnd = (HWND)pContext;
HTREEITEM hItem;
TREEDATA* pdata;
if( dwFlags & DPESC_TIMEDOUT )
return FALSE; // don't try again
if( hWnd == NULL )
return FALSE;
// allocate memory to remember the guid
pdata = (TREEDATA*)malloc(sizeof(TREEDATA));
if( NULL == pdata )
return FALSE;
pdata->guid = pDPSessionDesc->guidInstance;
pdata->dwRefresh = 1;
#ifdef UNICODE
hItem = AddItemToTree( hWnd, pDPSessionDesc->lpszSessionName,
(DWORD)pdata, 1);
#else
hItem = AddItemToTree( hWnd, pDPSessionDesc->lpszSessionNameA,
(DWORD)pdata, 1);
#endif
if( hItem )
{
// It was new
TreeView_SelectItem( hWnd, hItem );
// Enumerate players for new session
DPUtil_EnumPlayers( (GUID*)&pDPSessionDesc->guidInstance, EnumPlayer,
(VOID*)hWnd, DPENUMPLAYERS_SESSION );
}
else
{
// It was already in the tree
free( pdata );
}
return TRUE;
}
//-----------------------------------------------------------------------------
// Name: ResetTreeRefresh()
// Desc:
//-----------------------------------------------------------------------------
VOID ResetTreeRefresh( HWND hwndTV )
{
TV_ITEM item;
HTREEITEM hItem;
TREEDATA* psearchdata;
memset( &item, 0, sizeof(item) );
// Get the first app item (child of the running apps item)
hItem = (HTREEITEM)SendMessage( hwndTV, TVM_GETNEXTITEM, TVGN_ROOT,(LPARAM) NULL);
while (hItem)
{
// gets its data
item.mask = TVIF_PARAM;
item.hItem = hItem;
SendMessage( hwndTV, TVM_GETITEM, 0, (LPARAM)&item );
// set the dwRefresh to 0
psearchdata = (TREEDATA*)item.lParam;
if (psearchdata) psearchdata->dwRefresh = 0;
SendMessage( hwndTV, TVM_SETITEM, 0, (LPARAM)&item );
// get the next one
hItem = (HTREEITEM)SendMessage( hwndTV, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem );
}
return ;
}
//-----------------------------------------------------------------------------
// Name: RemoveStaleSessions()
// Desc:
//-----------------------------------------------------------------------------
VOID RemoveStaleSessions( HWND hwndTV )
{
TV_ITEM item;
HTREEITEM hItem,hItemNext;
TREEDATA* psearchdata;
memset(&item,0,sizeof(item));
// get the first app item (child of the running apps item)
hItem = (HTREEITEM)SendMessage( hwndTV, TVM_GETNEXTITEM, TVGN_ROOT,(LPARAM) NULL);
while (hItem)
{
// get the next one
hItemNext = (HTREEITEM)SendMessage( hwndTV, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem );
// gets its data
item.mask = TVIF_PARAM;
item.hItem = hItem;
SendMessage( hwndTV, TVM_GETITEM, 0, (LPARAM)&item );
// if dwRefresh is still 0, it wasn't enum'ed
psearchdata = (TREEDATA*)item.lParam;
if (psearchdata && (0 == psearchdata->dwRefresh))
{
free(psearchdata);
SendMessage( hwndTV, TVM_DELETEITEM, 0, (LPARAM)hItem );
}
hItem = hItemNext;
}
return;
}
//-----------------------------------------------------------------------------
// Name: DlgProcJoinSession()
// Desc: Dialog procedure for Join Session Dialog
//-----------------------------------------------------------------------------
BOOL CALLBACK DlgProcJoinSession( HWND hDlg, UINT msg, WPARAM wParam,
LPARAM lParam )
{
static NM_TREEVIEW nmtv;
static HWND hWndCtl;
static TCHAR strPlayerName[MAX_PLAYERNAME+1];
static HANDLE dphEvent = NULL;
static UINT idTimer = 0;
TV_ITEM tvItem;
TCHAR strSessionName[MAX_SESSIONNAME+1];
DWORD dwPNameSize;
HRESULT hr = DP_OK;
HTREEITEM htiCur, htiNext;
GUID* pGuid;
switch( msg )
{
case WM_NOTIFY:
switch (((NMHDR FAR *) lParam)->code)
{
case PSN_SETACTIVE:
// Only the back button is valid at this point
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK);
if( hWndCtl )
TreeView_DeleteAllItems( hWndCtl );
// Enum sessions and let dplay decide the timeout
hr = DPUtil_EnumSessions( 0, EnumSession, (VOID*)hWndCtl,
DPENUMSESSIONS_ASYNC );
if( FAILED(hr) )
return FALSE;
// Enumerate players for all sessions
ghtiSession = TreeView_GetFirstVisible( hWndCtl );
while( ghtiSession )
{
// delete previous players from display
if ((htiNext = htiCur = TreeView_GetChild(hWndCtl, ghtiSession))
!= (HTREEITEM)0)
{
do
{
htiNext = TreeView_GetNextSibling(hWndCtl, htiCur);
TreeView_DeleteItem(hWndCtl, htiCur);
htiCur = htiNext;
} while (htiNext);
}
tvItem.hItem = ghtiSession;
tvItem.pszText = strSessionName;
tvItem.cchTextMax = MAX_SESSIONNAME;
TreeView_GetItem(hWndCtl, &tvItem);
// enumerate players for selected session
DPUtil_EnumPlayers( (GUID*)tvItem.lParam, EnumPlayer, (LPVOID) hWndCtl, DPENUMPLAYERS_SESSION);
ghtiSession = TreeView_GetNextItem(hWndCtl, ghtiSession, TVGN_NEXTVISIBLE);
}
// set Finish button highlite
if (GetDlgItemText(hDlg, IDC_JOIN_PLAYERNAME, strPlayerName, MAX_PLAYERNAME) &&
(htiCur = TreeView_GetSelection(hWndCtl)))
{
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK|PSWIZB_FINISH);
}
else
{
PropSheet_SetWizButtons(GetParent(hDlg),PSWIZB_BACK|PSWIZB_DISABLEDFINISH);
}
SetFocus(hWndCtl);
// start up timer
idTimer = SetTimer(hDlg, ENUM_TIMER_ID, ENUM_TIMEOUT, NULL);
return(TRUE);
case PSN_WIZFINISH:
if (idTimer)
{
KillTimer(hDlg, idTimer);
idTimer = 0;
}
// add user selections to registry
if (ghDuelKey)
{
RegSet(TEXT("PlayerName"), (CONST BYTE *)strPlayerName,
sizeof(strPlayerName));
}
// get the session guid
if (nmtv.itemNew.lParam)
{
// user selected a session item, so just grab its lParam
pGuid = (GUID*)nmtv.itemNew.lParam;
}
else
{
// user selected a player item, so grab its parent's (session) lParam
htiCur = TreeView_GetParent(hWndCtl, nmtv.itemNew.hItem);
if (!htiCur)
{
// fail finish
ShowError(IDS_WIZARD_ERROR_GSG);
SetWindowLong(hDlg, DWL_MSGRESULT, -1);
return (TRUE);
}
tvItem.hItem = htiCur;
tvItem.pszText = strSessionName;
tvItem.cchTextMax = MAX_SESSIONNAME;
TreeView_GetItem(hWndCtl, &tvItem);
pGuid = (GUID*)tvItem.lParam;
}
// Open session
if( FAILED( hr = DPUtil_OpenSession( pGuid ) ) )
{
// Fail finish
ShowError(IDS_DPLAY_ERROR_JS);
SetWindowLong(hDlg, DWL_MSGRESULT, -1);
return TRUE;
}
// create player
if( FAILED( hr = DPUtil_CreatePlayer( &g_LocalPlayerDPID, strPlayerName,
NULL, NULL, 0 ) ) )
{
// fail finish
ShowError(IDS_DPLAY_ERROR_CP);
SetWindowLong(hDlg, DWL_MSGRESULT, -1);
return (TRUE);
}
// everything went well, release allocated memory and finish
ReleaseSessionData(hWndCtl);
ReleaseSPData();
return(TRUE);
case PSN_QUERYCANCEL:
if (idTimer)
{
KillTimer(hDlg, idTimer);
idTimer = 0;
}
DPUtil_EnumSessions(0, EnumSession, (LPVOID)hWndCtl,
DPENUMSESSIONS_STOPASYNC);
ReleaseSessionData(hWndCtl);
ReleaseSPData();
DPUtil_Release(); // Indicates no game session
return(TRUE);
case PSN_WIZBACK:
if (idTimer)
{
KillTimer(hDlg, idTimer);
idTimer = 0;
}
DPUtil_EnumSessions(0, EnumSession, (LPVOID)hWndCtl,
DPENUMSESSIONS_STOPASYNC);
ReleaseSessionData(hWndCtl);
return(TRUE);
case TVN_SELCHANGING:
nmtv = *((NM_TREEVIEW *) lParam);
// set Finish button status
if (GetDlgItemText(hDlg, IDC_JOIN_PLAYERNAME, strPlayerName, MAX_PLAYERNAME) &&
(htiCur = TreeView_GetSelection(hWndCtl)))
{
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK|PSWIZB_FINISH);
}
else
{
PropSheet_SetWizButtons(GetParent(hDlg),PSWIZB_BACK|PSWIZB_DISABLEDFINISH);
}
return(FALSE);
case NM_CLICK:
return(FALSE);
}
break;
case WM_INITDIALOG:
// setup title fonts
SendDlgItemMessage(hDlg, IDC_JOIN_SESSION_TITLE, WM_SETFONT, (WPARAM)ghHeadingFont, MAKELPARAM(TRUE,0));
SendDlgItemMessage(hDlg, IDC_JOIN_PLAYER_TITLE, WM_SETFONT, (WPARAM)ghHeadingFont, MAKELPARAM(TRUE,0));
// setup user's previous data
dwPNameSize = MAX_PLAYERNAME+1;
strPlayerName[0]=0;
if (ghDuelKey && (RegGet(TEXT("PlayerName"),(LPBYTE)strPlayerName,&dwPNameSize) == ERROR_SUCCESS))
SetDlgItemText(hDlg, IDC_JOIN_PLAYERNAME, strPlayerName);
hWndCtl = GetDlgItem(hDlg, IDC_JOIN_SESSION);
if (hWndCtl == NULL) return(TRUE);
InitTreeViewImageLists(hWndCtl);
return(TRUE);
case WM_TIMER:
// guard against leftover timer messages after timer has been killed
if (!idTimer) break;
ResetTreeRefresh(hWndCtl);
// enum sessions and let dplay decide the timeout
hr = DPUtil_EnumSessions(0, EnumSession, (LPVOID) hWndCtl,
DPENUMSESSIONS_ASYNC);
if (FAILED(hr) && hr != DPERR_CONNECTING)
{
KillTimer(hDlg, idTimer);
idTimer = 0;
if (hr != DPERR_USERCANCEL)
ShowError(IDS_DPLAY_ERROR_ES);
}
RemoveStaleSessions(hWndCtl);
// set Finish button highlite
if (GetDlgItemText(hDlg, IDC_JOIN_PLAYERNAME, strPlayerName, MAX_PLAYERNAME) &&
(htiCur = TreeView_GetSelection(hWndCtl)))
{
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK|PSWIZB_FINISH);
}
else
{
PropSheet_SetWizButtons(GetParent(hDlg),PSWIZB_BACK|PSWIZB_DISABLEDFINISH);
}
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_JOIN_PLAYERNAME:
if (HIWORD(wParam) == EN_CHANGE)
{
// set Finish button status
if (GetDlgItemText(hDlg, IDC_JOIN_PLAYERNAME, strPlayerName, MAX_PLAYERNAME) &&
(htiCur = TreeView_GetSelection(hWndCtl)))
{
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK|PSWIZB_FINISH);
}
else
{
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK|PSWIZB_DISABLEDFINISH);
}
}
break;
}
break;
}
return FALSE;
}
//-----------------------------------------------------------------------------
// Name: DlgProcHostSession()
// Desc: Dialog proc for Host Session Dialog
//-----------------------------------------------------------------------------
BOOL CALLBACK DlgProcHostSession(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
static TCHAR strSessionName[MAX_SESSIONNAME+1];
static TCHAR strPlayerName[MAX_PLAYERNAME+1];
HRESULT hr;
DWORD dwPNameSize, dwSNameSize;
switch( msg )
{
case WM_NOTIFY:
switch (((NMHDR FAR *) lParam)->code)
{
case PSN_SETACTIVE:
if (GetDlgItemText(hDlg, IDC_HOST_SESSIONNAME, strSessionName, MAX_SESSIONNAME) &&
GetDlgItemText(hDlg, IDC_HOST_PLAYERNAME, strPlayerName, MAX_PLAYERNAME))
{
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK|PSWIZB_FINISH);
}
else
{
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK|PSWIZB_DISABLEDFINISH);
}
return(TRUE);
case PSN_WIZFINISH:
// add user selections to registry
if (ghDuelKey)
{
RegSet(TEXT("PlayerName"), (CONST BYTE *)strPlayerName, sizeof(strPlayerName));
RegSet(TEXT("SessionName"), (CONST BYTE *)strSessionName, sizeof(strSessionName));
}
// create session
if ((hr = DPUtil_CreateSession(strSessionName)) != DP_OK)
{
// fail finish
ShowError(IDS_DPLAY_ERROR_CS);
SetWindowLong(hDlg, DWL_MSGRESULT, -1);
return (TRUE);
}
// create player
if( FAILED( hr = DPUtil_CreatePlayer( &g_LocalPlayerDPID, strPlayerName,
NULL, NULL, 0 ) ) )
{
ShowError(IDS_DPLAY_ERROR_CP);
SetWindowLong(hDlg, DWL_MSGRESULT, -1);
return (TRUE);
}
// everything went well, release allocated memory and finish
ReleaseSPData();
return(TRUE);
case PSN_WIZBACK:
SetWindowLong(hDlg, DWL_MSGRESULT, IDD_CHOOSEPROVIDER);
return(TRUE);
case PSN_QUERYCANCEL:
// release allocated memory
ReleaseSPData();
// release dplay
DPUtil_Release(); // Indicates no game session
return(TRUE);
}
break;
case WM_INITDIALOG:
// setup title font
SendDlgItemMessage(hDlg, IDC_HOST_TITLE, WM_SETFONT, (WPARAM)ghTitleFont, MAKELPARAM(TRUE,0));
SendDlgItemMessage(hDlg, IDC_HOST_SESSION_TITLE, WM_SETFONT, (WPARAM)ghHeadingFont, MAKELPARAM(TRUE,0));
SendDlgItemMessage(hDlg, IDC_HOST_PLAYER_TITLE, WM_SETFONT, (WPARAM)ghHeadingFont, MAKELPARAM(TRUE,0));
dwPNameSize = MAX_PLAYERNAME+1;
dwSNameSize = MAX_SESSIONNAME+1;
strPlayerName[0]=0;
strSessionName[0]=0;
if (ghDuelKey)
{
if (RegGet(TEXT("PlayerName"), (LPBYTE)strPlayerName, &dwPNameSize) == ERROR_SUCCESS)
SetDlgItemText(hDlg, IDC_HOST_PLAYERNAME, strPlayerName);
if (RegGet(TEXT("SessionName"), (LPBYTE)strSessionName, &dwSNameSize) == ERROR_SUCCESS)
SetDlgItemText(hDlg, IDC_HOST_SESSIONNAME, strSessionName);
}
return(TRUE);
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_HOST_SESSIONNAME:
if (HIWORD(wParam) == EN_CHANGE)
{
if (GetDlgItemText(hDlg, IDC_HOST_SESSIONNAME, strSessionName, MAX_SESSIONNAME) &&
GetDlgItemText(hDlg, IDC_HOST_PLAYERNAME, strPlayerName, MAX_PLAYERNAME))
{
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK|PSWIZB_FINISH);
}
else
{
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK|PSWIZB_DISABLEDFINISH);
}
return TRUE;
}
break;
case IDC_HOST_PLAYERNAME:
if (HIWORD(wParam) == EN_CHANGE)
{
if (GetDlgItemText(hDlg, IDC_HOST_SESSIONNAME, strSessionName, MAX_SESSIONNAME) &&
GetDlgItemText(hDlg, IDC_HOST_PLAYERNAME, strPlayerName, MAX_PLAYERNAME))
{
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK|PSWIZB_FINISH);
}
else
{
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK|PSWIZB_DISABLEDFINISH);
}
}
break;
}
break;
}
return FALSE;
}
//-----------------------------------------------------------------------------
// Name: InitTreeViewImageLists()
// Desc: Creates an image list, adds bitmaps to it, and associates the image
// list with a tree-view control.
//-----------------------------------------------------------------------------
BOOL InitTreeViewImageLists(HWND hwndTV)
{
HIMAGELIST himl; // handle of image list
HBITMAP hbmp; // handle of bitmap
// Create the image list.
if ((himl = ImageList_Create(CX_BITMAP, CY_BITMAP,
FALSE, NUM_BITMAPS, 0)) == NULL)
return FALSE;
// Add the session and player bitmaps.
hbmp = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_CLOSED_SESSION));
gnSession = ImageList_Add(himl, hbmp, (HBITMAP) NULL);
DeleteObject(hbmp);
hbmp = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_PLAYER));
gnPlayer = ImageList_Add(himl, hbmp, (HBITMAP) NULL);
DeleteObject(hbmp);
// Fail if not all of the images were added.
if (ImageList_GetImageCount(himl) < 2)
return FALSE;
// Associate the image list with the tree-view control.
TreeView_SetImageList(hwndTV, himl, TVSIL_NORMAL);
return TRUE;
}
//-----------------------------------------------------------------------------
// Name: FindItemInTree()
// Desc:
//-----------------------------------------------------------------------------
HTREEITEM FindItemInTree( HWND hwndTV, TREEDATA* pdata )
{
TV_ITEM item;
HTREEITEM hItem;
TREEDATA* psearchdata;
memset(&item,0,sizeof(item));
// get the first app item (child of the running apps item)
hItem = (HTREEITEM)SendMessage( hwndTV, TVM_GETNEXTITEM, TVGN_ROOT,(LPARAM) NULL);
while (hItem)
{
// gets its data
item.mask = TVIF_PARAM;
item.hItem = hItem;
SendMessage( hwndTV, TVM_GETITEM, 0, (LPARAM)&item );
// is this the one?
psearchdata = (TREEDATA*)item.lParam;
if( IsEqualGUID( psearchdata->guid, pdata->guid ) )
{
// mark the item as seen
psearchdata->dwRefresh = 1;
SendMessage( hwndTV, TVM_SETITEM, 0, (LPARAM)&item );
return hItem;
}
// try the next one
hItem = (HTREEITEM)SendMessage( hwndTV, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem );
}
return NULL;
}
//-----------------------------------------------------------------------------
// Name: AddItemToTree()
// Desc: Adds items to a tree-view control.
//-----------------------------------------------------------------------------
HTREEITEM AddItemToTree( HWND hwndTV, TCHAR* strItem, DWORD dwData,
int nLevel )
{
static HTREEITEM hPrev = (HTREEITEM) TVI_FIRST;
static HTREEITEM hPrevRootItem = NULL;
static HTREEITEM hPrevLev2Item = NULL;
HTREEITEM hItem;
TV_ITEM tvi;
TV_INSERTSTRUCT tvins;
if( 1 == nLevel )
{
hItem = FindItemInTree( hwndTV, (TREEDATA*)dwData );
if (hItem) return NULL;
}
memset( &tvi,0,sizeof(tvi) );
memset( &tvins,0,sizeof(tvins) );
tvi.mask = TVIF_TEXT | TVIF_IMAGE
| TVIF_SELECTEDIMAGE | TVIF_PARAM;
// Set the state
if (nLevel == 1)
{
tvi.mask |= TVIF_STATE;
tvi.state = TVIS_SELECTED;
}
// Set the text of the item.
tvi.pszText = strItem;
// Set the image
if (nLevel == 1)
{
tvi.iImage = gnSession;
tvi.iSelectedImage = gnSession;
}
else
{
tvi.iImage = gnPlayer;
tvi.iSelectedImage = gnPlayer;
}
// Save the heading level in the item's application-defined
// data area.
tvi.lParam = (LPARAM) dwData;
#ifdef NONAMELESSUNION
tvins.u.item = tvi;
#else
tvins.item = tvi;
#endif
tvins.hInsertAfter = hPrev;
// Set the parent item based on the specified level.
if (nLevel == -1)
tvins.hParent = hPrevRootItem;
else if (nLevel == 1)
tvins.hParent = TVI_ROOT;
else if (nLevel == 2)
tvins.hParent = hPrevRootItem;
else
tvins.hParent = hPrevLev2Item;
// Add the item to the tree-view control.
hPrev = (HTREEITEM) SendMessage(hwndTV, TVM_INSERTITEM, 0,
(LPARAM) (LPTV_INSERTSTRUCT) &tvins);
// Save the handle of the item.
if (nLevel == 1)
hPrevRootItem = hPrev;
else if (nLevel == 2)
hPrevLev2Item = hPrev;
return hPrev;
}
//-----------------------------------------------------------------------------
// Name: ReleaseSessionData()
// Desc:
//-----------------------------------------------------------------------------
VOID ReleaseSessionData(HWND hWndCtl)
{
HTREEITEM htiSession = TreeView_GetRoot( hWndCtl );
while( htiSession )
{
TCHAR strSessionName[MAX_SESSIONNAME+1];
TV_ITEM tvItem;
tvItem.hItem = htiSession;
tvItem.pszText = strSessionName;
tvItem.cchTextMax = MAX_SESSIONNAME;
TreeView_GetItem( hWndCtl, &tvItem );
if( tvItem.lParam )
free( (VOID*)tvItem.lParam );
htiSession = TreeView_GetNextSibling( hWndCtl, htiSession );
}
}
//-----------------------------------------------------------------------------
// Name: ReleaseSPData()
// Desc: Releases the memory allocated for service provider guids
// depends on global variable ghWndSPControl
//-----------------------------------------------------------------------------
VOID ReleaseSPData()
{
LPVOID lpCon = NULL;
int count,index;
if (ghWndSPCtl)
{
count = SendMessage(ghWndSPCtl, LB_GETCOUNT, 0, 0);
for (index = 0; index < count; index++)
{
lpCon = (LPVOID) SendMessage(ghWndSPCtl, LB_GETITEMDATA, index, 0);
if (lpCon) GlobalFreePtr(lpCon);
}
}
}