976 lines
28 KiB
C++
976 lines
28 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// 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");
|
|
}
|
|
|