1306 lines
41 KiB
C++
1306 lines
41 KiB
C++
//+---------------------------------------------------------------------------
|
||
//
|
||
// Microsoft Windows
|
||
// Copyright (C) Microsoft Corporation, 2000.
|
||
//
|
||
// File: I S H E L L F 2 . C P P
|
||
//
|
||
// Contents: Provide IShellFolder2 interface for CConnectionsFolderDetails
|
||
// interface. Supercedes IShellDetails. This does not describe
|
||
// IShellFolder members of IShellFolder2 - those are provided in ishellf.cpp
|
||
// This object is created by the ishellv code, primarily to support the
|
||
// WebView data pane in the folder
|
||
//
|
||
// Notes:
|
||
//
|
||
// Author: deonb 18 May 20000
|
||
//
|
||
//----------------------------------------------------------------------------
|
||
|
||
|
||
#include "pch.h"
|
||
#pragma hdrstop
|
||
|
||
#include "foldinc.h" // Standard shell\folder includes
|
||
#include "cfutils.h" // Connections folder utilities
|
||
#include "raserror.h"
|
||
#include "naming.h"
|
||
//---[ externs ]--------------------------------------------------------------
|
||
|
||
extern COLS c_rgCols[];
|
||
|
||
inline HRESULT HrCopyToSTRRET(
|
||
STRRET * pstr,
|
||
PCWSTR pszIn)
|
||
{
|
||
HRESULT hr = S_OK;
|
||
UINT uiByteLen = (lstrlen(pszIn) + 1) * sizeof(WCHAR);
|
||
|
||
Assert(pstr);
|
||
|
||
if (!pstr)
|
||
{
|
||
hr = E_INVALIDARG;
|
||
}
|
||
else
|
||
{
|
||
pstr->uType = STRRET_WSTR;
|
||
pstr->pOleStr = (PWSTR) SHAlloc(uiByteLen);
|
||
|
||
if (pstr->pOleStr == NULL)
|
||
{
|
||
hr = E_OUTOFMEMORY;
|
||
}
|
||
else
|
||
{
|
||
CopyMemory(pstr->pOleStr, pszIn, uiByteLen);
|
||
}
|
||
}
|
||
|
||
TraceHr(ttidShellFolder, FAL, hr, FALSE, "HrCopyToSTRRET");
|
||
return hr;
|
||
}
|
||
|
||
const WCHAR c_szDevice[] = L"\\DEVICE\\";
|
||
const WCHAR c_szLocalSubnet[] = L"255.255.255.255";
|
||
const WCHAR c_crlf[] = L"\r\n";
|
||
|
||
HRESULT HrGetAutoNetSetting(PWSTR pszGuid, DHCP_ADDRESS_TYPE * pAddrType);
|
||
HRESULT HrGetAutoNetSetting(REFGUID pGuidId, DHCP_ADDRESS_TYPE * pAddrType);
|
||
|
||
//+---------------------------------------------------------------------------
|
||
//
|
||
// Member: GetAutoNetSettingsForAdapter
|
||
//
|
||
// Purpose: Get the AutoNet settings for an adapter and return inside a
|
||
// formatted string
|
||
//
|
||
// Arguments:
|
||
// cfe [in] The connectoid
|
||
// uiFormatString [in] ResourceID of the FormatMessage (not sprintf) compatible
|
||
// Format string
|
||
// szString [out] Output string
|
||
//
|
||
// Returns:
|
||
//
|
||
// Author: deonb 2 April 2001
|
||
//
|
||
// Notes:
|
||
//
|
||
HRESULT GetAutoNetSettingsForAdapter(IN const CConFoldEntry& cfe, IN UINT uiFormatString, OUT tstring& szString)
|
||
{
|
||
HRESULT hr = S_OK;
|
||
|
||
LPCWSTR szTmpString = NULL;
|
||
|
||
if (IsMediaRASType(cfe.GetNetConMediaType()))
|
||
{
|
||
szTmpString = SzLoadIds(IDS_DHCP_ISP);
|
||
}
|
||
else
|
||
{
|
||
DHCP_ADDRESS_TYPE DhcpAddress;
|
||
hr = HrGetAutoNetSetting(cfe.GetGuidID(), &DhcpAddress);
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
switch (DhcpAddress)
|
||
{
|
||
case UNKNOWN_ADDR:
|
||
hr = E_FAIL;
|
||
break;
|
||
case NORMAL_ADDR:
|
||
szTmpString = SzLoadIds(IDS_DHCP);
|
||
break;
|
||
case AUTONET_ADDR:
|
||
szTmpString = SzLoadIds(IDS_AUTONET);
|
||
break;
|
||
case ALTERNATE_ADDR:
|
||
szTmpString = SzLoadIds(IDS_ALTERNATE_ADDR);
|
||
break;
|
||
case STATIC_ADDR:
|
||
szTmpString = SzLoadIds(IDS_STATIC_CFG);
|
||
break;
|
||
default:
|
||
hr = E_FAIL;
|
||
AssertSz(NULL, "Invalid DHCP Address type");
|
||
}
|
||
}
|
||
}
|
||
|
||
if (szTmpString)
|
||
{
|
||
WCHAR szFormatBuf[1024];
|
||
if (DwFormatString(SzLoadIds(uiFormatString), szFormatBuf, 1024, szTmpString))
|
||
{
|
||
szString = szFormatBuf;
|
||
}
|
||
else
|
||
{
|
||
hr = HrFromLastWin32Error();
|
||
}
|
||
}
|
||
|
||
TraceHr(ttidShellFolder, FAL, hr, FALSE, "GetAutoNetSettingsForAdapter");
|
||
|
||
return hr;
|
||
}
|
||
|
||
//+---------------------------------------------------------------------------
|
||
//
|
||
// Member: GetPrimaryIPAddressForAdapter
|
||
//
|
||
// Purpose: Get the primary IP Address for an adapter and return inside a
|
||
// formatted string
|
||
//
|
||
// Arguments:
|
||
// cfe [in] The connectoid
|
||
// uiFormatString [in] ResourceID of the FormatMessage (not sprintf) compatible
|
||
// Format string
|
||
// szString [out] Output string
|
||
//
|
||
// Returns:
|
||
//
|
||
// Author: deonb 2 April 2001
|
||
//
|
||
// Notes:
|
||
//
|
||
HRESULT GetPrimaryIPAddressForAdapter(IN const CConFoldEntry& cfe, IN UINT uiFormatString, OUT tstring& szString)
|
||
{
|
||
HRESULT hr = S_OK;
|
||
|
||
if (IsMediaRASType(cfe.GetNetConMediaType()))
|
||
{
|
||
DWORD cb = sizeof(RASCONN);
|
||
DWORD cConnections;
|
||
DWORD dwErr;
|
||
LPRASCONN pRasConn = reinterpret_cast<LPRASCONN>(new BYTE[cb]);
|
||
if (!pRasConn)
|
||
{
|
||
return E_OUTOFMEMORY;
|
||
}
|
||
pRasConn->dwSize = sizeof(RASCONN);
|
||
|
||
do
|
||
{
|
||
dwErr = RasEnumConnections(pRasConn, &cb, &cConnections);
|
||
if (ERROR_BUFFER_TOO_SMALL == dwErr)
|
||
{
|
||
delete[] pRasConn;
|
||
pRasConn = reinterpret_cast<LPRASCONN>(new BYTE[cb]);
|
||
if (!pRasConn)
|
||
{
|
||
return E_OUTOFMEMORY;
|
||
}
|
||
}
|
||
} while (ERROR_BUFFER_TOO_SMALL == dwErr);
|
||
|
||
if (!dwErr)
|
||
{
|
||
Assert( (cb % sizeof(RASCONN)) == 0);
|
||
|
||
DWORD dwItems = cb / sizeof(RASCONN);
|
||
for (DWORD x = 0; x < dwItems; x++)
|
||
{
|
||
if (pRasConn[x].guidEntry == cfe.GetGuidID())
|
||
{
|
||
RASPPPIP rasPPPIP;
|
||
rasPPPIP.dwSize = sizeof(RASPPPIP);
|
||
DWORD dwSize = rasPPPIP.dwSize;
|
||
dwErr = RasGetProjectionInfo(pRasConn[x].hrasconn, RASP_PppIp, &rasPPPIP, &dwSize);
|
||
if (!dwErr)
|
||
{
|
||
WCHAR szFormatBuf[MAX_PATH];
|
||
if (DwFormatString(
|
||
SzLoadIds(uiFormatString),
|
||
szFormatBuf,
|
||
MAX_PATH,
|
||
rasPPPIP.szIpAddress,
|
||
c_szLocalSubnet
|
||
) )
|
||
{
|
||
szString = szFormatBuf;
|
||
}
|
||
else
|
||
{
|
||
hr = HrFromLastWin32Error();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Assert(dwErr != ERROR_BUFFER_TOO_SMALL);
|
||
|
||
hr = HrFromLastWin32Error();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
hr = HrFromLastWin32Error();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
|
||
PIP_ADAPTER_INFO pAdapterInfo = NULL;
|
||
DWORD dwOutBufLen = 0;
|
||
DWORD dwRet = ERROR_SUCCESS;
|
||
|
||
dwRet = GetAdaptersInfo(pAdapterInfo, &dwOutBufLen);
|
||
if (dwRet == ERROR_BUFFER_OVERFLOW)
|
||
{
|
||
pAdapterInfo = (PIP_ADAPTER_INFO) CoTaskMemAlloc(dwOutBufLen);
|
||
if (NULL == pAdapterInfo)
|
||
{
|
||
hr = E_OUTOFMEMORY;
|
||
}
|
||
}
|
||
else if (ERROR_SUCCESS == dwRet)
|
||
{
|
||
hr = E_FAIL;
|
||
}
|
||
else
|
||
{
|
||
hr = HRESULT_FROM_WIN32(dwRet);
|
||
}
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
dwRet = GetAdaptersInfo(pAdapterInfo, &dwOutBufLen);
|
||
if (ERROR_SUCCESS != dwRet)
|
||
{
|
||
CoTaskMemFree(pAdapterInfo);
|
||
hr = HRESULT_FROM_WIN32(dwRet);
|
||
}
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
WCHAR wszGuid[c_cchGuidWithTerm];
|
||
|
||
::StringFromGUID2(cfe.GetGuidID(), wszGuid, c_cchGuidWithTerm);
|
||
|
||
BOOL fFound = FALSE;
|
||
PIP_ADAPTER_INFO pAdapterInfoEnum = pAdapterInfo;
|
||
while (pAdapterInfoEnum)
|
||
{
|
||
USES_CONVERSION;
|
||
|
||
if (lstrcmp(wszGuid, A2W(pAdapterInfoEnum->AdapterName)) == 0)
|
||
{
|
||
LPCWSTR strIPAddress = A2W(pAdapterInfoEnum->IpAddressList.IpAddress.String);
|
||
LPCWSTR strSubnetMask = A2W(pAdapterInfoEnum->IpAddressList.IpMask.String);
|
||
LPCWSTR strGateway = A2W(pAdapterInfoEnum->GatewayList.IpAddress.String);
|
||
|
||
WCHAR szFormatBuf[MAX_PATH];
|
||
LPCWSTR szMode = NULL;
|
||
|
||
if (strIPAddress && strSubnetMask && strGateway)
|
||
{
|
||
LPCWSTR szArgs[] = {strIPAddress, strSubnetMask};
|
||
|
||
if (DwFormatString(
|
||
SzLoadIds(uiFormatString), // lpSource
|
||
szFormatBuf, // Buffer
|
||
MAX_PATH, // Len
|
||
strIPAddress,
|
||
strSubnetMask
|
||
) )
|
||
{
|
||
szString = szFormatBuf;
|
||
}
|
||
else
|
||
{
|
||
hr = HrFromLastWin32Error();
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
|
||
pAdapterInfoEnum = pAdapterInfoEnum->Next;
|
||
}
|
||
|
||
CoTaskMemFree(pAdapterInfo);
|
||
}
|
||
}
|
||
}
|
||
|
||
TraceHr(ttidShellFolder, FAL, hr, FALSE, "GetPrimaryIPAddressForAdapter");
|
||
|
||
return hr;
|
||
}
|
||
|
||
//+---------------------------------------------------------------------------
|
||
//
|
||
// Member: GetWirelessModeForAdapter
|
||
//
|
||
// Purpose: Get the Wireless mode for an adapter and return inside a
|
||
// formatted string
|
||
//
|
||
// Arguments:
|
||
// cfe [in] The connectoid
|
||
// uiFormatString [in] ResourceID of the FormatMessage (not sprintf) compatible
|
||
// Format string
|
||
// szString [out] Output string
|
||
//
|
||
// Returns:
|
||
//
|
||
// Author: deonb 2 April 2001
|
||
//
|
||
// Notes:
|
||
//
|
||
HRESULT GetWirelessModeForAdapter(IN const CConFoldEntry& cfe, IN UINT uiFormatString, OUT tstring& szString)
|
||
{
|
||
HRESULT hr = S_OK;
|
||
|
||
DWORD dwInfraStructureMode = 0;
|
||
DWORD dwInfraStructureModeSize = sizeof(DWORD);
|
||
|
||
hr = HrQueryNDISAdapterOID(cfe.GetGuidID(),
|
||
OID_802_11_INFRASTRUCTURE_MODE,
|
||
&dwInfraStructureModeSize,
|
||
&dwInfraStructureMode);
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
WCHAR szTmpBuf[MAX_PATH];
|
||
LPCWSTR szMode = NULL;
|
||
|
||
switch (dwInfraStructureMode)
|
||
{
|
||
case Ndis802_11IBSS:
|
||
szMode = SzLoadIds(IDS_TOOLTIP_ADHOC);
|
||
break;
|
||
case Ndis802_11Infrastructure:
|
||
szMode = SzLoadIds(IDS_TOOLTIP_INFRASTRUCTURE);
|
||
break;
|
||
}
|
||
|
||
if (szMode)
|
||
{
|
||
if (DwFormatString(
|
||
SzLoadIds(uiFormatString),
|
||
szTmpBuf, // Buffer
|
||
MAX_PATH, // Len
|
||
szMode
|
||
))
|
||
{
|
||
szString = szTmpBuf;
|
||
}
|
||
else
|
||
{
|
||
hr = HrFromLastWin32Error();
|
||
}
|
||
}
|
||
}
|
||
|
||
TraceHr(ttidShellFolder, FAL, hr, FALSE, "GetWirelessModeForAdapter");
|
||
return hr;
|
||
}
|
||
|
||
//+---------------------------------------------------------------------------
|
||
//
|
||
// Member: GetWirelessSSIDForAdapter
|
||
//
|
||
// Purpose: Get the Wireless SSID for an adapter and return inside a
|
||
// formatted string
|
||
//
|
||
// Arguments:
|
||
// cfe [in] The connectoid
|
||
// uiFormatString [in] ResourceID of the FormatMessage (not sprintf) compatible
|
||
// Format string
|
||
// szString [out] Output string
|
||
//
|
||
// Returns:
|
||
//
|
||
// Author: deonb 4 April 2001
|
||
//
|
||
// Notes:
|
||
//
|
||
HRESULT GetWirelessSSIDForAdapter(IN const CConFoldEntry& cfe, IN UINT uiFormatString, OUT tstring& szString)
|
||
{
|
||
HRESULT hr = S_OK;
|
||
|
||
NDIS_802_11_SSID ndisSSID;
|
||
DWORD dwndisSSIDSize = sizeof(NDIS_802_11_SSID);
|
||
|
||
hr = HrQueryNDISAdapterOID(cfe.GetGuidID(),
|
||
OID_802_11_SSID,
|
||
&dwndisSSIDSize,
|
||
&ndisSSID);
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
if (ndisSSID.SsidLength > 1)
|
||
{
|
||
WCHAR szuSSID[sizeof(ndisSSID.Ssid)+1];
|
||
|
||
DWORD dwLen = ndisSSID.SsidLength;
|
||
if (dwLen > sizeof(ndisSSID.Ssid))
|
||
{
|
||
dwLen = sizeof(ndisSSID.Ssid);
|
||
AssertSz(FALSE, "Unexpected SSID encountered");
|
||
}
|
||
|
||
ndisSSID.Ssid[dwLen] = 0;
|
||
mbstowcs(szuSSID, reinterpret_cast<LPSTR>(ndisSSID.Ssid), celems(szuSSID));
|
||
|
||
WCHAR szTmpBuf[MAX_PATH];
|
||
|
||
if (DwFormatString(
|
||
SzLoadIds(uiFormatString),
|
||
szTmpBuf, // Buffer
|
||
MAX_PATH, // Len
|
||
szuSSID
|
||
))
|
||
{
|
||
szString = szTmpBuf;
|
||
}
|
||
else
|
||
{
|
||
hr = HrFromLastWin32Error();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
hr = E_FAIL;
|
||
}
|
||
}
|
||
|
||
TraceHr(ttidShellFolder, FAL, hr, FALSE, "GetWirelessModeForAdapter");
|
||
return hr;
|
||
}
|
||
|
||
|
||
//+---------------------------------------------------------------------------
|
||
//
|
||
// Member: GetWirelessEncryptionForAdapter
|
||
//
|
||
// Purpose: Get the Wireless Encryption for an adapter and return inside a
|
||
// formatted string
|
||
//
|
||
// Arguments:
|
||
// cfe [in] The connectoid
|
||
// uiFormatString [in] ResourceID of the FormatMessage (not sprintf) compatible
|
||
// Format string
|
||
// szString [out] Output string
|
||
//
|
||
// Returns:
|
||
//
|
||
// Author: deonb 4 April 2001
|
||
//
|
||
// Notes:
|
||
//
|
||
HRESULT GetWirelessEncryptionForAdapter(IN const CConFoldEntry& cfe, IN UINT uiFormatString, OUT tstring& szString)
|
||
{
|
||
HRESULT hr = S_OK;
|
||
|
||
DWORD dwEncryption = 0;
|
||
DWORD dwEncryptionSize = sizeof(DWORD);
|
||
|
||
hr = HrQueryNDISAdapterOID(cfe.GetGuidID(),
|
||
OID_802_11_WEP_STATUS,
|
||
&dwEncryptionSize,
|
||
&dwEncryption);
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
WCHAR szTmpBuf[MAX_PATH];
|
||
LPCWSTR szMode = NULL;
|
||
|
||
if (Ndis802_11WEPEnabled == dwEncryption)
|
||
{
|
||
szMode = SzLoadIds(IDS_CONFOLD_STATUS_ENABLED);
|
||
}
|
||
else
|
||
{
|
||
szMode = SzLoadIds(IDS_CONFOLD_STATUS_DISABLED);
|
||
}
|
||
|
||
if (szMode)
|
||
{
|
||
if (DwFormatString(
|
||
SzLoadIds(uiFormatString),
|
||
szTmpBuf, // Buffer
|
||
MAX_PATH, // Len
|
||
szMode
|
||
))
|
||
{
|
||
szString = szTmpBuf;
|
||
}
|
||
else
|
||
{
|
||
hr = HrFromLastWin32Error();
|
||
}
|
||
}
|
||
}
|
||
|
||
TraceHr(ttidShellFolder, FAL, hr, FALSE, "GetWirelessEncryptionForAdapter");
|
||
return hr;
|
||
}
|
||
|
||
|
||
|
||
//+---------------------------------------------------------------------------
|
||
//
|
||
// Member: GetWirelessSignalStrengthForAdapter
|
||
//
|
||
// Purpose: Get the Wireless Signal Strength for an adapter and return inside a
|
||
// formatted string
|
||
//
|
||
// Arguments:
|
||
// cfe [in] The connectoid
|
||
// uiFormatString [in] ResourceID of the FormatMessage (not sprintf) compatible
|
||
// Format string
|
||
// szString [out] Output string
|
||
//
|
||
// Returns:
|
||
//
|
||
// Author: deonb 4 April 2001
|
||
//
|
||
// Notes:
|
||
//
|
||
HRESULT GetWirelessSignalStrengthForAdapter(IN const CConFoldEntry& cfe, IN UINT uiFormatString, OUT tstring& szString)
|
||
{
|
||
HRESULT hr = S_OK;
|
||
|
||
DWORD pdwEnumValue;
|
||
|
||
LONG lSignalStrength = 0;
|
||
DWORD dwSignalStrengthSize = sizeof(DWORD);
|
||
|
||
hr = HrQueryNDISAdapterOID(cfe.GetGuidID(),
|
||
OID_802_11_RSSI,
|
||
&dwSignalStrengthSize,
|
||
&lSignalStrength);
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
WCHAR szTmpBuf[MAX_PATH];
|
||
|
||
if (DwFormatString(
|
||
SzLoadIds(uiFormatString),
|
||
szTmpBuf, // Buffer
|
||
MAX_PATH, // Len
|
||
PszGetRSSIString(lSignalStrength)))
|
||
{
|
||
szString = szTmpBuf;
|
||
}
|
||
else
|
||
{
|
||
hr = HrFromLastWin32Error();
|
||
}
|
||
}
|
||
|
||
TraceHr(ttidShellFolder, FAL, hr, FALSE, "GetWirelessSignalStrengthForAdapter");
|
||
return hr;
|
||
}
|
||
|
||
//+---------------------------------------------------------------------------
|
||
//
|
||
// Member: CConnectionFolderDetails::GetDetailsOf
|
||
//
|
||
// Purpose: Returns the column information, either for the columns
|
||
// themselves, or for the actual details of the view items.
|
||
//
|
||
// Arguments:
|
||
// pidl [in] The pidl for the object being requested
|
||
// iColumn [in] The details column needed
|
||
// lpDetails [in] Buffer that receives the detail data
|
||
//
|
||
// Returns:
|
||
//
|
||
// Author: jeffspr 16 Mar 1998
|
||
//
|
||
// Notes:
|
||
//
|
||
HRESULT CConnectionFolder::GetDetailsOf(
|
||
LPCITEMIDLIST pidl,
|
||
UINT iColumn,
|
||
LPSHELLDETAILS lpDetails)
|
||
{
|
||
TraceFileFunc(ttidShellFolder);
|
||
|
||
HRESULT hr = S_OK;
|
||
PCWSTR pszString = NULL;
|
||
WCHAR szStatus[CONFOLD_MAX_STATUS_LENGTH];
|
||
tstring szTmpString;
|
||
|
||
// If the column requested is beyond our set of columns,
|
||
// return failure.
|
||
//
|
||
if (((INT)iColumn < 0) || ((INT)iColumn >= ICOL_MAX))
|
||
{
|
||
hr = E_FAIL;
|
||
}
|
||
else
|
||
{
|
||
// If NULL, caller wants strings for the column headers
|
||
//
|
||
CONFOLDENTRY cfe; // Need this scope as we assign pszString from it.
|
||
|
||
if (NULL == pidl)
|
||
{
|
||
if (c_rgCols[iColumn].iStringRes)
|
||
{
|
||
pszString = SzLoadIds(c_rgCols[iColumn].iStringRes);
|
||
}
|
||
lpDetails->fmt = c_rgCols[iColumn].iFormat;
|
||
lpDetails->cxChar = c_rgCols[iColumn].iColumnSize;
|
||
|
||
}
|
||
else
|
||
{
|
||
INT iStringRes = 0;
|
||
|
||
PCONFOLDPIDL pcfp;
|
||
hr = pcfp.InitializeFromItemIDList(pidl);
|
||
if (FAILED(hr))
|
||
{
|
||
return hr;
|
||
}
|
||
|
||
hr = pcfp.ConvertToConFoldEntry(cfe);
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
Assert(!cfe.empty());
|
||
lpDetails->fmt = c_rgCols[iColumn].iColumnSize;
|
||
lpDetails->cxChar = c_rgCols[iColumn].iColumnSize;
|
||
|
||
if (!cfe.GetWizard())
|
||
{
|
||
// Retrieve the appropriate column
|
||
//
|
||
switch(iColumn)
|
||
{
|
||
case ICOL_NAME: // 0
|
||
pszString = cfe.GetName();
|
||
break;
|
||
|
||
case ICOL_TYPE: // 1
|
||
MapNCMToResourceId(cfe.GetNetConMediaType(), cfe.GetCharacteristics(), &iStringRes);
|
||
pszString = SzLoadIds(iStringRes);
|
||
break;
|
||
|
||
case ICOL_STATUS: // 2
|
||
MapNCSToComplexStatus(cfe.GetNetConStatus(), cfe.GetNetConMediaType(), cfe.GetNetConSubMediaType(), cfe.GetCharacteristics(), szStatus, CONFOLD_MAX_STATUS_LENGTH, cfe.GetGuidID());
|
||
pszString = szStatus;
|
||
break;
|
||
|
||
case ICOL_DEVICE_NAME: // 3
|
||
pszString = cfe.GetDeviceName();
|
||
break;
|
||
|
||
case ICOL_PHONEORHOSTADDRESS: // 4
|
||
case ICOL_PHONENUMBER: // 7
|
||
case ICOL_HOSTADDRESS: // 8
|
||
pszString = cfe.GetPhoneOrHostAddress();
|
||
break;
|
||
|
||
case ICOL_OWNER: // 5
|
||
if (cfe.GetCharacteristics() & NCCF_ALL_USERS)
|
||
{
|
||
pszString = SzLoadIds(IDS_CONFOLD_DETAILS_OWNER_SYSTEM);
|
||
}
|
||
else
|
||
{
|
||
pszString = PszGetOwnerStringFromCharacteristics(pszGetUserName(), cfe.GetCharacteristics() );
|
||
}
|
||
break;
|
||
|
||
case ICOL_ADDRESS: //6
|
||
{
|
||
if (!fIsConnectedStatus(cfe.GetNetConStatus()))
|
||
{
|
||
hr = E_FAIL;
|
||
}
|
||
else
|
||
{
|
||
BOOL bSomeDetail = FALSE;
|
||
tstring szAutonet;
|
||
tstring szIp;
|
||
|
||
hr = GetPrimaryIPAddressForAdapter(cfe, IDS_DETAILS_IP_ADDRESS, szIp);
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
szTmpString += szIp;
|
||
bSomeDetail = TRUE;
|
||
}
|
||
|
||
hr = GetAutoNetSettingsForAdapter(cfe, IDS_DETAILS_ADDRESS_TYPE, szAutonet);
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
if (bSomeDetail)
|
||
{
|
||
szTmpString += c_crlf;
|
||
}
|
||
szTmpString += szAutonet;
|
||
bSomeDetail = TRUE;
|
||
}
|
||
|
||
if (bSomeDetail)
|
||
{
|
||
hr = S_OK;
|
||
pszString = szTmpString.c_str();
|
||
}
|
||
}
|
||
}
|
||
|
||
break;
|
||
|
||
case ICOL_WIRELESS_MODE:
|
||
{
|
||
if ( (NCS_DISCONNECTED != cfe.GetNetConStatus()) &&
|
||
(NCS_HARDWARE_DISABLED != cfe.GetNetConStatus()) &&
|
||
(NCS_HARDWARE_MALFUNCTION!= cfe.GetNetConStatus()) &&
|
||
(NCS_HARDWARE_NOT_PRESENT!= cfe.GetNetConStatus()) &&
|
||
(NCS_MEDIA_DISCONNECTED != cfe.GetNetConStatus()) &&
|
||
(cfe.GetNetConMediaType() == NCM_LAN) &&
|
||
(cfe.GetNetConSubMediaType() == NCSM_WIRELESS) )
|
||
{
|
||
BOOL bSomeDetail = FALSE;
|
||
tstring szString;
|
||
|
||
hr = GetWirelessModeForAdapter(cfe, IDS_DETAILS_802_11_MODE, szString);
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
szTmpString += szString;
|
||
bSomeDetail = TRUE;
|
||
}
|
||
|
||
|
||
hr = GetWirelessSSIDForAdapter(cfe, IDS_DETAILS_802_11_SSID_TYPE, szString);
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
if (bSomeDetail)
|
||
{
|
||
szTmpString += c_crlf;
|
||
}
|
||
szTmpString += szString;
|
||
bSomeDetail = TRUE;
|
||
}
|
||
|
||
hr = GetWirelessEncryptionForAdapter(cfe, IDS_DETAILS_802_11_ENCRYPTION_TYPE, szString);
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
if (bSomeDetail)
|
||
{
|
||
szTmpString += c_crlf;
|
||
}
|
||
szTmpString += szString;
|
||
bSomeDetail = TRUE;
|
||
}
|
||
|
||
hr = GetWirelessSignalStrengthForAdapter(cfe, IDS_DETAILS_802_11_SIGNAL_STRENGTH, szString);
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
if (bSomeDetail)
|
||
{
|
||
szTmpString += c_crlf;
|
||
}
|
||
szTmpString += szString;
|
||
bSomeDetail = TRUE;
|
||
}
|
||
|
||
if (bSomeDetail)
|
||
{
|
||
hr = S_OK;
|
||
pszString = szTmpString.c_str();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
hr = E_FAIL;
|
||
}
|
||
}
|
||
|
||
break;
|
||
|
||
default:
|
||
AssertSz(FALSE, "CConnectionFolder::GetDetailsOf - Invalid ICOL from the Shell");
|
||
pszString = NULL;
|
||
hr = E_FAIL;
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// If we're the wizard, and they want the name, then load
|
||
// the friendly rendition for webview's sake
|
||
//
|
||
switch(iColumn)
|
||
{
|
||
case ICOL_NAME: // 0
|
||
pszString = SzLoadIds(IDS_CONFOLD_WIZARD_DISPLAY_NAME);
|
||
break;
|
||
|
||
case ICOL_TYPE: // 1
|
||
pszString = SzLoadIds(IDS_CONFOLD_WIZARD_TYPE);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
// Copy the string to the return buffer type. If there was no string loaded,
|
||
// then just copy a null string a return it. This will happen for each
|
||
// wizard item, since we provide no text.
|
||
//
|
||
hr = HrCopyToSTRRET(&(lpDetails->str), pszString ? pszString : L" \0");
|
||
}
|
||
}
|
||
|
||
return hr;
|
||
}
|
||
|
||
//+---------------------------------------------------------------------------
|
||
//
|
||
// Member: CConnectionFolderDetails::EnumSearches
|
||
//
|
||
// Purpose: Requests a pointer to an interface that allows a client to
|
||
// enumerate the available search objects.
|
||
//
|
||
// Arguments:
|
||
// IEnumExtraSearch [in] Address of a pointer to an enumerator object's
|
||
// IEnumExtraSearch interface.
|
||
//
|
||
// Returns:
|
||
//
|
||
// Author: deonb 17 May 2000
|
||
//
|
||
// Notes:
|
||
//
|
||
STDMETHODIMP CConnectionFolder::EnumSearches (
|
||
IEnumExtraSearch **ppEnum)
|
||
{
|
||
TraceFileFunc(ttidShellFolder);
|
||
return E_NOTIMPL;
|
||
}
|
||
|
||
//+---------------------------------------------------------------------------
|
||
//
|
||
// Member: CConnectionFolderDetails::GetDefaultColumn
|
||
//
|
||
// Purpose: Gets the default sorting and display columns.
|
||
//
|
||
// Arguments:
|
||
// dwReserved [in] Reserved. Set to zero.
|
||
// pSort [out] Pointer to a value that receives the index of the default sorted column.
|
||
// pDisplay [out] Pointer to a value that receives the index of the default display column.
|
||
//
|
||
// Returns:
|
||
//
|
||
// Author: deonb 17 May 2000
|
||
//
|
||
// Notes:
|
||
//
|
||
STDMETHODIMP CConnectionFolder::GetDefaultColumn (
|
||
DWORD dwReserved,
|
||
ULONG *pSort,
|
||
ULONG *pDisplay )
|
||
{
|
||
TraceFileFunc(ttidShellFolder);
|
||
return E_NOTIMPL;
|
||
}
|
||
|
||
//+---------------------------------------------------------------------------
|
||
//
|
||
// Member: CConnectionFolderDetails::GetDefaultColumnState
|
||
//
|
||
// Purpose: Retrieves the default state for a specified column.
|
||
//
|
||
// Arguments:
|
||
// iColumn [in] Integer that specifies the column number.
|
||
// pcsFlags [out] Pointer to flags that indicate the default column state.
|
||
//
|
||
// Returns:
|
||
//
|
||
// Author: deonb 17 May 2000
|
||
//
|
||
// Notes:
|
||
//
|
||
STDMETHODIMP CConnectionFolder::GetDefaultColumnState (
|
||
UINT iColumn,
|
||
DWORD *pcsFlags )
|
||
{
|
||
TraceFileFunc(ttidShellFolder);
|
||
|
||
HRESULT hr;
|
||
if ( (static_cast<INT>(iColumn) >= ICOL_NAME) && (static_cast<INT>(iColumn) < ICOL_MAX) )
|
||
{
|
||
*pcsFlags = c_rgCols[iColumn].csFlags;
|
||
hr = S_OK;
|
||
}
|
||
else
|
||
{
|
||
hr = E_FAIL;
|
||
}
|
||
|
||
return hr;
|
||
}
|
||
|
||
//+---------------------------------------------------------------------------
|
||
//
|
||
// Member: CConnectionFolderDetails::GetDefaultSearchGUID
|
||
//
|
||
// Purpose: Returns the globally unique identifier (GUID) of the default
|
||
// search object for the folder.
|
||
//
|
||
// Arguments:
|
||
// lpGUID [out] GUID of the default search object.
|
||
//
|
||
// Returns:
|
||
//
|
||
// Author: deonb 17 May 2000
|
||
//
|
||
// Notes:
|
||
//
|
||
STDMETHODIMP CConnectionFolder::GetDefaultSearchGUID (
|
||
LPGUID lpGUID )
|
||
{
|
||
TraceFileFunc(ttidShellFolder);
|
||
return E_NOTIMPL;
|
||
}
|
||
|
||
#define DEFINE_SCID(name, fmtid, pid) const SHCOLUMNID name = { fmtid, pid }
|
||
|
||
//+---------------------------------------------------------------------------
|
||
//
|
||
// Member: CConnectionFolderDetails::GetDetailsEx
|
||
//
|
||
// Purpose: Retrieves detailed information, identified by a property set ID
|
||
// (FMTID) and property ID (PID), on an item in a shell folder.
|
||
//
|
||
// Arguments:
|
||
// pidl [in] PIDL of the item, relative to the parent folder. This method accepts
|
||
// only single-level PIDLs. The structure must contain exactly one
|
||
// SHITEMID structure followed by a terminating zero.
|
||
// pscid [in] Pointer to an SHCOLUMNID structure that identifies the column.
|
||
// pv [out] Pointer to a VARIANT with the requested information.
|
||
// The value will be fully typed.
|
||
// Returns:
|
||
//
|
||
// Author: deonb 17 May 2000
|
||
//
|
||
// Notes:
|
||
//
|
||
#define STR_FMTID_DUIWebViewProp TEXT("{4BF1583F-916B-4719-AC31-8896A4BD8D8B}")
|
||
#define PSCID_DUIWebViewProp {0x4bf1583f, 0x916b, 0x4719, 0xac, 0x31, 0x88, 0x96, 0xa4, 0xbd, 0x8d, 0x8b}
|
||
DEFINE_SCID(SCID_WebViewDisplayProperties, PSGUID_WEBVIEW, PID_DISPLAY_PROPERTIES);
|
||
#ifdef __cplusplus
|
||
#define IsEqualSCID(a, b) (((a).pid == (b).pid) && IsEqualIID((a).fmtid, (b).fmtid) )
|
||
#else
|
||
#define IsEqualSCID(a, b) (((a).pid == (b).pid) && IsEqualIID(&((a).fmtid),&((b).fmtid)))
|
||
#endif
|
||
|
||
const TCHAR szDUI_LAN_Props[] =
|
||
TEXT("prop:")
|
||
TEXT("Name;") // ICOL_NAME (0)
|
||
STR_FMTID_DUIWebViewProp TEXT("1") // ICOL_TYPE (1)
|
||
TEXT(";")
|
||
STR_FMTID_DUIWebViewProp TEXT("2") // ICOL_STATUS (2)
|
||
TEXT(";")
|
||
STR_FMTID_DUIWebViewProp TEXT("3") // ICOL_DEVICE_NAME (3)
|
||
TEXT(";")
|
||
STR_FMTID_DUIWebViewProp TEXT("6") // ICOL_ADDRESS (6)
|
||
TEXT(";")
|
||
;
|
||
|
||
const TCHAR szDUI_WIRELESS_LAN_Props[] =
|
||
TEXT("prop:")
|
||
TEXT("Name;") // ICOL_NAME (0)
|
||
STR_FMTID_DUIWebViewProp TEXT("2") // ICOL_STATUS (2)
|
||
TEXT(";")
|
||
STR_FMTID_DUIWebViewProp TEXT("6") // ICOL_ADDRESS (6)
|
||
TEXT(";")
|
||
STR_FMTID_DUIWebViewProp TEXT("9") // ICOL_WIRELESS_MODE (9)
|
||
TEXT(";")
|
||
;
|
||
|
||
const TCHAR szDUI_PHONEISDN_Props[] =
|
||
TEXT("prop:")
|
||
TEXT("Name;") // ICOL_NAME (0)
|
||
STR_FMTID_DUIWebViewProp TEXT("1") // ICOL_TYPE (1)
|
||
TEXT(";")
|
||
STR_FMTID_DUIWebViewProp TEXT("2") // ICOL_STATUS (2)
|
||
TEXT(";")
|
||
STR_FMTID_DUIWebViewProp TEXT("3") // ICOL_DEVICE_NAME (3)
|
||
TEXT(";")
|
||
STR_FMTID_DUIWebViewProp TEXT("7") // ICOL_PHONENUMBER (7)
|
||
TEXT(";")
|
||
STR_FMTID_DUIWebViewProp TEXT("6") // ICOL_ADDRESS (6)
|
||
TEXT(";")
|
||
;
|
||
|
||
const TCHAR szDUI_RASOTHER_Props[] =
|
||
TEXT("prop:")
|
||
TEXT("Name;") // ICOL_NAME (0)
|
||
STR_FMTID_DUIWebViewProp TEXT("1") // ICOL_TYPE (1)
|
||
TEXT(";")
|
||
STR_FMTID_DUIWebViewProp TEXT("2") // ICOL_STATUS (2)
|
||
TEXT(";")
|
||
STR_FMTID_DUIWebViewProp TEXT("3") // ICOL_DEVICE_NAME (3)
|
||
TEXT(";")
|
||
STR_FMTID_DUIWebViewProp TEXT("8") // ICOL_HOSTADDRESS (8)
|
||
TEXT(";")
|
||
STR_FMTID_DUIWebViewProp TEXT("6") // ICOL_ADDRESS (6)
|
||
TEXT(";")
|
||
;
|
||
|
||
STDMETHODIMP CConnectionFolder::GetDetailsEx (
|
||
LPCITEMIDLIST pidl,
|
||
const SHCOLUMNID *pscid,
|
||
VARIANT *pv )
|
||
{
|
||
|
||
TraceFileFunc(ttidShellFolder);
|
||
|
||
HRESULT hr = S_OK;
|
||
|
||
if ( (!pidl) || (!pscid) || (!pv) )
|
||
{
|
||
return E_INVALIDARG;
|
||
}
|
||
|
||
VariantInit(pv);
|
||
|
||
if (IsEqualSCID(*pscid, SCID_WebViewDisplayProperties))
|
||
{
|
||
VariantInit(pv);
|
||
|
||
pv->vt = VT_BSTR;
|
||
|
||
PCONFOLDPIDL pcfp;
|
||
hr = pcfp.InitializeFromItemIDList(pidl);
|
||
if (FAILED(hr))
|
||
{
|
||
return hr;
|
||
}
|
||
|
||
switch (pcfp->ncm)
|
||
{
|
||
case NCM_LAN:
|
||
if ( pcfp->ncsm == NCSM_WIRELESS )
|
||
{
|
||
pv->bstrVal = SysAllocString(szDUI_WIRELESS_LAN_Props);
|
||
}
|
||
else
|
||
{
|
||
pv->bstrVal = SysAllocString(szDUI_LAN_Props);
|
||
}
|
||
break;
|
||
|
||
case NCM_BRIDGE:
|
||
pv->bstrVal = SysAllocString(szDUI_LAN_Props);
|
||
break;
|
||
|
||
case NCM_NONE:
|
||
case NCM_DIRECT:
|
||
case NCM_PPPOE:
|
||
case NCM_SHAREDACCESSHOST_LAN:
|
||
case NCM_SHAREDACCESSHOST_RAS:
|
||
case NCM_TUNNEL:
|
||
pv->bstrVal = SysAllocString(szDUI_RASOTHER_Props);
|
||
break;
|
||
|
||
case NCM_PHONE:
|
||
case NCM_ISDN:
|
||
pv->bstrVal = SysAllocString(szDUI_PHONEISDN_Props);
|
||
break;
|
||
|
||
default:
|
||
AssertSz(NULL, "Unexpected NetCon Media Type");
|
||
hr = E_FAIL;
|
||
}
|
||
}
|
||
else if (IsEqualIID(pscid->fmtid, FMTID_DUIWebViewProp) && pscid->pid < ICOL_MAX)
|
||
{
|
||
// this is a webview property -- get the value from GetDetailsOf(...)
|
||
SHELLDETAILS sd = {0};
|
||
hr = GetDetailsOf(pidl, pscid->pid, &sd);
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
WCHAR szTemp[INFOTIPSIZE];
|
||
hr = StrRetToBufW(&sd.str, pidl, szTemp, INFOTIPSIZE);
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
pv->vt = VT_BSTR;
|
||
pv->bstrVal = SysAllocString(szTemp);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
if (IsEqualGUID(pscid->fmtid, GUID_NETSHELL_PROPS))
|
||
{
|
||
CComBSTR bstrDisplayString;
|
||
|
||
PCONFOLDPIDL pcfp;
|
||
hr = pcfp.InitializeFromItemIDList(pidl);
|
||
if FAILED(hr)
|
||
{
|
||
return hr;
|
||
}
|
||
|
||
CONFOLDENTRY cfe;
|
||
hr = pcfp.ConvertToConFoldEntry(cfe);
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
Assert(!cfe.empty());
|
||
|
||
INT iStringRes;
|
||
if (!cfe.GetWizard())
|
||
{
|
||
switch (pscid->pid)
|
||
{
|
||
case ICOL_NAME:
|
||
WCHAR szDisplayName[2];
|
||
szDisplayName[0] = towupper(*cfe.GetName());
|
||
szDisplayName[1] = NULL;
|
||
bstrDisplayString = szDisplayName;
|
||
break;
|
||
|
||
case ICOL_DEVICE_NAME:
|
||
bstrDisplayString = cfe.GetDeviceName();
|
||
if (bstrDisplayString.Length() == 0) // e.g. Incoming Connections
|
||
{
|
||
bstrDisplayString = cfe.GetName();
|
||
}
|
||
break;
|
||
|
||
case ICOL_PHONEORHOSTADDRESS:
|
||
AssertSz(FALSE, "Can't group by this column - IDefCategoryProvider should have prevented this.");
|
||
bstrDisplayString = cfe.GetPhoneOrHostAddress();
|
||
break;
|
||
|
||
case ICOL_TYPE:
|
||
MapNCMToResourceId(pcfp->ncm, pcfp->dwCharacteristics, &iStringRes);
|
||
bstrDisplayString = SzLoadIds(iStringRes);
|
||
break;
|
||
|
||
case ICOL_NETCONMEDIATYPE:
|
||
pv->vt = VT_I4;
|
||
pv->lVal = pcfp->ncm;
|
||
return S_OK;
|
||
|
||
case ICOL_NETCONSUBMEDIATYPE:
|
||
pv->vt = VT_I4;
|
||
pv->lVal = pcfp->ncsm;
|
||
return S_OK;
|
||
|
||
case ICOL_NETCONSTATUS:
|
||
pv->vt = VT_I4;
|
||
pv->lVal = pcfp->ncs;
|
||
return S_OK;
|
||
|
||
case ICOL_NETCONCHARACTERISTICS:
|
||
pv->vt = VT_I4;
|
||
pv->lVal = pcfp->dwCharacteristics;
|
||
return S_OK;
|
||
|
||
case ICOL_STATUS:
|
||
WCHAR szStatus[CONFOLD_MAX_STATUS_LENGTH];
|
||
MapNCSToComplexStatus(pcfp->ncs, pcfp->ncm, pcfp->ncsm, pcfp->dwCharacteristics, szStatus, CONFOLD_MAX_STATUS_LENGTH, pcfp->guidId);
|
||
bstrDisplayString = szStatus;
|
||
break;
|
||
|
||
case ICOL_OWNER:
|
||
if (cfe.GetCharacteristics() & NCCF_ALL_USERS)
|
||
{
|
||
bstrDisplayString = SzLoadIds(IDS_CONFOLD_DETAILS_OWNER_SYSTEM);
|
||
}
|
||
else
|
||
{
|
||
bstrDisplayString = PszGetOwnerStringFromCharacteristics(pszGetUserName(), cfe.GetCharacteristics() );
|
||
}
|
||
break;
|
||
|
||
default:
|
||
hr = E_FAIL;
|
||
break;
|
||
}
|
||
}
|
||
else // if !(pccfe.GetWizard())
|
||
{
|
||
switch (pscid->pid)
|
||
{
|
||
case ICOL_NAME: // 0
|
||
WCHAR szDisplayName[2];
|
||
szDisplayName[0] = towupper(*cfe.GetName());
|
||
szDisplayName[1] = NULL;
|
||
bstrDisplayString = szDisplayName;
|
||
break;
|
||
case ICOL_TYPE: // 1
|
||
default:
|
||
bstrDisplayString = SzLoadIds(IDS_CONFOLD_WIZARD_TYPE);
|
||
break;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
if (bstrDisplayString.Length() == 0)
|
||
{
|
||
hr = E_FAIL;
|
||
}
|
||
else
|
||
{
|
||
pv->vt = VT_BSTR;
|
||
pv->bstrVal = bstrDisplayString.Detach();
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
hr = E_FAIL;
|
||
}
|
||
|
||
return hr;
|
||
}
|
||
|
||
//+---------------------------------------------------------------------------
|
||
//
|
||
// Member: CConnectionFolderDetails::MapNameToSCID
|
||
//
|
||
// Purpose: Converts a column name to the appropriate property set ID (FMTID)
|
||
// and property ID (PID).
|
||
//
|
||
// Arguments:
|
||
// iColumn [in] Zero-based index of the desired information field. It is
|
||
// identical to the column number of the information as it is
|
||
// displayed in a Microsoft<66> Windows<77> Explorer Details view.
|
||
// pscid [out] Pointer to an SHCOLUMNID structure containing the FMTID and PID.
|
||
|
||
// Returns:
|
||
//
|
||
// Author: deonb 17 May 2000
|
||
//
|
||
// Notes:
|
||
//
|
||
STDMETHODIMP CConnectionFolder::MapColumnToSCID (
|
||
|
||
UINT iColumn,
|
||
SHCOLUMNID *pscid )
|
||
{
|
||
TraceFileFunc(ttidShellFolder);
|
||
|
||
HRESULT hr = S_OK;
|
||
if (!pscid)
|
||
{
|
||
return E_INVALIDARG;
|
||
}
|
||
|
||
if ( (static_cast<INT>(iColumn) >= ICOL_NAME) && (static_cast<INT>(iColumn) < ICOL_MAX) )
|
||
{
|
||
pscid->fmtid = GUID_NETSHELL_PROPS;
|
||
pscid->pid = iColumn;
|
||
}
|
||
else
|
||
{
|
||
hr = E_INVALIDARG;
|
||
}
|
||
|
||
return hr;
|
||
}
|