Встретилась в блоге Ника Ходжеса интересная новость - разработчик http://www.ksdev.com/ вместе со своими наработками (VGScene, DXScene, or ImageFX) переходит в Embarcadero.
Похоже, после стольких лет, у Delphi наконец появится какой-то вариант векторного UI фреймворка.
Краткие заметки по ит-шным темам, с которыми я сталкиваюсь. Чаще это вопросы работы с СУБД и прикладной разработки.
Показаны сообщения с ярлыком delphi. Показать все сообщения
Показаны сообщения с ярлыком delphi. Показать все сообщения
воскресенье, 13 февраля 2011 г.
пятница, 21 января 2011 г.
Как правильно заблокировать окно от перерисовки
Иногда это может понадобиться, если что-то активно добавляется, открывается и т.п.
Типичный способ, рекомендуемый первым, это вызов LockWindowUpdate. Что есть в корне неверно - в Майкрософт не очень удобно выбрали название функции.
http://www.transl-gunsmoker.ru/2010/12/lockwindowupdate_29.html
http://msdn.microsoft.com/en-us/library/dd145034%28v=vs.85%29.aspx
Правильный пример:
Хитрость в том, что работает только RedrawWindow, а Invalidate нет.
UPD
На практике оказало не все так весело - окно просто прячется, а не перестает отрисовываться. У нас решилось точечным применением, только к изменяемым элементам - панелям, таб сетам и т.п.
Типичный способ, рекомендуемый первым, это вызов LockWindowUpdate. Что есть в корне неверно - в Майкрософт не очень удобно выбрали название функции.
http://www.transl-gunsmoker.ru/2010/12/lockwindowupdate_29.html
http://msdn.microsoft.com/en-us/library/dd145034%28v=vs.85%29.aspx
Правильный пример:
procedure SetWindowLock(AHandle: THandle); begin SendMessage(AHandle, WM_SETREDRAW, 0, 0); end; procedure EndWindowLock(AHandle: THandle); begin SendMessage(AHandle, WM_SETREDRAW, 1, 0); RedrawWindow(AHandle, nil, 0, RDW_ERASE or RDW_FRAME or RDW_INVALIDATE or RDW_ALLCHILDREN); end;
Хитрость в том, что работает только RedrawWindow, а Invalidate нет.
UPD
На практике оказало не все так весело - окно просто прячется, а не перестает отрисовываться. У нас решилось точечным применением, только к изменяемым элементам - панелям, таб сетам и т.п.
понедельник, 29 марта 2010 г.
Вывод лога DUnit в файл
Иногда нет возможности запускать тесты из консольного приложения, что делает невозможным логгирование вывода стандартными средствами. Что бы, к примеру, запущенная после коммита процедура сборки/тестирования, в случае ошибки, бросила в почту разработчикам лог с непрошедшими тестами.
Для решения на скорую руку был набросан простенький класс (чуть более чем полностью слизанный с TextTestRunner), позволяющий логгировать все в файл - FileTestRunner
Проверен на D2009.
Для решения на скорую руку был набросан простенький класс (чуть более чем полностью слизанный с TextTestRunner), позволяющий логгировать все в файл - FileTestRunner
Проверен на D2009.
среда, 24 марта 2010 г.
Упрощение CheckException в DUnit с помощью анонимных функций
К сожалению, для проверки функции на возврат исключения возможен только для процедуры типа:
TTestMethod = procedure of object;Легким движением руки(наследником или правкой оригинального класса) для свежих версий Delphi упрощаем написание таких тестов:
procedure CheckException(AMethod: TTestMethod; AExceptionClass: TClass; msg :string = '');
TTestProc2 = reference to procedure;
TTestCase2 = class(TTestCase)
public
procedure CheckException2(AMethod: TTestProc2; AExceptionClass: TClass; msg :string = '');
end;
Пример использования:
...
CheckException2(procedure begin DirDelete(TestDir); end, EInOutError);
суббота, 13 февраля 2010 г.
Desktop-интерфес на html?
На днях, долго выбираемй мной домашний антивирус avast!, заполучил довольно симпатичный новый внешний вид(откровенно говоря старый был жутковат). Проходясь по UI в поисках возможности временного отключения резидентной защиты(кстати эта возможность появилась - правда не так удобно как в Касперском) я набрел на форму "О программе", где вычитал, что построен новый интерфейс с использованием библиотеки HTMLayout.
Вспоминая мучения во время разработки пользовательского интерфейса на Delphi - интересная это в общем штука, позволяет привнести в мир desktop разработки все прелести html/css:
Использует ее уже достаточно много крупных компаний, так что для приложений, требующих развитого UI, можно пробовать. Пока хорошей/популярной обертки для Delphi нет, но начало уже положено.
Подробнее, в интервью с разработчиком, можно почитать здесь
Вспоминая мучения во время разработки пользовательского интерфейса на Delphi - интересная это в общем штука, позволяет привнести в мир desktop разработки все прелести html/css:
HTMLayout – это, грубо говоря, веб-браузер, который Windows-программист может встроить в свою программу и, таким образом, построить интерфейс программы на базе DHTML
Использует ее уже достаточно много крупных компаний, так что для приложений, требующих развитого UI, можно пробовать. Пока хорошей/популярной обертки для Delphi нет, но начало уже положено.
Подробнее, в интервью с разработчиком, можно почитать здесь
пятница, 25 сентября 2009 г.
Динамически загружаемые bpl , их выгрузка и интерфейсы
Очевидная, но съевшая кучу времени ошибка.
Если в проекте используются динамически загружаемые/выгружаемые bpl, следует помнить, что при выгрузке информации о классах, реализованных в этих bpl в памяти не остается.
Предположим есть некий список, в котором регистрируются _интерфейсы_, имплиментирующие классы которых реализованы в динамически загружаемых bpl(к примеру в плагинах). Сам список живет в базовом приложении, которое и загружает эти пакеты.
Если оставить разрушение этих объектов на совести основного кода, что при использовании интерфейсов довольно очевидно, но делать это _после_ выгрузки bpl с кодом класса реализующего интерфейс, например в секции finalization, - будем получать маловразумительные AV.
Если в проекте используются динамически загружаемые/выгружаемые bpl, следует помнить, что при выгрузке информации о классах, реализованных в этих bpl в памяти не остается.
Предположим есть некий список, в котором регистрируются _интерфейсы_, имплиментирующие классы которых реализованы в динамически загружаемых bpl(к примеру в плагинах). Сам список живет в базовом приложении, которое и загружает эти пакеты.
Если оставить разрушение этих объектов на совести основного кода, что при использовании интерфейсов довольно очевидно, но делать это _после_ выгрузки bpl с кодом класса реализующего интерфейс, например в секции finalization, - будем получать маловразумительные AV.
Интерфейсы должны быть интерфейсами!
Встретился интересный баг связанные с тем, что смешивается интерфейс и обычный объект. Вернее интерфейс кастрируется до некого альтернативного указателя на экземпляр объекта, без использования замечательного механизма подсчета ссылок.
Есть объект, унаследованный от TComponent и поддерживающий какой-то интерфейс. Временем жизни этого объекта управляет некая фабрика, честно убивающая его при закрытии приложения вручную, как обычный объект - т.е. посредством вызова Free.
А в совершенно другой части приложения есть ссылка на этот объект, но в виде глобальной переменной модуля. Некрасиво, но пока приложение живет проблем нет.
А при завершении работы - фабрика все честно чистит и умирает сама, выполняется весь пользовательский код. И начинают финализироваться модули, обнуляя интерфейсы и соотв. дергая TComponent._Release у давно умершего объекта...
Обнаружить сию неприятность удалось только благодаря FastMM, который заполняет память под разрушенными объектами по специфическому шаблону:
Есть объект, унаследованный от TComponent и поддерживающий какой-то интерфейс. Временем жизни этого объекта управляет некая фабрика, честно убивающая его при закрытии приложения вручную, как обычный объект - т.е. посредством вызова Free.
А в совершенно другой части приложения есть ссылка на этот объект, но в виде глобальной переменной модуля. Некрасиво, но пока приложение живет проблем нет.
А при завершении работы - фабрика все честно чистит и умирает сама, выполняется весь пользовательский код. И начинают финализироваться модули, обнуляя интерфейсы и соотв. дергая TComponent._Release у давно умершего объекта...
Обнаружить сию неприятность удалось только благодаря FastMM, который заполняет память под разрушенными объектами по специфическому шаблону:
Q: My program used to work fine, but if I enable "FullDebugMode" and run it I get an access violation at address $8080xxxx. Why?
A: You are attempting to access properties of a freed object. When you free a block in "FullDebugMode", FastMM fills the freed memory area with a pattern of $80 bytes. If there were any pointers, long strings or object references inside the freed object they will now point to $80808080 which is in a reserved address space.
четверг, 19 марта 2009 г.
Указатель на метод интерфейса
Понадобилось на днях коллегам передать в качестве callback-функции метод объекта, доступ к которому есть только через интерфейс. Показалось, что проблемы особой нет - интерфейс "знает" о своем объекте, осталось вычислить адрес объекта да самого метода.
Но реальность оказалась не столь оптимистичной - на текущий момент Delphi такого функционала не поддерживает:
Но реальность оказалась не столь оптимистичной - на текущий момент Delphi такого функционала не поддерживает:
- http://groups.google.com.ua/group/borland.public.delphi.objectpascal/browse_thread/thread/4c5dcb094b82522f?pli=1
- http://qc.embarcadero.com/wc/qcmain.aspx?d=941 (а судя по датам и не будет поддерживать)
- метод в интерфейсе напрямую возвращающий адрес метода объекта
IAnIntf = interface
function GetPointerToProc: TAnObjectProc:
end
- объект-обертку над интерфейсом
TWrapObj = class
private
AnIntf: ITheIntf;
protected
procedure AnProc(const Value: string);
end;
procedure TWrapObj.AnProc(const Value: string);
begin
AnIntf.AnProc(Value);
end;
возможно как-то можно будет выкрутиться через анонимные функции?нельзя, ибо
TAnProc = procedure (S: string) of object;
это разные типы
TAnProc2 = reference to procedure (S: string);
> Still I think making (procedure of object) and (procedure of Interface) equivalent
> typeswould be the better solution.
Like I said, the semantics for the compiler would be quite different, so
it would make sense to make them different types (even if both
represented internally by a TMethod). Actually, if the interface
instance variable is nil, it is impossible to get the method address.
This is not a problem for objects, since there the static address is
taken.
пятница, 9 января 2009 г.
Borland, умолчания и поддержка старого
Компания меняет не только названия, но и простым разработчикам не дает скучать.
Вводная - при неизменных внешних условиях перестала выполняться сборка релиза из командной строки при переходе с 2007 на 2009 - упорно попадал туда код дебага. В то время как из среды - все ок.
Проведенное в два этапа(первый был еще на 2007 и текущей проблемы не касался см.) расследование показало, что:
- в импортируемом проектами файле CodeGear.Delphi.Targets дефолтный таргет изменен с Build на Make. А последний при смене конфигурации Debug|Release не пересобирает dcu
- группы проектов, в отличии от проектов, не обновляются до соотв. версии и импортируют $(MSBuildBinPath)\Borland.Group.Targets, который существует только при инсталяции 2007(или когда там msbuild прикрутили?)
- таргет Build для группы проектов не задает таргет для конечных проектов(т.е. используется умолчательный, который теперь Make, да)
Выходом может быть использование таргета BuildAll для группы проектов.
Вводная - при неизменных внешних условиях перестала выполняться сборка релиза из командной строки при переходе с 2007 на 2009 - упорно попадал туда код дебага. В то время как из среды - все ок.
Проведенное в два этапа(первый был еще на 2007 и текущей проблемы не касался см.) расследование показало, что:
- в импортируемом проектами файле CodeGear.Delphi.Targets дефолтный таргет изменен с Build на Make. А последний при смене конфигурации Debug|Release не пересобирает dcu
- группы проектов, в отличии от проектов, не обновляются до соотв. версии и импортируют $(MSBuildBinPath)\Borland.Group.Targets, который существует только при инсталяции 2007(или когда там msbuild прикрутили?)
- таргет Build для группы проектов не задает таргет для конечных проектов(т.е. используется умолчательный, который теперь Make, да)
Выходом может быть использование таргета BuildAll для группы проектов.
Delphi 2009 и приведение к PAnsiString
Часть winapi функций требуют передачи себе в кач-ве параметров структур с PAnsiChar строками (например mapi). В предыдущих версиях приведение строк посредством PChar(SomeString) работало, используя область памяти выделенную под SomeString, а в 2009 результат PAnsiString(AnsiString(SomeString)), уже как вычисление обычной строки из юникодной, размещается в локальной области памяти, что чревато тем, что старый код может перестать работать на, казалось бы, ровном месте (хотя конечно прямое приведение к pchar тоже имеет кучу особенностей).
Например код приведенный ниже возвращает разные результаты на 2007 и 2009 Делфи
Например код приведенный ниже возвращает разные результаты на 2007 и 2009 Делфи
program array_error_test;
{$APPTYPE CONSOLE}
uses
SysUtils,
StrUtils,
Classes;
procedure DoMain;
const
Count = 5;
type
RecType = record
AnString: PAnsiChar;
end;
var
RecArr: array of RecType;
I: Integer;
SomeStrings: TStringList;
begin
SetLength(RecArr, Count);
SomeStrings := TStringList.Create;
try
for I := 0 to Length(RecArr) - 1 do
begin
SomeStrings.Add(DupeString(IntToStr(I), 10));
RecArr[I].AnString := PAnsiChar(AnsiString(SomeStrings[I]));
end;
for I := 0 to Length(RecArr) - 1 do
WriteLn(RecArr[I].AnString);
finally
SomeStrings.Free;
end;
end;
begin
DoMain;
ReadLn;
end.
четверг, 8 января 2009 г.
Delphi 2009 и InternetQueryOption
Переносится в одном из проектов код на 2009 Делфи и соотвественно кушаются все прелести первопроходчества.
Для получения адреса прокси сервера пользовалась функция InternetQueryOption. После сборки в 2009 стала она возвращать мусор. Ничего криминального замечено не было, замена на InternetQueryOptionW не помогала.
Решение нашлось в
http://akirabbq.spaces.live.com/blog/cns!CEB8A04DC43BCEE9!264.entry
кто виноват не совсем понятно, но неприятно :(
По сути - в структуре INTERNET_PROXY_INFO lpszProxy должно быть не LPCTSTR(которое в 2009 уже PWideChar), а просто LPCSTR, хотя в исходных сишных заголовках она объявлена как LPCTSTR.
Решить проблему можно создав необходимую структуру у себя.
Для получения адреса прокси сервера пользовалась функция InternetQueryOption. После сборки в 2009 стала она возвращать мусор. Ничего криминального замечено не было, замена на InternetQueryOptionW не помогала.
Решение нашлось в
http://akirabbq.spaces.live.com/blog/cns!CEB8A04DC43BCEE9!264.entry
кто виноват не совсем понятно, но неприятно :(
По сути - в структуре INTERNET_PROXY_INFO lpszProxy должно быть не LPCTSTR(которое в 2009 уже PWideChar), а просто LPCSTR, хотя в исходных сишных заголовках она объявлена как LPCTSTR.
Решить проблему можно создав необходимую структуру у себя.
четверг, 4 сентября 2008 г.
Microsoft runtime и Firebird Embeded 2.1.1
Для возможности x64 билдов разработчики Firebird перешли на vc8, что потянуло за собой, в принципе уже привычную, проблему распространения vc runtime.
Но учитывая теперешний зоопарк ОС, технологий совместимости 32/64, попыток решения dll хелл, и вообще постижения Дао от МС, деплоймент этого runtime становится очень непростым.
Он, рантайм 8-ой версии, не идет, пока, в поставки никакх ОС - и Висте его тоже нет(по меньшей мере до SP).
Первое - для правильной установки, как это рекомендует МС, нужны права Администратора. А для установки на win2k до SP1 - обновление инсталятора МС до 3.1
Для интеграции этого redist себе в инсталятор - нужно делать msi инсталяторы, создание которых в корректном виде не самое простое занятие, для котрого хороших
свободных инструментов вроде как и нет, и опять таки необходимы права администратора.
В принципе на первый вгляд проблем быть не должно - что стоит поставить этот рантайм,
когда разворачивается сервер СУБД. Но тем, кто пытается распространять shareware системы, особенно с FB embeded, приходится хуже - необходимо тянуть этот рантайм со своим приложением.
Есть три пути его поставки:
Ссылки:
Но учитывая теперешний зоопарк ОС, технологий совместимости 32/64, попыток решения dll хелл, и вообще постижения Дао от МС, деплоймент этого runtime становится очень непростым.
Он, рантайм 8-ой версии, не идет, пока, в поставки никакх ОС - и Висте его тоже нет(по меньшей мере до SP).
Первое - для правильной установки, как это рекомендует МС, нужны права Администратора. А для установки на win2k до SP1 - обновление инсталятора МС до 3.1
Для интеграции этого redist себе в инсталятор - нужно делать msi инсталяторы, создание которых в корректном виде не самое простое занятие, для котрого хороших
свободных инструментов вроде как и нет, и опять таки необходимы права администратора.
В принципе на первый вгляд проблем быть не должно - что стоит поставить этот рантайм,
когда разворачивается сервер СУБД. Но тем, кто пытается распространять shareware системы, особенно с FB embeded, приходится хуже - необходимо тянуть этот рантайм со своим приложением.
Есть три пути его поставки:
- Официальный.
Устанавливаем инсталятором от MS и все работает. Не подходит, если нет гарантии наличия админских прав у пользователей, наличия Windows Installer 3.0 or later, portable решения. - Экстенсивный.
Поставляем со своим приложением просто необходимые бинарники рантайма. Так делает, впрочем, большинство софта - стоит только поискать msvcr80.dll по жесткому диску :)). Но, поставлять нужно ТРИ копии рантайма, одну для работы самого fbembed, вторую в каталоге intl для fbintl и третью в для подключаемых функций в каталоге udf. - Хитро-экстенсивный.
Пользуясь текстовой природой манифестов, в каталогах intl и udf оставить только манифест, с измененными путями к файлам вида:
<file name="..\msvcr80.dll">
<file name="..\msvcp80.dll">
ВАЖНО, в таком случае указать в манифесте своего приложения зависимость от Microsoft.VC80.CRT.
такой манифест представляет собой текстовый файл <FullAppName>.manifest с содержимым:<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.VC80.CRT" version="8.0.50608.0" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
</dependentAssembly>
</dependency>
</assembly>
Этот манифест можно включить в ресурсы самого приложения, см. например
Ссылки:
- Microsoft Visual C++ 2005 Redistributable Package (x86)
http://www.microsoft.com/downloads/details.aspx?familyid=32BC1BEE-A3F9-4C13-9C99-220B62A191EE&displaylang=en - http://www.ibase.ru/fb21instfaq.htm
- http://delphi.about.com/library/bluc/text/uc111601a.htm
вторник, 2 сентября 2008 г.
Не используйте сlass helper's?
Не сказать, что я их когда-то использовал, но вот встретился материал:
http://www.deltics.co.nz/blog/?p=282
Суть в том, что если в проекте объявлено два хелпера к одному классу, то использоваться будет ТОЛЬКО один, но какой именно - не известно(зависит от порядка юнитов и т.п.).
Так что можно поиметь плавающих ошибок на ровном месте...
http://www.deltics.co.nz/blog/?p=282
Суть в том, что если в проекте объявлено два хелпера к одному классу, то использоваться будет ТОЛЬКО один, но какой именно - не известно(зависит от порядка юнитов и т.п.).
Так что можно поиметь плавающих ошибок на ровном месте...
Подписаться на:
Сообщения (Atom)