Too Frequently Asked Questions of RU.DELPHI hierarchy. Слишком часто задаваемые вопросы эх иерархии RU.DELPHI Copyright (c) Alexey Mahotkin 1997-1998 Редакция 0.12 от 01 Mar 1998 Общие вопросы программирования на Borland Delphi. Compiler/maintainer: Alexey Mahotkin, 2:5020/433, alexm(at)hsys.msk.ru Благодарности: активным писателям эх иерархии RU.DELPHI и контрибуторам этого F.A.Q., without whom nihil. С целью предотвращения спама произведено небольшое искажение e-mail адресов. AA: Akzhan Abdulin, 2:5040/55 AB: Anthony Buntyakov, antosha(at)metcombank.ru ArAs: Arthur Aseev, 2:5030/465.2 AG: Andrey Grigoriev, 2:5061/24.20 AK: Alex Konshin, 2:5030/217 AL: Alexander Lokshin, 2:5020/529 AP: Alexander Petrosyan, 2:5020/468.8 AlPe: Alex Petin, 2:5000/97.8 AR: Andrey Ruckoy, 2:5047/7 AnSa: Andrey Sarinkov, 2:5040/33.121 AS: Alexey Sinutin, 2:5022/12.16 AV: Andrew Verigo, 2:452/23.32 AY: Alexey Yashin, 2:5020/62.31 BL: Boris Loboda, 2:461/256 BP: Boris Podchezertseff, 2:5020/656.20 DK: Dmitry Kryloff, 2:5054/9.20 DS: Dmitry Shikhman, 2:468/13.32 EK: Eugene Kopko, 2:464/196 EL: Evgeny Levashoff, 2:5022/31.7 EM: Eugene Mayevski, 2:463/209 ES: Eugeny Sverchkov, 2:5031/12.23 IA: Ilya Andreev, 2:5030/55.28 IG: Ivan Gudym, 2:4642/2213.9 IS: Igor Slusarev, 2:5020/118.18 JB: Juris Bekins, 2:5100/35 MV: Max Vystropov, 2:5020/1412 PS: Pavel Shklovsky, 2:5011/18 RP: Roman Procopovich, 2:5030/254.201 RR: Roman Rechmakov, 2:5020/952.26 SB: Stanislav Babin, 2:5030/356.7 SK: Serge Korolev, 2:5020/104 SM: Sergey Mazunov, 2:5083/30.20 SO: Sergey Okhapkin, 2:5020/47 SV: Serg Vostrikov, 2:5053/15.3 SA: Sergey Arkhipov, 2:5054/88.10 SB: Sergey Belov, sbelov(at)aha.ru VB: Victor Babkin, 2:463/279.6 VS: Vlad Sharnin, vlad(at)nplks.rb.ru Q: 1. Как сделать так, чтобы программу можно было запустить только в одном экземпляре? A: Воспользуйтесь функцией ActivatePrevInstance из библиотеки rxLib. Для завершения второго экземпляра, попытавшегося запуститься, используйте Application.Terminate; (AS): Другой вариант: X:\DELPHI2\DEMOS\IPCDEMOS\ipcthrd.pas, функция IsMonitorRunning(). (EK): CreateSemaphore(nil,0,1,'MySemaphoreName'); if GetLastError = ERROR_ALREADY_EXISTS then Halt(1); .......... Application.Run; Q: 2. Как работать с разными графическими форматами, кроме BMP, хотя бы самыми распространенными: GIF, JPG, TIFF? A: Воспользуйтесь библиотекой ImageLib. Лежит на www.imagelib.com. Hа компакте с Delphi 3 в каталоге EXTRAS есть библиотека JPEG. Если сказать в модуле uses jpeg; то можно работать с .jpg как с TPicture. (AA): Опять-таки, есть LightLib Images (url не помню, но по altavista находится с полпинка, поставляется с книжкой Чарлза Калверта). Еще есть Nishita ViewLib, freeware. JPG/JIF/GIF/BMP/DIB/RLE/TGA/PCX. http://einstein.ae.eng.ua.edu/nishita/index.htm Q: 3. Куда из Delphi 3 делся модуль для работы с ReportSmith? А мои любимые модули работы с OLE: ole2, oleauto и olectl? A: Они лежат в X:\DELPHI3\LIB\DELPHI2\. Q: 4. Моя программа довольно долго делает какую-то полезную работу, типа чтения дерева каталогов или обильных вычислений, и в этот момент почти не работают остальные программы. Как разрешить им это делать? A: Application.ProcessMessages. (AA): Win32: Если вы хотите отдавать timeslices в нитях, пользуйтесь Sleep(0); это отдаст остаток слайса системе. Win16: Если вы хотите разрешить отработку сообщений другим программам, но не вашей, то лучше пользоваться Yield(). Q: 5. Как мне вывести какое-нибудь окошко с картинкой, пока программа грузится? A: Смотрите пример в X:\DELPHI\DEMOS\DB\MASTAPP\mastapp.dpr. Удобно использовать функцию ShowSplashWindow из rxLib. Q: 6. Как мне запустить какую-нибудь программу? А как подождать, пока эта программа не отработает? Как выяснить, работает ли программа или уже завершилась? Как принудительно закрыть выполняющуюся программу? A: WinExec() или ShellExecute. У второй больше возможностей. (AY, VB): CreateProcess(). (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): Handle:=Winexec(App, 0); PostMessage(Handle, WM_QUIT, 0, 0); Q: 7. Как мне работать с файлами MS Word или таблицами Excel? A: Воспользоватьс функцией CreateOLEObject и работать с VBA или 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; ..... Q: 8. Как сделать так, чтобы запущенна программа не была видна на панели задач? NB: Предположим, вы пользуетесь компонентой TrxTrayIcon из rxLib, иначе непонятно, как вы будете возвращать ее из минимизированного состояния. A: (EM, DS): type TForm1 = class(TForm) Label1: TLabel; RxTrayIcon1: TRxTrayIcon; procedure FormCreate(Sender : TObject); procedure RxTrayIcon1DblClick(Sender: TObject); private { Private declarations } procedure ApplicationMinimize(Sender : TObject); procedure ApplicationRestore(Sender : TObject); public { Public declarations } 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_HIDE); end; procedure TForm1.RxTrayIcon1DblClick(Sender: TObject); begin Application.Restore; Application.BringToFront; end; (AK): Только сpазу пpедупpеждаю пpо гpабли, на котоpые я наступал: Будь готов к тому, что если пpи попытке закpытия пpиложения в OnCloseQuery или OnClose выводится вопpос о подтвеpждении, то могут быть пpоблемы с автоматическим завеpшением пpогpаммы пpи shutdown - под Win95 пpосто зависает, под WinNT не завеpшается. Очевидно, что сообщение выводится, но его не видно (пpичем SW_RESTORE не сpабатывает). Решение - ловить WM_QueryEndSession и после всяких завеpшающих действий и вызова CallTerminateProcs выдавать Halt. Q: 9. А как поместить свою иконку на taskbar, там где часы и переключатель клавиатуры? A: В библиотеке rxLib есть компонент TrxTrayIcon. Q: 10. Как сделать так, чтобы в моей форме курсор перемещалс по полям ввода по Enter, как по Tab? A: (SV): Если вы хотите обрабатывать событие на уровне формы (а не в каждом отдельном компоненте), уберите обработчики события у всех компонент и создайте FormKeyPress -- обработчик OnKeyPress для формы: procedure Form1.OnKeyPress(Sender : TObject; var Key : char); begin if Key = #13 then begin SelectNext(Sender as TWinControl, true, true); Key := #0; end; end; (AnSa): Давно хотелось высказаться по поводy этого способа. Во-пеpвых, нyжно выставлять y фоpмы KeyPreview = True. Во-втоpых, если на фоpмy поместить default-кнопкy, то никакого пеpемещения фокyса не бyдет. Q: 11. А где взять нормальный хелп дл Delphi 3? И для вторых, собственно, тоже -- часть ссылок ведет в никуда, часть ведет не туда, некоторые компоненты без хелпа... A: Hадо поставить нормальные Delphi 3, а не Confidentional/Field beta. Для Delphi 2 -- или найдите где-нибудь обновленные файлы .HLP, например, на www.borland.com или на Delphi Super Page, или на каком-нибудь компакте, или поставьте себе версию 2.01. Моя имеет истинную версию (Help|About..., наберите Alt-VERSION) 2.0.76.0. Узнать ее можно также по странице Internet в панели компонентов. Q: 12. Посоветуйте что-нибудь для работы с модемом и/или COM-портом из Delphi. A: AsyncPro. Он покроет 95% ваших нужд. Для маньяков, желающих пользоваться Win32 -- открывайте "COMx" как файл и пишите/читайте. Еще хорошо почитать Help на тему вещей, начинающихся на "comm". Q: 13. А как включить окошко CPU Window? A: (AP): Вставьте в registry строковый ключ HKCU\Software\Borland\Delphi\2.0\Debugging\EnableCPU=1 соответственно для Delphi 3 -- Delphi\3.0. Q: 14. А как печатать на матричном принтере в текстовом режиме для скорости? A: (AR): var f : textfile; begin AssignFile ( f, 'prn' ); Rewrite ( f ); WriteLn ( f, 'some data' ); CloseFile ( f ); end. NB: Hе забудьте, что слать данные надо в 866 кодовой странице. См. ниже. Q: 15. Посоветуйте хорошую книгу по Delphi. A: a) Кен Хендриксон "Руководство разработчика баз данных" b) Рэй Конопка "Hаписание оригинальных компонент в среде Delphi" c) Рэй Лишнер "Секреты Delphi 2" d) Том Сван "Програмирование в Delphi для Windows95" e) Tом Сван "Секреты 32 разрядного программирования в Delphi" f) Джеффри Рихтер "Windows для профессионалов" (highly recommended!) g) Т. Миллер, "Использование Delphi 3" Q: 16. Как сделать плавно изменющийся цвет заголовка окна, как в MSOffice'95? A: Hадо ловить сообщение WM_NCPAINT. Существует также компонент CustomNC by Alex Prilipko 2:5045/29, которые позволяет самому рисовать всю неклиентскую часть окна. (AP): Тот компонент - плохой. Совсем. Правильный компонент, by Акжан Абдулин и еще кто-то был в фэхе(не WDEVDELPHI). Ищите cap*.zip. NB: cap030.zip и cap031p.zip были в файлэхе FED32SRC. Q: 17. Как мне перекодировать строки из Win-кодировки в Dos-кодировку и наоборот? A: CharToOEM/OEMToChar, CharToOEMBuff/OEMToCharBuff. Q: 18. Как работать с архивными файлами, хотя бы с самыми распространенными, типа .ZIP? A: (AS): Воспользуйтесь библиотекой ExceedZip 3.0 (www.exceedsoft.com) (VS): Hа CDROM с Delphi3 есть каталог INFO\EXTRAS\ZLIB. Подробности на http://quest.jpl.nasa.gov/zlib/ Q: 19. Как правильно закрыть и удалить форму? Почему моя MDI Child форма при закрывании просто минимизируется? A: Обрабатывайте событие OnClose дл формы и выставлйте в нем параметр Action в caFree. Дело в том, что его значение по умолчанию для MDI Child форм =caMinimize. Кстати, если сделать Action := caNone, то форму нельзя будет закрыть. Q: 20. Мне надо добавить много строк в TListbox или в TCombobox или в TMemo или в TRichEdit, при этом сам объект постоянно мигает, перерисовываясь. Как избавиться от этого? A: BeginUpdate/EndUpdate. Q: 21. Как исправить проблемы с вызовом помощи при одновременно стоящих Delphi 1 и Delphi2? A: (AP): Решаютс так... 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" ...и скажите "START HelpPath.REG": Q: 22. Что такое rxLib? A: Одна из самых, если не сама лучшая библиотека общего назначения для Delphi. Огромное количество компонентов и полезных функций. Полные исходные тексты. Совместима со всеми Delphi (1, 2 и 3), а также с C++-Builder. Великолепные примеры использования. Исчерпывающие файлы помощи на русском языке. Текущая версия -- 2.40. IMHO -- a must have для любого дельфиста. Прежде чем огорчаться отсутствием чего-либо или пытаться написать свое -- посмотрите, нет ли этого в rxLib. Скажем так -- без rxLib мое программирование на Delphi будет гораздо более утомительным. Авторы: Fedor Koshevnikov (kosh(at)masterbank.msk.ru) Igor Pavluk (pavluk(at)masterbank.msk.ru) Serge Korolev (korolev(at)masterbank.msk.ru) Q: 23. Как мне запрограммировать непрямоугольную форму, например, как у Norton CrashGuard, в форме щита? A: (ArAs): SetWindowRgn(); (только Win32). (AV): Есть компонент TFormShaper, free for noncommercial use: http://www.wirtschaft.tu-ilmenau.de/~aeg/ (AM:) (Win32) Пример кода, создающий эллиптическую форму, которую к тому же можно двигать за любую точку, что демонстрирует обработку сообщения WM_NCHITTEST: unit main; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Label1: TLabel; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Private declarations } rgn : HRGN; procedure WMNCHitTest(var Message : TWMNCHitTest); message WM_NCHITTEST; protected public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.FormCreate(Sender: TObject); begin rgn := CreateEllipticRgn(0, 0, Width, Height); SetWindowRgn(Handle, rgn, True); end; procedure TForm1.WMNCHitTest(var Message : TWMNCHitTest); begin if PtInRegion(rgn, Message.XPos, Message.YPos) then Message.Result := HTCAPTION else Message.Result := HTNOWHERE; end; procedure TForm1.FormDestroy(Sender: TObject); begin DeleteObject(rgn); end; end. (DK:) Hадо задать форме стиль окна WS_EX_TRANSPARENT. Тогда будут рисоваться только лежащие на ней контролы. Вот пример кода: type TForm1 = class(TForm) { ... } protected procedure CreateParams(var Params : TCreateParams); override; end; procedure TForm1.CreateParams(var Params : TCreateParams); begin inherited CreateParams(Params); { форма становится прозрачной } Params.ExStyle := Params.ExStyle or WS_EX_TRANSPARENT; end; end; Q: 24. Delphi 2 & 3 не отображают русские TTF под Windows NT WorkStation + ServicePack#3. A: (AlPe): Попробуй сделать [HKLM\Software\Microsoft\Windows NT\CurrentVersion\FontMapper] DEFAULT=0xcc (204) вместо 0x00 (Именно DEFAULT, а не (Default):-) получше маленько будет... Q: 25. Как установить компонент от Delphi 2 под Delphi 3? Delphi требуют .PAS-файл. A: Hикак. Ищите исходник или .DCU, скомпилированный дл Delphi 3. Q: 26. Как получить от программы сообщения на русском языке? A: (EL): 1) В X:\Delphi\Sources\vcl - отредактировать все файлы текстовых ресурсов Delphi (или наиболее часто возникающие Exception'ы и надписи на кнопках). 2) В Delphi\bin есть компилятор текстовых ресурсов (brcc32.exe - точно не помню).Откомпилировать все изменненные *.rc. 3) Получившиеся res-файлы кинуть в Delphi\Lib (SB): Для Delphi 3: 1) Delphi3\Doc\Consts.int переименовать в Delphi3\Doc\Consts.pas; 2) внутри Consts.pas в конце дописать: "end."; 3) внутри Consts.pas исправить все "Yes", "No", "Cancel" и т. д. на русский вариант; 4) откомпилировать consts.pas с помощью dcc32, получится Consts.dcu. 5) Consts.dcu скопировать в Delphi 3\Lib вместо имеющегося там. NB: Русские ресурсы для D1 и D2 проходили в свое время по WDEVDELPHI в файле . Q: 27. При возникновении ошибки во врем отладки программы машина перезагружается. Что делать? A: Снести QEMM. Hачисто. Простое отключение его функций не помогает. Q: 28. Как использовать свои курсоры в программе? A: {$R CURSORS.RES} const crZoomIn = 1; crZoomOut = 2; Screen.Cursors[crZoomIn] := LoadCursor(hInstance, 'CURSOR_ZOOMIN'); Screen.Cursors[crZoomOut] := LoadCursor(hInstance, 'CURSOR_ZOOMOUT'); Q: 29. Как правильно создавать компоненты в run-time? Что задавать в качестве параметра Owner при создании компоненты? Как обрабатывать события от созданных компонент, типа нажатий на кнопки? A: 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: 30. Как ограничить перемещение курсора мыши какой-либо областью экрана? A: ClipCursor() Q: 31. Как отловить события создания или удаления файлов другими программами? A: (Win32:) FindFirstChangeNotification/FindNextChangeNotification/ FindCloseChangeNotification (Win16:) FileCDR, но она плохо документирована. Q: 32. Как сделать так, чтобы по Alt-F4 форма не закрывалась, а выдавала запрос на сохранение? A: Обрабатывать OnCloseQuery. Q: 33. При работе программ на D1 под Win95 в hicolor-режимах иконки на TBitBtn'ах обнаруживаются странные коричневые артефакты. Как от них избавиться? A: (AB): Залить фон битмапа синим цветом. Q: 34. Как работать с registry? A: TRegistry. Q: 35. Как получить короткий путь файла если имеется длинный? ("c:\Program Files" ==> "c:\progra~1"). A: GetShortPath() Q: 36. Как напрмую работать с портами/памтью из-под Win95/NT? A: (VS): а http://www.strongsoftware.net/tvicport/ лежат TVicHW32 и TVicPort. Под Win95 можно обращаться к портам из ассемблерных вставок. Под NT этот номер не пройдет -- скорее всего, придется писать драйвер устройства. RTFM WindowsNT Device Driver Kit. Q: 37. Как переключать раскладку клавиатуры из своей программы? A: ActivateKeyboardLayout. Q: 38. Как просматривать HTML в программе? A: Можно воспользоватьс Netscape Navigator или Internet Explorer -- они умеют быть OLE-серверами. (AL): Еще на www.pbear.com лежат THTMLViewer и TFrameViewer. Q: 39. Как перехватывать клавиши, нажатые в окне другой программы? И вообще, любые события, поступающие другим программам? A: (AP): SetWindowsHookEx(). Пример использования лежит на www.i-connect.ru/~paf/links31.zip Q: 40. Как вывести диалог выбора _директории_? A: (DS): SelectDirectory, rxLib: TDirectoryEdit. Q: 41. Не работает передача данных по OLE в русский Excel. A: (SM): Дело в этом что в 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: 42. Можно ли скомпилировать на Delphi 2/3 программу, работающую под Windows 3.1? A: (NP): Нет, но на компактах с Delphi 2/3 поставлется Delphi 1 специально для этой цели. Q: 43. Как вызывать из 32-битной программы 16-битные DLL? A: (EM): Надо применть так называемые Thunks. Смотри статью на http://www.itecuk.com/delmag/thunk95.htm Q: 44. Почему у меня record a : word; b : longint end; имеет размер восемь байт вместо шести? A: RTFM packed, $A. Q: 45. Где взть подробную документацию по работе с RTF, TRichEdit? A: (MC): www.microsoft.com/msdn, зарегистрироваться и искать. Q: 46. Как можно перетаскивать форму не только за заголовок? A: WM_NCHITTEST.