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.

2045 lines
53 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. ExtensionData.cpp
  5. Abstract:
  6. This file provides implementation of the named
  7. extension data functions (get / set / notify)
  8. Author:
  9. Eran Yariv (EranY) Nov, 1999
  10. Revision History:
  11. --*/
  12. #include "faxsvc.h"
  13. #pragma hdrstop
  14. static
  15. DWORD
  16. FAXGetExtensionData (
  17. IN DWORD dwOrigDeviceId,
  18. IN FAX_ENUM_DEVICE_ID_SOURCE DevIdSrc,
  19. IN LPCWSTR lpctstrNameGUID,
  20. IN OUT LPBYTE *ppData,
  21. IN OUT LPDWORD lpdwDataSize
  22. );
  23. static
  24. DWORD
  25. FAXSetExtensionData (
  26. IN HINSTANCE hInst,
  27. IN LPCWSTR lpcwstrComputerName,
  28. IN DWORD dwOrigDeviceId,
  29. IN FAX_ENUM_DEVICE_ID_SOURCE DevIdSrc,
  30. IN LPCWSTR lpctstrNameGUID,
  31. IN LPBYTE pData,
  32. IN DWORD dwDataSize
  33. );
  34. static
  35. BOOL
  36. FindTAPIPermanentLineIdFromFaxDeviceId (
  37. IN DWORD dwFaxDeviceId,
  38. OUT LPDWORD lpdwTapiLineId
  39. );
  40. BOOL CExtNotifyCallbackPacket::Init(
  41. PFAX_EXT_CONFIG_CHANGE pCallback,
  42. DWORD dwDeviceId,
  43. LPCWSTR lpcwstrDataGuid,
  44. LPBYTE lpbData,
  45. DWORD dwDataSize)
  46. {
  47. DEBUG_FUNCTION_NAME(TEXT("CExtNotifyCallbackPacket::Init"));
  48. DWORD ec = ERROR_SUCCESS;
  49. Assert(pCallback);
  50. Assert(lpcwstrDataGuid);
  51. Assert(lpbData);
  52. Assert(dwDataSize);
  53. Assert(m_lpbData == NULL);
  54. m_pCallback = pCallback;
  55. m_dwDeviceId = dwDeviceId;
  56. m_lpwstrGUID = StringDup (lpcwstrDataGuid);
  57. if (!m_lpwstrGUID)
  58. {
  59. ec = GetLastError();
  60. DebugPrintEx(
  61. DEBUG_ERR,
  62. TEXT("Cannot allocate memory to copy string %s"),
  63. lpcwstrDataGuid);
  64. goto Error;
  65. }
  66. m_dwDataSize = dwDataSize;
  67. m_lpbData = (LPBYTE)MemAlloc(m_dwDataSize);
  68. if (!m_lpbData)
  69. {
  70. ec = GetLastError();
  71. DebugPrintEx(
  72. DEBUG_ERR,
  73. TEXT("Failed to allocate data for callback packet. Size (%ld)"),
  74. m_dwDataSize);
  75. goto Error;
  76. }
  77. memcpy(m_lpbData, lpbData, m_dwDataSize);
  78. goto Exit;
  79. Error:
  80. MemFree(m_lpwstrGUID);
  81. MemFree(m_lpbData);
  82. m_lpwstrGUID = NULL;
  83. m_lpbData = NULL;
  84. Exit:
  85. return (ERROR_SUCCESS == ec);
  86. };
  87. CExtNotifyCallbackPacket::CExtNotifyCallbackPacket()
  88. {
  89. m_lpwstrGUID = NULL;
  90. m_lpbData = NULL;
  91. }
  92. CExtNotifyCallbackPacket::~CExtNotifyCallbackPacket()
  93. {
  94. MemFree(m_lpwstrGUID);
  95. MemFree(m_lpbData);
  96. }
  97. /************************************
  98. * *
  99. * CDeviceAndGUID *
  100. * *
  101. ************************************/
  102. bool
  103. CDeviceAndGUID::operator < ( const CDeviceAndGUID &other ) const
  104. /*++
  105. Routine name : operator <
  106. Class: CDeviceAndGUID
  107. Routine description:
  108. Compares myself with another Device and GUID key
  109. Author:
  110. Eran Yariv (EranY), Nov, 1999
  111. Arguments:
  112. other [in] - Other key
  113. Return Value:
  114. true only is i'm less than the other key
  115. --*/
  116. {
  117. if (m_dwDeviceId < other.m_dwDeviceId)
  118. {
  119. return true;
  120. }
  121. if (m_dwDeviceId > other.m_dwDeviceId)
  122. {
  123. return false;
  124. }
  125. //
  126. // Equal device id, comapre GUIDs
  127. //
  128. return (m_strGUID.compare (other.m_strGUID) < 0);
  129. } // CDeviceAndGUID::operator <
  130. /************************************
  131. * *
  132. * CLocalNotificationSink *
  133. * *
  134. ************************************/
  135. CLocalNotificationSink::CLocalNotificationSink (
  136. PFAX_EXT_CONFIG_CHANGE lpConfigChangeCallback,
  137. DWORD dwNotifyDeviceId,
  138. HINSTANCE hInst) :
  139. CNotificationSink (),
  140. m_lpConfigChangeCallback (lpConfigChangeCallback),
  141. m_dwNotifyDeviceId (dwNotifyDeviceId),
  142. m_hInst (hInst)
  143. /*++
  144. Routine name : CLocalNotificationSink::CLocalNotificationSink
  145. Class: CLocalNotificationSink
  146. Routine description:
  147. CEtensionNotificationSink constractor
  148. Author:
  149. Eran Yariv (EranY), Nov, 1999
  150. Arguments:
  151. lpConfigChangeCallback [in] - Pointer to notification callback
  152. dwNotifyDeviceId [in] - Device id to notify with
  153. Return Value:
  154. None.
  155. --*/
  156. {
  157. m_type = SINK_TYPE_LOCAL;
  158. } // CLocalNotificationSink::CLocalNotificationSink
  159. bool
  160. CLocalNotificationSink::operator == (
  161. const CNotificationSink &rhs
  162. ) const
  163. {
  164. Assert (SINK_TYPE_UNKNOWN != rhs.Type());
  165. //
  166. // Comapre types and then downcast to CLocalNotificationSink and compare pointers
  167. //
  168. return ((SINK_TYPE_LOCAL == rhs.Type()) &&
  169. (m_lpConfigChangeCallback ==
  170. (static_cast<const CLocalNotificationSink&>(rhs)).m_lpConfigChangeCallback
  171. )
  172. );
  173. } // CLocalNotificationSink::operator ==
  174. HRESULT
  175. CLocalNotificationSink::Notify (
  176. DWORD dwDeviceId,
  177. LPCWSTR lpcwstrNameGUID,
  178. LPCWSTR lpcwstrComputerName,
  179. HANDLE hModule,
  180. LPBYTE lpData,
  181. DWORD dwDataSize,
  182. LPBOOL lpbRemove
  183. )
  184. /*++
  185. Routine name : CLocalNotificationSink::Notify
  186. Class: CLocalNotificationSink
  187. Routine description:
  188. Notify the sink
  189. Author:
  190. Eran Yariv (EranY), Nov, 1999
  191. Arguments:
  192. dwDeviceId [in ] - Device id
  193. lpcwstrNameGUID [in ] - Data name
  194. lpData [in ] - Pointer to data
  195. dwDataSize [in ] - Data size
  196. lpbRemove [out] - Set to TRUE if this sink cannot be used and must be removed.
  197. Return Value:
  198. Standard HRESULT.
  199. --*/
  200. {
  201. HRESULT hr = NOERROR;
  202. CExtNotifyCallbackPacket * pCallbackPacket = NULL;
  203. DEBUG_FUNCTION_NAME(TEXT("CLocalNotificationSink::Notify"));
  204. Assert (m_lpConfigChangeCallback); // Should have caught it in FaxExtRegisterForExtensionEvents
  205. *lpbRemove = FALSE;
  206. if (!lstrcmp (TEXT(""), lpcwstrComputerName))
  207. {
  208. //
  209. // The source of the data change was local (extension)
  210. //
  211. if (hModule == m_hInst)
  212. {
  213. //
  214. // The source of the data change is the same module this sink notifies to.
  215. // Don't notify and return success.
  216. //
  217. DebugPrintEx(
  218. DEBUG_MSG,
  219. TEXT("Local extension (hInst = %ld) set data and the notification for it was blocked"),
  220. m_hInst);
  221. return hr;
  222. }
  223. }
  224. pCallbackPacket = new (std::nothrow) CExtNotifyCallbackPacket();
  225. if (!pCallbackPacket)
  226. {
  227. DebugPrintEx(
  228. DEBUG_ERR,
  229. TEXT("Failed to allocate callback packet"));
  230. hr = HRESULT_FROM_WIN32(GetLastError());
  231. goto Error;
  232. }
  233. if (!pCallbackPacket->Init(
  234. m_lpConfigChangeCallback,
  235. m_dwNotifyDeviceId,
  236. lpcwstrNameGUID,
  237. lpData,
  238. dwDataSize))
  239. {
  240. DWORD ec;
  241. ec = GetLastError();
  242. DebugPrintEx(
  243. DEBUG_ERR,
  244. TEXT("Failed to initialize callback packet (ec: %ld)"),
  245. ec);
  246. hr = HRESULT_FROM_WIN32(ec);
  247. goto Error;
  248. }
  249. if (!PostQueuedCompletionStatus (
  250. g_pNotificationMap->m_hCompletionPort,
  251. 0,
  252. 0,
  253. (LPOVERLAPPED)pCallbackPacket
  254. ))
  255. {
  256. DWORD dwRes;
  257. dwRes = GetLastError ();
  258. DebugPrintEx(
  259. DEBUG_ERR,
  260. TEXT("PostQueuedCompletionStatus failed. (ec: %ld)"),
  261. dwRes);
  262. hr = HRESULT_FROM_WIN32(dwRes);
  263. goto Error;
  264. }
  265. goto Exit;
  266. Error:
  267. if (pCallbackPacket)
  268. {
  269. delete pCallbackPacket;
  270. }
  271. Exit:
  272. return hr;
  273. } // CLocalNotificationSink::Notify
  274. /************************************
  275. * *
  276. * CSinksList *
  277. * *
  278. ************************************/
  279. CSinksList::~CSinksList ()
  280. {
  281. DEBUG_FUNCTION_NAME(TEXT("CSinksList::~CSinksList"));
  282. try
  283. {
  284. for (SINKS_LIST::iterator it = m_List.begin(); it != m_List.end(); ++it)
  285. {
  286. CNotificationSink *pSink = *it;
  287. delete pSink;
  288. }
  289. }
  290. catch (exception &ex)
  291. {
  292. DebugPrintEx(
  293. DEBUG_ERR,
  294. TEXT("Got an STL exception while clearing a sinks list (%S)"),
  295. ex.what());
  296. }
  297. } // CSinksList::~CSinksList ()
  298. /************************************
  299. * *
  300. * CNotificationMap *
  301. * *
  302. ************************************/
  303. CNotificationMap::~CNotificationMap ()
  304. {
  305. DEBUG_FUNCTION_NAME(TEXT("CNotificationMap::~CNotificationMap"));
  306. try
  307. {
  308. for (NOTIFY_MAP::iterator it = m_Map.begin(); it != m_Map.end(); ++it)
  309. {
  310. CSinksList *pSinksList = (*it).second;
  311. delete pSinksList;
  312. }
  313. }
  314. catch (exception &ex)
  315. {
  316. DebugPrintEx(
  317. DEBUG_ERR,
  318. TEXT("Got an STL exception while clearing the notifications map (%S)"),
  319. ex.what());
  320. }
  321. //
  322. // Handle our completion port threads now
  323. //
  324. if (m_hCompletionPort)
  325. {
  326. CloseHandle (m_hCompletionPort);
  327. }
  328. //
  329. // Close our critical section
  330. //
  331. m_CsExtensionData.SafeDelete();
  332. } // CNotificationMap::~CNotificationMap
  333. void
  334. CNotificationMap::Notify (
  335. DWORD dwDeviceId,
  336. LPCWSTR lpcwstrNameGUID,
  337. LPCWSTR lpcwstrComputerName,
  338. HANDLE hModule,
  339. LPBYTE lpData,
  340. DWORD dwDataSize)
  341. /*++
  342. Routine name : CNotificationMap::Notify
  343. Class: CNotificationMap
  344. Routine description:
  345. Notify the all the sinks (in a list) for a map lookup value.
  346. Each sink that returns a failure code (FALSE) is deleted and removed from
  347. the list.
  348. After the list is traversed, if it becomes empty, it is deleted and
  349. removed from the map.
  350. Author:
  351. Eran Yariv (EranY), Nov, 1999
  352. Arguments:
  353. dwDeviceId [in] - Device id
  354. lpcwstrNameGUID [in] - Data name
  355. lpcwstrComputerName [in] - Computer where data changing module runs
  356. hModule [in] - Handle of the module that changed the data
  357. lpData [in] - Pointer to new data
  358. dwDataSize [in] - New data size
  359. Return Value:
  360. None.
  361. --*/
  362. {
  363. SINKS_LIST::iterator ListIter;
  364. CSinksList *pList;
  365. DEBUG_FUNCTION_NAME(TEXT("CNotificationMap::Notify"));
  366. //
  367. // We're notifying now - block calls to Add*Sink and Remove*Sink
  368. //
  369. if (g_bServiceIsDown)
  370. {
  371. //
  372. // We don't supply extension data services when the service is going down
  373. //
  374. DebugPrintEx(
  375. DEBUG_ERR,
  376. TEXT("Called while service is shutting - operation canceled"));
  377. return;
  378. }
  379. Assert (!m_bNotifying);
  380. m_bNotifying = TRUE;
  381. CDeviceAndGUID key (dwDeviceId, lpcwstrNameGUID);
  382. NOTIFY_MAP::iterator it;
  383. if((it = m_Map.find(key)) == m_Map.end())
  384. {
  385. //
  386. // Key not found in map - no one to notify
  387. //
  388. DebugPrintEx(
  389. DEBUG_MSG,
  390. TEXT("No one to notify"));
  391. goto exit;
  392. }
  393. //
  394. // Retrieve list
  395. //
  396. pList = (*it).second;
  397. //
  398. // If the list is already being notified, we're in a loop here - quit now
  399. //
  400. if (pList->m_bNotifying)
  401. {
  402. //
  403. // OK, here's what happened.
  404. // We were walking the list and notifying each sink. One sink, while processing
  405. // it's notification, called FaxExtSetData on the same GUID + device ID.
  406. // This resulted in a 2nd notification attempt that we're now catching.
  407. // The second notification will not be sent !!!
  408. //
  409. DebugPrintEx(
  410. DEBUG_MSG,
  411. TEXT("Notification loop caught on device ID = %ld, GUID = %s. 2nd notification cancelled"),
  412. dwDeviceId,
  413. lpcwstrNameGUID);
  414. goto exit;
  415. }
  416. //
  417. // Mark map value as busy notifying
  418. //
  419. pList->m_bNotifying = TRUE;
  420. //
  421. // Walk the list and notify each element
  422. //
  423. for (ListIter = pList->m_List.begin(); ListIter != pList->m_List.end(); ++ListIter)
  424. {
  425. CNotificationSink *pSink = (*ListIter);
  426. BOOL bRemove;
  427. pSink->Notify ( dwDeviceId,
  428. lpcwstrNameGUID,
  429. lpcwstrComputerName,
  430. hModule,
  431. lpData,
  432. dwDataSize,
  433. &bRemove
  434. );
  435. if (bRemove)
  436. {
  437. //
  438. // The notification indicates that the sink became invalid.
  439. // This is a good time to remove it from the list.
  440. //
  441. //
  442. // Tell the sink to gracefully disconnect
  443. //
  444. HRESULT hr = pSink->Disconnect ();
  445. delete pSink;
  446. //
  447. // Remove item from list, advancing the iterator to next item (or end)
  448. //
  449. ListIter = pList->m_List.erase (ListIter);
  450. }
  451. }
  452. //
  453. // Mark map value as not busy notifying
  454. //
  455. pList->m_bNotifying = FALSE;
  456. //
  457. // We might get an empty list here at the end
  458. //
  459. if (pList->m_List.empty())
  460. {
  461. //
  462. // Remove empty list from map
  463. //
  464. delete pList;
  465. m_Map.erase (key);
  466. }
  467. exit:
  468. //
  469. // We're not notifying any more - allow calls to Add*Sink and Remove*Sink
  470. //
  471. m_bNotifying = FALSE;
  472. } // CNotificationMap::Notify
  473. CNotificationSink *
  474. CNotificationMap::AddLocalSink (
  475. HINSTANCE hInst,
  476. DWORD dwDeviceId,
  477. DWORD dwNotifyDeviceId,
  478. LPCWSTR lpcwstrNameGUID,
  479. PFAX_EXT_CONFIG_CHANGE lpConfigChangeCallback
  480. )
  481. /*++
  482. Routine name : CNotificationMap::AddLocalSink
  483. Class: CNotificationMap
  484. Routine description:
  485. Adds a local sink to the list of sinks for a given device id + GUID
  486. Author:
  487. Eran Yariv (EranY), Nov, 1999
  488. Arguments:
  489. hInst [in] - Instance of extension
  490. dwDeviceId [in] - Device id to listen to
  491. dwNotifyDeviceId [in] - Device id to report in callback
  492. lpcwstrNameGUID [in] - Data name
  493. lpConfigChangeCallback [in] - Pointer to notification callback
  494. Return Value:
  495. Pointer to newly created sink.
  496. If NULL, sets the last error.
  497. --*/
  498. {
  499. DWORD dwRes = ERROR_SUCCESS;
  500. SINKS_LIST::iterator ListIter;
  501. NOTIFY_MAP::iterator it;
  502. CSinksList *pList;
  503. CNotificationSink *pSink = NULL;
  504. DEBUG_FUNCTION_NAME(TEXT("CNotificationMap::AddLocalSink"));
  505. Assert (lpConfigChangeCallback); // Should have caught it in FaxExtRegisterForExtensionEvents
  506. if (m_bNotifying)
  507. {
  508. //
  509. // We're notifying now - can't change the list.
  510. //
  511. DebugPrintEx(
  512. DEBUG_MSG,
  513. TEXT("Caller tried to to add a local sink to a notification list while notifying"));
  514. SetLastError (ERROR_BUSY); // The requested resource is in use.
  515. return NULL;
  516. }
  517. //
  518. // See if entry exists in map
  519. //
  520. CDeviceAndGUID key (dwDeviceId, lpcwstrNameGUID);
  521. if((it = m_Map.find(key)) == m_Map.end())
  522. {
  523. //
  524. // Key not found in map - add it with a new list
  525. //
  526. pList = new (std::nothrow) CSinksList;
  527. if (!pList)
  528. {
  529. DebugPrintEx(
  530. DEBUG_ERR,
  531. TEXT("Cannot allocate a new sinks list"));
  532. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  533. return NULL;
  534. }
  535. m_Map[key] = pList;
  536. }
  537. else
  538. {
  539. //
  540. // Get the existing list
  541. //
  542. pList = (*it).second;
  543. }
  544. //
  545. // Create new sink
  546. //
  547. pSink = new (std::nothrow) CLocalNotificationSink (lpConfigChangeCallback, dwNotifyDeviceId, hInst);
  548. if (!pSink)
  549. {
  550. //
  551. // Can't crate sink
  552. //
  553. DebugPrintEx(
  554. DEBUG_ERR,
  555. TEXT("Cannot allocate a notification sink"));
  556. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  557. goto exit;
  558. }
  559. //
  560. // Scan the list to see if an identical sink already exists.
  561. //
  562. for (ListIter = pList->m_List.begin(); ListIter != pList->m_List.end(); ++ListIter)
  563. {
  564. CNotificationSink *pCurSink = (*ListIter);
  565. if (*pSink == *pCurSink)
  566. {
  567. //
  568. // Ooops, same sink already exists
  569. //
  570. DebugPrintEx(
  571. DEBUG_MSG,
  572. TEXT("Caller tried to to add an indetical local sink to a notification list"));
  573. SetLastError (ERROR_ALREADY_ASSIGNED);
  574. //
  575. // Tell the sink to gracefully disconnect
  576. //
  577. HRESULT hr = pSink->Disconnect ();
  578. delete pSink;
  579. pSink = NULL;
  580. goto exit;
  581. }
  582. }
  583. //
  584. // Add the new sink
  585. //
  586. pList->m_List.insert (pList->m_List.end(), pSink);
  587. exit:
  588. if (pList->m_List.empty())
  589. {
  590. //
  591. // Remove empty list from map
  592. //
  593. delete pList;
  594. m_Map.erase (key);
  595. }
  596. return pSink;
  597. } // CNotificationMap::AddLocalSink
  598. DWORD
  599. CNotificationMap::RemoveSink (
  600. CNotificationSink *pSinkToRemove
  601. )
  602. /*++
  603. Routine name : CNotificationMap::RemoveSink
  604. Class: CNotificationMap
  605. Routine description:
  606. Removes a sink from the list of sinks for a given sink pointer.
  607. If the list is empty, it is deleted and removed from the map.
  608. Author:
  609. Eran Yariv (EranY), Nov, 1999
  610. Arguments:
  611. Return Value:
  612. Standard Win32 error code.
  613. --*/
  614. {
  615. DEBUG_FUNCTION_NAME(TEXT("CNotificationMap::RemoveSink"));
  616. if (m_bNotifying)
  617. {
  618. //
  619. // We're notifying now - can't change the list.
  620. //
  621. DebugPrintEx(
  622. DEBUG_MSG,
  623. TEXT("Caller tried to to add a local sink to a notification list while notifying"));
  624. return ERROR_BUSY; // The requested resource is in use.
  625. }
  626. //
  627. // Lookup the sink
  628. //
  629. NOTIFY_MAP::iterator it;
  630. BOOL bFound = FALSE;
  631. for (it = m_Map.begin(); it != m_Map.end (); ++it)
  632. {
  633. //
  634. // Get map value (list of sinks)
  635. //
  636. CSinksList *pList = (*it).second;
  637. //
  638. // Lookup sink in list
  639. //
  640. SINKS_LIST::iterator ListIter;
  641. CNotificationSink *pSink = NULL;
  642. for (ListIter = pList->m_List.begin(); ListIter != pList->m_List.end(); ++ListIter)
  643. {
  644. pSink = (*ListIter);
  645. if (pSinkToRemove == pSink) // Pointer comparison !!!!
  646. {
  647. //
  648. // Found the sink - remove it
  649. //
  650. pList->m_List.erase (ListIter);
  651. HRESULT hr = pSinkToRemove->Disconnect ();
  652. delete pSinkToRemove;
  653. bFound = TRUE;
  654. break;
  655. }
  656. }
  657. if (bFound)
  658. {
  659. //
  660. // Since we removed a sink from the list, the list may become empty now
  661. //
  662. if (pList->m_List.empty())
  663. {
  664. //
  665. // Remove empty list
  666. //
  667. m_Map.erase (it);
  668. delete pList;
  669. }
  670. //
  671. // Break the map search
  672. //
  673. break;
  674. }
  675. }
  676. if (!bFound)
  677. {
  678. //
  679. // Reached the end of the map but the requested sink could not be found
  680. //
  681. DebugPrintEx(
  682. DEBUG_MSG,
  683. TEXT("Caller tried to to remove a non-existent sink"));
  684. return ERROR_NOT_FOUND; // Element not found.
  685. }
  686. return ERROR_SUCCESS;
  687. } // CNotificationMap::RemoveSink
  688. DWORD
  689. CNotificationMap::ExtNotificationThread(
  690. LPVOID UnUsed
  691. )
  692. /*++
  693. Routine name : CNotificationMap::ExtNotificationThread
  694. Routine description:
  695. This is the main thread function of the thread(s)
  696. that dequeue the notification completion port.
  697. This is a static class function !!!!
  698. Pointers to instances of ExtNotificationDataPacket are dequeued
  699. by this function and the map notificiation function is called on them.
  700. Author:
  701. Eran Yariv (EranY), Dec, 1999
  702. Arguments:
  703. UnUsed [in] - Unused
  704. Return Value:
  705. Standard Win32 Error code
  706. --*/
  707. {
  708. DWORD dwRes;
  709. DEBUG_FUNCTION_NAME(TEXT("CNotificationMap::ExtNotificationThread"));
  710. for (;;)
  711. {
  712. DWORD dwNumBytes;
  713. ULONG_PTR CompletionKey;
  714. CExtNotifyCallbackPacket *pPacket;
  715. if (!GetQueuedCompletionStatus (
  716. g_pNotificationMap->m_hCompletionPort,
  717. &dwNumBytes,
  718. &CompletionKey,
  719. (LPOVERLAPPED*) &pPacket,
  720. INFINITE
  721. ))
  722. {
  723. dwRes = GetLastError ();
  724. DebugPrintEx(
  725. DEBUG_ERR,
  726. TEXT("GetQueuedCompletionStatus failed with error = %ld. Aborting thread"),
  727. dwRes);
  728. return dwRes;
  729. }
  730. if (SERVICE_SHUT_DOWN_KEY == CompletionKey)
  731. {
  732. //
  733. // This is a special signal from the service that all thread should die now. Tell all other notification threads to die
  734. //
  735. if (!PostQueuedCompletionStatus(
  736. g_pNotificationMap->m_hCompletionPort,
  737. 0,
  738. SERVICE_SHUT_DOWN_KEY,
  739. (LPOVERLAPPED) NULL))
  740. {
  741. dwRes = GetLastError();
  742. DebugPrintEx(
  743. DEBUG_ERR,
  744. TEXT("PostQueuedCompletionStatus failed (SERVICE_SHUT_DOWN_KEY). (ec: %ld)"),
  745. dwRes);
  746. }
  747. if (!DecreaseServiceThreadsCount())
  748. {
  749. DebugPrintEx(
  750. DEBUG_ERR,
  751. TEXT("DecreaseServiceThreadsCount() failed (ec: %ld)"),
  752. GetLastError());
  753. }
  754. return ERROR_SUCCESS;
  755. }
  756. Assert (pPacket && pPacket->m_lpbData && pPacket->m_dwDataSize && pPacket->m_lpwstrGUID );
  757. //
  758. // Do the notification
  759. //
  760. DebugPrintEx(
  761. DEBUG_MSG,
  762. TEXT("Calling notification callback %p. DeviceId: %ld GUID: %s Data: %p DataSize: %ld"),
  763. pPacket->m_pCallback,
  764. pPacket->m_dwDeviceId,
  765. pPacket->m_lpwstrGUID,
  766. pPacket->m_lpbData,
  767. pPacket->m_dwDataSize);
  768. pPacket->m_pCallback(pPacket->m_dwDeviceId, // Notify with internal device id.
  769. pPacket->m_lpwstrGUID,
  770. pPacket->m_lpbData,
  771. pPacket->m_dwDataSize);
  772. //
  773. // Kill notification object
  774. //
  775. delete pPacket;
  776. } // Dequeue loop
  777. UNREFERENCED_PARAMETER (UnUsed);
  778. } // CNotificationMap::ExtNotificationThread
  779. DWORD
  780. CNotificationMap::Init ()
  781. /*++
  782. Routine name : CNotificationMap::Init
  783. Routine description:
  784. Initialize the notification map
  785. Author:
  786. Eran Yariv (EranY), Dec, 1999
  787. Arguments:
  788. Return Value:
  789. Standard Win32 error code
  790. --*/
  791. {
  792. DWORD dwRes;
  793. DWORD dwNumThreads = 0;
  794. DEBUG_FUNCTION_NAME(TEXT("CNotificationMap::Init"));
  795. //
  796. // Try to init our critical section
  797. //
  798. if (!m_CsExtensionData.Initialize())
  799. {
  800. dwRes = GetLastError();
  801. DebugPrintEx(
  802. DEBUG_ERR,
  803. TEXT("CFaxCriticalSection::Initialize(&m_CsExtensionData) failed: err = %d"),
  804. dwRes);
  805. return dwRes;
  806. }
  807. //
  808. // Create the completion port
  809. //
  810. m_hCompletionPort = CreateIoCompletionPort (
  811. INVALID_HANDLE_VALUE, // No device
  812. NULL, // New one
  813. 0, // Key
  814. MAX_CONCURRENT_EXT_DATA_SET_THREADS);
  815. if (NULL == m_hCompletionPort)
  816. {
  817. dwRes = GetLastError ();
  818. DebugPrintEx(
  819. DEBUG_ERR,
  820. TEXT("CreateIoCompletionPort failed with %ld"),
  821. dwRes);
  822. return dwRes;
  823. }
  824. //
  825. // Create completion port dequeueing thread(s)
  826. //
  827. for (DWORD dw = 0; dw < NUM_EXT_DATA_SET_THREADS; dw++)
  828. {
  829. HANDLE hThread = CreateThreadAndRefCount (
  830. NULL, // Security
  831. 0, // Stack size
  832. g_pNotificationMap->ExtNotificationThread, // Start routine
  833. 0, // Parameter
  834. 0, // Creation flag(s)
  835. NULL); // Don't want thread id
  836. if (NULL == hThread)
  837. {
  838. dwRes = GetLastError ();
  839. DebugPrintEx(
  840. DEBUG_ERR,
  841. TEXT("CreateThreadAndRefCount failed with %ld"),
  842. dwRes);
  843. }
  844. else
  845. {
  846. dwNumThreads++;
  847. CloseHandle(hThread);
  848. }
  849. }
  850. if (!dwNumThreads)
  851. {
  852. //
  853. // Not even a single thread was created
  854. //
  855. CloseHandle (m_hCompletionPort);
  856. m_hCompletionPort = NULL;
  857. return dwRes;
  858. }
  859. return ERROR_SUCCESS;
  860. } // CNotificationMap::Init
  861. /************************************
  862. * *
  863. * CMapDeviceId *
  864. * *
  865. ************************************/
  866. DWORD
  867. CMapDeviceId::AddDevice (
  868. DWORD dwDeviceId,
  869. DWORD dwFaxId
  870. )
  871. /*++
  872. Routine name : CMapDeviceId::AddDevice
  873. Routine description:
  874. Adds a new device to the devices map
  875. Author:
  876. Eran Yariv (EranY), Dec, 1999
  877. Arguments:
  878. dwDeviceId [in] - The source id of the device
  879. dwFaxId [in] - The unique fax device id (destination id)
  880. Return Value:
  881. Standard Win32 error code
  882. --*/
  883. {
  884. DEVICE_IDS_MAP::iterator it;
  885. DWORD dwRes = ERROR_SUCCESS;
  886. DEBUG_FUNCTION_NAME(TEXT("CMapDeviceId::AddDevice"));
  887. EnterCriticalSection (&g_pNotificationMap->m_CsExtensionData);
  888. try
  889. {
  890. //
  891. // See if entry exists in map
  892. //
  893. if((it = m_Map.find(dwDeviceId)) != m_Map.end())
  894. {
  895. dwRes = ERROR_ALREADY_ASSIGNED;
  896. goto exit;
  897. }
  898. //
  899. // Add new map entry
  900. //
  901. m_Map[dwDeviceId] = dwFaxId;
  902. }
  903. catch (exception &ex)
  904. {
  905. DebugPrintEx(
  906. DEBUG_ERR,
  907. TEXT("map caused exception (%S)"),
  908. ex.what());
  909. dwRes = ERROR_GEN_FAILURE;
  910. }
  911. exit:
  912. LeaveCriticalSection (&g_pNotificationMap->m_CsExtensionData);
  913. return dwRes;
  914. } // CMapDeviceId::AddDevice
  915. DWORD
  916. CMapDeviceId::RemoveDevice (
  917. DWORD dwDeviceId
  918. )
  919. /*++
  920. Routine name : CMapDeviceId::RemoveDevice
  921. Routine description:
  922. Removes an existing device from the devices map
  923. Author:
  924. Eran Yariv (EranY), Dec, 1999
  925. Arguments:
  926. dwDeviceId [in] - The source id of the device
  927. Return Value:
  928. Standard Win32 error code
  929. --*/
  930. {
  931. DEVICE_IDS_MAP::iterator it;
  932. DWORD dwRes = ERROR_SUCCESS;
  933. DEBUG_FUNCTION_NAME(TEXT("CMapDeviceId::RemoveDevice"));
  934. EnterCriticalSection (&g_pNotificationMap->m_CsExtensionData);
  935. try
  936. {
  937. //
  938. // See if entry exists in map
  939. //
  940. if((it = m_Map.find(dwDeviceId)) == m_Map.end())
  941. {
  942. dwRes = ERROR_NOT_FOUND;
  943. goto exit;
  944. }
  945. //
  946. // Remove map entry
  947. //
  948. m_Map.erase (it);
  949. }
  950. catch (exception &ex)
  951. {
  952. DebugPrintEx(
  953. DEBUG_ERR,
  954. TEXT("map caused exception (%S)"),
  955. ex.what());
  956. dwRes = ERROR_GEN_FAILURE;
  957. }
  958. exit:
  959. LeaveCriticalSection (&g_pNotificationMap->m_CsExtensionData);
  960. return dwRes;
  961. } // CMapDeviceId::RemoveDevice
  962. DWORD
  963. CMapDeviceId::LookupUniqueId (
  964. DWORD dwOtherId,
  965. LPDWORD lpdwFaxId
  966. ) const
  967. /*++
  968. Routine name : CMapDeviceId::LookupUniqueId
  969. Routine description:
  970. Looks up a unique fax device id from a given device id
  971. Author:
  972. Eran Yariv (EranY), Dec, 1999
  973. Arguments:
  974. dwOtherId [in ] - Given device it (lookup source)
  975. lpdwFaxId [out] - Fax unique device id
  976. Return Value:
  977. Standard Win32 error code
  978. --*/
  979. {
  980. DEVICE_IDS_MAP::iterator it;
  981. DWORD dwRes = ERROR_SUCCESS;
  982. DEBUG_FUNCTION_NAME(TEXT("CMapDeviceId::LookupUniqueId"));
  983. if (!dwOtherId)
  984. {
  985. //
  986. // Special device id == 0 case
  987. //
  988. *lpdwFaxId = 0;
  989. return dwRes;
  990. }
  991. EnterCriticalSection (&g_pNotificationMap->m_CsExtensionData);
  992. try
  993. {
  994. //
  995. // See if entry exists in map
  996. //
  997. if((it = m_Map.find(dwOtherId)) == m_Map.end())
  998. {
  999. dwRes = ERROR_NOT_FOUND;
  1000. goto exit;
  1001. }
  1002. *lpdwFaxId = (*it).second;
  1003. }
  1004. catch (exception &ex)
  1005. {
  1006. DebugPrintEx(
  1007. DEBUG_ERR,
  1008. TEXT("map caused exception (%S)"),
  1009. ex.what());
  1010. dwRes = ERROR_GEN_FAILURE;
  1011. }
  1012. exit:
  1013. LeaveCriticalSection (&g_pNotificationMap->m_CsExtensionData);
  1014. return dwRes;
  1015. } // CMapDeviceId::LookupUniqueId
  1016. /************************************
  1017. * *
  1018. * Globals *
  1019. * *
  1020. ************************************/
  1021. CNotificationMap* g_pNotificationMap; // Map of DeviceId+GUID to list of notification sinks
  1022. /*
  1023. The map maps between TAPI permanent line ids to fax unique ids.
  1024. TAPI-based FSPs / EFPSs talk to us using TAPI-permamnet line ids and have no clue of the
  1025. fax unique device ids. This map is here for quick lookup for TAPI-based FSPs.
  1026. */
  1027. CMapDeviceId* g_pTAPIDevicesIdsMap; // Map between TAPI permanent line id and fax unique device id.
  1028. DWORD
  1029. LookupUniqueFaxDeviceId (
  1030. DWORD dwDeviceId,
  1031. LPDWORD lpdwResult,
  1032. FAX_ENUM_DEVICE_ID_SOURCE DevIdSrc)
  1033. /*++
  1034. Routine name : LookupUniqueFaxDeviceId
  1035. Routine description:
  1036. Looks up a fax unique device id from a general device id.
  1037. Author:
  1038. Eran Yariv (EranY), Dec, 1999
  1039. Arguments:
  1040. dwDeviceId [in ] - Original device id
  1041. lpdwResult [out] - Looked up device id
  1042. DevIdSrc [in ] - Source of device id
  1043. Return Value:
  1044. Standard Win32 error code.
  1045. --*/
  1046. {
  1047. DEBUG_FUNCTION_NAME(TEXT("LookupUniqueFaxDeviceId"));
  1048. switch (DevIdSrc)
  1049. {
  1050. case DEV_ID_SRC_FAX: // No maping required
  1051. *lpdwResult = dwDeviceId;
  1052. return ERROR_SUCCESS;
  1053. case DEV_ID_SRC_TAPI:
  1054. return g_pTAPIDevicesIdsMap->LookupUniqueId (dwDeviceId, lpdwResult);
  1055. default:
  1056. DebugPrintEx(
  1057. DEBUG_ERR,
  1058. TEXT("Invalid device id source (%ld)"),
  1059. DevIdSrc);
  1060. ASSERT_FALSE;
  1061. return ERROR_INVALID_PARAMETER;
  1062. }
  1063. } // LookupUniqueFaxDeviceId
  1064. /************************************
  1065. * *
  1066. * Get/Set Data *
  1067. * *
  1068. ************************************/
  1069. static
  1070. BOOL
  1071. FindTAPIPermanentLineIdFromFaxDeviceId (
  1072. IN DWORD dwFaxDeviceId,
  1073. OUT LPDWORD lpdwTapiLineId
  1074. )
  1075. /*++
  1076. Routine name : FindTAPIPermanentLineIdFromFaxDeviceId
  1077. Routine description:
  1078. Given a fax device id, returns the TAPI permanent line id associated with this fax device.
  1079. If the fax device is not found or is a virtual fax (no TAPI association), the search fails.
  1080. Author:
  1081. Eran Yariv (EranY), Feb, 2000
  1082. Arguments:
  1083. dwFaxDeviceId [in] - Fax device id
  1084. lpdwTapiLineId [out] - TAPI permanent line id
  1085. Return Value:
  1086. TRUE if the search succeeed. FALSE otherwise.
  1087. --*/
  1088. {
  1089. BOOL bRes = FALSE;
  1090. DEBUG_FUNCTION_NAME(TEXT("FindTAPIPermanentLineIdFromFaxDeviceId"));
  1091. EnterCriticalSection(&g_CsLine);
  1092. PLINE_INFO pLine = GetTapiLineFromDeviceId (dwFaxDeviceId, FALSE);
  1093. if (!pLine)
  1094. {
  1095. goto exit;
  1096. }
  1097. if (pLine->Flags & FPF_VIRTUAL)
  1098. {
  1099. //
  1100. // This fax device is virtual. It does not have a corresponding TAPI line.
  1101. //
  1102. goto exit;
  1103. }
  1104. *lpdwTapiLineId = pLine->TapiPermanentLineId;
  1105. bRes = TRUE;
  1106. exit:
  1107. LeaveCriticalSection(&g_CsLine);
  1108. return bRes;
  1109. } // FindTAPIPermanentLineIdFromFaxDeviceId
  1110. DWORD
  1111. FAXGetExtensionData (
  1112. IN DWORD dwOrigDeviceId,
  1113. IN FAX_ENUM_DEVICE_ID_SOURCE DevIdSrc,
  1114. IN LPCWSTR lpctstrNameGUID,
  1115. IN OUT LPBYTE *ppData,
  1116. IN OUT LPDWORD lpdwDataSize
  1117. )
  1118. /*++
  1119. Routine name : FAXGetExtensionData
  1120. Routine description:
  1121. Gets the extension data for a device (internal)
  1122. Author:
  1123. Eran Yariv (EranY), Feb, 2000
  1124. Arguments:
  1125. dwOrigDeviceId [in] - Original device id (as arrived from extension)
  1126. DevIdSrc [in] - Device id source (Fax / TAPI)
  1127. lpctstrNameGUID [in] - Data GUID
  1128. ppData [out] - Pointer to data buffer
  1129. lpdwDataSize [out] - Pointer to retrieved data size
  1130. Return Value:
  1131. Standard Win32 error code
  1132. --*/
  1133. {
  1134. DWORD dwRes;
  1135. DEBUG_FUNCTION_NAME(TEXT("FAXGetExtensionData"));
  1136. if (!lpctstrNameGUID || !ppData || !lpdwDataSize)
  1137. {
  1138. return ERROR_INVALID_PARAMETER;
  1139. }
  1140. if ((DevIdSrc != DEV_ID_SRC_FAX) && (DevIdSrc != DEV_ID_SRC_TAPI))
  1141. {
  1142. //
  1143. // Invalid device id class
  1144. //
  1145. return ERROR_INVALID_PARAMETER;
  1146. }
  1147. dwRes = IsValidGUID (lpctstrNameGUID);
  1148. if (ERROR_SUCCESS != dwRes)
  1149. {
  1150. if (ERROR_WMI_GUID_NOT_FOUND == dwRes)
  1151. {
  1152. //
  1153. // Return a more conservative error code
  1154. //
  1155. dwRes = ERROR_INVALID_PARAMETER;
  1156. }
  1157. return dwRes;
  1158. }
  1159. if (DEV_ID_SRC_FAX == DevIdSrc)
  1160. {
  1161. //
  1162. // Try to see if this fax device has a matching tapi line id.
  1163. //
  1164. DWORD dwTapiLineId;
  1165. if (FindTAPIPermanentLineIdFromFaxDeviceId (dwOrigDeviceId, &dwTapiLineId))
  1166. {
  1167. //
  1168. // Matching tapi line id found. Use it to read the data.
  1169. //
  1170. DevIdSrc = DEV_ID_SRC_TAPI;
  1171. dwOrigDeviceId = dwTapiLineId;
  1172. }
  1173. }
  1174. EnterCriticalSection (&g_pNotificationMap->m_CsExtensionData);
  1175. dwRes = ReadExtensionData ( dwOrigDeviceId,
  1176. DevIdSrc,
  1177. lpctstrNameGUID,
  1178. ppData,
  1179. lpdwDataSize
  1180. );
  1181. if (ERROR_SUCCESS != dwRes)
  1182. {
  1183. DebugPrintEx(
  1184. DEBUG_ERR,
  1185. TEXT("Reading extension data for device id %ld, GUID %s failed with %ld"),
  1186. dwOrigDeviceId,
  1187. lpctstrNameGUID,
  1188. dwRes);
  1189. }
  1190. LeaveCriticalSection (&g_pNotificationMap->m_CsExtensionData);
  1191. return dwRes;
  1192. } // FAXGetExtensionData
  1193. DWORD
  1194. FAXSetExtensionData (
  1195. IN HINSTANCE hInst,
  1196. IN LPCWSTR lpcwstrComputerName,
  1197. IN DWORD dwOrigDeviceId,
  1198. IN FAX_ENUM_DEVICE_ID_SOURCE DevIdSrc,
  1199. IN LPCWSTR lpctstrNameGUID,
  1200. IN LPBYTE pData,
  1201. IN DWORD dwDataSize
  1202. )
  1203. /*++
  1204. Routine name : FAXSetExtensionData
  1205. Routine description:
  1206. Writes the extension data for a device (internal)
  1207. Author:
  1208. Eran Yariv (EranY), Feb, 2000
  1209. Arguments:
  1210. hInst [in] - Caller's instance
  1211. lpcwstrComputerName [in] - Calling module computer name
  1212. dwOrigDeviceId [in] - Original device id (as arrived from extension)
  1213. DevIdSrc [in] - Device id source (Fax / TAPI)
  1214. lpctstrNameGUID [in] - Data GUID
  1215. pData [in] - Pointer to data buffer
  1216. dwDataSize [in] - Data size
  1217. Return Value:
  1218. Standard Win32 error code
  1219. --*/
  1220. {
  1221. DWORD dwRes;
  1222. DEBUG_FUNCTION_NAME(TEXT("FAXSetExtensionData"));
  1223. if (!lpctstrNameGUID || !pData || !dwDataSize || !lpcwstrComputerName)
  1224. {
  1225. return ERROR_INVALID_PARAMETER;
  1226. }
  1227. if ((DevIdSrc != DEV_ID_SRC_FAX) && (DevIdSrc != DEV_ID_SRC_TAPI))
  1228. {
  1229. //
  1230. // Invalid device id class
  1231. //
  1232. return ERROR_INVALID_PARAMETER;
  1233. }
  1234. dwRes = IsValidGUID (lpctstrNameGUID);
  1235. if (ERROR_SUCCESS != dwRes)
  1236. {
  1237. if (ERROR_WMI_GUID_NOT_FOUND == dwRes)
  1238. {
  1239. //
  1240. // Return a more conservative error code
  1241. //
  1242. dwRes = ERROR_INVALID_PARAMETER;
  1243. }
  1244. return dwRes;
  1245. }
  1246. FAX_ENUM_DEVICE_ID_SOURCE RegistryDeviceIdSource = DevIdSrc;
  1247. DWORD dwRegistryDeviceId = dwOrigDeviceId;
  1248. if (DEV_ID_SRC_FAX == DevIdSrc)
  1249. {
  1250. //
  1251. // Try to see if this fax device has a matching tapi line id.
  1252. //
  1253. DWORD dwTapiLineId;
  1254. if (FindTAPIPermanentLineIdFromFaxDeviceId (dwOrigDeviceId, &dwTapiLineId))
  1255. {
  1256. //
  1257. // Matching tapi line id found. Use it to read the data.
  1258. //
  1259. RegistryDeviceIdSource = DEV_ID_SRC_TAPI;
  1260. dwRegistryDeviceId = dwTapiLineId;
  1261. }
  1262. }
  1263. EnterCriticalSection (&g_pNotificationMap->m_CsExtensionData);
  1264. dwRes = WriteExtensionData (dwRegistryDeviceId,
  1265. RegistryDeviceIdSource,
  1266. lpctstrNameGUID,
  1267. pData,
  1268. dwDataSize
  1269. );
  1270. if (ERROR_SUCCESS != dwRes)
  1271. {
  1272. DebugPrintEx(
  1273. DEBUG_ERR,
  1274. TEXT("Writing extension data for device id %ld (registry device id = %ld), GUID %s failed with %ld"),
  1275. dwOrigDeviceId,
  1276. dwRegistryDeviceId,
  1277. lpctstrNameGUID,
  1278. dwRes);
  1279. goto exit;
  1280. }
  1281. //
  1282. // Notification is always done using the fax id (not the TAPI device id).
  1283. // We must lookup the fax id from the TAPI id before we attempt notification registration.
  1284. //
  1285. DWORD dwFaxUniqueID;
  1286. dwRes = LookupUniqueFaxDeviceId (dwOrigDeviceId, &dwFaxUniqueID, DevIdSrc);
  1287. if (ERROR_SUCCESS != dwRes)
  1288. {
  1289. DebugPrintEx(
  1290. DEBUG_ERR,
  1291. TEXT("LookupUniqueFaxDeviceId failed for device id %ld (ec: %ld). No write notification will be performed."),
  1292. dwOrigDeviceId,
  1293. dwRes);
  1294. //
  1295. // We support writing to non-exiting devices configuration data
  1296. //
  1297. }
  1298. if (ERROR_SUCCESS == dwRes)
  1299. {
  1300. try
  1301. {
  1302. g_pNotificationMap->Notify (
  1303. dwFaxUniqueID, // Device for which data has changed
  1304. lpctstrNameGUID, // Name of data
  1305. lpcwstrComputerName,// Computer name from which data has chnaged
  1306. hInst, // Module handle from which data has changed
  1307. pData, // Pointer to new data
  1308. dwDataSize); // Size of new data
  1309. }
  1310. catch (exception &ex)
  1311. {
  1312. DebugPrintEx(
  1313. DEBUG_ERR,
  1314. TEXT("Notify() caused exception (%S)"),
  1315. ex.what());
  1316. }
  1317. }
  1318. exit:
  1319. LeaveCriticalSection (&g_pNotificationMap->m_CsExtensionData);
  1320. return dwRes;
  1321. } // FAXSetExtensionData
  1322. /************************************
  1323. * *
  1324. * RPC handlers *
  1325. * *
  1326. ************************************/
  1327. extern "C"
  1328. error_status_t
  1329. FAX_GetExtensionData (
  1330. IN handle_t hFaxHandle,
  1331. IN DWORD dwDeviceId,
  1332. IN LPCWSTR lpctstrNameGUID,
  1333. IN OUT LPBYTE *ppData,
  1334. IN OUT LPDWORD lpdwDataSize
  1335. )
  1336. /*++
  1337. Routine name : FAX_GetExtensionData
  1338. Routine description:
  1339. Read the extension's private data - Implements FaxGetExtensionData
  1340. Author:
  1341. Eran Yariv (EranY), Nov, 1999
  1342. Arguments:
  1343. hFaxHandle [in ] - Unused
  1344. dwDeviceId [in ] - Device identifier.
  1345. 0 = Unassociated data
  1346. lpctstrNameGUID [in ] - GUID of named data
  1347. ppData [out] - Pointer to data buffer
  1348. lpdwDataSize [out] - Returned size of data
  1349. Return Value:
  1350. Standard RPC error codes
  1351. --*/
  1352. {
  1353. DWORD dwRes;
  1354. BOOL fAccess;
  1355. DEBUG_FUNCTION_NAME(TEXT("FAX_GetExtensionData"));
  1356. //
  1357. // Access check
  1358. //
  1359. dwRes = FaxSvcAccessCheck (FAX_ACCESS_QUERY_CONFIG, &fAccess, NULL);
  1360. if (ERROR_SUCCESS != dwRes)
  1361. {
  1362. DebugPrintEx(DEBUG_ERR,
  1363. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  1364. dwRes);
  1365. return dwRes;
  1366. }
  1367. if (FALSE == fAccess)
  1368. {
  1369. DebugPrintEx(DEBUG_ERR,
  1370. TEXT("The user does not have the FAX_ACCESS_QUERY_CONFIG right"));
  1371. return ERROR_ACCESS_DENIED;
  1372. }
  1373. return FAXGetExtensionData (dwDeviceId,
  1374. DEV_ID_SRC_FAX, // RPC clients do not know the TAPI line ids
  1375. lpctstrNameGUID,
  1376. ppData,
  1377. lpdwDataSize);
  1378. } // FAX_GetExtensionData
  1379. extern "C"
  1380. error_status_t
  1381. FAX_SetExtensionData (
  1382. IN handle_t hFaxHandle,
  1383. IN LPCWSTR lpcwstrComputerName,
  1384. IN DWORD dwDeviceId,
  1385. IN LPCWSTR lpctstrNameGUID,
  1386. IN LPBYTE pData,
  1387. IN DWORD dwDataSize
  1388. )
  1389. /*++
  1390. Routine name : FAX_SetExtensionData
  1391. Routine description:
  1392. Write the extension's private data - Implements FaxSetExtensionData
  1393. Author:
  1394. Eran Yariv (EranY), Nov, 1999
  1395. Arguments:
  1396. hFaxHandle [in] - The handle of the module that sets the data
  1397. lpcwstrComputerName [in] - The computer name of the module that sets the data
  1398. dwDeviceId [in] - Device identifier.
  1399. 0 = Unassociated data
  1400. lpctstrNameGUID [in] - GUID of named data
  1401. pData [in] - Pointer to data
  1402. dwDataSize [in] - Size of data
  1403. Return Value:
  1404. Standard RPC error codes
  1405. --*/
  1406. {
  1407. DWORD dwRes;
  1408. BOOL fAccess;
  1409. DEBUG_FUNCTION_NAME(TEXT("FAX_SetExtensionData"));
  1410. //
  1411. // Access check
  1412. //
  1413. dwRes = FaxSvcAccessCheck (FAX_ACCESS_MANAGE_CONFIG, &fAccess, NULL);
  1414. if (ERROR_SUCCESS != dwRes)
  1415. {
  1416. DebugPrintEx(DEBUG_ERR,
  1417. TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
  1418. dwRes);
  1419. return dwRes;
  1420. }
  1421. if (FALSE == fAccess)
  1422. {
  1423. DebugPrintEx(DEBUG_ERR,
  1424. TEXT("The user does not have the FAX_ACCESS_MANAGE_CONFIG right"));
  1425. return ERROR_ACCESS_DENIED;
  1426. }
  1427. return FAXSetExtensionData ((HINSTANCE)hFaxHandle,
  1428. lpcwstrComputerName,
  1429. dwDeviceId,
  1430. DEV_ID_SRC_FAX, // RPC clients do not know the TAPI line ids
  1431. lpctstrNameGUID,
  1432. pData,
  1433. dwDataSize);
  1434. } // FAX_SetExtensionData
  1435. /************************************
  1436. * *
  1437. * Callback functions (fxsext.h) *
  1438. * *
  1439. ************************************/
  1440. DWORD
  1441. FaxExtGetData (
  1442. DWORD dwDeviceId, // Device id (0 = No device)
  1443. FAX_ENUM_DEVICE_ID_SOURCE DevIdSrc, // The source of the device id
  1444. LPCWSTR lpcwstrNameGUID,// GUID of data
  1445. LPBYTE *ppData, // (Out) Pointer to allocated data
  1446. LPDWORD lpdwDataSize // (Out) Pointer to data size
  1447. )
  1448. /*++
  1449. Routine name : FaxExtGetData
  1450. Routine description:
  1451. Callback function (called from the fax extension).
  1452. Gets data for a device + GUID
  1453. Author:
  1454. Eran Yariv (EranY), Dec, 1999
  1455. Arguments:
  1456. dwDeviceId [in] - Device id (0 = No device)
  1457. DevIdSrc [in] - The source of the device id
  1458. lpcwstrNameGUID [in] - GUID of data
  1459. ppData [in] - Pointer to data buffer
  1460. lpdwDataSize [in] - Data size retrieved
  1461. Return Value:
  1462. Standard Win32 error code
  1463. --*/
  1464. {
  1465. DEBUG_FUNCTION_NAME(TEXT("FaxExtGetData"));
  1466. if (g_bServiceIsDown)
  1467. {
  1468. //
  1469. // We don't supply extension data services when the service is going down
  1470. //
  1471. DebugPrintEx(
  1472. DEBUG_ERR,
  1473. TEXT("Called while service is shutting - operation canceled"));
  1474. return ERROR_SHUTDOWN_IN_PROGRESS;
  1475. }
  1476. return FAXGetExtensionData ( dwDeviceId,
  1477. DevIdSrc,
  1478. lpcwstrNameGUID,
  1479. ppData,
  1480. lpdwDataSize
  1481. );
  1482. } // FaxExtGetData
  1483. DWORD
  1484. FaxExtSetData (
  1485. HINSTANCE hInst,
  1486. DWORD dwDeviceId,
  1487. FAX_ENUM_DEVICE_ID_SOURCE DevIdSrc,
  1488. LPCWSTR lpcwstrNameGUID,
  1489. LPBYTE pData,
  1490. DWORD dwDataSize
  1491. )
  1492. /*++
  1493. Routine name : FaxExtSetData
  1494. Routine description:
  1495. Callback function (called from the fax extension).
  1496. Sets data for a device + GUID
  1497. Author:
  1498. Eran Yariv (EranY), Dec, 1999
  1499. Arguments:
  1500. hInst [in] - Extension DLL instance
  1501. dwDeviceId [in] - Device id (0 = No device)
  1502. DevIdSrc [in] - The source of the device id
  1503. lpcwstrNameGUID [in] - GUID of data
  1504. pData [in] - Pointer to data
  1505. size [in] - Data size
  1506. Return Value:
  1507. Standard Win32 error code
  1508. --*/
  1509. {
  1510. DEBUG_FUNCTION_NAME(TEXT("FaxExtSetData"));
  1511. if (g_bServiceIsDown)
  1512. {
  1513. //
  1514. // We don't supply extension data services when the service is going down
  1515. //
  1516. DebugPrintEx(
  1517. DEBUG_ERR,
  1518. TEXT("Called while service is shutting - operation canceled"));
  1519. return ERROR_SHUTDOWN_IN_PROGRESS;
  1520. }
  1521. return FAXSetExtensionData ( hInst,
  1522. TEXT (""), // No computer name - a local extension sets the data
  1523. dwDeviceId,
  1524. DevIdSrc,
  1525. lpcwstrNameGUID,
  1526. pData,
  1527. dwDataSize
  1528. );
  1529. } // FaxExtSetData
  1530. HANDLE
  1531. FaxExtRegisterForEvents (
  1532. HINSTANCE hInst,
  1533. DWORD dwDeviceId, // Device id (0 = No device)
  1534. FAX_ENUM_DEVICE_ID_SOURCE DevIdSrc, // The source of the device id
  1535. LPCWSTR lpcwstrNameGUID, // GUID of data
  1536. PFAX_EXT_CONFIG_CHANGE lpConfigChangeCallback // Notification callback function
  1537. )
  1538. /*++
  1539. Routine name : FaxExtRegisterForEvents
  1540. Routine description:
  1541. Register a local callback for notifications on a data change for a device and GUID
  1542. Author:
  1543. Eran Yariv (EranY), Nov, 1999
  1544. Arguments:
  1545. hInst [in] - Instance of calling extension
  1546. dwDeviceId [in] - Device id
  1547. bTapiDevice [in] - If TRUE, the function attempts to convert to a
  1548. Fax unique device id.
  1549. The callback will receive the device id specified in
  1550. dwDeviceId regardless of the lookup.
  1551. lpcwstrNameGUID [in] - Data name
  1552. lpConfigChangeCallback [in] - Pointer to notification callback function
  1553. Return Value:
  1554. Notification HANDLE.
  1555. If NULL, call GetLastError () to retrieve error code.
  1556. --*/
  1557. {
  1558. HANDLE h = NULL;
  1559. DEBUG_FUNCTION_NAME(TEXT("FaxExtRegisterForEvents"));
  1560. if (g_bServiceIsDown)
  1561. {
  1562. //
  1563. // We don't supply extension data services when the service is going down
  1564. //
  1565. DebugPrintEx(
  1566. DEBUG_ERR,
  1567. TEXT("Called while service is shutting - operation canceled"));
  1568. SetLastError (ERROR_SHUTDOWN_IN_PROGRESS);
  1569. return NULL;
  1570. }
  1571. if (!lpConfigChangeCallback)
  1572. {
  1573. SetLastError (ERROR_INVALID_PARAMETER);
  1574. return NULL;
  1575. }
  1576. DWORD dwRes = IsValidGUID (lpcwstrNameGUID);
  1577. if (ERROR_SUCCESS != dwRes)
  1578. {
  1579. if (ERROR_WMI_GUID_NOT_FOUND == dwRes)
  1580. {
  1581. //
  1582. // Return a more conservative error code
  1583. //
  1584. dwRes = ERROR_INVALID_PARAMETER;
  1585. }
  1586. SetLastError (dwRes);
  1587. return NULL;
  1588. }
  1589. //
  1590. // Notification is always done using the fax id (not the TAPI device id).
  1591. // We must lookup the fax id from the TAPI id before we attempt notification registration.
  1592. //
  1593. DWORD dwFaxUniqueID;
  1594. dwRes = LookupUniqueFaxDeviceId (dwDeviceId, &dwFaxUniqueID, DevIdSrc);
  1595. if (ERROR_SUCCESS != dwRes)
  1596. {
  1597. DebugPrintEx(
  1598. DEBUG_ERR,
  1599. TEXT("LookupUniqueFaxDeviceId failed for device id %ld (ec: %ld)"),
  1600. dwDeviceId,
  1601. dwRes);
  1602. SetLastError (dwRes);
  1603. return NULL;
  1604. }
  1605. EnterCriticalSection (&g_pNotificationMap->m_CsExtensionData);
  1606. try
  1607. {
  1608. //
  1609. // STL throws exceptions
  1610. //
  1611. h = (HANDLE) g_pNotificationMap->AddLocalSink (
  1612. hInst, // Instance of extension
  1613. dwFaxUniqueID, // Listen to fax device unique id
  1614. dwDeviceId, // Report the id specified by the caller.
  1615. lpcwstrNameGUID,
  1616. lpConfigChangeCallback);
  1617. }
  1618. catch (exception &ex)
  1619. {
  1620. DebugPrintEx(
  1621. DEBUG_ERR,
  1622. TEXT("AddLocalSink() caused exception (%S)"),
  1623. ex.what());
  1624. SetLastError (ERROR_GEN_FAILURE);
  1625. }
  1626. LeaveCriticalSection (&g_pNotificationMap->m_CsExtensionData);
  1627. return h;
  1628. } // FaxExtRegisterForEvents
  1629. DWORD
  1630. FaxExtUnregisterForEvents (
  1631. HANDLE hNotification
  1632. )
  1633. /*++
  1634. Routine name : FaxExtUnregisterForEvents
  1635. Routine description:
  1636. Unregsiters a local callback for notifications on a data change for a device and GUID.
  1637. The functions succeeds only if the same callback function was previously registered
  1638. (by calling FaxExtRegisterForEvents) to the same device id and GUID.
  1639. Author:
  1640. Eran Yariv (EranY), Nov, 1999
  1641. Arguments:
  1642. hNotification [in] - Notification handle
  1643. returned by FaxExtRegisterForExtensionEvents
  1644. Return Value:
  1645. Standard Win32 error code.
  1646. --*/
  1647. {
  1648. DWORD dwRes;
  1649. DEBUG_FUNCTION_NAME(TEXT("FaxExtUnregisterForEvents"));
  1650. if (g_bServiceIsDown)
  1651. {
  1652. //
  1653. // We don't supply extension data services when the service is going down
  1654. //
  1655. DebugPrintEx(
  1656. DEBUG_ERR,
  1657. TEXT("Called while service is shutting - operation canceled"));
  1658. return ERROR_SHUTDOWN_IN_PROGRESS;
  1659. }
  1660. EnterCriticalSection (&g_pNotificationMap->m_CsExtensionData);
  1661. try
  1662. {
  1663. //
  1664. // STL throws exceptions
  1665. //
  1666. dwRes = g_pNotificationMap->RemoveSink ( (CNotificationSink *)(hNotification) );
  1667. }
  1668. catch (exception &ex)
  1669. {
  1670. DebugPrintEx(
  1671. DEBUG_ERR,
  1672. TEXT("RemoveLocalSink() caused exception (%S)"),
  1673. ex.what());
  1674. dwRes = ERROR_GEN_FAILURE;
  1675. }
  1676. LeaveCriticalSection (&g_pNotificationMap->m_CsExtensionData);
  1677. return dwRes;
  1678. } // FaxExtUnregisterForEvents