/*========================================================================== * * 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