Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1071 lines
29 KiB

/*==========================================================================
*
* Copyright (C) 1996-1997 Microsoft Corporation. All Rights Reserved.
*
* File: dplenum.c
* Content: Methods for enumeration
*
* History:
* Date By Reason
* ======= ======= ======
* 4/13/96 myronth Created it
* 10/23/96 myronth Added client/server methods
* 12/10/96 myronth Fixed bugs #4622 and #5043
* 2/12/97 myronth Mass DX5 changes
* 3/4/97 myronth Fixed enum size bug #6149
* 3/12/97 myronth Added EnumConnections
* 3/25/97 kipo EnumConnections takes a const *GUID now
* 4/7/97 myronth Fixed PRV_EnumConnections to use CreateCompoundAddress
* 5/10/97 kipo added GUID to EnumConnections callback
* 5/14/97 myronth Check for valid guid in EnumLocalApps, bug #7695
* 5/17/97 myronth Fixed bug #8506 (return bogus error if last app
* is invalid), fixed more GUIDFromString bugs
* 8/22/97 myronth Added registry support for Description and Private
* values, also cleaned up LP enumeration code
* 11/20/97 myronth Made EnumConnections & DirectPlayEnumerate
* drop the lock before calling the callback (#15208)
* 12/2/97 myronth Changed EnumLocalApp to use Desc fields (#15448)
* 01/20/98 sohailm Don't free sp list after EnumConnections (#17006)
* 10/22/99 aarono Add support to hide apps from enum calls
***************************************************************************/
#include "dplobpr.h"
//--------------------------------------------------------------------------
//
// Definitions
//
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
//
// Globals
//
//--------------------------------------------------------------------------
LPLSPNODE glpLSPHead = NULL;
//--------------------------------------------------------------------------
//
// Functions
//
//--------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_CallEnumAddressTypesCallback"
HRESULT PRV_CallEnumAddressTypesCallback(HKEY hkeySP,
LPDPLENUMADDRESSTYPESCALLBACK lpfnEnumCallback,
LPVOID lpContext)
{
HRESULT hr;
WCHAR wszGuidStr[GUID_STRING_SIZE];
DWORD dwGuidStrSize = sizeof(wszGuidStr)/sizeof(WCHAR);
GUID guidAddressType;
HKEY hkeyAddressTypes;
DWORD dwIndex = 0;
LONG lReturn;
BOOL bReturn = TRUE;
DPF(7, "Entering PRV_CallEnumAddressTypesCallback");
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x",
hkeySP, lpfnEnumCallback, lpContext);
ASSERT(hkeySP);
// Get the Address Type registry key
lReturn = OS_RegOpenKeyEx(hkeySP, SZ_ADDRESS_TYPES, 0,
KEY_READ, &hkeyAddressTypes);
if(lReturn != ERROR_SUCCESS)
{
DPF_ERR("No Address Types found for the Service Provider!");
return DP_OK;
}
// Walk the list of Address Types in the registry, looking for the GUID passed in
while((ERROR_NO_MORE_ITEMS != OS_RegEnumKeyEx(hkeyAddressTypes, dwIndex++,
(LPWSTR)wszGuidStr, &dwGuidStrSize, NULL, NULL, NULL, NULL)) && bReturn)
{
// Convert the string to a real GUID
hr = GUIDFromString(wszGuidStr, &guidAddressType);
if(FAILED(hr))
{
DPF_ERR("Couldn't convert Address Type string to GUID");
dwGuidStrSize = sizeof(wszGuidStr)/sizeof(WCHAR);
continue;
}
// Call the callback
bReturn = ((LPDPLENUMADDRESSTYPESCALLBACK)lpfnEnumCallback)
(&guidAddressType, lpContext, 0L);
// Reset the size variable in the success case
dwGuidStrSize = sizeof(wszGuidStr)/sizeof(WCHAR);
}
// Close the Address Types key
RegCloseKey(hkeyAddressTypes);
return DP_OK;
} // PRV_CallEnumAddressTypesCallback
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_EnumAddressTypes"
HRESULT PRV_EnumAddressTypes(LPDIRECTPLAYLOBBY lpDPL,
LPDPLENUMADDRESSTYPESCALLBACK lpfnEnumCallback,
REFGUID guidSPIn, LPVOID lpContext, DWORD dwFlags)
{
LPDPLOBBYI_DPLOBJECT this;
HRESULT hr = DP_OK;
HKEY hkeySPHead, hkeySP;
DWORD dwIndex = 0;
DWORD dwNameSize;
WCHAR wszSPName[DPLOBBY_REGISTRY_NAMELEN];
WCHAR wszGuidStr[GUID_STRING_SIZE];
DWORD dwGuidStrSize = sizeof(wszGuidStr)/sizeof(WCHAR);
DWORD dwType = REG_SZ;
GUID guidSP;
LONG lReturn;
BOOL bFound = FALSE;
DPF(7, "Entering PRV_EnumAddressTypes");
DPF(9, "Parameters: 0x%08x, 0x%08x, guid, 0x%08x, 0x%08x",
lpDPL, lpfnEnumCallback, lpContext, dwFlags);
TRY
{
if( !VALID_DPLOBBY_INTERFACE( lpDPL ))
{
return DPERR_INVALIDINTERFACE;
}
this = DPLOBJECT_FROM_INTERFACE(lpDPL);
if( !VALID_DPLOBBY_PTR( this ) )
{
return DPERR_INVALIDOBJECT;
}
if( !VALIDEX_CODE_PTR( lpfnEnumCallback ) )
{
return DPERR_INVALIDPARAMS;
}
if (!VALID_READ_PTR(guidSPIn, sizeof(GUID)))
{
DPF_ERR("Invalid SP GUID pointer");
return DPERR_INVALIDPARAMS;
}
// There are no flags defined for DX3
if( dwFlags )
{
return DPERR_INVALIDPARAMS;
}
}
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
{
DPF_ERR( "Exception encountered validating parameters" );
return DPERR_INVALIDPARAMS;
}
// Open the Service Providers key
lReturn = OS_RegOpenKeyEx(HKEY_LOCAL_MACHINE, SZ_DPLAY_SP_KEY, 0,
KEY_READ, &hkeySPHead);
if(lReturn != ERROR_SUCCESS)
{
// This just means that the Service Providers key doesn't exist (most
// likely), so in that case, there are no SP's to enumerate.
DPF_ERR("There are no Service Providers registered");
return DP_OK;
}
// Walk the list of SP's in the registry, looking for the GUID passed in
while(!bFound)
{
// Get the next SP in the list
dwNameSize = DPLOBBY_REGISTRY_NAMELEN;
lReturn = OS_RegEnumKeyEx(hkeySPHead, dwIndex++, (LPWSTR)wszSPName,
&dwNameSize, NULL, NULL, NULL, NULL);
// If lReturn is ERROR_NO_MORE_ITEMS, we want to end on this iteration
if(lReturn == ERROR_NO_MORE_ITEMS)
break;;
// Open the SP key
lReturn = OS_RegOpenKeyEx(hkeySPHead, (LPWSTR)wszSPName, 0,
KEY_READ, &hkeySP);
if(lReturn != ERROR_SUCCESS)
{
DPF_ERR("Unable to open key for Service Provider!");
continue;
}
// Get the GUID of the SP
dwGuidStrSize = GUID_STRING_SIZE;
lReturn = OS_RegQueryValueEx(hkeySP, SZ_GUID, NULL, &dwType,
(LPBYTE)wszGuidStr, &dwGuidStrSize);
if(lReturn != ERROR_SUCCESS)
{
RegCloseKey(hkeySP);
DPF_ERR("Unable to query GUID key value!");
continue;
}
// Convert the string to a real GUID
hr = GUIDFromString(wszGuidStr, &guidSP);
if(FAILED(hr))
{
DPF_ERRVAL("Invalid SP guid -- skipping SP, hr = 0x%08x", hr);
RegCloseKey(hkeySP);
// Set the hresult back to DP_OK in case this is the last
// SP in the registry -- we want the method call
// to succeed if we got this far, we just don't want to
// call the callback for this particular SP
hr = DP_OK;
continue;
}
// If we match the GUID passed in, then enumerate them
if(IsEqualGUID(guidSPIn, &guidSP))
{
// Enumerate the Address Types for this SP
hr = PRV_CallEnumAddressTypesCallback(hkeySP,
lpfnEnumCallback, lpContext);
bFound = TRUE;
}
// Close the SP key
RegCloseKey(hkeySP);
}
// Close the DPlay Apps key
RegCloseKey(hkeySPHead);
// If we didn't find the SP, return an error
// REVIEW!!!! -- Is this really the error we want here????
if(!bFound)
return DPERR_UNAVAILABLE;
return hr;
} // PRV_EnumAddressTypes
#undef DPF_MODNAME
#define DPF_MODNAME "DPL_EnumAddressTypes"
HRESULT DPLAPI DPL_EnumAddressTypes(LPDIRECTPLAYLOBBY lpDPL,
LPDPLENUMADDRESSTYPESCALLBACK lpfnEnumCallback,
REFGUID guidSP, LPVOID lpContext, DWORD dwFlags)
{
HRESULT hr;
DPF(7, "Entering DPL_EnumAddressTypes");
DPF(9, "Parameters: 0x%08x, 0x%08x, guid, 0x%08x, 0x%08x",
lpDPL, lpfnEnumCallback, lpContext, dwFlags);
ENTER_DPLOBBY();
// Set the ANSI flag to TRUE and call the internal function
hr = PRV_EnumAddressTypes(lpDPL, lpfnEnumCallback, guidSP, lpContext, dwFlags);
LEAVE_DPLOBBY();
return hr;
} // DPL_EnumAddressTypes
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_FreeLSPNode"
void PRV_FreeLSPNode(LPLSPNODE lpNode)
{
DPF(7, "Entering PRV_FreeLSPNode");
if(!lpNode)
return;
if(lpNode->lpwszName)
DPMEM_FREE(lpNode->lpwszName);
if(lpNode->lpwszPath)
DPMEM_FREE(lpNode->lpwszPath);
if(lpNode->lpszDescA)
DPMEM_FREE(lpNode->lpszDescA);
if(lpNode->lpwszDesc)
DPMEM_FREE(lpNode->lpwszDesc);
DPMEM_FREE(lpNode);
} // PRV_FreeLSPNode
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_FreeLSPList"
void PRV_FreeLSPList(LPLSPNODE lpLSPHead)
{
LPLSPNODE lpTemp;
DPF(7, "Entering PRV_FreeLSPList");
DPF(9, "Parameters: 0x%08x", lpLSPHead);
// Walk the list and free each node
while(lpLSPHead)
{
// Save the next one
lpTemp = lpLSPHead->lpNext;
// Free all of the members
PRV_FreeLSPNode(lpLSPHead);
// Move to the next one
lpLSPHead = lpTemp;
}
} // PRV_FreeLSPList
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_AddLSPNode"
HRESULT PRV_AddLSPNode(LPWSTR lpwszName, LPWSTR lpwszPath, LPWSTR lpwszDesc,
LPSTR lpszDescA, LPWSTR lpwszGuid, DWORD dwReserved1,
DWORD dwReserved2, DWORD dwNodeFlags)
{
LPLSPNODE lpLSPNode = NULL;
DWORD dwDescASize;
HRESULT hr;
DPF(7, "Entering PRV_AddLSPNode");
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, %lu, %lu, 0x%08x",
lpwszName, lpwszPath, lpwszDesc, lpszDescA, lpwszGuid, dwReserved1,
dwReserved2, dwNodeFlags);
// Allocate memory for the node
lpLSPNode = DPMEM_ALLOC(sizeof(LSPNODE));
if(!lpLSPNode)
{
DPF_ERR("Failed to allocate memory for Lobby Provider node, skipping LP");
return DPERR_OUTOFMEMORY;
}
// Allocate memory for the Name string and copy it
hr = GetString(&lpLSPNode->lpwszName, lpwszName);
if(FAILED(hr))
{
DPF_ERR("Unable to allocate memory for Lobby Provider Name string, skipping provider");
hr = DPERR_OUTOFMEMORY;
goto ERROR_ADDLSPNODE;
}
// Allocate memory for the Path string and copy it
hr = GetString(&lpLSPNode->lpwszPath, lpwszPath);
if(FAILED(hr))
{
DPF_ERR("Unable to allocate memory for Lobby Provider Path string, skipping provider");
hr = DPERR_OUTOFMEMORY;
goto ERROR_ADDLSPNODE;
}
if(dwNodeFlags & LSPNODE_DESCRIPTION)
{
// Allocate memory for the DescriptionA string and copy it
dwDescASize = lstrlenA(lpszDescA)+1;
lpLSPNode->lpszDescA = DPMEM_ALLOC(dwDescASize);
if(!lpLSPNode->lpszDescA)
{
DPF_ERR("Unable to allocate memory for Lobby Provider Path string, skipping provider");
hr = DPERR_OUTOFMEMORY;
goto ERROR_ADDLSPNODE;
}
memcpy(lpLSPNode->lpszDescA, lpszDescA, dwDescASize);
// Allocate memory for the DescriptionW string and copy it
hr = GetString(&lpLSPNode->lpwszDesc, lpwszDesc);
if(FAILED(hr))
{
DPF_ERR("Unable to allocate memory for Lobby Provider DescriptionW string, skipping provider");
hr = DPERR_OUTOFMEMORY;
goto ERROR_ADDLSPNODE;
}
}
// Convert the string to a real GUID
hr = GUIDFromString(lpwszGuid, &lpLSPNode->guid);
if(FAILED(hr))
{
DPF_ERRVAL("Invalid LP guid -- skipping LP, hr = 0x%08x", hr);
goto ERROR_ADDLSPNODE;
}
// Finish setting up the node
lpLSPNode->dwReserved1 = dwReserved1;
lpLSPNode->dwReserved2 = dwReserved2;
lpLSPNode->dwNodeFlags = dwNodeFlags;
// Add the node to the list
lpLSPNode->lpNext = glpLSPHead;
glpLSPHead = lpLSPNode;
return DP_OK;
ERROR_ADDLSPNODE:
if(lpLSPNode->lpwszName)
DPMEM_FREE(lpLSPNode->lpwszName);
if(lpLSPNode->lpwszPath)
DPMEM_FREE(lpLSPNode->lpwszPath);
if(lpLSPNode->lpwszDesc)
DPMEM_FREE(lpLSPNode->lpwszDesc);
if(lpLSPNode->lpszDescA)
DPMEM_FREE(lpLSPNode->lpszDescA);
DPMEM_FREE(lpLSPNode);
return hr;
} // PRV_AddLSPNode
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_BuildLSPList"
HRESULT PRV_BuildLSPList()
{
HKEY hkeyLobbySP, hkeySP;
WCHAR szSPName[DPLOBBY_REGISTRY_NAMELEN];
WCHAR szSPPath[DPLOBBY_REGISTRY_NAMELEN];
WCHAR szSPDescW[DPLOBBY_REGISTRY_NAMELEN];
CHAR szSPDescA[DPLOBBY_REGISTRY_NAMELEN];
WCHAR wszGuidStr[GUID_STRING_SIZE];
DWORD dwSize;
DWORD dwGuidStrSize = GUID_STRING_SIZE;
DWORD dwType = REG_SZ;
DWORD dwIndex = 0;
DWORD dwReserved1, dwReserved2, dwReservedSize;
LONG lReturn;
DWORD dwError;
HRESULT hr;
DWORD dwNodeFlags = 0;
DPF(7, "Entering PRV_BuildLSPList");
if(glpLSPHead)
{
return DP_OK;
}
// Open the DPLobby SP key
lReturn = OS_RegOpenKeyEx(HKEY_LOCAL_MACHINE, SZ_DPLOBBY_SP_KEY, 0,
KEY_READ, &hkeyLobbySP);
if(lReturn != ERROR_SUCCESS)
{
// This just means that the DPLobby SP key doesn't exist (most
// likely), so in that case, there are no Lobby SP's to enumerate.
return DP_OK;
}
// Walk the list of Lobby SP's in the registry, enumerating them
while(1)
{
// Get the next LSP Name
dwSize = sizeof(szSPName)/sizeof(TCHAR);
lReturn = OS_RegEnumKeyEx(hkeyLobbySP, dwIndex++, szSPName,
&dwSize, NULL, NULL, NULL, NULL);
if(lReturn == ERROR_NO_MORE_ITEMS)
break;
else if(lReturn != ERROR_SUCCESS)
{
dwError = GetLastError();
DPF_ERRVAL("Unable to get Lobby Provider name from the registry -- dwError = %u -- skipping provider", dwError);
continue;
}
// Open the subkey
lReturn = OS_RegOpenKeyEx(hkeyLobbySP, szSPName, 0, KEY_READ, &hkeySP);
if(lReturn != ERROR_SUCCESS)
{
dwError = GetLastError();
DPF_ERRVAL("Unable to open Lobby Provider key in the registry -- dwError = %u -- skipping provider", dwError);
continue;
}
// First see if the "Private" key exists. If it does, then set the flag
// so that it will get skipped during enumeration
lReturn = OS_RegQueryValueEx(hkeySP, SZ_PRIVATE, NULL, &dwType, NULL, &dwSize);
if (ERROR_SUCCESS == lReturn)
{
// The key exists, so set the flag so we don't enumerate it
dwNodeFlags |= LSPNODE_PRIVATE;
}
// Get the LSP Path
dwSize = sizeof(szSPPath);
lReturn = OS_RegQueryValueEx(hkeySP, SZ_PATH, NULL, &dwType,
(LPBYTE)szSPPath, &dwSize);
if(lReturn != ERROR_SUCCESS)
{
dwError = GetLastError();
DPF_ERRVAL("Unable to get Lobby Provider path from the registry -- dwError = %u -- skipping provider", dwError);
RegCloseKey(hkeySP);
continue;
}
// Get the LSP Descriptions
// If the DescriptionA value doesn't exist, then don't worry about
// getting the DescriptionW value. If the DescriptionA value exits,
// but the DescriptionW value does not, convert the DescriptionA
// value to Unicode and store it in DescriptionW.
// NOTE: We always assume the DescriptionA value is an ANSI string,
// even if it's stored in a Unicode format on NT & Memphis. So we
// always retrieve this as an ANSI string
dwSize = sizeof(szSPDescA);
lReturn = RegQueryValueExA(hkeySP, "DescriptionA", NULL, &dwType,
(LPBYTE)szSPDescA, &dwSize);
if(lReturn == ERROR_SUCCESS)
{
// Save the description flag
dwNodeFlags |= LSPNODE_DESCRIPTION;
// Get the DescriptionW value
dwSize = sizeof(szSPDescW);
lReturn = OS_RegQueryValueEx(hkeySP, SZ_DESCRIPTIONW, NULL, &dwType,
(LPBYTE)szSPDescW, &dwSize);
if(lReturn != ERROR_SUCCESS)
{
// Convert the ANSI Description string to Unicode and store it
AnsiToWide(szSPDescW, szSPDescA, (lstrlenA(szSPDescA)+1));
}
}
// Get the GUID of the LSP
dwGuidStrSize = GUID_STRING_SIZE;
lReturn = OS_RegQueryValueEx(hkeySP, SZ_GUID, NULL, &dwType,
(LPBYTE)wszGuidStr, &dwGuidStrSize);
if(lReturn != ERROR_SUCCESS)
{
RegCloseKey(hkeySP);
DPF_ERR("Unable to query GUID key value for Lobby Provider!");
continue;
}
// Get the Reserved1 dword (we don't care if it fails)
dwType = REG_DWORD;
dwReservedSize = sizeof(DWORD);
dwReserved1 = 0;
OS_RegQueryValueEx(hkeySP, SZ_DWRESERVED1, NULL, &dwType,
(LPBYTE)&dwReserved1, &dwReservedSize);
// Get the Reserved1 dword (we don't care if it fails)
dwReservedSize = sizeof(DWORD);
dwReserved2 = 0;
OS_RegQueryValueEx(hkeySP, SZ_DWRESERVED1, NULL, &dwType,
(LPBYTE)&dwReserved2, &dwReservedSize);
// Add the node to the list
hr = PRV_AddLSPNode(szSPName, szSPPath, szSPDescW, szSPDescA,
wszGuidStr, dwReserved1, dwReserved2, dwNodeFlags);
if(FAILED(hr))
{
DPF_ERRVAL("Failed adding Lobby Provider to internal list, hr = 0x%08x", hr);
}
// Close the SP key
RegCloseKey(hkeySP);
}
// Close the Lobby SP key
RegCloseKey(hkeyLobbySP);
return DP_OK;
} // PRV_BuildLSPList
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_EnumConnections"
HRESULT PRV_EnumConnections(LPCGUID lpGuid, LPDPENUMCONNECTIONSCALLBACK lpCallback,
LPVOID lpContext, DWORD dwFlags, BOOL bAnsi)
{
LPLSPNODE lpLSPNode, lpLSPHead;
BOOL bContinue = TRUE;
DPNAME name;
HRESULT hr = DP_OK;
DPCOMPOUNDADDRESSELEMENT AddrOnly;
LPDPADDRESS lpAddress = NULL;
DWORD dwAddressSize;
DWORD dwAddressSizeSave;
LPWSTR lpwszName = NULL;
DPF(7, "Entering PRV_EnumConnections");
DPF(9, "Parameters: ");
// Rebuild the LSP List
PRV_BuildLSPList();
// If we don't have any entries, just bail here
if(!glpLSPHead)
return DP_OK;
// Get a pointer to the first lobby provider, and store our head pointer
lpLSPHead = glpLSPHead;
lpLSPNode = glpLSPHead;
// Setup the unfinished address
memset(&AddrOnly, 0, sizeof(DPCOMPOUNDADDRESSELEMENT));
AddrOnly.guidDataType = DPAID_LobbyProvider;
AddrOnly.dwDataSize = sizeof(GUID);
AddrOnly.lpData = &lpLSPNode->guid;
// Calculate the size of the finished address
hr = InternalCreateCompoundAddress(&AddrOnly, 1, NULL, &dwAddressSize);
if(hr != DPERR_BUFFERTOOSMALL)
{
DPF_ERRVAL("Failed to retrieve the size of the output address buffer, hr = 0x%08x", hr);
return hr;
}
// Allocate the buffer for the finished address
lpAddress = DPMEM_ALLOC(dwAddressSize);
if(!lpAddress)
{
DPF_ERR("Unable to allocate memory for temporary address structure");
return DPERR_OUTOFMEMORY;
}
// Clear the DPNAME struct
memset(&name,0,sizeof(name));
name.dwSize = sizeof(name);
// now, we have a list of SP's. walk the list, and call the app back
// run through what we found...
dwAddressSizeSave = dwAddressSize;
// Drop the locks
LEAVE_ALL();
while ((lpLSPNode) && (bContinue))
{
// If the private flag is set, don't enumerate it
if(!(lpLSPNode->dwNodeFlags & LSPNODE_PRIVATE))
{
// Create the real DPADDRESS
dwAddressSize = dwAddressSizeSave;
AddrOnly.lpData = &lpLSPNode->guid;
hr = InternalCreateCompoundAddress(&AddrOnly, 1, lpAddress,
&dwAddressSize);
if(SUCCEEDED(hr))
{
// Call the callback
// If the caller is ANSI, convert the string
if (bAnsi)
{
// If we have a description string, use it, and we already
// have an ANSI version to use
if(lpLSPNode->dwNodeFlags & LSPNODE_DESCRIPTION)
{
name.lpszShortNameA = lpLSPNode->lpszDescA;
// Call the app's callback
bContinue= lpCallback(&lpLSPNode->guid, lpAddress, dwAddressSize, &name,
DPCONNECTION_DIRECTPLAYLOBBY, lpContext);
}
else
{
hr = GetAnsiString(&(name.lpszShortNameA), lpLSPNode->lpwszName);
if(SUCCEEDED(hr))
{
// Call the app's callback
bContinue= lpCallback(&lpLSPNode->guid, lpAddress, dwAddressSize, &name,
DPCONNECTION_DIRECTPLAYLOBBY, lpContext);
// Free our short name buffer
DPMEM_FREE(name.lpszShortNameA);
}
else
{
DPF_ERR("Unable to allocate memory for temporary name string, skipping Connection");
}
}
}
else
{
// If we have a description, use it
if(lpLSPNode->dwNodeFlags & LSPNODE_DESCRIPTION)
lpwszName = lpLSPNode->lpwszDesc;
else
lpwszName = lpLSPNode->lpwszName;
name.lpszShortName = lpwszName;
// Call the app's callback
bContinue= lpCallback(&lpLSPNode->guid, lpAddress, dwAddressSize, &name,
DPCONNECTION_DIRECTPLAYLOBBY, lpContext);
}
}
else
{
DPF(2, "Failed to create DPADDRESS structure, skipping this Connection, hr = 0x%08x", hr);
}
}
lpLSPNode = lpLSPNode->lpNext;
} // while
// Take the locks back
ENTER_ALL();
// Free our temporary address struct
DPMEM_FREE(lpAddress);
return DP_OK;
} // PRV_EnumConnections
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_CallEnumLocalAppCallback"
HRESULT PRV_CallEnumLocalAppCallback(LPWSTR lpwszAppName, LPGUID lpguidApp,
LPDPLENUMLOCALAPPLICATIONSCALLBACK lpfnEnumCallback,
LPVOID lpContext, BOOL bAnsi, LPSTR lpszDescA,
LPWSTR lpwszDescW)
{
LPDPLAPPINFO lpai = NULL;
LPSTR lpszAppName = NULL;
BOOL bReturn;
DPF(7, "Entering PRV_CallEnumLocalAppCallback");
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x, 0x%08x, %lu, 0x%08x, 0x%08x",
lpwszAppName, lpguidApp, lpfnEnumCallback, lpContext, bAnsi,
lpszDescA, lpwszDescW);
// Allocate memory for the AppInfo struct
lpai = DPMEM_ALLOC(sizeof(DPLAPPINFO));
if(!lpai)
{
DPF_ERR("Unable to allocate memory for AppInfo structure!");
return DPERR_OUTOFMEMORY;
}
// Set the size
lpai->dwSize = sizeof(DPLAPPINFO);
// If the description strings exist, use them
// NOTE: We can assume that if the DescriptionA string exists,
// they both do.
if(lpszDescA)
{
if(bAnsi)
lpai->lpszAppNameA = lpszDescA;
else
lpai->lpszAppName = lpwszDescW;
}
else
{
// If we're ANSI, convert the string
if(bAnsi)
{
if(FAILED(GetAnsiString(&lpszAppName, lpwszAppName)))
{
DPMEM_FREE(lpai);
DPF_ERR("Unable to allocate memory for temporary string!");
return DPERR_OUTOFMEMORY;
}
lpai->lpszAppNameA = lpszAppName;
}
else
{
lpai->lpszAppName = lpwszAppName;
}
}
// Set the GUID
lpai->guidApplication = *lpguidApp;
// Call the callback
bReturn = ((LPDPLENUMLOCALAPPLICATIONSCALLBACK)lpfnEnumCallback)
(lpai, lpContext, 0L);
// Free all of our memory
if(lpszAppName)
DPMEM_FREE(lpszAppName);
DPMEM_FREE(lpai);
// Set our HRESULT return value
if(bReturn)
return DP_OK;
else
return DPLOBBYPR_CALLBACKSTOP;
} // PRV_CallEnumLocalAppCallback
#undef DPF_MODNAME
#define DPF_MODNAME "PRV_EnumLocalApplications"
HRESULT PRV_EnumLocalApplications(LPDIRECTPLAYLOBBY lpDPL,
LPDPLENUMLOCALAPPLICATIONSCALLBACK lpfnEnumCallback,
LPVOID lpContext, DWORD dwFlags, BOOL bAnsi)
{
LPDPLOBBYI_DPLOBJECT this;
HRESULT hr = DP_OK;
HKEY hkeyDPApps, hkeyApp;
WCHAR wszAppName[DPLOBBY_REGISTRY_NAMELEN];
DWORD dwIndex = 0;
DWORD dwNameSize;
WCHAR wszGuidStr[GUID_STRING_SIZE];
DWORD dwGuidStrSize = sizeof(wszGuidStr)/sizeof(WCHAR);
DWORD dwType = REG_SZ;
GUID guidApp;
LONG lReturn;
CHAR szDescA[DPLOBBY_REGISTRY_NAMELEN];
WCHAR wszDescW[DPLOBBY_REGISTRY_NAMELEN];
DWORD dwDescSize;
BOOL bDesc = FALSE;
LPSTR lpszDescA = NULL;
LPWSTR lpwszDescW = NULL;
BOOL bHide;
DWORD dwRegFlags;
DWORD dwRegFlagsSize;
DPF(7, "Entering PRV_EnumLocalApplications");
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x, 0x%08x, %lu",
lpDPL, lpfnEnumCallback, lpContext, dwFlags, bAnsi);
TRY
{
if( !VALID_DPLOBBY_INTERFACE( lpDPL ))
{
return DPERR_INVALIDINTERFACE;
}
this = DPLOBJECT_FROM_INTERFACE(lpDPL);
if( !VALID_DPLOBBY_PTR( this ) )
{
return DPERR_INVALIDOBJECT;
}
if( !VALIDEX_CODE_PTR( lpfnEnumCallback ) )
{
return DPERR_INVALIDPARAMS;
}
if( dwFlags )
{
return DPERR_INVALIDPARAMS;
}
}
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
{
LEAVE_DPLOBBY();
DPF_ERR( "Exception encountered validating parameters" );
return DPERR_INVALIDPARAMS;
}
// Open the Applications key
lReturn = OS_RegOpenKeyEx(HKEY_LOCAL_MACHINE, SZ_DPLAY_APPS_KEY, 0,
KEY_READ, &hkeyDPApps);
if(lReturn != ERROR_SUCCESS)
{
// This just means that the application key doesn't exist (most
// likely), so in that case, there are no apps to enumerate.
return DP_OK;
}
// Walk the list of DPlay games in the registry, enumerating them
while(1)
{
// Reset the pointers and the flag
lpszDescA = NULL;
lpwszDescW = NULL;
bDesc = FALSE;
bHide = FALSE;
// Get the next app in the list
dwNameSize = DPLOBBY_REGISTRY_NAMELEN;
lReturn = OS_RegEnumKeyEx(hkeyDPApps, dwIndex++, (LPWSTR)wszAppName,
&dwNameSize, NULL, NULL, NULL, NULL);
// If lReturn is ERROR_NO_MORE_ITEMS, we want this to be the last iteration
if(lReturn == ERROR_NO_MORE_ITEMS)
break;
// Open the app key
lReturn = OS_RegOpenKeyEx(hkeyDPApps, (LPWSTR)wszAppName, 0,
KEY_READ, &hkeyApp);
if(lReturn != ERROR_SUCCESS)
{
DPF_ERR("Unable to open app key!");
continue;
}
// see if we should even report this game (its hidden)
dwRegFlags = 0;
dwRegFlagsSize = sizeof(dwRegFlags);
lReturn = OS_RegQueryValueEx(hkeyApp, SZ_DWFLAGS, NULL, &dwType, (CHAR *)&dwRegFlags, &dwRegFlagsSize);
if(lReturn == ERROR_SUCCESS && dwRegFlags & DPLAPP_NOENUM){
// application is hidden, don't report it back to the application.
bHide = TRUE;
} else {
// Get the GUID of the Game
dwGuidStrSize = GUID_STRING_SIZE;
lReturn = OS_RegQueryValueEx(hkeyApp, SZ_GUID, NULL, &dwType,
(LPBYTE)wszGuidStr, &dwGuidStrSize);
if(lReturn != ERROR_SUCCESS)
{
RegCloseKey(hkeyApp);
DPF_ERR("Unable to query GUID key value!");
continue;
}
// Convert the string to a real GUID
hr = GUIDFromString(wszGuidStr, &guidApp);
if(FAILED(hr))
{
DPF_ERRVAL("Invalid game guid -- skipping game, hr = 0x%08x", hr);
RegCloseKey(hkeyApp);
// Set the hresult back to DP_OK in case this is the last
// application in the registry -- we want the method call
// to succeed if we got this far, we just don't want to
// call the callback for this particular application
hr = DP_OK;
continue;
}
// Get the Description strings
dwDescSize = sizeof(szDescA);
lReturn = RegQueryValueExA(hkeyApp, "DescriptionA", NULL, &dwType,
(LPBYTE)szDescA, &dwDescSize);
if(lReturn != ERROR_SUCCESS)
{
DPF(5,"Could not read Description lReturn = %d\n",lReturn);
// it's ok if the app doesn't have one of these...
}
else
{
DPF(5,"Got DescriptionA = %s\n",szDescA);
// Set our description flag
bDesc = TRUE;
// Now try to get the DescriptionW string if one exists. If for some
// reason a DescriptionW string exists, but the DescriptionA does not,
// we pretend the DescriptionW string doesn't exist either.
// NOTE: We always assume the DescriptionW string is a Unicode string,
// even on Win95. On Win95, this will be of the type REG_BINARY, but
// it is really just a Unicode string.
dwDescSize = sizeof(wszDescW);
lReturn = OS_RegQueryValueEx(hkeyApp, SZ_DESCRIPTIONW, NULL,
&dwType, (LPBYTE)wszDescW, &dwDescSize);
if(lReturn != ERROR_SUCCESS)
{
DPF(5,"Could not get DescriptionW, converting DescriptionA");
// We couldn't get DescriptionW, so convert DescriptionA...
AnsiToWide(wszDescW,szDescA,(lstrlenA(szDescA)+1));
}
else
{
DPF(5,"Got DescriptionW = %ls\n",wszDescW);
}
}
}
// Close the App key
RegCloseKey(hkeyApp);
// Setup the description pointers if they are valid
if(bDesc)
{
lpszDescA = (LPSTR)szDescA;
lpwszDescW = (LPWSTR)wszDescW;
}
if(bHide){
// not calling back for this hidden application
hr=DP_OK;
} else {
// Call the callback
hr = PRV_CallEnumLocalAppCallback(wszAppName, &guidApp,
lpfnEnumCallback, lpContext, bAnsi,
lpszDescA, lpwszDescW);
}
if(hr == DPLOBBYPR_CALLBACKSTOP)
{
hr = DP_OK;
break;
}
else
{
if(FAILED(hr))
break;
else
continue;
}
}
// Close the DPlay Apps key
RegCloseKey(hkeyDPApps);
dwNameSize = DPLOBBY_REGISTRY_NAMELEN;
return hr;
} // PRV_EnumLocalApplications
#undef DPF_MODNAME
#define DPF_MODNAME "DPL_EnumLocalApplications"
HRESULT DPLAPI DPL_EnumLocalApplications(LPDIRECTPLAYLOBBY lpDPL,
LPDPLENUMLOCALAPPLICATIONSCALLBACK lpfnEnumCallback,
LPVOID lpContext, DWORD dwFlags)
{
HRESULT hr;
DPF(7, "Entering DPL_EnumLocalApplications");
DPF(9, "Parameters: 0x%08x, 0x%08x, 0x%08x, 0x%08x",
lpDPL, lpfnEnumCallback, lpContext, dwFlags);
ENTER_DPLOBBY();
// Set the ANSI flag to TRUE and call the internal function
hr = PRV_EnumLocalApplications(lpDPL, lpfnEnumCallback, lpContext,
dwFlags, FALSE);
LEAVE_DPLOBBY();
return hr;
} // DPL_EnumLocalApplications