суббота, 31 января 2009 г.

UAC для разработчика

UAC (User account control) впервые появился в Windows Vista, и сразу же, не заслуженно, получил отрицательную репутацию, а в Интернете появилось полным полно статей как его отключить. Доходит даже до откровенного маразма, что эту функцию ставят как основной недостаток этой операционной системы. Не буду здесь подробно на нем останавливаться, скажу лишь, что у меня он включен по умолчанию, и я нахожу его очень даже полезным для себя, тем более что в Windows 7 он был значительно переработан, хотя на вкус и цвет – все фломастеры разные.

Хотим мы этого или нет UAC есть в операционной системе, и будет дальше, а разработчик программного обеспечения должен учитывать все возможные конфигурации системы, в том числе и с включенным UAC.

Несмотря на то, что UAC обладает некоторой "интеллектуальностью" и при запуске может определить нужно ли приложению увеличение привилегий или нет – возможности его ограничены, и он не всегда корректно работает, что приводит к тихому (или не всегда к тихому) «помиранию» запущенной программы, которой необходимы права администратора, но которые ей никто не дал. Поэтому перед разработчиком стоит задача явно указать необходимый уровень привилегий для своего приложения. Делается это через все тот же файл-манифест приложения, который появился в Windows XP и который используется для отрисовки интерфейса "в стиле XP".

Для явного указания необходимого уровня привилегий используется раздел Security:

<security>
<requestedprivileges>
<requestedexecutionlevel level="requireAdministrator">
</requestedprivileges>
</security>

Полностью файл-манифест приложения может выглядеть, например следующим образом:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity version="1.0.0.0" processorArchitecture="*"
name="UAC_Elevation_Prompt" type="win32" />
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="requireAdministrator" />
</requestedPrivileges>
</security>
</trustInfo>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32"
name="Microsoft.Windows.Common-Controls" version="6.0.0.0"
publicKeyToken="6595b64144ccf1df" language="*" processorArchitecture="*" />
</dependentAssembly>
</dependency>
</assembly>

Данный манифест необходимо включить в ресурсы приложения, процедура достаточно простая и аналогичная той, которую я описывал для работы с курсорами тут и тут.

После включения манифеста и сборки проекта при запуске приложения появится окно UAС, запрашивающее необходимые привилегии – теперь приложение уже не помрет молча.

Но не все так просто в Delphi 2009. По каким-то своим, никому не известным причинам, разработчики решили добавлять манифест во все проекты по умолчанию. С одной стороны – довольно удобно, но с другой получается наоборот больше работы. Вот, например, так же по умолчанию в ресурсы добавляется иконка приложения и информация о версии. Это не плохо – потому, что существуют инструменты для их быстрого и безболезненного изменения. А манифест – не очень хорошо, мягко говоря, потому как он жестко задан в файле WindowsXP.res в наиболее общей форме и не учитывает специфики конкретного приложения, и нет инструментов для его изменения.

Так вот, при попытке добавления описанного выше манифеста в проект Delphi 2009 получаем предупреждение компилятора о дублировании ресурсов и наш манифест не включается в приложение. Можно перейти в исходный код проекта и убрать директиву компилятора {$R *.res}, но в этом случае мы лишимся иконки приложения и информации о версии. Можно убрать файл WindowsXP.res куда подальше, чтобы Delphi его не нашла – но это тоже неудачный способ выхода из положения – поскольку нарушается работа VCL.

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

Оригинальный способ для решения проблем использован в файловом менеджере Total Commander – для выполнения операций требующих повышения привилегий используется отдельное приложение TCADMIN.EXE, которому передается команда в случае невозможности выполнения операции с правами текущего пользователя.

Интересно, а как еще можно организовать повышение привилегий в Runtime и решить проблемы с манифестом в Delphi 2009?

суббота, 24 января 2009 г.

Установка FIBPlus на Delphi 2009 Trial

Установка обновленных компонентов FIBPlus, о релизе которых я писал ранее, не обошлась без пляски с бубном.

Началось все с того, что инсталлятор не смог корректно установить компоненты на пробную версию Delphi 2009. В результате я получил оошибку:

!!! Unsucessfuly compile package FibPlus2009.dpk!!!


Открыв лог-файл, созданный в результате установки, я обнаружил истинную причину:

Generate DCC32 config file: C:\Program Files\Devrace\FIBPlus_Unicode\7.0.1076\sources\dcc32.cfg
Initial directory = C:\Program Files\Devrace\FIBPlus_Unicode\7.0.1076\sources\
Command Line = "C:\Program Files\CodeGear\RAD Studio\6.0\bin\dcc32.exe" FibPlus2009.dpk

Command line tools are not supported in the trial version.

Замечательно! Ну ладно, всегда можно скомпилировать и установить пакеты через IDE Delphi. Но эта попытка тоже не увенчалась успехом. Компилятор отказался найти файлы библиотеки FIBPlus, не смотря на то что при установке было указано добавить все пути в нужное место. Даже после того как я прописал все необходимые пути (Tools->Options->Library Win32), один из пакетов (FIBDBMidas2009.dpk) все равно наотрез отказался компилироваться. Но зато другие компоненты и мастеры установились и наконец-то заработали.


Интересный момент: готовилась к выходу именно новая версия компонентов FIBPlus с индексом 7.0, но что-то изменило планы разработчиков. :) В пользу этой версии говорит инсталлятор и файл readme.txt с описанием нововведений:

7.1076
1. Уникодные поля теперь могут маппироваться не на TFIBWideStringField а на
TFIBStringField
2 Добавлено свойство TFIBXSQLVAR.AsAnsiString: AnsiString ;

7.1019
1. В скриптере ошибка при обработке содержимого блоб-полей
2. Ошибка при работе строковых полей не являющихся FIBStringField
3. Подключен быстрый Locate
4. Восстановлена работоспособность IB_Services
5. Восстановлена работоспособность SQLEditor
6. Добавлен обработчик pFIBDataSet.OnLockSQLText. Позволяет заменить генерацию лок-сиквела своей.

и версия в Object Inspector :)


Ну как же так! Проверять программы надо перед релизом! ;-)

пятница, 23 января 2009 г.

Вышло обновление FIBPlus для Delphi/C++ Builder 2009

Без преувеличения можно сказать, что событие, которого ждали многие Delphi-программисты (и я в том числе) наконец-то свершилось! Не прошло и пол года (или прошло? :)) как вышла обновленная версия библиотеки компонентов для доступа к Firebird и Interbase – FIBPlus. Номер версии компонентов остался прежним – 6.9.5 поскольку единственное нововведение – это поддержка Delphi 2009, и эта версия не может быть установлена на более ранние версии Delphi. По сути – это те же самые компоненты только для Delphi 2009.

Теперь многие проекты, основанные на этой библиотеке, могут быть переведены на Delphi 2009, что не может не радовать. А то я уже стал задумываться об использовании стандартных IBX и хорошо, что до этого не дошло. :)

Единственное, что омрачает это приятное известие – это то, что разработчики тянули-тянули с выходом библиотеки, и у многих уже закончилась годовая подписка на обновления. У меня она закончилась буквально меньше месяца назад, что вдвойне обидно.

А еще иногда проскакивает мысль, что задержка с выходом компонентов делалась намеренно, но оставим это на совести разработчиков, а догадки – при себе.

вторник, 20 января 2009 г.

Delphi Prism - первое знакомство

Пару дней назад кое-как руки дошли и до нового продукта - Delphi Prism. (Что-то отставать я стал от технологий :)). Буду наверстывать.

Первое что бросается в глаза - разработчики обленились не стали возиться с собственной IDE и воспользовались бесплатным готовым решением компании Microsoft - оболочкой Microsoft Visual Studio.

Собственно, как и обещали разработчики - Delphi Prism совершает скачок из феодализма в коммунизм из .NET 1.1 в .NET 3.5. И первым подключенным по умолчанию модулем является System.Linq. На эту возможность я и решил сегодня посмотреть в первую очередь.

Для первого теста я выбрал LINQ to XML - решил посмотреть как будет выглядеть работа с XML файлами здесь. Файл и задачу выбрал такую же что и в моем предыдущем посте про работу с XML в Delphi. И по аналогии с C# быстро набросал код программы.

Первое, что бросилось в глаза - синтаксис LINQ немного отличается, так например меня ввело в ступор сообщение об ошибке на операторе orderby, оказывается тут он пишется как order by. Так же по привычке объявил переменные перед блоком begin ... end; что тут являлось ошибкой. :)

В конце-концов у меня получился следующий код:


namespace ConsoleApplication1;

interface

uses
System.Linq,
System.Xml,
System.Xml.Linq;

type
ConsoleApp = class
public
class method Main;
end;

implementation

class method ConsoleApp.Main;
begin
var ComputersFile: System.Xml.Linq.XElement;
ComputersFile := XElement.Load('test.xml');
var Elements := from el in ComputersFile.Descendants()
where el.Name = 'DisplayName'
order by el.Value
select el;

for e in Elements do
Console.WriteLine(e.value);

Console.Read;
end;

end.

Такую же программу я написал и на C# и решил их сравнить. Первое - размеры файлов были разные. Файл написанный с помощью Delphi Prism был больше. Мне это показалось странным - решил выяснить. Оказалось все просто: Delphi по умолчанию даже к консольному приложению, по каким-то своим личным соображениям добавляет иконку по умолчанию, удалив ее - размеры файлов стали одинаковы.

Еще не поленился дизассемблировать обе версии программы. IL-код их оказался совершенно разным, как собственно я и предполагал, сам не знаю что я надеялся там увидеть :) Не стал дальше копать и на этом решил пока остановиться.

В общем, первое впечатление осталось приятное - надо бы найти время по плотнее сесть поразбираться, но катастрофически ни на что не хватает времени.

Кстати в поставку Delphi Prism входят провайдеры для доступа к базам данных Interbase и Blackfish SQL, что позволяет писать управляемый код для работы с этими базами данных. Интересно, а как Delphi Prism интегрируется с Visual Studio? Будут ли доступны эти провайдеры при написании кода на C#? Но это уже материал для следующей заметки...

понедельник, 19 января 2009 г.

Осторожно! Помощники класса!

В продолжение темы помощников классов и записей. Я провел небольшое исследование в результате которого выяснилось несколько неприятных моментов применения хелперов. На первый взгляд все прекрасно! Мы можем взять и дополнить любой класс практически любым функционалом. Но не все так радужно.

Самая большая обнаруженная мной проблема состоит в том, что для класса может существовать только ОДИН хелпер. Для иллюстрации этого создадим один небольшой проект, содержащий один класс и два хелпера к нему, и посмотрим, что же у нас получилось.

program Project1;

{$APPTYPE CONSOLE}

uses
SysUtils;

type
TSomeObject = class
function X: integer;
end;

TSomeObjectHelper = class helper for TSomeObject
function y: integer;
end;

TSomeObjectHelper2 = class helper for TSomeObject
function z: integer;
end;

{ TSomeObjectHelper }

function TSomeObjectHelper.y: integer;
begin
result := 1;
end;

{ TSomeObject }

function TSomeObject.X: integer;
begin
result := 0;
end;

{ TSomeObjectHelper2 }

function TSomeObjectHelper2.z: integer;
begin
result := 2;
end;

begin
try
with TSomeObject.Create do
begin
writeln(z);
writeln(y);
end;
readln;
except
on E:Exception do
Writeln(E.Classname, ': ', E.Message);
end;
end.

Мы получим ошибку компиляции. Потому что компилятор, видит только один хелпер - TSomeClassHelper2. Если закомнтировать его описание и реализацию, то компилятор увидит второй хелпер.

К чему это может привести? Это может привести к трудноуловимым ошибкам, особенно в больших проектах, разрабатываемых не одним разработчиком. Или, как вариант, представим такую ситуацию: в какой нибудь библиотеке - например FIBPlus или DevExpress вдруг используют хелперы, вы снова добавили хелпер уже в своем коде. Компилятор увидел ВАШ хелпер, а исконный хелпер разработчиков - нет, и все - проект уже не скомпилируется. Ситуация еще больше усугубится если у библиотеки закрыты исходные коды.

Поэтому, применять хелперы следует с большой осторожностью, 100 раз подумав.

воскресенье, 18 января 2009 г.

Помощники записей

Сегодня, разбираясь с проектом, который я пытаюсь перевести на Delphi 2009, натолкнулся на одну забавную недокументированную возможность. Наряду с помощниками классов (Class Helpers) введенными в последних версиях Delphi, разработчику доступны и помощники записей!

Стоит сразу отметить, что данная возможность не поддерживается редактором кода и Code Insight. Так в редакторе код подчеркивается красным, а в Code Insight добавленное недоступно.

НО, с точки зрения компилятора, следующий код абсолютно рабочий:

type
TRectHelper = record helper for TRect
function Width: integer;
end;

{ TRectHelper }

function TRectHelper.Width: integer;
begin
Result := Self.Right - Self.Left;
end;

Использовать новый метод можно, например, следующим образом:

var
p: TRect;
begin
p.Top := 0;
p.Left := 0;
p.Bottom := 12;
p.Right := 12;
ShowMessage(inttostr(p.width));
end;

Не знаю, на сколько эта возможность может быть востребована, но она есть.

P.S. К слову сказать, что Class Helpers разработчики не рекомендуют использовать постоянно, а про Record Helpers они и вообще умолчали. :)

суббота, 17 января 2009 г.

Неизвестные возможности стандартных компонентов

Одной строкой: Сегодня Bose сделал уникальное открытие. Оказывается, что стандартный TDbGrid умеет рисовать многострочные заголовки с группировкой. Подробнее можно прочитать и посмотреть в его блоге.

Что самое смешное, что данная возможность не является недокументированной, по крайней мере в справке Delphi 2009 можно найти информацию о ней, но кто бы читал эту самую справку. :)

пятница, 16 января 2009 г.

5 книг по Delphi которые следует прочитать

Все мы когда-то только начинали и учились программировать. Кто-то сидел и сам разбирался со всеми возможными проблемами, кто- сразу лез на форум и пачками создавал темы вроде "АААААА! пАмАгИтЕ!". Но так или иначе все начинали с азов, которые описаны в литературе. (Хотя не все из второй категории :)).

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

Перво-наперво, из разряда "книги для начинающих" - это Стив Тейксейра, Ксавье Пачеко. Delphi 5, Руководство разработчика. В двух томах. - Очень удачная, на мой взгляд, книга все грамотно и понятно написано, начальные сведения я черпал именно из нее.

Еще одна очень хорошая книга, на этот раз отечественного автора - Архангельский А.Я. Программирование Delphi 5. - Достаточно объемная книга, в которой есть практически все, что нужно начинающему.

Небольшое отступление. Во всех приводимых книгах в основном описываются довольно старые версии Delphi, но это не так важно, поскольку в них описываются именно основы - так необходимые начинающему. А про все новомодные добавления в виде хелперов и анонимных методов на начальном этапе знать попросту вредно. Когда будет опыт - с ними разобраться не составит труда, и литература не понадобится.

Продолжу импровизированный TOP книг.

На начальном этапе также полезно будет почитать книгу Рода Стивенса - Delphi. Готовые алгоритмы. В ней рассматривается создание и эффективное использование алгоритмов для работы со стеками, списками, очередями - вещами хоть и не всегда применяемыми при реальном программировании, но знание которых очень полезно.

В переходном этапе - когда уже и не новичек, но все же еще чего то не хватает, я нашел для себя книгу П.Дарахвелидзе Е.Маркова. Программирование в Delphi 7

Ну и самая лучшее оставил на последок. Самой лучшей книгой я считаю книгу Марко Кэнту - Программирование в Delphi 7 для профессионалов. В которой рассматриваются практически все темы, связанные с программированием в Delphi.

Это книги из серии "то что читать полезно", но существует еще целый пласт книг на которых недобросовестные авторы просто делают деньги. Я их не осуждаю - каждый зарабатывает так как считает так как считает нужным, но читать я их не советую. В эту категорию для меня попадает довольно большое количество книг начиная от всевозможных "Библий" и "освой за 5-10-15 минут" и заканчивая чьими-то глазами. Поскольку в этих книгах довольно часто отражается не истинное положение вещей, а видение автора, причем не всегда правильное.

В прошлом году разгорелся даже довольно большой спор по поводу одной "статьи" одного такого автора на блоге Delphist.ru. Я абсолютно согласен с aktuba, в одной из приведенных мной книг даже подробно описано ПОЧЕМУ так делать нельзя, но принять участие в споре не смог, поскольку комментарии не добавлялись. Но вроде бы сейчас эта ошибка исправлена.

среда, 14 января 2009 г.

Работа с XML

Несмотря на то, что тема работы с XML в Delphi довольно широко обсуждалась в Интернете, вопросы на эту тему довольно часто возникают на всевозможных форумах.

Я тоже уже писал по этому поводу, но хотел бы вернуться к реальному случаю быстрого разбора XML файла и извлечения данных, который я сегодня проделал на работе. Получение необходимых данных у меня заняло не более 5 минут времени.

Предыстория. Сегодня понадобилось обработать данные об установленных программах на компьютерах пользователей (да, да, пиратов выявляем :)). Технический отдел предоставил мне такую информацию содраную с ничего не подозревающих пользователей по сети с использованием WMI. Программа, которой они пользовались выдает отчеты в формате XML. Соответственно - мне притащили гору XML файлов с довольно сложной структурой из которых мне необходимо было вытащить только название установленных программных продуктов.

Обработка. Просмотрев пару файлов вручную, понял что так и состариться не долго, и решил написать небольшой конвертер. Запустив Delphi - выбрал в репозитарии объект XML DataBinding и скормил ему один из файлов. Все настройки и параметры я оставил по умолчанию и в результате у меня сформировался модуль с большим количеством классов и интерфейсов для доступа к элементам этого XML файла. Я не стал долго разбираться со структурой классов, сразу же перешел к написанию конвертера.

В новом консольном приложении написал довольно простой код:


program XML2TXT;

uses
Forms,
Classes, SysUtils,
SoftwareXML in 'SoftwareXML.pas';

procedure CovertXML2Text;
var
softbase : IXMLSTDSoftwareType;
i: integer;
sr: TSearchRec;
CurDir: string;
ExportFile: TStringList;
begin
CurDir := IncludeTrailingPathDelimiter(ExtractFilePath(Application.ExeName));
if FindFirst(CurDir+'*.xml', faAnyFile, sr) = 0 then
repeat
ExportFile := TStringList.Create;
softbase := LoadSTDSoftware(Pchar(CurDir+sr.Name));
for i := 0 to softbase.InstalledSoftware.source.software.Count - 1 do
ExportFile.Add(softbase.InstalledSoftware.source.software[i].DisplayName);
ExportFile.Sort;
ExportFile.SaveToFile(CurDir + softbase.InstalledSoftware.Source.servername+'.txt');
ExportFile.Free;
until FindNext(sr) <> 0;
end;

begin
Application.Initialize;
CovertXML2Text;
end.

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

Чувствую что данный код потребует пояснений. Например, зачем я в консольном приложении использовал модуль Forms и вызывал процедуру Application.Initialize;?

На самом деле все просто - это небольшой хак, позволяющий использовать XML Data Binding в консольном приложении. Потому как в нем упорно отказывался инициализироваться класс для работы с XML. В истинных причинах пока не разбирался - сегодня было важно время, я и так 4 из 5 минут потратил на борьбу с этой ошибкой. :) Думаю позже разобраться с этой проблемой и написать в чем истинная причина.

Странный класс softbase был создан на основе XML файла - так назывался корневой элемент, а softbase.InstalledSoftware.source.software[i].DisplayName - просто навигация по вложенным элементам до нужного и получение его значения.

Вот собственно так выглядит один из самых быстрых способов работы с XML в Delphi.

понедельник, 12 января 2009 г.

Новое в Delphi 2009: работа с ресурсами

Чуть ранее я уже писал о работе с ресурсами в Delphi. Там был описан абсолютно универсальный способ, работающий в любой версии Delphi. Существует еще одна возможность прикрепления ресурсов. Но сегодня я расскажу о том, какие новые возможности по работе с ресурсами нам предлагает Delphi 2009.

Если раньше можно было добавить файл с описаниями ресурсов (*.rc) в проект, и он автоматически скомпилируется и привяжется, то в Delphi 2009 разработчики пошли еще дальше. Теперь с помощью менеджера проектов (Project Manager) в проект можно добавлять сами ресурсы!


Так же с помощью меню Project -> Resources можно вызвать менеджер ресурсов:


Единственное, чем мне не понравились эти нововведения - это не очень удобный менеджер ресурсов. Мне кажется в нем будет сложно работать при большом количестве подключаемых ресурсов. Так же удивило малое количество поддерживаемых типов ресурсов, поддерживаются только Bitmap, RCData и None. На самом деле тип ресурса определяется по формату файла. Так например при добавлении курсора в выпадающем списке становятся доступны варианты - Cursor, RCData, None, при выборе иконки - Icon, RCData и None, а при выборе JPEG изображения - только RCData И None.

Все подключенные подобным образом ресурсы при работе с программой подгружаются стандартным образом с использованием идентификатора, которй так же можно при желании изменить с помощью менеджера ресурсов.

воскресенье, 11 января 2009 г.

Технологии интеллектуального редактирования (Часть III)

В этой заметке я продолжу обзор наиболее продвинутых возможностей редактирования исходного кода в Delphi. Напомню, что несколько ранее в Части I рассматривались возможности интеллектуального поиска, а в Части II - возможности по быстрому созданию и переименованию конструкций кода.

Ну чтож, начнем. Наиболее мощной и одновременно ресурсоемкой является возможность перемещения (Move). Причем перемещать можно как статические члены класса в другой класс, так и сами классы в другое пространство имен. Для выполнения этой функции следует встать на соответствующий идентификатор и дать команду Refactor -> Move



Так же есть возможность быстро перемещать члены классов от дочерних классов к одному из родительских или наоборот - от родительского класса - к одному из классов-наследников. Если данная команда применима к выделенному члену класса, то на экране появится следующее диалоговое окно для выбора:


Это были две самые интересные, на мой взгляд, операции рефакторинга, которые позволяют вносить глобальные изменения в код, не рискуя при этом потерять его работоспособность или внести большое количество трудноуловимых ошибок.

Еще одной немаловажной особенностью является то, что перед применением выполнения рефакторинга можно оценить те изменения в коде которые получатся. А в том случае, если вдруг в результате затяжной операции рефакторинга произойдет какая либо ошибка - код вернется в исходное состояние.

Ну и еще - рефакторини можно отменять так же как и любые другие действия в редакторе кода - с помощью клавиш Ctrl+Z, что делает их очень мощным и простым инструментом.

суббота, 10 января 2009 г.

Технологии интеллектуального редактирования (Часть II)

Продолжим начатый ранее разговор о рефакторинге. Сегодня рассмотрим более продвинутые возможности по интеллектуальному редактированию.

Как обычно начнем с более простых возможностей, первой из которых рассмотрим быструю декларацию переменной и поля. В заметке посвященной LiveTemplates я уже рассказывал как можно быстро объявить переменную. Но есть еще один вариант. Представим себе ситуацию, когда вы уже пытаетесь скомпилировать проект с не объявленной переменной, естественно компилятор выдаст ошибку:

[DCC Error] Unit2.pas(94): E2003 Undeclared identifier: 's'

Так вот, если теперь встать на эту ошибку и из контекстного меню выбрать пункт Declare Variable то в диалоговом окне можно выбрать тип определяемой переменной и при необходимости даже инициализировать ее:

Этим средством удобно пользоваться когда необходимо быстро задействовать новые локальные переменны - например при добавлении циклов.

Аналогично можно поступить если требуется не локальная переменная, а поле класса - Declare Field. Единственное отличие заключается в том, что для поля класса можно дополнительно выбрать область видимости.

Следующая замечательная возможность называется визуальное создание метода (Extract Method). Она позволяет выделить в редакторе кода произвольную часть кода, и организовать ее в виде метода. На рисунке я выделил код, отвечающий за удаление временных файлов в отдельный метод:

При выделении более сложного участка кода в процессе рефакторинга автоматически создадутся параметры метода и его локальные переменные.

Пожалуй самая используемая мной возможность рефакторинга - это визуальное изменение параметров (Change Parameters). Очень удобно при большом количестве параметров, часть из которых задана со значениями по умолчанию. Вызывается из контекстного меню редактора кода, если предварительно выделить имя необходимой процедуры или метода.

Ну и в завершение еще одна из часто используемых и полезных функций рефакторинга - глобальное переименование идентификатора (Rename). Сколько хлопот раньше приносило переименование какого-либо визуального контрола (скажем TLabel) если он использовался коде. Все вхождения можно было отловить только с помощью компилятора и спотыкания на каждом вхождении. Но теперь с этим покончено. Необходимо всего лишь встать на необходимый идентификатор и дать команду Refactor -> Rename. Данная операция применима к названиям переменных, методов, полей, классов, структуур, интерфейсов и параметров.

Перед переименованием можно просмотреть все идентификаторы которые будут изменены.

В следующей части речь пойдет перемещениях частей кода. Не переключайтесь. :)

пятница, 9 января 2009 г.

Технологии интеллектуального редактирования (Часть I)

Продолжаю публиковать серию заметок начатую мной в заметке "Отличия новых версий Delphi от Delphi 7". Сегодня речь пойдет о технологиях интеллектуального редактирования (в англоязычной терминологии Refactoring). Взамен такого длинного русскоязычного названия я буду применять более короткое – "рефакторинг".

Итак, рефакторинг является одним из наиболее значимых нововведений последних версий Delphi. Ключевой особенностью рефакторинга является то, что перед применением изменений их можно просмотреть, а при необходимости легко отменить.

Начнем, пожалуй, с самых простых сценариев применения рефакторинга с поиска. Рассмотрим первую возможность - "Поиск модуля". Данная возможность позволяет найти необходимый модуль и добавить его к списку подключенных модулей в разделе Interface или Implementation. Кстати сказать, все команды рефакторинга вызываются либо из главного меню среды – Refactorings, либо через контекстное меню редактора кода. Причем можно производить поиск не только по имени модуля, но и по имении функций входяших в него (!!!). На рисунке приведен пример поиска модуля по функции ShellExecute:

При нажатии кнопки OK название модуля ShellAPI добавится в раздел подключенных модулей раздела Implementation.

Еще одна прекрасная возможность поиска - поиск ссылок (FindReference), позволяющаяя найти все упоминания о каком либо идентификаторе во всех связанных файлах проекта.

При двойном щелчке на элементах дерева в редакторе кода будет подсвечиваться соответствующая строчка кода.

Для поиска локальных идентификаторов можно воспользоваться вариантом этой функции - Find Local Reference. Результат ее действия аналогичен.

Рассмотрим еще одну возможность поиска. Новая возможность называется "Поиск класса" (FindClass), позволяющая находить определения классов по их именам.

Нажав кнопку OK мы перейдем к описанию класса.

На сегодня, пожалуй, все, продолжение в следующих заметках.

Обновление блога

Еще немного поразмыслив над целями, поставленными мной ранее в заметке «Цели блога 2009», и сопоставив их с текущими положением дел с хостингом, решил немного обновить блог. На это меня в большой степени подтолкнул блог «On-line помощь при ведении блога на Blogger.com» В новом обновленном дизайне блок для вывода содержания заметки несколько больше – так что исходный код теперь должен помещаться. Так же в скором времени планирую прикрутить подсветку синтаксиса для исходного кода и отказаться от размещения исходного кода в картинках – как в предыдущей моей заметке.

Еще из нового – появилась возможность подписываться в один клик в агрегатор новостей Google Reader, а так же получать новые заметки по электронной почте, так что не забываем подписываться на обновления, в планах еще много интересных (на мой взгляд) тем для заметок. :)

Теперь комментирование заметок встроено на страницу с самой заметкой, а не отдельно как было ранее. Комментировать стало удобнее – так что не забываем комментировать. :)

Самому пока не нравится как выводятся списки последних заметок и комментариев – буду думать как исправить. Пока пусть так будет. :) Если заметите еще проблемы с дизайном, можно оставлять комментарии к этой заметке, буду пытаться исправлять.

Вот, в принципе и все.

P.S. Странное черное поле ввода в правом верхнем углу - это поиск по блогу. :)

четверг, 8 января 2009 г.

Перевод проекта на Delphi 2009 – первые грабли

Сегодня выдалось немного свободного времени и решил я поковырять свой проект на предмет совместимости с Delphi 2009. В одной из моих предыдущих заметок я уже говорил, что проект отказался компилироваться. Начнем разбираться почему.

Первым делом компилятор споткнулся о «мертвую» (нигде не использующуюся) процедуру RunDosAndWait которая запускала консольное приложение фоном и ждала его выполнения. Честно говоря, я намеренно не стал убирать эту процедуру и берег ее для такого случая, как она мне сегодня пригодится – речь пойдет немного позже.

Итак, не работает функция CreateProcess(nil, PChar(CommandLine), nil, nil, true, 0, nil, nil, StartupInfo, ProcessInfo). Попробовал поискать в инете, толком решения проблемы не нашел. На одном из форумов тоже сталкивались с этой проблемой, но решения предложено не было.

Пробуем просто создать процесс:

Получаем следующую картинку:



Поскольку новая Delphi 2009 это один большой Юникод, то думаю следует поискать причину в этом. Попробуем разобраться почему код отлично работавший в предыдущих версиях резко перестал работать. В предыдущих версиях (не Юникод) при вызове функции CreateProcess фактически вызывалась ANSI-версия этой функции – CreateProcessA, в новой Юникод-версии фактически вызывается CreateProcessW и по всей видимости в этом то и кроется основная проблема. А так как CreateProcess это самая что ни на есть WinAPI функция, попробуем поискать ответы на наши вопросы в MSDN.

Вот собственно, что и следовало доказать. Функции CreateProcessA и CreaterocessW ведут себя по-разному:

The Unicode version of this function, CreateProcessW, can modify the contents of this string. Therefore, this parameter cannot be a pointer to read-only memory (such as a const variable or a literal string). If this parameter is a constant string, the function may cause an access violation.

Что в вольном переводе означает, что эта функция может изменить содержание строки и поэтому параметр не может быть константой или строкой символов. Напрашивается самый простой вариант:


Но в этом случае программа так же откажется работать. Дело в том, что оптимизирующий компилятор Delphi вместо нашей переменной все равно воткнет константу, поскольку он видит, что значение нигде по коду не меняется. Чтобы проверить правильность наших выводов относительно функции CreateProcess слегка изменим код, чтобы обновить оптимизатор:


Теперь программа исполняется так как положено. Единственное, что мне необходимо было сделать, чтобы обойти этот баг – это изменить описание функции. Вместо:

function RunDosAndWait(const CommandLine: string; OutSrings: TStrings): boolean;

написать

function RunDosAndWait(var CommandLine: string; OutSrings: TStrings): boolean;.

Все - с этим разобрались, но в этой же процедуре осталась ошибка с процедурой OemToChar, переводящей кириллический текст из консоли в удобочитаемый вид. Но об этом – в другой раз.

вторник, 6 января 2009 г.

Цели блога 2009

Сегодня с утра бродил по Интернету в поисках чего-то сверхважного, ну и в итоге нашел совершенно не то, что искал. :) Нашел интересный блог - «Блог про блоги от Дмитрия Донченко». Почему то меня заинтересовала запись, в которой автором организуется эстафета «Интернет-цели 2009». Немного пораздумав, решил тоже принять участие, но не в виде эстафеты, поскольку блогосфера у нас еще только начинает развиваться и то если начинает. Вот на пример у нас был один довольно активный блогер, но умотал в Австралию ... Больше я о таковых не слышал, TooDoo кстати тоже ... Отдельно стоят два прошлогодних стартапа - Биробиджанский блог и Дальневосточный IT-блог. Но они коллективные и узкоспециализированные, поэтому вернемся к моему блогу :)

Несмотря на то, что моему блогу уже более года, он еще зеленый. Отчасти это связано с текущей тематикой блога. Поэтому ставлю целью к двухлетию блога подойти более серьезно. :)

Как я писал в своей предыдущей записи – основной целью на 2009 год у меня является освоение новых технологий – в первую очередь технологий Microsoft, в результате это отразится и на самом блоге, он уже не будет таким узко-тематическим, и, по всей видимости, сменит название. По крайней мере, на сегодняшний день это как цель.

Второй целью является переезд блога с Blogger'а. Что-то в последнее время перестал мне нравится этот сервис. Скорее всего блог превратится в standalone и публикации в нем будут появляться более регулярно.

Ну наверное еще читателей побольше, и в рейтинге повыше. Почему то хочется в ТОП1000 на яндекс.блогах и сотню на счетчике feedburner.

Вот такие пока цели, на мой взгляд довольно достижимые. Посмотрим, что из этого всего получится. Обсудим через год. ;-)

понедельник, 5 января 2009 г.

Новый год – новые технологии

Возможно, данный пост несколько запоздал, но я только что вернулся из поездки в Хабаровск и только сейчас смог спокойно сесть перед компьютером, чтобы отдохнуть и предаться размышлениям.

На мой взгляд, новогодние каникулы имеют большой смысл. Это время, когда старый год уже ушел, а новый еще вроде как и не наступил. Вся суета, которая обычно случается под конец года уже позади и можно спокойно оглянуться назад, на то, что уже сделано или наоборот не сделано, и посмотреть вперед.

Так как я в прошедшем году так или иначе был связан с программированием, а именно с программированием в среде Delphi, то хочу заострить внимание на ней. Что же случилось за прошедший год с Delphi? А произошло два важных события: 1) в очередной раз перепродались – на этот раз компании Embarcadero 2) выпустили новую версию среды.

Выпущенная версия Delphi имеет номер 12. Существует поверие, которого я тоже придерживаюсь, что наиболее стабильными и удачными являются нечетные версии Delphi. Я работаю с Delphi начиная с 3-й версии, и в основном пользовался именно нечетными версиями. Взять, например такой шедевр, как Delphi 7 не потерявшей актуальности и по сей день. Но как из любого правила есть исключение и таким исключением явилась Delphi версии 9, более известная как Delphi 2005 – полностью провальная и глючная версия. И на сегодняшний момент я считаю наиболее стабильной 11-ю версию среды – Delphi 2007.


Это то, что касалось второго пункта. Теперь первый. Глубоко сомневаюсь, что все эти перестроения пошли продукту на пользу. Есть хорошая поговорка – «Новая метла по новому метет», ну и намела она, на отсутствие обратной совместимости с большим количеством сторонних компонентов и на отсутствие исходных кодов, которые раньше стабильно поставлялись с каждой версией Delphi.

Ладно, оставим в покое саму среду – на самом деле она не такая уж и плохая, и я не сколько не жалею, что посвятил ей очень много времени. Основная проблема мне видится в самой поддержке своих разработчиков от производителя. Вот, к примеру, захотелось мне создать мега стартап, неважно какой. Что мне для этого необходимо? Инструмент. Я неплохо знаю Delphi и хочу использовать его. Версии Turbo Explorer мне явно не достаточно, да и устарела она уже, следовательно, мне придется выкладывать деньги за полную версию ПО (к слову - Delphi 2009 for Win32 Professional Box - 30300 руб). А если разработчик не один – то получается довольно приличная сумма для стартапа.

В то же время, ближайший оппонент – компания Microsoft предлагает довольно интересную программу – BizSpark. Подробнее писать о ней не буду (или пока не буду, кому интересно – можно пойти по ссылке или почитать тут, кстати впервые о ней я услышал на днях разработчика, которые проходили в Хабаровске). Скажу суть – практически все технологии компании доступны для стартапов, на определенных условиях, но все же доступны. А где альтернатива от Embarcadero?

Вот отсюда и получается, что мне как разработчику на данный момент выгоднее пользоваться технологиями Microsoft для создания новых проектов. Отсюда и получаются новые приоритеты на 2009 год, которые уже давно подогреваются мыслями о смене языка и переходом на платформу .NET.