Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1334 lines
30 KiB

#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#undef ASSERT
#include "cmmn.h"
#include <shlwapi.h>
#include "hwdev.h"
#include "hnotif.h"
#include "vol.h"
#include "mtpts.h"
#include "miscdev.h"
#include "drvbase.h"
#include "regnotif.h"
#include "users.h"
#include "logging.h"
#include "sfstr.h"
#include "dbg.h"
#include "tfids.h"
#include <setupapi.h>
#pragma warning(disable: 4201)
#include <winioctl.h>
#pragma warning(default: 4201)
#define ARRAYSIZE(a) (sizeof((a))/sizeof((a)[0]))
///////////////////////////////////////////////////////////////////////////////
//
const GUID guidVolumeClass =
{0x53f5630d, 0xb6bf, 0x11d0,
{0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b}};
const GUID guidDiskClass =
{0x53f56307, 0xb6bf, 0x11d0,
{0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b}};
const GUID guidCdRomClass =
{0x53f56308L, 0xb6bf, 0x11d0,
{0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b}};
const GUID guidImagingDeviceClass =
{0x6bdd1fc6L, 0x810f, 0x11d0,
{0xbe, 0xc7, 0x08, 0x00, 0x2b, 0xe2, 0x09, 0x2f}};
const GUID guidVideoCameraClass =
{0x6994AD05L, 0x93EF, 0x11D0,
{0xA3, 0xCC, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
const GUID guidInvalid =
{0xFFFFFFFFL, 0xFFFF, 0xFFFF,
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}};
///////////////////////////////////////////////////////////////////////////////
//
BOOL CHWEventDetectorHelper::_fDiagnosticAppPresent = FALSE;
DWORD CHWEventDetectorHelper::_dwDiagAppLastCheck = (DWORD)-1;
SERVICE_STATUS_HANDLE CHWEventDetectorHelper::_ssh = NULL;
BOOL CHWEventDetectorHelper::_fListCreated = FALSE;
CNamedElemList* CHWEventDetectorHelper::
_rgpnel[HWEDLIST_COUNT_OF_LISTS] = {0};
// For the debugger extension
DWORD CHWEventDetectorHelper::_cpnel =
ARRAYSIZE(CHWEventDetectorHelper::_rgpnel);
BOOL CHWEventDetectorHelper::_fDocked = FALSE;
CImpersonateEveryone* CHWEventDetectorHelper::_pieo = NULL;
CCriticalSection CHWEventDetectorHelper::_cs;
BOOL CHWEventDetectorHelper::_fInited = FALSE;
#ifdef DEBUG
DWORD _cDbgDeviceHandle = 0;
#endif
///////////////////////////////////////////////////////////////////////////////
//
HRESULT _DeviceInstIsRemovable(DEVINST devinst, BOOL* pfRemovable)
{
DWORD dwCap;
DWORD cbCap = sizeof(dwCap);
CONFIGRET cr = CM_Get_DevNode_Registry_Property_Ex(devinst,
CM_DRP_CAPABILITIES, NULL, &dwCap, &cbCap, 0, NULL);
if (CR_SUCCESS == cr)
{
if (CM_DEVCAP_REMOVABLE & dwCap)
{
*pfRemovable = TRUE;
}
else
{
*pfRemovable = FALSE;
}
}
else
{
*pfRemovable = FALSE;
}
return S_OK;
}
HANDLE _GetDeviceHandle(LPCTSTR psz, DWORD dwDesiredAccess)
{
HANDLE hDevice = CreateFile(psz, dwDesiredAccess,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
#ifdef DEBUG
if (INVALID_HANDLE_VALUE != hDevice)
{
++_cDbgDeviceHandle;
TRACE(TF_LEAK, TEXT("_GetDeviceHandle: %d"), _cDbgDeviceHandle);
}
#endif
return hDevice;
}
void _CloseDeviceHandle(HANDLE hDevice)
{
CloseHandle(hDevice);
#ifdef DEBUG
if (INVALID_HANDLE_VALUE != hDevice)
{
--_cDbgDeviceHandle;
TRACE(TF_LEAK, TEXT("_CloseDeviceHandle: %d"), _cDbgDeviceHandle);
}
#endif
}
HRESULT _GetVolumeName(LPCWSTR pszDeviceID, LPWSTR pszVolumeName,
DWORD cchVolumeName)
{
WCHAR szDeviceIDWithSlash[MAX_DEVICEID];
LPWSTR pszNext;
DWORD cchLeft;
HRESULT hres = SafeStrCpyNEx(szDeviceIDWithSlash, pszDeviceID,
ARRAYSIZE(szDeviceIDWithSlash), &pszNext, &cchLeft);
if (SUCCEEDED(hres))
{
hres = SafeStrCpyN(pszNext, TEXT("\\"), cchLeft);
if (SUCCEEDED(hres))
{
if (GetVolumeNameForVolumeMountPoint(szDeviceIDWithSlash,
pszVolumeName, cchVolumeName))
{
hres = S_OK;
}
else
{
*pszVolumeName = 0;
hres = S_FALSE;
}
}
}
return hres;
}
HRESULT _GetHWDeviceInstFromVolumeIntfID(LPCWSTR pszDeviceIntfID,
CHWDeviceInst** pphwdevinst, CNamedElem** ppelemToRelease)
{
CNamedElemList* pnel;
HRESULT hres = CHWEventDetectorHelper::GetList(HWEDLIST_VOLUME, &pnel);
*pphwdevinst = NULL;
*ppelemToRelease = NULL;
if (S_OK == hres)
{
CNamedElem* pelem;
hres = pnel->Get(pszDeviceIntfID, &pelem);
if (SUCCEEDED(hres) && (S_FALSE != hres))
{
CVolume* pvol = (CVolume*)pelem;
hres = pvol->GetHWDeviceInst(pphwdevinst);
if (SUCCEEDED(hres) && (S_FALSE != hres))
{
*ppelemToRelease = pelem;
}
else
{
pelem->RCRelease();
}
}
pnel->RCRelease();
}
return hres;
}
HRESULT _GetHWDeviceInstFromDeviceNode(LPCWSTR pszDeviceNode,
CHWDeviceInst** pphwdevinst, CNamedElem** ppelemToRelease)
{
CNamedElemList* pnel;
HRESULT hres = CHWEventDetectorHelper::GetList(HWEDLIST_MISCDEVNODE, &pnel);
*pphwdevinst = NULL;
*ppelemToRelease = NULL;
if (S_OK == hres)
{
CNamedElem* pelem;
hres = pnel->GetOrAdd(pszDeviceNode, &pelem);
if (SUCCEEDED(hres))
{
CMiscDeviceNode* pmiscdevnode =
(CMiscDeviceNode*)pelem;
hres = pmiscdevnode->GetHWDeviceInst(pphwdevinst);
if (SUCCEEDED(hres) && (S_FALSE != hres))
{
*ppelemToRelease = pelem;
}
else
{
pelem->RCRelease();
}
}
pnel->RCRelease();
}
return hres;
}
HRESULT _GetHWDeviceInstFromDeviceIntfID(LPCWSTR pszDeviceIntfID,
CHWDeviceInst** pphwdevinst, CNamedElem** ppelemToRelease)
{
CNamedElemList* pnel;
HRESULT hres = CHWEventDetectorHelper::GetList(HWEDLIST_MISCDEVINTF, &pnel);
*pphwdevinst = NULL;
*ppelemToRelease = NULL;
if (S_OK == hres)
{
CNamedElem* pelem;
hres = pnel->Get(pszDeviceIntfID, &pelem);
if (SUCCEEDED(hres) && (S_FALSE != hres))
{
CMiscDeviceInterface* pmiscdevintf =
(CMiscDeviceInterface*)pelem;
hres = pmiscdevintf->GetHWDeviceInst(pphwdevinst);
if (SUCCEEDED(hres) && (S_FALSE != hres))
{
*ppelemToRelease = pelem;
}
else
{
pelem->RCRelease();
}
}
pnel->RCRelease();
}
return hres;
}
HRESULT _GetHWDeviceInstFromDeviceOrVolumeIntfID(LPCWSTR pszDeviceIntfID,
CHWDeviceInst** pphwdevinst, CNamedElem** ppelemToRelease)
{
HRESULT hres = _GetHWDeviceInstFromVolumeIntfID(pszDeviceIntfID,
pphwdevinst, ppelemToRelease);
if (S_FALSE == hres)
{
// Not a volume ID, try other devices
hres = _GetHWDeviceInstFromDeviceIntfID(pszDeviceIntfID,
pphwdevinst, ppelemToRelease);
}
return hres;
}
HRESULT _GetDeviceIDFromMtPtName(LPCWSTR pszMtPt, LPWSTR pszDeviceID,
DWORD cchDeviceID)
{
CNamedElemList* pnel;
HRESULT hres = CHWEventDetectorHelper::GetList(HWEDLIST_MTPT, &pnel);
if (S_OK == hres)
{
CNamedElem* pelem;
hres = pnel->Get(pszMtPt, &pelem);
if (SUCCEEDED(hres) && (S_FALSE != hres))
{
CMtPt* pmtpt = (CMtPt*)pelem;
hres = pmtpt->GetVolumeName(pszDeviceID, cchDeviceID);
pelem->RCRelease();
}
pnel->RCRelease();
}
return hres;
}
HRESULT _GetDeviceIDFromHDevNotify(HDEVNOTIFY hdevnotify,
LPWSTR pszDeviceID, DWORD cchDeviceID, DWORD* pcchRequired)
{
// This should be a drive not a volume. Cannot get Media arrival/removal
// from volume.
CNamedElemList* pnel;
HRESULT hres = CHWEventDetectorHelper::GetList(HWEDLIST_HANDLENOTIF, &pnel);
if (S_OK == hres)
{
CNamedElemEnum* penum;
hres = pnel->GetEnum(&penum);
if (SUCCEEDED(hres))
{
CNamedElem* pelem;
BOOL fFoundIt = FALSE;
while (!fFoundIt && SUCCEEDED(hres = penum->Next(&pelem)) &&
(S_FALSE != hres))
{
CHandleNotif* phnotif = (CHandleNotif*)pelem;
HDEVNOTIFY hdevnotifyLocal = phnotif->GetDeviceNotifyHandle();
if (hdevnotifyLocal == hdevnotify)
{
// Found it
hres = phnotif->GetName(pszDeviceID, cchDeviceID,
pcchRequired);
fFoundIt = TRUE;
}
pelem->RCRelease();
}
penum->RCRelease();
}
pnel->RCRelease();
}
return hres;
}
HRESULT _GetDeviceID(LPCWSTR pszName, LPWSTR pszDeviceID, DWORD cchDeviceID)
{
HRESULT hres;
if (*pszName && (TEXT('\\') == *pszName) &&
*(pszName + 1) && (TEXT('\\') == *(pszName + 1)) &&
*(pszName + 2) && (TEXT('?') == *(pszName + 2)))
{
hres = SafeStrCpyN(pszDeviceID, pszName, cchDeviceID);
}
else
{
hres = _GetDeviceIDFromMtPtName(pszName, pszDeviceID, cchDeviceID);
}
return hres;
}
HRESULT _GetVolume(LPCWSTR pszVolume, CVolume** ppvol)
{
WCHAR szDeviceID[MAX_DEVICEID];
HRESULT hr = _GetDeviceID(pszVolume, szDeviceID, ARRAYSIZE(szDeviceID));
*ppvol = NULL;
if (SUCCEEDED(hr) && (S_FALSE != hr))
{
CNamedElemList* pnel;
hr = CHWEventDetectorHelper::GetList(HWEDLIST_VOLUME, &pnel);
if (S_OK == hr)
{
CNamedElem* pelem;
hr = pnel->Get(szDeviceID, &pelem);
if (SUCCEEDED(hr) && (S_FALSE != hr))
{
*ppvol = (CVolume*)pelem;
// Do not release
}
pnel->RCRelease();
}
}
return hr;
}
HRESULT _GetAltDeviceID(LPCWSTR pszDeviceID, LPWSTR pszDeviceIDAlt,
DWORD cchDeviceIDAlt)
{
CNamedElemList* pnel;
HRESULT hres = CHWEventDetectorHelper::GetList(HWEDLIST_MTPT, &pnel);
if (S_OK == hres)
{
CNamedElemEnum* penum;
hres = pnel->GetEnum(&penum);
if (SUCCEEDED(hres))
{
BOOL fFoundIt = FALSE;
CNamedElem* pelem;
while (!fFoundIt && SUCCEEDED(hres = penum->Next(&pelem)) &&
(S_FALSE != hres))
{
CMtPt* pmtpt = (CMtPt*)pelem;
WCHAR szDeviceIDVolume[MAX_DEVICEID];
hres = pmtpt->GetVolumeName(szDeviceIDVolume,
ARRAYSIZE(szDeviceIDVolume));
if (SUCCEEDED(hres))
{
if (!lstrcmp(szDeviceIDVolume, pszDeviceID))
{
// Use me!
DWORD cchReq;
fFoundIt = TRUE;
hres = pmtpt->GetName(pszDeviceIDAlt,
cchDeviceIDAlt, &cchReq);
}
}
pelem->RCRelease();
}
penum->RCRelease();
}
pnel->RCRelease();
}
return hres;
}
HRESULT _GetDeviceNumberInfoFromHandle(HANDLE hDevice, DEVICE_TYPE* pdevtype,
ULONG* pulDeviceNumber, ULONG* pulPartitionNumber)
{
HRESULT hr;
STORAGE_DEVICE_NUMBER sdn = {0};
DWORD dwDummy;
BOOL b = DeviceIoControl(hDevice, IOCTL_STORAGE_GET_DEVICE_NUMBER,
NULL, 0, &sdn, sizeof(sdn), &dwDummy, NULL);
if (b)
{
*pdevtype = sdn.DeviceType;
*pulDeviceNumber = sdn.DeviceNumber;
*pulPartitionNumber = sdn.PartitionNumber;
hr = S_OK;
}
else
{
hr = S_FALSE;
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
HRESULT _CoTaskMemCopy(LPCWSTR pszSrc, LPWSTR* ppszDest)
{
HRESULT hres = S_OK;
*ppszDest = (LPWSTR)CoTaskMemAlloc((lstrlen(pszSrc) + 1) * sizeof(WCHAR));
if (*ppszDest)
{
lstrcpy(*ppszDest, pszSrc);
}
else
{
*ppszDest = NULL;
hres = E_OUTOFMEMORY;
}
return hres;
}
void _CoTaskMemFree(void* pv)
{
if (pv)
{
CoTaskMemFree(pv);
}
}
HRESULT DupString(LPCWSTR pszSrc, LPWSTR* ppszDest)
{
HRESULT hres;
*ppszDest = (LPWSTR)LocalAlloc(LPTR, (lstrlen(pszSrc) + 1) *
sizeof(WCHAR));
if (*ppszDest)
{
lstrcpy(*ppszDest, pszSrc);
hres = S_OK;
}
else
{
hres = E_OUTOFMEMORY;
}
return hres;
}
///////////////////////////////////////////////////////////////////////////////
//
HRESULT _GetDeviceInstance(LPCWSTR pszDeviceIntfID, DEVINST* pdevinst,
GUID* pguidInterface)
{
HRESULT hres = S_FALSE;
// not thread safe
static WCHAR szDeviceIntfIDLast[MAX_DEVICEID] = TEXT("");
static DEVINST devinstLast;
static GUID guidInterfaceLast;
// Cached
if (!lstrcmpi(szDeviceIntfIDLast, pszDeviceIntfID))
{
// Yep
*pdevinst = devinstLast;
*pguidInterface = guidInterfaceLast;
hres = S_OK;
}
else
{
// No
HDEVINFO hdevinfo = SetupDiCreateDeviceInfoList(NULL, NULL);
*pdevinst = NULL;
if (INVALID_HANDLE_VALUE != hdevinfo)
{
SP_DEVICE_INTERFACE_DATA sdid = {0};
sdid.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
if (SetupDiOpenDeviceInterface(hdevinfo, pszDeviceIntfID, 0, &sdid))
{
DWORD cbsdidd = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) +
(MAX_DEVICE_ID_LEN * sizeof(WCHAR));
SP_DEVINFO_DATA sdd = {0};
SP_DEVICE_INTERFACE_DETAIL_DATA* psdidd =
(SP_DEVICE_INTERFACE_DETAIL_DATA*)LocalAlloc(LPTR, cbsdidd);
if (psdidd)
{
psdidd->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
sdd.cbSize = sizeof(SP_DEVINFO_DATA);
// SetupDiGetDeviceInterfaceDetail (below) requires that the
// cbSize member of SP_DEVICE_INTERFACE_DETAIL_DATA be set
// to the size of the fixed part of the structure, and to pass
// the size of the full thing as the 4th param.
if (SetupDiGetDeviceInterfaceDetail(hdevinfo, &sdid, psdidd,
cbsdidd, NULL, &sdd))
{
*pdevinst = sdd.DevInst;
*pguidInterface = sdid.InterfaceClassGuid;
hres = S_OK;
}
LocalFree((HLOCAL)psdidd);
}
}
SetupDiDestroyDeviceInfoList(hdevinfo);
}
if (SUCCEEDED(hres) && (S_FALSE != hres))
{
// Cache it
if (SUCCEEDED(SafeStrCpyN(szDeviceIntfIDLast, pszDeviceIntfID,
ARRAYSIZE(szDeviceIntfIDLast))))
{
devinstLast = *pdevinst;
guidInterfaceLast = *pguidInterface;
}
else
{
szDeviceIntfIDLast[0] = 0;
}
}
else
{
szDeviceIntfIDLast[0] = 0;
}
}
return hres;
}
HRESULT _GetDeviceInstanceFromDevNode(LPCWSTR pszDeviceNode, DEVINST* pdevinst)
{
HRESULT hres = S_FALSE;
HDEVINFO hdevinfo = SetupDiCreateDeviceInfoList(NULL, NULL);
*pdevinst = NULL;
if (INVALID_HANDLE_VALUE != hdevinfo)
{
SP_DEVINFO_DATA sdd = {0};
sdd.cbSize = sizeof(SP_DEVINFO_DATA);
if (SetupDiOpenDeviceInfo(hdevinfo, pszDeviceNode, NULL, 0, &sdd))
{
*pdevinst = sdd.DevInst;
hres = S_OK;
}
SetupDiDestroyDeviceInfoList(hdevinfo);
}
return hres;
}
///////////////////////////////////////////////////////////////////////////////
//
void CHWEventDetectorHelper::TraceDiagnosticMsg(LPWSTR pszMsg, ...)
{
// Big buffer, but there's no wvsnprintf, and device names can get
// really big.
WCHAR szBuf[2048];
int cch;
int cch2 = wsprintf(szBuf, TEXT("~0x%08X~"), GetCurrentThreadId());
va_list vArgs;
va_start(vArgs, pszMsg);
cch = wvsprintf(szBuf + cch2, pszMsg, vArgs) + cch2;
va_end(vArgs);
if (cch < ARRAYSIZE(szBuf) - 2)
{
szBuf[cch] = TEXT('\r');
szBuf[cch + 1] = TEXT('\n');
szBuf[cch + 2] = 0;
cch += 3;
}
#ifndef FEATURE_USELIVELOGGING
WriteToLogFileW(szBuf);
#else // FEATURE_USELIVELOGGING
CallNamedPipe(TEXT("\\\\.\\pipe\\ShellService_Diagnostic"), szBuf,
cch * sizeof(WCHAR), NULL, 0, NULL, NMPWAIT_NOWAIT);
#endif // FEATURE_USELIVELOGGING
}
//static
HRESULT CHWEventDetectorHelper::CheckDiagnosticAppPresence()
{
DWORD dwNow = GetTickCount();
BOOL fPerformCheckNow = FALSE;
if (dwNow < _dwDiagAppLastCheck)
{
// We wrapped, or init case of -1
fPerformCheckNow = TRUE;
}
else
{
if (dwNow > (_dwDiagAppLastCheck + 15 * 1000))
{
fPerformCheckNow = TRUE;
}
}
if (fPerformCheckNow)
{
#ifndef FEATURE_USELIVELOGGING
DWORD dwType;
DWORD dwUseLogFile = 0;
DWORD cbSize = sizeof(dwUseLogFile);
BOOL fReCheck = ((ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\ShellHWDetection"), TEXT("LogFile"), &dwType, (void *)&dwUseLogFile, &cbSize)) &&
(REG_DWORD == dwType) &&
(sizeof(dwUseLogFile) == cbSize) &&
(0 != dwUseLogFile));
#else // FEATURE_USELIVELOGGING
HANDLE hEvent = OpenEvent(SYNCHRONIZE, FALSE,
TEXT("ShellService_Diagnostic"));
BOOL fReCheck = hEvent;
CloseHandle(hEvent);
#endif // FEATURE_USELIVELOGGING
if (fReCheck)
{
// Yep, it's there!
if (!_fDiagnosticAppPresent)
{
TRACE(TF_SHHWDTCTDTCT, TEXT("Diagnostic App appeared!"));
}
_fDiagnosticAppPresent = TRUE;
}
else
{
if (_fDiagnosticAppPresent)
{
TRACE(TF_SHHWDTCTDTCT, TEXT("Diagnostic App disappeared!"));
}
_fDiagnosticAppPresent = FALSE;
}
_dwDiagAppLastCheck = dwNow;
}
return S_OK;
}
//static
HRESULT CHWEventDetectorHelper::SetServiceStatusHandle(
SERVICE_STATUS_HANDLE ssh)
{
_ssh = ssh;
return S_OK;
}
//static
HRESULT CHWEventDetectorHelper::GetList(HWEDLIST hwedlist,
CNamedElemList** ppnel)
{
HRESULT hres;
CNamedElemList* pnel = _rgpnel[hwedlist];
if (pnel)
{
pnel->RCAddRef();
}
*ppnel = pnel;
hres = *ppnel ? S_OK : E_FAIL;
if (S_FALSE == hres)
{
TRACE(TF_SHHWDTCTDTCT, TEXT("CHWEventDetectorHelper::GetList S_FALSE'd"));
}
return hres;
}
//static
HRESULT CHWEventDetectorHelper::DeleteLists()
{
for (DWORD dw = 0; dw < ARRAYSIZE(_rgpnel); ++dw)
{
if (_rgpnel[dw])
{
_rgpnel[dw]->EmptyList();
_rgpnel[dw]->RCRelease();
_rgpnel[dw] = NULL;
}
}
return S_OK;
}
//static
HRESULT CHWEventDetectorHelper::CreateLists()
{
HRESULT hres = S_FALSE;
if (!_fListCreated)
{
for (DWORD dw = 0; SUCCEEDED(hres) && (dw < ARRAYSIZE(_rgpnel)); ++dw)
{
_rgpnel[dw] = new CNamedElemList();
if (!_rgpnel[dw])
{
hres = E_OUTOFMEMORY;
// should RCRelease the already allocated ones
}
}
if (SUCCEEDED(hres))
{
// Initialize them ALL first
hres = _rgpnel[HWEDLIST_HANDLENOTIF]->Init(
CHandleNotif::Create, NULL);
if (SUCCEEDED(hres))
{
hres = _rgpnel[HWEDLIST_VOLUME]->Init(CVolume::Create,
CVolume::GetFillEnum);
}
if (SUCCEEDED(hres))
{
hres = _rgpnel[HWEDLIST_DISK]->Init(
CDisk::Create, CDisk::GetFillEnum);
}
if (SUCCEEDED(hres))
{
hres = _rgpnel[HWEDLIST_MISCDEVINTF]->Init(
CMiscDeviceInterface::Create, NULL);
}
if (SUCCEEDED(hres))
{
hres = _rgpnel[HWEDLIST_MISCDEVNODE]->Init(
CMiscDeviceNode::Create, NULL);
}
if (SUCCEEDED(hres))
{
hres = _rgpnel[HWEDLIST_MTPT]->Init(CMtPt::Create, NULL);
}
if (SUCCEEDED(hres))
{
hres = _rgpnel[HWEDLIST_ADVISECLIENT]->Init(CAdviseClient::Create, NULL);
}
#ifdef DEBUG
if (SUCCEEDED(hres))
{
_rgpnel[HWEDLIST_HANDLENOTIF]->InitDebug(TEXT("CHandleNotif"));
_rgpnel[HWEDLIST_VOLUME]->InitDebug(TEXT("CVolume"));
_rgpnel[HWEDLIST_DISK]->InitDebug(TEXT("CDisk"));
_rgpnel[HWEDLIST_MISCDEVINTF]->InitDebug(TEXT("CMiscDeviceInterface"));
_rgpnel[HWEDLIST_MISCDEVNODE]->InitDebug(TEXT("CMiscDeviceNode"));
_rgpnel[HWEDLIST_MTPT]->InitDebug(TEXT("CMtPt"));
_rgpnel[HWEDLIST_ADVISECLIENT]->InitDebug(TEXT("CAdviseClient"));
}
#endif
if (SUCCEEDED(hres))
{
_fListCreated = TRUE;
TRACE(TF_SHHWDTCTDTCT, TEXT("CNamedElemList's created"));
}
}
}
return hres;
}
//static
HRESULT CHWEventDetectorHelper::FillLists()
{
ASSERT(_fListCreated);
// Enumerate those having an enumerator
HRESULT hres = _rgpnel[HWEDLIST_DISK]->ReEnum();
if (SUCCEEDED(hres))
{
hres = _rgpnel[HWEDLIST_VOLUME]->ReEnum();
}
return hres;
}
//static
HRESULT CHWEventDetectorHelper::EmptyLists()
{
for (DWORD dw = 0; dw < HWEDLIST_COUNT_OF_LISTS; ++dw)
{
_rgpnel[dw]->EmptyList();
}
_fListCreated = FALSE;
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
//
// static
HRESULT CHWEventDetectorHelper::InitDockState()
{
BOOL fDocked;
HRESULT hr = _MachineIsDocked(&fDocked);
if (SUCCEEDED(hr) && (S_FALSE != hr))
{
CHWEventDetectorHelper::_fDocked = fDocked;
}
return hr;
}
// static
HRESULT CHWEventDetectorHelper::DockStateChanged(BOOL* pfDockStateChanged)
{
BOOL fDocked;
HRESULT hr = _MachineIsDocked(&fDocked);
if (SUCCEEDED(hr) && (S_FALSE != hr))
{
if (fDocked != _fDocked)
{
*pfDockStateChanged = TRUE;
}
// Update it too
CHWEventDetectorHelper::_fDocked = fDocked;
}
return hr;
}
//static
HRESULT CHWEventDetectorHelper::RegisterDeviceNotification(
PVOID pvNotificationFilter, HDEVNOTIFY* phdevnotify,
BOOL fAllInterfaceClasses)
{
HRESULT hres;
DWORD dwFlags;
ASSERT(_ssh);
if (fAllInterfaceClasses)
{
dwFlags = DEVICE_NOTIFY_ALL_INTERFACE_CLASSES;
}
else
{
dwFlags = 0;
}
TRACE(TF_SHHWDTCTDTCTDETAILED,
TEXT("Entered CHWEventDetectorImpl::RegisterDeviceNotification"));
#ifndef DEBUG
dwFlags |= DEVICE_NOTIFY_SERVICE_HANDLE;
*phdevnotify = ::RegisterDeviceNotification(_ssh, pvNotificationFilter,
dwFlags);
#else
if (IsWindow((HWND)_ssh))
{
dwFlags |= DEVICE_NOTIFY_WINDOW_HANDLE;
*phdevnotify = ::RegisterDeviceNotification(_ssh, pvNotificationFilter,
dwFlags);
}
else
{
dwFlags |= DEVICE_NOTIFY_SERVICE_HANDLE;
*phdevnotify = ::RegisterDeviceNotification(_ssh, pvNotificationFilter,
dwFlags);
}
#endif
if (*phdevnotify)
{
TRACE(TF_SHHWDTCTDTCTDETAILED,
TEXT("RegisterDeviceNotification SUCCEEDED: 0x%08X"),
*phdevnotify);
hres = S_OK;
}
else
{
hres = S_FALSE;
}
return hres;
}
// static
HRESULT CHWEventDetectorHelper::Init()
{
_cs.Init();
_fInited = TRUE;
return S_OK;
}
// static
HRESULT CHWEventDetectorHelper::Cleanup()
{
_cs.Enter();
CloseLogFile();
if (_pieo)
{
_pieo->RCRelease();
_pieo = NULL;
}
_fInited = FALSE;
_cs.Leave();
_cs.Delete();
return S_OK;
}
// static
HRESULT CHWEventDetectorHelper::GetImpersonateEveryone(
CImpersonateEveryone** ppieo)
{
HRESULT hr;
*ppieo = NULL;
if (_fInited)
{
_cs.Enter();
if (!_pieo)
{
_pieo = new CImpersonateEveryone();
}
if (_pieo)
{
_pieo->RCAddRef();
*ppieo = _pieo;
hr = S_OK;
}
else
{
hr = E_OUTOFMEMORY;
}
_cs.Leave();
}
else
{
hr = E_UNEXPECTED;
}
return hr;
}
#ifdef DEBUG
void CHWEventDetectorHelper::_DbgAssertValidState()
{
for (DWORD dw = 0; dw < ARRAYSIZE(_rgpnel); ++dw)
{
if (_rgpnel[dw])
{
// Need to disable this since there is 2 services using this data,
// and it is now feasible to have a refcount diff than 1 at the end
// of an operation.
// _rgpnel[dw]->AssertAllElemsRefCount1();
_rgpnel[dw]->AssertNoDuplicate();
}
}
}
#endif
///////////////////////////////////////////////////////////////////////////////
//
HRESULT CHandleNotifTarget::HNTInitSurpriseRemoval()
{
_fSurpriseRemovalAware = TRUE;
return S_OK;
}
BOOL CHandleNotifTarget::HNTIsSurpriseRemovalAware()
{
return _fSurpriseRemovalAware;
}
CHandleNotifTarget::CHandleNotifTarget() : _fSurpriseRemovalAware(FALSE)
{}
CHandleNotifTarget::~CHandleNotifTarget()
{}
///////////////////////////////////////////////////////////////////////////////
// Interface enumerator
HRESULT CIntfFillEnum::Next(LPWSTR pszElemName, DWORD cchElemName,
DWORD* pcchRequired)
{
ASSERT (pszElemName && cchElemName && pcchRequired);
HRESULT hr = S_FALSE;
BOOL fFound = FALSE;
while (SUCCEEDED(hr) && !fFound && _pszNextInterface && *_pszNextInterface)
{
// Do we have a filter?
if (_iecb)
{
// Yep
hr = (_iecb)(_pszNextInterface);
}
else
{
hr = S_OK;
}
if (SUCCEEDED(hr))
{
// Was it filtered out?
if (S_FALSE != hr)
{
// No
hr = SafeStrCpyNReq(pszElemName, _pszNextInterface,
cchElemName, pcchRequired);
if (SUCCEEDED(hr))
{
fFound = TRUE;
_pszNextInterface += lstrlen(_pszNextInterface) + 1;
}
}
else
{
// Yes, lopp again
_pszNextInterface += lstrlen(_pszNextInterface) + 1;
}
}
}
return hr;
}
HRESULT CIntfFillEnum::_Init(const GUID* pguidInterface,
INTERFACEENUMFILTERCALLBACK iecb)
{
HRESULT hr;
HMACHINE hMachine = NULL;
ULONG ulSize;
ULONG ulFlags = CM_GET_DEVICE_INTERFACE_LIST_PRESENT;
CONFIGRET cr = CM_Get_Device_Interface_List_Size_Ex(&ulSize,
(GUID*)pguidInterface, NULL, ulFlags, hMachine);
_iecb = iecb;
if ((CR_SUCCESS == cr) && (ulSize > 1))
{
_pszNextInterface = _pszDeviceInterface =
(LPTSTR)LocalAlloc(LPTR, ulSize * sizeof(TCHAR));
if (_pszDeviceInterface)
{
cr = CM_Get_Device_Interface_List_Ex((GUID*)pguidInterface, NULL,
_pszDeviceInterface, ulSize, ulFlags, hMachine);
if (CR_SUCCESS == cr)
{
hr = S_OK;
}
else
{
hr = S_FALSE;
}
}
else
{
hr = E_OUTOFMEMORY;
}
}
else
{
hr = S_FALSE;
}
return hr;
}
CIntfFillEnum::CIntfFillEnum() : _pszDeviceInterface(NULL),
_pszNextInterface(NULL)
{}
CIntfFillEnum::~CIntfFillEnum()
{
if (_pszDeviceInterface)
{
LocalFree((HLOCAL)_pszDeviceInterface);
}
}
///////////////////////////////////////////////////////////////////////////////
//
HRESULT _MachineIsDocked(BOOL* pfDocked)
{
HRESULT hr;
HW_PROFILE_INFO hpi;
if (GetCurrentHwProfile(&hpi))
{
DWORD dwDockInfo = hpi.dwDockInfo &
(DOCKINFO_DOCKED | DOCKINFO_UNDOCKED);
if ((DOCKINFO_DOCKED | DOCKINFO_UNDOCKED) == dwDockInfo)
{
// Not dockable
*pfDocked = FALSE;
}
else
{
*pfDocked = (DOCKINFO_DOCKED & dwDockInfo);
#ifdef DEBUG
// Make sure we understand how this works
if (!(*pfDocked))
{
ASSERT(DOCKINFO_UNDOCKED & dwDockInfo);
}
#endif
}
hr = S_OK;
}
else
{
hr = S_FALSE;
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
HRESULT _BuildMoniker(LPCWSTR /*pszEventHandler*/, REFCLSID rclsid,
DWORD dwSessionID, IMoniker** ppmoniker)
{
IMoniker* pmonikerClass;
HRESULT hr = CreateClassMoniker(rclsid, &pmonikerClass);
*ppmoniker = NULL;
if (SUCCEEDED(hr))
{
IMoniker* pmonikerSession;
WCHAR szSessionID[30];
// should be safe
wsprintf(szSessionID, TEXT("session:%d"), dwSessionID);
hr = CreateItemMoniker(TEXT("!"), szSessionID, &pmonikerSession);
if (SUCCEEDED(hr))
{
hr = pmonikerClass->ComposeWith(pmonikerSession, FALSE, ppmoniker);
// Do not Release, we return it!
pmonikerSession->Release();
}
pmonikerClass->Release();
}
return hr;
}
EXTERN_C HRESULT WINAPI CreateHardwareEventMoniker(REFCLSID clsid, LPCTSTR pszEventHandler, IMoniker **ppmoniker)
{
HRESULT hr;
if (ppmoniker)
{
if (pszEventHandler && *pszEventHandler)
{
DWORD dwSessionID = NtCurrentPeb()->SessionId;
hr = _BuildMoniker(pszEventHandler, clsid, dwSessionID, ppmoniker);
}
else
{
hr = E_INVALIDARG;
}
}
else
{
hr = E_POINTER;
}
return hr;
}