2020 lines
81 KiB
C++
2020 lines
81 KiB
C++
//==========================================================================
|
|
//
|
|
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
// PARTICULAR PURPOSE.
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
//
|
|
//This module implements a sample Windows NT Fax Service Provider
|
|
//
|
|
|
|
#include "SampleFSP.h"
|
|
#include <tchar.h>
|
|
|
|
HANDLE g_HeapHandle = NULL;
|
|
|
|
// DeviceReceiveThread() is a thread to watch for an incoming fax transmission
|
|
DWORD WINAPI DeviceReceiveThread(LPDWORD pdwDeviceId);
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// function: DllEntryPoint
|
|
//
|
|
// Synopsis: DLL entry-point function
|
|
//
|
|
// Arguments: [hInstance] - handle to the DLL
|
|
// [dwReason] - specifies a flag indicating why the DLL entry-point function is being called
|
|
//
|
|
// Returns: TRUE on success
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL WINAPI
|
|
DllEntryPoint(
|
|
HINSTANCE hInstance,
|
|
DWORD dwReason,
|
|
LPVOID pContext
|
|
)
|
|
{
|
|
// pDeviceInfo is a pointer to the virtual fax devices
|
|
PDEVICE_INFO pDeviceInfo;
|
|
// pCurrentDeviceInfo is a pointer to the current virtual fax device
|
|
PDEVICE_INFO pCurrentDeviceInfo;
|
|
|
|
if (dwReason == DLL_PROCESS_ATTACH) {
|
|
// Set g_hInstance
|
|
g_hInstance = hInstance;
|
|
// Disable the DLL_THREAD_ATTACH and DLL_THREAD_DETACH notifications for the DLL
|
|
DisableThreadLibraryCalls(hInstance);
|
|
}
|
|
else if (dwReason == DLL_PROCESS_DETACH) {
|
|
if (g_pDeviceInfo != NULL) {
|
|
// Enumerate the virtual fax devices
|
|
for (pCurrentDeviceInfo = g_pDeviceInfo[0]; pCurrentDeviceInfo; pCurrentDeviceInfo = pDeviceInfo) {
|
|
pDeviceInfo = pCurrentDeviceInfo->pNextDeviceInfo;
|
|
|
|
if (pCurrentDeviceInfo->ExitEvent) {
|
|
// Set the event to indicate the thread to watch for an incoming fax transmission is to exit
|
|
SetEvent(pCurrentDeviceInfo->ExitEvent);
|
|
}
|
|
|
|
// Delete the critical section
|
|
DeleteCriticalSection(&pCurrentDeviceInfo->cs);
|
|
// Delete the virtual fax device data
|
|
MemFreeMacro(pCurrentDeviceInfo);
|
|
}
|
|
g_pDeviceInfo = NULL;
|
|
}
|
|
// Close the log file
|
|
CloseLogFile();
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// function: FaxDevVirtualDeviceCreation
|
|
//
|
|
// Synopsis: The fax service calls the FaxDevVirtualDeviceCreation function during
|
|
// initialization to allow the fax service provider
|
|
// to present virtual fax devices
|
|
//
|
|
// Arguments: [DeviceCount] - pointer to a variable that receives the number of virtual
|
|
// fax devices the fax service must create for the fax service provider
|
|
// [DeviceNamePrefix] - pointer to a variable that receives a string of the
|
|
// name prefix for the virtual fax devices
|
|
// [DeviceIdPrefix] - pointer to a variable that receives a unique numeric
|
|
// value that identifies the virtual fax devices
|
|
// [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
|
|
// [CompletionKey] - specifies a completion port key value
|
|
//
|
|
// Returns: TRUE on success
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL WINAPI
|
|
FaxDevVirtualDeviceCreation(
|
|
OUT LPDWORD DeviceCount,
|
|
OUT LPWSTR DeviceNamePrefix,
|
|
OUT LPDWORD DeviceIdPrefix,
|
|
IN HANDLE CompletionPort,
|
|
IN ULONG_PTR CompletionKey
|
|
)
|
|
{
|
|
BOOL bReturnValue;
|
|
HRESULT hr = S_OK;
|
|
|
|
WriteDebugString(L"---SampleFSP: FaxDevVirtualDeviceCreation Enter---\n");
|
|
|
|
// Initialize the parameters
|
|
*DeviceCount = 0;
|
|
ZeroMemory(DeviceNamePrefix, 128 * sizeof(WCHAR));
|
|
*DeviceIdPrefix = 0;
|
|
|
|
// Copy the handle to the completion port
|
|
g_CompletionPort = CompletionPort;
|
|
g_CompletionKey = CompletionKey;
|
|
|
|
// Get the registry data for the newfsp service provider
|
|
bReturnValue = GetNewFspRegistryData(NULL,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
DeviceCount);
|
|
|
|
if (bReturnValue == FALSE) {
|
|
WriteDebugString(L" ERROR: GetNewFspRegistryData Failed: 0x%08x\n", GetLastError());
|
|
WriteDebugString(L" ERROR: FaxDevVirtualDeviceCreation Failed\n");
|
|
WriteDebugString(L"---SampleFSP: FaxDevVirtualDeviceCreation Exit---\n");
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if (*DeviceCount == 0) {
|
|
WriteDebugString(L" ERROR: No Virtual Fax Devices Installed\n");
|
|
WriteDebugString(L" ERROR: FaxDevVirtualDeviceCreation Failed\n");
|
|
WriteDebugString(L"---SampleFSP: FaxDevVirtualDeviceCreation Exit---\n");
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
// Copy the name prefix for the virtual fax devices, limited to 128 WCHARs including the termininating null character
|
|
hr = StringCchCopy(DeviceNamePrefix, 128, NEWFSP_DEVICE_NAME_PREFIX);
|
|
if(hr != S_OK)
|
|
{
|
|
WriteDebugString(L"StringCchCopy failed, hr = 0x%x for DeviceNamePrefix", hr);
|
|
return FALSE;
|
|
}
|
|
// Copy the values that identifies the virtual fax devices
|
|
*DeviceIdPrefix = NEWFSP_DEVICE_ID_PREFIX;
|
|
|
|
WriteDebugString(L"---SampleFSP: FaxDevVirtualDeviceCreation Exit---\n");
|
|
|
|
return TRUE;
|
|
}
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// function: FaxLineCallback
|
|
//
|
|
// Synopsis: An application-defined callback function that the fax service calls
|
|
// to deliver TAPI events to the fax service provider
|
|
//
|
|
// Arguments: [FaxHandle] - specifies a fax handle returned by the FaxDevStartJob function
|
|
// [hDevice] - specifies a handle to either a line device or a call device
|
|
// [dwMessage] - specifies a line device or a call device message
|
|
// [dwInstance] - specifies job-specific instance data passed back to the application
|
|
// [dwParam1] - specifies a parameter for this message
|
|
// [dwParam2] - specifies a parameter for this message
|
|
// [dwParam3] - specifies a parameter for this message
|
|
// Returns: TRUE on success
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
VOID CALLBACK
|
|
FaxLineCallback(
|
|
IN HANDLE FaxHandle,
|
|
IN DWORD hDevice,
|
|
IN DWORD dwMessage,
|
|
IN DWORD_PTR dwInstance,
|
|
IN DWORD_PTR dwParam1,
|
|
IN DWORD_PTR dwParam2,
|
|
IN DWORD_PTR dwParam3
|
|
)
|
|
{
|
|
// pdwDeviceId is the pointer to the virtual fax device identifier
|
|
LPDWORD pdwDeviceId;
|
|
// hThread is a handle to the thread to watch for an incoming fax transmission
|
|
HANDLE hThread;
|
|
|
|
WriteDebugString(L"---SampleFSP: fnFaxLineCallback Enter---\n");
|
|
|
|
// Wait for access to this virtual fax device
|
|
EnterCriticalSection(&g_pDeviceInfo[hDevice - NEWFSP_DEVICE_ID_PREFIX]->cs);
|
|
|
|
if ((dwParam1 == 0) && (g_pDeviceInfo[hDevice - NEWFSP_DEVICE_ID_PREFIX]->ExitEvent)) {
|
|
// 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
|
|
SetEvent(g_pDeviceInfo[hDevice - NEWFSP_DEVICE_ID_PREFIX]->ExitEvent);
|
|
g_pDeviceInfo[hDevice - NEWFSP_DEVICE_ID_PREFIX]->ExitEvent = NULL;
|
|
}
|
|
else if ((dwParam1 != 0) && (g_pDeviceInfo[hDevice - NEWFSP_DEVICE_ID_PREFIX]->ExitEvent == NULL)) {
|
|
// Allocate a block of memory for the virtual fax device identifier
|
|
pdwDeviceId = (LPDWORD) MemAllocMacro(sizeof(DWORD));
|
|
if (pdwDeviceId != NULL) {
|
|
// Copy the virtual fax device identifier
|
|
*pdwDeviceId = (hDevice - NEWFSP_DEVICE_ID_PREFIX);
|
|
|
|
// Receive has been enabled for this virtual fax device so create the thread to watch for an incoming fax transmission
|
|
g_pDeviceInfo[hDevice - NEWFSP_DEVICE_ID_PREFIX]->ExitEvent = CreateEvent(NULL,
|
|
TRUE,
|
|
FALSE,
|
|
NULL);
|
|
if (g_pDeviceInfo[hDevice - NEWFSP_DEVICE_ID_PREFIX]->ExitEvent != NULL) {
|
|
hThread = CreateThread(NULL,
|
|
0,
|
|
(unsigned long (_stdcall*) (void*)) DeviceReceiveThread,
|
|
pdwDeviceId,
|
|
0,
|
|
NULL);
|
|
if (hThread != NULL) {
|
|
// Close the handle to the thread
|
|
CloseHandle(hThread);
|
|
}
|
|
else {
|
|
// Close the handle to the exit event
|
|
CloseHandle(g_pDeviceInfo[hDevice - NEWFSP_DEVICE_ID_PREFIX]->ExitEvent);
|
|
g_pDeviceInfo[hDevice - NEWFSP_DEVICE_ID_PREFIX]->ExitEvent = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Release access to this virtual fax device
|
|
LeaveCriticalSection(&g_pDeviceInfo[hDevice - NEWFSP_DEVICE_ID_PREFIX]->cs);
|
|
|
|
WriteDebugString(L"---SampleFSP: fnFaxLineCallback Exit---\n");
|
|
|
|
return;
|
|
}
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// function: FaxDevInitialize
|
|
//
|
|
// Synopsis: 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
|
|
//
|
|
// Arguments: [LineAppHandle] - specifies a handle to the fax service's registration with TAPI
|
|
// [HeapHandle] - specifies a handle to a heap that the fax service provider must
|
|
// use for all memory allocations
|
|
// [LineCallbackFunction] - pointer to a variable that receives a pointer to a TAPI
|
|
// line callback function
|
|
// [FaxServiceCallback] - pointer to a service callback function
|
|
//
|
|
// Returns: TRUE on success
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL WINAPI
|
|
FaxDevInitialize(
|
|
IN HLINEAPP LineAppHandle,
|
|
IN HANDLE HeapHandle,
|
|
OUT PFAX_LINECALLBACK *LineCallbackFunction,
|
|
IN PFAX_SERVICE_CALLBACK FaxServiceCallback
|
|
)
|
|
{
|
|
// bLoggingEnabled indicates if logging is enabled
|
|
BOOL bLoggingEnabled;
|
|
// szLoggingDirectory indicates the logging directory
|
|
WCHAR szLoggingDirectory[MAX_PATH_LEN];
|
|
// pDeviceInfo is a pointer to the virtual fax devices
|
|
PDEVICE_INFO pDeviceInfo;
|
|
// pCurrentDeviceInfo is a pointer to the current virtual fax device
|
|
PDEVICE_INFO pCurrentDeviceInfo;
|
|
// dwNumDevices is the number of virtual fax devices
|
|
DWORD dwNumDevices;
|
|
// dwIndex is a counter to enumerate each virtual fax device
|
|
DWORD dwIndex;
|
|
// bReturnValue is the value to return to the fax service
|
|
BOOL bReturnValue;
|
|
|
|
WriteDebugString(L"---SampleFSP: FaxDevInitialize Enter---\n");
|
|
|
|
// Set g_hLineApp
|
|
g_LineAppHandle = LineAppHandle;
|
|
|
|
// Set g_hHeap
|
|
MemInitializeMacro(HeapHandle);
|
|
|
|
// Set LineCallbackFunction
|
|
*LineCallbackFunction = FaxLineCallback;
|
|
|
|
// Get the registry data for the newfsp service provider
|
|
bLoggingEnabled = FALSE;
|
|
ZeroMemory(szLoggingDirectory, sizeof(szLoggingDirectory));
|
|
pDeviceInfo = NULL;
|
|
dwNumDevices = 0;
|
|
bReturnValue = GetNewFspRegistryData(&bLoggingEnabled,
|
|
szLoggingDirectory,
|
|
sizeof(szLoggingDirectory)/sizeof(szLoggingDirectory[0]),
|
|
&pDeviceInfo,
|
|
&dwNumDevices);
|
|
|
|
if (bReturnValue == FALSE) {
|
|
WriteDebugString(L" ERROR: GetNewFspRegistryData Failed: 0x%08x\n", GetLastError());
|
|
WriteDebugString(L" ERROR: FaxDevInitialize Failed\n");
|
|
WriteDebugString(L"---SampleFSP: FaxDevInitialize Exit---\n");
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if (dwNumDevices == 0) {
|
|
WriteDebugString(L" ERROR: No Virtual Fax Devices Installed\n");
|
|
WriteDebugString(L" ERROR: FaxDevInitialize Failed\n");
|
|
WriteDebugString(L"---SampleFSP: FaxDevInitialize Exit---\n");
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
// Open the log file
|
|
bReturnValue = OpenLogFile(bLoggingEnabled, szLoggingDirectory);
|
|
|
|
if (dwNumDevices > 0) {
|
|
// Allocate a block of memory for the virtual fax device data
|
|
g_pDeviceInfo = (PDEVICE_INFO*) MemAllocMacro(sizeof(PDEVICE_INFO) * dwNumDevices);
|
|
if (g_pDeviceInfo == NULL) {
|
|
// Set the error code
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
// Enumerate the virtual fax devices
|
|
for (pCurrentDeviceInfo = pDeviceInfo; pCurrentDeviceInfo; pCurrentDeviceInfo = pDeviceInfo) {
|
|
// Delete the virtual fax device data
|
|
pDeviceInfo = pCurrentDeviceInfo->pNextDeviceInfo;
|
|
MemFreeMacro(pCurrentDeviceInfo);
|
|
}
|
|
|
|
WriteDebugString(L" ERROR: FaxDevInitialize Failed: ERROR_NOT_ENOUGH_MEMORY\n");
|
|
WriteDebugString(L"---SampleFSP: FaxDevInitialize Exit---\n");
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
else {
|
|
g_pDeviceInfo = NULL;
|
|
}
|
|
|
|
// Marshall the virtual fax devices
|
|
for (pCurrentDeviceInfo = pDeviceInfo, dwIndex = 0;
|
|
pCurrentDeviceInfo;
|
|
pCurrentDeviceInfo = pCurrentDeviceInfo->pNextDeviceInfo, dwIndex++) {
|
|
g_pDeviceInfo[dwIndex] = pCurrentDeviceInfo;
|
|
|
|
// Initialize the virtual fax device's critical section
|
|
InitializeCriticalSection(&g_pDeviceInfo[dwIndex]->cs);
|
|
// Initialize the virtual fax device's status to idle
|
|
g_pDeviceInfo[dwIndex]->Status = DEVICE_IDLE;
|
|
// Initialize the virtual fax device's handle to the exit event
|
|
g_pDeviceInfo[dwIndex]->ExitEvent = NULL;
|
|
// Initialize the virtual fax device's associated fax job
|
|
g_pDeviceInfo[dwIndex]->pJobInfo = NULL;
|
|
}
|
|
|
|
WriteDebugString(L"---SampleFSP: FaxDevInitialize Exit---\n");
|
|
|
|
return TRUE;
|
|
}
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// function: FaxDevStartJob
|
|
//
|
|
// Synopsis: The fax service calls the FaxDevStartJob function to initialize a new fax job
|
|
//
|
|
// Arguments: [LineHandle] - specifies a handle to the open line device associated with the fax job
|
|
// [DeviceId] - specifies the TAPI line device identifier associated with the fax job
|
|
// [FaxHandle] - pointer to a variable that receives a fax handle associated with the fax job
|
|
// [CompletionPortHandle] - specifies a handle to an I/O completion port
|
|
// [CompletionKey] - specifies a completion port key value
|
|
//
|
|
// Returns: void
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL WINAPI
|
|
FaxDevStartJob(
|
|
IN HLINE LineHandle,
|
|
IN DWORD DeviceId,
|
|
OUT PHANDLE FaxHandle,
|
|
IN HANDLE CompletionPortHandle,
|
|
IN ULONG_PTR CompletionKey
|
|
)
|
|
{
|
|
// pJobInfo is a pointer to the fax job data
|
|
PJOB_INFO pJobInfo;
|
|
|
|
WriteDebugString(L"---SampleFSP: FaxDevStartJob Enter---\n");
|
|
|
|
// Initialize the parameters
|
|
*FaxHandle = NULL;
|
|
|
|
// Allocate a block of memory for the fax job instance data
|
|
pJobInfo = (PJOB_INFO) MemAllocMacro(sizeof(JOB_INFO));
|
|
if (pJobInfo == NULL) {
|
|
// Set the error code
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
WriteDebugString(L" ERROR: FaxDevStartJob Failed: ERROR_NOT_ENOUGH_MEMORY\n");
|
|
WriteDebugString(L"---SampleFSP: FaxDevStartJob Exit---\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// Set the FaxHandle
|
|
*FaxHandle = (PHANDLE) pJobInfo;
|
|
|
|
// Wait for access to this virtual fax device
|
|
EnterCriticalSection(&g_pDeviceInfo[DeviceId]->cs);
|
|
|
|
// Initialize the fax job data
|
|
// Set the fax job's associated virtual fax device
|
|
pJobInfo->pDeviceInfo = g_pDeviceInfo[DeviceId];
|
|
// Copy the handle to the I/O completion port
|
|
pJobInfo->CompletionPortHandle = CompletionPortHandle;
|
|
// Copy the completion port key value
|
|
pJobInfo->CompletionKey = CompletionKey;
|
|
// Initialize the fax job type
|
|
pJobInfo->JobType = JOB_UNKNOWN;
|
|
// Set the fax job status to FS_INITIALIZING
|
|
pJobInfo->Status = FS_INITIALIZING;
|
|
// Copy the handle to the open line device associated with the fax job
|
|
pJobInfo->LineHandle = LineHandle;
|
|
// Initialize the handle to the active call associated with the fax job
|
|
pJobInfo->CallHandle = (HCALL) 0;
|
|
// Initialize the full path to the file that contains the data stream for the fax document
|
|
pJobInfo->FileName = NULL;
|
|
// Initialize the name of the calling device
|
|
pJobInfo->CallerName = NULL;
|
|
// Initialize the telephone number of the calling device
|
|
pJobInfo->CallerNumber = NULL;
|
|
// Initialize name of the receiving device
|
|
pJobInfo->ReceiverName = NULL;
|
|
// Initialize telephone number of the receiving device
|
|
pJobInfo->ReceiverNumber = NULL;
|
|
// Initialize number of retries associated with the fax job
|
|
pJobInfo->RetryCount = 0;
|
|
// Initialize whether the fax service provider should generate a brand at the top of the fax transmission
|
|
pJobInfo->Branding = FALSE;
|
|
// Initialize the number of pages associated with the fax job
|
|
pJobInfo->PageCount = 0;
|
|
// Initialize the identifier of the remote fax device
|
|
pJobInfo->CSI = NULL;
|
|
// Initialize the identifier of the calling fax device
|
|
pJobInfo->CallerId = NULL;
|
|
// Initialize the routing string associated with the fax job
|
|
pJobInfo->RoutingInfo = NULL;
|
|
|
|
// Set the virtual fax device status
|
|
g_pDeviceInfo[DeviceId]->Status = DEVICE_START;
|
|
// Set the virtual fax device's associated fax job
|
|
g_pDeviceInfo[DeviceId]->pJobInfo = pJobInfo;
|
|
|
|
// Release access to this virtual fax device
|
|
LeaveCriticalSection(&g_pDeviceInfo[DeviceId]->cs);
|
|
|
|
WriteDebugString(L"---SampleFSP: FaxDevStartJob Exit---\n");
|
|
|
|
return TRUE;
|
|
}
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// function: FaxDevEndJob
|
|
//
|
|
// Synopsis: The fax service calls the FaxDevEndJob function after the last operation in a fax job
|
|
//
|
|
// Arguments: [FaxHandle] - specifies a fax handle returned by the FaxDevStartJob function
|
|
//
|
|
// Returns: TRUE on success
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL WINAPI
|
|
FaxDevEndJob(
|
|
IN HANDLE FaxHandle
|
|
)
|
|
{
|
|
// pJobInfo is a pointer to the fax job data
|
|
PJOB_INFO pJobInfo;
|
|
// pDeviceInfo is a pointer to the virtual fax device data
|
|
PDEVICE_INFO pDeviceInfo;
|
|
|
|
WriteDebugString(L"---SampleFSP: FaxDevEndJob Enter---\n");
|
|
|
|
if (FaxHandle == NULL) {
|
|
// Set the error code
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
|
|
WriteDebugString(L" ERROR: FaxDevEndJob Failed: ERROR_INVALID_HANDLE\n");
|
|
WriteDebugString(L"---SampleFSP: FaxDevEndJob Exit---\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// Get the fax job data from FaxHandle
|
|
pJobInfo = (PJOB_INFO) FaxHandle;
|
|
// Get the virtual fax device data from the fax job data
|
|
pDeviceInfo = (PDEVICE_INFO) pJobInfo->pDeviceInfo;
|
|
|
|
// Wait for access to this virtual fax device
|
|
EnterCriticalSection(&pDeviceInfo->cs);
|
|
|
|
// Free the fax job data
|
|
// Free the full path to the file that contains the data stream for the fax document
|
|
if (pJobInfo->FileName != NULL) {
|
|
MemFreeMacro(pJobInfo->FileName);
|
|
}
|
|
// Free the name of the calling device
|
|
if (pJobInfo->CallerName != NULL) {
|
|
MemFreeMacro(pJobInfo->CallerName);
|
|
}
|
|
// Free the telephone number of the calling device
|
|
if (pJobInfo->CallerNumber != NULL) {
|
|
MemFreeMacro(pJobInfo->CallerNumber);
|
|
}
|
|
// Free name of the receiving device
|
|
if (pJobInfo->ReceiverName != NULL) {
|
|
MemFreeMacro(pJobInfo->ReceiverName);
|
|
}
|
|
// Free telephone number of the receiving device
|
|
if (pJobInfo->ReceiverNumber != NULL) {
|
|
MemFreeMacro(pJobInfo->ReceiverNumber);
|
|
}
|
|
// Free the identifier of the remote fax device
|
|
if (pJobInfo->CSI != NULL) {
|
|
MemFreeMacro(pJobInfo->CSI);
|
|
}
|
|
// Free the identifier of the calling fax device
|
|
if (pJobInfo->CallerId != NULL) {
|
|
MemFreeMacro(pJobInfo->CallerId);
|
|
}
|
|
// Free the routing string associated with the fax job
|
|
if (pJobInfo->RoutingInfo != NULL) {
|
|
MemFreeMacro(pJobInfo->RoutingInfo);
|
|
}
|
|
// Free the fax job data
|
|
MemFreeMacro(pJobInfo);
|
|
|
|
// Set the virtual fax device status
|
|
pDeviceInfo->Status = DEVICE_IDLE;
|
|
// Initialize the virtual fax device's associated fax job
|
|
pDeviceInfo->pJobInfo = NULL;
|
|
|
|
// Release access to this virtual fax device
|
|
LeaveCriticalSection(&pDeviceInfo->cs);
|
|
|
|
WriteDebugString(L"---SampleFSP: FaxDevEndJob Exit---\n");
|
|
|
|
return TRUE;
|
|
}
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// function: FaxDevSend
|
|
//
|
|
// Synopsis: The fax service calls the FaxDevSend function to signal a fax service
|
|
// provider that it must initiate an outgoing fax transmission
|
|
//
|
|
// Arguments: [FaxHandle] - specifies a fax handle returned by the FaxDevStartJob function
|
|
// [FaxSend] - pointer to a FAX_SEND structure that contains the sending information
|
|
// [FaxSendCallback] - pointer to a callback function that notifies the fax service
|
|
// of the call handle that TAPI assigns
|
|
//
|
|
// Returns: TRUE on success
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL WINAPI
|
|
FaxDevSend(
|
|
IN HANDLE FaxHandle,
|
|
IN PFAX_SEND FaxSend,
|
|
IN PFAX_SEND_CALLBACK FaxSendCallback
|
|
)
|
|
{
|
|
// pJobInfo is a pointer to the fax job data
|
|
PJOB_INFO pJobInfo;
|
|
// pDeviceInfo is a pointer to the virtual fax device data
|
|
PDEVICE_INFO pDeviceInfo;
|
|
|
|
// dwReceiverNumberAttributes is the file attributes of the directory specified in the telephone number of the receiving device
|
|
DWORD dwReceiverNumberAttributes;
|
|
|
|
// hSourceFile is the handle to the source file
|
|
HANDLE hSourceFile = INVALID_HANDLE_VALUE;
|
|
// lptstrFilePart is the filename
|
|
LPTSTR lptstrFilePart = NULL;
|
|
// szFilePath is the source filename path
|
|
WCHAR szFilePath[MAX_PATH_LEN];
|
|
// hDestinationFile is the handle to the destination file
|
|
HANDLE hDestinationFile = INVALID_HANDLE_VALUE;
|
|
// szDestinationFilename is the destination filename
|
|
WCHAR szDestinationFilename[MAX_PATH_LEN + _MAX_FNAME + 6];
|
|
// szDeviceFolder is the associated device folder.
|
|
WCHAR szDeviceFolder[MAX_PATH_LEN];
|
|
|
|
// FileBytes is the bytes to be copied from the source file to the destination file
|
|
BYTE FileBytes[1024];
|
|
// dwBytes is the number of bytes read from the source file
|
|
DWORD dwBytes;
|
|
//iDestinationDevice is the destination device
|
|
int iDestinationDevice;
|
|
|
|
HRESULT hr = S_OK;
|
|
BOOL bRetVal = FALSE;
|
|
|
|
WriteDebugString(L"---SampleFSP: FaxDevSend Enter---\n");
|
|
|
|
if (FaxHandle == NULL) {
|
|
// Set the error code
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
|
|
WriteDebugString(L" ERROR: FaxDevSend Failed: ERROR_INVALID_HANDLE\n");
|
|
WriteDebugString(L"---SampleFSP: FaxDevSend Exit---\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// Get the fax job data from FaxHandle
|
|
pJobInfo = (PJOB_INFO) FaxHandle;
|
|
// Get the virtual fax device data from the fax job data
|
|
pDeviceInfo = (PDEVICE_INFO) pJobInfo->pDeviceInfo;
|
|
|
|
// Wait for access to this virtual fax device
|
|
EnterCriticalSection(&pDeviceInfo->cs);
|
|
|
|
if (pDeviceInfo->Status == DEVICE_ABORTING) {
|
|
goto ExitUserAbort;
|
|
}
|
|
|
|
// Set the virtual fax device status
|
|
pDeviceInfo->Status = DEVICE_SEND;
|
|
|
|
// Set the fax job type
|
|
pJobInfo->JobType = JOB_SEND;
|
|
// Copy the handle to the active call associated with the fax job
|
|
pJobInfo->CallHandle = FaxSend->CallHandle;
|
|
// Copy the full path to the file that contains the data stream for the fax document
|
|
if (FaxSend->FileName != NULL) {
|
|
pJobInfo->FileName = (LPWSTR) MemAllocMacro((lstrlen(FaxSend->FileName) + 1) * sizeof(WCHAR));
|
|
if (pJobInfo->FileName)
|
|
{
|
|
hr = StringCchCopy(pJobInfo->FileName, (lstrlen(FaxSend->FileName) + 1),FaxSend->FileName);
|
|
if(hr != S_OK)
|
|
{
|
|
WriteDebugString(L"StringCchCopy failed, hr = 0x%x for pJobInfo->FileName", hr);
|
|
bRetVal = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
}
|
|
}
|
|
// Copy the name of the calling device
|
|
if (FaxSend->CallerName != NULL) {
|
|
pJobInfo->CallerName = (LPWSTR) MemAllocMacro((lstrlen(FaxSend->CallerName) + 1) * sizeof(WCHAR));
|
|
if (pJobInfo->CallerName) {
|
|
hr = StringCchCopy(pJobInfo->CallerName, (lstrlen(FaxSend->CallerName) + 1),FaxSend->CallerName);
|
|
if(hr != S_OK)
|
|
{
|
|
WriteDebugString( L"StringCchCopy failed, hr = 0x%x for pJobInfo->CallerName", hr );
|
|
bRetVal = FALSE;
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
// Copy the telephone number of the calling device
|
|
if (FaxSend->CallerNumber != NULL) {
|
|
pJobInfo->CallerNumber = (LPWSTR) MemAllocMacro((lstrlen(FaxSend->CallerNumber) + 1) * sizeof(WCHAR));
|
|
if (pJobInfo->CallerNumber) {
|
|
hr = StringCchCopy(pJobInfo->CallerNumber, (lstrlen(FaxSend->CallerNumber) + 1),FaxSend->CallerNumber);
|
|
if(hr != S_OK)
|
|
{
|
|
WriteDebugString( L"StringCchCopy failed, hr = 0x%x for pJobInfo->CallerNumber", hr );
|
|
bRetVal = FALSE;
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
// Copy the name of the receiving device
|
|
if (FaxSend->ReceiverName != NULL) {
|
|
pJobInfo->ReceiverName = (LPWSTR) MemAllocMacro((lstrlen(FaxSend->ReceiverName) + 1) * sizeof(WCHAR));
|
|
if (pJobInfo->ReceiverName) {
|
|
hr = StringCchCopy(pJobInfo->ReceiverName, (lstrlen(FaxSend->ReceiverName) + 1),FaxSend->ReceiverName);
|
|
if(hr != S_OK)
|
|
{
|
|
WriteDebugString(L"StringCchCopy failed, hr = 0x%x for pJobInfo->ReceiverName", hr );
|
|
bRetVal = FALSE;
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
// Copy the telephone number of the receiving device
|
|
if (FaxSend->ReceiverNumber != NULL) {
|
|
pJobInfo->ReceiverNumber = (LPWSTR) MemAllocMacro((lstrlen(FaxSend->ReceiverNumber) + 1) * sizeof(WCHAR));
|
|
if (pJobInfo->ReceiverNumber)
|
|
{
|
|
hr = StringCchCopy(pJobInfo->ReceiverNumber, (lstrlen(FaxSend->ReceiverNumber) + 1),FaxSend->ReceiverNumber);
|
|
if(hr != S_OK)
|
|
{
|
|
WriteDebugString( L"StringCchCopy failed, hr = 0x%x for pJobInfo->ReceiverNumber", hr );
|
|
bRetVal = FALSE;
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
//We skip the 1st char "T" or "P" (Tone or Pulse) that the fax service added based on the dialing rule
|
|
iDestinationDevice = _wtoi(_wcsinc(FaxSend->ReceiverNumber));
|
|
if(iDestinationDevice > NEWFSP_DEVICE_LIMIT -1)
|
|
{
|
|
pJobInfo->Status = FS_BAD_ADDRESS;
|
|
WriteDebugString( L"Receive Number is invalid. " );
|
|
bRetVal = FALSE;
|
|
goto Exit;
|
|
|
|
}
|
|
hr = StringCchCopy(szDeviceFolder, MAX_PATH_LEN,g_pDeviceInfo[iDestinationDevice]->Directory);
|
|
if(hr != S_OK)
|
|
{
|
|
WriteDebugString( L"StringCchCopy failed, hr = 0x%x for szDeviceFolder", hr );
|
|
bRetVal = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
// Copy whether the fax service provider should generate a brand at the top of the fax transmission
|
|
pJobInfo->Branding = FaxSend->Branding;
|
|
|
|
// Release access to this virtual fax device
|
|
LeaveCriticalSection(&pDeviceInfo->cs);
|
|
|
|
WriteDebugString(L" FaxSend->SizeOfStruct : 0x%08x\n", FaxSend->SizeOfStruct);
|
|
WriteDebugString(L" FaxSend->FileName : %s\n", FaxSend->FileName);
|
|
WriteDebugString(L" FaxSend->CallerName : %s\n", FaxSend->CallerName);
|
|
WriteDebugString(L" FaxSend->CallerNumber : %s\n", FaxSend->CallerNumber);
|
|
WriteDebugString(L" FaxSend->ReceiverName : %s\n", FaxSend->ReceiverName);
|
|
WriteDebugString(L" FaxSend->ReceiverNumber : %s\n", FaxSend->ReceiverNumber);
|
|
WriteDebugString(L" FaxSend->Branding : %s\n", FaxSend->Branding ? L"TRUE" : L"FALSE");
|
|
WriteDebugString(L" FaxSend->CallHandle : 0x%08x\n", FaxSend->CallHandle);
|
|
WriteDebugString(L" Dest. device Folder : %s\n", szDeviceFolder);
|
|
|
|
|
|
// Wait for access to this virtual fax device
|
|
EnterCriticalSection(&pDeviceInfo->cs);
|
|
|
|
if (pDeviceInfo->Status == DEVICE_ABORTING) {
|
|
goto ExitUserAbort;
|
|
}
|
|
|
|
// Set the fax job status
|
|
pJobInfo->Status = FS_INITIALIZING;
|
|
// Post the FS_INITIALIZING line status event to the fax service
|
|
PostJobStatus(pJobInfo->CompletionPortHandle,
|
|
pJobInfo->CompletionKey,
|
|
FS_INITIALIZING,
|
|
ERROR_SUCCESS);
|
|
|
|
// Validate the folder of the receive device
|
|
dwReceiverNumberAttributes = GetFileAttributes(szDeviceFolder);
|
|
if ((dwReceiverNumberAttributes == 0xFFFFFFFF) || ((dwReceiverNumberAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)) {
|
|
// The folder of the receive device is invalid
|
|
goto ExitFatalError;
|
|
}
|
|
|
|
// Open the source file
|
|
hSourceFile = CreateFile(FaxSend->FileName,
|
|
GENERIC_READ,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
if (hSourceFile == INVALID_HANDLE_VALUE) {
|
|
// The source file failed to be opened
|
|
goto ExitFatalError;
|
|
}
|
|
|
|
// Split the full path of the file that contains the data stream for the fax document
|
|
|
|
//Separate path and file name
|
|
DWORD dwRetVal = GetFullPathName(FaxSend->FileName,MAX_PATH_LEN, szFilePath, &lptstrFilePart);
|
|
if(dwRetVal == 0 )
|
|
{
|
|
WriteDebugString( L"GetFullPathName failed, ec = %d", GetLastError() );
|
|
bRetVal = FALSE;
|
|
goto Exit;
|
|
}
|
|
// Set the destination filename
|
|
hr = StringCchCopy(szDestinationFilename, MAX_PATH_LEN + _MAX_FNAME + 6,szDeviceFolder);
|
|
if(hr != S_OK)
|
|
{
|
|
WriteDebugString( L"StringCchCopy failed, hr = 0x%x for szDestinationFilename szDeviceFolder", hr );
|
|
bRetVal = FALSE;
|
|
goto Exit;
|
|
}
|
|
hr = StringCchCat(szDestinationFilename, MAX_PATH_LEN + _MAX_FNAME + 6,L"\\");
|
|
if(hr != S_OK)
|
|
{
|
|
WriteDebugString( L"StringCchCat failed, hr = 0x%x for szDestinationFilename \\", hr );
|
|
bRetVal = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
WCHAR* strFileName = _tcschr(lptstrFilePart, '.');
|
|
hr = StringCchCatN(szDestinationFilename, MAX_PATH_LEN + _MAX_FNAME + 6,lptstrFilePart, _tcslen(lptstrFilePart) - _tcslen(strFileName) );
|
|
if(hr != S_OK)
|
|
{
|
|
WriteDebugString( L"StringCchCat failed, hr = 0x%x for szDestinationFilename \\", hr );
|
|
bRetVal = FALSE;
|
|
goto Exit;
|
|
}
|
|
hr = StringCchCat(szDestinationFilename, MAX_PATH_LEN + _MAX_FNAME + 6,L".tif" );
|
|
if(hr != S_OK)
|
|
{
|
|
WriteDebugString( L"StringCchCat failed, hr = 0x%x for szDestinationFilename \\", hr );
|
|
bRetVal = FALSE;
|
|
goto Exit;
|
|
}
|
|
WriteDebugString( L"\n File Name %s ", szDestinationFilename );
|
|
|
|
if ( wcslen(szDestinationFilename) >= MAX_PATH) {
|
|
// The destination file path is too long
|
|
goto ExitFatalError;
|
|
}
|
|
|
|
// Create the destination file
|
|
hDestinationFile = CreateFile(szDestinationFilename,
|
|
GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
if (hDestinationFile == INVALID_HANDLE_VALUE) {
|
|
// The destination file failed to be created
|
|
goto ExitFatalError;
|
|
}
|
|
|
|
// Release access to this virtual fax device
|
|
LeaveCriticalSection(&pDeviceInfo->cs);
|
|
|
|
// Wait for access to this virtual fax device
|
|
EnterCriticalSection(&pDeviceInfo->cs);
|
|
|
|
if (pDeviceInfo->Status == DEVICE_ABORTING) {
|
|
goto ExitUserAbort;
|
|
}
|
|
|
|
// Set the fax job status
|
|
pJobInfo->Status = FS_TRANSMITTING;
|
|
// Post the FS_TRANSMITTING line status event to the fax service
|
|
PostJobStatus(pJobInfo->CompletionPortHandle,
|
|
pJobInfo->CompletionKey,
|
|
FS_TRANSMITTING,
|
|
ERROR_SUCCESS);
|
|
|
|
// Release access to this virtual fax device
|
|
LeaveCriticalSection(&pDeviceInfo->cs);
|
|
|
|
while (TRUE) {
|
|
// The following sleep statement slows the bit copy to a reasonable speed so that a FaxDevAbortOperation()
|
|
// call is possible
|
|
Sleep(250);
|
|
|
|
// Wait for access to this virtual fax device
|
|
EnterCriticalSection(&pDeviceInfo->cs);
|
|
|
|
if (pDeviceInfo->Status == DEVICE_ABORTING) {
|
|
goto ExitUserAbort;
|
|
}
|
|
|
|
// Read the bytes from the source file
|
|
if (ReadFile(hSourceFile,
|
|
FileBytes,
|
|
sizeof(FileBytes),
|
|
&dwBytes,
|
|
NULL) == FALSE) {
|
|
// Failed to read the bytes from the source file
|
|
goto ExitFatalError;
|
|
}
|
|
|
|
if (dwBytes == 0) {
|
|
// The file pointer has reached the end of the source file
|
|
// Release access to this virtual fax device
|
|
LeaveCriticalSection(&pDeviceInfo->cs);
|
|
break;
|
|
}
|
|
|
|
// Write the bytes to the destination file
|
|
if (WriteFile(hDestinationFile,
|
|
FileBytes,
|
|
dwBytes,
|
|
&dwBytes,
|
|
NULL) == FALSE) {
|
|
// Failed to write the bytes to the destination file
|
|
goto ExitFatalError;
|
|
}
|
|
|
|
// Release access to this virtual fax device
|
|
LeaveCriticalSection(&pDeviceInfo->cs);
|
|
}
|
|
|
|
// Wait for access to this virtual fax device
|
|
EnterCriticalSection(&pDeviceInfo->cs);
|
|
|
|
if (pDeviceInfo->Status == DEVICE_ABORTING) {
|
|
goto ExitUserAbort;
|
|
}
|
|
|
|
// Close the destination file
|
|
CloseHandle(hDestinationFile);
|
|
|
|
// Close the source file
|
|
CloseHandle(hSourceFile);
|
|
|
|
// Set the fax job status
|
|
pJobInfo->Status = FS_COMPLETED;
|
|
// Post the FS_COMPLETED line status event to the fax service
|
|
PostJobStatus(pJobInfo->CompletionPortHandle,
|
|
pJobInfo->CompletionKey,
|
|
FS_COMPLETED,
|
|
ERROR_SUCCESS);
|
|
|
|
// Release access to this virtual fax device
|
|
LeaveCriticalSection(&pDeviceInfo->cs);
|
|
|
|
WriteDebugString(L"---SampleFSP: FaxDevSend Exit---\n");
|
|
|
|
return TRUE;
|
|
|
|
ExitFatalError:
|
|
// Set the fax job status
|
|
pJobInfo->Status = FS_FATAL_ERROR;
|
|
goto Exit;
|
|
|
|
ExitUserAbort:
|
|
// Set the fax job status
|
|
pJobInfo->Status = FS_USER_ABORT;
|
|
goto Exit;
|
|
|
|
Exit:
|
|
// Close and delete the destination file
|
|
if (hDestinationFile != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(hDestinationFile);
|
|
|
|
DeleteFile(szDestinationFilename);
|
|
}
|
|
|
|
// Close the source file
|
|
if (hSourceFile != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(hSourceFile);
|
|
}
|
|
|
|
// Post the line status event to the fax service
|
|
PostJobStatus(pJobInfo->CompletionPortHandle,
|
|
pJobInfo->CompletionKey,
|
|
pJobInfo->Status,
|
|
ERROR_SUCCESS);
|
|
|
|
// Release access to this virtual fax device
|
|
LeaveCriticalSection(&pDeviceInfo->cs);
|
|
|
|
WriteDebugString(L"---SampleFSP: FaxDevSend Exit---\n");
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// function: FaxDevReceive
|
|
//
|
|
// Synopsis: The fax service calls the FaxDevReceive function to signal an incoming
|
|
// fax transmission to the fax service provider
|
|
|
|
//
|
|
// Arguments: [FaxHandle] - specifies a fax handle returned by the FaxDevStartJob function
|
|
// [CallHandle] - specifies a TAPI call handle
|
|
// [FaxReceive] - pointer to a FAX_RECEIVE stucture that contains information
|
|
// about an incoming fax document
|
|
//
|
|
// Returns: TRUE on success
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL WINAPI
|
|
FaxDevReceive(
|
|
IN HANDLE FaxHandle,
|
|
IN HCALL CallHandle,
|
|
IN OUT PFAX_RECEIVE FaxReceive
|
|
)
|
|
{
|
|
// pJobInfo is a pointer to the fax job data
|
|
PJOB_INFO pJobInfo;
|
|
// pDeviceInfo is a pointer to the virtual fax device data
|
|
PDEVICE_INFO pDeviceInfo;
|
|
|
|
// hSourceFile is the handle to the source file
|
|
HANDLE hSourceFile = INVALID_HANDLE_VALUE;
|
|
// szSourceFilename is the source filename
|
|
WCHAR szSourceFilename[MAX_PATH + MAX_PATH_LEN + 1];
|
|
|
|
// hFindFile is a find file handle
|
|
HANDLE hFindFile = INVALID_HANDLE_VALUE;
|
|
// FindData is a WIN32_FIND_DATA structure
|
|
WIN32_FIND_DATA FindData;
|
|
// szSearchPath is the search path
|
|
WCHAR szSearchPath[MAX_PATH];
|
|
|
|
// hDestinationFile is the handle to the destination file
|
|
HANDLE hDestinationFile = INVALID_HANDLE_VALUE;
|
|
|
|
// FileBytes is the bytes to be copied from the source file to the destination file
|
|
BYTE FileBytes[1024];
|
|
// dwBytes is the number of bytes read from the source file
|
|
DWORD dwBytes;
|
|
HRESULT hr = S_OK;
|
|
BOOL bRetVal = FALSE;
|
|
|
|
WriteDebugString(L"---SampleFSP: FaxDevReceive Enter---\n");
|
|
|
|
if (FaxHandle == NULL) {
|
|
// Set the error code
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
|
|
WriteDebugString(L" ERROR: FaxDevReceive Failed: ERROR_INVALID_HANDLE\n");
|
|
WriteDebugString(L"---SampleFSP: FaxDevReceive Exit---\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// Get the fax job data from FaxHandle
|
|
pJobInfo = (PJOB_INFO) FaxHandle;
|
|
// Get the virtual fax device data from the fax job data
|
|
pDeviceInfo = (PDEVICE_INFO) pJobInfo->pDeviceInfo;
|
|
|
|
// Wait for access to this virtual fax device
|
|
EnterCriticalSection(&pDeviceInfo->cs);
|
|
|
|
if (pDeviceInfo->Status == DEVICE_ABORTING) {
|
|
goto ExitUserAbort;
|
|
}
|
|
|
|
// Set the virtual fax device status
|
|
pDeviceInfo->Status = DEVICE_RECEIVE;
|
|
|
|
// Set the fax job type
|
|
pJobInfo->JobType = JOB_RECEIVE;
|
|
// Copy the handle to the active call associated with the fax job
|
|
pJobInfo->CallHandle = CallHandle;
|
|
|
|
// Release access to this virtual fax device
|
|
LeaveCriticalSection(&pDeviceInfo->cs);
|
|
|
|
WriteDebugString(L" CallHandle : 0x%08x\n", CallHandle);
|
|
WriteDebugString(L" FaxReceive->SizeOfStruct : 0x%08x\n", FaxReceive->SizeOfStruct);
|
|
WriteDebugString(L" FaxReceive->FileName : %s\n", FaxReceive->FileName);
|
|
WriteDebugString(L" FaxReceive->ReceiverName : %s\n", FaxReceive->ReceiverName);
|
|
WriteDebugString(L" FaxReceive->ReceiverNumber : %s\n", FaxReceive->ReceiverNumber);
|
|
|
|
// Wait for access to this virtual fax device
|
|
EnterCriticalSection(&pDeviceInfo->cs);
|
|
|
|
if (pDeviceInfo->Status == DEVICE_ABORTING) {
|
|
goto ExitUserAbort;
|
|
}
|
|
|
|
// Set the fax job status
|
|
pJobInfo->Status = FS_ANSWERED;
|
|
// Post the FS_ANSWERED line status event to the fax service
|
|
PostJobStatus(pJobInfo->CompletionPortHandle,
|
|
pJobInfo->CompletionKey,
|
|
FS_ANSWERED,
|
|
ERROR_SUCCESS);
|
|
|
|
// Set the search path
|
|
hr = StringCchCopy(szSearchPath, MAX_PATH, pDeviceInfo->Directory);
|
|
if(hr != S_OK)
|
|
{
|
|
WriteDebugString( L"StringCchCopy failed, hr = 0x%x for szSearchPath ", hr );
|
|
bRetVal = FALSE;
|
|
goto Exit;
|
|
}
|
|
hr = StringCchCat(szSearchPath, MAX_PATH, L"\\*.tif");
|
|
if(hr != S_OK)
|
|
{
|
|
WriteDebugString( L"StringCchCat failed, hr = 0x%x for szSearchPath ", hr );
|
|
bRetVal = FALSE;
|
|
goto Exit;
|
|
}
|
|
// Initialize the find file data
|
|
ZeroMemory(&FindData, sizeof(FindData));
|
|
FindData.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
|
|
|
|
// Find the incoming fax file
|
|
hFindFile = FindFirstFile(szSearchPath, &FindData);
|
|
if (hFindFile == INVALID_HANDLE_VALUE) {
|
|
// The incoming fax file was not found
|
|
goto ExitFatalError;
|
|
}
|
|
|
|
// Close the find file handle
|
|
FindClose(hFindFile);
|
|
hFindFile = INVALID_HANDLE_VALUE;
|
|
|
|
// Set the source filename
|
|
hr = StringCchCopy(szSourceFilename, MAX_PATH + MAX_PATH_LEN + 1, pDeviceInfo->Directory);
|
|
if(hr != S_OK)
|
|
{
|
|
WriteDebugString( L"StringCchCopy failed, hr = 0x%x for szSourceFilename ", hr );
|
|
bRetVal = FALSE;
|
|
goto Exit;
|
|
}
|
|
hr = StringCchCat(szSourceFilename, MAX_PATH + MAX_PATH_LEN + 1, L"\\");
|
|
if(hr != S_OK)
|
|
{
|
|
WriteDebugString( L"StringCchCat failed, hr = 0x%x for szSourceFilename ", hr );
|
|
bRetVal = FALSE;
|
|
goto Exit;
|
|
}
|
|
hr = StringCchCat(szSourceFilename, MAX_PATH + MAX_PATH_LEN + 1, FindData.cFileName);
|
|
if(hr != S_OK)
|
|
{
|
|
WriteDebugString( L"StringCchCat failed, hr = 0x%x for szSourceFilename ", hr );
|
|
bRetVal = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
if (wcslen(szSourceFilename) >= MAX_PATH) {
|
|
// The source file name is too long
|
|
goto ExitFatalError;
|
|
}
|
|
|
|
// Open the source file
|
|
hSourceFile = CreateFile(szSourceFilename,
|
|
GENERIC_READ,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
if (hSourceFile == INVALID_HANDLE_VALUE) {
|
|
// The source file failed to be opened
|
|
goto ExitFatalError;
|
|
}
|
|
|
|
// Open the destination file
|
|
hDestinationFile = CreateFile(FaxReceive->FileName,
|
|
GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
if (hDestinationFile == INVALID_HANDLE_VALUE) {
|
|
// The destination file failed to be created
|
|
goto ExitFatalError;
|
|
}
|
|
|
|
// Release access to this virtual fax device
|
|
LeaveCriticalSection(&pDeviceInfo->cs);
|
|
|
|
// Wait for access to this virtual fax device
|
|
EnterCriticalSection(&pDeviceInfo->cs);
|
|
|
|
if (pDeviceInfo->Status == DEVICE_ABORTING) {
|
|
goto ExitUserAbort;
|
|
}
|
|
|
|
// Set the fax job status
|
|
pJobInfo->Status = FS_RECEIVING;
|
|
// Post the FS_RECEIVING line status event to the fax service
|
|
PostJobStatus(pJobInfo->CompletionPortHandle,
|
|
pJobInfo->CompletionKey,
|
|
FS_RECEIVING,
|
|
ERROR_SUCCESS);
|
|
|
|
// Release access to this virtual fax device
|
|
LeaveCriticalSection(&pDeviceInfo->cs);
|
|
|
|
while (TRUE) {
|
|
// The following sleep statement slows the bit copy to a reasonable speed so that a FaxDevAbortOperation() call is possible
|
|
Sleep(250);
|
|
|
|
// Wait for access to this virtual fax device
|
|
EnterCriticalSection(&pDeviceInfo->cs);
|
|
|
|
if (pDeviceInfo->Status == DEVICE_ABORTING) {
|
|
goto ExitUserAbort;
|
|
}
|
|
|
|
// Read the bytes from the source file
|
|
if (ReadFile(hSourceFile,
|
|
FileBytes,
|
|
sizeof(FileBytes),
|
|
&dwBytes,
|
|
NULL) == FALSE) {
|
|
// Failed to read the bytes from the source file
|
|
goto ExitFatalError;
|
|
}
|
|
|
|
if (dwBytes == 0) {
|
|
// The file pointer has reached the end of the source file
|
|
// Release access to this virtual fax device
|
|
LeaveCriticalSection(&pDeviceInfo->cs);
|
|
break;
|
|
}
|
|
|
|
// Write the bytes to the destination file
|
|
if (WriteFile(hDestinationFile,
|
|
FileBytes,
|
|
dwBytes,
|
|
&dwBytes,
|
|
NULL) == FALSE) {
|
|
// Failed to write the bytes to the destination file
|
|
goto ExitFatalError;
|
|
}
|
|
|
|
// Release access to this virtual fax device
|
|
LeaveCriticalSection(&pDeviceInfo->cs);
|
|
}
|
|
|
|
// Wait for access to this virtual fax device
|
|
EnterCriticalSection(&pDeviceInfo->cs);
|
|
|
|
if (pDeviceInfo->Status == DEVICE_ABORTING) {
|
|
goto ExitUserAbort;
|
|
}
|
|
|
|
// Close the destination file
|
|
CloseHandle(hDestinationFile);
|
|
|
|
// Close the source file
|
|
CloseHandle(hSourceFile);
|
|
|
|
//Source file is now copied, delete the source file
|
|
DeleteFile(szSourceFilename);
|
|
|
|
// Set the fax job status
|
|
pJobInfo->Status = FS_COMPLETED;
|
|
// Post the FS_COMPLETED line status event to the fax service
|
|
PostJobStatus(pJobInfo->CompletionPortHandle,
|
|
pJobInfo->CompletionKey,
|
|
FS_COMPLETED,
|
|
ERROR_SUCCESS);
|
|
|
|
// Release access to this virtual fax device
|
|
LeaveCriticalSection(&pDeviceInfo->cs);
|
|
|
|
WriteDebugString(L"---SampleFSP: FaxDevReceive Exit---\n");
|
|
|
|
return TRUE;
|
|
|
|
ExitFatalError:
|
|
// Set the fax job status
|
|
pJobInfo->Status = FS_FATAL_ERROR;
|
|
goto Exit;
|
|
|
|
ExitUserAbort:
|
|
// Set the fax job status
|
|
pJobInfo->Status = FS_USER_ABORT;
|
|
goto Exit;
|
|
|
|
Exit:
|
|
// Close the destination file
|
|
if (hDestinationFile != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(hDestinationFile);
|
|
}
|
|
|
|
// Close the source file
|
|
if (hSourceFile != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(hSourceFile);
|
|
}
|
|
|
|
// Post the line status event to the fax service
|
|
PostJobStatus(pJobInfo->CompletionPortHandle,
|
|
pJobInfo->CompletionKey,
|
|
pJobInfo->Status,
|
|
ERROR_SUCCESS);
|
|
|
|
// Release access to this virtual fax device
|
|
LeaveCriticalSection(&pDeviceInfo->cs);
|
|
|
|
WriteDebugString(L"---SampleFSP: FaxDevReceive Exit---\n");
|
|
|
|
return FALSE;
|
|
}
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// function: FaxDevReportStatus
|
|
//
|
|
// Synopsis: 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
|
|
//
|
|
// Arguments: [FaxHandle] - specifies a fax handle returned by the FaxDevStartJob function
|
|
// [FaxStatus] - pointer to a FAX_DEV_STATUS structure that receives status and
|
|
// identification information
|
|
// [FaxStatusSize] - specifies the size, in bytes, of the buffer pointer to by
|
|
// the FaxStatus parameter
|
|
// [FaxStatusSizeRequired] - pointer to a variable that receives the calculated
|
|
// size, in bytes, of the buffer required to hold the FAX_DEV_STATUS structure
|
|
//
|
|
// Returns: TRUE on success
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL WINAPI
|
|
FaxDevReportStatus(
|
|
IN HANDLE FaxHandle OPTIONAL,
|
|
OUT PFAX_DEV_STATUS FaxStatus,
|
|
IN DWORD FaxStatusSize,
|
|
OUT LPDWORD FaxStatusSizeRequired
|
|
)
|
|
{
|
|
// pJobInfo is a pointer to the fax job data
|
|
PJOB_INFO pJobInfo;
|
|
// pDeviceInfo is a pointer to the virtual fax device data
|
|
PDEVICE_INFO pDeviceInfo;
|
|
// dwSize is the size of the completion packet
|
|
DWORD dwSize;
|
|
// upString is the offset of the strings within the completion packet
|
|
UINT_PTR upStringOffset;
|
|
HRESULT hr = S_OK;
|
|
BOOL bRetVal = FALSE;
|
|
|
|
WriteDebugString(L"---SampleFSP: FaxDevReportStatus Enter---\n");
|
|
|
|
if (FaxHandle == NULL) {
|
|
// Set the error code
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
|
|
WriteDebugString(L" ERROR: FaxDevReportStatus Failed: ERROR_INVALID_HANDLE\n");
|
|
WriteDebugString(L"---SampleFSP: FaxDevReportStatus Exit---\n");
|
|
return FALSE;
|
|
}
|
|
|
|
if (FaxStatusSizeRequired == NULL) {
|
|
// Set the error code
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
WriteDebugString(L" ERROR: FaxDevReportStatus Failed: ERROR_INVALID_PARAMETER\n");
|
|
WriteDebugString(L"---SampleFSP: FaxDevReportStatus Exit---\n");
|
|
return FALSE;
|
|
}
|
|
|
|
if ((FaxStatus == NULL) && (FaxStatusSize != 0)) {
|
|
// Set the error code
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
WriteDebugString(L" ERROR: FaxDevReportStatus Failed: ERROR_INVALID_PARAMETER\n");
|
|
WriteDebugString(L"---SampleFSP: FaxDevReportStatus Exit---\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// Get the fax job data from FaxHandle
|
|
pJobInfo = (PJOB_INFO) FaxHandle;
|
|
// Get the virtual fax device data from the fax job data
|
|
pDeviceInfo = (PDEVICE_INFO) pJobInfo->pDeviceInfo;
|
|
|
|
// Wait for access to this virtual fax device
|
|
EnterCriticalSection(&pDeviceInfo->cs);
|
|
|
|
// Initialize the size of the completion packet
|
|
dwSize = sizeof(FAX_DEV_STATUS);
|
|
if (pJobInfo->CSI != NULL) {
|
|
// Increase the size of the completion packet for the remote fax device indentifier
|
|
dwSize += (lstrlen(pJobInfo->CSI) + 1) * sizeof(WCHAR);
|
|
}
|
|
if (pJobInfo->CallerId != NULL) {
|
|
// Increase the size of the completion packet for the calling fax device identifier
|
|
dwSize += (lstrlen(pJobInfo->CallerId) + 1) * sizeof(WCHAR);
|
|
}
|
|
if (pJobInfo->RoutingInfo != NULL) {
|
|
// Increase the size of the completion packet for the routing string
|
|
dwSize += (lstrlen(pJobInfo->RoutingInfo) + 1) * sizeof(WCHAR);
|
|
}
|
|
|
|
// Set the calculated size of the buffer required to hold the completion packet
|
|
*FaxStatusSizeRequired = dwSize;
|
|
|
|
if ((FaxStatus == NULL) && (FaxStatusSize == 0)) {
|
|
// Release access to this virtual fax device
|
|
LeaveCriticalSection(&pDeviceInfo->cs);
|
|
WriteDebugString(L"---SampleFSP: FaxDevReportStatus Exit---\n");
|
|
return TRUE;
|
|
}
|
|
|
|
if (FaxStatusSize < dwSize) {
|
|
// Set the error code
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
// Release access to this virtual fax device
|
|
LeaveCriticalSection(&pDeviceInfo->cs);
|
|
|
|
WriteDebugString(L" ERROR: FaxDevReportStatus Failed: ERROR_INSUFFICIENT_BUFFER\n");
|
|
WriteDebugString(L"---SampleFSP: FaxDevReportStatus Exit---\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// Initialize upStringOffset
|
|
upStringOffset = sizeof(FAX_DEV_STATUS);
|
|
|
|
// Set the completion packet's structure size
|
|
FaxStatus->SizeOfStruct = sizeof(FAX_DEV_STATUS);
|
|
// Copy the completion packet's fax status identifier
|
|
FaxStatus->StatusId = pJobInfo->Status;
|
|
// Set the completion packet's string resource identifier to 0
|
|
FaxStatus->StringId = 0;
|
|
// Copy the completion packet's current page number
|
|
FaxStatus->PageCount = pJobInfo->PageCount;
|
|
// Copy the completion packet's remote fax device identifier
|
|
if (pJobInfo->CSI != NULL) {
|
|
FaxStatus->CSI = (LPWSTR) ((UINT_PTR) FaxStatus + upStringOffset);
|
|
hr = StringCchCopy(FaxStatus->CSI, (lstrlen(pJobInfo->CSI) + 1) ,pJobInfo->CSI);
|
|
if(hr != S_OK)
|
|
{
|
|
WriteDebugString(L"StringCchCopy failed, hr = 0x%x for FaxStatus->CSI", hr);
|
|
LeaveCriticalSection(&pDeviceInfo->cs);
|
|
return FALSE;
|
|
}
|
|
upStringOffset += (lstrlen(pJobInfo->CSI) + 1) * sizeof(WCHAR);
|
|
}
|
|
// Set the completion packet's calling fax device identifier to NULL
|
|
FaxStatus->CallerId = NULL;
|
|
if (pJobInfo->CallerId != NULL) {
|
|
FaxStatus->CallerId = (LPWSTR) ((UINT_PTR) FaxStatus + upStringOffset);
|
|
hr = StringCchCopy(FaxStatus->CallerId, (lstrlen(pJobInfo->CallerId) + 1) ,pJobInfo->CallerId);
|
|
if(hr != S_OK)
|
|
{
|
|
WriteDebugString(L"StringCchCopy failed, hr = 0x%x for FaxStatus->CallerId", hr);
|
|
LeaveCriticalSection(&pDeviceInfo->cs);
|
|
return FALSE;
|
|
}
|
|
upStringOffset += (lstrlen(pJobInfo->CallerId) + 1) * sizeof(WCHAR);
|
|
}
|
|
// Set the completion packet's routing string to NULL
|
|
FaxStatus->RoutingInfo = NULL;
|
|
if (pJobInfo->RoutingInfo != NULL) {
|
|
FaxStatus->RoutingInfo = (LPWSTR) ((UINT_PTR) FaxStatus + upStringOffset);
|
|
hr = StringCchCopy(FaxStatus->RoutingInfo, (lstrlen(pJobInfo->RoutingInfo) + 1) ,pJobInfo->RoutingInfo);
|
|
if(hr != S_OK)
|
|
{
|
|
WriteDebugString(L"StringCchCopy failed, hr = 0x%x for FaxStatus->RoutingInfo", hr);
|
|
LeaveCriticalSection(&pDeviceInfo->cs);
|
|
return FALSE;
|
|
}
|
|
upStringOffset += (lstrlen(pJobInfo->RoutingInfo) + 1) * sizeof(WCHAR);
|
|
}
|
|
// Copy the completion packet's Win32 error code
|
|
FaxStatus->ErrorCode = ERROR_SUCCESS;
|
|
|
|
// Release access to this virtual fax device
|
|
LeaveCriticalSection(&pDeviceInfo->cs);
|
|
|
|
WriteDebugString(L"---SampleFSP: FaxDevReportStatus Exit---\n");
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// function: FaxDevAbortOperation
|
|
//
|
|
// Synopsis: 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
|
|
|
|
// Arguments: [FaxHandle] - specifies a fax handle returned by the FaxDevStartJob function
|
|
//
|
|
// Returns: TRUE on success
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL WINAPI
|
|
FaxDevAbortOperation(
|
|
IN HANDLE FaxHandle
|
|
)
|
|
{
|
|
// pJobInfo is a pointer to the fax job data
|
|
PJOB_INFO pJobInfo;
|
|
// pDeviceInfo is a pointer to the virtual fax device data
|
|
PDEVICE_INFO pDeviceInfo;
|
|
|
|
WriteDebugString(L"---SampleFSP: FaxDevAbortOperation Enter---\n");
|
|
|
|
if (FaxHandle == NULL) {
|
|
// Set the error code
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
|
|
WriteDebugString(L" ERROR: FaxDevAbortOperation Failed: ERROR_INVALID_HANDLE\n");
|
|
WriteDebugString(L"---SampleFSP: FaxDevAbortOperation Exit---\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// Get the fax job data from FaxHandle
|
|
pJobInfo = (PJOB_INFO) FaxHandle;
|
|
// Get the virtual fax device data from the fax job data
|
|
pDeviceInfo = (PDEVICE_INFO) pJobInfo->pDeviceInfo;
|
|
|
|
// Wait for access to this virtual fax device
|
|
EnterCriticalSection(&pDeviceInfo->cs);
|
|
|
|
// Set the virtual fax device status
|
|
pDeviceInfo->Status = DEVICE_ABORTING;
|
|
|
|
// Release access to this virtual fax device
|
|
LeaveCriticalSection(&pDeviceInfo->cs);
|
|
|
|
WriteDebugString(L"---SampleFSP: FaxDevAbortOperation Exit---\n");
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// function: DeviceReceiveThread
|
|
//
|
|
// Synopsis: Thread to watch for an incoming fax transmission
|
|
//
|
|
// Arguments: [pdwDeviceId] - pointer to the virtual fax device identifier
|
|
//
|
|
// Returns: DWORD
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD WINAPI DeviceReceiveThread(LPDWORD pdwDeviceId)
|
|
{
|
|
// hChangeNotification is a handle to a notification change in a directory
|
|
HANDLE hChangeNotification;
|
|
// hWaitObjects are the handles to the wait objects
|
|
HANDLE hWaitObjects[2];
|
|
// dwDeviceId is the virtual fax device identifier
|
|
DWORD dwDeviceId;
|
|
// pLineMessage is a pointer to LINEMESSAGE structure to signal an incoming fax transmission to the fax service
|
|
LPLINEMESSAGE pLineMessage;
|
|
|
|
WriteDebugString(L"---SampleFSP: DeviceReceiveThread Enter---\n");
|
|
|
|
// Copy the virtual fax device identifier
|
|
dwDeviceId = *pdwDeviceId;
|
|
MemFreeMacro(pdwDeviceId);
|
|
|
|
// Create the change notification handle
|
|
hChangeNotification = FindFirstChangeNotification(g_pDeviceInfo[dwDeviceId]->Directory,
|
|
FALSE,
|
|
FILE_NOTIFY_CHANGE_ATTRIBUTES);
|
|
if (hChangeNotification == INVALID_HANDLE_VALUE) {
|
|
goto Exit;
|
|
}
|
|
|
|
// Wait for access to this virtual fax device
|
|
EnterCriticalSection(&g_pDeviceInfo[dwDeviceId]->cs);
|
|
|
|
// Set hWaitObjects
|
|
hWaitObjects[0] = g_pDeviceInfo[dwDeviceId]->ExitEvent;
|
|
hWaitObjects[1] = hChangeNotification;
|
|
|
|
// Release access to this virtual fax device
|
|
LeaveCriticalSection(&g_pDeviceInfo[dwDeviceId]->cs);
|
|
|
|
while (TRUE) {
|
|
// Wait for the exit event or notification change to be signaled
|
|
if ( WaitForMultipleObjects(2,
|
|
hWaitObjects,
|
|
FALSE,
|
|
INFINITE) == WAIT_OBJECT_0) {
|
|
break;
|
|
}
|
|
|
|
// Wait for access to this virtual fax device
|
|
EnterCriticalSection(&g_pDeviceInfo[dwDeviceId]->cs);
|
|
|
|
if (g_pDeviceInfo[dwDeviceId]->Status == DEVICE_IDLE) {
|
|
// Allocate a block of memory for the completion packet
|
|
pLineMessage = (LPLINEMESSAGE) LocalAlloc(LPTR, sizeof(LINEMESSAGE));
|
|
if (pLineMessage != NULL) {
|
|
// Initialize the completion packet
|
|
// Set the completion packet's handle to the virtual fax device
|
|
pLineMessage->hDevice = dwDeviceId + NEWFSP_DEVICE_ID_PREFIX;
|
|
// Set the completion packet's virtual fax device message
|
|
pLineMessage->dwMessageID = 0;
|
|
// Set the completion packet's instance data
|
|
pLineMessage->dwCallbackInstance = 0;
|
|
// Set the completion packet's first parameter
|
|
pLineMessage->dwParam1 = LINEDEVSTATE_RINGING;
|
|
// Set the completion packet's second parameter
|
|
pLineMessage->dwParam2 = 0;
|
|
// Set the completion packet's third parameter
|
|
pLineMessage->dwParam3 = 0;
|
|
|
|
WriteDebugString(L"---SampleFSP: DeviceReceiveThread Signaling Fax Service...---\n");
|
|
|
|
// Post the completion packet
|
|
PostQueuedCompletionStatus(g_CompletionPort,
|
|
sizeof(LINEMESSAGE),
|
|
g_CompletionKey,
|
|
(LPOVERLAPPED) pLineMessage);
|
|
}
|
|
}
|
|
|
|
// Release access to this virtual fax device
|
|
LeaveCriticalSection(&g_pDeviceInfo[dwDeviceId]->cs);
|
|
|
|
// Find the next notification change
|
|
FindNextChangeNotification(hChangeNotification);
|
|
}
|
|
|
|
Exit:
|
|
if (hChangeNotification != INVALID_HANDLE_VALUE) {
|
|
// Close the handle to the change notification
|
|
FindCloseChangeNotification(hChangeNotification);
|
|
}
|
|
|
|
// Close the handle to the exit event
|
|
CloseHandle(hWaitObjects[0]);
|
|
|
|
WriteDebugString(L"---SampleFSP: DeviceReceiveThread Exit---\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// function: DllRegisterServer
|
|
//
|
|
// Synopsis: Function for the in-process server to create its registry entries
|
|
//
|
|
// Arguments: void
|
|
//
|
|
// Returns: S_OK on success
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDAPI DllRegisterServer()
|
|
{
|
|
// hModWinfax is the handle to the winfax module
|
|
HMODULE hModWinfax;
|
|
|
|
// szCurrentDirectory is the name of the current directory
|
|
WCHAR szCurrentDirectory[MAX_PATH_LEN];
|
|
// szCurrentFilename is the name of the current filename
|
|
WCHAR szCurrentFilename[_MAX_FNAME];
|
|
// szDestinationFilename is the name of the destination filename
|
|
WCHAR szDestinationFilename[MAX_PATH];
|
|
// szWinFaxDllLocation is the location of the winfax.dll
|
|
WCHAR szWinFaxDllLocation[MAX_PATH+12]={0};
|
|
|
|
// pFaxRegisterServiceProvider is a pointer to the FaxRegisterServiceProvider() winfax api
|
|
PFAXREGISTERSERVICEPROVIDER pFaxRegisterServiceProvider;
|
|
|
|
// pDeviceInfo is a pointer to the virtual fax devices
|
|
PDEVICE_INFO pDeviceInfo;
|
|
// pCurrentDeviceInfo is a pointer to the current virtual fax device
|
|
PDEVICE_INFO pCurrentDeviceInfo;
|
|
// dwIndex is a counter to enumerate each virtual fax device
|
|
DWORD dwIndex;
|
|
|
|
BOOL bRetVal = FALSE;
|
|
HRESULT hr = S_OK;
|
|
// Open the log file
|
|
OpenLogFile(FALSE, NULL);
|
|
|
|
WriteDebugString(L"---SampleFSP: DllRegisterServer Enter---\n");
|
|
|
|
// Get the current directory
|
|
if (GetCurrentDirectory(MAX_PATH_LEN, szCurrentDirectory) == 0) {
|
|
WriteDebugString(L" ERROR: GetCurrentDirectory Failed: 0x%08x\n", GetLastError());
|
|
WriteDebugString(L" ERROR: DllRegisterServer Failed\n");
|
|
WriteDebugString(L"---SampleFSP: DllRegisterServer Exit---\n");
|
|
|
|
// Close the log file
|
|
CloseLogFile();
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
// Set the current filename
|
|
|
|
hr = StringCchCopy(szCurrentFilename, _MAX_FNAME,szCurrentDirectory);
|
|
if(hr != S_OK)
|
|
{
|
|
WriteDebugString(L"StringCchCopy failed, hr = 0x%x for szCurrentFilename", hr);
|
|
return hr;
|
|
}
|
|
hr = StringCchCat(szCurrentFilename, _MAX_FNAME,L"\\SampleFSP.dll");
|
|
if(hr != S_OK)
|
|
{
|
|
WriteDebugString(L"StringCchCat failed, hr = 0x%x for szCurrentFilename ", hr);
|
|
return hr;
|
|
}
|
|
// Get the destination filename
|
|
if (ExpandEnvironmentStrings(NEWFSP_PROVIDER_IMAGENAME, szDestinationFilename, MAX_PATH) == 0) {
|
|
WriteDebugString(L" ERROR: ExpandEnvironmentStrings Failed: 0x%08x\n", GetLastError());
|
|
WriteDebugString(L" ERROR: DllRegisterServer Failed\n");
|
|
WriteDebugString(L"---SampleFSP: DllRegisterServer Exit---\n");
|
|
|
|
// Close the log file
|
|
CloseLogFile();
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
if (lstrcmpi(szDestinationFilename, szCurrentFilename) != 0) {
|
|
// Copy the current filename to the destination filename
|
|
if (CopyFile(L"SampleFSP.dll", szDestinationFilename, FALSE) == FALSE) {
|
|
WriteDebugString(L" ERROR: CopyFile Failed: 0x%08x\n", GetLastError());
|
|
WriteDebugString(L" ERROR: DllRegisterServer Failed\n");
|
|
WriteDebugString(L"---SampleFSP: DllRegisterServer Exit---\n");
|
|
|
|
// Close the log file
|
|
CloseLogFile();
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
}
|
|
|
|
//we assume that winfax.dll is located in SystemDirectory path
|
|
|
|
if (GetSystemDirectory(szWinFaxDllLocation, MAX_PATH+1) == 0)
|
|
{
|
|
WriteDebugString( L"GetSystemDirectory failed, ec = %d\n", GetLastError() );
|
|
// Close the log file
|
|
CloseLogFile();
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
hr = StringCchCat(szWinFaxDllLocation,MAX_PATH+12,L"\\winfax.dll" );
|
|
if(hr != S_OK)
|
|
{
|
|
WriteDebugString( L"StringCchCat failed, hr = 0x%x for szWinFaxDllLocation", hr );
|
|
return hr;
|
|
}
|
|
|
|
if (wcslen(szWinFaxDllLocation) >= MAX_PATH) {
|
|
WriteDebugString(L" ERROR: Winfax.dll location is too long\n");
|
|
// Close the log file
|
|
CloseLogFile();
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
// Load the winfax dll
|
|
hModWinfax = LoadLibrary( szWinFaxDllLocation );
|
|
if (hModWinfax == NULL) {
|
|
WriteDebugString(L" ERROR: LoadLibrary Failed: 0x%08x\n", GetLastError());
|
|
WriteDebugString(L" ERROR: DllRegisterServer Failed\n");
|
|
WriteDebugString(L"---SampleFSP: DllRegisterServer Exit---\n");
|
|
|
|
// Close the log file
|
|
CloseLogFile();
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
pFaxRegisterServiceProvider = (PFAXREGISTERSERVICEPROVIDER) GetProcAddress(hModWinfax, "FaxRegisterServiceProviderW");
|
|
if (pFaxRegisterServiceProvider == NULL) {
|
|
WriteDebugString(L" ERROR: GetProcAddress Failed: 0x%08x\n", GetLastError());
|
|
WriteDebugString(L" ERROR: DllRegisterServer Failed\n");
|
|
|
|
FreeLibrary(hModWinfax);
|
|
|
|
WriteDebugString(L"---SampleFSP: DllRegisterServer Exit---\n");
|
|
|
|
// Close the log file
|
|
CloseLogFile();
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
// Register the fax service provider
|
|
if (pFaxRegisterServiceProvider(NEWFSP_PROVIDER,
|
|
NEWFSP_PROVIDER_FRIENDLYNAME,
|
|
NEWFSP_PROVIDER_IMAGENAME,
|
|
NEWFSP_PROVIDER_PROVIDERNAME) == FALSE) {
|
|
WriteDebugString(L" ERROR: FaxRegisterServiceProvider Failed: 0x%08x\n", GetLastError());
|
|
WriteDebugString(L" ERROR: DllRegisterServer Failed\n");
|
|
|
|
FreeLibrary(hModWinfax);
|
|
|
|
WriteDebugString(L"---SampleFSP: DllRegisterServer Exit---\n");
|
|
|
|
// Close the log file
|
|
CloseLogFile();
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
FreeLibrary(hModWinfax);
|
|
|
|
// Set g_hHeap
|
|
MemInitializeMacro(GetProcessHeap());
|
|
|
|
// Create the virtual fax devices
|
|
for (dwIndex = 0, pCurrentDeviceInfo = NULL, pDeviceInfo = NULL; dwIndex < NEWFSP_DEVICE_LIMIT; dwIndex++) {
|
|
// Allocate a block of memory for the virtual fax device data
|
|
if (pCurrentDeviceInfo == NULL) {
|
|
pCurrentDeviceInfo = (PDEVICE_INFO) MemAllocMacro(sizeof(DEVICE_INFO));
|
|
if (pCurrentDeviceInfo == NULL) {
|
|
continue;
|
|
}
|
|
}
|
|
else {
|
|
pCurrentDeviceInfo->pNextDeviceInfo = (PDEVICE_INFO) MemAllocMacro(sizeof(DEVICE_INFO));
|
|
if (pCurrentDeviceInfo->pNextDeviceInfo == NULL) {
|
|
continue;
|
|
}
|
|
|
|
// Set the pointer to the current virtual fax device
|
|
pCurrentDeviceInfo = pCurrentDeviceInfo->pNextDeviceInfo;
|
|
}
|
|
|
|
// Set the indentifier of the virtual fax device
|
|
pCurrentDeviceInfo->DeviceId = dwIndex;
|
|
// Set the virtual fax device's incoming fax directory to the current directory
|
|
|
|
hr = StringCchCopy(pCurrentDeviceInfo->Directory,MAX_PATH_LEN,szCurrentDirectory );
|
|
if(hr != S_OK)
|
|
{
|
|
WriteDebugString( L"StringCchCopy failed, hr = 0x%x for pCurrentDeviceInfo->Directory", hr );
|
|
return hr;
|
|
}
|
|
//lstrcpy(pCurrentDeviceInfo->Directory, szCurrentDirectory);
|
|
|
|
if (pDeviceInfo == NULL) {
|
|
// Set the pointer to the virtual fax devices
|
|
pDeviceInfo = pCurrentDeviceInfo;
|
|
}
|
|
}
|
|
|
|
// Set the registry data for the newfsp service provider
|
|
SetNewFspRegistryData(FALSE, szCurrentDirectory, pDeviceInfo);
|
|
|
|
// Enumerate the virtual fax devices
|
|
for (pCurrentDeviceInfo = pDeviceInfo; pCurrentDeviceInfo; pCurrentDeviceInfo = pDeviceInfo) {
|
|
// Delete the virtual fax device data
|
|
pDeviceInfo = pCurrentDeviceInfo->pNextDeviceInfo;
|
|
MemFreeMacro(pCurrentDeviceInfo);
|
|
}
|
|
|
|
WriteDebugString(L"---SampleFSP: DllRegisterServer Exit---\n");
|
|
|
|
// Close the log file
|
|
CloseLogFile();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// function: DllUnregisterServer
|
|
//
|
|
// Synopsis: Function for the in-process server to delete its registry entries
|
|
//
|
|
// Arguments: VOID
|
|
//
|
|
// Returns: S_OK on success
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDAPI DllUnregisterServer()
|
|
{
|
|
// hModWinfax is the handle to the winfax module
|
|
HMODULE hModWinfax;
|
|
// hServiceProvidersKey is the handle to the fax service providers registry key
|
|
HKEY hServiceProvidersKey = NULL;
|
|
// hNewFspKey is the handle to the newfsp service provider registry key
|
|
HKEY hNewFspKey = NULL;
|
|
// hNewFspKey is the handle to the newfsp service provider registry key
|
|
HKEY hDevicesKey = NULL;
|
|
|
|
// szWinFaxDllLocation is the location of the winfax.dll
|
|
WCHAR szWinFaxDllLocation[MAX_PATH+12]={0};
|
|
|
|
// pFaxRegisterServiceProvider is a pointer to the FaxRegisterServiceProvider() winfax api
|
|
PFAXUNREGISTERSERVICEPROVIDER pFaxUnregisterServiceProvider;
|
|
|
|
BOOL bRetVal = FALSE;
|
|
DWORD dwIndex = 0;
|
|
HRESULT hr = S_OK;
|
|
WCHAR strIndex[20] = {0};
|
|
// Open the log file
|
|
OpenLogFile(FALSE, NULL);
|
|
|
|
WriteDebugString(L"---SampleFSP: DllUnregisterServer Enter---\n");
|
|
//we assume that winfax.dll is located in SystemDirectory path
|
|
if (GetSystemDirectory(szWinFaxDllLocation, MAX_PATH+1) == 0)
|
|
{
|
|
WriteDebugString( L"GetSystemDirectory failed, ec = %d\n", GetLastError() );
|
|
// Close the log file
|
|
CloseLogFile();
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
hr = StringCchCat(szWinFaxDllLocation,MAX_PATH+12,L"\\winfax.dll" );
|
|
if(hr != S_OK)
|
|
{
|
|
WriteDebugString( L"StringCchCat failed, hr = 0x%x for szWinFaxDllLocation", hr );
|
|
return hr;
|
|
}
|
|
|
|
if (wcslen(szWinFaxDllLocation) >= MAX_PATH) {
|
|
WriteDebugString(L" ERROR: Winfax.dll location is too long\n");
|
|
// Close the log file
|
|
CloseLogFile();
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
// Load the winfax dll
|
|
hModWinfax = LoadLibrary( szWinFaxDllLocation );
|
|
if (hModWinfax == NULL) {
|
|
WriteDebugString(L" ERROR: LoadLibrary Failed: 0x%08x\n", GetLastError());
|
|
WriteDebugString(L" ERROR: DllUnregisterServer Failed\n");
|
|
WriteDebugString(L"---SampleFSP: DllUnregisterServer Exit---\n");
|
|
|
|
// Close the log file
|
|
CloseLogFile();
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
pFaxUnregisterServiceProvider = (PFAXUNREGISTERSERVICEPROVIDER) GetProcAddress(hModWinfax, "FaxUnregisterServiceProviderW");
|
|
if (pFaxUnregisterServiceProvider == NULL) {
|
|
WriteDebugString(L" ERROR: GetProcAddress Failed: 0x%08x\n", GetLastError());
|
|
WriteDebugString(L" ERROR: DllUnregisterServer Failed\n");
|
|
|
|
FreeLibrary(hModWinfax);
|
|
|
|
WriteDebugString(L"---SampleFSP: DllUnregisterServer Exit---\n");
|
|
|
|
// Close the log file
|
|
CloseLogFile();
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
// Open the fax service providers registry key
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
FAX_PROVIDERS_REGKEY,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hServiceProvidersKey) != ERROR_SUCCESS) {
|
|
WriteDebugString(L" ERROR: RegOpenKeyEx Failed: 0x%08x\n", GetLastError());
|
|
goto Exit;
|
|
}
|
|
|
|
// Open the newfsp service provider registry key
|
|
if (RegOpenKeyEx(hServiceProvidersKey,
|
|
NEWFSP_PROVIDER,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hNewFspKey) != ERROR_SUCCESS) {
|
|
WriteDebugString(L" ERROR: RegOpenKeyEx Failed: 0x%08x\n", GetLastError());
|
|
goto Exit;
|
|
}
|
|
|
|
// Open the newfsp service provider registry key
|
|
if (RegOpenKeyEx(hNewFspKey,
|
|
NEWFSP_DEVICES,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hDevicesKey) != ERROR_SUCCESS) {
|
|
WriteDebugString(L" ERROR: RegOpenKeyEx Failed: 0x%08x\n", GetLastError());
|
|
goto Exit;
|
|
}
|
|
|
|
// Create the virtual fax devices
|
|
for (dwIndex = 0; dwIndex < NEWFSP_DEVICE_LIMIT; dwIndex++)
|
|
{
|
|
_itot_s(dwIndex, strIndex,10);
|
|
if (RegDeleteKey(hDevicesKey, strIndex)!= ERROR_SUCCESS) {
|
|
WriteDebugString(L" ERROR: RegDeleteKey Failed: 0x%08x\n", GetLastError());
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if (RegDeleteKey(hNewFspKey, NEWFSP_DEVICES) != ERROR_SUCCESS) {
|
|
WriteDebugString(L" ERROR: RegDeleteKey Failed: 0x%08x\n", GetLastError());
|
|
goto Exit;
|
|
}
|
|
|
|
// Register the fax service provider
|
|
if (pFaxUnregisterServiceProvider(NEWFSP_PROVIDER) == FALSE) {
|
|
WriteDebugString(L" ERROR: FaxUnregisterServiceProvider Failed: 0x%08x\n", GetLastError());
|
|
WriteDebugString(L" ERROR: DllUnregisterServer Failed\n");
|
|
|
|
FreeLibrary(hModWinfax);
|
|
|
|
WriteDebugString(L"---SampleFSP: DllUnregisterServer Exit---\n");
|
|
|
|
// Close the log file
|
|
CloseLogFile();
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
FreeLibrary(hModWinfax);
|
|
WriteDebugString(L"---SampleFSP: DllRegisterServer Exit---\n");
|
|
bRetVal = TRUE;
|
|
Exit:
|
|
// Close the log file
|
|
CloseLogFile();
|
|
|
|
if(hNewFspKey)
|
|
{
|
|
RegCloseKey(hNewFspKey);
|
|
hNewFspKey = NULL;
|
|
}
|
|
if(hServiceProvidersKey)
|
|
{
|
|
RegCloseKey(hServiceProvidersKey);
|
|
hServiceProvidersKey = NULL;
|
|
}
|
|
if(bRetVal == TRUE)
|
|
return S_OK;
|
|
else
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
|
|
|
|
|
|
|