Показаны сообщения с ярлыком Delphi. Показать все сообщения
Показаны сообщения с ярлыком Delphi. Показать все сообщения

пятница, 7 ноября 2014 г.

Delphi FireDAC Array DML (BULK INSERT) MySQL, PostgreSQL и возможно другие

На заметку: при использовании запроса INSERT INTO с массивом параметров нужно обязательно ставить пробел перед VALUES иначе запрос будет выполняться для каждой записи массива отдельно.
Пример
INSERT INTO TABLE1(FIELD1, FIELD2)[Пробел тут]VALUES(:p1, :p2)
Проблема в разборе запроса и определении места ключевого слова VALUES.

пятница, 30 мая 2014 г.

Delphi быстро читаем stdin

Для консольных приложений бывает необходимо быстро считать входные данные.
Сразу к коду:
const
  rbsize = 65355;
var
  d: longint;
  rb: array [0 .. 85 * rbsize] of char;
procedure ReadInput;
var
  PInput: ^TTextRec;
  c: byte;
begin
  d := 0;
  PInput := @Input;
  PInput^.BufSize := 0;
  while PInput^.BufEnd = PInput^.BufSize do
  begin
    SetTextBuf(Input, rb[d], rbsize);
    Read(c);
    Inc(d, PInput^.BufEnd);
    PInput^.BufPos := PInput^.BufEnd;
  end;
end;

После выполнения процедуры ReadInput массив rb[0..d] будет содержать данные из файловой переменной Input(stdin). Размер массива rb статичен и может быть изменен в зависимости от задачи.

вторник, 27 августа 2013 г.

Определяем, что запущенный процесс написан на Delphi

Если программа написана на Delphi и использует модуль Controls, то при её запуске будет создан глобальный атом вида
'Delphi[восьмизначный идентификатор процесса (PID)]'.
Таким образом чтобы проверить написан ли запущенный процесс с использованием Delphi (модуля Controls) достаточно проверить наличие атома с соответствующим идентификатором процесса:
  ShowMessage(
    BoolToStr(
      GlobalFindAtom(
        PChar(Format('Delphi%.8X', [StrToInt(Edit1.Text)]))
      ) <> 0
    , True)
    );

Естественно можно написать программу и без использования Controls. В таком случае можно проверить поле TimeDateStamp PE заголовка программы - для программ написанных на Delphi он равен $2A425E19 (19.06.1992 22:22:17)

суббота, 19 января 2013 г.

Delphi Региональные настройки и TFormatSettings

Часто региональные настройки систем пользователей отличаются, при том что все они в одном языковом регионе. При этом в Delphi по-умолчанию используются настройки системы при загрузке региональных параметров.
Чтобы принудительно загружать из системы настройки нужного языка необходимо до инициализации модуля SysUtils вызвать SetThreadLocale($0419); (для русской языка)
Для этого можно создать модуль, например так:
unit Locale;
interface
implementation
uses
  Windows;
initialization
  SetThreadLocale($0419);
end.
И включить его в файл проекта первым модулем (Для продвинутых кодеров до первого обращения к SysUtils).
Проверить результат можно так:
Caption := FormatDateTime(LongDateFormat + ' ' + LongTimeFormat, Now);

P.S.: Пока писал эту заметку заметил баг в SysUtils.TFormatSettings.TranslateDateFormat.FixDateSeparator (код от XE2) =)
в этой процедуре происходит подмена разделителя дат на слэш '/'
в моем случае разделитель дат точка '.', длинный формат даты 'd MMMM yyyy ''г.'''
в итоге получаю '19 Январь 2013 г/' - забавно
Скорее всего функция должна игнорировать текст в кавычках.
Баг уже зарегистрирован в

Delphi Оптимальная локализация приложений

При разработке на Delphi часто приходится писать программы для использования в одном языковом регионе, т.е. для пользователей которым нужен только один язык в программе.
Есть разные методы локализации, в том числе подмена указателей в PResStringRec. Этот способ плох лишним использованием памяти и дополнительными действиями в runtime - фактически нелокализованные строки остаются в модуле и никогда не используются.
Оптимальным же способом локализации является подмена модулей с переводом содержащихся в них строк. Например, можно взять стандартный модуль RTLConsts.pas скопировать его в папку проекта и перевести содержимое. В таком случае перевод будет скомпилирован и прилинкован к модулю.

Подмену указателей можно использовать для временной подмены строк. Например, для отображения диалога с нестандартым текстом кнопок. Для этого надо переделать процедуру HookResourceString в функцию:
function HookResourceString(ResStringRec: PResStringRec;
  NewStr: PChar): PChar;
var
  OldProtect: DWORD;
begin
  VirtualProtect(ResStringRec, SizeOf(ResStringRec^),
    PAGE_EXECUTE_READWRITE, @OldProtect);
  Result := PChar(ResStringRec^.Identifier);
  ResStringRec^.Identifier := Integer(NewStr);
  VirtualProtect(ResStringRec, SizeOf(ResStringRec^),
    OldProtect, @OldProtect);
end;
Сам код временной подмены:
const
  sAccept: PChar = '&Accept';
  sDecline: PChar = '&Decline';
var
  SaveYes: PChar;
  SaveNo: PChar;
begin
  SaveYes := HookResourceString(@SMsgDlgYes, sAccept);
  SaveNo := HookResourceString(@SMsgDlgNo, sDecline);
  MessageDlg('Do you accept terms?', mtConfirmation, mbYesNo, 0);
  HookResourceString(@SMsgDlgYes, SaveYes);
  HookResourceString(@SMsgDlgNo, SaveNo);
  MessageDlg('Do you accept terms?', mtConfirmation, mbYesNo, 0);
end;

Delphi HInstance

Глобальная переменная SysInit.HInstance инициализируется для exe модуля в SysInit._InitExe вызовом HInstance := GetModuleHandle(nil)
Фактически значение данной переменной - это указатель на адрес в памяти по которому загружен PE модуль.
Используя этот адрес можно, например, получить дату сборки проекта, получив прямой доступ к PE заголовку файла в памяти:
function GetLinkDate: TDateTime;
begin
  Result := FileDateToDateTime
    (PInteger(
      PImageNtHeaders(
        Cardinal(PImageDosHeader(HInstance)._lfanew) +  HInstance)^
    .OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE]
    .VirtualAddress + HInstance + 4
    )^);
end;

вторник, 17 января 2012 г.

Оптимальное копирование из Recordset в TStrings

При работе с ADO компонентами часто возникает необходимость копирования данных из Recordset в структуры, которые в дальнейшем используются в программе. Такими структурами могут быть объекты определенного класса, массивы записей, всякого рода списки и т.п.
О том как скопировать данные с наименьшими затратами я опишу далее.

четверг, 18 августа 2011 г.

TcxGridDBChartView и автоматический расчет осей (Delphi)

Для справки
В devExpress компоненте TcxGrid при построении графиков с использованием TcxGridDBChartView есть 3 варианта расчета минимального и максимального значения осей:
  • mmvZeroBasedAuto (по-умолчанию) - максимальное значение берется из данных, минимальное = 0 или при наличии отрицательных значений минимум из данных
  • mmvAuto - максимальное и минимальное значение берется из данных
  • mmvCustom - максимальное и минимальное значение берется из соответствующих свойств оси
Значение присваивается свойству MinMaxValues осей (например, DiagramLine.AxisValue.MinMaxValues)

среда, 17 августа 2011 г.

FreeAndNil, Assigned and Destructor (Delphi)

FreeAndNil и зачем он нужен
Каждый объект в Delphi имеет свой жизненный цикл.
Обычно он сводится к:
  • созданию объекта
  • манипуляциям с объектом
  • удалению объекта
При этом, объявляя переменную объекта класса мы объявляем указатель на объект данного класса
Например выражение MyList: TList; объявляет указатель с именем MyList - это все равно что мы бы написали MyList: Pointer;, с тем лишь отличием, что в первом случае указатель будет типизированным.

четверг, 30 июня 2011 г.

Работа с TList (Delphi)

Класс TList - один из наиболее часто используемых классов в Delphi.
Данный класс реализует методы работы с массивом указателей:
  • Добавление и удаление элементов списка
  • Манипуляции над элементами списка (перестановка, сдвиг, сортировка) 
  • Поиск по списку 
Как оптимальнее использовать данный класс в работе рассмотрим подробнее...