windows-nt/Source/XPSP1/NT/net/config/shell/folder/ac_ctrayui.cpp
2020-09-26 16:20:57 +08:00

497 lines
14 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 2000
//
// File: ac_CTrayUiCpp.h
//
// Contents: Home Networking Auto Config Tray Icon UI code
//
// Author: jeffsp 9/27/2000
//
//----------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
#include "ac_CTrayUi.h"
#include "foldinc.h" // Standard shell\tray includes
#include <nsres.h>
#include "foldres.h"
#include "traymsgs.h"
#include <dbt.h>
#include <ndisguid.h>
#include "lm.h"
UINT g_uWindowRefCount = 0;
HWND g_hwndHnAcTray = NULL;
UINT_PTR g_HnAcTimerHandle = NULL;
HDEVNOTIFY g_hDeviceChangeNotify = NULL;
CRITICAL_SECTION g_WindowCriticalSection;
const WCHAR c_szHnAcTrayClass[] = L"Home Net Auto Config Tray";
const DWORD c_dwAutoConfigBalloonTimeoutSeconds = 15;
static const WCHAR c_szRunDll32[] = L"rundll32.exe";
static const WCHAR c_szRunHomeNetworkWizard[] = L"hnetwiz.dll,HomeNetWizardRunDll";
DWORD WINAPI ac_AsyncDeviceChange(LPVOID lpParam);
HRESULT IsAdapterPhysical(GUID* pGuid, BOOL* bPhysical);
LRESULT
CALLBACK
CHnAcTrayUI_WndProc (
HWND hwnd, // window handle
UINT uiMessage, // type of message
WPARAM wParam, // additional information
LPARAM lParam) // additional information
{
switch (uiMessage)
{
case WM_CREATE:
return OnHnAcTrayWmCreate(hwnd);
case MYWM_NOTIFYICON:
return OnHnAcMyWMNotifyIcon(hwnd, uiMessage, wParam, lParam);
case WM_DESTROY:
g_hwndHnAcTray = NULL;
PostQuitMessage(0);
break;
default: // Passes it on if unproccessed
return (DefWindowProc (hwnd, uiMessage, wParam, lParam));
}
return (0);
}
HRESULT ac_CreateHnAcTrayUIWindow()
{
HRESULT hr = S_OK;
// create a hidden window
//
WNDCLASS wndclass;
ZeroMemory (&wndclass, sizeof(wndclass));
wndclass.lpfnWndProc = CHnAcTrayUI_WndProc;
wndclass.hInstance = _Module.GetResourceInstance();
wndclass.lpszClassName = c_szHnAcTrayClass;
RegisterClass (&wndclass);
EnterCriticalSection(&g_WindowCriticalSection); // we have to protect this since we are on a thread pool callback
if(0 == g_uWindowRefCount++)
{
CreateWindow(c_szHnAcTrayClass,
c_szHnAcTrayClass,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
_Module.GetResourceInstance(),
NULL);
}
LeaveCriticalSection(&g_WindowCriticalSection);
BOOL bGetMessage;
MSG Message;
while(bGetMessage = GetMessage(&Message, g_hwndHnAcTray, 0, 0) && -1 != bGetMessage)
{
DispatchMessage(&Message);
}
return hr;
}
LRESULT OnHnAcTrayWmCreate(HWND hwnd)
{
g_hwndHnAcTray = hwnd;
HICON hiconTray;
HRESULT hr = S_OK;
hiconTray = LoadIcon(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDI_CONFOLD_HOMENET_WIZARD));
if (hiconTray)
{
NOTIFYICONDATA nid;
ZeroMemory (&nid, sizeof(nid));
nid.cbSize = sizeof(NOTIFYICONDATA);
nid.hWnd = g_hwndHnAcTray;
nid.uID = 9998;
nid.uFlags = NIF_MESSAGE | NIF_ICON; // | NIF_STATE;
nid.uCallbackMessage = MYWM_NOTIFYICON;
nid.hIcon = hiconTray;
// nid.dwState = NIS_HIDDEN;
// nid.dwStateMask = nid.dwState;
// Configure the balloon tip
{
nid.uFlags |= NIF_INFO;
nid.dwInfoFlags = NIIF_INFO;
nid.uTimeout = c_dwAutoConfigBalloonTimeoutSeconds * 1000;
// WARNING these fields are 64 and 256 chars max
lstrcpyW(nid.szInfoTitle, SzLoadIds(IDS_AUTOCONFIGTRAY_RUN_HOME_NET_WIZARD_BALLOON_TITLE));
lstrcpyW(nid.szInfo, SzLoadIds(IDS_AUTOCONFIGTRAY_RUN_HOME_NET_WIZARD_BALLOON));
}
hr = HrShell_NotifyIcon(NIM_ADD, &nid);
nid.uVersion = NOTIFYICON_VERSION;
nid.uFlags = 0;
hr = HrShell_NotifyIcon(NIM_SETVERSION, &nid);
}
return 0;
}
LRESULT OnHnAcTrayWmNotify(
HWND hwnd,
WPARAM wParam,
LPARAM lParam )
{
return (DefWindowProc (hwnd, WM_NOTIFY, wParam, lParam));
}
LRESULT OnHnAcMyWMNotifyIcon(HWND hwnd, UINT uiMessage, WPARAM wParam, LPARAM lParam)
{
UINT uiIcon;
UINT uiMouseMsg;
uiIcon = (UINT) wParam;
uiMouseMsg = (UINT) lParam;
switch (uiMouseMsg)
{
case NIN_BALLOONTIMEOUT:
ac_DestroyHnAcTrayUIWindow();
break;
case NIN_BALLOONHIDE:
break;
case NIN_BALLOONSHOW:
break;
case NIN_BALLOONUSERCLICK:
HrRunHomeNetworkWizard(hwnd);
ac_DestroyHnAcTrayUIWindow();
break;
case NIN_KEYSELECT:
break;
case NIN_SELECT:
break;
}
return 0;
}
HRESULT HrRunHomeNetworkWizard(
HWND hwndOwner)
{
TraceFileFunc(ttidShellFolder);
HRESULT hr = S_OK;
WCHAR szPath[MAX_PATH];
hr = SHGetFolderPath(
hwndOwner,
CSIDL_SYSTEM,
NULL,
SHGFP_TYPE_CURRENT,
szPath);
if (SUCCEEDED(hr))
{
HINSTANCE hInst = ::ShellExecute(hwndOwner, NULL, c_szRunDll32, c_szRunHomeNetworkWizard, szPath, SW_SHOW );
if (hInst <= reinterpret_cast<HINSTANCE>(32))
{
hr = HRESULT_FROM_WIN32(static_cast<DWORD>(reinterpret_cast<DWORD_PTR>(hInst)));
}
}
TraceHr(ttidShellFolder, FAL, hr, FALSE, "HrRunHomeNetworkWizard");
return hr;
}
LRESULT ac_DestroyHnAcTrayUIWindow()
{
HRESULT hr = S_OK;
NOTIFYICONDATA nid;
ZeroMemory (&nid, sizeof(nid));
nid.cbSize = sizeof(NOTIFYICONDATA);
nid.hWnd = g_hwndHnAcTray;
nid.uID = 9998;
nid.uFlags = 0;
nid.uCallbackMessage = MYWM_NOTIFYICON;
nid.hIcon = 0;
hr = HrShell_NotifyIcon(NIM_DELETE, &nid);
#if 0
if (!SUCCEEDED(hr)){
MessageBox( NULL,
L"NotifyIcon DELETE failed",
L"This is a test...",
MB_OK | MB_ICONERROR);
}
#endif
EnterCriticalSection(&g_WindowCriticalSection);
if(0 == --g_uWindowRefCount)
{
DestroyWindow(g_hwndHnAcTray);
}
LeaveCriticalSection(&g_WindowCriticalSection);
return 0;
}
LRESULT ac_DeviceChange(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
{
// COM is initialized
if(NULL != g_hDeviceChangeNotify)
{
HRESULT hr;
if(DBT_DEVICEARRIVAL == wParam)
{
DEV_BROADCAST_DEVICEINTERFACE* pInfo = (DEV_BROADCAST_DEVICEINTERFACE*)lParam;
if (DBT_DEVTYP_DEVICEINTERFACE == pInfo->dbcc_devicetype)
{
LPWSTR pszNetDeviceGuid = wcsrchr(pInfo->dbcc_name, L'\\'); // need a better way to do this, but shouldn't crash
if(NULL != pszNetDeviceGuid)
{
GUID* pDeviceGuid = reinterpret_cast<GUID*>(CoTaskMemAlloc(sizeof(GUID)));
if(NULL != pDeviceGuid)
{
hr = CLSIDFromString(pszNetDeviceGuid + 1, pDeviceGuid); // +1 is safe, at worst it will point to L'\0'
if(SUCCEEDED(hr))
{
// we have to move this off-uithread
if(0 == QueueUserWorkItem(ac_AsyncDeviceChange, pDeviceGuid, WT_EXECUTELONGFUNCTION))
{
hr = E_FAIL;
}
}
if(FAILED(hr))
{
CoTaskMemFree(pDeviceGuid);
}
}
}
}
}
}
return TRUE;
}
HRESULT ac_Register(HWND hWindow)
{
HRESULT hr = S_OK;
#ifdef _WIN64
// The autoconfig service is not available on IA64 (since the homenet wizard
// isn't present)
hr = E_FAIL;
#else
//if the machine is a server SKU we don't create the autocfg stuff
OSVERSIONINFOEXW verInfo = {0};
ULONGLONG ConditionMask = 0;
verInfo.dwOSVersionInfoSize = sizeof(verInfo);
verInfo.wProductType = VER_NT_SERVER;
VER_SET_CONDITION(ConditionMask, VER_PRODUCT_TYPE, VER_GREATER_EQUAL);
if(TRUE == (VerifyVersionInfo(&verInfo, VER_PRODUCT_TYPE, ConditionMask)))
{
hr = E_FAIL;
}
#endif
if(SUCCEEDED(hr))
{
// if machine is joined to a domain don't create the autocfg stuff
LPWSTR pszNameBuffer;
NETSETUP_JOIN_STATUS BufferType;
if(NERR_Success == NetGetJoinInformation(NULL, &pszNameBuffer, &BufferType))
{
NetApiBufferFree(pszNameBuffer);
if(NetSetupDomainName == BufferType)
{
hr = E_FAIL;
}
}
else
{
hr = E_FAIL;
}
}
if(SUCCEEDED(hr))
{
DEV_BROADCAST_DEVICEINTERFACE PnpFilter; // device change notifications for homenet auto config service
ZeroMemory (&PnpFilter, sizeof(PnpFilter));
PnpFilter.dbcc_size = sizeof(PnpFilter);
PnpFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
PnpFilter.dbcc_classguid = GUID_NDIS_LAN_CLASS;
g_hDeviceChangeNotify = RegisterDeviceNotification( hWindow, &PnpFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
if(NULL != g_hDeviceChangeNotify)
{
InitializeCriticalSection(&g_WindowCriticalSection); // REVIEW: no memory exception
}
}
return hr;
}
HRESULT ac_Unregister(HWND hWindow)
{
if(NULL != g_hDeviceChangeNotify)
{
UnregisterDeviceNotification(g_hDeviceChangeNotify);
g_hDeviceChangeNotify = NULL;
DeleteCriticalSection(&g_WindowCriticalSection);
}
return S_OK;
}
DWORD WINAPI ac_AsyncDeviceChange(LPVOID lpParam)
{
HRESULT hr;
GUID* pDeviceGuid = reinterpret_cast<GUID*>(lpParam);
BOOL fUninitializeCOM = TRUE;
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
if (RPC_E_CHANGED_MODE == hr)
{
fUninitializeCOM = FALSE;
hr = S_OK;
}
if(SUCCEEDED(hr))
{
BOOL fPhysical;
hr = IsAdapterPhysical(pDeviceGuid, &fPhysical);
if(SUCCEEDED(hr) && TRUE == fPhysical)
{
IHNetCfgMgr* pHomenetConfigManager;
hr = HrCreateInstance(CLSID_HNetCfgMgr, CLSCTX_INPROC, &pHomenetConfigManager);
if(SUCCEEDED(hr))
{
IHNetConnection* pHomenetConnection;
hr = pHomenetConfigManager->GetIHNetConnectionForGuid(pDeviceGuid, TRUE, TRUE, &pHomenetConnection);
if(SUCCEEDED(hr))
{
BOOLEAN fShowBalloon;
hr = pHomenetConnection->ShowAutoconfigBalloon(&fShowBalloon);
if(SUCCEEDED(hr) && fShowBalloon)
{
ac_CreateHnAcTrayUIWindow();
}
ReleaseObj(pHomenetConnection);
}
ReleaseObj(pHomenetConfigManager);
}
}
if(TRUE == fUninitializeCOM)
{
CoUninitialize();
}
}
CoTaskMemFree(pDeviceGuid);
return hr;
}
HRESULT IsAdapterPhysical(GUID* pGuid, BOOL* bPhysical)
{
// com is initialized
HRESULT hr;
*bPhysical = FALSE;
INetCfg* pNetConfig;
hr = HrCreateInstance(CLSID_CNetCfg, CLSCTX_SERVER, &pNetConfig);
if(SUCCEEDED(hr))
{
INetCfgLock* pNetConfigLock;
hr = pNetConfig->QueryInterface(&pNetConfigLock);
if(SUCCEEDED(hr))
{
hr = pNetConfig->Initialize(NULL);
if(SUCCEEDED(hr))
{
GUID NetDevClass = GUID_DEVCLASS_NET;
IEnumNetCfgComponent* pNetConfigComponentEnum;
hr = pNetConfig->EnumComponents(&NetDevClass, &pNetConfigComponentEnum);
if (SUCCEEDED(hr))
{
INetCfgComponent* pNetConfigComponent;
BOOL fFound = FALSE;
ULONG ulFetched;
while (FALSE == fFound && S_OK == pNetConfigComponentEnum->Next(1, &pNetConfigComponent, &ulFetched))
{
Assert(1 == ulFetched);
GUID DeviceGuid;
hr = pNetConfigComponent->GetInstanceGuid( &DeviceGuid );
if (SUCCEEDED(hr) && (InlineIsEqualGUID(DeviceGuid,*pGuid)))
{
fFound = TRUE;
DWORD dwCharacteristics;
hr = pNetConfigComponent->GetCharacteristics(&dwCharacteristics);
if(SUCCEEDED(hr))
{
if(NCF_PHYSICAL & dwCharacteristics)
{
*bPhysical = TRUE;
}
}
}
ReleaseObj(pNetConfigComponent);
}
ReleaseObj(pNetConfigComponentEnum);
}
pNetConfig->Uninitialize();
}
ReleaseObj(pNetConfigLock);
}
ReleaseObj(pNetConfig);
}
return hr;
}