Для IP-телефонии я пользуюсь JustVoip (один из сервисов Betamax). Этот сервис отличается низкими ценами (в 2-3 раза ниже, чем у Skype) и наличием бесплатных звонков во многие страны на стационарный телефон.
Так вот, как-то надо было мне позвонить другу в Германию. Запускаю JustVoip и звоню ему на домашний телефон – не снимает. Набираю ему на мобильный, а программа мне пишет: "Стоимость минуты 0.08€, у вас не хватает средств". Смотрю, точно на счету – 0.07€. Захожу на сайт сервиса, чтобы пополнить счет, а на сайте написано: "На счету 0.08€". А ведь это ровно стоимость минуты!
Вот наглядный пример, когда округление суммы на счете до центов реализовано разными алгоритмами. Система одна, счет один, а клиентские программы разные и в результате различный баланс :(
Итак, авторы программ задумайтесь над тем, чтобы алгоритмы обработки данных в рамках одной системы были одинаковыми!
Язык программирования самого высокого уровня содержит всего несколько команд для управления программистами
30 апреля 2010
27 апреля 2010
Delphi 2010: Ловим ошибки отсроченной загрузки DLL
Как я писал раньше, Delphi 2010 научилась вызывать функций из DLL новым способом – с помощью отсроченной загрузки DLL.
Одним из недостатков этого способа является то, что если при вызове функции произойдет ошибка, то пользователь не узнает ее причину. В случае если DLL не существует, так же как и если в DLL нет нужной функции, то сообщение в программе будет однотипным:
События, которые происходят при отложенной загрузке DLL и вызове её функций, можно перехватить и обработать самому. Установить свой обработчик на эти события позволяет функция SetDliNotifyHook. Эта функция работает с параметрами процедурного типа DelayedLoadHook описанного в юните System:
DelayedLoadHook = function (dliNotify: dliNotification; pdli: PDelayLoadInfo): Pointer; stdcall;
где:
• dliNotify – это событие которое происходит с DLL:
- dliNoteStartProcessing – намёк, что будет работа по загрузке DLL;
– dliNotePreLoadLibrary – идёт загрузка DLL;
– dliNotePreGetProcAddress – идёт попытка получения адреса вызываемой функции;
– dliNoteEndProcessing – окончание работы по загрузке функции из DLL;
– dliFailLoadLibrary – ошибка при загрузке DLL;
– dliFailGetProcAddress – ошибка при получении адреса вызываемой функции.
• pdli – указатель на структуру типа TDelayLoadInfo с полями:
– cb – размер структуры;
– pidd – данные в необработанной форме;
– ppfn – указатель на адрес функции, которая загружена;
– szDll – название DLL;
– dlp – название или номер загружаемой функции;
– hmodCur – информация о DLL (запись типа TDelayLoadProc);
– pfnCur – указатель на адрес функции, которая будет вызвана;
– dwLastError – номер полученной ошибки.
Более подробно о функции SetDliNotifyHook и связанных с ее работой типах вы можете почитать в справке Delphi 2010. А мы приступим к написанию собственного обработчика ошибок при отложенной загрузке DLL и вызове её функций.
Т.к. нас интересует только перехват и обработка ошибок, то воспользуемся урезанной версией функции SetDliNotifyHook – SetDliFailureHook, которая устанавливает обработчик событий только на события возникающие при ошибке: dliFailLoadLibrary и dliFailGetProcAddress. Чтобы не писать перехватчик в каждом новом проекте, вынесем его код в отдельную юниту.
Unit dliHandler;
Interface
Uses
SysUtils;
Type
// Ошибка при работе с отсроченной загрузкой DLL
EDliFailure = class(Exception)
ErrorCode: Integer;
constructor Create(const sMessage: String;
const iErrorCode: Integer);
end;
Implementation
constructor EDliFailure.Create(const sMessage: String; const iErrorCode: Integer);
begin
inherited Create(sMessage);
ErrorCode := iErrorCode;
end;
// Функция возвращает имя или номер импортируемой функции
function ImportName(const AProc: TDelayLoadProc): String;
begin
if AProc.fImportByName
then Result := AProc.szProcName
else Result := '#' + IntToStr(AProc.dwOrdinal);
end;
// Обработчик ошибок генерирующий "красивую" ошибку
function DelayedLoadHook(dliNotify: dliNotification; pdli: PDelayLoadInfo): Pointer; stdcall;
begin
If dliNotify = dliFailGetProcAddress
then Raise EDliFailure.Create('В ' + pdli.szDll + ' не найдена функция ' + ImportName(pdli.dlp), 2)
else Raise EDliFailure.Create('Ошибка при загрузке ' + pdli.szDll, 1); //dliFailLoadLibrary}
end;
Var
LOldFailureHook: TDelayedLoadHook;
Initialization
// Устанавливаем свой обработчик
LOldFailureHook := SetDliFailureHook(DelayedLoadHook);
Finalization
// На всякий случай вернем старый обработчик
SetDliFailureHook(LOldFailureHook);
end.
Добавляем dliHandler в любой проект и наслаждаемся автоматической обработкой ошибок при работе с отсроченной загрузкой DLL во всем проекте. Теперь вместо непонятного сообщения "External exception" пользователь увидит:
• если не удалось загрузить DLL
• если не удалось получить адрес функции
При необходимости, можно обработать ошибку и для каждого конкретного случая вызова функции (специально для этого в dliHandler я определил класс EDliFailure):
Try
...
fFee := CalcFee(1234)
...
Except
on E: EDliFailure do
Case E.ErrorCode of
1: HandleDliFailLoadLibrary;
2: HandleDliFailGetProcAddress;
End
else Raise
End;
где, HandleDliFailLoadLibrary и HandleDliFailGetProcAddress – специфические для данного конкретного случая обработчики ошибок.
Как видите, научить программу выводить понятные пользователю сообщения об ошибке легко.
Одним из недостатков этого способа является то, что если при вызове функции произойдет ошибка, то пользователь не узнает ее причину. В случае если DLL не существует, так же как и если в DLL нет нужной функции, то сообщение в программе будет однотипным:
События, которые происходят при отложенной загрузке DLL и вызове её функций, можно перехватить и обработать самому. Установить свой обработчик на эти события позволяет функция SetDliNotifyHook. Эта функция работает с параметрами процедурного типа DelayedLoadHook описанного в юните System:
DelayedLoadHook = function (dliNotify: dliNotification; pdli: PDelayLoadInfo): Pointer; stdcall;
где:
• dliNotify – это событие которое происходит с DLL:
- dliNoteStartProcessing – намёк, что будет работа по загрузке DLL;
– dliNotePreLoadLibrary – идёт загрузка DLL;
– dliNotePreGetProcAddress – идёт попытка получения адреса вызываемой функции;
– dliNoteEndProcessing – окончание работы по загрузке функции из DLL;
– dliFailLoadLibrary – ошибка при загрузке DLL;
– dliFailGetProcAddress – ошибка при получении адреса вызываемой функции.
• pdli – указатель на структуру типа TDelayLoadInfo с полями:
– cb – размер структуры;
– pidd – данные в необработанной форме;
– ppfn – указатель на адрес функции, которая загружена;
– szDll – название DLL;
– dlp – название или номер загружаемой функции;
– hmodCur – информация о DLL (запись типа TDelayLoadProc);
– pfnCur – указатель на адрес функции, которая будет вызвана;
– dwLastError – номер полученной ошибки.
Более подробно о функции SetDliNotifyHook и связанных с ее работой типах вы можете почитать в справке Delphi 2010. А мы приступим к написанию собственного обработчика ошибок при отложенной загрузке DLL и вызове её функций.
Т.к. нас интересует только перехват и обработка ошибок, то воспользуемся урезанной версией функции SetDliNotifyHook – SetDliFailureHook, которая устанавливает обработчик событий только на события возникающие при ошибке: dliFailLoadLibrary и dliFailGetProcAddress. Чтобы не писать перехватчик в каждом новом проекте, вынесем его код в отдельную юниту.
Unit dliHandler;
Interface
Uses
SysUtils;
Type
// Ошибка при работе с отсроченной загрузкой DLL
EDliFailure = class(Exception)
ErrorCode: Integer;
constructor Create(const sMessage: String;
const iErrorCode: Integer);
end;
Implementation
constructor EDliFailure.Create(const sMessage: String; const iErrorCode: Integer);
begin
inherited Create(sMessage);
ErrorCode := iErrorCode;
end;
// Функция возвращает имя или номер импортируемой функции
function ImportName(const AProc: TDelayLoadProc): String;
begin
if AProc.fImportByName
then Result := AProc.szProcName
else Result := '#' + IntToStr(AProc.dwOrdinal);
end;
// Обработчик ошибок генерирующий "красивую" ошибку
function DelayedLoadHook(dliNotify: dliNotification; pdli: PDelayLoadInfo): Pointer; stdcall;
begin
If dliNotify = dliFailGetProcAddress
then Raise EDliFailure.Create('В ' + pdli.szDll + ' не найдена функция ' + ImportName(pdli.dlp), 2)
else Raise EDliFailure.Create('Ошибка при загрузке ' + pdli.szDll, 1); //dliFailLoadLibrary}
end;
Var
LOldFailureHook: TDelayedLoadHook;
Initialization
// Устанавливаем свой обработчик
LOldFailureHook := SetDliFailureHook(DelayedLoadHook);
Finalization
// На всякий случай вернем старый обработчик
SetDliFailureHook(LOldFailureHook);
end.
Добавляем dliHandler в любой проект и наслаждаемся автоматической обработкой ошибок при работе с отсроченной загрузкой DLL во всем проекте. Теперь вместо непонятного сообщения "External exception" пользователь увидит:
• если не удалось загрузить DLL
• если не удалось получить адрес функции
При необходимости, можно обработать ошибку и для каждого конкретного случая вызова функции (специально для этого в dliHandler я определил класс EDliFailure):
Try
...
fFee := CalcFee(1234)
...
Except
on E: EDliFailure do
Case E.ErrorCode of
1: HandleDliFailLoadLibrary;
2: HandleDliFailGetProcAddress;
End
else Raise
End;
где, HandleDliFailLoadLibrary и HandleDliFailGetProcAddress – специфические для данного конкретного случая обработчики ошибок.
Как видите, научить программу выводить понятные пользователю сообщения об ошибке легко.
21 апреля 2010
Fast Reports переманивает клиентов у конкурентов
Когда-то давно, на заре человечества, единственным и неповторимым генератором отчетов для Delphi был QuickReport (про ReportSmith даже вспоминать не будем). Он много лет входил в поставку Delphi и его изначально использовали все. Поработав с QuickReport и устав регулярно вспоминать "матерей его разработчиков" программисты стали искать ему альтернативу. Кто то пытался сам улучшить QuickReport, кто то стал генерировать отчеты в MS Word/Excel (например, я), кто то, в надежде на лучшее, украл или купил другие генераторы Report Builder или Rave Reports (или даже монстра по имени Crystal Reports), а кто то стал писать свой генератор отчетов. Одним из тех, кого не устроил QuickReport и кто начал писать свой генератор, был Александр Цыганенко – автор FastReport. Думал ли Александр в далеком 1998 году, что его генератор станет лидером рынка?
За последние десять лет ситуация изменилась – генераторов отчетов, которые могут быть использованы в Delphi, написано уже много и на любой вкус. Поэтому рынок генераторов отчетов уже насытился и теперь начинается новая стадия борьбы за старых клиентов. Стадия, в которой главная роль отводится не программистам, а маркетологам. Компания Fast Reports, опередив своих конкурентов по функциональным возможностям их генераторов отчетов, решила дожать тех, кто сомневался в его покупке и начала акцию по переманиванию пользователей других коммерческих генераторов отчетов на FastReport. В обмен на лицензию конкурента они предлагают скидку в 20% на FastReport 4 VCL, FastReport VCL OLAP Pack, FastReport.NET и FastReport Studio. VCL-версию FastReport можно получить в обмен на Report Builder, Rave Reports, Crystal Reports и ActiveReports.
Обидно за QuickReport. Его, классика жанра, вообще обделили вниманием. Но, думаю – это "заслужено", ни кто на просторах бывшего СССР не покупал это убожество программисткой мысли.
За последние десять лет ситуация изменилась – генераторов отчетов, которые могут быть использованы в Delphi, написано уже много и на любой вкус. Поэтому рынок генераторов отчетов уже насытился и теперь начинается новая стадия борьбы за старых клиентов. Стадия, в которой главная роль отводится не программистам, а маркетологам. Компания Fast Reports, опередив своих конкурентов по функциональным возможностям их генераторов отчетов, решила дожать тех, кто сомневался в его покупке и начала акцию по переманиванию пользователей других коммерческих генераторов отчетов на FastReport. В обмен на лицензию конкурента они предлагают скидку в 20% на FastReport 4 VCL, FastReport VCL OLAP Pack, FastReport.NET и FastReport Studio. VCL-версию FastReport можно получить в обмен на Report Builder, Rave Reports, Crystal Reports и ActiveReports.
Обидно за QuickReport. Его, классика жанра, вообще обделили вниманием. Но, думаю – это "заслужено", ни кто на просторах бывшего СССР не покупал это убожество программисткой мысли.
14 апреля 2010
Delphi 2010: Отсроченная загрузка DLL
Долгие годы программы на Delphi умели загружать DLL двумя способами: статически и динамически. В Delphi 2010 появился третий способ – отсроченная загрузка.
Сделаем простенькую DLL, которая экспортирует некую функцию, например, CalcFee:
library TestDLL;
Function CalcFee(const iID: Integer): Currency;
begin
Result := ...;
end;
Exports
CalcFee;
end.
и рассмотрим все три способа.
1. Статическая загрузка.
Это самый простой способ вызвать функцию из DLL. Для его реализации необходимо всего лишь описать внешнюю функцию:
Function CalcFee (const iID: Integer): Currency; external 'TestDLL.dll';
И после этого её можно вызывать:
fFee := CalcFee(1234)
Наша DLL загружается при запуске программы и остается загруженной до завершения ее работы.
За этой простотой скрывается большая проблема – если DLL удалить или испортить, то программа просто не запустится.
2. Динамическая загрузка.
Этот способ – более продвинутый, но требует написания значительно большего количества кода:
Var
CalcFee: function(const iID: Integer): Currency;
hDLL: THandle;
begin
hDLL := LoadLibrary('TestDLL.dll');
If hDLL <> 0
then try
@CalcFee := GetProcAddress(hDLL, 'CalcFee');
If @CalcFee = nil
then ShowMessage('В TestDLL.dll не найдена функция CalcFee')
else fFee := CalcFee(1234);
finally
FreeLibrary(hDLL);
end
else ShowMessage('Ошибка при загрузке TestDLL.dll')
В этом коде используются функции Win32 API из Windows.pas:
- LoadLibrary – загружаем DLL;
- GetProcAddress – получаем адрес функции по её имени;
- FreeLibrary – выгружаем DLL из памяти.
Динамическая загрузка позволяет загружать DLL только при необходимости и выгружать её, если она больше не нужна. Второе преимущество и более важное – это возможность обработать ошибки при загрузке DLL и вызове функции. Поэтому даже без DLL или с испорченной DLL программа будет работать. Если перед загрузкой DLL ее удалить, то получим нормальное сообщение:
3. Отсроченная загрузка
В Delphi 2010 появился третий способ вызова функций из DLL – отсроченная загрузка. Как и динамическая загрузка, она позволяет загружать DLL только при необходимости (например, для экономии ресурсов), но также как при статической загрузке, функцию достаточно лишь описать, добавив директиву delayed:
Function CalcFee(const iID: Integer): Currency; external 'TestDLL.dll' delayed;
Недостатки этого способа – это то, что DLL уже нельзя выгрузить и то, что если при вызове функции произойдет ошибка, то пользователь не узнает ее причину. В справке написано "Trying to call a delayed routine that cannot be resolved results in a run-time error (or an exception, if the SysUtils unit is loaded)". Если DLL удалить или если в DLL нет нужной функции, сообщение будет однотипным:
Если функция будет использована в консольной программе, то сообщение об ошибке будет тоже не информативным:
"Runtime error 255 at 7C812AFB "
Но спасение есть. При желании ошибки, возникающие во время загрузки DLL или вызове её функций можно перехватить и обработать с помощью процедур SetDliNotifyHook и SetDliFailureHook из юниты System.
Не знаю, как вам, но мне идея отсроченной загрузки DLL понравилась, и я буду её в будущем использовать.
Сделаем простенькую DLL, которая экспортирует некую функцию, например, CalcFee:
library TestDLL;
Function CalcFee(const iID: Integer): Currency;
begin
Result := ...;
end;
Exports
CalcFee;
end.
и рассмотрим все три способа.
1. Статическая загрузка.
Это самый простой способ вызвать функцию из DLL. Для его реализации необходимо всего лишь описать внешнюю функцию:
Function CalcFee (const iID: Integer): Currency; external 'TestDLL.dll';
И после этого её можно вызывать:
fFee := CalcFee(1234)
Наша DLL загружается при запуске программы и остается загруженной до завершения ее работы.
За этой простотой скрывается большая проблема – если DLL удалить или испортить, то программа просто не запустится.
2. Динамическая загрузка.
Этот способ – более продвинутый, но требует написания значительно большего количества кода:
Var
CalcFee: function(const iID: Integer): Currency;
hDLL: THandle;
begin
hDLL := LoadLibrary('TestDLL.dll');
If hDLL <> 0
then try
@CalcFee := GetProcAddress(hDLL, 'CalcFee');
If @CalcFee = nil
then ShowMessage('В TestDLL.dll не найдена функция CalcFee')
else fFee := CalcFee(1234);
finally
FreeLibrary(hDLL);
end
else ShowMessage('Ошибка при загрузке TestDLL.dll')
В этом коде используются функции Win32 API из Windows.pas:
- LoadLibrary – загружаем DLL;
- GetProcAddress – получаем адрес функции по её имени;
- FreeLibrary – выгружаем DLL из памяти.
Динамическая загрузка позволяет загружать DLL только при необходимости и выгружать её, если она больше не нужна. Второе преимущество и более важное – это возможность обработать ошибки при загрузке DLL и вызове функции. Поэтому даже без DLL или с испорченной DLL программа будет работать. Если перед загрузкой DLL ее удалить, то получим нормальное сообщение:
3. Отсроченная загрузка
В Delphi 2010 появился третий способ вызова функций из DLL – отсроченная загрузка. Как и динамическая загрузка, она позволяет загружать DLL только при необходимости (например, для экономии ресурсов), но также как при статической загрузке, функцию достаточно лишь описать, добавив директиву delayed:
Function CalcFee(const iID: Integer): Currency; external 'TestDLL.dll' delayed;
Недостатки этого способа – это то, что DLL уже нельзя выгрузить и то, что если при вызове функции произойдет ошибка, то пользователь не узнает ее причину. В справке написано "Trying to call a delayed routine that cannot be resolved results in a run-time error (or an exception, if the SysUtils unit is loaded)". Если DLL удалить или если в DLL нет нужной функции, сообщение будет однотипным:
Если функция будет использована в консольной программе, то сообщение об ошибке будет тоже не информативным:
"Runtime error 255 at 7C812AFB "
Но спасение есть. При желании ошибки, возникающие во время загрузки DLL или вызове её функций можно перехватить и обработать с помощью процедур SetDliNotifyHook и SetDliFailureHook из юниты System.
Не знаю, как вам, но мне идея отсроченной загрузки DLL понравилась, и я буду её в будущем использовать.
08 апреля 2010
TIOBE: Delphi удерживает позиции
Вчера компания TIOBE Software опубликовала апрельский индекс популярности языков программирования - TIOBE Programming Community Index. Согласно ему, язык программирования Delphi уверенно удерживает занятое в феврале 2010-го года 9-е место. По сравнению с апрелем прошлого года он поднялся с 11-го на 9-е место. При этом, начиная с 2001-го года, пики популярности Delphi были в 2004-м году: 12-е место в январе и 7-е в августе.
По сравнению с апрелем прошлого года рейтинг языка Pascal, опустился с 15-го на 16-е место. При этом в сентябре 2009-го он входил в дюжину лидеров и занимал 12-е место. Жалко прародителя :(
"TIOBE Programming Community Index" обновляется один раз в месяц и основан на количестве квалифицированных инженеров, курсов и разработчиков дополнительного программного обеспечения. Для сбора этой информации используются поисковые машины (Google, MSN, Yahoo!, Wikipedia и YouTube). Для языка Delphi отслеживаются: Delphi, Kylix, Object Pascal, Free Pascal, Chrome (исключая "Google Chrome"), Oxygene, Delphi.NET и Delphi Prism.
По сравнению с апрелем прошлого года рейтинг языка Pascal, опустился с 15-го на 16-е место. При этом в сентябре 2009-го он входил в дюжину лидеров и занимал 12-е место. Жалко прародителя :(
"TIOBE Programming Community Index" обновляется один раз в месяц и основан на количестве квалифицированных инженеров, курсов и разработчиков дополнительного программного обеспечения. Для сбора этой информации используются поисковые машины (Google, MSN, Yahoo!, Wikipedia и YouTube). Для языка Delphi отслеживаются: Delphi, Kylix, Object Pascal, Free Pascal, Chrome (исключая "Google Chrome"), Oxygene, Delphi.NET и Delphi Prism.
01 апреля 2010
Embarcadero Technologies покупает бренд "Borland"
По сообщению BusinessWeek компания Embarcadero Technologies, крупнейший производитель и поставщик платформенно-независимых инструментов для разработки, управления и оптимизации приложений и баз данных, подписала соглашение с Micro Focus International plc о приобретении эксклюзивного права на использование торговой марки "Borland" в названии продуктов линейки "Rapid Application, Web and Java™ Development Tools".
"Мы возрождаем славное имя Borland! Когда-то "Borland" входил в тройку самых известных в мире брендов. В какой-то степени, использование "Borland" в названии наших продуктов – это возвращение к нашим корням. Borland – это бренд, в будущее которого верят многие ИТ-профессионалы!" – сказал вице-президент по связям с разработчиками и главный евангелист Embarcadero Technologies Дэвид Интерсаймон ("David I").
С первого апреля 2010 года, слово "Borland" будет использоваться в названии всех новых версий инструментальных средств для разработки приложений компании Embarcadero Technologies: Borland® RAD Studio, Borland® Delphi, Borland® C++Builder, Borland® Delphi Prism, Borland® JBuilder, Borland® Delphi for PHP.
"Мы возрождаем славное имя Borland! Когда-то "Borland" входил в тройку самых известных в мире брендов. В какой-то степени, использование "Borland" в названии наших продуктов – это возвращение к нашим корням. Borland – это бренд, в будущее которого верят многие ИТ-профессионалы!" – сказал вице-президент по связям с разработчиками и главный евангелист Embarcadero Technologies Дэвид Интерсаймон ("David I").
С первого апреля 2010 года, слово "Borland" будет использоваться в названии всех новых версий инструментальных средств для разработки приложений компании Embarcadero Technologies: Borland® RAD Studio, Borland® Delphi, Borland® C++Builder, Borland® Delphi Prism, Borland® JBuilder, Borland® Delphi for PHP.
Подписаться на:
Сообщения (Atom)