【问题标题】:How can I use the WinFax Pro COM objects from a .NET app?如何使用 .NET 应用程序中的 WinFax Pro COM 对象?
【发布时间】:2011-06-15 06:46:12
【问题描述】:

我知道,WinFax Pro 是 1998 年的。

(注意:这不是 WinFax.dll,它显然是 Windows 的一部分。这是 WinFax Pro,一个单独的商业附加应用程序,最初来自 Delrina,后来被赛门铁克收购)。

我在仍然使用 WinFax Pro 作为操作系统的办公室工作。他们将客户传真号码存储在 WinFax Pro“电话簿”中,并使用它来通知客户服务访问。它现在的工作方式是,某人查看从 Mac 日历生成的(打印的)时间表,然后单击 WinFax 电话簿中的所有适当条目,以发送通知传真。

这就像我们过去所说的“转椅”集成,但它指的是 2 个屏幕。这甚至不是 2 个屏幕——它是一张纸和一个屏幕。

无论如何,我正在尝试使其自动化并且遇到了麻烦。

好消息:
- WinFax Pro 将其功能公开为 COM 对象: WinFax.SDKSend 用于传真发送引擎; WinFax.SDKPhoneBook 为通讯录等。
- WinFax Pro 提供了一个类型库 wfxctl32.tlb,它描述了这些不同的 COM 对象。 - 我能够通过从 tlbimport 生成的包装器成功使用 .NET (C#) 中的 WinFax.SDKSend 对象。 (我使用的是 .NET 3.5,不能使用 .NET 4.0)。

坏消息:
除了 WinFax.SDKSend,我无法调用 WinFax COM 对象上的任何方法。签名看起来并不比 WinFax.SDKSend 中的签名复杂,但我不断收到异常。

C# 代码:

public void Run()
{
    var pb = new wfxctl32.CSDKPhoneBook();
    string id = pb.GetFolderListFirst(1, "");
}

例外:

异常:System.InvalidCastException:无法转换 COM 对象 将“wfxctl32.CSDKPhoneBookClass”键入接口类型 'wfxctl32.ISDKPhoneBook'。此操作失败,因为 对具有 IID 的接口的 COM 组件上的 QueryInterface 调用 '{A67FCC81-9949-11D0-961E-444553540000}' 由于以下原因而失败 错误:不支持此类接口(HRESULT 异常:0x80004002 (E_NOINTERFACE))。

在 System.RuntimeType.InvokeDispMethod(String name, BindingFlags invokeAttr, Object target, Object[] args, Boolean[] byrefModifiers, Int32culture, String[] namedParameters)
在 System.RuntimeType.InvokeMember(字符串名称、BindingFlags bindingFlags、Binder binder、Object 目标、Object[] providedArgs、ParameterModifier[] 修饰符、CultureInfo 文化、String[] namedParams)
在 System.RuntimeType.ForwardCallToInvokeMember(String memberName, BindingFlags flags, Object target, Int32[] aWrapperTypes, MessageData& msgData)
在 wfxctl32.CSDKPhoneBookClass.GetFolderListFirst(Int16 standardFolder, String folderID)

【问题讨论】:

    标签: c# .net com interop winfax


    【解决方案1】:

    我打开了the OleView tool,它是 Windows SDK 的一部分,我可以看到 WinFax.SDKPhoneBook 的 COM 接口在对象上不存在。嗯,这是一个惊喜。接口由类型库描述,tlbimport.exe 为其生成一个包装器。该接口也记录在 WinFax Pro SDK PDF 文档中。但是我找不到任何人成功使用 WinFax.SDKPhoneBook 的早期绑定接口的示例。

    当我尝试使用 javascript 调用 COM 对象时,它工作得很好。

    function say(x){ WScript.Echo(x); }
    
    var Folder = function(id) {
        this.Id = id;
        this.DisplayName = null;
        this.Parent = null;
    };
    
    Folder.prototype.GetFolderName = function() {
        if (this.DisplayName === null) {
            this.DisplayName = comObject.GetFolderDisplayName(this.Id);
        }
        return (this.Parent === null) ? this.DisplayName
            : this.Parent.GetFolderName() + "/" + this.DisplayName;
    };
    
    var comObject = new ActiveXObject("WinFax.SDKPhoneBook");
    
    var GetPbFoldersForId = function(firstId) {
        // stage 1 - do searches for folders
        var list = [];
        var id = firstId;
        do {
            list.push(new Folder(id));
            id = comObject.GetFolderListNext();
        } while (id != "");
    
        // stage 2 - get subfolders, if any, for each folder
        var subs =[];
        for (var i=0; i<list.length; i++) {
            id = comObject.GetFolderListFirst(0,list[i].Id);
            if (id != "") {
                var a = GetPbFoldersForId(id);  // recurse
                for (var j=0; j < a.length; j++) {
                    if (a[j].Parent === null) {a[j].Parent = list[i];}
                    subs.push(a[j]);
                }
            }
        }
    
        for (var k=0; k<subs.length; k++) {
            list.push(subs[k]);
        }
    
        return list; // a list of folders
    };
    
    var id = comObject.GetFolderListFirst(1, "");
    Folders = GetPbFoldersForId(id);
    
    for (var k=0; k<Folders.length; k++) {
        say(Folders[k].GetFolderName());
    }
    

    这使我得出结论,WinFax Pro COM 接口不是双接口 - 它们只是 IDispatch(后期绑定),并且可以从 VB6、VBScript、Javascript、Perl、Python 和其他后期绑定语言自然访问,但不是直接来自 C# 或 VB.NET 等 .NET 语言。


    Does C# .NET support IDispatch late binding? 告诉我如何从 C# 连接 IDispatch 接口。使用它,我可以做这样的事情:

    public sealed class PhoneBook // a singleton
    {
        Object comObject;
        Type type;
    
        private readonly static PhoneBook _instance = new PhoneBook();
        public static PhoneBook Instance  { get { return _instance; } }
    
        private PhoneBook()
        {
            var t = Type.GetTypeFromProgID("WinFax.SDKPhoneBook");
            if (t == null)
                throw new ArgumentException("WinFax Pro is not installed.");
            comObject = Activator.CreateInstance(t);
            type = comObject.GetType();
        }
    
        public string GetUserGroupFirst(int flavor, string id)
        {
            var parameters = new Object[2];
            parameters[0] = flavor;
            parameters[1] = id;
            string s = type.InvokeMember("GetUserGroupFirst",
                                         BindingFlags.InvokeMethod,
                                         null,
                                         comObject,
                                         parameters) as String;
            return s;
        }
    ....
    

    PhoneBook 类是 IDispatch 接口的包装器。我为 typelib 中的每个方法和属性编写了一个包装方法。我认为这有点像 .NET 4.0 会自动为我做的事情。无论如何,这对我来说效果很好。

    我在此处发布此 Q&A 只是为了让其他使用 WinFax Pro 的人可以了解这些信息。我搜索了所有的中间管,找不到任何好的信息,所以我把它放在那里。


    编辑 - 此 .NET 代码现在在 ASPNET MVC 应用程序中运行,允许用户从网页或 REST 客户端查找条目和发送传真。

    【讨论】:

    • 你现在可能已经厌倦了它,但这不可能是真正的原因。 Tlbimp 在类型库中找到双接口没有问题,服务器实际上没有实现它是闻所未闻的。这种事故最常见的原因是版本控制问题,类型库与安装的版本不匹配。很常见,更新需要新的 guid。
    • @Hans - 你可能是对的;我不是 COM 专家。但是,当我在有问题的 ProgId (WinFax.SDKPhoneBook) 上使用 OleView 时,我看到了 IDispatch、IUnknown、ITypeInfo 和其他一些(刚刚不在机器上),但没有看到 WinFax Pro 定义的应用程序接口。这让我感到困惑,因为我认为如果 .tlb 有它,那么 COM 对象会将它公开为早期绑定接口。我查看了版本和 GUID——这似乎不是问题。看起来赛门铁克从未实现过早期绑定接口。你认为这是不可能的吗? (严肃的Q)
    • 哦,赛门铁克。我突然就没那么感兴趣了。你有事情要做,应该为你工作。祝你好运。
    【解决方案2】:

    我认为这是最坏情况的解决方案,但您始终可以为 C++(甚至可能是 VB6)中的 Winfax COM 对象编写自己的包装器,并让该代码完成实际工作,然后从您的.Net 代码。这样您就不必太担心如何将 COM 接口类型转换为 .Net 兼容类型等,因此它可能会更容易一些。

    【讨论】:

      【解决方案3】:

      我无法帮助您解决您的特定问题,但请注意,COM 互操作仅适用于具有相同“位数”的 com dll,并且 .NET 将默认生成一个应用程序,该应用程序是运行它的计算机的本机应用程序(即它将在 64 位计算机上生成 64 位应用程序)。

      几乎所有的 COM dll 都是 32 位的,尤其是商业的,所以您必须通过将项目设置中的 CPU 类型从“任何”设置为“32 位”来强制应用始终构建 32 位。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-10-10
        • 1970-01-01
        • 2012-02-11
        • 2011-10-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多