© 2004 Microsoft Corporation. All rights reserved.

Figure 2 The Fax Service Snap-in

Figure 2 The Fax Service Snap-in
Figure 5 FaxDoc Object Properties

Property
Type
Read/Write
Description
FaxNumber
String
R/W
Recipient fax number. Must be specified unless you provide the FaxDoc with a valid TAPI ConnectionObject
ConnectionObject
Object

Optional TAPI 3.0 call object. You may use it if you want to perform the connection on your own
FileName
String
R/W
Name of the file to be sent. This property must be set to a valid file name before calling the Send method
BillingCode
String
R/W
Optional app- or server-specific billing code that applies to this fax transmission
TSID
String
R/W
Transmitting station ID. Overwrites that of the server
DiscountSend
Long
R/W
A nonzero value for this property specifies that the fax should be sent during discount rate period. If set to 0, the fax will be sent immediately
SendCoverPage
Long
R/W
If this property is set to a nonzero value, the server will include a cover page with the fax transmission
ServerCoverPage
Long
R/W
A nonzero value here indicates that the fax service should use a server-defined cover page (instead of one defined locally)
CoverPageName
String
R/W
Name of the cover page to be included with this fax (name or the full path)
CoverPageNote
String
R/W
Note to appear on the cover page
CoverPageSubject
String
R/W
Subject line to appear on the cover page
DisplayName
String
R/W
Friendly name of the user to be associated with the transmission. Displayed in the fax queue
EmailAddress
String
R/W
E-mail address of the user sending the fax. Appears on the cover page
RecipientName
RecipientTitle
RecipientAddress
RecipientState
RecipientZip
RecipientCountry
String
R/W
Optional strings that appear on the cover page. There are also settings for the recipient's company, department, office, and phone numbers. All of these properties apply to the message sender when prefixed with "Sender." (Examples are SenderName, SenderTitle, SenderOffice, and so on.)
Figure 6 Sample Procedure for Sending Faxes
Sub SendDocByFax()
    
    Dim FaxServer As Object
    Dim FaxDoc As Object

    'Create FaxServer object...
    Set FaxServer = CreateObject("FaxServer.FaxServer")
    '...and connect to it - no empty name allowed
    FaxServer.Connect ("mycomputer")
    'Create document
    Set FaxDoc = FaxServer.CreateDocument("d:\documents\mydoc.doc")
    
    FaxDoc.FaxNumber = "+99 (99) 999999"
    FaxDoc.RecipientName = "John Doe"
    FaxDoc.Send
       
    Set FaxDoc = Nothing
    
    FaxServer.Disconnect
    
    Set FaxServer = Nothing
End Sub
Figure 7 Sending a File
void CFaxTestDlg::SendDocument()
{
   HANDLE               fxHandle;
   PFAX_JOB_PARAM       pfxParam;
   PFAX_COVERPAGE_INFO  pcpInfo;
   DWORD                dwJobId;
   LPCTSTR              pszServerName = NULL;

   // If server name is empty - assume null i.e. local server
   if ( !m_strServerName.IsEmpty() )
      pszServerName = m_strServerName;

   // Connect to the fax server
   if ( !FaxConnectFaxServer(pszServerName, &fxHandle) )
   {
      ReportOSError();
      return;
   }

   // Prepare and allocate job params and cover page data
   if ( FaxCompleteJobParams( &pfxParam, &pcpInfo ) )
   {
      ReportOSError();
      FaxClose(fxHandle);
      return;
   }

   // Display property sheet and gather all recipient and sender info
   CFaxParamsSheet   fps(pfxParam, pcpInfo, m_bUseCoverPage);
   
   // If succeeded send it
   if ( fps.DoModal() != IDCANCEL )
   {
      // Free cover page info if not needed
      if ( !m_bUseCoverPage )
      {
         FaxFreeBuffer(pcpInfo);
         pcpInfo = NULL;
      }

      // Try to send
      if( FaxSendDocument( fxHandle, m_strFileName, pfxParam, pcpInfo, 
          &dwJobId ) )
         AfxMessageBox("SendDoc succeeded");
      else
         ReportOSError();
   }

   // Cleanup here
   FaxFreeBuffer(pfxParam);
   
   if ( pcpInfo )
      FaxFreeBuffer(pcpInfo);

   FaxClose(fxHandle);
}
Figure 8 Controlling Fax Printing
void CFaxTestDlg::PrintText()
{
   FAX_COVERPAGE_INFO   cpInfo;
   FAX_PRINT_INFO       fpInfo;
   FAX_CONTEXT_INFO     fcInfo;
   CDC                  fxDC;
   CSize                sz;
   CRect                rPage;
   LPCTSTR              pszPrinterName = NULL;
   DWORD                dwJobId;

   // If printer name is empty - assume local printer
   if ( !m_strPrinter.IsEmpty() )
      pszPrinterName = m_strPrinter;

   // Prepare structures
   ZeroMemory(&cpInfo,sizeof(FAX_COVERPAGE_INFO));
   ZeroMemory(&fpInfo,sizeof(FAX_PRINT_INFO));

   cpInfo.SizeOfStruct = sizeof(FAX_COVERPAGE_INFO);
   fpInfo.SizeOfStruct = sizeof(FAX_PRINT_INFO);

   // Collect the recipient info and cover page information
   CFxPrintInfoSheet fpiSheet(&fpInfo, &cpInfo, m_bUseCoverPage);

   if ( fpiSheet.DoModal() == IDCANCEL )
      return;

   // Get the printer context
   if ( FaxStartPrintJob( pszPrinterName,
                          &fpInfo,
                          &dwJobId,
                          &fcInfo ) )
   {
      ReportOSError();
      return;
   }

   // Attach HDC to CDC so it is released no matter what happens
   VERIFY(fxDC.Attach(fcInfo.hDC));

   // Print the cover page if needed
   if ( m_bUseCoverPage )
   {
      if ( FaxPrintCoverPage(&fcInfo, &cpInfo) )
      {
         ReportOSError();
         return;
      }
   }

   // Get client rectangle
   CRect   rClient(0, 
                   0, 
                   fxDC.GetDeviceCaps(HORZRES),
                   fxDC.GetDeviceCaps(VERTRES));

   fxDC.StartPage();

   // And draw the text
   fxDC.DrawText(m_strFaxText, &rClient, DT_LEFT | DT_WORDBREAK );

   fxDC.EndPage();
   fxDC.EndDoc();

   fxDC.DeleteDC();
}
Figure 9 Functions Exported by Routing Extensions

Function
Description
FaxRouteInitialize
Called immediately after the extension is loaded by the fax service. Provides the service with the heap handle to be used when exchanging memory with the server, and a set of callback functions implemented inside the fax service
FaxRouteDevice-ChangeNotification
Fax service calls this function whenever a new device has been added to the system, or an existing device has been removed
FaxRouteDeviceEnable
The fax service will call this method to inform the extension DLL that it should (or shouldn't) process faxes received by a specific device
FaxRouteGetRoutingInfo
Called by administrative tools to configure a routing extension
FaxRouteSetRoutingInfo
Called by administrative tools to retrieve the configuration of a routing extension
Figure 11 FAX_ROUTE_CALLBACKROUTINE Members

Member Function
Description
FaxRouteAddFile
Adds new file name to the fax file list
FaxRouteGetFile
Retrieves file information from the fax file list
FaxRouteDeleteFile
Deletes a file from the fax file list
FaxRouteEnumFiles
Enumerates all files in the fax file list
FaxRouteModifyRoutingData
Modifies routing data for a subsequent routing method (by modifying the RoutingInfoData member of the FAX_ROUTE structure)
Figure 12 Sample Routing Method
BOOL WINAPI  FaxRouteMethod1(CONST FAX_ROUTE*   pFaxRoute,   
                             PVOID*             pFailureData,
                             LPDWORD            pdwDataSize )
{
   AFX_MANAGE_STATE(AfxGetStaticModuleState());
   LTRACE( "FaxRouteMethod1");

   TCHAR   szErrorMsg[1024];
   DWORD   dwSize = 0;
   LPWSTR  pszFileName = NULL;

   *pFailureData = NULL;
   *pdwDataSize  = 0;

   try
   {
      CRFaxes fxRset;
      
      // Open the recordset and prepare it for append operation
      fxRset.Open();
      fxRset.AddNew();
      
      fxRset.m_nJobId            = pFaxRoute -> JobId;
      fxRset.m_strCallerId       = pFaxRoute -> CallerId;
      fxRset.m_strCsid           = pFaxRoute -> Csid;
      fxRset.m_strTsid           = pFaxRoute -> Tsid;
      fxRset.m_nDeviceId         = pFaxRoute -> DeviceId;
      fxRset.m_strDeviceName     = pFaxRoute -> DeviceName;
      fxRset.m_strReceiverName   = pFaxRoute -> ReceiverName;
      fxRset.m_strReceiverNumber = pFaxRoute -> ReceiverNumber;

      // Try to retrieve the file name - first query the size
      FaxRouteGetFile( pFaxRoute -> JobId,
                       1,
                       pszFileName,
                       &dwSize );
      // Allocate buffer
      pszFileName = (LPWSTR) HeapAlloc( fxHeap, HEAP_ZERO_MEMORY, 
         dwSize );
      // Get file name
      FaxRouteGetFile( pFaxRoute -> JobId,
                       1,
                       pszFileName,
                       &dwSize );

      fxRset.m_strFileName   = pszFileName;
      // Free the buffer
      HeapFree(fxHeap, 0, pszFileName );
      // Update recorset
      fxRset.Update();
   }
   catch ( CException* e )
   {
      e -> GetErrorMessage(szErrorMsg, sizeof(szErrorMsg));
      e -> Delete();
      LTRACE(szErrorMsg);
      return FALSE;
   }
   catch ( ... )
   {   
      LTRACE( "Unknown exception caught");
      return FALSE;
   }

   return TRUE;
}