我以前见过这个问题,但我没有看到任何明确的答案,也绝对没有任何解决我问题的答案。我创建了一个使用FAXCOMEXLib库发送传真(半自动)的windows服务。到目前为止,我的服务在发送文本文件(.txt)方面是成功的。但当我尝试发送pdf、jpg或tif文件时,我会收到"操作失败";错误在SO中,我看到了很多关于运行服务的用户权限的讨论。我尝试了很多不同的选项(本地服务、本地用户、具有管理员权限的自定义用户、允许服务与桌面交互)。但似乎没有什么不同。该服务似乎没有权限打开适当的应用程序;打印";pdf、jpg或tif文件。但我只是猜测。有人在Windows服务中通过FAXCOMEXLib成功发送传真吗?这是我发送传真的代码:
fileName = @"D:tempFaxTest.txt"; //THIS WORKS
//fileName = @"D:tempFaxTest.pdf"; //Operation failed
//fileName = @"D:tempFaxTest.tif"; //Operation failed
faxDoc.Sender.Name = faxRec.From;
faxDoc.Sender.Company = faxRec.From;
faxDoc.Body = fileName;
faxDoc.Subject = faxRec.ReferenceId;
faxDoc.DocumentName = faxRec.ReferenceId;
var to = "xxxxxxxxxx";
faxDoc.Recipients.Add(to, "Some Name");
var serverName = Environment.MachineName;
string[] returnVal = faxDoc.Submit(serverName);
如果你想知道,是的,这些文件确实存在于具有这些名称的服务器上,并且它们是有效的文件(我可以在Adobe Reader和图片查看器中打开它们)。如果我在我的开发机器上本地运行它,这也很好。当然,在发送之前(在我的本地机器上)会弹出相应的查看器。我的猜测是,由于某种原因,该服务无法打开查看器。有人在Windows服务中以这种方式成功发送PDF吗?
MSDN文章中对它进行了很好的描述。需要发生的一件不平凡的事情是一些软件需要将文件内容转换为可以传真的可打印文本。报价:
可以作为传真正文发送的文档示例有文本文件(.txt)、Microsoft Word文档(.doc)或Microsoft Excel电子表格(.xls)。从客户端计算机发送传真时,正文必须与安装在该计算机上的应用程序相关联,并且该应用程序必须支持PrintTo谓词;否则,传真将失败。
因此,您可以做的一个简单测试是右键单击资源管理器中的文件,然后查找"打印"命令。接下来,将文件拖动到打印机,以练习PrintTo谓词。如果这些测试失败,那么它就不起作用了,你需要安装一个知道如何打印文件的应用程序。
从服务中执行此操作会对执行打印的应用程序提出额外要求。他们中有很多人在服务中表现得不太好。尤其是当你尝试打印时,微软强烈建议你永远不要在服务中这样做。例如,Office应用程序最近没有这样做,这使得MSDN的建议已经很弱了。
在我的机器上,.tif扩展与UWP应用程序相关联,这在服务中也不起作用。考虑到有大量的应用程序处理这些流行的扩展,给出好的建议是很困难的,最好去superuser.com,说出具体的扩展、Windows版本和你喜欢使用的应用程序。从用户会话中执行此操作无疑是最不麻烦的。
我想给出一个完整的答案。之前发布的答案有一些解决方案,但它们并没有提供我们在自定义Windows服务中使用FAXCOMEXLib通过传真线成功发送pdf文件所需的全部内容。
首先,我想说,FAXCOMEXLib是为windows控制台应用程序而设计的,而不是为windows服务而设计的。您甚至可以在文档中阅读此内容。我想这就是为什么我们很难让它发挥作用的原因。
然而,经过多次尝试和错误,我们终于能够让它发挥作用。我们面临的大多数问题都与Adobe Reader中的设置和权限有关。我们发现,在处理PDf文件时,Adobe Reader试图在幕后做很多事情。它试图做的那些"事情"需要用户交互(点击警报框等)。当在Windows服务下运行时,该服务没有用户交互,这导致我们的进程无限期挂起,最终出错。但是,我们发现有一种方法可以绕过这一切。以下是我们的做法:
以下是我们正在使用的有效代码片段:
fileName = @"D:tempFaxTest.pdf";
faxDoc.Sender.Name = faxRec.From;
faxDoc.Sender.Company = faxRec.From;
faxDoc.Body = fileName;
faxDoc.Subject = faxRec.ReferenceId;
faxDoc.DocumentName = faxRec.ReferenceId;
var to = "xxxxxxxxxx";
faxDoc.Recipients.Add(to, "Some Name");
var serverName = Environment.MachineName;
var myProcesses = Process.GetProcessesByName("AcroRd32");
foreach (var myProcess in myProcesses)
{
if (DateTime.Now.Ticks - myProcess.StartTime.Ticks > TimeSpan.FromSeconds(30).Ticks) {
myProcess.Kill();
}
}
string[] returnVal = faxDoc.Submit(serverName);
当然,在我们的服务中还有更多的代码。其他代码做一些事情,比如处理回调事件处理程序来跟踪发送/完成/失败传真的状态等。但这是实际启动"发送"的代码的"核心"。
这里列出了我们对服务器所做的配置更改,以使我们的自定义Windows服务能够正确解码、渲染和发送pdf文件作为传真。其中一些列出在一些答案中,但有些没有,我希望这是一个完整的答案。
- 以管理员身份登录到服务器,并在服务器上安装传真服务器角色
- 确保传真调制解调器设备/卡正确安装在服务器上,并且传真线路处于活动状态。您可以尝试直接从Windows传真实用程序发送几份带有文本文件的测试传真。(在我们的案例中,我们遇到了问题,因为我们必须拨打"9"和一个秘密密码才能接通外线长途电话)
- 在服务器上安装Adobe Reader
- 在服务器上创建一个用户,以便Windows服务以"身份"运行。我们称我们的用户为"FaxServiceUser">
- 以FaxServiceUser身份登录服务器至少一次。登录时,将"Adobe PDF"设备设置为默认打印机
- 此外,以该用户身份登录时,请使用Adobe打开PDF文件,然后单击EULA
- 以该用户身份登录时,以及打开Adobe Reader时,请更改以下设置:
- 如果选中,请取消选中"启动阅读器时显示消息"(在"常规"下)
- 取消选中"启动时启用保护模式"复选框(这可能仅适用于Acrobat 10。在Acrobat 11中,此选项被移到"安全(增强)",标题为"启动时启用保护模式"。只需确保取消选中此选项)
- 取消选中"启用增强的安全性"(在"安全性(增强)"下-这可能仅适用于Acrobat 11及更高版本)
- 选择Updater选项并禁用Automatic Download and Install Updates
- 取消选中"从URL创建链接"(在"常规"下)
- 取消选中"Make Hand tool read articles"(在"General"下)
- 取消选中"启动阅读器时显示消息"(在"常规"下)
- 取消选中"自动计算字段值"(在"表单"下)
- 取消选中"显示焦点矩形"(在"窗体"下)
- 取消选中"显示文本字段溢出指示符"(在"表单"下)
- 取消选中"启用Acrobat JavaScript"(在"JavaScript"下)
- 取消选中"显示欢迎对话框"(在"审阅"下)
- 取消选中"打开文件时显示服务器连接警告对话框"(在"审阅"下)
- 如果需要,请参阅此链接以获得有关Adobe Reader设置的帮助:http://kb.faxback.com/How+To+Configure+Adobe+XI+for+Use+with+NET+SatisMAX
- 在构建、部署和安装Windows服务后,将服务的属性更改为"作为"您之前创建的用户运行(在我们的案例中为"FaxServiceUser")
- 将该FaxServiceUser的权限添加到它需要从/读取/写入/删除的任何文件夹中
- 由于Adobe是作为桌面应用程序运行的,请在您的服务中添加一些代码来释放Adobe Reader使用的内存(您可以在示例代码中的
myProcess.Kill()
函数中看到我们是如何做到这一点的)
这样就可以了。这有点麻烦,但我希望这能提供一个完整的例子,说明如何将Adobe Reader与您的自定义Windows服务结合起来,在Windows服务器上从pdf文件发送传真。我们已经做了几个月了,没有任何问题。我们的客户传真量很低,所以我无法说明在传真量很大的情况下是如何工作的。因此,如果你正在寻找一种"免费"发送传真的方式,而不需要支付国际文传电讯社之类的费用,这可能是一个可行的选择,至少对于低容量来说是这样。
问题似乎与名为"AcroRd32"的进程有关,该进程在Acrobat Reader中打开传真并在发送前将其转换为TIFF文件。该进程不会释放内存。
尝试按以下停止过程
Dim myProcesses() As Process Dim myProcess As Process
' How to retrieve the program associat with pdf, when i only know the file extension ?
myProcesses = Process.GetProcessesByName("AcroRd32") For Each myProcess In myProcesses
If Date.Now.Ticks - myProcess.StartTime.Ticks > TimeSpan.FromSeconds(30).Ticks Then
myProcess.Kill()
End If
Next
我希望这会有所帮助。
我也想使用faxcomexlib通过Windows服务发送传真,但经过研究,我意识到这个Windows库在服务中不可用,我使用进程监视器实现了这一点,因为我决定使用传真服务器。要创建一个.exe文件并从服务中调用它并向它发送所需的参数,然后我在通过Windows服务调用进程时遇到了会话问题,然后我解决了这个问题,现在通过Windows发送传真。该服务很容易完成。