Leaked source code of windows server 2003
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.

616 lines
16 KiB

  1. /****************************************************************************
  2. *
  3. * DEVICE.CPP
  4. *
  5. * Copyright (C) Microsoft Corporation 1996-1999
  6. * All rights reserved
  7. *
  8. ***************************************************************************/
  9. #include "Sampusd.h"
  10. #include <stdio.h>
  11. VOID
  12. FileChangeThread(
  13. LPVOID lpParameter
  14. );
  15. UsdSampDevice::UsdSampDevice( LPUNKNOWN punkOuter ):
  16. m_cRef(1),
  17. m_punkOuter(NULL),
  18. m_fValid(FALSE),
  19. m_pDcb(NULL),
  20. m_DeviceDataHandle(INVALID_HANDLE_VALUE),
  21. m_hSignalEvent(INVALID_HANDLE_VALUE),
  22. m_hThread(NULL),
  23. m_guidLastEvent(GUID_NULL),
  24. m_EventSignalState(TRUE)
  25. {
  26. //
  27. // See if we are aggregated. If we are ( which will be almost always the case )
  28. // save pointer to controlling Unknown , so subsequent calls will be delegated
  29. // If not, set the same pointer to "this" .
  30. // N.b. cast below is important in order to point to right virtual table
  31. //
  32. if (punkOuter) {
  33. m_punkOuter = punkOuter;
  34. }
  35. else {
  36. m_punkOuter = reinterpret_cast<IUnknown*>
  37. (static_cast<INonDelegatingUnknown*>
  38. (this));
  39. }
  40. m_hShutdownEvent = CreateEvent( NULL, // Attributes
  41. TRUE, // Manual reset
  42. FALSE, // Initial state - not set
  43. NULL ); // Anonymous
  44. if ( (INVALID_HANDLE_VALUE !=m_hShutdownEvent) && (NULL != m_hShutdownEvent)) {
  45. m_fValid = TRUE;
  46. }
  47. }
  48. UsdSampDevice::~UsdSampDevice( VOID )
  49. {
  50. // Kill notification thread if it exists
  51. SetNotificationHandle(NULL);
  52. if (m_hShutdownEvent && m_hShutdownEvent!=INVALID_HANDLE_VALUE) {
  53. CloseHandle(m_hShutdownEvent);
  54. }
  55. if( INVALID_HANDLE_VALUE != m_DeviceDataHandle ) {
  56. CloseHandle( m_DeviceDataHandle );
  57. }
  58. if (m_pszDeviceNameA) {
  59. delete [] m_pszDeviceNameA;
  60. m_pszDeviceNameA = NULL;
  61. }
  62. }
  63. STDMETHODIMP UsdSampDevice::GetCapabilities( PSTI_USD_CAPS pUsdCaps )
  64. {
  65. HRESULT hres = STI_OK;
  66. ZeroMemory(pUsdCaps,sizeof(*pUsdCaps));
  67. pUsdCaps->dwVersion = STI_VERSION;
  68. // We do support device notifications, but not reuiring polling
  69. pUsdCaps->dwGenericCaps = STI_USD_GENCAP_NATIVE_PUSHSUPPORT;
  70. return hres;
  71. }
  72. STDMETHODIMP UsdSampDevice::GetStatus( PSTI_DEVICE_STATUS pDevStatus )
  73. {
  74. HRESULT hres = STI_OK;
  75. //
  76. // If we are asked, verify whether device is online
  77. //
  78. pDevStatus->dwOnlineState = 0L;
  79. if( pDevStatus->StatusMask & STI_DEVSTATUS_ONLINE_STATE ) {
  80. if (INVALID_HANDLE_VALUE != m_DeviceDataHandle) {
  81. // File is always on-line
  82. pDevStatus->dwOnlineState |= STI_ONLINESTATE_OPERATIONAL;
  83. }
  84. }
  85. //
  86. // If we are asked, verify state of event
  87. //
  88. pDevStatus->dwEventHandlingState &= ~STI_EVENTHANDLING_PENDING;
  89. if( pDevStatus->StatusMask & STI_DEVSTATUS_EVENTS_STATE ) {
  90. //
  91. // Launch app very first time we load
  92. //
  93. if(m_EventSignalState) {
  94. pDevStatus->dwEventHandlingState = STI_EVENTHANDLING_PENDING;
  95. m_guidLastEvent = guidEventFirstLoaded;
  96. m_EventSignalState = FALSE;
  97. }
  98. if (IsChangeDetected(NULL,FALSE)) {
  99. pDevStatus->dwEventHandlingState |= STI_EVENTHANDLING_PENDING;
  100. }
  101. }
  102. return hres;
  103. }
  104. STDMETHODIMP UsdSampDevice::DeviceReset( VOID )
  105. {
  106. HRESULT hres = STI_OK;
  107. // Reset current active device
  108. if (INVALID_HANDLE_VALUE != m_DeviceDataHandle) {
  109. ::SetFilePointer( m_DeviceDataHandle, 0, NULL, FILE_BEGIN);
  110. m_dwLastOperationError = ::GetLastError();
  111. }
  112. hres = HRESULT_FROM_WIN32(m_dwLastOperationError);
  113. return hres;
  114. }
  115. STDMETHODIMP UsdSampDevice::Diagnostic( LPDIAG pBuffer )
  116. {
  117. HRESULT hres = STI_OK;
  118. // Initialize response buffer
  119. pBuffer->dwStatusMask = 0;
  120. ZeroMemory(&pBuffer->sErrorInfo,sizeof(pBuffer->sErrorInfo));
  121. pBuffer->sErrorInfo.dwGenericError = NOERROR;
  122. pBuffer->sErrorInfo.dwVendorError = 0;
  123. // This example always returns that the unit passed diagnostics
  124. return hres;
  125. }
  126. STDMETHODIMP UsdSampDevice:: SetNotificationHandle( HANDLE hEvent )
  127. // SYNCHRONIZED
  128. {
  129. HRESULT hres = STI_OK;
  130. TAKE_CRIT_SECT t(m_cs);
  131. if (hEvent && (hEvent !=INVALID_HANDLE_VALUE)) {
  132. m_hSignalEvent = hEvent;
  133. if (m_DeviceDataHandle != INVALID_HANDLE_VALUE) {
  134. //
  135. // if we need to be asyncronous, create notification thread
  136. //
  137. m_dwAsync = 1;
  138. m_guidLastEvent = GUID_NULL;
  139. if (m_dwAsync) {
  140. if (!m_hThread) {
  141. DWORD dwThread;
  142. m_hThread = ::CreateThread(NULL,
  143. 0,
  144. (LPTHREAD_START_ROUTINE)FileChangeThread,
  145. (LPVOID)this,
  146. 0,
  147. &dwThread);
  148. m_pDcb->WriteToErrorLog(STI_TRACE_INFORMATION,
  149. L"SampUSD::Enabling notification monitoring",
  150. NOERROR) ;
  151. }
  152. }
  153. else {
  154. hres = STIERR_UNSUPPORTED;
  155. }
  156. }
  157. else {
  158. hres = STIERR_NOT_INITIALIZED;
  159. }
  160. }
  161. else {
  162. //
  163. // Disable hardware notifications
  164. //
  165. SetEvent(m_hShutdownEvent);
  166. if ( m_hThread ) {
  167. WaitForSingleObject(m_hThread,400);
  168. CloseHandle(m_hThread);
  169. m_hThread = NULL;
  170. m_guidLastEvent = GUID_NULL;
  171. }
  172. m_pDcb->WriteToErrorLog(STI_TRACE_INFORMATION,
  173. L"SampUSD::Disabling notification monitoring",
  174. NOERROR) ;
  175. }
  176. return hres;
  177. }
  178. STDMETHODIMP UsdSampDevice::GetNotificationData( LPSTINOTIFY pBuffer )
  179. // SYNCHRONIZED
  180. {
  181. HRESULT hres = STI_OK;
  182. TAKE_CRIT_SECT t(m_cs);
  183. //
  184. // If we have notification ready - return it's guid
  185. //
  186. if (!IsEqualIID(m_guidLastEvent,GUID_NULL)) {
  187. pBuffer->guidNotificationCode = m_guidLastEvent;
  188. m_guidLastEvent = GUID_NULL;
  189. pBuffer->dwSize = sizeof(STINOTIFY);
  190. }
  191. else {
  192. hres = STIERR_NOEVENTS;
  193. }
  194. return hres;
  195. }
  196. STDMETHODIMP UsdSampDevice::Escape( STI_RAW_CONTROL_CODE EscapeFunction,
  197. LPVOID pInData,
  198. DWORD cbInDataSize,
  199. LPVOID pOutData,
  200. DWORD cbOutDataSize,
  201. LPDWORD pcbActualData )
  202. {
  203. HRESULT hres = STI_OK;
  204. //
  205. // Write indata to device if needed.
  206. //
  207. hres = STIERR_UNSUPPORTED;
  208. return hres;
  209. }
  210. STDMETHODIMP UsdSampDevice::GetLastError( LPDWORD pdwLastDeviceError )
  211. // SYNCHRONIZED
  212. {
  213. HRESULT hres = STI_OK;
  214. TAKE_CRIT_SECT t(m_cs);
  215. if ( IsBadWritePtr( pdwLastDeviceError,4 ))
  216. {
  217. hres = STIERR_INVALID_PARAM;
  218. }
  219. else
  220. {
  221. *pdwLastDeviceError = m_dwLastOperationError;
  222. }
  223. return hres;
  224. }
  225. STDMETHODIMP UsdSampDevice::GetLastErrorInfo(STI_ERROR_INFO *pLastErrorInfo)
  226. // SYNCHRONIZED
  227. {
  228. HRESULT hres = STI_OK;
  229. TAKE_CRIT_SECT t(m_cs);
  230. if ( IsBadWritePtr( pLastErrorInfo,4 ))
  231. {
  232. hres = STIERR_INVALID_PARAM;
  233. }
  234. else
  235. {
  236. pLastErrorInfo->dwGenericError = m_dwLastOperationError;
  237. pLastErrorInfo->szExtendedErrorText[0] = L'\0';
  238. }
  239. return hres;
  240. }
  241. STDMETHODIMP UsdSampDevice::LockDevice( VOID )
  242. {
  243. HRESULT hres = STI_OK;
  244. return hres;
  245. }
  246. STDMETHODIMP UsdSampDevice::UnLockDevice( VOID )
  247. {
  248. HRESULT hres = STI_OK;
  249. return hres;
  250. }
  251. STDMETHODIMP UsdSampDevice::RawReadData( LPVOID lpBuffer, LPDWORD lpdwNumberOfBytes,
  252. LPOVERLAPPED lpOverlapped )
  253. {
  254. HRESULT hres = STI_OK;
  255. BOOL fRet = FALSE;
  256. DWORD dwBytesReturned = 0;
  257. if (INVALID_HANDLE_VALUE != m_DeviceDataHandle)
  258. {
  259. m_dwLastOperationError = NOERROR;
  260. fRet = ::ReadFile(m_DeviceDataHandle,
  261. lpBuffer,
  262. *lpdwNumberOfBytes,
  263. lpdwNumberOfBytes,
  264. lpOverlapped);
  265. if (!fRet) {
  266. m_dwLastOperationError = ::GetLastError();
  267. }
  268. hres = HRESULT_FROM_WIN32(m_dwLastOperationError);
  269. }
  270. else
  271. {
  272. hres = STIERR_NOT_INITIALIZED;
  273. }
  274. return hres;
  275. }
  276. STDMETHODIMP UsdSampDevice::RawWriteData( LPVOID lpBuffer, DWORD dwNumberOfBytes,
  277. LPOVERLAPPED lpOverlapped )
  278. {
  279. HRESULT hres = STI_OK;
  280. BOOL fRet = FALSE;;
  281. DWORD dwBytesReturned = 0;
  282. if (INVALID_HANDLE_VALUE != m_DeviceDataHandle)
  283. {
  284. fRet = ::WriteFile(m_DeviceDataHandle,
  285. lpBuffer,
  286. dwNumberOfBytes,
  287. &dwBytesReturned,
  288. lpOverlapped);
  289. if (!fRet) {
  290. m_dwLastOperationError = ::GetLastError();
  291. }
  292. hres = HRESULT_FROM_WIN32(m_dwLastOperationError);
  293. }
  294. else
  295. {
  296. hres = STIERR_NOT_INITIALIZED;
  297. }
  298. return hres;
  299. }
  300. STDMETHODIMP UsdSampDevice::RawReadCommand( LPVOID lpBuffer, LPDWORD lpdwNumberOfBytes,
  301. LPOVERLAPPED lpOverlapped )
  302. {
  303. HRESULT hres = STIERR_UNSUPPORTED;
  304. return hres;
  305. }
  306. STDMETHODIMP UsdSampDevice::RawWriteCommand( LPVOID lpBuffer, DWORD nNumberOfBytes,
  307. LPOVERLAPPED lpOverlapped )
  308. {
  309. HRESULT hres = STIERR_UNSUPPORTED;
  310. return hres;
  311. }
  312. STDMETHODIMP UsdSampDevice::Initialize( PSTIDEVICECONTROL pDcb, DWORD dwStiVersion,
  313. HKEY hParametersKey )
  314. {
  315. HRESULT hres = STI_OK;
  316. UINT uiNameLen = 0;
  317. WCHAR szDeviceNameW[MAX_PATH];
  318. if (!pDcb) {
  319. return STIERR_INVALID_PARAM;
  320. }
  321. *szDeviceNameW = L'\0';
  322. // Check STI specification version number
  323. m_pDcb = pDcb;
  324. m_pDcb->AddRef();
  325. // Get the name of the device port we need to open
  326. hres = m_pDcb->GetMyDevicePortName(szDeviceNameW,sizeof(szDeviceNameW)/sizeof(WCHAR));
  327. if (!SUCCEEDED(hres) || !*szDeviceNameW) {
  328. return hres;
  329. }
  330. // Convert name to SBCS
  331. uiNameLen = WideCharToMultiByte(CP_ACP, 0, szDeviceNameW, -1, NULL, NULL, 0, 0);
  332. if (!uiNameLen) {
  333. return STIERR_INVALID_PARAM;
  334. }
  335. m_pszDeviceNameA = new CHAR[uiNameLen+1];
  336. if (!m_pszDeviceNameA) {
  337. return STIERR_INVALID_PARAM;
  338. }
  339. WideCharToMultiByte(CP_ACP, 0, szDeviceNameW, -1, m_pszDeviceNameA, uiNameLen, 0, 0);
  340. //
  341. // Open device ourselves
  342. //
  343. m_DeviceDataHandle = CreateFileA( m_pszDeviceNameA,
  344. GENERIC_READ , // Access mask
  345. FILE_SHARE_READ | FILE_SHARE_WRITE, // Share mode
  346. NULL, // SA
  347. OPEN_EXISTING, // Create disposition
  348. FILE_ATTRIBUTE_SYSTEM, // Attributes
  349. NULL );
  350. m_dwLastOperationError = ::GetLastError();
  351. hres = (m_DeviceDataHandle != INVALID_HANDLE_VALUE) ?
  352. S_OK : MAKE_HRESULT(SEVERITY_ERROR,FACILITY_WIN32,m_dwLastOperationError);
  353. return hres;
  354. }
  355. VOID
  356. UsdSampDevice::
  357. RunNotifications(VOID)
  358. {
  359. HANDLE hNotifyFileSystemChange = INVALID_HANDLE_VALUE;
  360. DWORD dwErr;
  361. CHAR szDirPath[MAX_PATH];
  362. CHAR *pszLastSlash;
  363. //
  364. // Find name of the parent directory for out file and set up waiting on any
  365. // changes in it.
  366. //
  367. lstrcpyA(szDirPath,m_pszDeviceNameA);
  368. pszLastSlash = strrchr(szDirPath,'\\');
  369. if (pszLastSlash) {
  370. *pszLastSlash = '\0';
  371. }
  372. hNotifyFileSystemChange = FindFirstChangeNotificationA(
  373. szDirPath,
  374. FALSE,
  375. FILE_NOTIFY_CHANGE_SIZE |
  376. FILE_NOTIFY_CHANGE_LAST_WRITE |
  377. FILE_NOTIFY_CHANGE_FILE_NAME |
  378. FILE_NOTIFY_CHANGE_DIR_NAME
  379. );
  380. if (hNotifyFileSystemChange == INVALID_HANDLE_VALUE) {
  381. dwErr = ::GetLastError();
  382. return;
  383. }
  384. // Set initial values for time and size
  385. IsChangeDetected(NULL);
  386. //
  387. HANDLE hEvents[2] = {m_hShutdownEvent,hNotifyFileSystemChange};
  388. BOOL fLooping = TRUE;
  389. while (fLooping) {
  390. dwErr = ::WaitForMultipleObjects(2,
  391. hEvents,
  392. FALSE,
  393. INFINITE );
  394. switch(dwErr) {
  395. case WAIT_OBJECT_0+1:
  396. // Change detected - signal
  397. if (m_hSignalEvent !=INVALID_HANDLE_VALUE) {
  398. // Which change ?
  399. if (IsChangeDetected(&m_guidLastEvent)) {
  400. m_pDcb->WriteToErrorLog(STI_TRACE_INFORMATION,
  401. L"SampUSD::Monitored file change detected",
  402. NOERROR) ;
  403. ::SetEvent(m_hSignalEvent);
  404. }
  405. }
  406. // Go back to waiting for next file system event
  407. FindNextChangeNotification(hNotifyFileSystemChange);
  408. break;
  409. case WAIT_OBJECT_0:
  410. // Fall through
  411. default:
  412. fLooping = FALSE;
  413. }
  414. }
  415. FindCloseChangeNotification(hNotifyFileSystemChange);
  416. }
  417. BOOL
  418. UsdSampDevice::
  419. IsChangeDetected(
  420. GUID *pguidEvent,
  421. BOOL fRefresh // TRUE
  422. )
  423. {
  424. BOOL fRet = FALSE;
  425. LARGE_INTEGER liNewHugeSize;
  426. FILETIME ftLastWriteTime;
  427. DWORD dwError;
  428. WIN32_FILE_ATTRIBUTE_DATA sNewFileAttributes;
  429. ZeroMemory(&sNewFileAttributes,sizeof(sNewFileAttributes));
  430. dwError = NOERROR;
  431. if ( GetFileAttributesExA(m_pszDeviceNameA,GetFileExInfoStandard, &sNewFileAttributes)) {
  432. ftLastWriteTime =sNewFileAttributes.ftLastWriteTime;
  433. liNewHugeSize.LowPart = sNewFileAttributes.nFileSizeLow;
  434. liNewHugeSize.HighPart= sNewFileAttributes.nFileSizeHigh ;
  435. }
  436. else {
  437. BY_HANDLE_FILE_INFORMATION sFileInfo;
  438. if (GetFileInformationByHandle(m_DeviceDataHandle,&sFileInfo)) {
  439. ftLastWriteTime =sFileInfo.ftLastWriteTime;
  440. liNewHugeSize.LowPart = sFileInfo.nFileSizeLow;
  441. liNewHugeSize.HighPart= sFileInfo.nFileSizeHigh ;
  442. }
  443. else {
  444. dwError = ::GetLastError();
  445. }
  446. }
  447. if (NOERROR == dwError ) {
  448. //
  449. // First check size, because it is easy to change time without changing size
  450. //
  451. if (m_dwLastHugeSize.QuadPart != liNewHugeSize.QuadPart) {
  452. if (pguidEvent) {
  453. *pguidEvent = guidEventSizeChanged;
  454. }
  455. fRet = TRUE;
  456. }
  457. else {
  458. if (CompareFileTime(&m_ftLastWriteTime,&ftLastWriteTime) == -1 ) {
  459. if (pguidEvent) {
  460. *pguidEvent = guidEventTimeChanged;
  461. }
  462. fRet = TRUE;
  463. }
  464. else {
  465. // Nothing really changed
  466. }
  467. }
  468. m_ftLastWriteTime = ftLastWriteTime;
  469. m_dwLastHugeSize = liNewHugeSize;
  470. }
  471. return fRet;
  472. }
  473. VOID
  474. FileChangeThread(
  475. LPVOID lpParameter
  476. )
  477. {
  478. UsdSampDevice *pThisDevice = (UsdSampDevice *)lpParameter;
  479. pThisDevice->RunNotifications();
  480. }