//+--------------------------------------------------------------------------- // // 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 #include "tfind.h" #include #include #include #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 * 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; }