1462 lines
37 KiB
C++
1462 lines
37 KiB
C++
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1997.
|
||
|
//
|
||
|
// File: T M A I N . C P P
|
||
|
//
|
||
|
// Contents: Main code for UPnP Shell tray object
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
// Author: jeffspr 19 Jan 2000
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#include "pch.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#include <upscmn.h>
|
||
|
#include "tfind.h"
|
||
|
#include <ncreg.h>
|
||
|
#include <ncfile.h>
|
||
|
#include <lm.h>
|
||
|
|
||
|
#include "clist.h"
|
||
|
#include "clistndn.h"
|
||
|
|
||
|
#include "tconst.h"
|
||
|
|
||
|
DWORD g_dwDeviceFinderCookie = 0;
|
||
|
LONG g_lFindData = 0;
|
||
|
|
||
|
const TCHAR c_szUPnPDeviceList[] = TEXT("PersistedDeviceUDNs");
|
||
|
const DWORD c_dwTimeout = 10000;
|
||
|
|
||
|
CONST TCHAR c_szMainWindowClassName[] = TEXT("UPnP Notification Monitor");
|
||
|
CONST TCHAR c_szMainWindowTitle[] = TEXT("UPnP Notification Monitor");
|
||
|
CONST TCHAR c_szNameMap[] = TEXT("FriendlyNames");
|
||
|
|
||
|
UINT g_iTotalBalloons = 0;
|
||
|
BOOL g_fTrayPresent = FALSE;
|
||
|
BOOL g_fCoInitialized = FALSE;
|
||
|
HWND g_hwnd = NULL;
|
||
|
BOOL g_fDialogLaunched = FALSE;
|
||
|
BOOL g_fSearchInProgress = FALSE;
|
||
|
|
||
|
VOID OpenContextMenu(HWND hwnd, POINT * pPoint);
|
||
|
VOID OnTaskBarIconRButtonUp(HWND hwnd);
|
||
|
VOID DeInitTrayData(VOID);
|
||
|
|
||
|
LRESULT CALLBACK DiscoveredDevicesDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
|
||
|
|
||
|
VOID AddTrayIcon(HWND hwnd, INT iDevices, PTSTR szName)
|
||
|
{
|
||
|
NOTIFYICONDATA nid = {0};
|
||
|
INT iTrayID = IDI_TRAYICON;
|
||
|
HICON hiconTray = LoadIcon(_Module.GetResourceInstance(),
|
||
|
MAKEINTRESOURCE(IDI_TRAYICON));
|
||
|
if (hiconTray)
|
||
|
{
|
||
|
nid.uID = 0;
|
||
|
nid.cbSize = sizeof(NOTIFYICONDATA);
|
||
|
nid.hWnd = hwnd;
|
||
|
nid.uCallbackMessage = WM_USER_TRAYCALLBACK;
|
||
|
nid.hIcon = hiconTray;
|
||
|
nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP | NIF_INFO;
|
||
|
nid.uTimeout = c_dwTimeout;
|
||
|
nid.dwInfoFlags = NIIF_INFO;
|
||
|
|
||
|
TCHAR * szTitle = NULL;
|
||
|
TCHAR * szInfo = NULL;
|
||
|
TCHAR * szInstructions = NULL;
|
||
|
|
||
|
if (iDevices == 1)
|
||
|
{
|
||
|
_tcsncpy(nid.szInfoTitle, szName, celems(nid.szInfoTitle));
|
||
|
nid.szInfoTitle[celems(nid.szInfoTitle) - 1] = TEXT('\0');
|
||
|
|
||
|
szInfo = TszFromWsz(WszLoadIds(IDS_UPNPTRAYUI_VIEWINFO_1));
|
||
|
if(szInfo)
|
||
|
_tcscpy(nid.szInfo, szInfo);
|
||
|
else
|
||
|
{
|
||
|
TraceTag(ttidShellFolder, "AddTrayIcon:"
|
||
|
"Memory Allocation Failed");
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
szTitle = TszFromWsz(WszLoadIds(IDS_UPNPTRAYUI_DEVICES_DISCOVERED));
|
||
|
if(szTitle)
|
||
|
_tcscpy(nid.szInfoTitle, szTitle);
|
||
|
else
|
||
|
{
|
||
|
TraceTag(ttidShellFolder, "AddTrayIcon:"
|
||
|
"Memory Allocation Failed");
|
||
|
}
|
||
|
|
||
|
szInfo = TszFromWsz(WszLoadIds(IDS_UPNPTRAYUI_VIEWINFO_N));
|
||
|
if(szInfo)
|
||
|
_tcscpy(nid.szInfo, szInfo);
|
||
|
else
|
||
|
{
|
||
|
TraceTag(ttidShellFolder, "AddTrayIcon:"
|
||
|
"Memory Allocation Failed");
|
||
|
}
|
||
|
};
|
||
|
|
||
|
szInstructions = TszFromWsz(WszLoadIds(IDS_UPNPTRAYUI_INSTRUCTIONS));
|
||
|
if(szInstructions)
|
||
|
_tcscpy(nid.szTip, szInstructions);
|
||
|
else
|
||
|
{
|
||
|
TraceTag(ttidShellFolder, "AddTrayIcon:"
|
||
|
"Memory Allocation Failed");
|
||
|
}
|
||
|
|
||
|
delete szTitle;
|
||
|
delete szInfo;
|
||
|
delete szInstructions;
|
||
|
|
||
|
g_iTotalBalloons++;
|
||
|
}
|
||
|
|
||
|
g_fTrayPresent = Shell_NotifyIcon(NIM_ADD, &nid);
|
||
|
if (g_fTrayPresent)
|
||
|
{
|
||
|
g_fDialogLaunched = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: ForceTrayBalloon
|
||
|
//
|
||
|
// Purpose: Force the tray balloon to come back up because the user
|
||
|
// hasn't yet touched it.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// hwnd [in] Our tray window
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// Author: jeffspr 28 Jan 2000
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
VOID ForceTrayBalloon(HWND hwnd, INT iDevices, PTSTR szName)
|
||
|
{
|
||
|
NOTIFYICONDATA nid ={0};
|
||
|
|
||
|
nid.uID = 0;
|
||
|
nid.cbSize = sizeof(NOTIFYICONDATA);
|
||
|
nid.hWnd = hwnd;
|
||
|
nid.uFlags = NIF_INFO;
|
||
|
nid.uTimeout = c_dwTimeout;
|
||
|
nid.dwInfoFlags = NIIF_INFO;
|
||
|
|
||
|
TCHAR * szTitle = NULL;
|
||
|
TCHAR * szInfo = NULL;
|
||
|
TCHAR * szInstructions = NULL;
|
||
|
|
||
|
if (iDevices == 1)
|
||
|
{
|
||
|
_tcsncpy(nid.szInfoTitle, szName, celems(nid.szInfoTitle));
|
||
|
nid.szInfoTitle[celems(nid.szInfoTitle) - 1] = TEXT('\0');
|
||
|
|
||
|
szInfo = TszFromWsz(WszLoadIds(IDS_UPNPTRAYUI_VIEWINFO_1));
|
||
|
if(szInfo)
|
||
|
_tcscpy(nid.szInfo, szInfo);
|
||
|
else
|
||
|
{
|
||
|
TraceTag(ttidShellFolder, "ForceTrayBalloon:"
|
||
|
"Memory Allocation Failed");
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
szTitle = TszFromWsz(WszLoadIds(IDS_UPNPTRAYUI_DEVICES_DISCOVERED));
|
||
|
if(szTitle)
|
||
|
_tcscpy(nid.szInfoTitle, szTitle);
|
||
|
else
|
||
|
{
|
||
|
TraceTag(ttidShellFolder, "ForceTrayBalloon:"
|
||
|
"Memory Allocation Failed");
|
||
|
}
|
||
|
szInfo = TszFromWsz(WszLoadIds(IDS_UPNPTRAYUI_VIEWINFO_N));
|
||
|
if(szInfo)
|
||
|
_tcscpy(nid.szInfo, szInfo);
|
||
|
else
|
||
|
{
|
||
|
TraceTag(ttidShellFolder, "ForceTrayBalloon:"
|
||
|
"Memory Allocation Failed");
|
||
|
}
|
||
|
};
|
||
|
|
||
|
szInstructions = TszFromWsz(WszLoadIds(IDS_UPNPTRAYUI_INSTRUCTIONS));
|
||
|
if(szInstructions)
|
||
|
_tcscpy(nid.szTip, szInstructions);
|
||
|
else
|
||
|
{
|
||
|
TraceTag(ttidShellFolder, "ForceTrayBalloon:"
|
||
|
"Memory Allocation Failed");
|
||
|
}
|
||
|
|
||
|
delete szTitle;
|
||
|
delete szInfo;
|
||
|
delete szInstructions;
|
||
|
|
||
|
g_iTotalBalloons++;
|
||
|
g_fTrayPresent = Shell_NotifyIcon(NIM_MODIFY, &nid);
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: RemoveTrayIcon
|
||
|
//
|
||
|
// Purpose: Remove the UPNP Monitor icon from the tray. This is done when
|
||
|
// the devices dialog has gone away.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// hwnd [in] Our tray window
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// Author: jeffspr 28 Jan 2000
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
VOID RemoveTrayIcon(HWND hwnd)
|
||
|
{
|
||
|
if (g_fTrayPresent)
|
||
|
{
|
||
|
NOTIFYICONDATA nid = {0};
|
||
|
|
||
|
nid.uID = 0;
|
||
|
nid.cbSize = sizeof(NOTIFYICONDATA);
|
||
|
nid.hWnd = hwnd;
|
||
|
nid.uCallbackMessage = WM_USER_TRAYCALLBACK;
|
||
|
nid.uFlags = 0;
|
||
|
|
||
|
g_fTrayPresent = !(Shell_NotifyIcon(NIM_DELETE, &nid));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrCreateShortcut
|
||
|
//
|
||
|
// Purpose: Create a shortcut for the item passed in.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// lpszExe [in] What this is a shortcut to.
|
||
|
// lpszLink [in] The file location for the shortcut
|
||
|
// lpszDesc [in] Description (name that will appear)
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// Author: jeffspr 13 Jan 2000
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
HRESULT HrCreateShortcut (HWND hwnd, LPCTSTR lpszLink, LPCTSTR szUdn)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
IShellFolder * psfDeskTop = NULL;
|
||
|
|
||
|
LPWSTR wszUdn = NULL;
|
||
|
LPWSTR wszLink = NULL;
|
||
|
|
||
|
wszUdn = WszFromTsz(szUdn);
|
||
|
wszLink = WszFromTsz(lpszLink);
|
||
|
|
||
|
if (!wszUdn || !wszLink)
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
goto Error;
|
||
|
}
|
||
|
|
||
|
CoInitialize(NULL);
|
||
|
|
||
|
// Create a pidl for the connection
|
||
|
//
|
||
|
// (tongl 2/16/00): we are now a delegated folder, the pidl must be constructed
|
||
|
// within the IShellFolder object using the allocator set by IDelegate.
|
||
|
// We call parseDisplayName giving the UDN to get the absolute pidl
|
||
|
// (i.e. including the pidl for any parent folders)
|
||
|
//
|
||
|
hr = SHGetDesktopFolder(&psfDeskTop);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
Assert(psfDeskTop);
|
||
|
|
||
|
LPITEMIDLIST pidlFull = NULL;
|
||
|
LPWSTR pszNotifyString;
|
||
|
|
||
|
pszNotifyString = CreateChangeNotifyString(wszUdn);
|
||
|
if (pszNotifyString)
|
||
|
{
|
||
|
hr = psfDeskTop->ParseDisplayName( NULL, // hwndOwner
|
||
|
NULL, // pbcReserved
|
||
|
pszNotifyString, // lpszDisplayName
|
||
|
NULL, // pchEaten,
|
||
|
&pidlFull, // ppidl,
|
||
|
NULL // pdwAttributes
|
||
|
);
|
||
|
|
||
|
delete [] pszNotifyString;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
Assert(pidlFull);
|
||
|
|
||
|
IShellLink *psl = NULL;
|
||
|
|
||
|
hr = CoCreateInstance(CLSID_ShellLink, NULL,
|
||
|
CLSCTX_INPROC_SERVER,
|
||
|
IID_IShellLink, (LPVOID*)&psl);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
IPersistFile *ppf = NULL;
|
||
|
|
||
|
// Set the combined IDL
|
||
|
//
|
||
|
hr = psl->SetIDList(pidlFull);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = psl->QueryInterface(IID_IPersistFile,
|
||
|
(LPVOID *)&ppf);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// Create the link file.
|
||
|
//
|
||
|
hr = ppf->Save(wszLink, TRUE);
|
||
|
|
||
|
ReleaseObj(ppf);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ReleaseObj(psl);
|
||
|
}
|
||
|
|
||
|
FreeIDL(pidlFull);
|
||
|
}
|
||
|
ReleaseObj(psfDeskTop);
|
||
|
}
|
||
|
|
||
|
Error:
|
||
|
free(wszUdn);
|
||
|
free(wszLink);
|
||
|
|
||
|
TraceError("HrCreateShortcut", hr);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: OnTrayViewDevices
|
||
|
//
|
||
|
// Purpose: If one new device in the list, bring up dialog to create
|
||
|
// shortcut. In either case bring up NetworkNeighborhood
|
||
|
// folder.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// hwnd [in] Our parent hwnd.
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// Author: tongl 25 Feb 2000
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
VOID OnTrayViewDevices(HWND hwnd)
|
||
|
{
|
||
|
if (g_fDialogLaunched)
|
||
|
return;
|
||
|
|
||
|
g_fDialogLaunched = TRUE;
|
||
|
RemoveTrayIcon(g_hwnd);
|
||
|
|
||
|
NewDeviceNode * pNDN = NULL;
|
||
|
|
||
|
// In any case:
|
||
|
// 1) persist discovered devices so they don't show as new devices
|
||
|
// again
|
||
|
|
||
|
// Walk through the new device list and add them to the known
|
||
|
// device list
|
||
|
//
|
||
|
BOOL fFind = g_CListNewDeviceNode.FFirst(&pNDN);
|
||
|
while (fFind)
|
||
|
{
|
||
|
LPTSTR pszUdn = TszDupTsz(pNDN->pszUDN);
|
||
|
if (pszUdn)
|
||
|
{
|
||
|
BOOL fResult;
|
||
|
|
||
|
fResult = g_CListUDN.FAdd(pszUdn);
|
||
|
if (!fResult)
|
||
|
{
|
||
|
TraceTag(ttidShellFolder,
|
||
|
"OnTrayViewDevices: "
|
||
|
"could not add UDN to g_CListUDN");
|
||
|
|
||
|
delete [] pszUdn;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceTag(ttidShellFolder,
|
||
|
"OnTrayViewDevices: "
|
||
|
"could not copy UDN");
|
||
|
}
|
||
|
fFind = g_CListNewDeviceNode.FNext(&pNDN);
|
||
|
}
|
||
|
|
||
|
// save the known device list to registry
|
||
|
HrSaveTrayData();
|
||
|
|
||
|
// flush the new devices list
|
||
|
g_CListNewDeviceNode.Flush();
|
||
|
|
||
|
// allow tray icons to be added for new devices
|
||
|
g_fDialogLaunched = FALSE;
|
||
|
|
||
|
// 2) bring up the folder
|
||
|
HrOpenSpecialShellFolder(hwnd, CSIDL_NETWORK);
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: OnTrayLButtonDown
|
||
|
//
|
||
|
// Purpose: Message processing for an LBUTTONDOWN message on the tray
|
||
|
// icon
|
||
|
//
|
||
|
// Arguments:
|
||
|
// hwnd [in] Our tray window
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// Author: jeffspr 28 Jan 2000
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
VOID OnTrayLButtonDown(HWND hwnd)
|
||
|
{
|
||
|
// Otherwise, launch it.
|
||
|
//
|
||
|
OnTrayViewDevices(hwnd);
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: OnTrayLButtonUp
|
||
|
//
|
||
|
// Purpose: Message processing for an LBUTTONUP message on the tray icon
|
||
|
//
|
||
|
// Arguments:
|
||
|
// hwnd [in] Our tray window
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// Author: jeffspr 28 Jan 2000
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
VOID OnTrayLButtonUp(HWND hwnd)
|
||
|
{
|
||
|
// Remove the tray icon since we're loading the dialog box and won't have
|
||
|
// any items to display there anymore.
|
||
|
//
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: ProcessTrayCallback
|
||
|
//
|
||
|
// Purpose: Message processing for the tray icon callback messages.
|
||
|
// Mostly these are button up/down events
|
||
|
//
|
||
|
// Arguments:
|
||
|
// hwnd [in] Our tray window
|
||
|
// wParam [in] standard tray callback param. see usage below
|
||
|
// lParam [in] standard tray callback param. see usage below
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// Author: jeffspr 28 Jan 2000
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
VOID ProcessTrayCallback(
|
||
|
HWND hwnd,
|
||
|
WPARAM wParam,
|
||
|
LPARAM lParam)
|
||
|
{
|
||
|
UINT uID = (UINT) wParam;
|
||
|
UINT uMouseMsg = (UINT) lParam;
|
||
|
DWORD dwError = 0;
|
||
|
|
||
|
switch (uMouseMsg)
|
||
|
{
|
||
|
case WM_LBUTTONDOWN:
|
||
|
OnTrayLButtonDown(hwnd);
|
||
|
break;
|
||
|
|
||
|
case WM_LBUTTONUP:
|
||
|
OnTrayLButtonUp(hwnd);
|
||
|
break;
|
||
|
|
||
|
case WM_RBUTTONUP:
|
||
|
OnTaskBarIconRButtonUp(hwnd);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: MainWindowProc
|
||
|
//
|
||
|
// Purpose: Main window for the tray monitor
|
||
|
//
|
||
|
// Arguments:
|
||
|
// hwnd [in] Standard
|
||
|
// unMsg [in] Standard
|
||
|
// wParam [in] Standard
|
||
|
// lParam [in] Standard
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// Author: jeffspr 28 Jan 2000
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
LRESULT CALLBACK MainWindowProc (
|
||
|
HWND hwnd,
|
||
|
UINT unMsg,
|
||
|
WPARAM wParam,
|
||
|
LPARAM lParam)
|
||
|
{
|
||
|
BOOL fDoDefault = FALSE;
|
||
|
LRESULT lr = 0;
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
switch (unMsg)
|
||
|
{
|
||
|
case WM_CREATE:
|
||
|
g_hwnd = hwnd;
|
||
|
|
||
|
hr = HrInitTrayData();
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = HrStartSearch();
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case WM_DESTROY:
|
||
|
hr = HrSaveTrayData();
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
RemoveTrayIcon(hwnd);
|
||
|
DeInitTrayData();
|
||
|
}
|
||
|
|
||
|
g_hwnd = NULL;
|
||
|
|
||
|
PostQuitMessage (0);
|
||
|
break;
|
||
|
|
||
|
case WM_USER_TRAYCALLBACK:
|
||
|
ProcessTrayCallback(hwnd, wParam, lParam);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
fDoDefault = TRUE;
|
||
|
}
|
||
|
|
||
|
if (fDoDefault)
|
||
|
{
|
||
|
lr = DefWindowProc (hwnd, unMsg, wParam, lParam);
|
||
|
}
|
||
|
|
||
|
return lr;
|
||
|
}
|
||
|
|
||
|
VOID OnTaskBarIconRButtonUp(HWND hwnd)
|
||
|
{
|
||
|
POINT pt;
|
||
|
|
||
|
GetCursorPos(&pt);
|
||
|
OpenContextMenu(hwnd, &pt);
|
||
|
}
|
||
|
|
||
|
#if (WINVER > 0x0400)
|
||
|
VOID SetIconFocus(HWND hwnd)
|
||
|
{
|
||
|
NOTIFYICONDATA nid;
|
||
|
|
||
|
ZeroMemory (&nid, sizeof(nid));
|
||
|
nid.cbSize = sizeof(NOTIFYICONDATA);
|
||
|
nid.hWnd = hwnd;
|
||
|
nid.uID = 0;
|
||
|
|
||
|
Shell_NotifyIcon(NIM_SETFOCUS, &nid);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
VOID OpenContextMenu(HWND hwnd, POINT * pPoint)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
INT iCmd = 0;
|
||
|
INT iMenu = 0;
|
||
|
HMENU hmenu = 0;
|
||
|
BOOL fDisconnected = FALSE;
|
||
|
INT iIdCustomMin = -1;
|
||
|
INT iIdCustomMax = -1;
|
||
|
BOOL fBranded = FALSE;
|
||
|
|
||
|
// Find the connection info based on the tray icon id.
|
||
|
//
|
||
|
hmenu = LoadMenu(_Module.GetResourceInstance(),
|
||
|
MAKEINTRESOURCE(POPUP_TRAY));
|
||
|
if (hmenu)
|
||
|
{
|
||
|
// Get the first menu from the popup. For some reason, this hack is
|
||
|
// required instead of tracking on the outside menu
|
||
|
//
|
||
|
HMENU hmenuTrack = GetSubMenu(hmenu, 0);
|
||
|
|
||
|
// Set the default menu item
|
||
|
//
|
||
|
SetMenuDefaultItem(hmenuTrack, CMIDM_TRAY_VIEW_DEVICES, FALSE);
|
||
|
|
||
|
// Set the owner window to be foreground as a hack so the
|
||
|
// popup menu disappears when the user clicks elsewhere.
|
||
|
//
|
||
|
SetForegroundWindow(hwnd);
|
||
|
|
||
|
// Part of the above hack. Bring up the menu and figure out the result
|
||
|
iCmd = TrackPopupMenu(hmenuTrack, TPM_RETURNCMD | TPM_NONOTIFY | TPM_RIGHTBUTTON,
|
||
|
pPoint->x, pPoint->y, 0, hwnd, NULL);
|
||
|
DestroyMenu(hmenu);
|
||
|
|
||
|
MSG msgTmp;
|
||
|
while (PeekMessage(&msgTmp, hwnd, WM_LBUTTONDOWN, WM_LBUTTONUP, PM_REMOVE))
|
||
|
{
|
||
|
DispatchMessage(&msgTmp);
|
||
|
}
|
||
|
|
||
|
// Process the command
|
||
|
//
|
||
|
switch (iCmd)
|
||
|
{
|
||
|
case CMIDM_TRAY_VIEW_DEVICES:
|
||
|
// (TongL) - per design change 2/22/00
|
||
|
OnTrayViewDevices(hwnd);
|
||
|
break;
|
||
|
|
||
|
// Tray menu cancelled without selection
|
||
|
//
|
||
|
case 0:
|
||
|
break;
|
||
|
|
||
|
// Unknown command
|
||
|
//
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Shift the focus back to the shell
|
||
|
//
|
||
|
#if (WINVER > 0x0400)
|
||
|
SetIconFocus(hwnd);
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HWND StartUPnPTray()
|
||
|
{
|
||
|
WNDCLASSEX wcex;
|
||
|
|
||
|
// Register our window class.
|
||
|
//
|
||
|
ZeroMemory (&wcex, sizeof(wcex));
|
||
|
wcex.cbSize = sizeof(wcex);
|
||
|
wcex.style = CS_HREDRAW | CS_VREDRAW;
|
||
|
wcex.lpfnWndProc = MainWindowProc;
|
||
|
wcex.hInstance = _Module.GetResourceInstance();
|
||
|
wcex.hCursor = LoadCursor (NULL, IDC_ARROW);
|
||
|
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
||
|
wcex.lpszClassName = c_szMainWindowClassName;
|
||
|
|
||
|
if (RegisterClassEx (&wcex))
|
||
|
{
|
||
|
// Create our main window.
|
||
|
//
|
||
|
HWND hwnd;
|
||
|
|
||
|
hwnd = CreateWindowEx (
|
||
|
0,
|
||
|
c_szMainWindowClassName,
|
||
|
c_szMainWindowTitle,
|
||
|
WS_OVERLAPPEDWINDOW,
|
||
|
0, 0, 0, 0,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
_Module.GetResourceInstance(),
|
||
|
NULL);
|
||
|
if (hwnd)
|
||
|
{
|
||
|
ShowWindow (hwnd, SW_HIDE);
|
||
|
|
||
|
return hwnd;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
HRESULT HrRegisterInGit(IUnknown *punk, DWORD *pdwCookie)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
IGlobalInterfaceTable * pgit;
|
||
|
|
||
|
pgit = NULL;
|
||
|
|
||
|
hr = CoCreateInstance(CLSID_StdGlobalInterfaceTable,
|
||
|
NULL,
|
||
|
CLSCTX_INPROC_SERVER,
|
||
|
IID_IGlobalInterfaceTable,
|
||
|
(LPVOID*)&pgit);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = pgit->RegisterInterfaceInGlobal(punk, IID_IUPnPDeviceFinder,
|
||
|
pdwCookie);
|
||
|
|
||
|
pgit->Release();
|
||
|
}
|
||
|
|
||
|
TraceError("HrRegisterInGit", hr);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT HrGetDeviceFinderFromGit(IUPnPDeviceFinder **ppdf)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
IGlobalInterfaceTable * pgit;
|
||
|
|
||
|
pgit = NULL;
|
||
|
|
||
|
hr = CoCreateInstance(CLSID_StdGlobalInterfaceTable,
|
||
|
NULL,
|
||
|
CLSCTX_INPROC_SERVER,
|
||
|
IID_IGlobalInterfaceTable,
|
||
|
(LPVOID*)&pgit);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = pgit->GetInterfaceFromGlobal(g_dwDeviceFinderCookie,
|
||
|
IID_IUPnPDeviceFinder,
|
||
|
(LPVOID *)ppdf);
|
||
|
|
||
|
pgit->Release();
|
||
|
}
|
||
|
|
||
|
TraceError("HrGetDeviceFinderFromGit", hr);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
VOID UnregisterInGit(DWORD dwCookie)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
IGlobalInterfaceTable * pgit;
|
||
|
|
||
|
pgit = NULL;
|
||
|
|
||
|
hr = CoCreateInstance(CLSID_StdGlobalInterfaceTable,
|
||
|
NULL,
|
||
|
CLSCTX_INPROC_SERVER,
|
||
|
IID_IGlobalInterfaceTable,
|
||
|
(LPVOID*)&pgit);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = pgit->RevokeInterfaceFromGlobal(dwCookie);
|
||
|
|
||
|
pgit->Release();
|
||
|
}
|
||
|
|
||
|
TraceError("HrUnregisterInGit", hr);
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrInitTrayData
|
||
|
//
|
||
|
// Purpose: Load the tray data during app (or service) startup
|
||
|
//
|
||
|
// Arguments:
|
||
|
// (none)
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// Author: jeffspr 9 Dec 1999
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
HRESULT HrInitTrayData()
|
||
|
{
|
||
|
HRESULT hr = HrLoadPersistedDevices();
|
||
|
|
||
|
Assert(!g_dwDeviceFinderCookie);
|
||
|
|
||
|
if (!g_fCoInitialized)
|
||
|
{
|
||
|
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
g_fCoInitialized = TRUE;
|
||
|
|
||
|
IUPnPDeviceFinder * pdfTray = NULL;
|
||
|
|
||
|
hr = CoCreateInstance(CLSID_UPnPDeviceFinder,
|
||
|
NULL,
|
||
|
CLSCTX_INPROC_SERVER,
|
||
|
IID_IUPnPDeviceFinder,
|
||
|
(void **)&pdfTray);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = HrRegisterInGit(pdfTray, &g_dwDeviceFinderCookie);
|
||
|
|
||
|
pdfTray->Release();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TraceHr(ttidShellTray, FAL, hr, FALSE, "HrInitTrayData");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
VOID DeInitTrayData()
|
||
|
{
|
||
|
g_CListFolderDeviceNode.Flush();
|
||
|
g_CListNewDeviceNode.Flush();
|
||
|
g_CListUDN.Flush();
|
||
|
g_CListNameMap.Flush();
|
||
|
|
||
|
UnregisterInGit(g_dwDeviceFinderCookie);
|
||
|
|
||
|
if (g_fCoInitialized)
|
||
|
{
|
||
|
CoUninitialize();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HRESULT HrStartSearch()
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
if (!g_fSearchInProgress && g_dwDeviceFinderCookie)
|
||
|
{
|
||
|
CComObject<CUPnPMonitorDeviceFinderCallback> * pCallback = NULL;
|
||
|
|
||
|
TraceTag(ttidShellTray, "DeviceFinderCallback created. Turn on "
|
||
|
"thread id tracing to get useful info");
|
||
|
|
||
|
IUPnPDeviceFinderCallback * pudfc = NULL;
|
||
|
|
||
|
pCallback->CreateInstance(&pCallback);
|
||
|
hr = pCallback->QueryInterface(IID_IUPnPDeviceFinderCallback,
|
||
|
(LPVOID *)&pudfc);
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
// Find the devices
|
||
|
//
|
||
|
BSTR bstrFind = NULL;
|
||
|
|
||
|
hr = HrSysAllocString(L"upnp:rootdevice", &bstrFind);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
LONG lFindData = 0;
|
||
|
IUPnPDeviceFinder * pdfTray = NULL;
|
||
|
|
||
|
hr = HrGetDeviceFinderFromGit(&pdfTray);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
if (g_lFindData)
|
||
|
{
|
||
|
// Cancel outstanding search first
|
||
|
hr = pdfTray->CancelAsyncFind(g_lFindData);
|
||
|
}
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = pdfTray->CreateAsyncFind(bstrFind, 0, pudfc, &g_lFindData);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
g_fSearchInProgress = TRUE;
|
||
|
hr = pdfTray->StartAsyncFind(g_lFindData);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
g_fSearchInProgress = FALSE;
|
||
|
}
|
||
|
|
||
|
// This has been handed off to the device finder now
|
||
|
ReleaseObj(pudfc);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ReleaseObj(pdfTray);
|
||
|
}
|
||
|
|
||
|
::SysFreeString(bstrFind);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
TraceError("Failed to create callback object in "
|
||
|
"StartUPnPFind", hr);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceTag(ttidShellTray, "Not starting search again since we are already"
|
||
|
" searching...");
|
||
|
}
|
||
|
|
||
|
TraceError("HrStartSearch", hr);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT HrSaveTrayData()
|
||
|
{
|
||
|
HRESULT hr = HrSavePersistedDevices();
|
||
|
|
||
|
TraceHr(ttidShellTray, FAL, hr, FALSE, "HrSaveTrayData");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrOpenUPnPRegRoot
|
||
|
//
|
||
|
// Purpose: Open the UPnP registry root, and return it to the caller
|
||
|
//
|
||
|
// Arguments:
|
||
|
// phkeyRegRoot [out] Return var for HKEY
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// Author: jeffspr 13 Dec 1999
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
HRESULT HrOpenUPnPRegRoot(HKEY * phkeyRegRoot)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
HKEY hkeyRegRoot = NULL;
|
||
|
DWORD dwDisposition = 0;
|
||
|
|
||
|
hr = HrRegCreateKeyEx(
|
||
|
HKEY_CURRENT_USER,
|
||
|
c_szUPnPRegRoot,
|
||
|
REG_OPTION_NON_VOLATILE,
|
||
|
KEY_ALL_ACCESS,
|
||
|
NULL,
|
||
|
&hkeyRegRoot,
|
||
|
&dwDisposition);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
*phkeyRegRoot = hkeyRegRoot;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrInputUDNListFromRegistry
|
||
|
//
|
||
|
// Purpose: Import UDN lists from registry.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// hkeyList [in] HKEY to read from
|
||
|
// pszValue [in] Registry value to load
|
||
|
// pCList [in] CList to populate
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// Author: jeffspr 18 Jan 2000
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
HRESULT HrInputUDNListFromRegistry(HKEY hkeyList,
|
||
|
LPCTSTR pszValue,
|
||
|
CListString * pCList)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
LPBYTE pbDevices = NULL;
|
||
|
DWORD dwSize = 0;
|
||
|
DWORD dwType = REG_MULTI_SZ;
|
||
|
|
||
|
Assert(hkeyList);
|
||
|
Assert(pszValue);
|
||
|
Assert(pCList);
|
||
|
|
||
|
// Query the multi-sz from our registry location.
|
||
|
//
|
||
|
hr = HrRegQueryValueWithAlloc (
|
||
|
hkeyList,
|
||
|
pszValue,
|
||
|
&dwType,
|
||
|
&pbDevices,
|
||
|
&dwSize);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// Walk through the multi-sz and copy into our UDN list
|
||
|
//
|
||
|
TCHAR * pszIterate = (TCHAR *) pbDevices;
|
||
|
while (pszIterate[0] != TEXT('\0'))
|
||
|
{
|
||
|
pCList->FAdd(TszDupTsz(pszIterate));
|
||
|
pszIterate += (_tcslen(pszIterate) + 1);
|
||
|
}
|
||
|
|
||
|
delete pbDevices;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Ignore this, just means that we don't have any devices listed yet.
|
||
|
//
|
||
|
if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
|
||
|
{
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrInputNameMapFromRegistry
|
||
|
//
|
||
|
// Purpose: Reads the mapping between UDN and friendly name from the
|
||
|
// registry into the given list
|
||
|
//
|
||
|
// Arguments:
|
||
|
// hkeyParent [in] Parent HKEY of UPnP
|
||
|
// pCList [in out] List to add items to
|
||
|
//
|
||
|
// Returns: S_OK if success, E_OUTOFMEMORY if no memory, Win32 error
|
||
|
// otherwise
|
||
|
//
|
||
|
// Author: danielwe 2000/10/25
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
HRESULT HrInputNameMapFromRegistry(HKEY hkeyParent, CListNameMap * pCList)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
HKEY hkey;
|
||
|
|
||
|
Assert(hkeyParent);
|
||
|
Assert(pCList);
|
||
|
|
||
|
hr = HrRegOpenKeyEx(hkeyParent, c_szNameMap, KEY_READ, &hkey);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
WCHAR szValueName[MAX_PATH];
|
||
|
WCHAR szValueData[MAX_PATH];
|
||
|
DWORD cbValueName;
|
||
|
DWORD cbValueData;
|
||
|
DWORD dwIndex = 0;
|
||
|
DWORD dwType;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
cbValueName = MAX_PATH;
|
||
|
cbValueData = MAX_PATH;
|
||
|
|
||
|
// Enumerate each value name
|
||
|
hr = HrRegEnumValue(hkey, dwIndex, szValueName, &cbValueName,
|
||
|
&dwType, (LPBYTE)szValueData, &cbValueData);
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
NAME_MAP * pnm;
|
||
|
|
||
|
pnm = new NAME_MAP;
|
||
|
if (pnm)
|
||
|
{
|
||
|
pnm->szName = TszDupTsz(szValueData);
|
||
|
if (!pnm->szName)
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pnm->szUdn = TszDupTsz(szValueName);
|
||
|
if (!pnm->szUdn)
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pCList->FAdd(pnm);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
++dwIndex;
|
||
|
} while (S_OK == hr);
|
||
|
|
||
|
if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr)
|
||
|
{
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
|
||
|
RegCloseKey(hkey);
|
||
|
}
|
||
|
|
||
|
TraceError("HrInputNameMapFromRegistry", hr);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrSaveNameMapToRegistry
|
||
|
//
|
||
|
// Purpose: Persists the in-memory mapping of UDN to friendly name into
|
||
|
// the registry
|
||
|
//
|
||
|
// Arguments:
|
||
|
// hkeyParent [in] Parent HKEY of UPnP
|
||
|
// pCList [in out] List to add items to
|
||
|
//
|
||
|
// Returns: S_OK if success, E_OUTOFMEMORY if no memory, Win32 error
|
||
|
// otherwise
|
||
|
//
|
||
|
// Author: danielwe 2000/10/25
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
HRESULT HrSaveNameMapToRegistry(HKEY hkeyParent, CListNameMap * pCList)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
HKEY hkey;
|
||
|
|
||
|
Assert(hkeyParent);
|
||
|
Assert(pCList);
|
||
|
|
||
|
hr = HrRegCreateKeyEx(hkeyParent, c_szNameMap, 0, KEY_ALL_ACCESS, NULL,
|
||
|
&hkey, NULL);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
BOOL fRet;
|
||
|
NAME_MAP * pnm;
|
||
|
|
||
|
fRet = pCList->FFirst(&pnm);
|
||
|
while (fRet && SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = HrRegSetSz(hkey, pnm->szUdn, pnm->szName);
|
||
|
fRet = pCList->FNext(&pnm);
|
||
|
}
|
||
|
|
||
|
|
||
|
RegCloseKey(hkey);
|
||
|
}
|
||
|
|
||
|
TraceError("HrSaveNameMapToRegistry", hr);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrLoadPersistedDevices
|
||
|
//
|
||
|
// Purpose: Load the persisted device list out of the registry
|
||
|
// and populate our linked lists before we start the
|
||
|
// UPnP device finder.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// (none)
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// Author: jeffspr 9 Dec 1999
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
HRESULT HrLoadPersistedDevices()
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
HKEY hkeyRegRoot = NULL;
|
||
|
|
||
|
hr = HrOpenUPnPRegRoot(&hkeyRegRoot);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = HrInputUDNListFromRegistry(hkeyRegRoot, c_szUPnPDeviceList, &g_CListUDN);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = HrInputNameMapFromRegistry(hkeyRegRoot, &g_CListNameMap);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
RegSafeCloseKey(hkeyRegRoot);
|
||
|
|
||
|
TraceHr(ttidShellTray, FAL, hr, FALSE, "HrLoadPersistedDevices");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrSaveUDNListToRegistry
|
||
|
//
|
||
|
// Purpose: Save a PTSTR CList object to a multi-sz in the given key
|
||
|
//
|
||
|
// Arguments:
|
||
|
// hkeyList [in] Reg key to write to
|
||
|
// pszValue [in] Reg value name
|
||
|
// pCList [in] List object to process
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// Author: jeffspr 19 Jan 2000
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
HRESULT HrSaveUDNListToRegistry(HKEY hkeyList,
|
||
|
LPCTSTR pszValue,
|
||
|
CListString * pCList)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
DWORD dwStringSize = 0;
|
||
|
LPTSTR pszFind = NULL;
|
||
|
LPBYTE pbBuffer = NULL;
|
||
|
|
||
|
BOOL fReturn = pCList->FFirst(&pszFind);
|
||
|
while (fReturn)
|
||
|
{
|
||
|
dwStringSize += (_tcslen(pszFind) + 1);
|
||
|
fReturn = pCList->FNext(&pszFind);
|
||
|
}
|
||
|
|
||
|
// If there aren't any items, then we need at least a trailing NULL
|
||
|
//
|
||
|
if (dwStringSize == 0)
|
||
|
{
|
||
|
dwStringSize++;
|
||
|
}
|
||
|
|
||
|
pbBuffer = new BYTE[(dwStringSize+1) * sizeof(TCHAR)];
|
||
|
if (!pbBuffer)
|
||
|
{
|
||
|
TraceTag(ttidShellTray, "Failed to allocate blob for persisted device write");
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LPTSTR pszOffset = (LPTSTR) pbBuffer;
|
||
|
DWORD dwStringUsedTotal = 0;
|
||
|
DWORD dwStringUsedTemp = 0;
|
||
|
|
||
|
pszOffset[0] = TEXT('\0'); // just in case we don't add any items
|
||
|
|
||
|
fReturn = pCList->FFirst(&pszFind);
|
||
|
while (fReturn)
|
||
|
{
|
||
|
dwStringUsedTemp = (_tcslen(pszFind) + 1);
|
||
|
dwStringUsedTotal += dwStringUsedTemp;
|
||
|
|
||
|
Assert(dwStringUsedTotal <= dwStringSize);
|
||
|
|
||
|
_tcscpy(pszOffset, pszFind);
|
||
|
pszOffset += dwStringUsedTemp;
|
||
|
|
||
|
// Set the terminating double-NULL
|
||
|
//
|
||
|
pszOffset[0] = TEXT('\0');
|
||
|
|
||
|
// Get the next item from the list.
|
||
|
//
|
||
|
fReturn = pCList->FNext(&pszFind);
|
||
|
}
|
||
|
|
||
|
// Make sure we cover the minimal case
|
||
|
//
|
||
|
if (dwStringUsedTotal == 0)
|
||
|
dwStringUsedTotal = 1; // we have at least a double-NULL
|
||
|
|
||
|
// Save our string back into the registry
|
||
|
//
|
||
|
hr = HrRegSetValueEx (
|
||
|
hkeyList,
|
||
|
pszValue,
|
||
|
REG_MULTI_SZ,
|
||
|
(const BYTE *)pbBuffer,
|
||
|
(dwStringUsedTotal + 1) * sizeof(TCHAR));
|
||
|
}
|
||
|
|
||
|
TraceHr(ttidShellTray, FAL, hr, FALSE, "HrSaveUDNListToRegistry");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrSavePersistedDevices
|
||
|
//
|
||
|
// Purpose: Write our list back to the registry
|
||
|
//
|
||
|
// Arguments:
|
||
|
// (none)
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// Author: jeffspr 13 Dec 1999
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
HRESULT HrSavePersistedDevices()
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
HKEY hkeyRegRoot = NULL;
|
||
|
|
||
|
hr = HrOpenUPnPRegRoot(&hkeyRegRoot);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = HrSaveUDNListToRegistry(hkeyRegRoot, c_szUPnPDeviceList, &g_CListUDN);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = HrSaveNameMapToRegistry(hkeyRegRoot, &g_CListNameMap);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
RegSafeCloseKey(hkeyRegRoot);
|
||
|
|
||
|
TraceHr(ttidShellTray, FAL, hr, FALSE, "HrSavePersistedDevices");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: FIsJoinedToDomain
|
||
|
//
|
||
|
// Purpose: Returns whether or not the machine is joined to a domain
|
||
|
//
|
||
|
// Arguments:
|
||
|
// (none)
|
||
|
//
|
||
|
// Returns: TRUE if joined, FALSE if not
|
||
|
//
|
||
|
// Author: danielwe 2001/04/16
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
BOOL FIsJoinedToDomain()
|
||
|
{
|
||
|
LPTSTR szDomain;
|
||
|
NETSETUP_JOIN_STATUS njs;
|
||
|
|
||
|
if (NERR_Success == NetGetJoinInformation(NULL, &szDomain, &njs))
|
||
|
{
|
||
|
NetApiBufferFree(szDomain);
|
||
|
|
||
|
return !!(njs == NetSetupDomainName);
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrUpdateTrayInfo
|
||
|
//
|
||
|
// Purpose: Update the tray as needed. This should get called at the
|
||
|
// initial SearchComplete and for every new device afterwards
|
||
|
// to make sure that we have the correct tooltip and add
|
||
|
// the tray icon again as needed
|
||
|
//
|
||
|
// Arguments:
|
||
|
// (none)
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// Author: jeffspr 28 Jan 2000
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
HRESULT HrUpdateTrayInfo()
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
NewDeviceNode * pNDN = NULL;
|
||
|
int iElements = 0;
|
||
|
|
||
|
// retrieve number of new devices pending...
|
||
|
iElements = g_CListNewDeviceNode.GetCount();
|
||
|
BOOL fRet = g_CListNewDeviceNode.FFirst(&pNDN);
|
||
|
|
||
|
TCHAR szDisplayName[MAX_PATH];
|
||
|
if (fRet)
|
||
|
{
|
||
|
_tcscpy(szDisplayName, TEXT(""));
|
||
|
_tcsncat(szDisplayName, pNDN->pszDisplayName, MAX_PATH - 1);
|
||
|
}
|
||
|
|
||
|
// check if we need to add the tray icon
|
||
|
if (fRet && (iElements > 0) && (!g_fTrayPresent) && (!g_fDialogLaunched))
|
||
|
{
|
||
|
if (!FIsJoinedToDomain())
|
||
|
{
|
||
|
AddTrayIcon(g_hwnd, iElements, szDisplayName);
|
||
|
}
|
||
|
}
|
||
|
else if ((iElements == 0) && (g_fTrayPresent))
|
||
|
{
|
||
|
// no more devices...
|
||
|
RemoveTrayIcon(g_hwnd);
|
||
|
}
|
||
|
|
||
|
TraceHr(ttidShellTray, FAL, hr, FALSE, "HrUpdateTrayInfo");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrInitializeUI
|
||
|
//
|
||
|
// Purpose: Initialize the tray
|
||
|
//
|
||
|
// Arguments:
|
||
|
// (none)
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// Author: jeffspr 28 Jan 2000
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
HRESULT HrInitializeUI()
|
||
|
{
|
||
|
HRESULT hr = HrUpdateTrayInfo();
|
||
|
|
||
|
TraceHr(ttidShellTray, FAL, hr, FALSE, "HrInitializeUI");
|
||
|
return hr;
|
||
|
}
|