Как я могу использовать COM-объекты WinFax Pro из приложения .NET? - PullRequest
3 голосов
/ 25 января 2011

Я знаю, WinFax Pro - это 1998 год.

(примечание: это не WinFax.dll, которая, по-видимому, является частью Windows. Это WinFax Pro, отдельное коммерческое приложение-надстройка, первоначально созданное Delrina, а позднее приобретенное Symantec).

Я работаю в офисе, который все еще использует WinFax Pro в качестве операционной системы. У них есть номера факсов клиентов, хранящиеся в «Телефонной книге» WinFax Pro, и они используются для уведомления клиентов о посещениях службы. Теперь он работает так: кто-то смотрит на (распечатанное) расписание, сгенерированное из Календаря Mac, затем нажимает на все соответствующие записи в телефонной книге WinFax, чтобы отправить уведомление по факсу.

Это похоже на то, что мы привыкли называть интеграцией "вращающееся кресло", но это относится к двум экранам. Это даже не 2 экрана - это один лист бумаги и один экран.

Во всяком случае, я пытаюсь автоматизировать это и возникают проблемы.

Хорошие новости:
- WinFax Pro предоставляет свои функции в виде объектов COM: WinFax.SDKSend для механизма отправки факсов; WinFax.SDKPhoneBook для адресной книги и т. Д.
- WinFax Pro поставляет библиотеку типов, wfxctl32.tlb, которая описывает эти различные COM-объекты. - Я могу успешно использовать объект WinFax.SDKSend из .NET (C #) через обертки, сгенерированные из tlbimport. (Я использую .NET 3.5, не могу сделать .NET 4.0).

Плохие новости:
Я не смог вызвать ни один из методов в WinFax COM-объектах, кроме WinFax.SDKSend. Подписи выглядят не сложнее, чем в WinFax.SDKSend, но я продолжаю получать исключения.

Код C #:

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

Исключение:

Исключение: System.InvalidCastException: невозможно преобразовать COM-объект введите 'wfxctl32.CSDKPhoneBookClass' для типа интерфейса 'Wfxctl32.ISDKPhoneBook. Эта операция не удалась, потому что QueryInterface вызов COM-компонента для интерфейса с IID Ошибка «{A67FCC81-9949-11D0-961E-444553540000}» по следующей причине ошибка: такой интерфейс не поддерживается (Исключение из HRESULT: 0x80004002 (E_NOINTERFACE)).

at System.RuntimeType.InvokeDispMethod (имя строки, BindingFlags invokeAttr, цель объекта, аргументы объекта [], логическое значение [] byrefModifiers, культура Int32, строка [] namedParameters)
at System.RuntimeType.InvokeMember (Имя строки, BindingFlags bindingFlags, Связыватель связывания, Объектная цель, Объект [] provideArgs, Модификаторы ParameterModifier [], КультураInfo Culture, String [] namedParams)
в System.RuntimeType.ForwardCallToInvokeMember (String memberName, флаги BindingFlags, объектная цель, Int32 [] aWrapperTypes, MessageData & msgData)
at wfxctl32.CSDKPhoneBookClass.GetFolderListFirst (стандартная папка Int16, папка StringID)

Ответы [ 3 ]

1 голос
/ 25 января 2011

Я открыл инструмент OleView , часть Windows SDK, и я вижу, что COM-интерфейс для WinFax.SDKPhoneBook отсутствует на объекте.Хм, это сюрприз.Интерфейс описывается библиотекой типов, и tlbimport.exe создает для нее оболочку.Также интерфейс документирован в PDF-документе WinFax Pro SDK.Но я не смог найти ни одного примера того, кто бы успешно использовал интерфейс с ранней привязкой для 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 идругие языки с поздним связыванием, но не напрямую из языков .NET, таких как C # или VB.NET.


Поддерживает ли C # .NET позднюю привязку IDispatch? рассказывает, как подключиться к интерфейсам IDispatch из C #.Используя это, я могу сделать что-то вроде этого:

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 сделает для меня автоматически.В любом случае, это хорошо сработало для меня.

Я публикую здесь эти вопросы и ответы только для того, чтобы другие люди, имеющие дело с WinFax Pro, могли иметь информацию.Я искал по всем трубкам и не смог найти никакой хорошей информации, поэтому выкладываю это туда.


EDIT - этот код .NET теперь выполняется в приложении ASPNET MVC, позволяя пользователям искать записи и отправлять факсы с веб-страницы или клиента REST.

0 голосов
/ 25 января 2011

Я не могу помочь вам с вашей конкретной проблемой, но учтите, что COM-взаимодействие работает только с компьютерами с той же «битностью», и .NET по умолчанию будет генерировать приложение, которое является родным для компьютера, на котором он работает т.е. он будет генерировать 64-битное приложение на 64-битном компьютере).

Почти все COM-библиотеки являются 32-битными, особенно коммерческими, поэтому вам придется принудительно заставлять приложение всегда создавать 32-битные, установив тип процессора в настройках проекта с «Любой» на «32-битный». *

0 голосов
/ 25 января 2011

Я бы посчитал это решением для наихудшего случая, но вы всегда можете написать свою собственную оболочку для COM-объектов Winfax в C ++ (или, возможно, даже VB6), и этот код будет выполнять реальную работу, а затем вызывать эти оболочки из.Net код.Таким образом, вам не нужно слишком беспокоиться о том, как выяснить, как преобразовать типы COM-интерфейсов в .Net-совместимые типы и т. Д., Так что это может немного облегчить задачу.

...