windows-nt/Source/XPSP1/NT/net/upnp/upnpui/dll/tfind.cpp

976 lines
28 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997.
//
// File: T F I N D . C P P
//
// Contents: Asynchronous find mechanism for UPnP tray monitor.
//
// Notes:
//
// Author: jeffspr 22 Nov 1999
//
//----------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
#include <wininet.h>
#include "tfind.h"
#include "clist.h"
#include "clistndn.h"
#include "tconst.h"
extern UINT g_iTotalBalloons;
CListString g_CListUDN;
CListString g_CListUDNSearch;
CListNDN g_CListNewDeviceNode;
CListNameMap g_CListNameMap;
BOOL g_fIconPresent = FALSE;
// (tongl)
// List of devices currently on the network
// This is the cached device list to show in "My Network Places" folder
CListFolderDeviceNode g_CListFolderDeviceNode;
CRITICAL_SECTION g_csFolderDeviceList;
// CLSID_NetworkNeighborhood
CONST WCHAR c_szNetworkNeighborhoodFolderPath[] = L"::{208D2C60-3AEA-1069-A2D7-08002B30309D}\\";
// CLSID UPnP Delegate Folder - note "," is used for the new parse syntax (guru)
CONST WCHAR c_szUPnPFolderPath[] = L"::{e57ce731-33e8-4c51-8354-bb4de9d215d1},";
CONST WCHAR c_szDelegateFolderPrefix[] = L"__upnpitem:";
CONST SIZE_T c_cchDelegateFolderPrefix = celems(c_szDelegateFolderPrefix) - 1;
BOOL CListFolderDeviceNode::FCompare(FolderDeviceNode * pNode, PCWSTR pszUDN)
{
// see whether UDNs match between two device nodes
Assert(pNode);
Assert(pszUDN);
return (wcscmp(pNode->pszUDN, pszUDN) == 0);
}
BOOL CListNDN::FCompare(NewDeviceNode * pNode, LPCTSTR pszUDN)
{
// see whether UDNs match between two device nodes
Assert(pNode);
Assert(pszUDN);
return (_tcscmp(pNode->pszUDN, pszUDN) == 0);
}
BOOL CListString::FCompare(LPTSTR pszCurrentNodeString, LPCTSTR pszKey)
{
// see whether UDNs match between two device nodes
Assert(pszCurrentNodeString);
Assert(pszKey);
return (_tcscmp(pszCurrentNodeString, pszKey) == 0);
}
BOOL CListNameMap::FCompare(NAME_MAP *pnm, LPCTSTR szUdn)
{
// see whether UDNs match between two device nodes
Assert(pnm);
Assert(szUdn);
return (_tcscmp(pnm->szUdn, szUdn) == 0);
}
TCHAR * BSTRToTsz(BSTR bstrInput)
{
return TszFromWsz(bstrInput);
}
// The string created is:
// "::CLSID_NetworkNeighborhood\\__upnpitem:UPNP_device_UDN"
//
// The new shell changes
// "::CLSID_NetworkNeighborhood\\::GUID for UPnP Delegate Folder,<parse string>
// <parse string > __upnpitem:UDN of the device
LPWSTR
CreateChangeNotifyString(LPCWSTR pszUdn)
{
LPWSTR pszNotifyString;
pszNotifyString = new WCHAR [ MAX_PATH ];
if (pszNotifyString)
{
Assert((celems(c_szNetworkNeighborhoodFolderPath) +
celems(c_szDelegateFolderPrefix)) < MAX_PATH);
CONST SIZE_T cchMax = MAX_PATH
- (celems(c_szNetworkNeighborhoodFolderPath) * sizeof(WCHAR))
- (celems(c_szUPnPFolderPath) * sizeof(WCHAR))
- (celems(c_szDelegateFolderPrefix) * sizeof(WCHAR))
+ 2; // +2 we have subtracted Three null characters
// note: we know that the folder path and the prefix can fit
// in the MAX_PATH buffer
wcscpy(pszNotifyString, c_szNetworkNeighborhoodFolderPath);
wcscat(pszNotifyString, c_szUPnPFolderPath);
wcscat(pszNotifyString, c_szDelegateFolderPrefix);
wcsncat(pszNotifyString, pszUdn, cchMax);
}
else
{
TraceTag(ttidShellFolder, "CreateChangeNotifyString: new failed");
}
return pszNotifyString;
}
//+---------------------------------------------------------------------------
//
// Function: NewDeviceNode::NewDeviceNode
//
// Purpose: Initializes a NewDeviceNode structure.
//
// Notes:
//
NewDeviceNode::NewDeviceNode()
{
pszUDN = NULL;
pszDisplayName = NULL;
pszType = NULL;
pszPresentationURL = NULL;
pszManufacturerName = NULL;
pszModelName = NULL;
pszModelNumber = NULL;
pszDescription = NULL;
}
//+---------------------------------------------------------------------------
//
// Function: NewDeviceNode::~NewDeviceNode
//
// Purpose: Deletes a NewDeviceNode structure.
//
// Author: donryan 18 Feb 2000
//
// Notes: Moved from CUPnPMonitorDeviceFinderCallback::DeviceAdded
//
NewDeviceNode::~NewDeviceNode()
{
delete pszUDN;
delete pszDisplayName;
delete pszType;
delete pszPresentationURL;
delete pszManufacturerName;
delete pszModelName;
delete pszModelNumber;
delete pszDescription;
}
//+---------------------------------------------------------------------------
//
// Function: HrMapUdnToFriendlyName
//
// Purpose: Given a UPnP device and UDN, maps the UDN to a friendly name
// from the registry if it is present, otherwise falls back to
// the friendly name from the device
//
// Arguments:
// pdev [in] UPnP device to check
// bstrUdn [in] UDN of device
// pbstrName [out] Returns friendly name of device
//
// Returns: S_OK if success, E_OUTOFMEMORY if no memory, or Win32 error
// code
//
// Author: danielwe 2000/10/25
//
// Notes:
//
HRESULT HrMapUdnToFriendlyName(IUPnPDevice *pdev, BSTR bstrUdn, BSTR *pbstrName)
{
HRESULT hr = S_OK;
NAME_MAP * pnm = NULL;
Assert(pbstrName);
*pbstrName = NULL;
if (g_CListNameMap.FFind(bstrUdn, &pnm))
{
Assert(pnm);
*pbstrName = SysAllocString(pnm->szName);
if (!*pbstrName)
{
hr = E_OUTOFMEMORY;
}
}
else
{
// UDN doesn't have a mapping in registry. Fall back to device's
// friendly name
//
hr = pdev->get_FriendlyName(pbstrName);
}
TraceError("HrMapUdnToFriendlyName", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrCreateDeviceNodeFromDevice
//
// Purpose: Utility function to transfer information from device object
// into NewDeviceNode structure.
//
// Arguments:
// pDevice [in] The device pointer
// ppNDN [out] The pointer to the NewDeviceNode pointer.
//
// Returns:
//
// Author: donryan 18 Feb 2000
//
// Notes: Moved from CUPnPMonitorDeviceFinderCallback::DeviceAdded
//
HRESULT
HrCreateDeviceNodeFromDevice(
IUPnPDevice * pDevice,
NewDeviceNode ** ppNDN
)
{
HRESULT hr = S_OK;
BSTR bstrUDN = NULL;
BSTR bstrDisplayName = NULL;
BSTR bstrType = NULL;
BSTR bstrPresentationURL = NULL;
BSTR bstrManufacturerName = NULL;
BSTR bstrModelName = NULL;
BSTR bstrModelNumber = NULL;
BSTR bstrDescription = NULL;
PTSTR pszUDN = NULL;
NewDeviceNode * pNDN = NULL;
Assert(pDevice);
Assert(ppNDN);
hr = pDevice->get_UniqueDeviceName(&bstrUDN);
if (FAILED(hr))
{
TraceTag(ttidShellTray, "Error calling pDevice->get_UniqueDeviceName");
goto Exit;
}
hr = HrMapUdnToFriendlyName(pDevice, bstrUDN, &bstrDisplayName);
if (FAILED(hr))
{
goto Exit;
}
hr = pDevice->get_Type(&bstrType);
if (FAILED(hr))
{
TraceTag(ttidShellTray, "Error calling pDevice->get_Type");
goto Exit;
}
hr = pDevice->get_PresentationURL(&bstrPresentationURL);
if (FAILED(hr))
{
TraceTag(ttidShellTray, "Error calling pDevice->get_PresentationURL");
goto Exit;
}
hr = pDevice->get_ManufacturerName(&bstrManufacturerName);
if (FAILED(hr))
{
TraceTag(ttidShellTray, "Error calling pDevice->get_ManufacturerName");
goto Exit;
}
hr = pDevice->get_ModelName(&bstrModelName);
if (FAILED(hr))
{
TraceTag(ttidShellTray, "Error calling pDevice->get_ModelName");
goto Exit;
}
hr = pDevice->get_ModelNumber(&bstrModelNumber);
if (FAILED(hr))
{
TraceTag(ttidShellTray, "Error calling pDevice->get_ModelNumber");
goto Exit;
}
hr = pDevice->get_Description(&bstrDescription);
if (FAILED(hr))
{
TraceTag(ttidShellTray, "Error calling pDevice->get_Description");
goto Exit;
}
// Create a new Device node, copy the strings into it, and add it to the device map
//
pNDN = new NewDeviceNode;
if (pNDN)
{
Assert(bstrUDN);
pNDN->pszUDN = BSTRToTsz(bstrUDN);
Assert(bstrDisplayName);
pNDN->pszDisplayName = BSTRToTsz(bstrDisplayName);
Assert(bstrType);
pNDN->pszType = BSTRToTsz(bstrType);
if (bstrPresentationURL)
{
pNDN->pszPresentationURL = BSTRToTsz(bstrPresentationURL);
}
else
{
pNDN->pszPresentationURL = new TCHAR [ 1 ];
if (pNDN->pszPresentationURL)
{
pNDN->pszPresentationURL[0] = TEXT('\0');
}
}
Assert(bstrManufacturerName);
pNDN->pszManufacturerName = BSTRToTsz(bstrManufacturerName);
Assert(bstrModelName);
pNDN->pszModelName = BSTRToTsz(bstrModelName);
if (bstrModelNumber)
{
pNDN->pszModelNumber = BSTRToTsz(bstrModelNumber);
}
else
{
pNDN->pszModelNumber = new TCHAR [ 1 ];
if (pNDN->pszModelNumber)
{
pNDN->pszModelNumber[0] = TEXT('\0');
}
}
if (bstrDescription)
{
pNDN->pszDescription = BSTRToTsz(bstrDescription);
}
else
{
pNDN->pszDescription = new TCHAR [ 1 ];
if (pNDN->pszDescription)
{
pNDN->pszDescription[0] = TEXT('\0');
}
}
// If they didn't all copy fine, delete them
//
if (!(pNDN->pszUDN && pNDN->pszDisplayName &&
pNDN->pszType && pNDN->pszPresentationURL &&
pNDN->pszManufacturerName && pNDN->pszModelName &&
pNDN->pszModelNumber && pNDN->pszDescription))
{
hr = E_OUTOFMEMORY;
delete pNDN;
pNDN = NULL;
}
}
else
{
TraceTag(ttidShellTray, "Could not allocate NewDeviceNode");
hr = E_OUTOFMEMORY;
}
Exit:
// transfer
*ppNDN = pNDN;
SysFreeString(bstrUDN);
SysFreeString(bstrDisplayName);
SysFreeString(bstrPresentationURL);
SysFreeString(bstrType);
SysFreeString(bstrManufacturerName);
SysFreeString(bstrModelName);
SysFreeString(bstrModelNumber);
SysFreeString(bstrDescription);
TraceHr(ttidShellTray, FAL, hr, FALSE, "HrCreateDeviceNodeFromDevice");
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: HrAddFolderDevice
//
// Purpose:
//
// Arguments:
// pDevice
//
// Returns:
//
// Author: tongl 15 Feb 2000
//
// Notes:
//
HRESULT HrAddFolderDevice(IUPnPDevice * pDevice)
{
HRESULT hr = S_OK;
BSTR bstrUDN = NULL;
BSTR bstrDisplayName = NULL;
BSTR bstrType = NULL;
BSTR bstrPresentationURL = NULL;
BSTR bstrDescription = NULL;
// (tongl) Per cmr, some device property (display name, presentation url)
// could change on an existing device and this function will be called but
// the device was not first removed. In this case we need to notify shell
// to first remove the existing device then add the new one.
BOOL fUpdate = FALSE;
BOOL fUpdateOldDevice = FALSE;
// fNewNode - If its really a new device
// fUpdate - The device is in MNP but must be updated bcoz device property has
// changed. Note above.
// fUpdateOldDevice - An old device has sent bye bye and later comes up alive
// with same UDN. We have cached the list of UDNs.
//
Assert(pDevice);
pDevice->AddRef();
hr = pDevice->get_UniqueDeviceName(&bstrUDN);
if (SUCCEEDED(hr))
{
// If we're doing a search right now, just add this UDN to the list
// of devices that we've found so far in the search
//
if (g_fSearchInProgress)
{
if (!g_CListUDNSearch.FAdd(WszDupWsz(bstrUDN)))
{
hr = E_OUTOFMEMORY;
}
}
}
else
{
TraceTag(ttidShellFolder, "Failed in pDevice->get_UniqueDeviceName from HrAddFolderDevice");
}
if (SUCCEEDED(hr))
{
hr = HrMapUdnToFriendlyName(pDevice, bstrUDN, &bstrDisplayName);
if (SUCCEEDED(hr))
{
hr = pDevice->get_Type(&bstrType);
if (SUCCEEDED(hr))
{
hr = pDevice->get_PresentationURL(&bstrPresentationURL);
if (SUCCEEDED(hr))
{
hr = pDevice->get_Description(&bstrDescription);
if (SUCCEEDED(hr))
{
BOOL fNewNode;
EnterCriticalSection(&g_csFolderDeviceList);
FolderDeviceNode * pNewDevice = NULL;
if( g_CListFolderDeviceNode.FFind((PWSTR)bstrUDN, &pNewDevice))
{
Assert(pNewDevice);
fNewNode = FALSE;
if (!pNewDevice->fDeleted)
{
// Only update if friendly name or description
// changed.
//
if ((wcscmp(pNewDevice->pszDescription, bstrDescription)) ||
(wcscmp(pNewDevice->pszDisplayName, bstrDisplayName)))
{
fUpdate = TRUE;
}
}
else
{
fUpdateOldDevice = TRUE;
}
}
else
{
// truely a new device
pNewDevice = new FolderDeviceNode;
fNewNode = TRUE;
if (!pNewDevice)
{
hr = E_OUTOFMEMORY;
}
}
if (pNewDevice)
{
CONST SIZE_T cchMax = MAX_PATH - 1;
pNewDevice->fDeleted = FALSE;
Assert(bstrUDN);
wcscpy(pNewDevice->pszUDN, L"");
wcsncat(pNewDevice->pszUDN,(PWSTR)bstrUDN, cchMax);
Assert(bstrDisplayName);
wcscpy(pNewDevice->pszDisplayName, L"");
wcsncat(pNewDevice->pszDisplayName, bstrDisplayName, cchMax);
Assert(bstrType);
wcscpy(pNewDevice->pszType, L"");
wcsncat(pNewDevice->pszType, (PWSTR)bstrType, cchMax);
wcscpy(pNewDevice->pszPresentationURL, L"");
if (bstrPresentationURL)
{
wcsncat(pNewDevice->pszPresentationURL,
(PWSTR)bstrPresentationURL,
cchMax);
}
wcscpy(pNewDevice->pszDescription, L"");
if (bstrDescription)
{
wcsncat(pNewDevice->pszDescription,
(PWSTR)bstrDescription,
cchMax);
}
// add to our list if a true new device
if (fNewNode)
{
g_CListFolderDeviceNode.FAdd(pNewDevice);
TraceTag(ttidShellFolder, "HrAddFolderDevice: Added %S to g_CListFolderDeviceNode", bstrDisplayName);
}
else
{
TraceTag(ttidShellFolder, "HrAddFolderDevice: Modified %S in g_CListFolderDeviceNode", bstrDisplayName);
}
TraceTag(ttidShellFolder, "HrAddFolderDevice: Now, g_CListFolderDeviceNode has %d elements", g_CListFolderDeviceNode.GetCount());
}
LeaveCriticalSection(&g_csFolderDeviceList);
if (fNewNode || fUpdate || fUpdateOldDevice)
{
if (SUCCEEDED(hr))
{
// notify shell to add the new device
LPWSTR pszNotifyString;
pszNotifyString = CreateChangeNotifyString(bstrUDN);
if (pszNotifyString)
{
if (fUpdate)
{
TraceTag(ttidShellFolder, "Generating update device event for %S", bstrDisplayName);
SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATHW, pszNotifyString, NULL);
}
else
{
// Assert(fNewNode);
// fNewNode or fUpdateOldDevice
TraceTag(ttidShellFolder, "Generating new device event for %S", bstrDisplayName);
SHChangeNotify(SHCNE_CREATE, SHCNF_PATHW, pszNotifyString, NULL);
}
delete [] pszNotifyString;
}
}
else
{
// Don't make a failure here.
//
TraceTag(ttidShellFolder, "Couldn't add device to list in CUPnPDeviceFolderDeviceFinderCallback::DeviceAdded");
}
}
else
{
TraceTag(ttidShellFolder, "Nothing about device %S:%S changed", bstrUDN, bstrDisplayName);
}
}
else
{
TraceTag(ttidShellFolder, "Failed in get_Description from HrAddFolderDevice");
}
}
else
{
TraceTag(ttidShellFolder, "Failed in get_PresentationURL from HrAddFolderDevice");
}
}
else
{
TraceTag(ttidShellFolder, "Failed in pDevice->get_Type from HrAddFolderDevice");
}
}
else
{
TraceTag(ttidShellFolder, "Failed in pDevice->get_FriendlyName from HrAddFolderDevice");
}
}
SysFreeString(bstrUDN);
SysFreeString(bstrDisplayName);
SysFreeString(bstrPresentationURL);
SysFreeString(bstrType);
SysFreeString(bstrDescription);
pDevice->Release();
TraceHr(ttidError, FAL, hr, (S_FALSE == hr), "HrAddFolderDevice");
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: HrDeleteFolderDevice
//
// Purpose:
//
// Arguments:
// szUDN
//
// Returns:
//
// Author: tongl 18 Feb 2000
//
// Notes:
//
HRESULT HrDeleteFolderDevice(PWSTR szUDN)
{
HRESULT hr = S_OK;
FolderDeviceNode * pDevice = NULL;
EnterCriticalSection(&g_csFolderDeviceList);
if (g_CListFolderDeviceNode.FFind(szUDN, &pDevice))
{
pDevice->fDeleted = TRUE;
}
else
{
// can't delete a device that's not in our cache
TraceTag(ttidShellFolder, "The device to delete is not in the cache: %S.", szUDN);
hr = E_FAIL;
}
LeaveCriticalSection(&g_csFolderDeviceList);
if (SUCCEEDED(hr))
{
// notify shell to delete the device
LPWSTR pszNotifyString;
pszNotifyString = CreateChangeNotifyString(szUDN);
if (pszNotifyString)
{
TraceTag(ttidShellFolder, "Delete device event for %S", szUDN);
SHChangeNotify(SHCNE_DELETE, SHCNF_PATHW, pszNotifyString, NULL);
delete [] pszNotifyString;
}
else
{
hr = E_OUTOFMEMORY;
}
}
TraceError("HrDeleteFolderDevice", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CUPnPMonitorDeviceFinderCallback::DeviceAdded
//
// Purpose: Our callback for "new device" -- duh. Here we get the
// important properties, pack them in a struct, and store them
// in our device list. We'll use this data if the user opens
// properties on one of the dialogs, or adds shortcuts.
//
// Arguments:
// lFindData [in] Our callback ID
// pDevice [in] The device pointer.
//
// Returns:
//
// Author: jeffspr 23 Nov 1999
//
// Notes:
//
HRESULT CUPnPMonitorDeviceFinderCallback::DeviceAdded(LONG lFindData,
IUPnPDevice * pDevice)
{
HRESULT hr = S_OK;
NewDeviceNode * pNDN = NULL;
Assert(pDevice);
pDevice->AddRef();
#if DBG
BSTR bstrUDN = NULL;
hr = pDevice->get_UniqueDeviceName(&bstrUDN);
TraceTag(ttidShellTray, "DeviceFinderCallback -- New Device. SearchId: %x, UDN: %S",
lFindData, bstrUDN);
SysFreeString(bstrUDN);
#endif // DBG
BSTR bstrPresUrl;
hr = pDevice->get_PresentationURL(&bstrPresUrl);
if (S_OK == hr)
{
URL_COMPONENTS urlComp = {0};
TraceTag(ttidShellTray, "Checking if %S is a valid URL...",
bstrPresUrl);
// All we want to do here is verify that the URL is valid. We don't
// need anything back from this function
//
urlComp.dwStructSize = sizeof(URL_COMPONENTS);
if (!InternetCrackUrl(bstrPresUrl, 0, 0, &urlComp))
{
TraceTag(ttidShellTray, "%S is NOT a valid URL!", bstrPresUrl);
hr = HrFromLastWin32Error();
}
SysFreeString(bstrPresUrl);
}
else
{
hr = E_FAIL;
TraceError("Device did not have presentation URL!", hr);
}
if (SUCCEEDED(hr))
{
// (tongl)
// add the device to our folder device list and notify shell in case folder is open
hr = HrAddFolderDevice(pDevice);
if (SUCCEEDED(hr))
{
// transfer information from device object
hr = HrCreateDeviceNodeFromDevice(pDevice, &pNDN);
if (SUCCEEDED(hr))
{
// Assuming we don't already have this device is our list, add it.
//
if (!g_CListUDN.FFind(pNDN->pszUDN, NULL))
{
// Add it to the New Device list.
//
g_CListNewDeviceNode.FAdd(pNDN);
// reset the total balloon count
g_iTotalBalloons =0;
}
else
{
// Cleanup already known device
//
delete pNDN;
}
}
}
}
pDevice->Release();
if (SUCCEEDED(hr))
{
if (!g_fSearchInProgress)
{
hr = HrUpdateTrayInfo();
}
}
TraceError("CUPnPMonitorDeviceFinderCallback::DeviceAdded", hr);
return S_OK;
}
//+---------------------------------------------------------------------------
//
// Member: CUPnPMonitorDeviceFinderCallback::DeviceRemoved
//
// Purpose: Device removed notification. NYI
//
// Arguments:
// lFindData []
// bstrUDN []
//
// Returns:
//
// Author: jeffspr 23 Nov 1999
//
// Notes:
//
HRESULT CUPnPMonitorDeviceFinderCallback::DeviceRemoved(
LONG lFindData,
BSTR bstrUDN)
{
TraceTag(ttidShellTray, "CUPnPMonitorDeviceFinderCallback::DeviceRemoved"
" lFindData = %x, UDN = %S", lFindData, bstrUDN);
Assert(bstrUDN);
// (tongl)
// delete the device from our folder device list and notify shell in case folder is open
HrDeleteFolderDevice((PWSTR)bstrUDN);
HRESULT hr = S_OK;
LPTSTR pszUdn;
BOOL fResult;
pszUdn = BSTRToTsz(bstrUDN);
if (!pszUdn)
{
TraceTag(ttidShellTray, "Could not copy UDN to TCHAR");
hr = E_OUTOFMEMORY;
goto Exit;
}
// search through new device list for new node, removing any nodes
// with matching UDNs
//
fResult = g_CListNewDeviceNode.FDelete(pszUdn);
if (!fResult)
{
// node wasn't deleted
TraceTag(ttidShellTray, "CUPnPMonitorDeviceFinderCallback::DeviceRemoved: "
"%S not found in g_CListNewDeviceNode", pszUdn);
}
// update tray information if search has completed
if (!g_fSearchInProgress)
{
hr = HrUpdateTrayInfo();
}
else
{
// search is still running so delete this from the search list
fResult = g_CListUDNSearch.FDelete(pszUdn);
if (!fResult)
{
// node wasn't deleted
TraceTag(ttidShellTray, "CUPnPMonitorDeviceFinderCallback::DeviceRemoved: "
"%S not found in g_CListUDNSearch", pszUdn);
}
}
Exit:
delete [] pszUdn;
TraceError("CUPnPMonitorDeviceFinderCallback::DeviceRemoved", hr);
return S_OK;
}
//+---------------------------------------------------------------------------
//
// Member: CUPnPMonitorDeviceFinderCallback::SearchComplete
//
// Purpose: Search complete. At this point I can add the tray icon
// if needed and allow for the UI to come up.
//
// Arguments:
// lFindData []
//
// Returns:
//
// Author: jeffspr 6 Jan 2000
//
// Notes:
//
HRESULT CUPnPMonitorDeviceFinderCallback::SearchComplete(LONG lFindData)
{
TraceTag(ttidShellTray, "CUPnPMonitorDeviceFinderCallback::SearchComplete"
" lFindData = %x", lFindData);
HRESULT hr = S_OK;
g_fSearchInProgress = FALSE;
// Add the tray icon and such (if appropriate)
//
hr = HrInitializeUI();
if (SUCCEEDED(hr))
{
EnterCriticalSection(&g_csFolderDeviceList);
FolderDeviceNode * pCurrentNode = NULL;
BOOL fReturn = g_CListFolderDeviceNode.FFirst(&pCurrentNode);
// Loop through all UDNs in the cached list of devices we've found
// and for each one, see if it was found during the search. If not,
// we should delete it from the folder view and from the cache.
while (fReturn && SUCCEEDED(hr))
{
LPWSTR szUdn;
if (!g_CListUDNSearch.FFind(pCurrentNode->pszUDN, &szUdn))
{
hr = HrDeleteFolderDevice(pCurrentNode->pszUDN);
if (SUCCEEDED(hr))
{
if (!g_CListFolderDeviceNode.FDelete(pCurrentNode->pszUDN))
{
hr = E_FAIL;
}
}
}
// move to the next node
fReturn = g_CListFolderDeviceNode.FNext(&pCurrentNode);
}
LeaveCriticalSection(&g_csFolderDeviceList);
}
g_CListUDNSearch.Flush();
TraceError("CUPnPMonitorDeviceFinderCallback::SearchComplete", hr);
return S_OK;
}
CUPnPMonitorDeviceFinderCallback::CUPnPMonitorDeviceFinderCallback()
{
m_pUnkMarshaler = NULL;
TraceTag(ttidShellTray, "CUPnPMonitorDeviceFinderCallback");
}
CUPnPMonitorDeviceFinderCallback::~CUPnPMonitorDeviceFinderCallback()
{
TraceTag(ttidShellTray, "~CUPnPMonitorDeviceFinderCallback");
}