Click here to Skip to main content
15,170,651 members
Articles / Desktop Programming / Win32
Article
Posted 9 Dec 2016

Stats

23.4K views
949 downloads
6 bookmarked

Send Fax with fax-modem in C#

Rate me:
Please Sign up or sign in to vote.
4.86/5 (9 votes)
11 Dec 2016CPOL4 min read
Sending Faxes with fax-modem and telephone line in C#

Introduction

This article is all about sending Faxes (with Fax-modem & Telephone line) in C#. The code is 100% tested with “U.S. Robotics V.92 USB Voice Modem” in Windows 7/ 8 / 10. As it is my first attempt to share something as an article, please ignore any errors/mistakes/etc.

Background

Recently I have been requested to do R&D on Sending Fax using Fax-modem and Telephone line from Windows 7, 8 and 10 for one of our client. During the R&D I have found that “FAXCOMLib” & “FAXCOMEXLib” can be used to send Faxes from Windows. So I started using available code provided in several blogs & articles, but none of the code worked properly. In most of the cases some events are not fired appropriately. Also we need to track status like – “Dialing”, “Transmitting”, “Complete”, etc.

Tasks before using the Code

You may need to confirm some tasks before going to the code-

  • Confirm Windows Fax and Scan service is installed
  • Confirm that you connected the modem and Install necessary driver, if required
  • Confirm modem is detected and shown in the Device Manager
  • Confirm that the modem is working by “Query Modem” from Diagnostics Tab
  • Set the Location (Country & Area code) from the Phone and Modem Window

Confirm Windows Fax and Scan service is installed

 

Confirm modem is detected and shown in the Device Manager and modem is working by “Query Modem” from Diagnostics Tab

 

Set the Location (Country & Area code) from the Phone and Modem Window

Using the code

I have used a C# Console Application to send Faxes. First create a Console Application, name it as you like – I named it FaxTest. Please note, I have used “FAXCOMEXLib” (Extended Lib). You can have a look on “https://msdn.microsoft.com/en-us/library/windows/desktop/ms693384(v=vs.85).aspx

Now to use “FAXCOMEXLib” we need to add “Microsoft Fax Service Extended COM Type Library” in the References as shown in the screenshot.

Add “Microsoft Fax Service Extended COM Type Library” in the References

 

Once we have added the references we are good to start coding –

We add a class named “FaxSender” to the project. Then include FAXCOMEXLib namespace-

C#
using FAXCOMEXLib;

 

In the class constructor, we have instantiated FaxServer, connected to the FaxServer by providing the MachineName (you can also provide the name manually as string which you can find from the system property) and Bind/Register the FaxServer events –

Note: We have used “FaxServer” interface instead of “FaxServerClass” as we have faced some error message; cannot remember right now, for which we may need to set Embed Interop Types of the Assembly to True!

C#
private static FaxServer faxServer;

public FaxSender()
{
    try
    {
        faxServer = new FaxServer();
        faxServer.Connect(Environment.MachineName);
        RegisterFaxServerEvents();
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}

 

We use “IFaxServerNotify2_Event“ interface to set event handlers and couple of events to listen; combined as OR  ( | ), Note: Several examples in web uses (+) which does not work correctly.

C#
private void RegisterFaxServerEvents()
{
    faxServer.OnOutgoingJobAdded += 
            new IFaxServerNotify2_OnOutgoingJobAddedEventHandler(faxServer_OnOutgoingJobAdded);
    faxServer.OnOutgoingJobChanged += 
            new IFaxServerNotify2_OnOutgoingJobChangedEventHandler(faxServer_OnOutgoingJobChanged);
    faxServer.OnOutgoingJobRemoved += 
            new IFaxServerNotify2_OnOutgoingJobRemovedEventHandler(faxServer_OnOutgoingJobRemoved);

var eventsToListen = 
          FAX_SERVER_EVENTS_TYPE_ENUM.fsetFXSSVC_ENDED | FAX_SERVER_EVENTS_TYPE_ENUM.fsetOUT_QUEUE
        | FAX_SERVER_EVENTS_TYPE_ENUM.fsetOUT_ARCHIVE | FAX_SERVER_EVENTS_TYPE_ENUM.fsetQUEUE_STATE 
        | FAX_SERVER_EVENTS_TYPE_ENUM.fsetACTIVITY | FAX_SERVER_EVENTS_TYPE_ENUM.fsetDEVICE_STATUS;

    faxServer.ListenToServerEvents(eventsToListen);
}

 

In the event handlers/listeners we print some basic notifications. The “OnOutgoingJobAdded” and “OnOutgoingJobRemoved” will trigger once. But “OnOutgoingJobChanged” will trigger several times whenever there is a change in job, and we can track “FaxJobStatus”. Say, if want want to know when it starts calling a number, we need to check if “FaxJobStatus.ExtendedStatusCode” is “fjesDIALING”, or, when it starts to send file, we need to check if “ExtendedStatusCode” is “fjesTRANSMITTING”, etc.

You can explore “FAX_JOB_EXTENDED_STATUS_ENUM” for different status. For detail you can have a look on “https://msdn.microsoft.com/en-us/library/windows/desktop/ms688631(v=vs.85).aspx

Note: if you look at the code carefully, you can see a “OutgoingQueue.Refresh()” is used to refreshes FaxOutgoingQueue object information from the fax server. You can see “https://msdn.microsoft.com/en-us/library/windows/desktop/ms693456(v=vs.85).aspx” to learn more

C#
#region Event Handlers/Listeners
private static void faxServer_OnOutgoingJobAdded(FaxServerpFaxServer, string bstrJobId)
{
    Console.WriteLine("OnOutgoingJobAdded event fired. A fax is added to the outgoing queue.");
}

private static void faxServer_OnOutgoingJobChanged(FaxServerpFaxServer, string bstrJobId, FaxJobStatuspJobStatus)
{
    Console.WriteLine("OnOutgoingJobChanged event fired. A fax is changed to the outgoing queue.");
    pFaxServer.Folders.OutgoingQueue.Refresh();
    PrintFaxStatus(pJobStatus);
}

private static void faxServer_OnOutgoingJobRemoved(FaxServerpFaxServer, string bstrJobId)
{
    Console.WriteLine("OnOutgoingJobRemoved event fired. Fax job is removed to outbound queue.");
}
#endregion

 

We use “PrintFaxStatus” method to track few status. Also note that successful fax send is confirmed by checking 2 conditions “faxJobStatus.Status” && “faxJobStatus.ExtendedStatusCode”. Because when I debugged, found that on “OnOutgoingJobChanged” event, the “ExtendedStatusCode” property was shown “fjesCALL_COMPLETED” on its first changed, the “Status” property was still in “fjsINPROGRESS”. After the next event trigger “Status” property was set to “fjsCOMPLETED”. That’s why I checked when both are complete.

C#
private static void PrintFaxStatus(FaxJobStatusfaxJobStatus)
{
    if (faxJobStatus.ExtendedStatusCode == FAX_JOB_EXTENDED_STATUS_ENUM.fjesDIALING)
    {
        Console.WriteLine("Dialing...");
    }

    if (faxJobStatus.ExtendedStatusCode == FAX_JOB_EXTENDED_STATUS_ENUM.fjesTRANSMITTING)
    {
        Console.WriteLine("Sending Fax...");
    }

    if (faxJobStatus.Status == FAX_JOB_STATUS_ENUM.fjsCOMPLETED
        && faxJobStatus.ExtendedStatusCode == FAX_JOB_EXTENDED_STATUS_ENUM.fjesCALL_COMPLETED)
    {
        Console.WriteLine("Fax is sent successfully.");
    }
}

 

In our “SendFax” method, we setup our document to send and for which we use “FaxDocument”. After we set the document, we call the “Submit” method which starts the fax sending process.

C#
public void SendFax()
{
    try
    {
        FaxDocumentSetup();
        objectsubmitReturnValue = faxDoc.Submit(faxServer.ServerName);
        faxDoc = null;                
    }
    catch (System.Runtime.InteropServices.COMExceptioncomException)
    {
        Console.WriteLine("Error connecting to fax server. Error Message: " + comException.Message);
        Console.WriteLine("StackTrace: " + comException.StackTrace);
    }
}

 

FaxDocumentSetup” method is simple, assigning some values to the required fields (as a test, I used hardcoded values ! you can use config file and/or parameters). You must change the test Fax number “12345678912” with a real Fax number and set file which you want to Fax. 

Note: Be informed that while sending a PDF, a pdf reader (say, adobe reader) should be installed in the machine. Also check, File is not in use when try to attach and send. You can use a simple method to check it, using File.OpenRead with a try catch block and close/dispose the FileStream in finally block after handling the IOException.

C#
private void FaxDocumentSetup()
{
    faxDoc = new FaxDocument();
    faxDoc.Priority = FAX_PRIORITY_TYPE_ENUM.fptHIGH;
    faxDoc.ReceiptType = FAX_RECEIPT_TYPE_ENUM.frtNONE;
    faxDoc.AttachFaxToReceipt = true;

    faxDoc.Sender.Name = "Md. Faroque Hossain";
    faxDoc.Sender.Company = "Aprosoft, Bangladesh";
    faxDoc.Body = @"E:\Aprosoft\WPF\Codes\FaxTest\FaxTest\TestPDFFilewithMultiPage.pdf";
    faxDoc.Subject = "Send Test Fax from Windows";
    faxDoc.DocumentName = "TestPDFFilewithMultiPage";
   faxDoc.Recipients.Add("12345678912", "TestReceipent-001");
}

 

Finally to Send Fax, use the below code-

C#
class Program
{
    static void Main(string[] args)
    {
        FaxSender fs = new FaxSender();
        fs.SendFax(); 
        Console.ReadLine();
    }
}

 

Hope this post may be helpful for someone ! Any comments/suggestions are welcome.

 

References:

  • Took help from some post by google, some msdn links are mentioned inline, but at this moment can't remember other. Thanks to those other posts !! 

Points of Interest

- Confirm successful fax send checking “faxJobStatus.Status” && faxJobStatus.ExtendedStatusCode”.

- While sending a PDF, a pdf reader (say, adobe reader) should be installed in the machine.

- Check, File is not in use when try to attach and send.

History

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Md. Faroque Hossain
Software Developer (Senior)
Bangladesh Bangladesh
B.Sc. & M.Sc. in Computer Science and Engineering
Profile: https://bd.linkedin.com/in/mfhossain786

Comments and Discussions

 
QuestionError sending fax from Windows Server 2016 Pin
raghukiranbnv14-Jun-19 2:02
Memberraghukiranbnv14-Jun-19 2:02 
AnswerRe: Error sending fax from Windows Server 2016 Pin
Md. Faroque Hossain7-Jul-19 22:40
MemberMd. Faroque Hossain7-Jul-19 22:40 
QuestionSend-Fax-with-fax-modem-in-Csharp using FaxComExLib Pin
Member 1102589618-Aug-17 7:41
MemberMember 1102589618-Aug-17 7:41 
Hi Md. Faroque Hossain,
Thanks to this post,I have implemented this code to send fax.
I am able to send fax successfully and getting the JobID.
But faxServer_OnOutgoingJobChanged() event not fired that's why i am not able to get the Fax Satatus only faxServer_OnOutgoingJobAdded() event fired.

Please help me.
My Code..

public class FaxSender
{
#region Global Variable
private static string eFaxServerName = ConfigurationManager.AppSettings["eFaxServerName"].ToString();
#endregion
    private static FaxServer faxServer;
    private FaxDocument faxDoc;
    private static string faxNumber = string.Empty;

    public FaxSender()
    {
        StringBuilder objSBTrace = new StringBuilder();

        try
        {               

            faxServer = new FaxServer();
            faxServer.Connect(eFaxServerName);
            RegisterFaxServerEvents();
        }
        catch (Exception ex)
        {

        }
    }

    private void RegisterFaxServerEvents()
    {

        try
        {

            faxServer.OnOutgoingJobAdded +=
            new IFaxServerNotify2_OnOutgoingJobAddedEventHandler(faxServer_OnOutgoingJobAdded);
            faxServer.OnOutgoingJobChanged +=
                new IFaxServerNotify2_OnOutgoingJobChangedEventHandler(faxServer_OnOutgoingJobChanged);
            faxServer.OnOutgoingJobRemoved +=
                new IFaxServerNotify2_OnOutgoingJobRemovedEventHandler(faxServer_OnOutgoingJobRemoved);

            var eventsToListen =
                FAX_SERVER_EVENTS_TYPE_ENUM.fsetFXSSVC_ENDED | FAX_SERVER_EVENTS_TYPE_ENUM.fsetOUT_QUEUE |
                FAX_SERVER_EVENTS_TYPE_ENUM.fsetOUT_ARCHIVE | FAX_SERVER_EVENTS_TYPE_ENUM.fsetQUEUE_STATE |
                FAX_SERVER_EVENTS_TYPE_ENUM.fsetACTIVITY | FAX_SERVER_EVENTS_TYPE_ENUM.fsetDEVICE_STATUS;

            faxServer.ListenToServerEvents(eventsToListen);
        }
        catch (Exception ex)
        {

        }
    }

    #region Event Listeners
    private static void faxServer_OnOutgoingJobAdded(FaxServer pFaxServer, string bstrJobId)
    {           

        Console.WriteLine("OnOutgoingJobAdded event fired. A fax is added to the outgoing queue.");
    }

    private static void faxServer_OnOutgoingJobChanged(FaxServer pFaxServer, string bstrJobId, FaxJobStatus pJobStatus)
    {           

        Console.WriteLine("OnOutgoingJobChanged event fired. A fax is changed to the outgoing queue.");

        pFaxServer.Folders.OutgoingQueue.Refresh();
        PrintFaxStatus(pJobStatus, bstrJobId);
    }

    private static void faxServer_OnOutgoingJobRemoved(FaxServer pFaxServer, string bstrJobId)
    {

        Console.WriteLine("OnOutgoingJobRemoved event fired. Fax job is removed to outbound queue.");
    }
    #endregion

    private static void PrintFaxStatus(FaxJobStatus faxJobStatus, string bstrJobId)
    {
        try
        {
            if (faxJobStatus.ExtendedStatusCode == FAX_JOB_EXTENDED_STATUS_ENUM.fjesDIALING)
            {
                Console.WriteLine("Dialing...");
            }

            if (faxJobStatus.ExtendedStatusCode == FAX_JOB_EXTENDED_STATUS_ENUM.fjesTRANSMITTING)
            {
                Console.WriteLine("Sending Fax...");
            }

            if (faxJobStatus.Status == FAX_JOB_STATUS_ENUM.fjsCOMPLETED
                && faxJobStatus.ExtendedStatusCode == FAX_JOB_EXTENDED_STATUS_ENUM.fjesCALL_COMPLETED)
            {
                Console.WriteLine("Fax is sent successfully.");
            }

            if (faxJobStatus.Status == FAX_JOB_STATUS_ENUM.fjsFAILED)
            {
                Console.WriteLine("Fax sending Failed.");
            }

            if (faxJobStatus.Status == FAX_JOB_STATUS_ENUM.fjsINPROGRESS)
            {
                Console.WriteLine("Fax is in-progress.");
            }

            if (faxJobStatus.Status == FAX_JOB_STATUS_ENUM.fjsNOLINE)
            {
                Console.WriteLine("Fax is no line.");
            }

            if (faxJobStatus.Status == FAX_JOB_STATUS_ENUM.fjsPAUSED)
            {
                Console.WriteLine("Fax is paused.");
            }

            if (faxJobStatus.Status == FAX_JOB_STATUS_ENUM.fjsPENDING)
            {
                Console.WriteLine("Fax is pending.");
            }

            if (faxJobStatus.Status == FAX_JOB_STATUS_ENUM.fjsRETRIES_EXCEEDED)
            {
                Console.WriteLine("Fax retry exceeded.");
            }

            if (faxJobStatus.Status == FAX_JOB_STATUS_ENUM.fjsRETRYING)
            {
                objSTrace.Append("Fax is retrying");
                SaveLogger.SaveLoggerTrace(objSTrace);
                objSTrace.Clear();
                Console.WriteLine("Fax is retrying.");
            }

            if (faxJobStatus.Status == FAX_JOB_STATUS_ENUM.fjsROUTING)
            {
                objSTrace.Append("Fax is routing.");
                SaveLogger.SaveLoggerTrace(objSTrace);
                objSTrace.Clear();
                Console.WriteLine("Fax is routing.");
            }  

        }
        catch (Exception ex)
        {
        }

    }

    public string SendFax(string subject, string FaxDocument, string FaxNumber)
    {

        faxNumber = FaxNumber;<br />
        try
        {
            FaxDocumentSetup(subject, FaxDocument, FaxNumber);
            var JobId = faxDoc.Submit(faxServer.ServerName);
            faxDoc = null;              

            result = Convert.ToString(JobId[0]);
            Console.WriteLine("Job Id: " + Convert.ToString(JobId[0]));
        }
        catch (System.Runtime.InteropServices.COMException comException)
        {

            Console.WriteLine("Error connecting to fax server. Error Message: " + comException.Message);
            Console.WriteLine("StackTrace: " + comException.StackTrace);
        }
        catch (Exception ex)
        {
        }
        return result;
    }

    private void FaxDocumentSetup(string subject, string FaxDocument, string FaxNumber)
    {

        try
        {                

            faxDoc = new FaxDocument();
            faxDoc.Priority = FAX_PRIORITY_TYPE_ENUM.fptHIGH;
            faxDoc.ReceiptType = FAX_RECEIPT_TYPE_ENUM.frtNONE;
            faxDoc.AttachFaxToReceipt = true;
            faxDoc.Body = FaxDocument;
            faxDoc.Subject = subject;
            faxDoc.Recipients.Add(FaxNumber);
        }
        catch (Exception ex)
        {<br />
        }
    }

}

AnswerRe: Send-Fax-with-fax-modem-in-Csharp using FaxComExLib Pin
Md. Faroque Hossain7-Jul-19 20:19
MemberMd. Faroque Hossain7-Jul-19 20:19 
Generalprint wi-fi Pin
Garrytroomen13-Dec-16 4:51
MemberGarrytroomen13-Dec-16 4:51 
GeneralRe: print wi-fi Pin
Md. Faroque Hossain19-Dec-16 23:29
MemberMd. Faroque Hossain19-Dec-16 23:29 
QuestionImages missing Pin
Wendelius9-Dec-16 4:11
mveWendelius9-Dec-16 4:11 
AnswerRe: Images missing Pin
Md. Faroque Hossain19-Dec-16 23:30
MemberMd. Faroque Hossain19-Dec-16 23:30 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.