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
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.
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-
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!
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.
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
#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.
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.
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.
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-
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