Вызвать VB6 DLL из многопоточного приложения-службы Windows c #?

Я запускаю многопоточную службу Windows, которая должна вызывать dll VB6. Нет документации об этой DLL VB6, и эта устаревшая система поддерживает очень важный бизнес-процесс.

В первый раз (1-й поток) эта dll работает хорошо. Поскольку другим потокам нужен доступ, он начинает давать неправильные результаты.

Я читал, как один парень говорит:

"Только будьте осторожны, если вы используете VB6. Если вы используете многопоточную службу, ваша потоковая модель должна измениться на поддержку квартир. VB поддерживает только несколько однопоточных квартир, но .NET работает полностью бесплатно с потоками, как правило. . Поток, который вызывает VB6 DLL, должен быть совместим с DLL ".

Другой парень из команды подал мне идею разместить этот ddl в отдельном домене приложения. Но я не уверен.

Как мы можем работать с dll VB6, вызываемым из многопоточного приложения службы Windows c #?


person Eduardo Xavier    schedule 03.07.2009    source источник
comment
Чтобы дать вам окончательный ответ, нам нужна дополнительная информация: работает ли он под COM + или нет, в первом случае выполняется внутри или вне процесса? Как установить его в систему: через regsvr32 или другим способом?   -  person Giulio Vian    schedule 06.07.2009
comment
Спасибо ребятам, я выяснил, в чем проблема. Эта dll не должна была работать ни с чем, кроме VB 6. В ней есть ошибка. Он не поддерживает региональные настройки английского языка на сервере, нам пришлось перейти на португальский язык; язык клиента. Пока я использую шаблон singleton и шаблон прокси для работы с этим устаревшим компонентом, и теперь он работает нормально.   -  person Eduardo Xavier    schedule 07.07.2009


Ответы (4)


Когда потоки входят, вы сохраняете объекты и повторно используете их позже в новых потоках? Если можете, создавайте новые объекты для каждого потока. У нас есть такая ситуация с dll уровня данных, который мы используем. Если вы создаете соединение в одном потоке, его нельзя будет использовать в другом. Если вы создаете новое соединение в каждом потоке, все работает нормально.

Если создавать объекты медленно, посмотрите на класс ThreadPool и атрибут ThreadStatic. Пулы потоков повторно используют один и тот же набор потоков для выполнения работы, а ThreadStatic позволяет создавать объект, существующий только для одного потока. например

[ThreadStatic]
public static LegacyComObject myObject;

По мере поступления запроса превратите его в задание и поставьте его в очередь в пуле потоков. При запуске задания проверьте, инициализирован ли статический объект;

void DoWork()
{ 
    if (myObject == null)
    { 
        // slow intialisation process
        myObject = New ...
    }

    // now do the work against myObject
    myObject.DoGreatStuff();
}
person Steve Cooper    schedule 03.07.2009

Ты говоришь

Я запускаю многопоточную службу Windows, которая должна вызывать dll VB6. Нет документации об этой DLL VB6, и эта устаревшая система поддерживает очень важный бизнес-процесс.

и в то же время вы говорите

В первый раз (поток 1º) эта dll работает хорошо. Поскольку другим потокам нужен доступ, он начинает давать неправильные результаты.

Я был бы очень уверен, что руководство знает о сбое, которое вы наблюдаете, потому что код, поддерживающий критически важный бизнес-процесс, старый и недокументированный и используется таким образом, который никогда не был предназначен для использования, и никогда не тестировался. использоваться. Бьюсь об заклад, он также никогда не тестировался для использования из .NET, не так ли?

Вот мое предложение, и оно похоже на то, что я реализовал на самом деле:

Ожидается, что VB6 DLL будет вызываться в одном потоке. Не разочаровывайте! Когда ваша служба запускается, пусть она запускает поток соответствующего типа (я не могу сказать, так как я намеренно забыл все эти STA / MTA прочее). Поставьте в очередь запросы к этому потоку для доступа к VB6 DLL. Попросите весь такой доступ проходить через единственный поток.

Таким образом, что касается VB6 DLL, она работает точно так же, как и была протестирована.


Кстати, это немного отличается от того, что я реализовал. У меня была веб-служба, а не служба Windows. У меня была C DLL, а не VB6, и это не был COM. Я просто реорганизовал весь доступ к этому объекту в один класс, а затем поместил операторы блокировки вокруг каждого из общедоступных методов.

person John Saunders    schedule 04.07.2009
comment
Я не мог больше согласиться с Джоном. Поскольку VB6 DLL фактически является для вас черным ящиком, используйте то, что гарантированно будет правдой. В лучшем случае DLL будет поддерживать потоковую модель однопоточного апартамента (STA). См. Эту ссылку в MSDN для соображений при вызове COM-объекта STA: msdn.microsoft.com/en-us/library/ms680112 (VS.85) .aspx. Чтобы получить максимальную отдачу от вложенных средств, вы можете просто использовать адаптер или синглтон для регулирования доступа к объектам по одному потоку за раз (как предложил Джон). Обязательно следите за своим COM-взаимодействием и маршалингом из .NET. - person Sean P. McDonough; 07.07.2009

Эта статья о многопоточности библиотек DLL Visual Basic 6 предоставляет некоторое понимание. Он говорит:

Чтобы сделать проект ActiveX DLL многопоточным, выберите нужные параметры многопоточности на вкладке «Общие» диалогового окна «Свойства проекта».

В этой статье говорится, что существует три возможных модели выберите из:

One thread of execution 
Thread pool with round-robin thread assignment 
Every externally created object is on its own thread 

Я предполагаю, что значение по умолчанию - one thread of execution, и что нужно выбрать один из двух других вариантов.

person Robert Harvey    schedule 03.07.2009

Возможно, вы захотите взглянуть на это: linky

И вот фрагмент, который привлек мое внимание:

COM-объекты VB6 являются объектами STA, что означает, что они должны выполняться в потоке STA. Вы создали два экземпляра объекта из двух потоков MTA, но сам объект будет работать в одном (созданном COM (OLE)) потоке STA, а доступ из двух потоков MTA будет маршалирован и синхронизирован. Итак, что вам следует сделать, это инициализировать потоки как STA, чтобы каждый объект работал в своем собственном потоке STA без маршалинга, и все будет в порядке.

В любом случае, COM-объекты в стиле VB всегда являются STA. Теперь, чтобы предотвратить маршалинг квартир и переключение потоков, вам нужно создать экземпляры в квартирах, инициализированных STA. Также обратите внимание, что когда вы устанавливаете атрибут [MTAThread] в Main, вы эффективно инициализируете основной поток как MTA, когда вы создаете экземпляры объектов STA из потоков MTA, COM создаст отдельный (неуправляемый) поток и инициализирует его как STA (это называется STA по умолчанию), все вызовы объектов STA из потоков MTA будут маршалироваться (и включать переключатели потоков), в некоторых случаях вызовы Idispatch завершатся ошибкой из-за сбоев маршалинга IP. Поэтому советуем использовать объекты STA (и, следовательно, VB6) только из совместимых квартир.

person Community    schedule 03.07.2009