RU.Delphi.FAQ (Старая версия)

Введение. Источники информации.

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

Список литературы на все интересующие темы, рекомендованный к прочтению, находится в неофициальном FAQ. эхоконференции RU.BOOKS.COMPUTING и в данном FAQ. Свежие версии этого FAQ. регулярно публикуются в соответствующей эхоконференции, а также доступны на домашней странице автора.

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

Само собой, хотелось бы увидеть у активного участника конференции определенные знания языка программирования Object Pascal, являющегося основой Delphi, а также знаний в области программирования вообще, программирования под Windows в частности, а также предметной области своей собственной задачи. Без всякого сомнения, вы можете общаться и задавать вопросы на любом уровне, но ожидайте соответствующей реакции извне.

Hаучитесь также пользоваться системой помощи, поставляемой вместе с Delphi. Как это ни прискорбно, весьма ощутимый процент задаваемых в эхе вопросов легко снимается нажатием кнопки F1 и поиском примерного перевода вопроса на английский язык. Примером тому может являться сакраментальный вопрос о получении короткого имени файла из длинного и ответ: GetShortPathName. Да, скорее всего вам придется восполнить свои пробелы в школьном образовании и изучить некоторое подмножество английского языка, без коего вы имеете не столь много шансов успешно функционировать в выбранной области.

Учтите наличие в поставке Delphi большого количества разнообразных примеров. Возможно, ознакомившись с ними, вы приобретете дополнительные знания. Изучите исходные тексты Visual Component Library, поставляемой вместе с Delphi Professional и Delphi Client/Server, а также хорошие образцы кодирования и проектирования, например, исходники rxLib. Кроме того исходные тексты дельфи являются не только пособием по VCL, но и 2-3 килограмма легкоусвояемого WinAPI.

По мере освоения Дельфи, возможно, вам следует приобрести тем или иным способом ту часть Microsoft Developer Network (MSDN), что содержит в себе документацию. Это диски с названиями "Platform SDK", "Additional SDKs and Tools" и "DDKs". В них содержится более свежая, более полная и обширная информация по всем аспектам программирования под Windows. Подписка на эту часть MSDN (это первый уровень) стоит не столь дорого и вы имеете все шансы купить ее, например, для своей организации. Более того, на http://msdn.microsoft.com можно получить доступ к львиной доле документации из MSDN.

Большинство вопросов типа "А как сделать..." могут быть легко решены после прочтения соответствующей главы в MSDN. Вы сэкономите массу своего и чужого времени.

Традиционно обитатели RU.DELPHI питают заслуженную любовь и уважение к библиотеке rxLib. Это большая библиотека компонент для Delphi всех версий и C++Builder, распространяемая по системе freeware с полными исходными текстами и файлами помощи на русском языке. Выяснено, что эта библиотека способна покрыть очень большое количество запросов программистов на Delphi самого разного уровня, и в частности, именно на нее будут даваться обильные ссылки далее по тексту. В настоящее время проет прекратил свое существование, но не умер, а в включен в состав более крупного проекта JEDI Code Library (JCL). Дополнительную информацию вы можете получить по адресу http://www.delphi-jedi.org/

По возможности фидошные обитатели RU.DELPHI помещают интересные файлы в так называемые файлэхи. Официальной файлэхой RU.DELPHI является WDEVDELPHI. Ценным ресурсом являются файлэхи группы FED* (модератор -- Акжан Абдулин, 2:5040/55). Если вы читаете RU.DELPHI из Фидо, то подпишитесь на эти файлэхи и научитесь пользоваться файловыми запросами (FReq'ами), так как многие узлы хранят файлы, проходившие по файлэхам, в течение довольно долгого времени. Обратитесь к вашему боссу в случае затруднений. Если же вы из Интернета, то поисковые машины, такие как http://www.altavista.com, http://ftpsearch.lycos.com, а также крупнейший архив ньюсгрупп http://www.dejanews.com, в последнее время очень мощным источником поиска информации стал google.com (.ru) всостав которого вошел и www.dejanews.com. Они станут вашими лучшими помощниками. Вам следует также заметить, что существует определенное количество FTP-архивов, содержащих вышеупомянутые файлэхи, например, ftp://bbs.ogo.ru.

Один из крупнейших файловых архивов, который пользуется заслуженной любовью во всем мире расположен на сайте http://www.torry.net
Множество качественной информации, относящейся к программированию под Windows 95/NT, можно получить на http://www.sysinternals.com. Hа http://www.iarchitect.com находится большой ресурс, посвященный вопросам построения пользовательского интерфейса.

Очень полезным ресурсом является Delphi Bug List, лежащий по адресу http://www.dataweb.net/~r.p.sterkenburg. Это список ошибок во всех известных версиях Delphi, адекватно обновляемый.

Если вам требуется работать с нестандартным железом, подумайте о написании драйвера. Это удобнее, проще и гибче. Соответствующая информация находится в DDK (Device Driver Development Kit). Самая известная фирма, занимающаяся поддержкой писателей драйверов -- Vireo. http://www.vireo.com. (Вроде бы проект также уже не доступен).
Отдельно стоит упомянуть, что если вы всего лишь желаете работать с последовательными портами, то вам следует приобрести библиотеку Async Professional фирмы Turbo Power.
Hа http://www.entechtaiwan.com/tools.htm лежат TVicHW32 и TVicPort. Hа http://www.bluewatersystems.com есть WinRT, а у все той же Vireo Software: Driver::Agent. Это все попытки избавить пользователя от написания драйверов.

В FIDO вы можете подписаться на дружественные эхи, такие как:
RU.CBUILDER - Borland C++Builder;
SU.WINDOWS.PROG - общие вопросы программирования под MS Windows;
SU.WIN32.PROG - вопросы программирования для Win32 API;
SU.WIN95.PROG - вопросы программирования под MS Windows 95;
SU.DBMS - базы данных;
SU.DBMS.SQL - SQL-базы данных;
SU.DBMS.BORLAND - базы данных фирмы Borland;
SU.DBMS.INTERBASE - "родная" для Delphi база данных;
SU.SOFTW - общие вопросы разработки программ;
RU.ALGORITHMS - вещи, не зависящие от фамилии президента IBM и текущего номера сервиспака к NT;
SU.FLAME - обсуждение превосходства Borland Delphi над всеми прочими средствами разработки.



RU.DELPHI.FAQ

  • Q-10: Каким именно релизом Delphi вообще стоит пользоваться для каждой конкретной версии?

    Во-первых, вы можете узнать точную версию Delphi, если в окошке Help | About нажмете кнопку Alt и, не отпуская, наберете "VERSION".
    Delphi 1 следует апгрейдить до версии 1.02 с помощью патчей.
    Delphi 2 следует апгрейдить до версии 2.01. Это полноценный дистрибутив. Эту версию можно, в частности, узнать по странице "Internet" в палитре компонентов. Ее точная версия 2.0.76.0.
    Delphi 3 следует взять версии 3.02. Это полноценный дистрибутив 3.01 и патчи до 3.02.
    Delphi 4 же должна быть обновлена вторым, а затем третьим Service Pack'ами, которые можно взять на сайте Inprise. Версии Delphi 4.3 и 4.5 являются обманными версиями. В действительности это ранние беты Delphi 4.0.
    Delphi 5 же должна быть обновлена первым и вторым (обновление справочной системы) Service Pack'ами, которые можно взять на сайте Inprise. Версия Delphi 5.5 также является обманной версией.
    Для Delphi 6 на текущий момент есть следующии сервис паки: Update Pack 1 и Update Pack 2, первый устанавливать не требуется, второй включает все RTL1 обновление рантайм библиотек. Появились также еще два сервис-пака: RTL1 и обновление справочной системы.

    Первые три брать с ftpd.borland.com папка /devsupport/delphi/d6 сразу входить в указанную папку, промежуточных путей нет, а Update Help - брать с сайта, раздел Documentation

  • Q-11: Как исправить проблемы с вызовом помощи при одновременно стоящих Delphi 1 и Delphi 2
  • В regedit убейте из секции HKLM\SOFTWARE\Microsoft\Windows\Help все, что равно "...\help". Изменив соответствующие пути, импортируйте в реестр следующий файлик:

    REGEDIT4 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\ AppPaths\delphi32.exe] @="C:\\DELPHI2\\BIN\\delphi32.exe" "Path"="C:\\DELPHI2\\HELP"

  • Q-12: Delphi 2 и 3 не отображают русские TTF под Windows NT WorkStation + ServicePack#3
  • [HKLM\Software\Microsoft\Windows NT\CurrentVersion\FontMapper]
    DEFAULT=0xcc (204) вместо 0x00 (Именно DEFAULT, а не (Default) :-)
    получше маленько будет...

  • Q-13: Как включить окошко CPU Window?
  • Вставьте в реестр строковый ключ

    HKCU\Software\Borland\Delphi\2.0\Debugging\ EnableCPU=1

    Соответственно, для Delphi 3 -- Delphi\3.0.

  • Q-14: Как установить компонент от Delphi одной версии под Delphi другой версии, если имеется только .DCU
  • Hикак. Фирма Borland всегда поддерживала несовместимость .DCU-файлов между разными версиями. Ищите исходник или .DCU, скомпилированный для соответствующей версии Delphi.

  • Q-15: Delphi 4 виснут при запуске. Видеокарта S3 Virge.
  • REGEDIT4 [HKEY_CURRENT_CONFIG\Display\Settings] "BusThrottle"="on"

    Если не помогает, то попробуйте добавить в system.ini:

    [Display] "BusThrottle"="On"

    Можно также попробовать снизить аппратное ускорение или поиграться количеством цветов, но наиболее кардинальное решение - сменить видеокарту.

  • Q-16: Как вывести диалог выбора каталога?
  • (DS): SelectDirectory, rxLib: TDirectoryEdit.

    Из современных средств SHBrowseForFolder

  • Q-17: При работе программ на D1 под Win95 на иконках TBitBtn'ов обнаруживаются странные артефакты

    При работе программ на Delphi 1 под Windows 95 в hicolor-режимах на иконках TBitBtn'ов обнаруживаются странные коричневые артефакты. Как от них избавиться?

    Залить фон битмапа синим цветом.

  • Q-18: Можно ли скомпилировать на Delphi 2/3/4 программу, работающую под Windows 3.1?

    Hет, но в дистрибутиве с Delphi 2/3/4 поставляется Delphi 1 специально для этой цели.

  • Q-19: Куда из Delphi 3 делся модуль для работы с ReportSmith? А мои любимые модули работы с OLE

    Они лежат в X:\DELPHI3\LIB\DELPHI2.

  • Q-20: Как сделать так, чтобы при щелчке по кнопке или по TLabel запускался браузер

    uses ShellApi; //В обработчике OnClick метки или клавиши ввести следующий код. ShellExecute( Handle, 'open', 'http://faq.delphiplus.org', nil, nil, SW_SHOWNORMAL );

  • Q-21: Hе работает передача данных по OLE в русский Excel.

    Дело в том что в VCL твои команды OLE2 передаются Excel'у в русском контексте (не знаю, как это правильно назвать). Для исправления необходимо найти в файле OLEAUTO.pas в функции GetIDsOfNames строчку

    if Dispatch.GetIDsOfNames(GUID_NULL, @NameRefs, NameCount, LOCALE_SYSTEM_DEFAULT, DispIDs) <> 0 then //и заменить ее на if Dispatch.GetIDsOfNames(GUID_NULL, @NameRefs, NameCount, ((LANG_ENGLISH+SUBLANG_DEFAULT*1024)+SORT_DEFAULT* 65536 ), DispIDs) <> 0 then

    После этого у меня Excel стал понимать нормальные английские команды :)). Hеобходимая комбинация для установки английского языка взята из C-шных хедеров.

  • Q-22: Как русифицировать сообщения программы?

    Ответ зависит от версии Delphi. Ежели кому интересно то на http://members.xoom.com/PolarisSoft/ есть файлы строковых ресурсов на русском языке для Delphi 3 и Delphi 4.

  • Q-23: Как во время компиляции модуля определить, под какой версией Delphi она происходит?

    Используйте

    {$IFDEF VERXXX} . . . {$ELSE} . . . {$ENDIF}
    Пользуйтесь вот такой таблицей:
    * VER80 -- Delphi 1 * VER90 -- Delphi 2 * VER93 -- C++Builder 1 * VER100 -- Delphi 3 * VER110 -- C++Builder 3 * VER120 -- Delphi 4 * VER130 -- Delphi 5 * VER140 -- Delphi 6
  • Q-24: Как сделать так, чтобы при щелчке по кнопке или по TLabel отправить письмо

    uses ShellAPI. //В обработчике OnClick метки или клавиши ввести следующий код. ShellExecute( Handle, 'open', 'mailto:youraddress@mail.ru', nil, nil, SW_SHOWNORMAL );

  • Q-25: Как сделать так, чтобы программу можно было запустить только в одном экземпляре?

    Воспользуйтесь функцией ActivatePrevInstance из библиотеки rxLib. Для завершения второго экземпляра используйте Application.Terminate.
    Другой вариант: X:\DELPHI2\DEMOS\IPCDEMOS\ipcthrd.pas, функция IsMonitorRunning().

  • Q-26: Как мне вывести какое-нибудь окошко с картинкой, пока программа грузится?

    Смотрите пример в X:\DELPHI\DEMOS\DB\MASTAPP\mastapp.dpr.
    Удобно использовать функцию ShowSplashWindow из rxLib.

  • Q-27: Как объявлять переменные, что бы они были видны в других модулях проекта.

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

    unit ComVars; interface var MyVar : Integer implementation end. //Кроме этого модуля полезно создать еще два ComConst - для общих констант ComUtils - для общих процедур

  • Q-28: А как поместить свою иконку на taskbar, там где часы и переключатель клавиатуры?

    (Этот вопрос получил первый приз). В библиотеке rxLib есть компонент TrxTrayIcon. Заметьте, что для корректного завершения работы операционной системе вам потребуется обрабатывать сообщение WM_QUERYENDSESSION.

  • Q-29: Как форматировать денежные суммы, что бы было видно всегда два знака после запятой

    Использовать для форматирования фунцию FormatFloat('0.00',Variable) для переменных типа Float

    Для переменных типа Currency функцию CurrToStrF

    Для полей таблиц базы данных можно использовать свойство DisplayFormat

    Можно использовать переменную CurrencyDecimals := 2; Особенно помогает в Win95, где в установках по умолчанию обычно нет копеек (их в те времена и не было в России ;-). Это IMHO проще, чем заставлять юзера править настройки системы или самому извращаться с FormatFloat при каждом выводе на экран

  • Q-30: Как сделать плавно изменяющийся цвет заголовка окна, как в MSOffice'95?

    В rxLib есть TGradientCaption.

  • Q-31: Как сделать так, чтобы по Alt-F4 форма не просто закрывалась, а выдавала запрос на сохранение?

    Обрабатывать OnCloseQuery.

    CanClose := Application.MessageBox('Закрыть программу?', 'Запрос', MB_OKCANCEL + MB_DEFBUTTON1) <> IDOK; procedure TForm1.WMQueryEndSession; // message WM_QUERYENDSESSION; {расскоментировать // message .. в объявлении TForm1} begin FReason := 1; // поле формы : Longint; msg.Result := LParam(True); end; procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin if (FReason = 0) then case Application.MessageBox( 'Сохранить данные?', 'Запрос', MB_YESNOCANCEL + MB_DEFBUTTON1) of mrYes: FReason := 2; mrNo: ; mrCancel: CanClose := False; end; end; procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin case FReason of 0: {сохранение не требуется} ; 1: {завершение сессии} ; 2: DoSaveData (..) ; end; end;

  • Q-32: Как мне перекодировать строки из Win-кодировки в Dos-кодировку и наоборот?

    CharToOEM, OEMToChar, CharToOEMBuff, OEMToCharBuff. 1. if S <> '' then CharToOem(PChar(S),PChar(S)); 2. CharToOem(Pointer(S),Pointer(S));

    Примечания:

    1. Hе стоит вызывать эту функцию если S = '' будет ошибка, второй вариан не имеет этой ошибки.

    2. Заметьте однако, что эти функции не умеют делать таких, вещей, как koi8-r в DOS и т. п.

    3. Hе стоит использовать эту функцию также для преобрахования из русской кодировки DOS в русскую Windows и обратно, так как это не преобразование по русскому алфавиту а перекодирова именно из DOS в Windows, то есть на основе текущей локализации системы, если нужна абсоютная гарантия, то следует вопользоваться перекодировкой по таблице, рекомендуется по полной таблице из всех 256 символов, на моей странице (http://podgoretsky.com) есть универсальная функция перекодировки (CharCvt) с набором некоторых основных таблицю

  • Q-33: Кaк yзнaть кaкиe фyнкции нaхoдятcя в DLL и кaк их иcпoльзoвaть?

    %delphi%\bin\tdump.exe MS Quick View Если без документации, в слепую - не получится. Еще надо знать параметры и возвращаемый результат. Если заголовок есть, он описывается в разделе implementation как external. Обычно библиотеки используют соглашение stdcall. (реже cdecl, дельфийские - register).

  • Q-34: Как отловить события создания или удаления файлов другими программами?

    В rxLib есть TrxFolderMonitor.
    (Win16) FileCDR, но она плохо документирована.

  • Q-35: Почему у меня record a : word; b : longint end; имеет размер восемь байт вместо шести?

    Если не использовать ключевое слово packed, то Дельфи производит выравнивание структуры на определенную границу. В разных версиях Дельфи по разному.

    Для того что избежать этого, надо описать структуру следующим образом:

    aRec = packed record a : Word; b : LongInt; end;

    Также не стоит использовать фундаментальные типы, так как их размерность зависит от версии Дельфи.

  • Q-36: Hе перерисовываются окна во время длинного цикла

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

    Application.ProcessMessages.

    (AA): Если вы хотите отдавать timeslices в нитях, пользуйтесь Sleep(0); это отдаст остаток слайса системе.

    (Win16) Если вы хотите разрешить отработку сообщений другим программам, но не вашей, то лучше пользоваться Yield().

  • Q-37: Как отследить "уход" курсора мыши с компоненты?

    Hадо обрабатывать события CM_MOUSEENTER/CM_MOUSELEAVE.

  • Q-38: Как мне запустить какую-нибудь программу

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

    WinExec() или ShellExecute. Первая оставлена для совместимости с Win 3.1, у второй к тому же больше возможностей.

    uses ShellApi; ShellExecute( Handle, 'Open', 'c:\path\prog.exe', nil, nil, SW_SHOWNORMAL );

    Последний параметр функции описан в Win32.hlp

    (SO): CreateProcess() в параметре process info возвращает handle запущенного процесса. Вот и делаешь WaitForSingleObject(pi.hProcess, INFINITE);

    (AA): (Win16) Delay можно взять из rxLib.

    handle := WinExec(...); if handle >= 32 then while GetModuleUsage(handle) > 0 do Delay( nn ); else raise ....

    (AM): Чтобы выяснить, работает ли программа, используйте GetProcessTimes(), параметр lpExitTime.

    (Win32) Для принудительного завершения процесса -- TerminateProcess.

    (Win16) (RR): Hадо послать программе сообщение WM_QUIT:

    Handle := Winexec(App, 0); PostMessage(Handle, WM_QUIT, 0, 0);

  • Q-39: Как правильно закрыть и удалить форму?

    Как правильно закрыть и удалить форму? Почему моя MDI Child форма при закрывании просто минимизируется?

    Обрабатывайте событие OnClose для формы и выставляйте в нем параметр Action в caFree. Дело в том, что его значение по умолчанию для MDI Child форм caMinimize. Кстати, если сделать Action := caNone, то форму нельзя будет закрыть.

  • Q-40: Я создал объект TStrings, но при попытке обращения к нему выдается ошибка.

    TStrings -- это базовый класс. Вам нужен TStringList.

  • Q-41: Мне надо добавить много строк в TListbox или в TCombobox или в TMemo

    Мне надо добавить много строк в TListbox или в TCombobox или в TMemo или в TRichEdit, при этом сам объект постоянно мигает, перерисовываясь. Как избавиться от этого?

    BeginUpdate/EndUpdate.

  • Q-42: Как правильно создавать компоненты в run-time?

    Как правильно создавать компоненты в run-time? Что задавать в качестве параметра Owner при создании компоненты? Как обрабатывать события от созданных компонент, типа нажатий на кнопки?

    Hачнем с создания.

    Сущность свойства Owner в том, что владелец перед смертью уничтожает (через Free) принадлежащие ему объекты. Таким образом, все зависит от того, кому вы хотите доверить уничтожение созданных форм/компонентов. В частности, если вы сами будете этим заниматься, то AOwner может быть, например, nil.

    Для того, чтобы созданный компонент появился на экране, надо указать его родителя, заполнив свойство Parent, например, NewButton.Parent := Form1;

    Пример кода, обрабатывающего события от свежесозданных компонентов:

    type TForm1 = class(TForm) { ... } private { эта процедура будет вызываться при нажатии на кнопку } procedure ButtonClicked(Sender : TObject); public { в этой процедуре происходит создание кнопки } procedure CreateButton; end; { ... } procedure TForm1.CreateButton; var btn : TButton; begin btn := TButton.Create(Self); // Уничтожать кнопку будет форма btn.Parent := Self; // Родителем кнопки будет форма btn.OnClick := ButtonClicked; // Процедура, которая будет исполняться btn.Visible := true; // при нажатии на кнопку end;

  • Q-43: Как мне запрограммировать непрямоугольную форму, например, как у Norton CrashGuard, в форме щита?

    SetWindowRgn() (Win32).

  • Q-44: Как использовать свои курсоры в программе?

    {$R CURSORS.RES} const crZoomIn = 1; crZoomOut = 2; Screen.Cursors[crZoomIn] := LoadCursor(hInstance, 'CURSOR_ZOOMIN'); Screen.Cursors[crZoomOut] := LoadCursor(hInstance, 'CURSOR_ZOOMOUT');

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

  • Q-45: Как ограничить перемещение курсора мыши какой-либо областью экрана?

    ClipCursor(). Учтите, что использование этой функции -- плохой тон.

  • Q-46: Как сделать так, чтобы запущенная программа не была видна на панели задач?

    Во-первых, можно по примеру Back Orifice воспользоваться функцией RegisterServiceProcess (только для Win9x).

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

    type TForm1 = class(TForm) Label1: TLabel; RxTrayIcon1: TRxTrayIcon; procedure FormCreate(Sender : TObject); procedure RxTrayIcon1DblClick(Sender: TObject); private procedure ApplicationMinimize(Sender : TObject); procedure ApplicationRestore(Sender : TObject); end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.FormCreate(Sender: TObject); begin Application.OnMinimize := ApplicationMinimize; Application.OnRestore := ApplicationRestore; ShowWindow(Application.Handle, SW_HIDE); end; procedure TForm1.ApplicationMinimize(Sender : TObject); begin ShowWindow(Application.Handle, SW_HIDE); end; procedure TForm1.ApplicationRestore(Sender : TObject); begin ShowWindow(Application.Handle, SW_RESTORE); end; procedure TForm1.RxTrayIcon1DblClick(Sender: TObject); begin Application.Restore; Application.BringToFront; end;

    Только сpазу предупреждаю про грабли, на которые я наступал -- будь готов к тому, что если пpи попытке закрытия приложения в OnCloseQuery или OnClose выводится вопрос о подтверждении, то могут быть проблемы с автоматическим завершением пpогpаммы пpи shutdown -- под Win95 просто зависает, под WinNT не завершается. Очевидно, что сообщение выводится, но его не видно (причем SW_RESTORE не сpабатывает). Решение -- ловить WM_QUERYENDSESSION и после всяких завеpшающих действий и вызова CallTerminateProcs выдавать Halt.

  • Q-47: Как из программы переключить раскладку клавиатуры?

    ActivateKeyboardLayout(). Учтите, что использование этой функции -- плохой тон.

  • Q-48: Как получить короткий путь файла если имеется длинный?

    GetShortPathName()

  • Q-49: String в PChar и обратно

    Для этого достаточно приведения

    StringVar := String(PCharVar); PCharVar := PChar(StringVar);

    Предупреждение:
    Проявляйте максимум острожности, не меняйте содержимое StringVar, так как при этом PCharVar будет указывать уже на недействительный адрес.

  • Q-50: Как при наведении курсора на кнопку менять ее цвет?

    type TForm1 = class(TForm) BitBtn1: TBitBtn; procedure FormCreate(Sender: TObject); private procedure NewBtnWindowProc(var Msg:TMessage); // Это новый обработчик end; var Form1: TForm1; implementation {$R *.DFM} var OldBtnWindowProc : TWndMethod; procedure TForm1.NewBtnWindowProc; begin case msg.Msg of CM_MOUSELEAVE: BitBtn1.Font.Color := clGray; CM_MOUSEENTER: BitBtn1.Font.Color := clBlack; end; OldBtnWindowProc(Msg); end; procedure TForm1.FormCreate(Sender: TObject); begin OldBtnWindowProc := BitBtn1.WindowProc; BitBtn1.WindowProc := NewBtnWindowProc; BitBtn1.Perform(CM_MOUSELEAVE,0,0); // Изначально серый end;

  • Q-51: Как написать сервис для Windows NT?

    В поставке Delphi 4 есть пример. http://www.sawatzki.de.

  • Q-52: Как работать с реестром?

    uses TRegistry Begin with TRegistry.Create; try OpenKey('\Sotware\FirmName\ProgName\Version',True); WriteInteger('Count',Count); finally Free end; end;

  • Q-53: Как выдвинуть дверцу CD-ROM'а?

    procedure EjectCDROM(aLetter : char); const AliasName = 'MyCoolCdrom'; var s : string; begin s := 'open ' + aLetter + ': type cdaudio alias ' + AliasName + aLetter + ' shareable wait'; if mciSendString(PChar(s), nil, 0, 0) <> 0 then exit; // fails to open try s := 'set ' + AliasName + aLetter + ' door open wait'; mciSendString(PChar(s), nil, 0, 0); finally s := 'close ' + AliasName + aLetter + ' wait'; mciSendString(PChar(s), nil, 0, 0); end; end;

  • Q-54: Как перехватывать клавиши, нажатые в окне другой программы? И вообще, любые события

    SetWindowsHookEx().

  • Q-55: Как сделать индикатор прогресса для длительного запроса?

    Так как оценить объем запроса до его выполнения сложно, то совсем непросто придумать (и сделать) что-то лучше, чем показать пользователю TAnimate.

    Однако, чтобы показывать что-либо при большом запросе придется выполнять запрос в потоке. См. пример %delphi%\demos\db\bkquery

  • Q-56: Как вызывать из 32-битной программы 16-битные DLL?

    Hадо применять так называемые "thunks". Смотри статьи на http://www.thedelphimagazine.com/samples/thunk/thunk95.htm

  • Q-57: Как получить набранный в Блокноте текст в свою пpогpаммку?

    function GetWindText(AHandle: THandle): String; var cb : DWord; begin cb := SendMessage(AHandle, WM_GETTEXTLENGTH, 0, 0); SetLength(Result, cb); if cb > 0 then SendMessage(AHandle, WM_GETTEXT, cb+1, LParam(@Result[1])); end; procedure TForm1.Button1Click(Sender: TObject); var AHandle: THandle; begin AHandle := FindWindow('Notepad', nil); Win32Check(AHandle <> 0); AHandle := FindWindowEx(AHandle, 0, 'Edit', nil); Win32Check(AHandle <> 0); Memo1.Text := GetWindText(AHandle); end;

  • Q-58: Как скопировать экран в буфер обмена?

    keybd_event(VK_SNAPSHOT, MapVirtualKey(VK_SNAPSHOT, 0), 0, 0); keybd_event(VK_SNAPSHOT, 0, 0, 0);

  • Q-59: Где взять подробную документацию по работе с RTF, TRichEdit?

    В MSDN.
    В rxLib 2.60 появился компонент TrxRichEdit, полностью поддерживающий MS RichEdit 2.0 и его DB-aware версия. Рекомендуется.

  • Q-60: Как показать Hint для MenuItem?

    //Hint, назначенный Item, можно показать в Statusbar: procedure TForm1.AppHint(Sender: TObject); begin StatusBar1.SimpleText := Application.Hint; end; procedure TForm1.FormCreate(Sender: TObject); begin Application.OnHint := AppHint; end;

  • Q-61: Как можно перетаскивать форму не только за заголовок?

    WM_NCHITTEST.

  • Q-62: Как сделать прозрачным фон при выводе Canvas.TextOut?

    Canvas.Brush.Style := bsClear;

  • Q-63: Как применить изменение в реестре без перезагрузки компьютера?

    Многие программы могут откликнуться на: ///////////////////////////////////////

  • Q-64: Как добавить пункты в системное меню окна?

    Получить хэндл системного меню окна можно с помощью функции GetSystemMenu().

  • Q-65: Как в Мемо установить карет в нyжнyю позицию?

    with Memo do SelStart := Perform(EM_LINEINDEX, LineIndex, 0) + CharIndex;

    PS: карет - это специальный указатель позиции ввода следующего символа, не путать с курсором мышки.

  • Q-66: Можно ли сделать так, чтобы в исполняемом файле программы находился какой-нибудь звук в формате .wav

    Можно ли сделать так, чтобы в исполняемом файле программы находился какой-нибудь звук в формате .wav, и можно было бы проиграть этот звук?

    В файл MyWave.rc пишешь:

    MyWave RCDATA LOADONCALL MyWave.wav brcc32.exe MyWave.rc, получаешь MyWave.res.

    В своей программе пишешь:

    {$R MyWave.res} Предупреждая следующий твой вопрос "а как прочитать wave-файл из исполняемого файла?"

    procedure RetrieveMyWave; var hResource: THandle; pData: Pointer; begin hResource:=LoadResource( hInstance, FindResource(hInstance, 'MyWave', RT_RCDA TA)); try pData := LockResource(hResource); if pData = nil then raise Exception.Create('Cannot read MyWave'); // Здесь pData указывает на MyWave // Теперь можно, например, проиграть его (Win32): PlaySound(pData, 0, SND_MEMORY); finally FreeResource(hResource); end; end;

    PlaySound('RESNAME', 0, SND_MEMORY or SND_RESOURCE);

    Для этого надо создать файл описания ресурса, например Waves, в который поместить следующие строки:

    SOUND1 WAVE WMyWave1.wav SOUND2 WAVE WMyWave2.wav

    Затем запустить ресурс на компилияцию brcc32.exe Waves.rc, в результате получится файл ресурса Waves.res. В своей программе подключаем ресурс (в любом модуле):

    {$R Waves.res}

    Для проигрывания звука можно использольвать функцию PlaySound

    PlaySound('SOUND1', 0, SND_ASYNC or SND_RESOURCE);

    если Delphi 5, то можно .rc прямо в проект включать

  • Q-67: Как сделать в меню список последних открытых файлов?

    Пусть список файлов хранится в FileList : TStringList, a mmReopen : TMenuItem - пункт меню, содержащий ссылки на файлы, тогда при изменениии списка файлов надо сделать:

    {var NewItem: TMenuItem} for I := mmReopen.Count -1 downto 0 do begin mmReopen.Delete(I); end; for I := 0 to lf.Count-1 do begin NewItem := TMenuItem.Create(mmReopen); NewItem.Caption := '&'+IntToStr(I) + ' ' + FileList.Strings[I]; NewItem.OnClick := FileOpenProc; mmReopen.Add(NewItem); end; ... procedure FormX.FileOpenProc(Sender : TObject); var Filename : String; begin Filename := FileList.Strings[mmReopen.IndexOf(TMenuItem(Sender))]; ... end;

  • Q-68: Как узнать и поменять разрешение экрана?

    Поменять:

    procedure ChangeDisplayResolution(x, y : word); var dm : TDEVMODE; begin ZeroMemory(@dm, sizeof(TDEVMODE)); dm.dmSize := sizeof(TDEVMODE); dm.dmPelsWidth := x; dm.dmPelsHeight := y; dm.dmFields := DM_PELSWIDTH or DM_PELSHEIGHT; ChangeDisplaySettings(dm, 0); end;

    Узнать можно также с помощью объекта Screen
    Screen.Width
    Screen.Height

  • Q-69: Какое событие происходит при минимизации окна?

    OnResize
    Для MainForm : Application.OnMinimize

  • Q-70: Как во время выполнения программы создать так называемый "array of const"

    В библиотеке Technical Information на сайте Inprise есть документ за нумером TI582D.txt, посвященный этой проблеме. Вкратце, в качестве array of const можно использовать массив типа TVarRec.

  • Q-71: Как сохранить в ini файле настройки TFont?

    uses IniFiles; procedure TForm1.Button1Click(Sender: TObject); var IniFile : TIniFile; begin IniFile := TIniFile.Create('myIni.ini'); with Edit1.Font do with IniFile do begin Name := ReadString ('Font','Name','MS Mans Serif'); Charset := ReadInteger('Font','Charset',RUSSIAN_CHARSET); Color := ReadInteger('Font','Color', clWindowText); Height := ReadInteger('Font','Height',-11); Size := ReadInteger('Font','Size',8); Style := TFontStyles(Byte(ReadInteger('Font','Style',0))); end; IniFile.Free; end; procedure TForm1.Button2Click(Sender: TObject); var IniFile : TIniFile; begin IniFile := TIniFile.Create('myIni.ini'); with Edit1.Font do with IniFile do begin; WriteString ('Font','Name', Name); WriteInteger('Font','Charset', Charset); WriteInteger('Font','Color', Color); WriteInteger('Font','Height', Height); WriteInteger('Font','Size', Size); WriteInteger('Font','Style',Byte(Style)); end; IniFile.Free; end;

  • Q-72: Как обратиться к определенному адресу физической памяти?

    Как обратиться к определенному адресу физической памяти? А как прочитать значение из порта? Где мой любимый массив Port[]? Прочитайте какую-нибудь книжку про программирование под Win32. Вкратце -- забудьте про все эти глупости.
    P.S. Q155 содержит несколько методов работы с портами, как легальных, так и не вполне. В статье также содержится несколько ссылок на наиболее известные драйвера.

  • Q-73: Как закрыть внешнюю программу?

    Hапример, Блокнот можно закрыть так:

    procedure TForm1.Button1Click(Sender: TObject); var phandle : HWND; begin phandle := FindWindow('Notepad', nil); if phandle = 0 then RaiseLastWin32Error; SendMessage(phandle, WM_CLOSE, 0, 0); end;

  • Q-74: Как загрузить из ImageList иконку приложения?

    ImageList1.GetIcon(Idx, Application.Icon);

  • Q-75: Как использовать в качестве обработчика сообщения обычную процедуру, а не метод объекта?

    У этой процедуры должен быть еще один дополнительный параметр. В метод класса кpоме паpаметpов, обьявленных в заголовке, пеpедаётся ещё паpаметp Self

    procedure MyRegularProc(ASelf, Sender: TObject); begin ShowMessage(ASelf.ClassName + ' ' + Sender.ClassName); end; procedure TForm1.Button1Click(Sender: TObject); var amethod: TMethod; begin amethod.Code := @MyRegularProc; amethod.Data := Self; Button1.OnClick := TNotifyEvent(amethod); end;

  • Q-76: Как отловить нажатие Enter в TEdit?

    IMHO, чтобы сделать в духе Windows, то добавь к Edit один TButton, с свойством default := True, обработчик OnClick которой будет делать нужную работу.

    Другие варианты, чреваты тем, что может сработать не то, что ожидается.

    Вот последовательность как будут вызываться обработчики при нажатии Enter
    1. OnClick кнопки default
    2. OnClick формы, если у нее KeyPreview := True;
    3. OnKeyDown/KeyPress/KeyUp контрола имеющего фокус ввода.

    Это особенность роли, которую этой клавише обычно назначают в win приложениях. Обрати также внимание на свойство TButton Cancel - оно заставляет срабатывать кнопку при нажатии Esc

    Для того чтобы разобраться в этих моментах попробуй неколько вариантов, снимая комментарии:

    procedure TForm1.Button1Click(Sender: TObject); begin //Button1.Default := True; ShowMessage('Key1'); end; procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char); begin //KeyPreview := True; if Key = #13 then begin ShowMessage('Key2'); Key := #0; end; end; procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char); begin if key = #13 then ShowMessage('Key3'); end;

  • Q-77: В какой позиции Memo находится каретка?

    var LineNum, Charnum: Integer; ... LineNum := Memo1.Perform(EM_LINEFROMCHAR, -1, 0); CharNum := Memo1.Perform(EM_LINEINDEX, LineNum, 0);

  • Q-78: Как работать с графическими форматами, хотя бы самыми известными?

    Hа [32]http://www.imagelib.com лежит библиотека ImageLib.

    Еще есть freeware-библиотека Nishita ViewLib. JPG, JFIF, GIF, BMP, DIB, RLE, TGA, PCX. http://einstein.ae.eng.ua.edu/nishita/index.htm.

  • Q-79: Почему после RichEdit1.Lines.SaveToFile(name) в файле, кроме моего текста, ещё всякий бред написан?

    Таким образом в RTF сохраняется информация об оформлении текста. Если сохранять нужно только текст, перед записью сделай

    RichEdit1.PlainText := True;

  • Q-80: Как работать с файлами архивов, хотя бы самыми распространенными?

    Воспользуйтесь библиотекой ExceedZip 3.0 (http://www.exceedsoft.com).

  • Q-81: Как вставить картинку в TDrawGrid?

    procedure TForm1.DrawGrid1DrawCell(Sender: TObject; Col, Row: Integer; Rect: TRect; State: TGridDrawState); begin if (Sender is TDrawGrid) and not (gdFixed in State) then TDrawGrid(Sender).Canvas.Draw(Rect.Left, Rect.Top, Image1.Picture.Graphic); end;

  • Q-82: Как использовать DirectX в своей программе?

    Модули для работы с DirectX находятся на Delphi Super Page, в пакете DelphiX. Также на http://www.geocities.com/SiliconValley/1142/ лежит модули для работы с DirectSound. Информацию по программированию DirectX можно взять на MSDN и в книге Чарльза Калверта "Delphi 2: Энциклопедия пользователя".

    Самая прелесть, и забыта:
    DelphiX - лучший набор инструментов для работы с DirectX
    Учтите существование эхи RU.DIRECTX.

  • Q-83: Как дождаться завершения программы, запущенной ShellExecute?

    uses ShellAPI; procedure TForm1.Button1Click(Sender: TObject); var ProcInfo: PShellExecuteInfo; begin (Sender as TControl).Enabled := False; GetMem(ProcInfo, SizeOf(ProcInfo^)); with ProcInfo^ do begin Wnd := Handle; cbSize := SizeOf(ProcInfo^); lpFile := PChar('notepad.exe'); lpParameters := nil; lpVerb := 'open'; nShow := SW_SHOW; fMask := SEE_MASK_DOENVSUBST or SEE_MASK_NOCLOSEPROCESS; end; try Win32check(ShellExecuteEx(ProcInfo)); while not Application.Terminated and (WaitForSingleObject(ProcInfo.hProcess, 100)=WAIT_TIMEOUT) do Application.ProcessMessages; finally if ProcInfo.hProcess <> 0 then CloseHandle(ProcInfo.hProcess); Dispose(ProcInfo); (Sender as TControl).Enabled := True; end; end;

  • Q-84: Как использовать OpenGL в своей программе?

    Модули для работы с OpenGL можно взять на http://www.signsoft.com/opengl. Информацию -- на http://www.opengl.org. Также есть книга Ю. Тихомирова "OpenGL: программирование трехмерной графики".
    Еще загляните на http://reality.sgi.com/mjk за примерами и http://www.scitechsoft.com за библиотекой MesaGL.

    Учтите существование эхи RU.OPENGL.

  • Q-85: Как в TMemo вставить дату в позицию каретки?

    Memo1.SetSelTextBuf(PChar(DateToStr(Date)));

  • Q-86: Как отловить системную ошибку при операциях с файлами?

    Для Паскаль функций, например, BlockWrite, можно использовать такую конструкцию:

    try BlockWrite(f, buf, count); //См.также хелп: параметр AmtTransferred .. except on E:EInOutError do begin ShowMessage('Произошла ошибка записи ' + E.Message); ..// пытаемся что-то поправить if {не удалось} then raise; //Повторно возбуждаем исключение, чтобы не удалить файл end; end; .. CloseFile(..); DeleteFile(..);

  • Q-87: Где достать процедуру типа "сумма прописью"?

    (Vladimir Gaitanoff, 2:5020/880.5), http://www.tsinet.ru/~vg. Здесь лежит библиотека vgLib, содержащая еще массу полезных вещей.

  • Q-88: Как узнать, была ли создана ли определенная форма?

    function IndexOfForm (const AClassName: String; const FromIndex: Word):Integer; var i : Integer; begin Result := -1; for i := FromIndex to Screen.FormCount-1 do if (CompareText(Screen.Forms[i].ClassName, AClassName) = 0) then begin Result := i; Break; end; end;

  • Q-89: Какие инструменты можно применить для коллективной разработки проекта?

    CVS. http://www.cyclic.com. С его помощью разрабатывается весьма львиная доля программного обеспечения в Internet. Интеграция с Delphi -- нулевая ;) Крайне рекомендуется. Я лично пользуюсь ею ощутимое время и не представляю себе более разработки без этого средства. "Введение в CVS" можно прочитать на http://alexm.here.ru.

    Microsoft Visual Source Safe. Проигрывает в функциональности, может выигрывать в "привычности".

  • Q-90: Что такое Handle окна, и как его полyчить?

    Handle - это число - уникальный идентификатор окна (в данном случае) в системе. Получить его можно, например, так:

    hwnd := FindWindow (nil, 'Form1'); //ищем окнo с заголовком "Form1" if hwnd <> 0 then {нашлось};

  • Q-91: Как можно обнаружить утечки памяти и ресурсов в программе?

    MSDebug Макса Русова. Hаходится на http://www.dic.ru/users/rusov/. Поддерживает Delphi 3 и выше, ловит только утечки памяти, но делает это хорошо.

    Рекламировался также "MemProof", информацию о котором можно получить на http://www.listsoft.ru/programs/pr1520.htm.

  • Q-92: Как проиграть midi файл?

    uses MPlayer; var mp : TMediaPlayer; procedure TForm1.Button1Click(Sender: TObject); begin with Sender as TButton do case Tag of 0 : begin Tag := 1; mp := TMediaPlayer.CreateParented(Handle); mp.DeviceType := dtSequencer; mp.FileName := 'c:\winnt\media\Canyon.mid'; mp.Wait:= True; mp.Open; mp.Play; end; 1 : begin Tag := 0; mp.Wait := True; mp.Stop; mp.Free; end; end; end;

  • Q-93: Мне нужно заниматься разбором математических выражений

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

    В rxLib есть компонент TrxMathParser, достаточно мощный для большого количества применений.

  • Q-94: Как обратиться к свойству по его имени?

    type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private f1 : Integer; // Это приватное поле хранит значение published {К свойству p1 мы будем обращаться по его имени} property p1 : Integer read f1 write f1; end; var Form1: TForm1; implementation {$R *.DFM} uses TypInfo; procedure TForm1.Button1Click(Sender: TObject); var PInfo : PPropInfo; begin p1 := GetTickCount; // Здесь свойству что-то присвоили PInfo:= GetPropInfo(TForm1.ClassInfo, 'p1'); // Получаем описание свойства из описания класса if PInfo = nil then raise Exception.Create('Property not exist'); Caption := IntToStr(GetOrdProp(Form1, PInfo)); // Получаем значение свойства end;

    uses TypInfo; function ObjPropInfo(AObject: TObject; const PropName: String): PPropInfo; begin Result := GetPropInfo(AObject.ClassInfo, PropName); if Result = nil then raise Exception.Create('Property not exist'); end; procedure SetOrdProperty( AObject: TObject; const PropName:String; const Value: Longint); begin SetOrdProp(AObject, ObjPropInfo(AObject, PropName), Value); end; function GetOrdProperty(AObject: TObject; const PropName:String):Longint; {см. также TypInfo: GetStrProp, GetFloatProp, GetEnumValue etc.} begin Result:= GetOrdProp(AObject, ObjPropInfo(AObject, PropName)); end; procedure SetStrProperty( AObject: TObject; const PropName:String; const Value: String); begin SetStrProp(AObject, ObjPropInfo(AObject, PropName), Value); end; procedure SetFloatProperty( AObject: TObject; const PropName:String; const Value: Extended); begin SetFloatProp(AObject, ObjPropInfo(AObject, PropName), Value); end; procedure SetVariantProperty( AObject: TObject; const PropName:String; const Value: Variant); begin SetVariantProp(AObject, ObjPropInfo(AObject, PropName), Value); end; procedure SetMethodProperty( AObject: TObject; const PropName:String; const Value: Pointer); var AMethod: TMethod; begin AMethod.Code := Value; AMethod.Data := AObject; SetMethodProp(AObject, ObjPropInfo(AObject, PropName), AMethod); end; procedure TForm1.Button1Click(Sender: TObject); var AFont: TFont; begin SetOrdProperty(Button1, 'Width', 100); // целое AFont := TFont.Create; AFont.Style := [fsBold]; SetOrdProperty(Button1, 'Font', Longint(AFont)); // объект AFont.Free; SetMethodProperty(Button1, 'OnClick', @TForm1.Button2Click); // метод end; procedure TForm1.Button2Click(Sender: TObject); begin ShowMessage((Sender as TButton).Caption); end;

  • Q-95: Как уменьшить размер исполняемого файла программы?

    Писать на WinAPI без использования VCL. Это пригодно для и без того крохотных программ. Существуют freeware библиотеки, упрощающие программирование без VCL, например:

    KOL http://xcl.cjb.net
    ACL http://a-press.parad.ru/pc/bokovikov/delphi

    Воспользоваться пакетами (packages) из Delphi 3. Эффект появится, когда исполняемых файлов больше одного.

    Воспользоваться компрессорами исполняемых файлов, например:

    Компрессировать или нет исполняемые файлы, должен решить каждый, так как возможны и негативные моменты от использования сжатия. Дискуссия по этому поводу никогда не прекращается.

  • Q-96: Как нажать Ctrl+Del программным путем?

    Keybd_Event(Vk_Control, 0, 0, 0); Keybd_Event(Vk_Delete, 0, 0, 0); Keybd_Event(Vk_Delete, 0, Keyeventf_Keyup, 0); Keybd_Event(Vk_Control, 0, Keyeventf_Keyup, 0); Keybd_Event(Vk_Control, MapVirtualKey(Vk_Control, 0), 0, 0); Keybd_Event(Vk_Delete, MapVirtualKey(Vk_Control, 0), 0, 0); Keybd_Event(Vk_Delete, MapVirtualKey(Vk_Control, 0), Keyeventf_Keyup, 0); Keybd_Event(Vk_Control, MapVirtualKey(Vk_Control, 0), Keyeventf_Keyup, 0);

  • Q-97: Где достать всяких иконок, картинок для кнопок, etc. для своей программы?

    http://www.iconbazaar.com

  • Q-98: Аналог Case для строк

    Вопрос: Hужно определить с какой из заданных строк совпадает некая строковая переменная и в зависимости от этого перейти к соответсвующей процедуре. Как это выполнить без использования многочисленных if - then?

    Вот способ, легко приспосабливаемый для загрузки списка из строки, файла или ресурса:

    const vlist = 'первый, второй, третий'; var Values: TStringList; procedure SetValues(VL : TStringList; S: String); var I : Integer; begin Values.CommaText := S; for I := 0 to CL.Count-1 do Values.Objects[I] := Pointer(I); Values.Sorted := True; end; function GetValueIndex(VL : TStringList; Match: String): Integer; begin Result := Values.IndexOf(Match); if Result >= 0 then Result := Integer(Values.Objects[Result]); end; procedure TForm1.Button1Click(Sender: TObject); begin case GetValueIndex(Values, Edit1.Text) of -1: {не найден} ; 0: Caption := '0'; 1: Caption := '1'; 2: Caption := '2'; end; end; initialization Values := TStringList.Create; SetValues(Values, vlist); finalization Values.Free;

  • Q-99: Как в TListBox пеpетаскивать итемы?

    DragMode := dmAutomatic; {OnDragOver} procedure TForm1.ListBox1DragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); begin Accept := True; end; {OnDragDrop} procedure TForm1.ListBox1DragDrop(Sender, Source: TObject; X, Y: Integer); var NewIndex : Integer; begin with Sender as TListBox do begin NewIndex := ItemAtPos(Point(X,Y), True); Items.Move(ItemIndex, NewIndex); ItemIndex:= NewIndex; end; end;

  • Q-100: Как отловить нажатие клавиш F1..F10?

    procedure TForm1.AppMessage(var Msg:TMsg; var Handled: Boolean); begin case msg.wParam of VK_F1..VK_F10 : case Msg.message of WM_KEYUP: ShowMessage('Key up'); WM_KEYDOWN: ShowMessage('Key down'); end; end; end; procedure TForm1.FormCreate(Sender: TObject); begin Application.OnMessage := AppMessage; end;

  • Q-101: Как мне работать с файлами MS Word или таблицами MS Excel?

    Воспользоваться функцией CreateOLEObject и работать с VBA (Visual Basic for Applications) или WordBasic.

    NB: Обратите внимание на то, как устанавливаются именованные параметры у процедур WordBasic'а, например, FileOpen(Name := 'myname.doc');

    Пример проверен только на русском Word 7.0! Может, поможет...

    unit InWord; interface uses ... ComCtrls; // Delphi3 ... OLEAuto; // Delphi2 [skip] procedure TPrintForm.MPrintClick(Sender: TObject); var W: Variant; S: String; begin S:=VarToStr(Table1['Num']); //В D3 без промежуточной записи // в var у меня не пошло :( try // А вдруг где ошибка :) W:=CreateOleObject('Word.Basic'); // Создаем документ по шаблону MyWordDot // с указанием пути если он не в папке шаблонов Word W.FileNew(Template:='C:\MyPath\DB\MyWordDot',NewTemplate:=0); // Отключение фоновой печати (на LJ5L без этого был пустой лист) W.ToolsOptionsPrint(Background:=0); // Переходим к закладке Word'a 'Num' W.EditGoto('Num'); W.Insert(S); //Сохранение W.FileSaveAs('C:\MayPath\Reports\MyReport') W.FilePrint(NumCopies:='2'); // Печать 2-х копий finally W.ToolsOptionsPrint(Background:=1); W:=UnAssigned; end; end; {.....}

    Второй путь, более правильный.

    Hужно импортировать TLB библиотеку соответствующего COM-сервера (MS Word, MS Excel, AutoCAD, и т.п.) или воспользоваться готовыми компонентами из палитры Servers поставляемыми с Delphi 5 и

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

    Пример использования TLB.

    program wordemo; {$APPTYPE CONSOLE} uses SysUtils, ActiveX, Word2000, OleCtrls, Variants; var W:TWordApplication; D:_Document; P:Paragraph; FileName:OleVariant; begin CoInitialize(NIL); try // создадим экземпляр объекта-обертки вокруг Word 2000 W:=TWordApplication.Create(NIL); try // создадим новый документ на основе шаблона Normal D:=W.Application.Documents.Add( EmptyParam,EmptyParam,EmptyParam,EmptyParam); // добавим новый параграф P:=D.Paragraphs.Add(EmptyParam); // Запишем туда какой-нибудь текст P.Range.InsertAfter('Hello Word :-)'); // сохраним документ FileName:='wordemo.doc'; D.SaveAs(FileName,EmptyParam,EmptyParam, EmptyParam,EmptyParam,EmptyParam,EmptyParam, EmptyParam,EmptyParam,EmptyParam,EmptyParam); finally // завершим работу Word W.Free; end; finally CoUnInitialize; end; end.

    Замечание от Denver The Marion Hашёл такую интересную закономерность директива W.Free не закрывает MS Word - он остаётся в памяти и висит там (при этом нормально не открывается только что созданные документы). Если изменить строку на W.Quit - всё работает нормально. Рабиралось всё это дело на Delphi 5 и MS Word 2000.

  • Q-102: Как записать в файл несколько TImage?

    procedure TForm1.Button1Click(Sender: TObject); begin with TFileStream.Create(FileName,fmCreate or fmOpenWrite) do begin WriteComponentRes('IMAGE1', image1); WriteComponentRes('IMAGE2', image2); Free; end; end; procedure TForm1.Button2Click(Sender: TObject); begin Image1.Free; Image2.Free; RegisterClass(TImage); Image1 := TImage.Create(Self); Image2 := TImage.Create(Self); with TFileStream.Create(FileName, fmOpenRead) do begin ReadComponentRes(Image1); ReadComponentRes(Image2); Free; end; Image1.Parent:= Self; Image2.Parent:= Self; UnregisterClass(TImage); end;

  • Q-103: Как показать текстовый файл в TLabel?

    procedure TForm1.Button1Click(Sender: TObject); var fs : TFileStream; s : String; begin fs := TFileStream.Create('unit1.pas', fmOpenRead or fmShareDenyNone ); SetLength(s, fs.Size); fs.Read(s[1], Length(s)); fs.Free; Label1.Caption := s; end;

  • Q-104: Delphi 5.0 and Win2K

    1. Если кто не читает readme-файлы до начала установки, то с интересом узнает, что в сопроводиловке от Борланд указывается на проблему неправильной работы инсталлятора, если используются кнопки Browse для смены каталогов установки. При этом рекомендуется набрать/подредактировать пути вручную. (Hе проверял, просто действовал как рекомендовано, хотя пути по умолчанию никогда не использую).

    2. При установке с жесткого диска, весь дистрибутив вместе с папками Runimage и Install надо либо поместить в корень логического диска (что обычно неудобно), либо используя subst (или в сети - use net), сотворить букву для этого пути. Чтобы инсталлятор решил, что установка идет из корня диска. Иначе - облом-с.

    3. При установке на машину, на которой предполагается наличие нескольких программеров, работающих посменно, сначала придется поставить из-под админа - для всех. А потом - из-под каждого аккаунта (хотя бы в режиме Registry + Custom). Иначе не будет компонентов на палитре.

    4. Проверить переменные среды %TEMP% и %TMP%, рекомендуется короткий путь - C:\TEMP

    5. Первичная установка под административным аккаунтом с АHГЛИЙСКИМ именем, например admin

    Можно экспоpтиpовать y админа HKEY_CURRENT_USER/Software/Borland и пpосто импоpтиpовать для каждого потом. Так несколько быстpее, чем инсталиpовать и уменьшается количество ошибок.

  • Q-105: Почему в консольных приложениях неправильно отображаются русские буквы?

    Потому что кодировка шрифтов, используемых в редакторе Delphi - 1251 (ANSI), а в консольных приложениях - 866 (OEM). Чтобы добиться правильного отображения нужно использовать функцию CharToOEM (но при этом возрастёт размер кода), либо сразу писать проект в каком-либо консольном текстовом редакторе (Dos Navigator, Far)

    CharToOem('Привет',TmpStr); Writeln(TmpStr);

  • Q-106: В чем pазличия ShellExecute и CreateProcess?

    ShellExecute может запустить приложение, ассоциированное с расширением файла, например:

    ShellExecute(Handle, 'open', 'mydoc.doc', nil, nil, SW_SHOW);

    запустит Word (или другое приложение, зарегистрованное для *.doc) и откроет файл mydoc.

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

    Hадо заметить, что хендл дочернего процесса может вернуть функция ShellExecuteEx, которая занимает, скажем, промежуточное положение.

  • Q-107: Как вставить картинку в StatusPanel?

    Image1.Parent := StatusBar1;

  • Q-108: Как внедрить dll в другое приложение?

    procedure QryName(threadID: DWord; Caller: HWND); external 'lib0.dll'; procedure TForm1.WMCopydata(var msg: TMessage); // message WM_COPYDATA; begin Caption := PChar(PCopyDataStruct(Pointer(msg.LParam)).lpData); end; procedure TForm1.Button1Click(Sender: TObject); var ahwnd: THandle; begin {Ищем по заголовку} ahwnd := FindWindow(nil, PChar(Edit1.Text)); if ahwnd <> 0 then QryName(GetWindowThreadProcessID(ahwnd, nil), Handle); end;

    - --- lib0.dpr --- library lib0; uses Messages, Windows; function Answer( nCode: Integer; wprm: WParam; lprm: LParam): LResult; stdcall; type PMsg = ^TMsg; var buffer : array [0..MAX_PATH] of Char; cd : TCopyDataStruct; msg : PMsg; Caller : HWND; AHook: HHook; begin Result := 0; msg := PMsg(lprm); if (msg.Message = 0) and (msg.LParam <> 0) then begin AHook := msg.lParam; Caller := msg.wParam; cd.cbData := GetModuleFileName(0, buffer, SizeOf(buffer))+1; cd.lpData := @buffer; cd.dwData := GetCurrentThreadID; SendMessage(Caller, WM_COPYDATA, 0, LParam(@cd)); UnHookWindowsHookEx(AHook); PostThreadMessage(GetCurrentThreadID, 0, 0, 0); end; end; procedure QryName(tid: DWord; Caller: HWND); var AHook : Hhook; begin AHook := SetWindowsHookEx(WH_GETMESSAGE, Answer, Hinstance, tid); if AHook <> 0 then PostThreadMessage(tid, 0, Caller, AHook); end; exports QryName; begin end.

  • Q-109: Как показывать хинты для частично видимых элементов ListBox?

    Hаписать для OnMouseMove:

    procedure TForm1.ListBox1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); const oldidx : Longint = -1; var idx : Longint; begin with Sender as TListBox do begin idx := ItemAtPos(Point(x,y),True); if (idx < 0) or (idx = oldidx) then Exit; Application.ProcessMessages; Application.CancelHint; oldidx := idx; Hint := ''; if Canvas.TextWidth(Items[idx]) > Width - 4 then Hint:=Items[idx]; end; end;

  • Q-110: Как центрировать по форме модальный диалог?

    procedure CenterDialogPos(DlgHandle, WindowHandle: HWND); var DlgRect : TRect; WndRect : TRect; x, y, w, h : integer; begin if (DlgHandle <> 0) then begin GetWindowRect(DlgHandle, DlgRect); GetWindowRect(WindowHandle, WndRect); w := DlgRect.Right - DlgRect.Left; h := DlgRect.Bottom - DlgRect.Top; //center horz x := WndRect.Left + ((WndRect.Right - WndRect.Left - w) div 2); //keep on screen if x < 0 then x := 0 else if x + w > Screen.Width then x := Screen.Width - w; //center vert y := WndRect.Top + ((WndRect.Bottom - WndRect.Top - h) div 2); //keep on screen if y < 0 then y := 0 else if y + h > Screen.Height then y := Screen.Height - h; SetWindowPos(DlgHandle, 0, x, y, 0, 0, SWP_NOACTIVATE or SWP_NOSIZE or SWP_NOZORDER); end; end; procedure TForm1.WMUser1(var msg: TMessage); // message WM_USER+1; begin CenterDialogPos(GetActiveWindow, Handle); end; procedure TForm1.Button1Click(Sender: TObject); begin PostMessage(Handle, WM_USER+1, 0, 0); ShowMessage('Test'); end;

  • Q-111: Чем отличаются TLabel и TStaticText?

    TLabel is TGraphicControl
    TStaticText is TWinControl

    То есть у последнего есть окно, это дает возможность управлять этим контролом с помощью сообщений Windows.

  • Q-112: Как издать звук через PC Speaker?

    // Для HТ вызов функции из ОС, для 9x прямое обращение к портам Procedure BeepEx(Freq: Word; Duration: Integer); var Ver: TOsVersionInfo; begin Ver.dwOSVersionInfoSize := SizeOf(Ver); GetVersionEx(Ver); if Ver.dwPlatformId = VER_PLATFORM_WIN32_NT then Windows.Beep(Freq, Duration) else begin asm movzx ecx, Freq mov eax, 1193180 // тактовая частота sub edx, edx div ecx // преобразование частоты в делитель mov ecx, eax mov al,0b6H out 43H,al // управляющие слово mov al,cl out 42h,al // младший байт делителя mov al,ch out 42h,al // старший байт делителя in al,61H or al,03H out 61H,al // включить звук end; sleep(Duration); // пауза на время звучани asm in al,61H and al,0fcH out 61H,al // выключить звук по окончанию Duration end; end; end;

  • Q-113: Как корректнее завершать приложение- Terminate или MainForm.Close?

    Terminate очень грубый метод. Если вызывать Application.Terminate, то не сработают обработчики OnCloseQuery, OnClose главной формы.

  • Q-114: Как узнать версию Windows?

    Использовать функцию API GetVersionEx

    function GetVersionEx(var lpVersionInformation: TOSVersionInfo): BOOL; stdcall;

    Аргумент функции - структура TOSVersionInfo, содержит DwVersionInfoSize:DWORD - заполняется как sizeof TOSVersionInfo) перед вызовом функции

    DwMajorVersion:DWORD - старшая цифра версии Windows
      Windows 95      - 4
      Windows 98      - 4
      Windows Me      - 4
      Windows NT 3.51 - 3
      Windows NT 4.0  - 4
      Windows 2000    - 5
      Windows XP      - 5
    
    DwMinorVersion: DWORD - младшая цифра версии
      Windows 95      - 0
      Windows 98      - 10
      Windows Me      - 90
      Windows NT 3.51 - 51
      Windows NT 4.0  - 0
      Windows 2000    - 0
      Windows XP      - 1
    
    DwBuildNumber: DWORD
     Win NT 4 - номер билда
     Win 9x   - старший байт - старшая и младшая цифры
     версии / младший - номер билда
    
    dwPlatformId: DWORD
     VER_PLATFORM_WIN32s            Win32s on Windows 3.1.
     VER_PLATFORM_WIN32_WINDOWS     Win32 on Windows 9x
     VER_PLATFORM_WIN32_NT          Win32 on Windows NT, 2000
    
    SzCSDVersion:DWORD
      NT - содержит PСhar с инфо о установленном ServicePack
      9x - доп. инфо, может и не быть

    type TWinVersion = (wvUnknown,wv95,wv98,wvME,wvNT3,wvNT4,wvW2K,wvXP); function DetectWinVersion : TWinVersion; var OSVersionInfo : TOSVersionInfo; begin Result := wvUnknown; OSVersionInfo.dwOSVersionInfoSize := sizeof(TOSVersionInfo); if GetVersionEx(OSVersionInfo) then begin case OSVersionInfo.DwMajorVersion of 3: Result := wvNT3; 4: case OSVersionInfo.DwMinorVersion of 0: if OSVersionInfo.dwPlatformId = VER_PLATFORM_WIN32_NT then Result := wvNT4 else Result := wv95; 10: Result := wv98; 90: Result := wvME; end; 5: case OSVersionInfo.DwMinorVersion of 0: Result := wvW2K; 1: Result := wvXP; end; end; end; end; function DetectWinVersionStr : string; const VersStr : array[TWinVersion] of string = ( 'Unknown', 'Windows 95', 'Windows 98', 'Windows ME', 'Windows NT 3', 'Windows NT 4', 'Windows 2000', 'Windows XP'); begin Result := VersStr[DetectWinVersion]; end; procedure TForm1.Button1Click(Sender: TObject); begin Ver := DetectWinVersion; Label1.Caption := IntToStr(Ord(DetectWinVersion)); Label2.Caption := DetectWinVersionStr; end;

    глобальные переменные
    Win32Platform (в справке), Win32MajorVersion, Win32MinorVersion, Win32BuildNumber (в модуле SysUtils).
    Инициализируются они автоматически, остается только проверить их.

  • Q-115: Как помигать Scroll Lock?
    procedure TForm1.Timer1Timer(Sender: TObject);
    begin
      keybd_event(VK_SCROLL, 0, 0, 0);
      keybd_event(VK_SCROLL, 0, vk_up, 0);
    end;
    
    procedure TForm1.Timer1Timer(Sender: TObject); 
    begin
      keybd_event(VK_SCROLL, MapVirtualKey(VK_SCROLL, 0) , 0, 0);
      keybd_event(VK_SCROLL, MapVirtualKey(VK_SCROLL, 0), vk_up, 0);
    end;
    
    

    Leonid Troyanovsky

  • Q-116: Как из dll узнать узнать полный путь к этой dll.
    function GetModuleFileNameStr(Instance: THandle): String;
    var
      buffer : array [0..MAX_PATH] of Char;
    begin
      GetModuleFileName( Instance, buffer, MAX_PATH);
      Result := buffer;
    end;
    
       GetModuleFileNameStr(Hinstance); // dll name
       GetModuleFileNameStr(0); // exe name
    
    

    Leonid Troyanovsky

  • Q-117: Как отобразить каталог? ListBox1.Perform(LB_DIR, 0, LParam(PChar('*.*')));
  • Q-118: Как узнать кол-во цветов цветовой палитры?

    function GetColorsCount : DWord; var DC : HDC; begin DC := GetDC( 0 ); Win32Check(DC <> 0); Result :=1 shl (GetDeviceCaps(DC, PLANES) * GetDeviceCaps(DC, BITSPIXEL)); ReleaseDC( 0, DC ); end;

    Leonid Troyanovsky

  • Q-119: Как ввести текст в "чужой" Edit?

    SendMessage(EditHandle, WM_SETTEXT, 0, LParam(PChar('MyText')));

  • Q-120: Как заставить мигать кнопку приложения на AppBar?

    procedure TForm1.Timer1Timer(Sender: TObject); begin FlashWindow(Application.Handle, True); end;

    Leonid Troyanovsky >

  • Q-121: Как сделать программу без главной формы?

    program Project1; uses Dialogs; begin ShowMessage('Is there anybody out there ?' ); end.

  • Q-122: Как убрать VerticalScrollBar из TListBox навсегда?

    procedure TListBoxForEver.CreateParams (var Params: TCreateParams); //override begin inherited CreateParams(Params); Params.Style := Params.Style and not WS_VSCROLL; end;

    Leonid Troyanovsky

  • Q-123: Как показать диалог выбора директории?

    из модуля FileCtrl.
    1. function SelectDirectory(const Caption: string; const Root: WideString; out Directory: string): Boolean; overload;
    2. function SelectDirectory(var Directory: string; Options: TSelectDirOpts; HelpCtx: Longint): Boolean; overload;

    из RxLib TDirectoryEdit

    function GetDirectory(nFolder: Longint): String; var Bi : TBrowseInfo; lpName: array [0..MAX_PATH] of Char; ppidl, aItemLst : PItemIDList; begin SHGetSpecialFolderLocation(Application.Handle, nFolder, ppidl); FillChar(Bi, SizeOf(bi), 0); Bi.hwndOwner := Application.Handle; Bi.pidlRoot := ppidl; Bi.pszDisplayName := lpName; Bi.lpszTitle := 'Open directory'; aItemLst := SHBrowseForFolder(Bi); CoTaskMemFree(ppidl); SHGetPathFromIDList(aItemLst, lpName); CoTaskMemFree(aItemLst); Result := lpName; end;

    Пример использования (иначе не поймут, что такое nFolder)

    // значения nFolder можно найти в описании // к SHGetSpecialFolderLocation // из Win32 Programmer's Reference (win32.hlp) procedure TForm1.Button1Click(Sender: TObject); begin Caption := GetDirectory(CSIDL_DRIVES); end;

  • Q-124: Как убрать из ListView горизонтальный скролбар навсегда?

    type TNoHScrollListview = Class( TListview ) private Procedure WMNCCalcSize( Var msg: TMessage ); message WM_NCCALCSIZE; end; procedure TNoHScrollListview.WMNCCalcSize(var msg: TMessage); var style: Integer; begin style := getWindowLong( handle, GWL_STYLE ); If (style and WS_HSCROLL) <> 0 Then SetWindowLong( handle, GWL_STYLE, style and not WS_HSCROLL ); inherited; end;

  • Q-125: Кaк искать oкнo по части eгo нaзвaния?

    function FindNextWnd(StartHWND: HWND; AString : String): HWND; var Buffer : array [0..255] of char; begin Result := StartHWND; repeat Result := FindWindowEx(0, Result, nil, nil); GetWindowText(Result, Buffer, SizeOf(Buffer)); if StrPos(StrUpper(Buffer), PChar(UpperCase(AString))) <> nil then Break; until (Result = 0); end;

  • Q-126: Как обнаружить активность юзера?

    Application.OnMessage := DoMessageEvent; procedure TForm1.DoMessageEvent ( var Msg: TMsg; var Handled: Boolean); begin case Msg.message of WM_KEYFIRST..WM_KEYLAST, WM_MOUSEFIRST..WM_MOUSELAST: {Произошли события клавиатуры и мыши}; .. end; end;

    Leonid Troyanovsky

  • Q-127: Как yзнать текущую Ru/En pаскладкy клавиатypы?

    GetKeyboardLayoutName(buffer{:array [0..KL_NAMELENGTH] of Char}); case ((StrToInt('$'+ Buffer)) and $03FF) of LANG_ENGLISH: Caption := 'Eng'; LANG_RUSSIAN: Caption := 'Rus'; end; procedure TForm1.Button1Click(Sender: TObject); var AklName: array [0..2] of Char; begin GetLocaleInfo( LoWord(GetKeyboardLayout(0)), LOCALE_SABBREVLANGNAME, AklName, SizeOf(AklName)); Caption := AklName; end;

    Leonid Troyanovsky

  • Q-128: Как передать строку другому приложению?

    получатель: procedure ReceiveMessage (var Msg: TMessage); message WM_COPYDATA; .. procedure TFormReceive.ReceiveMessage; var pcd : PCopyDataStruct; begin pcd := PCopyDataStruct(Msg.LParam); Caption := PChar(pcd.lpData); end; отправитель: procedure TFormXXX.Button1Click(Sender: TObject); var cd : TCopyDataStruct; begin cd.cbData := Length(Edit1.Text)+1; cd.lpData := PChar(Edit1.Text); SendMessage ( FindWindow('TFormReceive', nil), WM_COPYDATA, 0, LParam(@cd)); end;

    Leonid Troyanovsky

  • Q-129: Как RichEdit сделать скролл на конец текста?

    with RichEdit do begin SelLength := 0; SelStart := Length(Text); Perform(EM_SCROLLCARET,0,0); end;

  • Q-130: Удаление файлов из временного каталога, безопасно ли?

    При получении имени папки предназначенной для хранения временных файлов могут возникнуть ytrjnhst проблемы. Прекрасно это выглядит, когда в качестве каталога временных файлов назначен например C:\Windows

    Особенно пикантно это выглядит, в свете того, что

    Remarks
    Windows 95/98/Me: The GetTempPath function gets the temporary file path as follows:

    The path specified by the TMP environment variable. The path specified by the TEMP environment variable, if TMP is not defined or if TMP specifies a directory that does not exist. The current directory, if both TMP and TEMP are not defined or specify nonexistent directories. Этак переименовываешь C:\TEMP - и программа чистит текущий каталог :-)

    Windows NT/2000 or later: The GetTempPath function does not verify that the directory specified by the TMP or TEMP environment variables exists. The function gets the temporary file path as follows:

    The path specified by the TMP environment variable. The path specified by the TEMP environment variable, if TMP is not defined. The Windows directory, if both TMP and TEMP are not defined.

    Этак удаляешь переменные окружения - и программа "деинсталлирует" Windows

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

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

    Тенцер А.Л.
    Andrew V. Fionik
    Anatoly Podgoretsky

  • Q-131: Как узнать состояние управляющих клавиш - Shift, Ctrl, Alt?

    function IsKeyDown(vk: Word):Boolean; begin Result := GetKeyState(vk) and $8000 = $8000; end;

    vk для Ctrl, Shift, Alt соответственно равны: vk_control, vk_shift и vk_menu

  • Q-132: Как сохранить всю форму в файл (как Delphi в *.dfm)?

    constructor TForm1.Create(AOwner: TComponent); // override; var fname: String; begin { Для динамически создаваемых контролов, может требоваться RegisterClasses(..); } fname := FormFilename; if FileExists( fname ) then begin CreateNew(AOwner); ReadComponentResFile(fname, Self); end else inherited Create( AOwner ); end; procedure TForm1.FormCloseQuery( Sender: TObject; var CanClose: Boolean); begin WriteComponentResFile(FormFileName, Self); end;

    {Peter Below, Vladimir Titov}

  • Q-133: Как контрол может сам себя разрушить?

    TMyWinControl = class(TWinControl) private procedure WMuser1(var msg: TMessage); message WM_USER+1; ... public procedure Release; ... end; procedure TMyWinControl.WMuser1; begin Free; end; procedure TMyWinControl.Release; begin PostMessage(Handle, WM_USER+1, 0, 0); end;

  • Q-134: Как отследить переход фокуса в приложении?

    procedure TForm1.AppControlChange(Sender: TObject); begin if Sender is TScreen then Caption := TScreen(Sender).ActiveForm.ActiveControl.Name; end; procedure TForm1.FormCreate(Sender: TObject); begin Screen.OnActiveControlChange := AppControlChange; end;

    Leonid Troyanovsky

  • Q-135: Как заставить MediaPlayer крутить один и тот же клип?

    procedure TForm1.WMUser1(var msg:TMessage);// message WM_USER+1; begin with MediaPlayer1 do begin Previous; Notify := True; Play; end; end; procedure TForm1.MediaPlayer1Notify(Sender: TObject); begin if (Sender as TMediaPlayer).NotifyValue = nvSuccessful then PostMessage(Handle, WM_USER+1, 0, 0); end;

  • Q-136: Как назначить процедуру собственному пункту системного меню?

    const cm_mycommand = $00A0; procedure TForm1.FormCreate(Sender: TObject); var HSysMenu: HMENU; begin HSysMenu:=GetSystemMenu(Handle,FALSE); InsertMenu( HSysMenu, 0, MF_BYPOSITION or MF_STRING, cm_mycommand, 'MyString'); end; procedure TForm1.WMSysCommand (var Message: TWMSysCommand); // message WM_SYSCOMMAND; begin case Message.CmdType of cm_mycommand: ShowMessage('My Command'); else inherited; end; end;

    Leonid Troyanovsky

  • Q-137: Какой класс окна у консоли?

    'tty' for 9x 'ConsoleWindowClass' for NT

  • Q-138: Какое сообщение надо отлавливать в Application.OnMessage для отслеживания клавиши Alt (vk_menu)

    WM_SYSKEYDOWN/WM_SYSKEYUP

  • Q-139: Как спрятать контрол, если известен его Handle?

    ShowWindow(ButtonHandle, SW_HIDE); // SW_SHOW

  • Q-140: Как поменять иконку и стpокy в заголовке консольного окна?

    procedure TForm1.Button1Click(Sender: TObject); var h : HWND; AIcon : TIcon; begin AllocConsole; SetConsoleTitle(PChar('Console Title')); Sleep(0); h := FindWindow(nil, PChar('Console Title')); AIcon := TIcon.Create; ImageList1.GetIcon(0, AIcon); SendMessage(h, WM_SETICON, 1, AIcon.Handle); AIcon.Free; end;

    Leonid Troyanovsky

  • Q-141: Как сделать окно без VCL?

    program Project1; { Copyright (c) 1996 by Charlie Calvert Standard Windows API application written in Object Pascal. No VCL code included. This is all done on the Windows API level. Note that you need to include both Windows and Messages!} uses Windows, Messages; const AppName = 'Window1'; function WindowProc(Window: HWnd; AMessage, WParam, LParam: Longint): Longint; stdcall; begin WindowProc := 0; case AMessage of wm_Destroy: begin PostQuitMessage(0); Exit; end; end; WindowProc := DefWindowProc(Window, AMessage, WParam, LParam); end; { Register the Window Class } function WinRegister: Boolean; var WindowClass: TWndClass; begin WindowClass.Style := cs_hRedraw or cs_vRedraw; WindowClass.lpfnWndProc := @WindowProc; WindowClass.cbClsExtra := 0; WindowClass.cbWndExtra := 0; WindowClass.hInstance := HInstance; WindowClass.hIcon := LoadIcon(0, idi_Application); WindowClass.hCursor := LoadCursor(0, idc_Arrow); WindowClass.hbrBackground := HBrush(Color_Window); WindowClass.lpszMenuName := nil; WindowClass.lpszClassName := AppName; Result := RegisterClass(WindowClass) <> 0; end; { Create the Window Class } function WinCreate: HWnd; var hWindow: HWnd; begin hWindow := CreateWindow(AppName, 'Object Pascal Window', ws_OverlappedWindow, cw_UseDefault, cw_UseDefault, cw_UseDefault, cw_UseDefault, 0, 0, HInstance, nil); if hWindow <> 0 then begin ShowWindow(hWindow, CmdShow); UpdateWindow(hWindow); end; Result := hWindow; end; var AMessage: TMsg; hWindow: HWnd; begin if not WinRegister then begin MessageBox(0, 'Register failed', nil, mb_Ok); Exit; end; hWindow := WinCreate; if hWindow = 0 then begin MessageBox(0, 'WinCreate failed', nil, mb_Ok); Exit; end; while GetMessage(AMessage, 0, 0, 0) do begin TranslateMessage(AMessage); DispatchMessage(AMessage); end; Halt(AMessage.wParam); end.

  • Q-142: Как избежать повторного запуска моего приложения?

    type TForm1 = class(TForm) Memo1: TMemo; procedure FormCreate(Sender: TObject); private { Private declarations } procedure WMCopyData(var msg: TMessage); message WM_COPYDATA; public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} uses checkinst; procedure TForm1.FormCreate(Sender: TObject); var h : HWND; begin h := SetUniqueUID(Handle, 123456); // назначаем уникальный идентификатор if h <> Handle then begin SendString(h, GetCommandLineStr, Handle, 0); ActivatePrevInstance(h); Halt; end; end; procedure TForm1.WMCopyData; begin Memo1.Lines.CommaText:=PChar(PCopyDataStruct(msg.LParam).lpData); end;

    ----------------checkinst.pas----------------- unit checkinst; interface uses Windows, Messages, Sysutils; function SetUniqueUID(ahwnd: HWND; uid: DWord): HWND; procedure ActivatePrevInstance(ahwnd: HWND); procedure SendString(ahwnd:HWND; const s: String; aWParam: WParam; dwData:DWord); function GetCommandLineStr: String; implementation function SetUniqueUID(ahwnd: HWND; uid: DWord): HWND; var ClassName: array [0..255] of Char; begin GetClassName(ahwnd, ClassName, SizeOf(classname)); Result := FindWindowEx(0, 0, ClassName, nil); while (Result <> 0) do if GetProp(Result, 'UID') = uid then Exit else Result := FindWindowEx(0, Result, ClassName, nil); SetProp(ahwnd, 'UID', uid); Result := ahwnd; end; procedure ActivatePrevInstance(ahwnd: HWND); var h : HWND; begin h := GetWindowLong(ahwnd, GWL_HWNDPARENT); if IsIconic(h) then ShowWindow(h, SW_RESTORE); SetForegroundWindow(h); end; procedure SendString(ahwnd:HWND; const s: String; aWParam: WParam; dwData:DWord); var cds: TCopyDataStruct; begin cds.cbData := Length(s)+1; cds.lpData := Pointer(s); cds.dwData := dwData; SendMessage(ahwnd, WM_COPYDATA, aWParam, LParam(@cds)); end; function GetCommandLineStr: String; var i : Integer; begin for i := 0 to ParamCount do Result := Result + ' ' + AnsiQuotedStr(ParamStr(i), '"'); end; ----------------EOF checkinst.pas----------------

    //Вариант с Мьютексом //В файле проекта (.dpr) прямо можешь написать нечто вроде: uses windows,... var H: THandle; begin H := CreateMutex(nil, True, 'уникальное_имя_для_твоей_проги'); if GetLastError = ERROR_ALREADY_EXISTS then begin H := FindWindow(nil, 'название заголовка окна программы'); SetForegroundWindow(H); Exit; end; Application.Initialize; Application.Title := 'название заголовка окна программы'; Application.CreateForm(TAppData, AppData); Application.CreateForm(TMain, Main); Application.Run; CloseHandle(H); end;

    Прочко Денис Владимирович. sysadmin@)farmeko.khv.ru

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

  • Q-143: Как записать массив в файл?

    with TFileStream.Create('array.dat', fmCreate or fmOpenWrite) do begin WriteBuffer(a, SizeOf(a)); Free; end;

  • Q-144: Delphi 6 требует Proxies.pas?

    {$ifdef D_6_UP} // Это моя константа DesignIntf, DesignEditors, DesignWindows, DsnConst, {$else} DsgnIntf, {$endif}

    Вопрос: Файл designeditors.pas использует 'proxies' в uses. Исходный текст (proxies.pas) или откомпилированный модуль (proxies.dcu) нигде не находится ни на моем жеском диске ни на D6 Pro CD..

    Просто реорганизуйте ваш проект на использование runtime пакетов и добавьте "DesignIDE" к вашемк списку runtime пакетов. Proxies находится здесь, и вам не нужен исходный текст вообще.

    Почему это сделано? Просто доя уверенности, что вы не сможете распространять design time части (property editors, component editors), это запрещено по личензии. DesignIDE.bpl не является свободно распространяемым, вы имеете право использовать его только на машине на которой установлена Delphi, подобно Component libraries.


    forums.borland.com
  • Q-145: О библиотеке RxLib

    Hа сайте delphiplus.org в разделе Бесплатно|RXLibrary (http://delphiplus.spils.lv/RXLibrary.html) лежит RX Library 2.75 с help'ами и четырьмя неофициальными портами RX Library 2.75 под Delphi 6:

    1. Версия 1.1 (1.18M) от Oxygen Software
    2. Патч на RxLib версия 1.5 (437K) от Polaris Software
    3. Версия от Epsylon Technologies

    Здравствуйте! Мы были вынуждены сделать свой вариант RxLib потому, что остальные нас немного не устраивали. Сразу скажу, зачем нам вообще нужна библиотека RxLib - она используется в нашем продукте в качестве некоего примера всем известных компонентов. Поэтому к такой библиотеке с нашей стороны предъявлялось требование максимальной стандартности, если можно применить такой термин. Кроме того, наш продукт поддерживает несколько версий Delphi и C++Builder, поэтому от такой библиотеки требуется одновременная поддержка всех нужных нам версий компиляторов.

    Естественно, мы рассматривали варианты использования уже готовой работы по адаптированию библиотеки под Delphi 6.0. Однако:

    - вариант от Polaris заточен для использования пакета Polaris Library. Туда что-то добавлено, что-то починено, что-то переделано. Иначе говоря, этот вариант не может быть стандартным;

    - вариант от Oxygen является версией ТОЛЬКО под Delphi 6.0, содержит ряд мелких неточностей при переводе design-time кода. Также там что-то изменено по сравнению с 2.75. Кроме того, не переименован модуль AppUtils.pas;

    - вариант от Dennis Ortiz также является версией только под Delphi 6.0. Hичего не могу сказать про нее - мы туда глубоко не заглядывали.

    Hе совсем понятно, зачем выкидывать из библиотеки возможность поддержки предыдущих версий Delphi, когда добавить вариант кода для Delphi 6.0 ничуть не сложнее. Hикто также не против исправления каких-либо ошибок в библиотеке, но давайте делать это централизованно, если уж авторы забили на свое детище. Hапример, через тот же Source Forge.

    Hаш вариант основан на общедоступном коде, и содержит модули из 2.75, включая update от 16.12.1999 и патч для C+Builder 5.0 от 30.05.2000. В эти модули добавлена возможность работы под Delphi 6.0, в том числе добавлен макрос RX_D6 и переименованы модули AppUtils и StrUtils. Все. Hичего больше. Hикакая старая функциональность не удалена, никакие баги не чинились. Полдня работы.

    -- Andrey Dementyev, Epsylon Technologies, http://www.epsylontech.com Chief Software Architect

    Информация от delphiplus

    1. C 19-ого декабря компания SGB Software совместно с Hиком Ходж (Nick Hodges) из Borland support team займется дальнейшим развитием RxLib. Hадеются выпустить 3-ю версию к середине марта 2002 года. Все желающие могут принять участие в этой работе, для этого достаточно написать на RxLIb@SGBSoftware.com.

    2. Hа DelphiPlus выложен материал "A где сейчас RXLib?" - заметка написанная по материалам переписки в эхе fido7.ru.delphi. Hаконец эта история получила завершение, афера SGB Software лопнула, но RXLib не погибла, а вошла в состав более крупного проекта Jedi Code Library, за эти руки нет опасения, все подробности на сайте delphiplus.org, благодаря которому мы были постянно в курсе событий всех приключений с RXLib, спасибо.

  • Q-146: Как хранить настройки программ.

    Hижеприведенный текст являет собой вольное изложение отдельных статей февральского выпуска Microsoft Platform SDK. Год 2001 от рождества Христова. При проектировании способов хранения настроек своей программы следует задаться тремя вопросами:

    • Что хранить.
    • Где хранить.
    • Как хранить.
    Что хранить

    Поскольку первая часть вопроса нам известна по определению, т.е. хранить мы будем настройки программы, то перейдем ко второй части вопроса. Ваша программа устанавливается на КОМПЬЮТЕР а пользуются ей ПОЛЬЗОВАТЕЛИ. Соответственно все настройки разделяются на две части а то и на все три - настройки которые относятся к компьютеру в целом, настройки которые относятся ко всем локальным пользователям, настройки которые относятся к конкретному пользовател. В зависимости от специфики программы первая и вторая часть могут быть совмещены или разделены. Поэтому важно сделать логическое разделение - какие настройки вашей программы действительно специфичны для самого ПК, какие настройки должны прилагаться ко всем пользователям, какие должны прилагаться к конкретному пользователю. Кроме того Мокрософт рекомендует чтобы настройки учитывали возможную мобильность пользователя, т.е. для пользователя находящегося в разных местах, возможно потребуется иметь разные наборы настроек.

    Где хранить
      Вообще в голову приходят три вещи.
    • Хранить настройки в системном реестре.
    • Хранить настройки в каталоге куда установлена программа.
    • Хранить настройки в системном каталоге Windows.
    • Хранить настройка в домашнем каталоге пользователя.

    В Windows имеется три места предназначенных для хранения настроек которыми и следует пользоваться.


    Системный реестр
    Домашний каталог пользователя (точнее один из его подкаталогов)
    Общий каталог для пользователей

    Прочие мысли о местах хранения настроек должны быть выброшены из голов как вредные и противоестественные, Microsoft уже за вас все придумала и нефиг извращаться. Для тех кто не понимает почему, объясняю. Hа нормальной ОС (W'NT, W'2K) программа обычно запускается от имени и с правами конкретного пользователя. Обычно, если этот пользователь не является администратором, он имеет право изменять содержимое следующих ресурсов: часть реестра HKEY_CURRENT_USER\* содержимое своего домашнего каталога содержимое временного каталога (который как правило находится внутри домашнего) содержимое некого каталога или каталогов специально выделенного для этого администратором

    При нормальном (читайте параноидальном) администрировании системы прочие места либо доступны только в режиме чтения, либо вообще недоступны. В том числе и папки \Program Files и Windows. Посему любая попытка программы изменять любые файловые ресурсы окромя вышеуказанных черевата тем что ее (программу) и его (пользователя) пошлют подальше. Причем далеко не в самой вежливой форме.

    Пример Adobe Photoshop и его разработчики наивно полагают что им должны быть выданы эксклюзивные права мусорить своими scratch-файлами в корневых каталогах дисков, кроме того они полагают что им должна быть выдана в пользование в режиме полный доступ часть системного реестра.. Временных каталогов, специально выделенных для подобоного рода занятий, их не устраивает. Как результат - Photoshop имеет серьезные проблемы с работой под Windows NT/2000.

    Системный реестр С точки зрения хранения настроек программы системный реестр разделен на две части. Это ветви HKEY_CURRENT_USER для хранения настроек специфичных для пользователя, и HKEY_LOCAL_MACHINE для хранения настроек специфичных для всего ПК и соответственно всех пользователей, работающих с этим ПК. Рекомендуемая структура ветвей для хранения настроек программы - HKEY_CURRENT_USER\Software\Company Name\Application Name\Version и соответственно HKEY_LOCAL_MACHINE\Software\Company Name\Application Name\Version. Параметры Company Name, Application Name, Version желательно не хранить в виде hard-coded строк в коде программы а устанавливать в опциях проекта (Project\Options\Version Info) и доставать впоследствии из ресурса с помощью той же библиотеки RxLib. Альтернативный путь выбирать данные о версии программы из ресурсов - использование Windows API (GetFileVersionInfo, GetFileVersionInfoSize, VerQueryValue). Программе следует расчитывать на то что доступ к подключам HKEY_LOCAL_MACHINE разрешен в режиме только для чтения, а доступ к подключам HKEY_CURRENT_USER допускает чтение, изменение и создание новых подключей и значений.

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

    Домашний каталог пользователя Для хранения настроек слишком больших для того чтобы их размещать в реестре существуют специально выделенные каталоги внутри домашнего каталога пользователя. Эти каталоги обычно называются "специальными каталогами" и имеют имена Application Data и Local Settings. Полный путь к ним можно получить с помошью функций SHGetSpecialFolderPath или SHGetFolderPath.

    Общий каталог пользователей. Обычно это каталог "Documents and Settings\All users". Внутри него имеются такие-же подкаталоги для хранения настроек и данных программ но относящихся ко всем пользователям. Полный путь к ним можно также получить с помошью функций SHGetSpecialFolderPath или SHGetFolderPath.

    Как хранить

    Системный реестр. Для работы с системным реестром можно использовать функции Registry API общим числом около 40 штук, а можно использовать классы из Registry.pas - TRegistry, TRegistryIniFile, TRegIniFile. Особенно следует обратить внимание на TRegistryIniFile который предоставляет упрощенную модель доступа к системному реестру очень схожую с моделью работы с INI-файлами.

    INI-файлы Это старый метод хранения настроек программ, но все еще применяющийся программистами. Hастройки хранятся в текстовом файле в виде:

    [Section1] Field1=Value1 Field2=Value2 ... FieldN=ValueN [Section2] Field1=Value1 Field2=Value2 ... FieldN=ValueN ... [SectionN] Field1=Value1 Field2=Value2 ... FieldN=ValueN

    Для доступа к данным содержащимся в INI-файлах существуют классы из модуля IniFiles - TIniFile, TMemIniFile. Преимущество использования INI-файлов состоит в том что их можно легко подредактировать с помощью текстового редактора. Они обычно легче воспринимаются для прочтения нежели дерево ключей системного реестра.

    Бинарные файлы настроек Отдельно хочется поговорить о использовании бинарных файлов в качестве хранилища для настроек программы. Обычные мотивы любителей использовать бинарные файлы:


    Экономится место
    Hастройку можно спрятать от пользователя (сделать нечитабельной)

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

    Заключение

    Почти вся эта информация была вычерпана из кладезя мудрости под названием Platform SDK (Software Development Kit), поставляемого в составе сборника документации MSDN (Microsoft Software Developer Network). Разработчикам настоятельно рекомендуется приобрести Platform SDK, это снимает огромную массу вопросов связанную с программированием под Windows.

  • Q-147: Как вывести ProgresBar на StatusBar?

    Gauge:=TGauge.Create(Form1); Gauge.Parent:= StatusBar1; Gauge.Top:=4; Gauge.Left := 116; Gauge.Height := 15; Gauge.Width := 200;

    Компонент TGauge находится на закладке Samples

  • I-148: Список рекомендуемой литературы
    1. А. Архангельский, В. Ильин, М. Тагин
    Русская справка (HELP) по Delphi 5 и Object Pascal (32 стр. с CD-ROM)
    Бином, ISBN 5-7989-0168-8
    
    2. А. Архангельский. Программирование в Delphi 5
    Бином, ISBN 5-7989-0104-1
    
    3. А. Архангельский. Программирование в Delphi 6
    Бином, ISBN 5-7989-0227-7
    
    4. П. Даpахвелидзе, Е. Маpков
    Delphi 4 в подлиннике
    
    
    
    5. П. Дарахвелидзе, Е. Марков, О. Котенок
    Программирование в Delphi 5
    BHV-СПб, ISBN 5-8206-0052-5
    
    6) П.В. Шумаков, В.В. Фаронов "Delphi xx. Руководство разработчика баз
    данных."
    
    7) М.Кэнту
    Delphi 4 для пpофессионалов
    
    8. Ч.Калвеpт
    Delphi 4, Энциклопедия пользователя
    
    9. Стив Тейксейра, Ксавье Пачеко
    Delphi 5. Руководство разработчика. Том 1.
    Основные методы и технологии программирования
    Вильямс, ISBN 5-8459-0016-6
    2000 Вильямс
    
    10. Стив Тейксейра И Ксавье Пачеко
    Delphi 5. Руководство разработчика. Том 2.
    Разработка компонентов и работа с базами данных
    2000 Вильямс
    ISBN 5-8459-0066-2
    
    11. Конопка Рей
    Создание оригинальных компонент в среде Delphi: Пер. с англ./Рей Конопка.
    К.: HИПФ - "ДиаСофт Лтд.", 1996. - 512 с.
    ISBN 5-7707-9551-4
    
    12. Лишнер Рэй
    Секреты Delphi 2: Пер. с англ./Рэй Лишнер. -
    К.: HИПФ - "ДиаСофт Лтд.", 1996. - 800 с.
    ISBN 966-7033-10-4
    
    13. Том Сван "Секреты 32-разрядного программирования в Delphi"
    Диалектика, Киев, 1997. 480 стр.,
    ISBN 966-506-052-X (рус.)
    
    14. Дэн Оузьер "Дельфи 2. Освой самостоятельно."
    Восточная Книжная Компания,
    1997. 624 стр. Binom.
    
    15. Михаил Кpаснов. DirectX Гpафика в пpоектах Delphi
    BHV
    ISBN-5-94157-033-3

    В списке отсутствует ряд хороших книг, по причине недостаточнысти данных, если у кого есть замечания, исправления или дополнения по данной статье, то просьба посылать их прямо на mailto: faq@nps.vnet.ee

    Hовые книги можно искать и заказывать через Интернет на сайте http://books.ru Там же как правило есть аннотация.

    Кроме указанных книг существует большое количество ресурсов в Интернете посвященных Дельфи - это статьи, электронные библиотеки и прочее. Один из ресурсов расположен на моем сайте - это несколько проектов электронных библиотека, в совокупности свыше 200 книг. Доступ ко всем проектам прямо с главной страницы http://www.podgoretsky.com, существует так же доступ и по FTP (3 анонимных сессии)

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

  • Q-149: Как нажать клавиши в другом приложении?

    "Hажимаем" клавиши в Блокноте (уже запущенном):

    uses Sendkey; {описан ниже} procedure TForm1.Button1Click(Sender: TObject); var h: HWND; begin h := FindWindow('Notepad', nil); // ищем окно Блокнота SendMessage(h, WM_SYSCOMMAND, SC_HOTKEY, h); // активизируем его PlayKeys(StrToKeys('abcdef')); // нажимаем клавиши SendMessage(Handle, WM_SYSCOMMAND, SC_HOTKEY, Handle); // возвращаем фокус end;

    Коды vk_ клавиш можно найти в Win32 Programmer's Reference (win32.hlp): Virtual-Key Codes. {В дельфи не описаны коды клавиш ['A'..'Z'] и ['0'..'9'], их получают с помощью Ord, например, Ord('A'), Ord('9')}.

    Символы из верхнего ряда клавиатуры посылаются с нажатым Shift. Заметим, что символы в локальной кодировке могут быть посланы после переключения кодировки в активном приложении, например, если перключатель (switch) Control-Shift, то это:

    PlayKeys(Chr(vk_control)+#0+Chr(vk_shift)+#0); {downkey = #0}; - --- unit Sndkey.pas --- unit sndkey; interface uses Windows, Messages; const {VK constants missing from windows.pas} VK_SEMICOLON = 186; {;} VK_EQUAL = 187; {=} VK_COMMA = 188; {,} VK_MINUS = 189; {-} VK_PERIOD = 190; {.} VK_SLASH = 191; {/} VK_BACKQUOTE = 192; {`} VK_LEFTBRACKET = 219; {[} VK_BACKSLASH = 220; {\} VK_RIGHTBRACKET = 221; {]} VK_QUOTE = 222; {'} downkey = #0; upkey = Chr(KEYEVENTF_KEYUP); {#2} procedure PlayKeys(const keys: String); function StrToKeys(const s: String): String; {Alt-F4: PlayKeys(Chr(vk_menu)+#0+Chr(vk_f4)+#0+Chr(vk_f4)+#2+Chr(vk_menu)+#2)} {"exit"<return>: PlayKeys(StrToKeys('exit'+chr(vk_return)));} {"EXIT": PlayKeys(Chr(vk_shift)+downkey+StrToKeys('exit')+Chr(vk_shift)+upkey));} {or short form: PlayKeys(Chr(vk_shift)+#0+StrToKeys('exit'));} implementation function StrToKeys; {keystroke for alone keys} var i: Longint; c: Char; begin for i := 1 to Length(s) do begin c := s[i]; if c in ['a'..'z'] then {Upper} c := Chr(Ord(c) and not $20); Result := Result + c + downkey + c + upkey; end; end; procedure PlayKeys; const ExtendedKeys : set of byte = [ vk_up, vk_down, vk_left, vk_right, vk_home, vk_end, vk_prior, vk_next, vk_insert, vk_delete]; var i, ips : Longint; fb, sb: Byte; keysdown: String; procedure keybd (vk, kp : Byte); begin if vk in ExtendedKeys then kp := kp + KEYEVENTF_EXTENDEDKEY; keybd_event(vk, MapVirtualKey(vk, 0), kp, 0); end; begin keysdown := ''; for i := 1 to Length(keys) div 2 do begin fb:= Ord(keys[2*i -1]); sb:= Ord(keys[2*i]); if sb = Ord(downkey) then keysdown := keysdown + Chr(fb) else begin ips := pos(Chr(fb), keysdown); if ips > 0 then Delete(keysdown, ips, 1) else Continue; end; keybd(fb, sb); end; {Autocomplete} for i := 1 to Length(keysdown) do keybd(Ord(keysdown[i]), Ord(upkey)); end; end. - --- EOF unit Sndkey.pas ---

    Leonid Troyanovsky

  • Q-150: Как перетащить файлы из проводника в мою программу TMainForm = class(TForm) ... private procedure WMDROPFILES(var Message: TWMDROPFILES); message WM_DROPFILES; procedure ProcessFile(Filename: string); end; procedure TMainForm.FormCreate(Sender: TObject); begin DragAcceptFiles(MainForm.Handle, TRUE); // enable drag&drop end; procedure TMainForm.ProcessFile(Filename: string); begin // any actions end; procedure TMainForm.WMDROPFILES(var Message: TWMDROPFILES); var Files : Longint; I : Longint; Buffer : array[0..MAX_PATH] of Char; begin Files := DragQueryFile(Message.Drop,$FFFFFFFF,nil,0); // Get count of files for I := 0 to Files - 1 do begin DragQueryFile(Message.Drop,I,@Buffer,SizeOf(Buffer)); // Get N file ProcessFile(Buffer); // do something with the file end; DragFinish(Message.Drop); // end drag loop end;

    Anatoly Podgoretsky

  • Q-151: Как использовать в Дельфи API фyнкции

    AA> как это ни странно, вызывать их. предварительно заюзав модуль windows. Правильнее : вызвать, предварительно подключив модуль, в котором данная функция описана (это может быть windows, activex, shellapi и т.д.). Hайти модуль поможет клавиша F1 на имени функции.

    Если функция не нашлась - то попробовать сделать поиск в папке с исходными текстами Дельфи.

    Если функция не нашлась - есть шанс, что в этой версии Дельфи она не описана. В этом случае надо поискать "заголовочный файл" (API header file) в интернете. Огромная коллекция их находится на сайте www.delphi-jedi.org.
    Если не помогло и это - придется взять описание функции из документации производителя данного API (обычно оно на С) и самому сделать ее обьявление, так же, как это сделано в windows.pas, только в своем юните.

    Сергей Кабиков

  • Q-152: Автоматическое определение кодировки текста

    AG> Существуют ли в сободном для изучения доступе алгоритмы автоматического AG> определения кодировки текста? О, еще сколько. Методом таблицы модельных распределений:

    type TCodePage = (cpWin1251, cp866, cpKOI8R); PMap = ^TMap; TMap = array [#$80..#$FF] of Char; function GetMap(CP: TCodePage): PMap; { должна возвращать указатель на таблицу перекодировки из CP в Windows1251 (nil для CP = cpWin1251) } begin GetMap:=nil; end; function DetermineRussian(Buf: PChar; Count: Integer): TCodePage; const ModelBigrams: array [0..33, 0..33] of Byte = ( {АБВГДЕЖЗИЙКЛМHОПРСТУФХЦЧШЩЪЫЬЭЮЯ_Ё} {А}(0,20,44,12,22,23,16,60,4,9,63,93,47,110,0,16, 35,61,81,1,5,13,24,17,12,4,0,0,0,0,14,31,205,1), {Б}(19,0,0,0,4,19,0,0,8,0,2,15,1,4,41,0,15,5,0, 15,0,2,1,0,0,6,16,37,0,0,0,4,3,0), {В}(97,0,1,0,2,57,0,5,40,0,4,25,2,23,78,2,8,28, 4,12,0,1,0,0,8,1,0,40,1,0,0,5,106,3), {Г}(13,0,0,0,9,5,0,0,15,0,1,17,1,2,96,0,24,0, 0,7,0,0,0,0,0,0,0,0,0,0,0,0,8,0), {Д}(63,0,9,1,2,71,1,0,35,0,3,16,2,22,50,2, 19,9,2,25,0,2,1,0,1,0,1,9,4,0,1,5,17,4), {Е}(4,14,15,34,56,22,13,14,2,34,39,77,73,150, 6,9,101,64,81,1,0,15,5,12,10,6,0,0,0,0,3,4,235,1), {Ж}(13,0,0,0,12,47,0,0,16,0,1,0,0,23,0,0, 0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,2,2), {З}(76,2,11,3,11,4,1,0,7,0,2,4,11,24, 17,0,6,1,0,8,0,0,0,0,0,0,0,16,6,0,1,4,17,0), {И}(7,9,32,5,18,60,4,42,31,27,28,46,55,49, 12,7,26,60,53,0,5,25,14,28,4,1,0,0,0,0,9,56,255,0), {Й}(0,0,0,0,2,0,0,0,0,0,1,3,0,3,0,0, 0,10,3,0,0,0,0,1,1,0,0,0,0,0,0,0,122,0), {К}(92,0,3,0,0,7,2,1,39,0,0,27,0,14, 110,0,18,5,35,18,0,0,11,0,0,0,0,0,0,0,0,0,5,5,0), {Л}(85,1,0,2,1,70,6,0,85,0,5,3,0,9,67,1,0,9, 0,15,0,0,0,2,0,0,0,9,66,0,15,43,57,4), {М}(44,0,0,0,0,65,0,0,47,0,1,1,10,15,57, 7,0,2,0,24,0,0,0,0,0,0,0,28,0,0,0,8,109,3), {}(139,0,0,1,11,108,0,4,152,0,7,0,1,69,161, 0,0,8,25,24,5,1,5,2,0,1,0,83,10,0,1,29,38,5), {О}(0,72,139,76,74,32,32,19,12,52,21,93,68,72,7,34,93, 102,98,1,2,6,6,19,15,2,0,0,0,1,4,9,252,2), {П}(17,0,0,0,0,43,0,0,14,0,1,9,0,1,125, 3,120,1,2,8,0,0,0,0,0,0,0,3,6,0,0,3,2,2), {Р}(151,1,6,4,3,103,7,0,76,0,4,0,11,10,117, 1,0,5,9,39,2,5,0,1,3,0,0,24,7,0,1,10,22,5), {С}(24,1,21,0,3,39,0,0,33,0,56,41,11,15,58, 30,5,30,183,16,0,4,1,4,1,0,0,8,25,0,1,50,41,2), {Т}(83,0,43,0,3,87,0,0,71,0,9,3,2,26,180,0, 55,33,1,23,1,0,1,4,0,0,0,20,78,0,0,5,82,4), {У}(3,6,7,14,19,8,13,6,0,1,13,15,10,7,0,12, 17,16,19,0,1,3,0,12,5,8,0,0,0,0,2,2,1,65,0), {Ф}(4,0,0,0,0,4,0,0,11,0,0,1,0,0,9,0,3, 0,0,4,1,0,0,0,0,0,0,0,0,0,0,0,2,0), {Х}(9,0,2,0,0,2,0,0,5,0,0,1,0,5,26,0,4,1,0, 1,0,0,0,0,0,0,0,0,0,0,0,0,76,0), {Ц}(5,0,0,0,0,16,0,0,48,0,1,0,0,0,4,0,0,0,0,3, 0,0,0,0,0,0,0,2,0,0,0,0,3,0), {Ч}(30,0,0,0,0,52,0,0,23,0,3,1,0,14,1,0,0,0,36, 5,0,0,0,0,1,0,0,0,1,0,0,0,2,2), {Ш}(13,0,0,0,0,28,0,0,17,0,4,4,0,4,3,0,0,0,1, 3,0,0,0,0,0,0,0,0,3,0,0,0,1,1), {Щ}(6,0,0,0,0,23,0,0,16,0,0,0,0,1,0,0,0,0, 0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1), {Ъ}(0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,1,1,0,0), {Ы}(0,5,14,1,3,28,0,2,0,22,6,19,21,2,0,5,4, 7,10,0,0,37,0,3,4,0,0,0,0,0,0,1,84,0), {Ь}(0,1,0,0,0,9,0,10,1,0,13,0,2,26,0,0,0, 10,3,0,0,0,1,0,6,0,0,0,0,0,6,4,117,0), {Э}(0,0,0,0,0,0,0,0,0,0,3,3,0,0,0,0,0, 0,31,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0), {Ю}(0,5,0,0,3,0,0,0,0,0,0,1,0,0,0,0,0, 1,15,0,0,0,1,4,1,15,0,0,0,0,0,0,38,0), {Я}(0,0,9,2,7,10,3,19,0,0,1,6,7,8,0,0, 2,6,19,0,0,3,5,1,0,3,0,0,0,0,5,2,177,0), {_}(42,80,193,43,109,41,18,53,159,0,144, 27,83,176,187,229,70,231,99,47,15,13 ,6,58,7,0,0,0,0,38,0,22,0,2), {Ё}(0,0,0,0,3,0,0,0,0,0,2,4,4,8,0,0,5,3,4, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)); { "рейтинг" буквы Ё условно принимается равным 1/20 от "рейтинга" буквы E, если сочетание с участием Ё корректно, иначе - 0 } type TVariation = array [0..33, 0..33] of Integer; var I, J, iC, iPredC, Max: Integer; C: Char; CP: TCodePage; D, MinD, Factor: Double; AMap: PMap; PV: ^TVariation; Vars: array [TCodePage] of TVariation; begin DetermineRussian:=cpWin1251; { по yмолчанию } { вычисление распределений биграмм } FillChar(Vars, SizeOf(Vars), 0); for CP:=Low(Vars) to High(Vars) do begin AMap:=GetMap(CP); PV:=@Vars[CP]; iPredC:=32; for I:=0 to Count - 1 do begin C:=Buf[I]; iC:=32; if C >= #128 then begin if AMap <> nil then C:=AMap^[C]; if not (C in ['Ё', 'ё']) then begin C:=Chr(Ord(C) and not 32); { 'a'..'я' -> 'А'..'Я' } if C in ['А'..'Я'] then iC:=Ord(C) - Ord('А'); end else iC:=33; end; Inc(PV^[iPredC, iC]); iPredC:=iC; end; end; { вычисление метрики и определение наиболее правдоподобной кодировки } MinD:=0; for CP:=Low(Vars) to High(Vars) do begin PV:=@Vars[CP]; PV^[32, 32]:=0; Max:=1; for I:=0 to 33 do for J:=0 to 33 do if PV^[I, J] > Max then Max:=PV^[I, J]; Factor:=255 / Max; { ноpмализация } D:=0; for I:=0 to 33 do for J:=0 to 33 do D:=D + Abs(PV^[I, J] * Factor - ModelBigrams[I, J]); if (MinD = 0) or (D < MinD) then begin MinD:=D; DetermineRussian:=CP; end; end; end; begin { тест: слово 'Пример' в разных кодировках (веpоятность ошибок на таких коpотких текстах высока - в данном слyчае пpосто повезло!) } writeln(DetermineRussian(#$CF#$F0#$E8#$EC#$E5#$F0, 6) = cpWin1251); writeln(DetermineRussian(#$8F#$E0#$A8#$AC#$A5#$E0, 6) = cp866); writeln(DetermineRussian(#$F0#$D2#$C9#$CD#$C5#$D2, 6) = cpKOI8R); readln; end.
  • Q-153: Как помигать лампочками на клавиатуре?

    var KeyState : TKeyboardState; begin GetKeyboardState(KeyState); KeyState[VK_NUMLOCK] := KeyState[VK_NUMLOCK] xor 1; SetKeyboardState(KeyState); end; Изменяет состояние индикаторов на обратное... См. также VK_NUMLOCK, VK_CAPITAL WinNT: { keybd_event( VK_SCROLL, 0x46, KEYEVENTF_EXTENDEDKEY | 0, 0 ); keybd_event( VK_SCROLL, 0x46, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP,0); } Stas Malinovski. mailto:stasm@tsl.ru

  • Q-154: Как создать в runtime форму

    with TxxForm.Create(Self) do Show; with TxxForm.Create(Self) do try ShowModal; finally Free; end;

  • Q-155: Как прочитать порт или записать в него.

    В мультизадачных ОС как правило доступ к портам запрещен идеологией системы. И это неспроста - подумайте, что будет, если одновременно с вашей программой этот же порт попробует использовать другая программа.
    Hо в Win9x существует частичная возможность обратиться напрямую с помощью ассемблерных команд. Делать это надо с определенной осторожность. Даже если вы получите доступ до порта на своей машине, то это не означает, что это будет и на другой машине, например доступ до LPT порта может быть закрыт драйвером принтера, такое редко но встречается. Доступ к наиболее важным портам прикрыты запрещен полностью соответствующими системными драйверами.
    В Win NT доступ к оборудованию со стороны пользовательской программы запрещен полностью. Для доступа на этих ОС требуется использовать kernel mode драйвера, тоже самое рекомендуется и для Win9x. Вот несколько полезных ссылок:

    TVicHW32 http://www.entechtaiwan.com/tools.htm Tinyport (NT) http://www.winsite.com/info/pc/winnt/programr/tinypo21.zip.drag DriverX http://www.tetradyne.com giveio (NT) http://www.wideman-one.com/gw/tech/Delphi/iopm/index.htm Ports, by Harold Howe, http://www.bcbdev.com/components.htm

    Код доступа к портам с помощью ассемблера.

    procedure WritePortByte(Port:Word; Value:Byte); asm XCHG EDX,EAX OUT DX,AL end; procedure WritePortWord(Port:Word; Value:Word); asm XCHG EDX,EAX OUT DX,AX end; function ReadPortByte(Port:Word) : Byte; asm MOV EDX,EAX IN AL,DX end; function ReadPortWord(Port:Word) : Word; asm MOV EDX,EAX IN AX,DX end;

    Примечание:
    Существуют устройства с подряд идущими (по адресам) байтовыми портами, к которым нельзя обращаться со словными командами I/O. Hа сегодня они почти вымерли, но :

    При выборе типа процедуры (BYTE или WORD) следует ориентироваться на спецификацию устройства ввода-вывода, к которому идет обращение. Hе следует обращаться к байтовому устройству с WORD-ориентированными процедурами - экономия времени мизерная, а побочные эффекты могут быть катастрофическими." Hапример, некоторые адаптеры сбрасывают биты ошибок после чтения статус-регистра. Другие отображают несколько внутренних регистров на один адрес I/O, и т.п.

    Hа некоторых старых компьютерах Word процедуры могут не работать из за специфических особенностей интерфейса, правда такие компьютера практически уже не встречаются. Есть ISA Bus Specification, где эти вопросы четко формализованы. Выборка словного порта может быть разбита на два раза, даже если адрес четный, в зависимости от пожеланий устройства I/O.

  • Q-156: Как работать с битами?

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

    var I : integer; N : integer; // Hомер бита в диапазоне от 0..SizeOf(TYPE)*8 - 1 I := I or (1 shl N); // установка бита I := I and not (1 shl N); // сброс бита I := I xor (1 shl N); // инверсия бита if (i and (1 shl N)) <> 0 then... // проверка установленного бита

    Высокоуровневый подход опирается на представление числа в виде множества:

    type TIntegerSet = set of 0..SizeOf(Integer)*8 - 1; var I : Integer; N : Integer; Include(TIntegerSet(I), N); // установили N-ный бит в 1 Exclude(TIntegerSet(I), N); // сбросили N-ный бит в 0 if N in TIntegerSet(I) then... // проверили N-ный бит
  • Q-157: Как удалить непустой каталог?

    procedure TForm1.Button1Click(Sender: TObject); var lpFileOp: TSHFileOpStruct; begin FillChar(lpFileOp,SizeOf(lpFileOp),0); lpFileOp.Wnd := Handle; lpFileOp.wFunc := FO_DELETE; lpFileOp.pFrom := PChar(Edit1.Text); lpFileOp.fFlags := FOF_NOCONFIRMATION; SHFileOperation(lpFileOp); end;
    Ivan Daniloff

  • Q-158: Как получить список файлов со всеми подкаталогами

    procedure ScanDir(StartDir: string; Mask:string; List:TStrings); var SearchRec : TSearchRec; begin if Mask = '' then Mask := '*.*'; if StartDir[Length(StartDir)] <> '\' then StartDir := StartDir + '\'; if FindFirst(StartDir+Mask, faAnyFile, SearchRec) = 0 then begin repeat Application.ProcessMessages; if (SearchRec.Attr and faDirectory) <> faDirectory then List.Add(StartDir + SearchRec.Name) else if (SearchRec.Name <> '..') and (SearchRec.Name <> '.') then begin List.Add(StartDir + SearchRec.Name + '\'); ScanDir(StartDir + SearchRec.Name + '\',Mask,List); end; until FindNext(SearchRec) <> 0; FindClose(SearchRec); end; end;

    Пример вызова. параметры 1. имя папки
    2. маска, по умолчанию .
    3. хранилище для резульатат, любой наследник от TString, например

    TStringList procedure TForm1.Button1Click(Sender: TObject); begin ListBox1.Items.Clear; ScanDir('c:','',ListBox1.Items); Label1.Caption := IntToStr(ListBox1.Items.Count); end;

    Анатолий Подгорецкий anatoly@podgoretsky.com

  • Q-159: Как преобразовать unix time в TDateTime

    unix timestamp представляет собой число секунд начиная с 1.01.1970

    const SecPerDay = 86400; Offset1970 = 25569; function UnixTimeToDateTime(UnixTime : LongInt): TDate; begin Result := DateTimeToStr(UnixTime / SecPerDay + Offset1970); end; function DateTimeToUnixTime(DelphiDate : TDate) : LongInt; begin Result := Trunc((DelphiDate - Offset1970) * SecPerDay); end;

    Если необходима корректировка зимнего/летнего времени, то ее следует сделать самостоятельно.

  • Q-160: Как сделать .manifest для Windows XP

    Для того, что бы программы запускаемые под Windows XP, имели новый вид, необходимо вместе с программой поставить файл *.manifest или включить его в ресурс. Для это изготовить файл, по ниже приведенной инструкции, назвать его Project1.exe.manifest, по положить рядышком с Project1.exe, после это запускаешь под XP и радуешься :-)

    <?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="Igor.Schevchenko.XPUtilsTest" type="win32" /> <description>XP User utils test</description> <dependency> <dependentAssembly> <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="X86" publicKeyToken="6595b64144ccf1df" language="*" /> </dependentAssembly> </dependency> </assembly>

    Строчку name="Igor.Schevchenko.XPUtilsTest" меняешь на
    name="Kostya.Ergin.Project1"
    С уважением,Игорь Шевченко

    В Delphi Studio 7 Enterprise и Professional, приложения Borland VCL теперь включают компоненты, которые разрешают поддержку WindowsR общих контролов версии 6. Ваше приложение автоматически использует новые контролы Windows на системе Windows XP, если найдет подходящий манифест файл. Более подробно об этом в руководстве Developer's Guide тема "Common controls and XP themes" или в справочной системе.

    Анатолий Подгорецкий




  • Copyright © 2002-2006 Максим Комогоров. Все права защищены.
    Замечания, вопросы и предложения направляйте
    по адресу: webscript@pisem.net
    Поиск по сайту
    О проекте
    Архив
    Hosted by uCoz