reactos/dll/shellext/netshell/lanstatusui.cpp

1218 lines
36 KiB
C++

#include "precomp.h"
#include <winsock.h>
/// CLSID
/// HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{7007ACCF-3202-11D1-AAD2-00805FC1270E}
// IID B722BCCB-4E68-101B-A2BC-00AA00404770
#define WM_SHOWSTATUSDLG (WM_USER+10)
typedef struct tagNotificationItem
{
struct tagNotificationItem *pNext;
CLSID guidItem;
UINT uID;
HWND hwndDlg;
INetConnection *pNet;
} NOTIFICATION_ITEM;
typedef struct
{
INetConnection *pNet;
HWND hwndStatusDlg; /* LanStatusDlg window */
HWND hwndDlg; /* status dialog window */
DWORD dwAdapterIndex;
UINT_PTR nIDEvent;
UINT DHCPEnabled;
DWORD dwInOctets;
DWORD dwOutOctets;
DWORD IpAddress;
DWORD SubnetMask;
DWORD Gateway;
UINT uID;
UINT Status;
} LANSTATUSUI_CONTEXT;
class CLanStatus final :
public IOleCommandTarget
{
public:
CLanStatus();
// IUnknown
virtual HRESULT WINAPI QueryInterface(REFIID riid, LPVOID *ppvOut);
virtual ULONG WINAPI AddRef();
virtual ULONG WINAPI Release();
// IOleCommandTarget
virtual HRESULT WINAPI QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT *pCmdText);
virtual HRESULT WINAPI Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut);
private:
HRESULT InitializeNetTaskbarNotifications();
HRESULT ShowStatusDialogByCLSID(const GUID *pguidCmdGroup);
INetConnectionManager *m_lpNetMan;
LONG m_ref;
NOTIFICATION_ITEM *m_pHead;
};
CLanStatus::CLanStatus() :
m_lpNetMan(NULL),
m_ref(0),
m_pHead(NULL)
{
}
VOID
UpdateLanStatusUiDlg(
HWND hwndDlg,
MIB_IFROW *IfEntry,
LANSTATUSUI_CONTEXT *pContext)
{
WCHAR szFormat[MAX_PATH] = {0};
WCHAR szBuffer[MAX_PATH] = {0};
SYSTEMTIME TimeConnected;
DWORD DurationSeconds;
WCHAR Buffer[100];
WCHAR DayBuffer[30];
WCHAR LocBuffer[50];
#if 0
ULONGLONG Ticks;
#else
DWORD Ticks;
#endif
if (IfEntry->dwSpeed < 1000)
{
if (LoadStringW(netshell_hInstance, IDS_FORMAT_BIT, szFormat, sizeof(szFormat)/sizeof(WCHAR)))
{
swprintf(szBuffer, szFormat, IfEntry->dwSpeed);
SendDlgItemMessageW(hwndDlg, IDC_SPEED, WM_SETTEXT, 0, (LPARAM)szBuffer);
}
}
else if (IfEntry->dwSpeed < 1000000)
{
if (LoadStringW(netshell_hInstance, IDS_FORMAT_KBIT, szFormat, sizeof(szFormat)/sizeof(WCHAR)))
{
swprintf(szBuffer, szFormat, IfEntry->dwSpeed/1000);
SendDlgItemMessageW(hwndDlg, IDC_SPEED, WM_SETTEXT, 0, (LPARAM)szBuffer);
}
}
else if (IfEntry->dwSpeed < 1000000000)
{
if (LoadStringW(netshell_hInstance, IDS_FORMAT_MBIT, szFormat, sizeof(szFormat)/sizeof(WCHAR)))
{
swprintf(szBuffer, szFormat, IfEntry->dwSpeed/1000000);
SendDlgItemMessageW(hwndDlg, IDC_SPEED, WM_SETTEXT, 0, (LPARAM)szBuffer);
}
}
else
{
if (LoadStringW(netshell_hInstance, IDS_FORMAT_GBIT, szFormat, sizeof(szFormat)/sizeof(WCHAR)))
{
swprintf(szBuffer, szFormat, IfEntry->dwSpeed/1000000000);
SendDlgItemMessageW(hwndDlg, IDC_SPEED, WM_SETTEXT, 0, (LPARAM)szBuffer);
}
}
if (StrFormatByteSizeW(IfEntry->dwInOctets, szBuffer, sizeof(szFormat)/sizeof(WCHAR)))
{
SendDlgItemMessageW(hwndDlg, IDC_RECEIVED, WM_SETTEXT, 0, (LPARAM)szBuffer);
}
if (StrFormatByteSizeW(IfEntry->dwOutOctets, szBuffer, sizeof(szFormat)/sizeof(WCHAR)))
{
SendDlgItemMessageW(hwndDlg, IDC_SEND, WM_SETTEXT, 0, (LPARAM)szBuffer);
}
#if 0
Ticks = GetTickCount64();
#else
Ticks = GetTickCount();
#endif
DurationSeconds = Ticks / 1000;
TimeConnected.wSecond = (DurationSeconds % 60);
TimeConnected.wMinute = (DurationSeconds / 60) % 60;
TimeConnected.wHour = (DurationSeconds / (60 * 60)) % 24;
TimeConnected.wDay = DurationSeconds / (60 * 60 * 24);
if (!GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &TimeConnected, L"HH':'mm':'ss", LocBuffer, sizeof(LocBuffer) / sizeof(LocBuffer[0])))
return;
if (!TimeConnected.wDay)
{
SendDlgItemMessageW(hwndDlg, IDC_DURATION, WM_SETTEXT, 0, (LPARAM)LocBuffer);
}
else
{
if (TimeConnected.wDay == 1)
{
if (!LoadStringW(netshell_hInstance, IDS_DURATION_DAY, DayBuffer, sizeof(DayBuffer) / sizeof(DayBuffer[0])))
DayBuffer[0] = L'\0';
}
else
{
if (!LoadStringW(netshell_hInstance, IDS_DURATION_DAYS, DayBuffer, sizeof(DayBuffer) / sizeof(DayBuffer[0])))
DayBuffer[0] = L'\0';
}
swprintf(Buffer, DayBuffer, TimeConnected.wDay, LocBuffer);
SendDlgItemMessageW(hwndDlg, IDC_DURATION, WM_SETTEXT, 0, (LPARAM)Buffer);
}
}
VOID
UpdateLanStatus(HWND hwndDlg, LANSTATUSUI_CONTEXT * pContext)
{
MIB_IFROW IfEntry;
HICON hIcon, hOldIcon = NULL;
NOTIFYICONDATAW nid;
NETCON_PROPERTIES * pProperties = NULL;
ZeroMemory(&IfEntry, sizeof(IfEntry));
IfEntry.dwIndex = pContext->dwAdapterIndex;
if (GetIfEntry(&IfEntry) != NO_ERROR)
{
return;
}
hIcon = NULL;
if (IfEntry.dwOperStatus == MIB_IF_OPER_STATUS_CONNECTED || IfEntry.dwOperStatus == MIB_IF_OPER_STATUS_OPERATIONAL)
{
if (pContext->dwInOctets == IfEntry.dwInOctets && pContext->dwOutOctets == IfEntry.dwOutOctets && pContext->Status != 0)
{
hIcon = (HICON)LoadImage(netshell_hInstance, MAKEINTRESOURCE(IDI_NET_IDLE), IMAGE_ICON, 32, 32, LR_SHARED);
pContext->Status = 0;
}
else if (pContext->dwInOctets != IfEntry.dwInOctets && pContext->dwOutOctets != IfEntry.dwOutOctets && pContext->Status != 1)
{
hIcon = (HICON)LoadImage(netshell_hInstance, MAKEINTRESOURCE(IDI_NET_TRANSREC), IMAGE_ICON, 32, 32, LR_SHARED);
pContext->Status = 1;
}
else if (pContext->dwInOctets != IfEntry.dwInOctets && pContext->Status != 2)
{
hIcon = (HICON)LoadImage(netshell_hInstance, MAKEINTRESOURCE(IDI_NET_REC), IMAGE_ICON, 32, 32, LR_SHARED);
pContext->Status = 2;
}
else if (pContext->dwOutOctets != IfEntry.dwOutOctets && pContext->Status != 3)
{
hIcon = (HICON)LoadImage(netshell_hInstance, MAKEINTRESOURCE(IDI_NET_TRANS), IMAGE_ICON, 32, 32, LR_SHARED);
pContext->Status = 3;
}
}
else if (IfEntry.dwOperStatus == MIB_IF_OPER_STATUS_UNREACHABLE || IfEntry.dwOperStatus == MIB_IF_OPER_STATUS_DISCONNECTED)
{
if (pContext->Status != 4)
{
hIcon = (HICON)LoadImage(netshell_hInstance, MAKEINTRESOURCE(IDI_NET_OFF), IMAGE_ICON, 32, 32, LR_SHARED);
pContext->Status = 4;
}
}
else if (IfEntry.dwOperStatus == MIB_IF_OPER_STATUS_NON_OPERATIONAL)
{
if (pContext->Status != 5)
{
hIcon = (HICON)LoadImage(netshell_hInstance, MAKEINTRESOURCE(IDI_NET_OFF), IMAGE_ICON, 32, 32, LR_SHARED);
pContext->Status = 5;
}
}
if (hwndDlg && hIcon)
{
hOldIcon = (HICON)SendDlgItemMessageW(hwndDlg, IDC_NETSTAT, STM_SETICON, (WPARAM)hIcon, 0);
if (hOldIcon)
DestroyIcon(hOldIcon);
}
ZeroMemory(&nid, sizeof(nid));
nid.cbSize = sizeof(nid);
nid.uID = pContext->uID;
nid.hWnd = pContext->hwndStatusDlg;
nid.uVersion = 3;
if (pContext->pNet->GetProperties(&pProperties) == S_OK)
{
if (pProperties->dwCharacter & NCCF_SHOW_ICON)
{
if (hwndDlg)
nid.hIcon = (HICON)CopyImage(hIcon, IMAGE_ICON, 16, 16, LR_COPYFROMRESOURCE);
else
nid.hIcon = hIcon;
if (nid.hIcon)
nid.uFlags |= NIF_ICON;
nid.uFlags |= NIF_STATE;
nid.dwState = 0;
nid.dwStateMask = NIS_HIDDEN;
if (pProperties->pszwName)
{
if (wcslen(pProperties->pszwName) * sizeof(WCHAR) < sizeof(nid.szTip))
{
nid.uFlags |= NIF_TIP;
wcscpy(nid.szTip, pProperties->pszwName);
}
else
{
CopyMemory(nid.szTip, pProperties->pszwName, sizeof(nid.szTip) - sizeof(WCHAR));
nid.szTip[(sizeof(nid.szTip)/sizeof(WCHAR))-1] = L'\0';
nid.uFlags |= NIF_TIP;
}
}
}
else
{
nid.uFlags |= NIF_STATE;
nid.dwState = NIS_HIDDEN;
nid.dwStateMask = NIS_HIDDEN;
}
NcFreeNetconProperties(pProperties);
}
Shell_NotifyIconW(NIM_MODIFY, &nid);
if (nid.uFlags & NIF_ICON)
DestroyIcon(nid.hIcon);
pContext->dwInOctets = IfEntry.dwInOctets;
pContext->dwOutOctets = IfEntry.dwOutOctets;
if (hwndDlg)
UpdateLanStatusUiDlg(hwndDlg, &IfEntry, pContext);
}
VOID
InitializeLANStatusUiDlg(HWND hwndDlg, LANSTATUSUI_CONTEXT * pContext)
{
WCHAR szBuffer[MAX_PATH] = {0};
NETCON_PROPERTIES * pProperties;
if (pContext->pNet->GetProperties(&pProperties) != S_OK)
return;
if (pProperties->Status == NCS_DISCONNECTED)
LoadStringW(netshell_hInstance, IDS_STATUS_UNREACHABLE, szBuffer, MAX_PATH);
else if (pProperties->Status == NCS_MEDIA_DISCONNECTED)
LoadStringW(netshell_hInstance, IDS_STATUS_DISCONNECTED, szBuffer, MAX_PATH);
else if (pProperties->Status == NCS_CONNECTING)
LoadStringW(netshell_hInstance, IDS_STATUS_CONNECTING, szBuffer, MAX_PATH);
else if (pProperties->Status == NCS_CONNECTED)
LoadStringW(netshell_hInstance, IDS_STATUS_CONNECTED, szBuffer, MAX_PATH);
SendDlgItemMessageW(hwndDlg, IDC_STATUS, WM_SETTEXT, 0, (LPARAM)szBuffer);
pContext->dwInOctets = 0;
pContext->dwOutOctets = 0;
/* update adapter info */
pContext->Status = -1;
UpdateLanStatus(hwndDlg, pContext);
NcFreeNetconProperties(pProperties);
}
static
VOID
InsertColumnToListView(
HWND hDlgCtrl,
UINT ResId,
UINT SubItem,
UINT Size)
{
WCHAR szBuffer[200];
LVCOLUMNW lc;
if (!LoadStringW(netshell_hInstance, ResId, szBuffer, sizeof(szBuffer)/sizeof(WCHAR)))
return;
memset(&lc, 0, sizeof(LV_COLUMN) );
lc.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_FMT;
lc.iSubItem = SubItem;
lc.fmt = LVCFMT_FIXED_WIDTH;
lc.cx = Size;
lc.cchTextMax = wcslen(szBuffer);
lc.pszText = szBuffer;
(void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, SubItem, (LPARAM)&lc);
}
static
VOID
AddIPAddressToListView(
HWND hDlgCtrl,
PIP_ADDR_STRING pAddr,
INT Index)
{
LVITEMW li;
PIP_ADDR_STRING pCur;
WCHAR szBuffer[100];
UINT SubIndex;
ZeroMemory(&li, sizeof(LVITEMW));
li.mask = LVIF_TEXT;
li.iItem = Index;
pCur = pAddr;
SubIndex = 0;
do
{
if (SubIndex)
{
ZeroMemory(&li, sizeof(LVITEMW));
li.mask = LVIF_TEXT;
li.iItem = Index;
li.iSubItem = 0;
li.pszText = (LPWSTR)L"";
li.iItem = SendMessageW(hDlgCtrl, LVM_INSERTITEMW, 0, (LPARAM)&li);
}
if (MultiByteToWideChar(CP_ACP, 0, pCur->IpAddress.String, -1, szBuffer, sizeof(szBuffer)/sizeof(WCHAR)))
{
li.pszText = szBuffer;
li.iSubItem = 1;
li.iItem = Index++;
SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
}
SubIndex++;
pCur = pCur->Next;
} while (pCur && pCur->IpAddress.String[0]);
}
static
INT
InsertItemToListView(
HWND hDlgCtrl,
UINT ResId)
{
LVITEMW li;
WCHAR szBuffer[100];
ZeroMemory(&li, sizeof(LVITEMW));
li.mask = LVIF_TEXT;
li.iItem = ListView_GetItemCount(hDlgCtrl);
if (LoadStringW(netshell_hInstance, ResId, szBuffer, sizeof(szBuffer)/sizeof(WCHAR)))
{
li.pszText = szBuffer;
return (INT)SendMessageW(hDlgCtrl, LVM_INSERTITEMW, 0, (LPARAM)&li);
}
return -1;
}
INT_PTR
CALLBACK
LANStatusUiDetailsDlg(
HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
LANSTATUSUI_CONTEXT * pContext;
LVITEMW li;
WCHAR szBuffer[100];
PIP_ADAPTER_INFO pAdapterInfo, pCurAdapter;
PIP_PER_ADAPTER_INFO pPerAdapter;
DWORD dwSize;
HWND hDlgCtrl;
RECT rect;
switch (uMsg)
{
case WM_INITDIALOG:
pContext = (LANSTATUSUI_CONTEXT*)lParam;
hDlgCtrl = GetDlgItem(hwndDlg, IDC_DETAILS);
/* get client rect */
GetClientRect(hDlgCtrl, &rect);
/* calculate column width */
dwSize = rect.right / 2;
InsertColumnToListView(hDlgCtrl, IDS_PROPERTY, 0, dwSize);
InsertColumnToListView(hDlgCtrl, IDS_VALUE, 1, dwSize);
dwSize = 0;
pCurAdapter = NULL;
pAdapterInfo = NULL;
if (GetAdaptersInfo(NULL, &dwSize) == ERROR_BUFFER_OVERFLOW)
{
pAdapterInfo = static_cast<PIP_ADAPTER_INFO>(CoTaskMemAlloc(dwSize));
if (pAdapterInfo)
{
if (GetAdaptersInfo(pAdapterInfo, &dwSize) == NO_ERROR)
{
pCurAdapter = pAdapterInfo;
while (pCurAdapter && pCurAdapter->Index != pContext->dwAdapterIndex)
pCurAdapter = pCurAdapter->Next;
if (pCurAdapter->Index != pContext->dwAdapterIndex)
pCurAdapter = NULL;
}
}
}
ZeroMemory(&li, sizeof(LVITEMW));
li.mask = LVIF_TEXT;
li.iSubItem = 1;
li.pszText = szBuffer;
if (pCurAdapter)
{
li.iItem = InsertItemToListView(hDlgCtrl, IDS_PHYSICAL_ADDRESS);
if (li.iItem >= 0)
{
swprintf(szBuffer, L"%02x-%02x-%02x-%02x-%02x-%02x",pCurAdapter->Address[0], pCurAdapter->Address[1],
pCurAdapter->Address[2], pCurAdapter->Address[3], pCurAdapter->Address[4], pCurAdapter->Address[5]);
SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
}
li.iItem = InsertItemToListView(hDlgCtrl, IDS_IP_ADDRESS);
if (li.iItem >= 0)
if (MultiByteToWideChar(CP_ACP, 0, pCurAdapter->IpAddressList.IpAddress.String, -1, szBuffer, sizeof(szBuffer)/sizeof(WCHAR)))
SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
li.iItem = InsertItemToListView(hDlgCtrl, IDS_SUBNET_MASK);
if (li.iItem >= 0)
if (MultiByteToWideChar(CP_ACP, 0, pCurAdapter->IpAddressList.IpMask.String, -1, szBuffer, sizeof(szBuffer)/sizeof(WCHAR)))
SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
li.iItem = InsertItemToListView(hDlgCtrl, IDS_DEF_GATEWAY);
if (li.iItem >= 0 && pCurAdapter->GatewayList.IpAddress.String[0] != '0')
{
if (MultiByteToWideChar(CP_ACP, 0, pCurAdapter->GatewayList.IpAddress.String, -1, szBuffer, sizeof(szBuffer)/sizeof(WCHAR)))
SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
}
#if 0
li.iItem = InsertItemToListView(hDlgCtrl, IDS_LEASE_OBTAINED);
li.iItem = InsertItemToListView(hDlgCtrl, IDS_LEASE_EXPIRES);
#endif
}
dwSize = 0;
if (GetPerAdapterInfo(pContext->dwAdapterIndex, NULL, &dwSize) == ERROR_BUFFER_OVERFLOW)
{
pPerAdapter = static_cast<PIP_PER_ADAPTER_INFO>(CoTaskMemAlloc(dwSize));
if (pPerAdapter)
{
if (GetPerAdapterInfo(pContext->dwAdapterIndex, pPerAdapter, &dwSize) == ERROR_SUCCESS)
{
li.iItem = InsertItemToListView(hDlgCtrl, IDS_DNS_SERVERS);
if (li.iItem >= 0)
AddIPAddressToListView(hDlgCtrl, &pPerAdapter->DnsServerList, li.iItem);
}
CoTaskMemFree(pPerAdapter);
}
}
#if 0
if (pCurAdapter)
{
li.iItem = InsertItemToListView(hDlgCtrl, IDS_WINS_SERVERS);
AddIPAddressToListView(hDlgCtrl, &pCurAdapter->PrimaryWinsServer, li.iItem);
AddIPAddressToListView(hDlgCtrl, &pCurAdapter->SecondaryWinsServer, li.iItem+1);
}
#endif
CoTaskMemFree(pAdapterInfo);
break;
case WM_COMMAND:
if (LOWORD(wParam) == IDC_CLOSE)
{
EndDialog(hwndDlg, FALSE);
break;
}
}
return FALSE;
}
INT_PTR
CALLBACK
LANStatusUiAdvancedDlg(
HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
WCHAR szBuffer[100] = {0};
PROPSHEETPAGE *page;
LANSTATUSUI_CONTEXT * pContext;
DWORD dwIpAddr;
switch (uMsg)
{
case WM_INITDIALOG:
page = (PROPSHEETPAGE*)lParam;
pContext = (LANSTATUSUI_CONTEXT*)page->lParam;
SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pContext);
if (pContext->DHCPEnabled)
LoadStringW(netshell_hInstance, IDS_ASSIGNED_DHCP, szBuffer, sizeof(szBuffer)/sizeof(WCHAR));
else
LoadStringW(netshell_hInstance, IDS_ASSIGNED_MANUAL, szBuffer, sizeof(szBuffer)/sizeof(WCHAR));
szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
SendDlgItemMessageW(hwndDlg, IDC_DETAILSTYPE, WM_SETTEXT, 0, (LPARAM)szBuffer);
dwIpAddr = ntohl(pContext->IpAddress);
swprintf(szBuffer, L"%u.%u.%u.%u", FIRST_IPADDRESS(dwIpAddr), SECOND_IPADDRESS(dwIpAddr),
THIRD_IPADDRESS(dwIpAddr), FOURTH_IPADDRESS(dwIpAddr));
SendDlgItemMessageW(hwndDlg, IDC_DETAILSIP, WM_SETTEXT, 0, (LPARAM)szBuffer);
dwIpAddr = ntohl(pContext->SubnetMask);
swprintf(szBuffer, L"%u.%u.%u.%u", FIRST_IPADDRESS(dwIpAddr), SECOND_IPADDRESS(dwIpAddr),
THIRD_IPADDRESS(dwIpAddr), FOURTH_IPADDRESS(dwIpAddr));
SendDlgItemMessageW(hwndDlg, IDC_DETAILSSUBNET, WM_SETTEXT, 0, (LPARAM)szBuffer);
dwIpAddr = ntohl(pContext->Gateway);
if (dwIpAddr)
{
swprintf(szBuffer, L"%u.%u.%u.%u", FIRST_IPADDRESS(dwIpAddr), SECOND_IPADDRESS(dwIpAddr),
THIRD_IPADDRESS(dwIpAddr), FOURTH_IPADDRESS(dwIpAddr));
SendDlgItemMessageW(hwndDlg, IDC_DETAILSGATEWAY, WM_SETTEXT, 0, (LPARAM)szBuffer);
}
return TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDC_DETAILS)
{
pContext = (LANSTATUSUI_CONTEXT*)GetWindowLongPtr(hwndDlg, DWLP_USER);
if (pContext)
{
DialogBoxParamW(netshell_hInstance, MAKEINTRESOURCEW(IDD_LAN_NETSTATUSDETAILS), GetParent(hwndDlg),
LANStatusUiDetailsDlg, (LPARAM)pContext);
}
}
break;
default:
break;
}
return FALSE;
}
BOOL
FindNetworkAdapter(HDEVINFO hInfo, SP_DEVINFO_DATA *pDevInfo, LPWSTR pGuid)
{
DWORD dwIndex, dwSize;
HKEY hSubKey;
WCHAR szNetCfg[50];
WCHAR szDetail[200] = L"SYSTEM\\CurrentControlSet\\Control\\Class\\";
dwIndex = 0;
do
{
ZeroMemory(pDevInfo, sizeof(SP_DEVINFO_DATA));
pDevInfo->cbSize = sizeof(SP_DEVINFO_DATA);
/* get device info */
if (!SetupDiEnumDeviceInfo(hInfo, dwIndex++, pDevInfo))
break;
/* get device software registry path */
if (!SetupDiGetDeviceRegistryPropertyW(hInfo, pDevInfo, SPDRP_DRIVER, NULL, (LPBYTE)&szDetail[39], sizeof(szDetail)/sizeof(WCHAR) - 40, &dwSize))
break;
/* open device registry key */
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szDetail, 0, KEY_READ, &hSubKey) != ERROR_SUCCESS)
break;
/* query NetCfgInstanceId for current device */
dwSize = sizeof(szNetCfg);
if (RegQueryValueExW(hSubKey, L"NetCfgInstanceId", NULL, NULL, (LPBYTE)szNetCfg, &dwSize) != ERROR_SUCCESS)
{
RegCloseKey(hSubKey);
break;
}
RegCloseKey(hSubKey);
if (!_wcsicmp(pGuid, szNetCfg))
{
return TRUE;
}
} while (TRUE);
return FALSE;
}
VOID
DisableNetworkAdapter(INetConnection * pNet, LANSTATUSUI_CONTEXT * pContext, HWND hwndDlg)
{
HKEY hKey;
NETCON_PROPERTIES * pProperties;
LPOLESTR pDisplayName;
WCHAR szPath[200];
DWORD dwSize, dwType;
LPWSTR pPnp;
HDEVINFO hInfo;
SP_DEVINFO_DATA DevInfo;
SP_PROPCHANGE_PARAMS PropChangeParams;
BOOL bClose = FALSE;
NOTIFYICONDATAW nid;
if (FAILED(pNet->GetProperties(&pProperties)))
return;
hInfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT );
if (!hInfo)
{
NcFreeNetconProperties(pProperties);
return;
}
if (FAILED(StringFromCLSID((CLSID)pProperties->guidId, &pDisplayName)))
{
NcFreeNetconProperties(pProperties);
SetupDiDestroyDeviceInfoList(hInfo);
return;
}
NcFreeNetconProperties(pProperties);
if (FindNetworkAdapter(hInfo, &DevInfo, pDisplayName))
{
PropChangeParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
PropChangeParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE; //;
PropChangeParams.StateChange = DICS_DISABLE;
PropChangeParams.Scope = DICS_FLAG_CONFIGSPECIFIC;
PropChangeParams.HwProfile = 0;
if (SetupDiSetClassInstallParams(hInfo, &DevInfo, &PropChangeParams.ClassInstallHeader, sizeof(SP_PROPCHANGE_PARAMS)))
{
if (SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, hInfo, &DevInfo))
bClose = TRUE;
}
}
SetupDiDestroyDeviceInfoList(hInfo);
swprintf(szPath, L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s\\Connection", pDisplayName);
CoTaskMemFree(pDisplayName);
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szPath, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
return;
dwSize = 0;
if (RegQueryValueExW(hKey, L"PnpInstanceID", NULL, &dwType, NULL, &dwSize) != ERROR_SUCCESS || dwType != REG_SZ)
{
RegCloseKey(hKey);
return;
}
pPnp = static_cast<PWSTR>(CoTaskMemAlloc(dwSize));
if (!pPnp)
{
RegCloseKey(hKey);
return;
}
if (RegQueryValueExW(hKey, L"PnpInstanceID", NULL, &dwType, (LPBYTE)pPnp, &dwSize) != ERROR_SUCCESS)
{
CoTaskMemFree(pPnp);
RegCloseKey(hKey);
return;
}
RegCloseKey(hKey);
swprintf(szPath, L"System\\CurrentControlSet\\Hardware Profiles\\Current\\System\\CurrentControlSet\\Enum\\%s", pPnp);
CoTaskMemFree(pPnp);
if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, szPath, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL) != ERROR_SUCCESS)
return;
dwSize = 1; /* enable = 0, disable = 1 */
RegSetValueExW(hKey, L"CSConfigFlags", 0, REG_DWORD, (LPBYTE)&dwSize, sizeof(DWORD));
RegCloseKey(hKey);
if (!bClose)
return;
PropSheet_PressButton(GetParent(hwndDlg), PSBTN_CANCEL);
ZeroMemory(&nid, sizeof(nid));
nid.cbSize = sizeof(nid);
nid.uID = pContext->uID;
nid.hWnd = pContext->hwndDlg;
nid.uFlags = NIF_STATE;
nid.dwState = NIS_HIDDEN;
nid.dwStateMask = NIS_HIDDEN;
Shell_NotifyIconW(NIM_MODIFY, &nid);
}
INT_PTR
CALLBACK
LANStatusUiDlg(
HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
PROPSHEETPAGE *page;
LANSTATUSUI_CONTEXT * pContext;
LPPSHNOTIFY lppsn;
switch (uMsg)
{
case WM_INITDIALOG:
page = (PROPSHEETPAGE*)lParam;
pContext = (LANSTATUSUI_CONTEXT*)page->lParam;
pContext->hwndDlg = hwndDlg;
InitializeLANStatusUiDlg(hwndDlg, pContext);
SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pContext);
return TRUE;
case WM_COMMAND:
pContext = (LANSTATUSUI_CONTEXT*)GetWindowLongPtr(hwndDlg, DWLP_USER);
if (LOWORD(wParam) == IDC_STATUS_PROPERTIES)
{
if (pContext)
{
ShowNetConnectionProperties(pContext->pNet, GetParent(pContext->hwndDlg));
BringWindowToTop(GetParent(pContext->hwndDlg));
}
break;
}
else if (LOWORD(wParam) == IDC_ENDISABLE)
{
DisableNetworkAdapter(pContext->pNet, pContext, hwndDlg);
break;
}
case WM_NOTIFY:
lppsn = (LPPSHNOTIFY) lParam;
if (lppsn->hdr.code == PSN_APPLY || lppsn->hdr.code == PSN_RESET)
{
pContext = (LANSTATUSUI_CONTEXT*)GetWindowLongPtr(hwndDlg, DWLP_USER);
SetWindowLongPtr(hwndDlg, DWL_MSGRESULT, PSNRET_NOERROR);
pContext->hwndDlg = NULL;
return TRUE;
}
break;
}
return FALSE;
}
VOID
InitializePropertyDialog(
LANSTATUSUI_CONTEXT * pContext,
NETCON_PROPERTIES * pProperties)
{
DWORD dwSize, dwAdapterIndex, dwResult;
LPOLESTR pStr;
IP_ADAPTER_INFO *pAdapterInfo, *pCurAdapter;
if (FAILED(StringFromCLSID((CLSID)pProperties->guidId, &pStr)))
{
return;
}
/* get the IfTable */
dwSize = 0;
dwResult = GetAdaptersInfo(NULL, &dwSize);
if (dwResult!= ERROR_BUFFER_OVERFLOW)
{
CoTaskMemFree(pStr);
return;
}
pAdapterInfo = static_cast<PIP_ADAPTER_INFO>(CoTaskMemAlloc(dwSize));
if (!pAdapterInfo)
{
CoTaskMemFree(pAdapterInfo);
CoTaskMemFree(pStr);
return;
}
if (GetAdaptersInfo(pAdapterInfo, &dwSize) != NO_ERROR)
{
CoTaskMemFree(pAdapterInfo);
CoTaskMemFree(pStr);
return;
}
if (!GetAdapterIndexFromNetCfgInstanceId(pAdapterInfo, pStr, &dwAdapterIndex))
{
CoTaskMemFree(pAdapterInfo);
CoTaskMemFree(pStr);
return;
}
pCurAdapter = pAdapterInfo;
while (pCurAdapter->Index != dwAdapterIndex)
pCurAdapter = pCurAdapter->Next;
pContext->IpAddress = inet_addr(pCurAdapter->IpAddressList.IpAddress.String);
pContext->SubnetMask = inet_addr(pCurAdapter->IpAddressList.IpMask.String);
pContext->Gateway = inet_addr(pCurAdapter->GatewayList.IpAddress.String);
pContext->DHCPEnabled = pCurAdapter->DhcpEnabled;
CoTaskMemFree(pStr);
CoTaskMemFree(pAdapterInfo);
pContext->dwAdapterIndex = dwAdapterIndex;
}
VOID
ShowStatusPropertyDialog(
LANSTATUSUI_CONTEXT *pContext,
HWND hwndDlg)
{
HPROPSHEETPAGE hppages[2];
PROPSHEETHEADERW pinfo;
NETCON_PROPERTIES * pProperties = NULL;
ZeroMemory(&pinfo, sizeof(PROPSHEETHEADERW));
ZeroMemory(hppages, sizeof(hppages));
pinfo.dwSize = sizeof(PROPSHEETHEADERW);
pinfo.dwFlags = PSH_NOCONTEXTHELP | PSH_PROPTITLE | PSH_NOAPPLYNOW;
pinfo.phpage = hppages;
pinfo.hwndParent = hwndDlg;
if (pContext->pNet->GetProperties(&pProperties) == S_OK)
{
if (pProperties->pszwName)
{
pinfo.pszCaption = pProperties->pszwName;
pinfo.dwFlags |= PSH_PROPTITLE;
}
InitializePropertyDialog(pContext, pProperties);
if (pProperties->MediaType == NCM_LAN && pProperties->Status == NCS_CONNECTED)
{
hppages[0] = InitializePropertySheetPage(MAKEINTRESOURCEW(IDD_LAN_NETSTATUS), LANStatusUiDlg, (LPARAM)pContext, NULL);
if (hppages[0])
pinfo.nPages++;
hppages[pinfo.nPages] = InitializePropertySheetPage(MAKEINTRESOURCEW(IDD_LAN_NETSTATUSADVANCED), LANStatusUiAdvancedDlg, (LPARAM)pContext, NULL);
if (hppages[pinfo.nPages])
pinfo.nPages++;
if (pinfo.nPages)
{
PropertySheetW(&pinfo);
}
}
else if (pProperties->Status == NCS_MEDIA_DISCONNECTED || pProperties->Status == NCS_DISCONNECTED ||
pProperties->Status == NCS_HARDWARE_DISABLED)
{
ShowNetConnectionProperties(pContext->pNet, pContext->hwndDlg);
}
NcFreeNetconProperties(pProperties);
}
}
INT_PTR
CALLBACK
LANStatusDlg(
HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
LANSTATUSUI_CONTEXT * pContext;
switch (uMsg)
{
case WM_INITDIALOG:
pContext = (LANSTATUSUI_CONTEXT *)lParam;
SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)lParam);
pContext->nIDEvent = SetTimer(hwndDlg, 0xFABC, 1000, NULL);
return TRUE;
case WM_TIMER:
pContext = (LANSTATUSUI_CONTEXT*)GetWindowLongPtr(hwndDlg, DWLP_USER);
if (wParam == (WPARAM)pContext->nIDEvent)
{
UpdateLanStatus(pContext->hwndDlg, pContext);
}
break;
case WM_SHOWSTATUSDLG:
if (LOWORD(lParam) == WM_LBUTTONDOWN)
{
pContext = (LANSTATUSUI_CONTEXT*)GetWindowLongPtr(hwndDlg, DWLP_USER);
if (!pContext)
break;
if (pContext->hwndDlg)
{
ShowWindow(GetParent(pContext->hwndDlg), SW_SHOW);
BringWindowToTop(GetParent(pContext->hwndDlg));
}
else
{
ShowStatusPropertyDialog(pContext, hwndDlg);
}
break;
}
break;
}
return FALSE;
}
HRESULT
CLanStatus::InitializeNetTaskbarNotifications()
{
NOTIFYICONDATAW nid;
HWND hwndDlg;
INetConnectionManager *pNetConMan;
IEnumNetConnection *pEnumCon;
INetConnection *pNetCon;
NETCON_PROPERTIES* pProps;
HRESULT hr;
ULONG Count;
ULONG Index;
NOTIFICATION_ITEM * pItem, *pLast = NULL;
LANSTATUSUI_CONTEXT * pContext;
TRACE("InitializeNetTaskbarNotifications\n");
if (m_pHead)
{
pItem = m_pHead;
while (pItem)
{
hr = pItem->pNet->GetProperties(&pProps);
if (SUCCEEDED(hr))
{
ZeroMemory(&nid, sizeof(nid));
nid.cbSize = sizeof(nid);
nid.uID = pItem->uID;
nid.hWnd = pItem->hwndDlg;
nid.uFlags = NIF_STATE;
if (pProps->dwCharacter & NCCF_SHOW_ICON)
nid.dwState = 0;
else
nid.dwState = NIS_HIDDEN;
nid.dwStateMask = NIS_HIDDEN;
Shell_NotifyIconW(NIM_MODIFY, &nid);
NcFreeNetconProperties(pProps);
}
pItem = pItem->pNext;
}
return S_OK;
}
/* get an instance to of IConnectionManager */
//hr = CoCreateInstance(&CLSID_ConnectionManager, NULL, CLSCTX_INPROC_SERVER, &IID_INetConnectionManager, (LPVOID*)&pNetConMan);
hr = INetConnectionManager_Constructor(NULL, IID_INetConnectionManager, (LPVOID*)&pNetConMan);
if (FAILED(hr))
{
ERR("INetConnectionManager_Constructor failed\n");
return hr;
}
hr = pNetConMan->EnumConnections(NCME_DEFAULT, &pEnumCon);
if (FAILED(hr))
{
ERR("EnumConnections failed\n");
pNetConMan->Release();
return hr;
}
Index = 1;
do
{
hr = pEnumCon->Next(1, &pNetCon, &Count);
if (hr == S_OK)
{
TRACE("new connection\n");
pItem = static_cast<NOTIFICATION_ITEM*>(CoTaskMemAlloc(sizeof(NOTIFICATION_ITEM)));
if (!pItem)
break;
pContext = static_cast<LANSTATUSUI_CONTEXT*>(CoTaskMemAlloc(sizeof(LANSTATUSUI_CONTEXT)));
if (!pContext)
{
CoTaskMemFree(pItem);
break;
}
ZeroMemory(pContext, sizeof(LANSTATUSUI_CONTEXT));
pContext->uID = Index;
pContext->pNet = pNetCon;
pItem->uID = Index;
pItem->pNext = NULL;
pItem->pNet = pNetCon;
hwndDlg = CreateDialogParamW(netshell_hInstance, MAKEINTRESOURCEW(IDD_STATUS), NULL, LANStatusDlg, (LPARAM)pContext);
if (hwndDlg)
{
ZeroMemory(&nid, sizeof(nid));
nid.cbSize = sizeof(nid);
nid.uID = Index++;
nid.uFlags = NIF_MESSAGE;
nid.uVersion = 3;
nid.uCallbackMessage = WM_SHOWSTATUSDLG;
nid.hWnd = hwndDlg;
hr = pNetCon->GetProperties(&pProps);
if (SUCCEEDED(hr))
{
CopyMemory(&pItem->guidItem, &pProps->guidId, sizeof(GUID));
if (!(pProps->dwCharacter & NCCF_SHOW_ICON))
{
nid.dwState = NIS_HIDDEN;
nid.dwStateMask = NIS_HIDDEN;
nid.uFlags |= NIF_STATE;
}
if (pProps->Status == NCS_MEDIA_DISCONNECTED || pProps->Status == NCS_DISCONNECTED || pProps->Status == NCS_HARDWARE_DISABLED)
nid.hIcon = LoadIcon(netshell_hInstance, MAKEINTRESOURCE(IDI_NET_OFF));
else if (pProps->Status == NCS_CONNECTED)
nid.hIcon = LoadIcon(netshell_hInstance, MAKEINTRESOURCE(IDI_NET_IDLE));
if (nid.hIcon)
nid.uFlags |= NIF_ICON;
wcscpy(nid.szTip, pProps->pszwName);
nid.uFlags |= NIF_TIP;
}
pContext->hwndStatusDlg = hwndDlg;
pItem->hwndDlg = hwndDlg;
if (Shell_NotifyIconW(NIM_ADD, &nid))
{
if (pLast)
pLast->pNext = pItem;
else
m_pHead = pItem;
pLast = pItem;
Index++;
}
else
{
ERR("Shell_NotifyIconW failed\n");
CoTaskMemFree(pItem);
}
if (nid.uFlags & NIF_ICON)
DestroyIcon(nid.hIcon);
} else
ERR("CreateDialogParamW failed\n");
}
} while (hr == S_OK);
m_lpNetMan = pNetConMan;
pEnumCon->Release();
return S_OK;
}
HRESULT
CLanStatus::ShowStatusDialogByCLSID(const GUID *pguidCmdGroup)
{
NOTIFICATION_ITEM *pItem;
pItem = m_pHead;
while (pItem)
{
if (IsEqualGUID(pItem->guidItem, *pguidCmdGroup))
{
SendMessageW(pItem->hwndDlg, WM_SHOWSTATUSDLG, 0, WM_LBUTTONDOWN);
return S_OK;
}
pItem = pItem->pNext;
}
ERR("not found\n");
return E_FAIL;
}
HRESULT
WINAPI
CLanStatus::QueryInterface(
REFIID iid,
LPVOID *ppvObj)
{
*ppvObj = NULL;
if (IsEqualIID(iid, IID_IUnknown) ||
IsEqualIID(iid, IID_IOleCommandTarget))
{
*ppvObj = this;
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
ULONG
WINAPI
CLanStatus::AddRef()
{
ULONG refCount = InterlockedIncrement(&m_ref);
return refCount;
}
ULONG
WINAPI
CLanStatus::Release()
{
ULONG refCount = InterlockedDecrement(&m_ref);
if (!refCount)
delete this;
return refCount;
}
HRESULT
WINAPI
CLanStatus::QueryStatus(
const GUID *pguidCmdGroup,
ULONG cCmds,
OLECMD *prgCmds,
OLECMDTEXT *pCmdText)
{
MessageBoxW(NULL, pCmdText->rgwz, L"IOleCommandTarget_fnQueryStatus", MB_OK);
return E_NOTIMPL;
}
HRESULT
WINAPI
CLanStatus::Exec(
const GUID *pguidCmdGroup,
DWORD nCmdID,
DWORD nCmdexecopt,
VARIANT *pvaIn,
VARIANT *pvaOut)
{
if (pguidCmdGroup)
{
if (IsEqualGUID(*pguidCmdGroup, CGID_ShellServiceObject))
{
return InitializeNetTaskbarNotifications();
}
else
{
/* invoke status dialog */
return ShowStatusDialogByCLSID(pguidCmdGroup);
}
}
return S_OK;
}
HRESULT WINAPI LanConnectStatusUI_Constructor(IUnknown *pUnkOuter, REFIID riid, LPVOID *ppv)
{
TRACE("LanConnectStatusUI_Constructor\n");
if (!ppv)
return E_POINTER;
if (pUnkOuter)
return CLASS_E_NOAGGREGATION;
CLanStatus *pLanStatus = new CLanStatus;
if (!pLanStatus)
return E_OUTOFMEMORY;
pLanStatus->AddRef();
static volatile CLanStatus *pCachedLanStatus = NULL;
if (InterlockedCompareExchangePointer((void **)&pCachedLanStatus, pLanStatus, NULL) != NULL)
pLanStatus->Release();
return ((CLanStatus*)pCachedLanStatus)->QueryInterface(riid, ppv);
}