Вроде экземпляр объекта TRegExp создается, но при попытке с ним поработать вылазит ошибка:
Не был произведен вызов CoInitialize.
Если честно, столкнулась с этим впервые, пошла в интернет искать. Пришлось подключать ActiveX и использовать CoInitialize/CoUninitialize.
Нашла статью про подобную проблему. Попробовала так:
var
...
RE : TRegExp;
NeedToUninitialize : Boolean;
begin
NeedToUninitialize := Succeeded(CoInitialize(nil));
try
RE := TRegExp.Create(nil);
RE.IgnoreCase := true;
RE.Multiline := true;
RE.Global := true;
...
finally
RE.Free;
if NeedToUninitialize then CoUninitialize;
end;
...
end;
Но и тут не заладилось: если CoUninitialize писать без try...except, то на нем вываливается. И что-то мне эта ситуация совсем не понравилась, как-то мутно: коинициализируется — а потом что? Не будет ли проблем, если работать с библиотекой в несколько потоков и т.д.? Даже если CoInitialize/CoUninitialize делать не в функции, а при регистрации либы.
Кто-нибудь из читателей блога сталкивался с чем-нибудь подобным? Как решали?
___
Чтобы быть в курсе обновлений блога, можно подписаться на RSS.
Привет Мария. С такой проблемой не сталкивался и у меня тут соответственно вопрос: почему вас (тебя и ещё одного штаЦкого) тянет прямо на эту майкрософтскую библиотеку? Чем она завоевала ваши сердца?
ОтветитьУдалитьCoInitialize/CoUninitialize - это, вообще-то, основы COM, а не какие-то там "грабли". Delphi часто вызывает его за вас (при подключении нужного модуля), но только не в дополнительных потоках.
ОтветитьУдалить> на нем вываливается
Как вываливается? Дело в том, что вызывать вы его должны, когда закончили работу с COM. Если CoInitialize выше был первым вызовом в потоке, да плюс в коде между try и finally у вас появляется временная переменная-интерфейс (которая освобождается в end), то неудивительно, что вы получаете ошибку.
Обычно имеет смысл делать так (окей, лучше бы, конечно, использовать CoInitializeEx):
CoInitialize;
try
DoSomething;
finally
CoUnInitialize;
end;
Где вся работа происходит в процедуре DoSomething - таким макаром все временные интерфейсы гарантировано уплывут.
> Не будет ли проблем, если работать с библиотекой в несколько потоков и т.д.? Даже если CoInitialize/CoUninitialize делать не в функции, а при регистрации либы.
Если вы - это сервисный код, который ещё кто-то вызывает, то вызывать CoInitialize должен он, а не вы. Обычно это работает хорошо. TRegExp, к примеру, не делает этот вызов, оставляя его вызывающему, т.е. вам.
Добрый день.
ОтветитьУдалитьGunSmoker все правильно написал, но если лень сидеть разбираться с тем как все это работает. То вот мой вариант решения данной проблемы. Даже два.
1. В заголовке проекта, который описывает dll добавляем в uses oleauto. Собственно это позволяет частично забыть о том кто и когда должен вызывать и отключать COM. Есть правда и минус - мы не можем контролировать этот процесс и порой натыкаемся на странные ошибки, особенно если вызов dll может происходить несколько раз за работу программы (в случае динамического подключения через LoadLibrary), тогда приходится изголяться и придумывать механизмы защиты. С другой стороны, если dll грузится при старте программы и выгржается в конце, то все в порядке, имхо. Чтобы все работало надо, что вот эти модули:
OleAuto
OleCtl
Ole2
были доступны при компиляции либо в доступных путях, либо в папке с программой. А и да Delphi будет ругаться на этот uses, говоря, что он деприкейтед. :)
2. Путь более простой, в каком-то смысле, но более тяжелый по ресурсам - в заголовке dll указать в uses Forms, что так же произведет инициализацию COM, но тогда dll надо "вводить" в Application основной программы, и затем выводить. Однако опять же если dll грузится статично, то это становится. Проще.
Егор, даже не знаю, что ответить: использую и использую, как-то не задумывалась... А что для таких целей лучше подойдет?
ОтветитьУдалитьGunSmoker, спасибо за развернутый ответ! Буду разбираться, я действительно в этом ни бум-бум, еще не приходилось сталкиваться, я больше по базам данных... :)
Leechdraw, спасибо!
Не удержался :).
ОтветитьУдалитьЯ тоже задавался тем же вопросом, что и "Егор О.". И сам порядочно намучился с регулярками, перебрал массу вариантов.
Вообщем я остановился на PerlRegEx: http://www.regular-expressions.info/delphi.html
Из минусов, требуется DLL которая идет в комплекте.
Из плюсов: полная поддержка синтаксиса регулярок Perl (по крайней мере я лагов не замечал, а у других библиотек нарывался).
А вот если "честно" поставить RegexBuddy так и проблема с написанием/отладкой вообще пропадает, он может даже генерировать куски кода под Делфи.
Вообщем рекомендую посмотреть ;).
З.Ы. Кстати, есть баг с поддержкой юникодовской кирилицы, но это в принципе у Перловых регулярок. От этого никуда не денешся
Mifody, спасибо за наводку, обязательно надо будет попробовать.
ОтветитьУдалитьЕще лучше - использовать обертку над PCRE из JCL. Там и dll подключать никакие не надо.
ОтветитьУдалитьА с COM - библиотеками есть маленькая деталь: CoUninitialize в конце можно не делать, система разрулит. А если делать, то бывают вылеты, никак не связанные с собственным кодом - у меня такие сюрпризы выдавал MSXML.
>>Из минусов, требуется DLL которая идет в комплекте.
ОтветитьУдалитьНo это - совсем масенький минус. Там можно и объектники подключить. Можно менять директивы условной компиляции в начале pcre.pas - тогда dll можно не включать в проект. По дефолту уже настроенно на компилятор версии >=21.0 (d2010)
Еще не увидел упоминания TRegExpr от Андрея Сорокина.
ОтветитьУдалитьВот возможная причина ваших сбоев. Но рецепт не поможет, если вы вызываете CoUninitialize до того, как освобождены все COM-объекты в текущем потоке. Вопрос правда, зачем вообще вызывать эту функцию? Если она у вас вызывается при завершении программы/потока (а случаев, когда это надо в других местах можно по пальцам одной руки пересчитать), то почему бы не отдать процесс на откуп Windows и просто не вызывать CoUninitialize?
ОтветитьУдалитьpda, за ссылку спасибо :) Правда, этот вопрос для меня уже давным-давно не актуален, но, может, кому-нибудь пригодится информация.
ОтветитьУдалитьПривет.
ОтветитьУдалитьв самой dll.regexp надо дописать
"что отметил в кавычках"
procedure TRegExp.Connect;
var
punk: IUnknown;
begin
"CoInitialize(nil);"
if FIntf = nil then
begin
punk := GetServer;
Fintf:= punk as IRegExp2;
"CoUninitialize();"
end;
end;
Спасибо. Удачи.