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.

1569 lines
53 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. newfsp.c
  5. Abstract:
  6. This module implements a sample Windows NT Fax Service Provider
  7. --*/
  8. #include "newfsp.h"
  9. // DeviceReceiveThread() is a thread to watch for an incoming fax transmission
  10. DWORD WINAPI DeviceReceiveThread(LPDWORD pdwDeviceId);
  11. BOOL WINAPI
  12. DllEntryPoint(
  13. HINSTANCE hInstance,
  14. DWORD dwReason,
  15. LPVOID pContext
  16. )
  17. /*++
  18. Routine Description:
  19. DLL entry-point function
  20. Arguments:
  21. hInstance - handle to the DLL
  22. dwReason - specifies a flag indicating why the DLL entry-point function is being called
  23. Return Value:
  24. TRUE on success
  25. --*/
  26. {
  27. // pDeviceInfo is a pointer to the virtual fax devices
  28. PDEVICE_INFO pDeviceInfo;
  29. // pCurrentDeviceInfo is a pointer to the current virtual fax device
  30. PDEVICE_INFO pCurrentDeviceInfo;
  31. if (dwReason == DLL_PROCESS_ATTACH) {
  32. // Set g_hInstance
  33. g_hInstance = hInstance;
  34. // Disable the DLL_THREAD_ATTACH and DLL_THREAD_DETACH notifications for the DLL
  35. DisableThreadLibraryCalls(hInstance);
  36. }
  37. else if (dwReason == DLL_PROCESS_DETACH) {
  38. if (g_pDeviceInfo != NULL) {
  39. // Enumerate the virtual fax devices
  40. for (pCurrentDeviceInfo = g_pDeviceInfo[0]; pCurrentDeviceInfo; pCurrentDeviceInfo = pDeviceInfo) {
  41. pDeviceInfo = pCurrentDeviceInfo->pNextDeviceInfo;
  42. if (pCurrentDeviceInfo->ExitEvent) {
  43. // Set the event to indicate the thread to watch for an incoming fax transmission is to exit
  44. SetEvent(pCurrentDeviceInfo->ExitEvent);
  45. }
  46. // Delete the critical section
  47. DeleteCriticalSection(&pCurrentDeviceInfo->cs);
  48. // Delete the virtual fax device data
  49. MemFreeMacro(pCurrentDeviceInfo);
  50. }
  51. g_pDeviceInfo = NULL;
  52. }
  53. // Close the log file
  54. CloseLogFile();
  55. }
  56. return TRUE;
  57. }
  58. BOOL WINAPI
  59. FaxDevVirtualDeviceCreation(
  60. OUT LPDWORD DeviceCount,
  61. OUT LPWSTR DeviceNamePrefix,
  62. OUT LPDWORD DeviceIdPrefix,
  63. IN HANDLE CompletionPort,
  64. IN ULONG_PTR CompletionKey
  65. )
  66. /*++
  67. Routine Description:
  68. The fax service calls the FaxDevVirtualDeviceCreation function during initialization to allow the fax service provider to present virtual fax devices
  69. Arguments:
  70. DeviceCount - pointer to a variable that receives the number of virtual fax devices the fax service must create for the fax service provider
  71. DeviceNamePrefix - pointer to a variable that receives a string of the name prefix for the virtual fax devices
  72. DeviceIdPrefix - pointer to a variable that receives a unique numeric value that identifies the virtual fax devices
  73. CompletionPort - specifies a handle to an I/O completion port that the fax service provider must use to post I/O completion port packets to the fax service for asynchronous line status events
  74. CompletionKey - specifies a completion port key value
  75. Return Value:
  76. TRUE on success
  77. --*/
  78. {
  79. BOOL bReturnValue;
  80. WriteDebugString(L"---NewFsp: FaxDevVirtualDeviceCreation Enter---\n");
  81. // Initialize the parameters
  82. *DeviceCount = 0;
  83. ZeroMemory(DeviceNamePrefix, 128 * sizeof(WCHAR));
  84. *DeviceIdPrefix = 0;
  85. // Copy the handle to the completion port
  86. g_CompletionPort = CompletionPort;
  87. g_CompletionKey = CompletionKey;
  88. // Get the registry data for the newfsp service provider
  89. bReturnValue = GetNewFspRegistryData(NULL, NULL, NULL, DeviceCount);
  90. if (bReturnValue == FALSE) {
  91. WriteDebugString(L" ERROR: GetNewFspRegistryData Failed: 0x%08x\n", GetLastError());
  92. WriteDebugString(L" ERROR: FaxDevVirtualDeviceCreation Failed\n");
  93. WriteDebugString(L"---NewFsp: FaxDevVirtualDeviceCreation Exit---\n");
  94. return FALSE;
  95. }
  96. if (*DeviceCount == 0) {
  97. WriteDebugString(L" ERROR: No Virtual Fax Devices Installed\n");
  98. WriteDebugString(L" ERROR: FaxDevVirtualDeviceCreation Failed\n");
  99. WriteDebugString(L"---NewFsp: FaxDevVirtualDeviceCreation Exit---\n");
  100. return FALSE;
  101. }
  102. // Copy the name prefix for the virtual fax devices, limited to 128 WCHARs including the termininating null character
  103. lstrcpyn(DeviceNamePrefix, NEWFSP_DEVICE_NAME_PREFIX, 128);
  104. // Copy the values that identifies the virtual fax devices
  105. *DeviceIdPrefix = NEWFSP_DEVICE_ID_PREFIX;
  106. WriteDebugString(L"---NewFsp: FaxDevVirtualDeviceCreation Exit---\n");
  107. return TRUE;
  108. }
  109. VOID CALLBACK
  110. FaxLineCallback(
  111. IN HANDLE FaxHandle,
  112. IN DWORD hDevice,
  113. IN DWORD dwMessage,
  114. IN DWORD_PTR dwInstance,
  115. IN DWORD_PTR dwParam1,
  116. IN DWORD_PTR dwParam2,
  117. IN DWORD_PTR dwParam3
  118. )
  119. /*++
  120. Routine Description:
  121. An application-defined callback function that the fax service calls to deliver TAPI events to the fax service provider
  122. Arguments:
  123. FaxHandle - specifies a fax handle returned by the FaxDevStartJob function
  124. hDevice - specifies a handle to either a line device or a call device
  125. dwMessage - specifies a line device or a call device message
  126. dwInstance - specifies job-specific instance data passed back to the application
  127. dwParam1 - specifies a parameter for this message
  128. dwParam2 - specifies a parameter for this message
  129. dwParam3 - specifies a parameter for this message
  130. Return Value:
  131. TRUE on success
  132. --*/
  133. {
  134. // pdwDeviceId is the pointer to the virtual fax device identifier
  135. LPDWORD pdwDeviceId;
  136. // hThread is a handle to the thread to watch for an incoming fax transmission
  137. HANDLE hThread;
  138. WriteDebugString(L"---NewFsp: fnFaxLineCallback Enter---\n");
  139. // Wait for access to this virtual fax device
  140. EnterCriticalSection(&g_pDeviceInfo[hDevice - NEWFSP_DEVICE_ID_PREFIX]->cs);
  141. if ((dwParam1 == 0) && (g_pDeviceInfo[hDevice - NEWFSP_DEVICE_ID_PREFIX]->ExitEvent)) {
  142. // Receive has been disabled for this virtual fax device so set the event to indicate the thread to watch for an incoming fax transmission is to exit
  143. SetEvent(g_pDeviceInfo[hDevice - NEWFSP_DEVICE_ID_PREFIX]->ExitEvent);
  144. g_pDeviceInfo[hDevice - NEWFSP_DEVICE_ID_PREFIX]->ExitEvent = NULL;
  145. }
  146. else if ((dwParam1 != 0) && (g_pDeviceInfo[hDevice - NEWFSP_DEVICE_ID_PREFIX]->ExitEvent == NULL)) {
  147. // Allocate a block of memory for the virtual fax device identifier
  148. pdwDeviceId = MemAllocMacro(sizeof(DWORD));
  149. if (pdwDeviceId != NULL) {
  150. // Copy the virtual fax device identifier
  151. *pdwDeviceId = (hDevice - NEWFSP_DEVICE_ID_PREFIX);
  152. // Receive has been enabled for this virtual fax device so create the thread to watch for an incoming fax transmission
  153. g_pDeviceInfo[hDevice - NEWFSP_DEVICE_ID_PREFIX]->ExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  154. if (g_pDeviceInfo[hDevice - NEWFSP_DEVICE_ID_PREFIX]->ExitEvent != NULL) {
  155. hThread = CreateThread(NULL, 0, DeviceReceiveThread, pdwDeviceId, 0, NULL);
  156. if (hThread != NULL) {
  157. // Close the handle to the thread
  158. CloseHandle(hThread);
  159. }
  160. else {
  161. // Close the handle to the exit event
  162. CloseHandle(g_pDeviceInfo[hDevice - NEWFSP_DEVICE_ID_PREFIX]->ExitEvent);
  163. g_pDeviceInfo[hDevice - NEWFSP_DEVICE_ID_PREFIX]->ExitEvent = NULL;
  164. }
  165. }
  166. }
  167. }
  168. // Release access to this virtual fax device
  169. LeaveCriticalSection(&g_pDeviceInfo[hDevice - NEWFSP_DEVICE_ID_PREFIX]->cs);
  170. WriteDebugString(L"---NewFsp: fnFaxLineCallback Exit---\n");
  171. return;
  172. }
  173. BOOL WINAPI
  174. FaxDevInitialize(
  175. IN HLINEAPP LineAppHandle,
  176. IN HANDLE HeapHandle,
  177. OUT PFAX_LINECALLBACK *LineCallbackFunction,
  178. IN PFAX_SERVICE_CALLBACK FaxServiceCallback
  179. )
  180. /*++
  181. Routine Description:
  182. The fax service calls the FaxDevInitialize function each time the service starts to initialize communication between the fax service and the fax service provider DLL
  183. Arguments:
  184. LineAppHandle - specifies a handle to the fax service's registration with TAPI
  185. HeapHandle - specifies a handle to a heap that the fax service provider must use for all memory allocations
  186. LineCallbackFunction - pointer to a variable that receives a pointer to a TAPI line callback function
  187. FaxServiceCallback - pointer to a service callback function
  188. Return Value:
  189. TRUE on success
  190. --*/
  191. {
  192. // bLoggingEnabled indicates if logging is enabled
  193. BOOL bLoggingEnabled;
  194. // szLoggingDirectory indicates the logging directory
  195. WCHAR szLoggingDirectory[MAX_PATH_LEN];
  196. // pDeviceInfo is a pointer to the virtual fax devices
  197. PDEVICE_INFO pDeviceInfo;
  198. // pCurrentDeviceInfo is a pointer to the current virtual fax device
  199. PDEVICE_INFO pCurrentDeviceInfo;
  200. // dwNumDevices is the number of virtual fax devices
  201. DWORD dwNumDevices;
  202. // dwIndex is a counter to enumerate each virtual fax device
  203. DWORD dwIndex;
  204. // bReturnValue is the value to return to the fax service
  205. BOOL bReturnValue;
  206. WriteDebugString(L"---NewFsp: FaxDevInitialize Enter---\n");
  207. // Set g_hLineApp
  208. g_LineAppHandle = LineAppHandle;
  209. // Set g_hHeap
  210. MemInitializeMacro(HeapHandle);
  211. // Set LineCallbackFunction
  212. *LineCallbackFunction = FaxLineCallback;
  213. // Get the registry data for the newfsp service provider
  214. bLoggingEnabled = FALSE;
  215. ZeroMemory(szLoggingDirectory, sizeof(szLoggingDirectory));
  216. pDeviceInfo = NULL;
  217. dwNumDevices = 0;
  218. bReturnValue = GetNewFspRegistryData(&bLoggingEnabled, szLoggingDirectory, &pDeviceInfo, &dwNumDevices);
  219. if (bReturnValue == FALSE) {
  220. WriteDebugString(L" ERROR: GetNewFspRegistryData Failed: 0x%08x\n", GetLastError());
  221. WriteDebugString(L" ERROR: FaxDevInitialize Failed\n");
  222. WriteDebugString(L"---NewFsp: FaxDevInitialize Exit---\n");
  223. return FALSE;
  224. }
  225. if (dwNumDevices == 0) {
  226. WriteDebugString(L" ERROR: No Virtual Fax Devices Installed\n");
  227. WriteDebugString(L" ERROR: FaxDevInitialize Failed\n");
  228. WriteDebugString(L"---NewFsp: FaxDevInitialize Exit---\n");
  229. return FALSE;
  230. }
  231. // Open the log file
  232. bReturnValue = OpenLogFile(bLoggingEnabled, szLoggingDirectory);
  233. if (dwNumDevices > 0) {
  234. // Allocate a block of memory for the virtual fax device data
  235. g_pDeviceInfo = MemAllocMacro(sizeof(PDEVICE_INFO) * dwNumDevices);
  236. if (g_pDeviceInfo == NULL) {
  237. // Set the error code
  238. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  239. // Enumerate the virtual fax devices
  240. for (pCurrentDeviceInfo = pDeviceInfo; pCurrentDeviceInfo; pCurrentDeviceInfo = pDeviceInfo) {
  241. // Delete the virtual fax device data
  242. pDeviceInfo = pCurrentDeviceInfo->pNextDeviceInfo;
  243. MemFreeMacro(pCurrentDeviceInfo);
  244. }
  245. WriteDebugString(L" ERROR: FaxDevInitialize Failed: ERROR_NOT_ENOUGH_MEMORY\n");
  246. WriteDebugString(L"---NewFsp: FaxDevInitialize Exit---\n");
  247. return FALSE;
  248. }
  249. }
  250. else {
  251. g_pDeviceInfo = NULL;
  252. }
  253. // Marshall the virtual fax devices
  254. for (pCurrentDeviceInfo = pDeviceInfo, dwIndex = 0; pCurrentDeviceInfo; pCurrentDeviceInfo = pCurrentDeviceInfo->pNextDeviceInfo, dwIndex++) {
  255. g_pDeviceInfo[dwIndex] = pCurrentDeviceInfo;
  256. // Initialize the virtual fax device's critical section
  257. InitializeCriticalSection(&g_pDeviceInfo[dwIndex]->cs);
  258. // Initialize the virtual fax device's status to idle
  259. g_pDeviceInfo[dwIndex]->Status = DEVICE_IDLE;
  260. // Initialize the virtual fax device's handle to the exit event
  261. g_pDeviceInfo[dwIndex]->ExitEvent = NULL;
  262. // Initialize the virtual fax device's associated fax job
  263. g_pDeviceInfo[dwIndex]->pJobInfo = NULL;
  264. }
  265. WriteDebugString(L"---NewFsp: FaxDevInitialize Exit---\n");
  266. return TRUE;
  267. }
  268. BOOL WINAPI
  269. FaxDevStartJob(
  270. IN HLINE LineHandle,
  271. IN DWORD DeviceId,
  272. OUT PHANDLE FaxHandle,
  273. IN HANDLE CompletionPortHandle,
  274. IN ULONG_PTR CompletionKey
  275. )
  276. /*++
  277. Routine Description:
  278. The fax service calls the FaxDevStartJob function to initialize a new fax job
  279. Arguments:
  280. LineHandle - specifies a handle to the open line device associated with the fax job
  281. DeviceId - specifies the TAPI line device identifier associated with the fax job
  282. FaxHandle - pointer to a variable that receives a fax handle associated with the fax job
  283. CompltionPortHandle - specifies a handle to an I/O completion port
  284. CompletionKey - specifies a completion port key value
  285. Return Value:
  286. TRUE on success
  287. --*/
  288. {
  289. // pJobInfo is a pointer to the fax job data
  290. PJOB_INFO pJobInfo;
  291. WriteDebugString(L"---NewFsp: FaxDevStartJob Enter---\n");
  292. // Initialize the parameters
  293. *FaxHandle = NULL;
  294. // Allocate a block of memory for the fax job instance data
  295. pJobInfo = MemAllocMacro(sizeof(JOB_INFO));
  296. if (pJobInfo == NULL) {
  297. // Set the error code
  298. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  299. WriteDebugString(L" ERROR: FaxDevStartJob Failed: ERROR_NOT_ENOUGH_MEMORY\n");
  300. WriteDebugString(L"---NewFsp: FaxDevStartJob Exit---\n");
  301. return FALSE;
  302. }
  303. // Set the FaxHandle
  304. *FaxHandle = (PHANDLE) pJobInfo;
  305. // Wait for access to this virtual fax device
  306. EnterCriticalSection(&g_pDeviceInfo[DeviceId]->cs);
  307. // Initialize the fax job data
  308. // Set the fax job's associated virtual fax device
  309. pJobInfo->pDeviceInfo = g_pDeviceInfo[DeviceId];
  310. // Copy the handle to the I/O completion port
  311. pJobInfo->CompletionPortHandle = CompletionPortHandle;
  312. // Copy the completion port key value
  313. pJobInfo->CompletionKey = CompletionKey;
  314. // Initialize the fax job type
  315. pJobInfo->JobType = JOB_UNKNOWN;
  316. // Set the fax job status to FS_INITIALIZING
  317. pJobInfo->Status = FS_INITIALIZING;
  318. // Copy the handle to the open line device associated with the fax job
  319. pJobInfo->LineHandle = LineHandle;
  320. // Initialize the handle to the active call associated with the fax job
  321. pJobInfo->CallHandle = (HCALL) 0;
  322. // Initialize the full path to the file that contains the data stream for the fax document
  323. pJobInfo->FileName = NULL;
  324. // Initialize the name of the calling device
  325. pJobInfo->CallerName = NULL;
  326. // Initialize the telephone number of the calling device
  327. pJobInfo->CallerNumber = NULL;
  328. // Initialize name of the receiving device
  329. pJobInfo->ReceiverName = NULL;
  330. // Initialize telephone number of the receiving device
  331. pJobInfo->ReceiverNumber = NULL;
  332. // Initialize number of retries associated with the fax job
  333. pJobInfo->RetryCount = 0;
  334. // Initialize whether the fax service provider should generate a brand at the top of the fax transmission
  335. pJobInfo->Branding = FALSE;
  336. // Initialize the number of pages associated with the fax job
  337. pJobInfo->PageCount = 0;
  338. // Initialize the identifier of the remote fax device
  339. pJobInfo->CSI = NULL;
  340. // Initialize the identifier of the calling fax device
  341. pJobInfo->CallerId = NULL;
  342. // Initialize the routing string associated with the fax job
  343. pJobInfo->RoutingInfo = NULL;
  344. // Set the virtual fax device status
  345. g_pDeviceInfo[DeviceId]->Status = DEVICE_START;
  346. // Set the virtual fax device's associated fax job
  347. g_pDeviceInfo[DeviceId]->pJobInfo = pJobInfo;
  348. // Release access to this virtual fax device
  349. LeaveCriticalSection(&g_pDeviceInfo[DeviceId]->cs);
  350. WriteDebugString(L"---NewFsp: FaxDevStartJob Exit---\n");
  351. return TRUE;
  352. }
  353. BOOL WINAPI
  354. FaxDevEndJob(
  355. IN HANDLE FaxHandle
  356. )
  357. /*++
  358. Routine Description:
  359. The fax service calls the FaxDevEndJob function after the last operation in a fax job
  360. Arguments:
  361. FaxHandle - specifies a fax handle returned by the FaxDevStartJob function
  362. Return Value:
  363. TRUE on success
  364. --*/
  365. {
  366. // pJobInfo is a pointer to the fax job data
  367. PJOB_INFO pJobInfo;
  368. // pDeviceInfo is a pointer to the virtual fax device data
  369. PDEVICE_INFO pDeviceInfo;
  370. WriteDebugString(L"---NewFsp: FaxDevEndJob Enter---\n");
  371. if (FaxHandle == NULL) {
  372. // Set the error code
  373. SetLastError(ERROR_INVALID_HANDLE);
  374. WriteDebugString(L" ERROR: FaxDevEndJob Failed: ERROR_INVALID_HANDLE\n");
  375. WriteDebugString(L"---NewFsp: FaxDevEndJob Exit---\n");
  376. return FALSE;
  377. }
  378. // Get the fax job data from FaxHandle
  379. pJobInfo = (PJOB_INFO) FaxHandle;
  380. // Get the virtual fax device data from the fax job data
  381. pDeviceInfo = (PDEVICE_INFO) pJobInfo->pDeviceInfo;
  382. // Wait for access to this virtual fax device
  383. EnterCriticalSection(&pDeviceInfo->cs);
  384. // Free the fax job data
  385. // Free the full path to the file that contains the data stream for the fax document
  386. if (pJobInfo->FileName != NULL) {
  387. MemFreeMacro(pJobInfo->FileName);
  388. }
  389. // Free the name of the calling device
  390. if (pJobInfo->CallerName != NULL) {
  391. MemFreeMacro(pJobInfo->CallerName);
  392. }
  393. // Free the telephone number of the calling device
  394. if (pJobInfo->CallerNumber != NULL) {
  395. MemFreeMacro(pJobInfo->CallerNumber);
  396. }
  397. // Free name of the receiving device
  398. if (pJobInfo->ReceiverName != NULL) {
  399. MemFreeMacro(pJobInfo->ReceiverName);
  400. }
  401. // Free telephone number of the receiving device
  402. if (pJobInfo->ReceiverNumber != NULL) {
  403. MemFreeMacro(pJobInfo->ReceiverNumber);
  404. }
  405. // Free the identifier of the remote fax device
  406. if (pJobInfo->CSI != NULL) {
  407. MemFreeMacro(pJobInfo->CSI);
  408. }
  409. // Free the identifier of the calling fax device
  410. if (pJobInfo->CallerId != NULL) {
  411. MemFreeMacro(pJobInfo->CallerId);
  412. }
  413. // Free the routing string associated with the fax job
  414. if (pJobInfo->RoutingInfo != NULL) {
  415. MemFreeMacro(pJobInfo->RoutingInfo);
  416. }
  417. // Free the fax job data
  418. MemFreeMacro(pJobInfo);
  419. // Set the virtual fax device status
  420. pDeviceInfo->Status = DEVICE_IDLE;
  421. // Initialize the virtual fax device's associated fax job
  422. pDeviceInfo->pJobInfo = NULL;
  423. // Release access to this virtual fax device
  424. LeaveCriticalSection(&pDeviceInfo->cs);
  425. WriteDebugString(L"---NewFsp: FaxDevEndJob Exit---\n");
  426. return TRUE;
  427. }
  428. BOOL WINAPI
  429. FaxDevSend(
  430. IN HANDLE FaxHandle,
  431. IN PFAX_SEND FaxSend,
  432. IN PFAX_SEND_CALLBACK FaxSendCallback
  433. )
  434. /*++
  435. Routine Description:
  436. The fax service calls the FaxDevSend function to signal a fax service provider that it must initiate an outgoing fax transmission
  437. Arguments:
  438. FaxHandle - specifies a fax handle returned by the FaxDevStartJob function
  439. FaxSend - pointer to a FAX_SEND structure that contains the sending information
  440. FaxSendCallback - pointer to a callback function that notifies the fax service of the call handle that TAPI assigns
  441. Return Value:
  442. TRUE on success
  443. --*/
  444. {
  445. // pJobInfo is a pointer to the fax job data
  446. PJOB_INFO pJobInfo;
  447. // pDeviceInfo is a pointer to the virtual fax device data
  448. PDEVICE_INFO pDeviceInfo;
  449. // dwReceiverNumberAttributes is the file attributes of the directory specified in the telephone number of the receiving device
  450. DWORD dwReceiverNumberAttributes;
  451. // hSourceFile is the handle to the source file
  452. HANDLE hSourceFile = INVALID_HANDLE_VALUE;
  453. // szSourceName is the source filename name
  454. WCHAR szSourceName[_MAX_FNAME];
  455. // szSourceExt is the source filename extension
  456. WCHAR szSourceExt[_MAX_EXT];
  457. // hDestinationFile is the handle to the destination file
  458. HANDLE hDestinationFile = INVALID_HANDLE_VALUE;
  459. // szDestinationFilename is the destination filename
  460. WCHAR szDestinationFilename[MAX_PATH];
  461. // FileBytes is the bytes to be copied from the source file to the destination file
  462. BYTE FileBytes[1024];
  463. // dwBytes is the number of bytes read from the source file
  464. DWORD dwBytes;
  465. WriteDebugString(L"---NewFsp: FaxDevSend Enter---\n");
  466. if (FaxHandle == NULL) {
  467. // Set the error code
  468. SetLastError(ERROR_INVALID_HANDLE);
  469. WriteDebugString(L" ERROR: FaxDevSend Failed: ERROR_INVALID_HANDLE\n");
  470. WriteDebugString(L"---NewFsp: FaxDevSend Exit---\n");
  471. return FALSE;
  472. }
  473. // Get the fax job data from FaxHandle
  474. pJobInfo = (PJOB_INFO) FaxHandle;
  475. // Get the virtual fax device data from the fax job data
  476. pDeviceInfo = (PDEVICE_INFO) pJobInfo->pDeviceInfo;
  477. // Wait for access to this virtual fax device
  478. EnterCriticalSection(&pDeviceInfo->cs);
  479. if (pDeviceInfo->Status == DEVICE_ABORTING) {
  480. goto ExitUserAbort;
  481. }
  482. // Set the virtual fax device status
  483. pDeviceInfo->Status = DEVICE_SEND;
  484. // Set the fax job type
  485. pJobInfo->JobType = JOB_SEND;
  486. // Copy the handle to the active call associated with the fax job
  487. pJobInfo->CallHandle = FaxSend->CallHandle;
  488. // Copy the full path to the file that contains the data stream for the fax document
  489. if (FaxSend->FileName != NULL) {
  490. pJobInfo->FileName = MemAllocMacro((lstrlen(FaxSend->FileName) + 1) * sizeof(WCHAR));
  491. if (pJobInfo->FileName) {
  492. lstrcpy(pJobInfo->FileName, FaxSend->FileName);
  493. }
  494. }
  495. // Copy the name of the calling device
  496. if (FaxSend->CallerName != NULL) {
  497. pJobInfo->CallerName = MemAllocMacro((lstrlen(FaxSend->CallerName) + 1) * sizeof(WCHAR));
  498. if (pJobInfo->CallerName) {
  499. lstrcpy(pJobInfo->CallerName, FaxSend->CallerName);
  500. }
  501. }
  502. // Copy the telephone number of the calling device
  503. if (FaxSend->CallerNumber != NULL) {
  504. pJobInfo->CallerNumber = MemAllocMacro((lstrlen(FaxSend->CallerNumber) + 1) * sizeof(WCHAR));
  505. if (pJobInfo->CallerNumber) {
  506. lstrcpy(pJobInfo->CallerNumber, FaxSend->CallerNumber);
  507. }
  508. }
  509. // Copy the name of the receiving device
  510. if (FaxSend->ReceiverName != NULL) {
  511. pJobInfo->ReceiverName = MemAllocMacro((lstrlen(FaxSend->ReceiverName) + 1) * sizeof(WCHAR));
  512. if (pJobInfo->ReceiverName) {
  513. lstrcpy(pJobInfo->ReceiverName, FaxSend->ReceiverName);
  514. }
  515. }
  516. // Copy the telephone number of the receiving device
  517. if (FaxSend->ReceiverNumber != NULL) {
  518. pJobInfo->ReceiverNumber = MemAllocMacro((lstrlen(FaxSend->ReceiverNumber) + 1) * sizeof(WCHAR));
  519. if (pJobInfo->ReceiverNumber) {
  520. lstrcpy(pJobInfo->ReceiverNumber, FaxSend->ReceiverNumber);
  521. }
  522. }
  523. // Copy whether the fax service provider should generate a brand at the top of the fax transmission
  524. pJobInfo->Branding = FaxSend->Branding;
  525. // Release access to this virtual fax device
  526. LeaveCriticalSection(&pDeviceInfo->cs);
  527. WriteDebugString(L" FaxSend->SizeOfStruct : 0x%08x\n", FaxSend->SizeOfStruct);
  528. WriteDebugString(L" FaxSend->FileName : %s\n", FaxSend->FileName);
  529. WriteDebugString(L" FaxSend->CallerName : %s\n", FaxSend->CallerName);
  530. WriteDebugString(L" FaxSend->CallerNumber : %s\n", FaxSend->CallerNumber);
  531. WriteDebugString(L" FaxSend->ReceiverName : %s\n", FaxSend->ReceiverName);
  532. WriteDebugString(L" FaxSend->ReceiverNumber : %s\n", FaxSend->ReceiverNumber);
  533. WriteDebugString(L" FaxSend->Branding : %s\n", FaxSend->Branding ? L"TRUE" : L"FALSE");
  534. WriteDebugString(L" FaxSend->CallHandle : 0x%08x\n", FaxSend->CallHandle);
  535. // Wait for access to this virtual fax device
  536. EnterCriticalSection(&pDeviceInfo->cs);
  537. if (pDeviceInfo->Status == DEVICE_ABORTING) {
  538. goto ExitUserAbort;
  539. }
  540. // Set the fax job status
  541. pJobInfo->Status = FS_INITIALIZING;
  542. // Post the FS_INITIALIZING line status event to the fax service
  543. PostJobStatus(pJobInfo->CompletionPortHandle, pJobInfo->CompletionKey, FS_INITIALIZING, ERROR_SUCCESS);
  544. // Validate the telephone number of the receive device
  545. dwReceiverNumberAttributes = GetFileAttributes(FaxSend->ReceiverNumber);
  546. if ((dwReceiverNumberAttributes == 0xFFFFFFFF) || ((dwReceiverNumberAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)) {
  547. // The telephone number of the receive device is invalid
  548. goto ExitFatalError;
  549. }
  550. // Open the source file
  551. hSourceFile = CreateFile(FaxSend->FileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  552. if (hSourceFile == INVALID_HANDLE_VALUE) {
  553. // The source file failed to be opened
  554. goto ExitFatalError;
  555. }
  556. // Split the full path of the file that contains the data stream for the fax document
  557. _wsplitpath(FaxSend->FileName, NULL, NULL, szSourceName, szSourceExt);
  558. // Set the destination filename
  559. lstrcpy(szDestinationFilename, FaxSend->ReceiverNumber);
  560. lstrcat(szDestinationFilename, L"\\");
  561. lstrcat(szDestinationFilename, szSourceName);
  562. lstrcat(szDestinationFilename, szSourceExt);
  563. // Create the destination file
  564. hDestinationFile = CreateFile(szDestinationFilename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  565. if (hDestinationFile == INVALID_HANDLE_VALUE) {
  566. // The destination file failed to be created
  567. goto ExitFatalError;
  568. }
  569. // Release access to this virtual fax device
  570. LeaveCriticalSection(&pDeviceInfo->cs);
  571. // Wait for access to this virtual fax device
  572. EnterCriticalSection(&pDeviceInfo->cs);
  573. if (pDeviceInfo->Status == DEVICE_ABORTING) {
  574. goto ExitUserAbort;
  575. }
  576. // Set the fax job status
  577. pJobInfo->Status = FS_TRANSMITTING;
  578. // Post the FS_TRANSMITTING line status event to the fax service
  579. PostJobStatus(pJobInfo->CompletionPortHandle, pJobInfo->CompletionKey, FS_TRANSMITTING, ERROR_SUCCESS);
  580. // Release access to this virtual fax device
  581. LeaveCriticalSection(&pDeviceInfo->cs);
  582. while (TRUE) {
  583. // The following sleep statement slows the bit copy to a reasonable speed so that a FaxDevAbortOperation() call is possible
  584. Sleep(250);
  585. // Wait for access to this virtual fax device
  586. EnterCriticalSection(&pDeviceInfo->cs);
  587. if (pDeviceInfo->Status == DEVICE_ABORTING) {
  588. goto ExitUserAbort;
  589. }
  590. // Read the bytes from the source file
  591. if (ReadFile(hSourceFile, &FileBytes, sizeof(FileBytes), &dwBytes, NULL) == FALSE) {
  592. // Failed to read the bytes from the source file
  593. goto ExitFatalError;
  594. }
  595. if (dwBytes == 0) {
  596. // The file pointer has reached the end of the source file
  597. // Release access to this virtual fax device
  598. LeaveCriticalSection(&pDeviceInfo->cs);
  599. break;
  600. }
  601. // Write the bytes to the destination file
  602. if (WriteFile(hDestinationFile, &FileBytes, dwBytes, &dwBytes, NULL) == FALSE) {
  603. // Failed to write the bytes to the destination file
  604. goto ExitFatalError;
  605. }
  606. // Release access to this virtual fax device
  607. LeaveCriticalSection(&pDeviceInfo->cs);
  608. }
  609. // Wait for access to this virtual fax device
  610. EnterCriticalSection(&pDeviceInfo->cs);
  611. if (pDeviceInfo->Status == DEVICE_ABORTING) {
  612. goto ExitUserAbort;
  613. }
  614. // Close the destination file
  615. CloseHandle(hDestinationFile);
  616. // Close the source file
  617. CloseHandle(hSourceFile);
  618. // Set the fax job status
  619. pJobInfo->Status = FS_COMPLETED;
  620. // Post the FS_COMPLETED line status event to the fax service
  621. PostJobStatus(pJobInfo->CompletionPortHandle, pJobInfo->CompletionKey, FS_COMPLETED, ERROR_SUCCESS);
  622. // Release access to this virtual fax device
  623. LeaveCriticalSection(&pDeviceInfo->cs);
  624. WriteDebugString(L"---NewFsp: FaxDevSend Exit---\n");
  625. return TRUE;
  626. ExitFatalError:
  627. // Set the fax job status
  628. pJobInfo->Status = FS_FATAL_ERROR;
  629. goto Exit;
  630. ExitUserAbort:
  631. // Set the fax job status
  632. pJobInfo->Status = FS_USER_ABORT;
  633. goto Exit;
  634. Exit:
  635. // Close and delete the destination file
  636. if (hDestinationFile != INVALID_HANDLE_VALUE) {
  637. CloseHandle(hDestinationFile);
  638. DeleteFile(szDestinationFilename);
  639. }
  640. // Close the source file
  641. if (hSourceFile != INVALID_HANDLE_VALUE) {
  642. CloseHandle(hSourceFile);
  643. }
  644. // Post the line status event to the fax service
  645. PostJobStatus(pJobInfo->CompletionPortHandle, pJobInfo->CompletionKey, pJobInfo->Status, ERROR_SUCCESS);
  646. // Release access to this virtual fax device
  647. LeaveCriticalSection(&pDeviceInfo->cs);
  648. WriteDebugString(L"---NewFsp: FaxDevSend Exit---\n");
  649. return FALSE;
  650. }
  651. BOOL WINAPI
  652. FaxDevReceive(
  653. IN HANDLE FaxHandle,
  654. IN HCALL CallHandle,
  655. IN OUT PFAX_RECEIVE FaxReceive
  656. )
  657. /*++
  658. Routine Description:
  659. The fax service calls the FaxDevReceive function to signal an incoming fax transmission to the fax service provider
  660. Arguments:
  661. FaxHandle - specifies a fax handle returned by the FaxDevStartJob function
  662. CallHandle - specifies a TAPI call handle
  663. FaxReceive - pointer to a FAX_RECEIVE stucture that contains information about an incoming fax document
  664. Return Value:
  665. TRUE on success
  666. --*/
  667. {
  668. // pJobInfo is a pointer to the fax job data
  669. PJOB_INFO pJobInfo;
  670. // pDeviceInfo is a pointer to the virtual fax device data
  671. PDEVICE_INFO pDeviceInfo;
  672. // hSourceFile is the handle to the source file
  673. HANDLE hSourceFile = INVALID_HANDLE_VALUE;
  674. // szSourceFilename is the source filename
  675. WCHAR szSourceFilename[MAX_PATH];
  676. // hFindFile is a find file handle
  677. HANDLE hFindFile = INVALID_HANDLE_VALUE;
  678. // FindData is a WIN32_FIND_DATA structure
  679. WIN32_FIND_DATA FindData;
  680. // szSearchPath is the search path
  681. WCHAR szSearchPath[MAX_PATH];
  682. // hDestinationFile is the handle to the destination file
  683. HANDLE hDestinationFile = INVALID_HANDLE_VALUE;
  684. // FileBytes is the bytes to be copied from the source file to the destination file
  685. BYTE FileBytes[1024];
  686. // dwBytes is the number of bytes read from the source file
  687. DWORD dwBytes;
  688. WriteDebugString(L"---NewFsp: FaxDevReceive Enter---\n");
  689. if (FaxHandle == NULL) {
  690. // Set the error code
  691. SetLastError(ERROR_INVALID_HANDLE);
  692. WriteDebugString(L" ERROR: FaxDevReceive Failed: ERROR_INVALID_HANDLE\n");
  693. WriteDebugString(L"---NewFsp: FaxDevReceive Exit---\n");
  694. return FALSE;
  695. }
  696. // Get the fax job data from FaxHandle
  697. pJobInfo = (PJOB_INFO) FaxHandle;
  698. // Get the virtual fax device data from the fax job data
  699. pDeviceInfo = (PDEVICE_INFO) pJobInfo->pDeviceInfo;
  700. // Wait for access to this virtual fax device
  701. EnterCriticalSection(&pDeviceInfo->cs);
  702. if (pDeviceInfo->Status == DEVICE_ABORTING) {
  703. goto ExitUserAbort;
  704. }
  705. // Set the virtual fax device status
  706. pDeviceInfo->Status = DEVICE_RECEIVE;
  707. // Set the fax job type
  708. pJobInfo->JobType = JOB_RECEIVE;
  709. // Copy the handle to the active call associated with the fax job
  710. pJobInfo->CallHandle = CallHandle;
  711. // Copy the full path to the file that contains the data stream for the fax document
  712. if (FaxReceive->FileName != NULL) {
  713. pJobInfo->FileName = MemAllocMacro((lstrlen(FaxReceive->FileName) + 1) * sizeof(WCHAR));
  714. if (pJobInfo->FileName != NULL) {
  715. lstrcpy(pJobInfo->FileName, FaxReceive->FileName);
  716. }
  717. }
  718. // Release access to this virtual fax device
  719. LeaveCriticalSection(&pDeviceInfo->cs);
  720. WriteDebugString(L" CallHandle : 0x%08x\n", CallHandle);
  721. WriteDebugString(L" FaxReceive->SizeOfStruct : 0x%08x\n", FaxReceive->SizeOfStruct);
  722. WriteDebugString(L" FaxReceive->FileName : %s\n", FaxReceive->FileName);
  723. WriteDebugString(L" FaxReceive->ReceiverName : %s\n", FaxReceive->ReceiverName);
  724. WriteDebugString(L" FaxReceive->ReceiverNumber : %s\n", FaxReceive->ReceiverNumber);
  725. // Wait for access to this virtual fax device
  726. EnterCriticalSection(&pDeviceInfo->cs);
  727. if (pDeviceInfo->Status == DEVICE_ABORTING) {
  728. goto ExitUserAbort;
  729. }
  730. // Set the fax job status
  731. pJobInfo->Status = FS_ANSWERED;
  732. // Post the FS_ANSWERED line status event to the fax service
  733. PostJobStatus(pJobInfo->CompletionPortHandle, pJobInfo->CompletionKey, FS_ANSWERED, ERROR_SUCCESS);
  734. // Set the search path
  735. lstrcpy(szSearchPath, pDeviceInfo->Directory);
  736. lstrcat(szSearchPath, L"\\*.tif");
  737. // Initialize the find file data
  738. ZeroMemory(&FindData, sizeof(FindData));
  739. FindData.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
  740. // Find the incoming fax file
  741. hFindFile = FindFirstFile(szSearchPath, &FindData);
  742. if (hFindFile == INVALID_HANDLE_VALUE) {
  743. // The incoming fax file was not found
  744. goto ExitFatalError;
  745. }
  746. // Close the find file handle
  747. FindClose(hFindFile);
  748. hFindFile = INVALID_HANDLE_VALUE;
  749. // Set the source filename
  750. lstrcpy(szSourceFilename, pDeviceInfo->Directory);
  751. lstrcat(szSourceFilename, L"\\");
  752. lstrcat(szSourceFilename, FindData.cFileName);
  753. // Open the source file
  754. hSourceFile = CreateFile(szSourceFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  755. if (hSourceFile == INVALID_HANDLE_VALUE) {
  756. // The source file failed to be opened
  757. goto ExitFatalError;
  758. }
  759. // Open the destination file
  760. hDestinationFile = CreateFile(FaxReceive->FileName, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  761. if (hDestinationFile == INVALID_HANDLE_VALUE) {
  762. // The destination file failed to be created
  763. goto ExitFatalError;
  764. }
  765. // Release access to this virtual fax device
  766. LeaveCriticalSection(&pDeviceInfo->cs);
  767. // Wait for access to this virtual fax device
  768. EnterCriticalSection(&pDeviceInfo->cs);
  769. if (pDeviceInfo->Status == DEVICE_ABORTING) {
  770. goto ExitUserAbort;
  771. }
  772. // Set the fax job status
  773. pJobInfo->Status = FS_RECEIVING;
  774. // Post the FS_RECEIVING line status event to the fax service
  775. PostJobStatus(pJobInfo->CompletionPortHandle, pJobInfo->CompletionKey, FS_RECEIVING, ERROR_SUCCESS);
  776. // Release access to this virtual fax device
  777. LeaveCriticalSection(&pDeviceInfo->cs);
  778. while (TRUE) {
  779. // The following sleep statement slows the bit copy to a reasonable speed so that a FaxDevAbortOperation() call is possible
  780. Sleep(250);
  781. // Wait for access to this virtual fax device
  782. EnterCriticalSection(&pDeviceInfo->cs);
  783. if (pDeviceInfo->Status == DEVICE_ABORTING) {
  784. goto ExitUserAbort;
  785. }
  786. // Read the bytes from the source file
  787. if (ReadFile(hSourceFile, &FileBytes, sizeof(FileBytes), &dwBytes, NULL) == FALSE) {
  788. // Failed to read the bytes from the source file
  789. goto ExitFatalError;
  790. }
  791. if (dwBytes == 0) {
  792. // The file pointer has reached the end of the source file
  793. // Release access to this virtual fax device
  794. LeaveCriticalSection(&pDeviceInfo->cs);
  795. break;
  796. }
  797. // Write the bytes to the destination file
  798. if (WriteFile(hDestinationFile, &FileBytes, dwBytes, &dwBytes, NULL) == TRUE) {
  799. // Failed to write the bytes to the destination file
  800. goto ExitFatalError;
  801. }
  802. // Release access to this virtual fax device
  803. LeaveCriticalSection(&pDeviceInfo->cs);
  804. }
  805. // Wait for access to this virtual fax device
  806. EnterCriticalSection(&pDeviceInfo->cs);
  807. if (pDeviceInfo->Status == DEVICE_ABORTING) {
  808. goto ExitUserAbort;
  809. }
  810. // Close the destination file
  811. CloseHandle(hDestinationFile);
  812. // Close the source file
  813. CloseHandle(hSourceFile);
  814. // Set the fax job status
  815. pJobInfo->Status = FS_COMPLETED;
  816. // Post the FS_COMPLETED line status event to the fax service
  817. PostJobStatus(pJobInfo->CompletionPortHandle, pJobInfo->CompletionKey, FS_COMPLETED, ERROR_SUCCESS);
  818. // Release access to this virtual fax device
  819. LeaveCriticalSection(&pDeviceInfo->cs);
  820. WriteDebugString(L"---NewFsp: FaxDevReceive Exit---\n");
  821. return TRUE;
  822. ExitFatalError:
  823. // Set the fax job status
  824. pJobInfo->Status = FS_FATAL_ERROR;
  825. goto Exit;
  826. ExitUserAbort:
  827. // Set the fax job status
  828. pJobInfo->Status = FS_USER_ABORT;
  829. goto Exit;
  830. Exit:
  831. // Close the destination file
  832. if (hDestinationFile != INVALID_HANDLE_VALUE) {
  833. CloseHandle(hDestinationFile);
  834. }
  835. // Close the source file
  836. if (hSourceFile != INVALID_HANDLE_VALUE) {
  837. CloseHandle(hSourceFile);
  838. }
  839. // Post the line status event to the fax service
  840. PostJobStatus(pJobInfo->CompletionPortHandle, pJobInfo->CompletionKey, pJobInfo->Status, ERROR_SUCCESS);
  841. // Release access to this virtual fax device
  842. LeaveCriticalSection(&pDeviceInfo->cs);
  843. WriteDebugString(L"---NewFsp: FaxDevReceive Exit---\n");
  844. return FALSE;
  845. }
  846. BOOL WINAPI
  847. FaxDevReportStatus(
  848. IN HANDLE FaxHandle OPTIONAL,
  849. OUT PFAX_DEV_STATUS FaxStatus,
  850. IN DWORD FaxStatusSize,
  851. OUT LPDWORD FaxStatusSizeRequired
  852. )
  853. /*++
  854. Routine Description:
  855. The fax service calls the FaxDevReportStatus function to query a fax service provider for status information about an individual active fax operation or for status information after a failed fax operation
  856. Arguments:
  857. FaxHandle - specifies a fax handle returned by the FaxDevStartJob function
  858. FaxStatus - pointer to a FAX_DEV_STATUS structure that receives status and identification information
  859. FaxStatusSize - specifies the size, in bytes, of the buffer pointer to by the FaxStatus parameter
  860. FaxStatusSizeRequired - pointer to a variable that receives the calculated size, in bytes, of the buffer required to hold the FAX_DEV_STATUS structure
  861. Return Value:
  862. TRUE on success
  863. --*/
  864. {
  865. // pJobInfo is a pointer to the fax job data
  866. PJOB_INFO pJobInfo;
  867. // pDeviceInfo is a pointer to the virtual fax device data
  868. PDEVICE_INFO pDeviceInfo;
  869. // dwSize is the size of the completion packet
  870. DWORD dwSize;
  871. // upString is the offset of the strings within the completion packet
  872. UINT_PTR upStringOffset;
  873. WriteDebugString(L"---NewFsp: FaxDevReportStatus Enter---\n");
  874. if (FaxHandle == NULL) {
  875. // Set the error code
  876. SetLastError(ERROR_INVALID_HANDLE);
  877. WriteDebugString(L" ERROR: FaxDevReportStatus Failed: ERROR_INVALID_HANDLE\n");
  878. WriteDebugString(L"---NewFsp: FaxDevReportStatus Exit---\n");
  879. return FALSE;
  880. }
  881. if (FaxStatusSizeRequired == NULL) {
  882. // Set the error code
  883. SetLastError(ERROR_INVALID_PARAMETER);
  884. WriteDebugString(L" ERROR: FaxDevReportStatus Failed: ERROR_INVALID_PARAMETER\n");
  885. WriteDebugString(L"---NewFsp: FaxDevReportStatus Exit---\n");
  886. return FALSE;
  887. }
  888. if ((FaxStatus == NULL) && (FaxStatusSize != 0)) {
  889. // Set the error code
  890. SetLastError(ERROR_INVALID_PARAMETER);
  891. WriteDebugString(L" ERROR: FaxDevReportStatus Failed: ERROR_INVALID_PARAMETER\n");
  892. WriteDebugString(L"---NewFsp: FaxDevReportStatus Exit---\n");
  893. return FALSE;
  894. }
  895. // Get the fax job data from FaxHandle
  896. pJobInfo = (PJOB_INFO) FaxHandle;
  897. // Get the virtual fax device data from the fax job data
  898. pDeviceInfo = (PDEVICE_INFO) pJobInfo->pDeviceInfo;
  899. // Wait for access to this virtual fax device
  900. EnterCriticalSection(&pDeviceInfo->cs);
  901. // Initialize the size of the completion packet
  902. dwSize = sizeof(FAX_DEV_STATUS);
  903. if (pJobInfo->CSI != NULL) {
  904. // Increase the size of the completion packet for the remote fax device indentifier
  905. dwSize += (lstrlen(pJobInfo->CSI) + 1) * sizeof(WCHAR);
  906. }
  907. if (pJobInfo->CallerId != NULL) {
  908. // Increase the size of the completion packet for the calling fax device identifier
  909. dwSize += (lstrlen(pJobInfo->CallerId) + 1) * sizeof(WCHAR);
  910. }
  911. if (pJobInfo->RoutingInfo != NULL) {
  912. // Increase the size of the completion packet for the routing string
  913. dwSize += (lstrlen(pJobInfo->RoutingInfo) + 1) * sizeof(WCHAR);
  914. }
  915. // Set the calculated size of the buffer required to hold the completion packet
  916. *FaxStatusSizeRequired = dwSize;
  917. if ((FaxStatus == NULL) && (FaxStatusSize == 0)) {
  918. // Release access to this virtual fax device
  919. LeaveCriticalSection(&pDeviceInfo->cs);
  920. WriteDebugString(L"---NewFsp: FaxDevReportStatus Exit---\n");
  921. return TRUE;
  922. }
  923. if (FaxStatusSize < dwSize) {
  924. // Set the error code
  925. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  926. // Release access to this virtual fax device
  927. LeaveCriticalSection(&pDeviceInfo->cs);
  928. WriteDebugString(L" ERROR: FaxDevReportStatus Failed: ERROR_INSUFFICIENT_BUFFER\n");
  929. WriteDebugString(L"---NewFsp: FaxDevReportStatus Exit---\n");
  930. return FALSE;
  931. }
  932. // Initialize upStringOffset
  933. upStringOffset = sizeof(FAX_DEV_STATUS);
  934. // Set the completion packet's structure size
  935. FaxStatus->SizeOfStruct = sizeof(FAX_DEV_STATUS);
  936. // Copy the completion packet's fax status identifier
  937. FaxStatus->StatusId = pJobInfo->Status;
  938. // Set the completion packet's string resource identifier to 0
  939. FaxStatus->StringId = 0;
  940. // Copy the completion packet's current page number
  941. FaxStatus->PageCount = pJobInfo->PageCount;
  942. // Copy the completion packet's remote fax device identifier
  943. if (pJobInfo->CSI != NULL) {
  944. FaxStatus->CSI = (LPWSTR) ((UINT_PTR) FaxStatus + upStringOffset);
  945. lstrcpy(FaxStatus->CSI, pJobInfo->CSI);
  946. upStringOffset += (lstrlen(pJobInfo->CSI) + 1) * sizeof(WCHAR);
  947. }
  948. // Set the completion packet's calling fax device identifier to NULL
  949. FaxStatus->CallerId = NULL;
  950. if (pJobInfo->CallerId != NULL) {
  951. FaxStatus->CallerId = (LPWSTR) ((UINT_PTR) FaxStatus + upStringOffset);
  952. lstrcpy(FaxStatus->CallerId, pJobInfo->CallerId);
  953. upStringOffset += (lstrlen(pJobInfo->CallerId) + 1) * sizeof(WCHAR);
  954. }
  955. // Set the completion packet's routing string to NULL
  956. FaxStatus->RoutingInfo = NULL;
  957. if (pJobInfo->RoutingInfo != NULL) {
  958. FaxStatus->RoutingInfo = (LPWSTR) ((UINT_PTR) FaxStatus + upStringOffset);
  959. lstrcpy(FaxStatus->RoutingInfo, pJobInfo->RoutingInfo);
  960. upStringOffset += (lstrlen(pJobInfo->RoutingInfo) + 1) * sizeof(WCHAR);
  961. }
  962. // Copy the completion packet's Win32 error code
  963. FaxStatus->ErrorCode = ERROR_SUCCESS;
  964. // Release access to this virtual fax device
  965. LeaveCriticalSection(&pDeviceInfo->cs);
  966. WriteDebugString(L"---NewFsp: FaxDevReportStatus Exit---\n");
  967. return TRUE;
  968. }
  969. BOOL WINAPI
  970. FaxDevAbortOperation(
  971. IN HANDLE FaxHandle
  972. )
  973. /*++
  974. Routine Description:
  975. The fax service calls the FaxDevAbortOperation function to request that the fax service provider terminate the active fax operation for the fax job specified by the FaxHandle parameter
  976. Arguments:
  977. FaxHandle - specifies a fax handle returned by the FaxDevStartJob function
  978. Return Value:
  979. TRUE on success
  980. --*/
  981. {
  982. // pJobInfo is a pointer to the fax job data
  983. PJOB_INFO pJobInfo;
  984. // pDeviceInfo is a pointer to the virtual fax device data
  985. PDEVICE_INFO pDeviceInfo;
  986. WriteDebugString(L"---NewFsp: FaxDevAbortOperation Enter---\n");
  987. if (FaxHandle == NULL) {
  988. // Set the error code
  989. SetLastError(ERROR_INVALID_HANDLE);
  990. WriteDebugString(L" ERROR: FaxDevAbortOperation Failed: ERROR_INVALID_HANDLE\n");
  991. WriteDebugString(L"---NewFsp: FaxDevAbortOperation Exit---\n");
  992. return FALSE;
  993. }
  994. // Get the fax job data from FaxHandle
  995. pJobInfo = (PJOB_INFO) FaxHandle;
  996. // Get the virtual fax device data from the fax job data
  997. pDeviceInfo = (PDEVICE_INFO) pJobInfo->pDeviceInfo;
  998. // Wait for access to this virtual fax device
  999. EnterCriticalSection(&pDeviceInfo->cs);
  1000. // Set the virtual fax device status
  1001. pDeviceInfo->Status = DEVICE_ABORTING;
  1002. // Release access to this virtual fax device
  1003. LeaveCriticalSection(&pDeviceInfo->cs);
  1004. WriteDebugString(L"---NewFsp: FaxDevAbortOperation Exit---\n");
  1005. return TRUE;
  1006. }
  1007. DWORD WINAPI DeviceReceiveThread(LPDWORD pdwDeviceId)
  1008. /*++
  1009. Routine Description:
  1010. Thread to watch for an incoming fax transmission
  1011. Arguments:
  1012. pdwDeviceId - pointer to the virtual fax device identifier
  1013. Return Value:
  1014. DWORD
  1015. --*/
  1016. {
  1017. // hChangeNotification is a handle to a notification change in a directory
  1018. HANDLE hChangeNotification;
  1019. // hWaitObjects are the handles to the wait objects
  1020. HANDLE hWaitObjects[2];
  1021. // dwDeviceId is the virtual fax device identifier
  1022. DWORD dwDeviceId;
  1023. // pLineMessage is a pointer to LINEMESSAGE structure to signal an incoming fax transmission to the fax service
  1024. LPLINEMESSAGE pLineMessage;
  1025. WriteDebugString(L"---NewFsp: DeviceReceiveThread Enter---\n");
  1026. // Copy the virtual fax device identifier
  1027. dwDeviceId = *pdwDeviceId;
  1028. MemFreeMacro(pdwDeviceId);
  1029. // Create the change notification handle
  1030. hChangeNotification = FindFirstChangeNotification(g_pDeviceInfo[dwDeviceId]->Directory, FALSE, FILE_NOTIFY_CHANGE_ATTRIBUTES);
  1031. if (hChangeNotification == INVALID_HANDLE_VALUE) {
  1032. goto Exit;
  1033. }
  1034. // Wait for access to this virtual fax device
  1035. EnterCriticalSection(&g_pDeviceInfo[dwDeviceId]->cs);
  1036. // Set hWaitObjects
  1037. hWaitObjects[0] = g_pDeviceInfo[dwDeviceId]->ExitEvent;
  1038. hWaitObjects[1] = hChangeNotification;
  1039. // Release access to this virtual fax device
  1040. LeaveCriticalSection(&g_pDeviceInfo[dwDeviceId]->cs);
  1041. while (TRUE) {
  1042. // Wait for the exit event or notification change to be signaled
  1043. if (WaitForMultipleObjects(2, hWaitObjects, FALSE, INFINITE) == WAIT_OBJECT_0) {
  1044. break;
  1045. }
  1046. // Wait for access to this virtual fax device
  1047. EnterCriticalSection(&g_pDeviceInfo[dwDeviceId]->cs);
  1048. if (g_pDeviceInfo[dwDeviceId]->Status == DEVICE_IDLE) {
  1049. // Allocate a block of memory for the completion packet
  1050. pLineMessage = LocalAlloc(LPTR, sizeof(LINEMESSAGE));
  1051. if (pLineMessage != NULL) {
  1052. // Initialize the completion packet
  1053. // Set the completion packet's handle to the virtual fax device
  1054. pLineMessage->hDevice = dwDeviceId + NEWFSP_DEVICE_ID_PREFIX;
  1055. // Set the completion packet's virtual fax device message
  1056. pLineMessage->dwMessageID = 0;
  1057. // Set the completion packet's instance data
  1058. pLineMessage->dwCallbackInstance = 0;
  1059. // Set the completion packet's first parameter
  1060. pLineMessage->dwParam1 = LINEDEVSTATE_RINGING;
  1061. // Set the completion packet's second parameter
  1062. pLineMessage->dwParam2 = 0;
  1063. // Set the completion packet's third parameter
  1064. pLineMessage->dwParam3 = 0;
  1065. WriteDebugString(L"---NewFsp: DeviceReceiveThread Signaling Fax Service...---\n");
  1066. // Post the completion packet
  1067. PostQueuedCompletionStatus(g_CompletionPort, sizeof(LINEMESSAGE), g_CompletionKey, (LPOVERLAPPED) pLineMessage);
  1068. }
  1069. }
  1070. // Release access to this virtual fax device
  1071. LeaveCriticalSection(&g_pDeviceInfo[dwDeviceId]->cs);
  1072. // Find the next notification change
  1073. FindNextChangeNotification(hChangeNotification);
  1074. }
  1075. Exit:
  1076. if (hChangeNotification != INVALID_HANDLE_VALUE) {
  1077. // Close the handle to the change notification
  1078. FindCloseChangeNotification(hChangeNotification);
  1079. }
  1080. // Close the handle to the exit event
  1081. CloseHandle(hWaitObjects[0]);
  1082. WriteDebugString(L"---NewFsp: DeviceReceiveThread Exit---\n");
  1083. return 0;
  1084. }
  1085. STDAPI DllRegisterServer()
  1086. /*++
  1087. Routine Description:
  1088. Function for the in-process server to create its registry entries
  1089. Return Value:
  1090. S_OK on success
  1091. --*/
  1092. {
  1093. // hModWinfax is the handle to the winfax module
  1094. HANDLE hModWinfax;
  1095. // szCurrentDirectory is the name of the current directory
  1096. WCHAR szCurrentDirectory[MAX_PATH_LEN];
  1097. // szCurrentFilename is the name of the current filename
  1098. WCHAR szCurrentFilename[MAX_PATH];
  1099. // szDestinationFilename is the name of the destination filename
  1100. WCHAR szDestinationFilename[MAX_PATH];
  1101. // pFaxRegisterServiceProvider is a pointer to the FaxRegisterServiceProvider() winfax api
  1102. PFAXREGISTERSERVICEPROVIDER pFaxRegisterServiceProvider;
  1103. // pDeviceInfo is a pointer to the virtual fax devices
  1104. PDEVICE_INFO pDeviceInfo;
  1105. // pCurrentDeviceInfo is a pointer to the current virtual fax device
  1106. PDEVICE_INFO pCurrentDeviceInfo;
  1107. // dwIndex is a counter to enumerate each virtual fax device
  1108. DWORD dwIndex;
  1109. // Open the log file
  1110. OpenLogFile(FALSE, NULL);
  1111. WriteDebugString(L"---NewFsp: DllRegisterServer Enter---\n");
  1112. // Get the current directory
  1113. if (GetCurrentDirectory(MAX_PATH_LEN, szCurrentDirectory) == 0) {
  1114. WriteDebugString(L" ERROR: GetCurrentDirectory Failed: 0x%08x\n", GetLastError());
  1115. WriteDebugString(L" ERROR: DllRegisterServer Failed\n");
  1116. WriteDebugString(L"---NewFsp: DllRegisterServer Exit---\n");
  1117. // Close the log file
  1118. CloseLogFile();
  1119. return E_UNEXPECTED;
  1120. }
  1121. // Set the current filename
  1122. lstrcpy(szCurrentFilename, szCurrentDirectory);
  1123. lstrcat(szCurrentFilename, L"\\newfsp.dll");
  1124. // Get the destination filename
  1125. if (ExpandEnvironmentStrings(NEWFSP_PROVIDER_IMAGENAME, szDestinationFilename, MAX_PATH) == 0) {
  1126. WriteDebugString(L" ERROR: ExpandEnvironmentStrings Failed: 0x%08x\n", GetLastError());
  1127. WriteDebugString(L" ERROR: DllRegisterServer Failed\n");
  1128. WriteDebugString(L"---NewFsp: DllRegisterServer Exit---\n");
  1129. // Close the log file
  1130. CloseLogFile();
  1131. return E_UNEXPECTED;
  1132. }
  1133. if (lstrcmpi(szDestinationFilename, szCurrentFilename) != 0) {
  1134. // Copy the current filename to the destination filename
  1135. if (CopyFile(L"newfsp.dll", szDestinationFilename, FALSE) == FALSE) {
  1136. WriteDebugString(L" ERROR: CopyFile Failed: 0x%08x\n", GetLastError());
  1137. WriteDebugString(L" ERROR: DllRegisterServer Failed\n");
  1138. WriteDebugString(L"---NewFsp: DllRegisterServer Exit---\n");
  1139. // Close the log file
  1140. CloseLogFile();
  1141. return E_UNEXPECTED;
  1142. }
  1143. }
  1144. // Load the winfax dll
  1145. hModWinfax = LoadLibrary( L"winfax.dll" );
  1146. if (hModWinfax == NULL) {
  1147. WriteDebugString(L" ERROR: LoadLibrary Failed: 0x%08x\n", GetLastError());
  1148. WriteDebugString(L" ERROR: DllRegisterServer Failed\n");
  1149. WriteDebugString(L"---NewFsp: DllRegisterServer Exit---\n");
  1150. // Close the log file
  1151. CloseLogFile();
  1152. return E_UNEXPECTED;
  1153. }
  1154. pFaxRegisterServiceProvider = (PFAXREGISTERSERVICEPROVIDER) GetProcAddress(hModWinfax, "FaxRegisterServiceProviderW");
  1155. if (pFaxRegisterServiceProvider == NULL) {
  1156. WriteDebugString(L" ERROR: GetProcAddress Failed: 0x%08x\n", GetLastError());
  1157. WriteDebugString(L" ERROR: DllRegisterServer Failed\n");
  1158. FreeLibrary(hModWinfax);
  1159. WriteDebugString(L"---NewFsp: DllRegisterServer Exit---\n");
  1160. // Close the log file
  1161. CloseLogFile();
  1162. return E_UNEXPECTED;
  1163. }
  1164. // Register the fax service provider
  1165. if (pFaxRegisterServiceProvider(NEWFSP_PROVIDER, NEWFSP_PROVIDER_FRIENDLYNAME, NEWFSP_PROVIDER_IMAGENAME, NEWFSP_PROVIDER_PROVIDERNAME) == FALSE) {
  1166. WriteDebugString(L" ERROR: FaxRegisterServiceProvider Failed: 0x%08x\n", GetLastError());
  1167. WriteDebugString(L" ERROR: DllRegisterServer Failed\n");
  1168. FreeLibrary(hModWinfax);
  1169. WriteDebugString(L"---NewFsp: DllRegisterServer Exit---\n");
  1170. // Close the log file
  1171. CloseLogFile();
  1172. return E_UNEXPECTED;
  1173. }
  1174. FreeLibrary(hModWinfax);
  1175. // Set g_hHeap
  1176. MemInitializeMacro(GetProcessHeap());
  1177. // Create the virtual fax devices
  1178. for (dwIndex = 0, pCurrentDeviceInfo = NULL, pDeviceInfo = NULL; dwIndex < NEWFSP_DEVICE_LIMIT; dwIndex++) {
  1179. // Allocate a block of memory for the virtual fax device data
  1180. if (pCurrentDeviceInfo == NULL) {
  1181. pCurrentDeviceInfo = MemAllocMacro(sizeof(DEVICE_INFO));
  1182. if (pCurrentDeviceInfo == NULL) {
  1183. continue;
  1184. }
  1185. }
  1186. else {
  1187. pCurrentDeviceInfo->pNextDeviceInfo = MemAllocMacro(sizeof(DEVICE_INFO));
  1188. if (pCurrentDeviceInfo->pNextDeviceInfo == NULL) {
  1189. continue;
  1190. }
  1191. // Set the pointer to the current virtual fax device
  1192. pCurrentDeviceInfo = pCurrentDeviceInfo->pNextDeviceInfo;
  1193. }
  1194. // Set the indentifier of the virtual fax device
  1195. pCurrentDeviceInfo->DeviceId = dwIndex;
  1196. // Set the virtual fax device's incoming fax directory to the current directory
  1197. lstrcpy(pCurrentDeviceInfo->Directory, szCurrentDirectory);
  1198. if (pDeviceInfo == NULL) {
  1199. // Set the pointer to the virtual fax devices
  1200. pDeviceInfo = pCurrentDeviceInfo;
  1201. }
  1202. }
  1203. // Set the registry data for the newfsp service provider
  1204. SetNewFspRegistryData(FALSE, szCurrentDirectory, pDeviceInfo);
  1205. // Enumerate the virtual fax devices
  1206. for (pCurrentDeviceInfo = pDeviceInfo; pCurrentDeviceInfo; pCurrentDeviceInfo = pDeviceInfo) {
  1207. // Delete the virtual fax device data
  1208. pDeviceInfo = pCurrentDeviceInfo->pNextDeviceInfo;
  1209. MemFreeMacro(pCurrentDeviceInfo);
  1210. }
  1211. WriteDebugString(L"---NewFsp: DllRegisterServer Exit---\n");
  1212. // Close the log file
  1213. CloseLogFile();
  1214. return S_OK;
  1215. }