65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 C# 中的传真调制解调器发送传真

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.86/5 (9投票s)

2016年12月9日

CPOL

4分钟阅读

viewsIcon

32148

downloadIcon

1098

使用传真调制解调器和电话线发送传真(C#)

引言

本文将详细介绍如何使用 C# 通过传真调制解调器和电话线发送传真。该代码已在 Windows 7/ 8 / 10 上的“U.S. Robotics V.92 USB Voice Modem”上进行了 100% 测试。这是我第一次尝试作为文章分享内容,请忽略任何错误/遗漏/等。

背景

最近,我们的一位客户要求我对从 Windows 7、8 和 10 通过传真调制解调器和电话线发送传真进行研发。在研发过程中,我发现“FAXCOMLib”和“FAXCOMEXLib”可用于从 Windows 发送传真。因此,我开始使用博客和文章中提供的现有代码,但没有一个代码能正常工作。在大多数情况下,某些事件没有正确触发。我们还需要跟踪状态,例如——“正在拨号”、“正在传输”、“完成”等。

使用代码前的任务

在开始编写代码之前,您可能需要确认一些任务——

  • 确认已安装“Windows 传真和扫描”服务
  • 确认已连接调制解调器并安装必要的驱动程序(如果需要)
  • 确认调制解调器已检测到并在设备管理器中显示
  • 通过“诊断”选项卡中的“查询调制解调器”确认调制解调器工作正常
  • 在“电话和调制解调器”窗口中设置位置(国家和区号)

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

使用代码

我使用了一个 C# 控制台应用程序来发送传真。首先创建一个控制台应用程序,随意命名——我命名为 FaxTest。请注意,我使用了“FAXCOMEXLib”(扩展库)。您可以参考“https://msdn.microsoft.com/en-us/library/windows/desktop/ms693384(v=vs.85).aspx

现在,要使用“FAXCOMEXLib”,我们需要在“引用”中添加“Microsoft Fax Service Extended COM Type Library”,如下图所示。

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

 

添加完引用后,我们就可以开始编码了——

我们在项目中添加了一个名为“FaxSender”的类。然后包含 FAXCOMEXLib 命名空间——

using FAXCOMEXLib;

 

在类构造函数中,我们实例化了 FaxServer,通过提供 MachineName 连接到 FaxServer(您也可以手动提供字符串名称,该名称可以在系统属性中找到),并绑定/注册 FaxServer 事件——

注意:我们使用了“FaxServer”接口而不是“FaxServerClass”,因为我们遇到了一些错误消息;具体原因记不清了,但可能需要将程序集的 Embed Interop Types 设置为 True!

private static FaxServer faxServer;

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

 

我们使用“IFaxServerNotify2_Event”接口设置事件处理程序和要监听的几个事件;它们组合使用 OR (|),注意:网上的许多示例使用 (+) 符号,但那样的做法并不能正确工作。

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);
}

 

在事件处理程序/监听器中,我们打印一些基本通知。“OnOutgoingJobAdded”和“OnOutgoingJobRemoved”将触发一次。但“OnOutgoingJobChanged”会在每次作业发生变化时触发多次,我们可以据此跟踪“FaxJobStatus”。例如,如果我们想知道何时开始拨打某个号码,我们需要检查“FaxJobStatus.ExtendedStatusCode”是否为“fjesDIALING”,或者,如果我们想知道何时开始发送文件,我们需要检查“ExtendedStatusCode”是否为“fjesTRANSMITTING”,等等。

您可以探索“FAX_JOB_EXTENDED_STATUS_ENUM”来了解不同的状态。有关详细信息,您可以参考“https://msdn.microsoft.com/en-us/library/windows/desktop/ms688631(v=vs.85).aspx

注意:如果您仔细查看代码,您会发现使用了“OutgoingQueue.Refresh()”来从传真服务器刷新 FaxOutgoingQueue 对象的信息。您可以参考“https://msdn.microsoft.com/en-us/library/windows/desktop/ms693456(v=vs.85).aspx”以了解更多信息。

#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

 

我们使用“PrintFaxStatus”方法来跟踪一些状态。另请注意,通过检查 2 个条件“faxJobStatus.Status” && “faxJobStatus.ExtendedStatusCode”来确认传真发送成功。因为在我调试时,我发现“OnOutgoingJobChanged”事件触发时,“ExtendedStatusCode”属性最初显示为“fjesCALL_COMPLETED”,而“Status”属性仍然是“fjsINPROGRESS”。在下一次事件触发后,“Status”属性被设置为“fjsCOMPLETED”。这就是为什么我检查两者都完成后。

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.");
    }
}

 

在我们的“SendFax”方法中,我们设置要发送的文档,为此我们使用“FaxDocument”。设置好文档后,我们调用“Submit”方法,该方法启动传真发送过程。

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”方法很简单,为必需的字段分配一些值(作为测试,我使用了硬编码的值!您可以使用配置文件和/或参数)。您必须将测试传真号码“12345678912”更改为真实的传真号码,并设置您想要传真的文件。

注意:请注意,在发送 PDF 时,机器上应安装 PDF 阅读器(例如 Adobe Reader)。另外,在尝试附加和发送文件时,请检查文件未被占用。您可以使用一个简单的方法来检查它,使用 File.OpenRead 并带有一个 try catch 块,并在 finally 块中处理 IOException 后关闭/释放 FileStream。

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");
}

 

最后,要发送传真,请使用以下代码——

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

 

希望这篇博文能对某人有所帮助!欢迎任何评论/建议。

 

参考文献

  • 从 Google 的一些帖子中获取了帮助,其中一些 MSDN 链接内联提及,但此时记不起其他的了。感谢那些其他的帖子!! 

关注点

- 通过检查“faxJobStatus.Status” && faxJobStatus.ExtendedStatusCode”来确认成功发送传真。

- 发送 PDF 时,机器上应安装 PDF 阅读器(例如 Adobe Reader)。

- 在尝试附加和发送文件时,请检查文件未被占用。

历史

© . All rights reserved.