497 lines
14 KiB
C++
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;
|
|
|
|
} |