Не часто задаваемые вопросы по Delphi
Этот сборник вопросов по Delphi составлен и постоянно пополняется нами с 1998 г.
Мы используем как собственный опыт, так и сторонние источники для его пополнеия.
При этом мы отбираем вопросы, касающиеся специфицеских возможностей и нестандартных приемов программирования.
Мы надеемся, что и новички и специалисты найдут в данном сборнике ответы на интересующие их вопросы.
Даже если ответа на интересующий Вас вопрос здесь нет, то Вы наверняка узнаете что-то для себя новое.
Данный документ создан на основе БД программы Consul. Вы можете скачать программу Consul бесплатно.
В состав дистрибутива входит и настоящая база данных.


Общее 
Список авторов, чья информация использована в настоящей базе данных по Delphi в алфавитном порядке. 
Рекомендуемая литература по Delphi. 
Проблема с использованием Delphi-приложений в различных форматах экрана. 
Какие дефайны использовать для определения версии Delphi/CPPB ? 
Borland IDE 
Как включить окошко CPU Window? 
Как установить компонент от Delphi 2 под Delphi 3? Delphi требуют PAS-файл. 
Object Pascal 
Преобразование PChar в longint 
Различия в значении логического типа TRUE. 
Утечка памяти при поиске файлов( FindFirst, FindNext ). 
OLE 
Как работать с файлами MS Word или таблицами Excel? 
Пример запуска макроса в MS WinWord-е. 
API 
    Управление аппаратной частью 
Открытие и закрытие устройства CD ROM. 
Изменение громгости звука в Windows95 
Переключение видео режимов. 
Получение списка логических устройств в W95 и их типов. 
Как корректно проверить готовность дисковода? 
Как определить тип устройства? 
Привязка к серийному номеру винта. 
Минимальная инф-ия о состоянии модема. 
Как программно изменять громкость звука? 
    Сообщения & события 
Как контролироавать число документов в очереди принтера? 
Как послать самостийное сообщение всем главным окнам в Windows? 
Как отследить изменение файловой системы и/или реестра ОС? 
Обмен информацией между приложениями Win32 - Win16. 
Как пpинимать яpлыки пpи пеpетягивании их на контpол ? 
Как перехватить нажатие 'горячих клавиш' ОС? 
    DLL 
Как написать DLL, которую можно было-бы выполнить с помощью RunDll, RunDll32? 
    Администрирование 
[Win32] Как проверить, имеем ли мы административные привилегии в системе? 
Как отследить изменение файловой системы и/или реестра ОС? 
    Ресурсы 
Как инсталлировать на время работы программы свои шрифты? 
Как локализовать (русифицировать) ресурсы какого-либо пакета (runtime package)? 
Не горизонтальный шрифт. 
Выделение иконки из приложения. 
    Расширения оболочки W95 
А как поместить свою иконку в область индикаторов на taskbar? 
Хотелось бы иметь возможность отмены вставки нового узла в TTreeView по нажатию кнопки Esc. 
Как добавить горизонтальную полосу прокрутки в TListBox? 
Как создавать ярлыки на рабочем столе? 
Как получить имя папки pабочего стола? 
Хэндл рабочего стола для манипуляций с иконками рабочего стола? 
Очистка папки 'Документы'. 
Получение информыции о ярлыках. 
Как спрятать панель задач в Windows? 
Как очистить все файлы в меню Документы? 
Удаление файлов в корзину 
    Трюки 
Как эмулировать нажатие CTRL+ESC для показа стартового меню? 
Как перезагрузить Explorer? 
Как удалить кнопку 'Пуск' из панели задач (taskbar)? 
Как вставить в StatusPanel свои компоненты, например ProgressBar? 
Как консольное приложение может узнать что Винды завершаются? 
Как сделать так, чтобы запущенная программа не была видна на панели задач? 
Как запрограммировать непрямоугольную форму? 
Как получить иконку и имя Рабочего Стола? 
Как изменить внешний вид хинтов (всплывающих подсказок)? 
Отключение CTRL-ALT-DEL 
Как создать приложение чтобы его не было видно в tasklist'е при нажатии CTRL+ALT+DEL? 
Удаление запущенного процесса. 
    Работа с файлами 
Как отловить события создания или удаления файлов другими программами? 
[Win32] Как удалить файл в корзину (Recycle Bin)? 
Диалог выбора директории. 
Копирование файлов средствами Windows. 
    Мышь,клавиатура и таймер 
Как ограничить перемещение курсора мыши какой-либо областью экрана? 
Как переключать раскладку клавиатуры из своей программы? 
Как перехватывать клавиши, нажатые в окне другой программы? И любые события, поступающие другим программам? 
Как отчитывать промежутки времени с точностью, большей чем 60 мсек? 
    Процессы 
Как мне запустить какую-нибудь программу? 
А как подождать, пока запущенная мной программа не отработает? 
Принудительное завершение процесса. 
Как сделать так, чтобы программу можно было запустить только в одном экземпляре? 
[Win32] Как получить хэндлы всех пpоцессов, котоpые запущены на данный момент в системе? 
Как запретить переключение на другие задачи? 
Организация ожидания. 
Как выполнить перезагрузку (reboot) в Windows NT? 
Как спрятать окно приложения из списка задач и из таскбара? 
Получение хэндла главного окна процесса по хэндлу процесса. 
Как получить результат работы консольной программы ? 
Как поменять приоритет процесса? 
Запуск задач в качестве системных процессов. 
    Сетевые ф-ии 
Проверка подключения к сети. 
Как узнать список установленных cjm-портов? 
    Окна 
Перебор окон. 
    Другое 
Переменные окружения 
Информация о виртуальной памяти. 
Как сделать MS-Style диалог "О программе" ? 
Информация о часовых поясах. 
Как обновить ярлыки на рабочем столе? 
ЧТО ДЕЛАЕТ inf-файл? 
DB 
Просмотр удаленных записей в DBase 
Упаковка таблицы Paradox 
Как заставить BDE производить запись изменений в таблицах Paradox на диск? 
Ускорение работы с последовательностью записей. 
Путь к локальной таблице. 
Создание алиасов. 
SQL 
Как в DELPHI 3 заполнить поле одним и тем же значением сразу у многих записей? 
Сетевые ф-ии 
WSAAsyncSelect: параметр handle при запускаете dll (init). 
Как сделать чтобы при событиях моя программа отпpавляла кому-либо сообщение на мой компьютеp. 
Как работать с поименованными каналами под W'95/NT в сети? 
Как подключать сетевые диски? 
Стандартные элементы управления 
Мне надо добавить много строк в TListbox или в TCombobox или в TMemo или в TRichEdit,
 при этом сам объект постоянно мигает, перерисовываясь. Как избавиться от этого? 
Многоколоночный ListBox. 
Как указать максимальный размер текста для RichEdit Control? 
Выделение стpочек в TTreeView жиpным или бледным. 
Как в TMemo определить номер строки, в которой находится курсор и его местоположение в строке. 
Выделение стpок в TTreeView жиpным/бледным. 
Позициированиие в ListBox. 
Элементы VCL 
Отправка сообщений компонентам 
Ускорение работы TMemo 
Как привязать к конкретному компоненту дополнительную информацию? 
Cвойство Hint 
Каким образом можно отследить вставку и удаление компонент в форму в design-time? 
Как создать копию произвольного компонента? 
Как использовать ChartFX. 
Формы 
Как сделать так, чтобы по Alt-F4 форма не закрывалась, а выдавала запрос на сохранение? 
Как правильно создавать компоненты в run-time? 
Как можно перетаскивать форму не только за заголовок? 
Как сделать так, чтобы в моей форме курсор перемещался по полям ввода по Enter, как по Tab? 
Как запретить кнопку Close [x] в заголовке окна. 
Как отобразить некоторые окна своей программы в панели задач Windows (помимо главного окна) 
Свертывание фоpмы при откpытом модальном окне. 
Имея имя фоpмы нyжно пеpебpать на ней все компоненты имеющие свойство font. 
Необходимо, чтобы дочерняя форма не активизировала родительское окно. 
Как использовать форму из DLL ? 
MDI 
MDI-приложение, в котором способны сливаться не только меню дочернего и главного окна, но и полосы инструментов? 
Работа с принтером 
Простейший способ печати. 
Как мне отправить на принтер чистый поток данных? 
Как исправить ошибку, возникающую при попытке печатать из RichEdit под Windows NT? 
Как отправить на принтер чистый поток данных? 
Наиболее распространенные библиотеки компонентов 
rxLib 
Курсоры, иконки и др. 
Как использовать свои курсоры в программе? 
Как я могу использовать анимированный курсор? 
Работа с Help файлами 
Хелп с окошечком для поиска раздела. 
Как заставить Help-файлы нормально отображать русский под Windows 3.x? 
Графика 
    Создание и обработка изображений 
Как создать disable'ный битмап из обычного (emboss etc)? 
Как скопировать экран (или его часть) в TBitmap? 
Как правильно печатать любую информацию (растровые и векторные изображения), а также как сделать режим предварительного просмотра? 
Как быстро нарисовать тень в заданном регионе? 
Как рисовать на органе управления, если свойство Canvas недоступно? 
Работа с изображением в памяти. 
Как преобразовать ICO в BMP? 
Как из HBitmap получить АДРЕС БИТМАПА В ПАМЯТИ ? 
Создание иконки из битового изображения 
Преобразование цветного изображения в черно-белое 
    Графические форматы 
Как работать с разными графическими форматами, кроме BMP? 
JPG в Visual C++ 5.0. 
GIF из RxLib 2.40 
Другое 
Как перевести визуальный компонент, такой, как TPanel, в состояние перемещения (взять и перенести)? 
Подскажите способ обмена информацией между приложениями Win32 - Win16. 
Как сказать VCL, чтобы клавиши shortcut пунктов главного меню главной формы действовали только в этой форме? 
Как задать в качестве фона MDIForm картинку из TBitmap? 
[Win32] Как вывести на экран путь файла с "красивым" обрезанием по длине? 
Каким образом можно мзменить системное меню формы? 
Размер рабочего стола. 
Как умертвить PC Speaker? 
Как из программы переключать языки? 
Как удобнее работать с буфером обмена как последовательностью байт? 
Как изменить внешний вид хинтов (всплывающих подсказок)? 
Как проиграть Wave-ресурс? 
Каким образом можно мзменить системное меню формы? 
Добавление пунктов в системное меню. 
Поиск запущенной копии вашей программы. 
Форма отображения величин в окне "Watch List". 
Как работать с плагинами ? 
Имитация ввода с клавиатуры для программы выполняющейся в дос-окне? 
Как получить результат работы консольной программы ? 
Алгоритмы 
Как считать CRC-32 ? 
Преобразование сумм в выражения прописью. 
Bugs 
Const из другого unit'а дает неверное значение. 

Общее Список авторов, чья информация использована в настоящей базе данных по Delphi в алфавитном порядке.
Akzhan Abdulin, 2:5040/55 Anthony Buntyakov, antosha(at)metcombank.ru Arthur Aseev, 2:5030/465.2 Andrey Grigoriev, 2:5061/24.20 Alex Konshin, 2:5030/217 Alexander Lokshin, 2:5020/529 Alexey Mahotkin, 2:5020/433, alexm(at)hsys.msk.ru Alexander Petrosyan, 2:5020/468.8 Alex Petin, 2:5000/97.8 Andrey Ruckoy, 2:5047/7 Andrey Sarinkov, 2:5040/33.121 Alexey Sinutin, 2:5022/12.16 Andrew Verigo, 2:452/23.32 Alexey Yashin, 2:5020/62.31 Boris Loboda, 2:461/256 Boris Podchezertseff, 2:5020/656.20 Dmitry Kryloff, 2:5054/9.20 Dmitry Shikhman, 2:468/13.32 Eugene Kopko, 2:464/196 Evgeny Levashoff, 2:5022/31.7 Eugene Mayevski, 2:463/209 Eugeny Sverchkov, 2:5031/12.23 Ilya Andreev, 2:5030/55.28 Ivan Gudym, 2:4642/2213.9 Igor Slusarev, 2:5020/118.18 Juris Bekins, 2:5100/35 Max Vystropov, 2:5020/1412 Pavel Shklovsky, 2:5011/18 Roman Procopovich, 2:5030/254.201 Roman Rechmakov, 2:5020/952.26 Stanislav Babin, 2:5030/356.7 Serge Korolev, 2:5020/104 Sergey Mazunov, 2:5083/30.20 Sergey Okhapkin, 2:5020/47 Serg Vostrikov, 2:5053/15.3 Sergey Arkhipov, 2:5054/88.10 Sergey Belov, sbelov(at)aha.ru Victor Babkin, 2:463/279.6 Vlad Sharnin, vlad(at)nplks.rb.ru Chudin Andrey, 2:5020/1246.16 составление: Chudin Andrey, 2:5020/1246.16 Inprize FAQ В некоторых текстах ответов источник оговорен отдельно. Рекомендуемая литература по Delphi.
1) Кен Хендриксон "Руководство разработчика баз данных" 2) Рэй Конопка "Hаписание оригинальных компонент в среде Delphi" 3) Рэй Лишнер "Секреты Delphi 2" 4) Том Сван "Програмирование в Delphi для Windows95" 5) Tом Сван "Секреты 32 разрядного программирования в Delphi" 6) Джеффри Рихтер "Windows для профессионалов" (highly recommended!) 7) Т. Миллер, "Использование Delphi 3" Проблема с использованием Delphi-приложений в различных форматах экрана.
ОТВЕТЫ: Вот основные приемы, чтобы минимизировать различия во внешнем виде программ для разных разрешений: - используйте при разработке Small Font для Windows; - установите свойства AutoSize = true. Паскарел Вячеслав ------------ Я думаю, это ошибка Delphi или компонентов. Помогает только отключение масштабирования: у формы в Object Inspector Scaled заменить на False Blare@rocketmail.com ------------ Используйте AutoSize = true и PixelsPerInch>=120 (120 - стандартное значение для Delphi). Это не всегда решает все проблемы но, как правило, сильно облегчает жизнь. Alexey A. Kutuzov ------------ К предыдущему ответу хочется добавить следующее: При построении программы делайте все Control-элементы внутри формы масштабируемыми. Т.е. используйте свойства выравнивания, либо прописывайте код в OnResize, который сохранит пропорции содержимого формы. Andrew V. Fionik Еще можно добавить: // фиксируется разрешение при котором ведется разработка приложения ScreenWidth : Integer = 800; ScreenHeight : Integer = 600; // а затем масштабируется в соответствии с текущим разрешением ScaleBy(Screen.Height, ScreenHeight); Alexandre Stepatchev Добавлю к предыдущим ответам : не используйте при разработке не TrueType шрифты, они меняют размер в зависимости от настроек "крупный/мелкий шрифт". Используйте Arial, Times New Roman, Courier new и т.д. Отключите свойство Scaled. ntcstr@orc.ru Какие дефайны использовать для определения версии Delphi/CPPB ?
{$IFDEF VER80} - D1 (Delphi 1.0) {$IFDEF VER90} - D2 {$IFDEF VER93} - B1 (Builder 1.0) {$IFDEF VER100} - D3 {$IFDEF VER110} - B3 {$IFDEF VER120} - D4Borland IDE Как включить окошко CPU Window?
Вставьте в registry строковый ключ HKCU\Software\Borland\Delphi\2.0\Debugging\EnableCPU=1 соответственно для Delphi 3 -- Delphi\3.0. Как установить компонент от Delphi 2 под Delphi 3? Delphi требуют PAS-файл.
Hикак. Ищите исходник или .DCU, скомпилированный для Delphi 3.Object Pascal Преобразование PChar в longint
Question: Many Windows functions claim to want PChar parameters in the documentation, but they are defined as requiring LongInts. Is this a bug? Answer: No, this is where "typecasting" is used. Typecasting allows you to fool the compiler into thinking that one type of variable is of another type for the ultimate in flexibility. The last parameter of the Windows API function SendMessage() is a good example. It is documented as requiring a long integer, but commonly requires a PChar for some messages (WM_WININICHANGE). Generally, the variable you are typecasting from must be the same size as the variable type you are casting it to. In the SendMessage example, you could typecast a PChar as a longint, since both occupy 4 bytes of memory: Example: var s : array[0..64] of char; begin StrCopy(S, 'windows'); SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0, LongInt(@S)); end; Pointers are the easiest to typecast, and are the most flexible since you can pass anything to the called procedure, and the most dangerous for the same reason. You can also use untyped variable parameters for convenience, although var parameters are really pointers behind the scenes. Example: type PBigArray = ^TBigArray; TBigArray = Array[0..65000] of char; procedure ZeroOutPointerVariable(P : pointer; size : integer); var i : integer; begin for i := 0 to size - 1 do PBigArray(p)^[i] := #0; end; procedure ZeroOutUntypedVariable(var v, size : integer); var i : integer; begin for i := 0 to size - 1 do TBigArray(v)[i] := #0; end; procedure TForm1.Button1Click(Sender: TObject); var s : string[255]; i : integer; l : longint; begin s := 'Hello'; i := 10; l := 2000; ZeroOutPointerVariable(@s, sizeof(s)); ZeroOutPointerVariable(@i, sizeof(i)); ZeroOutPointerVariable(@l, sizeof(l)); s := 'Hello'; i := 10; l := 2000; ZeroOutUntypedVariable(s, sizeof(s)); ZeroOutUntypedVariable(i, sizeof(i)); ZeroOutUntypedVariable(l, sizeof(l)); end; Различия в значении логического типа TRUE.
In Delphi 3, the value "True" for data types ByteBool, WordBool, and LongBool is now represented as -1 for compatibility with Microsoft Visual Basic. Note that many compilers represent "True" as either non-zero or a positive 1. When passing values to non Visual Basic applications, you should consider using the following technique to avoid incompatibilities: LongBool(Abs(True)); When accepting boolean values from any external source, you should always test against the value "False". The following technique should always work, since the value for false is always zero: if BoolValPassed <> False then DoSomething. Утечка памяти при поиске файлов( FindFirst, FindNext ).
Не забывайте вызывать SysUtils.FindClose(SearchRec); begin Result := SysUtils.FindFirst(Path, Attr, SearchRec); while Result = 0 do begin ProcessSearchRec(SearchRec); Result := SysUtils.FindNext(SearchRec); end; SysUtils.FindClose(SearchRec); end;OLE Как работать с файлами MS Word или таблицами Excel?
Воспользоваться функцией CreateOLEObject и работать с VBA или WordBasic. === Cut Пример by Sergey Arkhipov 2:5054/88.10 === Пример проверен только на 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; ..... === Cut Конец примера === === Cut Пример 2 === ... MyExcel:=CreateOleObject('Excel.Application'); MyExcel.visible:=true; MyExcel.WorkBooks.Add; MyExcel.Cells(1,1):='Администрация'; ... === Cut Конец примера === Пример запуска макроса в MS WinWord-е.
... vvWord:= CreateOleObject('Word.Application.8'); vvWord.Application.Visible:=true; vvWord.Documents.Open( TempFileName ); vvWord.ActiveDocument.SaveAs( FileName, 1 ); // as .DOC vvWord.Application.Run( 'Macros Name' ); ...API Управление аппаратной частью Открытие и закрытие устройства CD ROM.
Most of you are probably familiar with the TMediaPlayer component. It's a nice multi-purpose component for multimedia, but it has one failing: its inability to close a CD-ROM drive tray if it's open. And unfortunately for us, there's no way to manipulate methods or properties of TMediaPlayer to enable this functionality. So what we have to do is use the Windows API; in particular, we'll be using the MMSystem.pas file. One thing to note: We can use Windows API function calls solely, but TMediaPlayer does some internal handling
that we don't need to worry about if we employ the component. So this example makes use of the TMediaPlayer. Just follow these steps: 1. Start a new project and drop a TMediaPlayer and a TButton on it. 2. Add a "MMSystem" declaration to the uses statement of your form. 3. Set AutoOpen to True on the TMediaPlayer. Set the DeviceType property to dtCDAudio. You might want to consider disabling the btEject option from EnabledButtons property since we'll be handling that functionality in code. 4. One thing I use this for is for data CD's in some applications, so I also set the Visible
property to False and just let my button do the opening and closing of the tray. 5. Finally, add the following code to the button's OnClick event: procedure TForm1.Button2Click(Sender: TObject); begin with MediaPlayer1 do if (MediaPlayer1.Mode = mpOpen) then mciSendCommand(MediaPlayer1.DeviceID, MCI_SET, MCI_SET_DOOR_CLOSED, 0) else mciSendCommand(MediaPlayer1.DeviceID, MCI_SET, MCI_SET_DOOR_OPEN, 0); end; Notice we use the function mciSendCommand. This is the "Swiss Army Knife" of the MMSystem unit. In Windows, everything's controlled by messages. With respect to device control,
mciSendCommand is very similar to a window's WndProc in that it acts as a message dipatcher. Just supply the device, the message type, message flags,
and message parameters, and you're on your way. For more detailed information, I suggest you look in the help file. -- By Brendan Delumpa Изменение громгости звука в Windows95
MMSYSTEM.PAS file in Delphi\Source\Rtl\Win has all the multimedia extension support in Windows. Переключение видео режимов.
unit VidMode; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls; type TForm1 = class(TForm) Edit1: TEdit; Label1: TLabel; Run: TButton; Test: TButton; Label2: TLabel; ComboBox1: TComboBox; procedure RunClick(Sender: TObject); procedure TestClick(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1 : TForm1; Modes : Array[0..255] of TDevMode; implementation {$R *.DFM} procedure TForm1.RunClick(Sender: TObject); var DC : THandle; // Bits : Integer; // HRes : Integer; // VRes : Integer; // DM : TDevMode; // ModeNum : LongInt; // Ok : Bool; I : Byte; begin // DC := Canvas.Handle; Bits := GetDeviceCaps(DC, BITSPIXEL); HRes := GetDeviceCaps(DC, HORZRES); VRes := GetDeviceCaps(DC, VERTRES); Edit1.Text := Format('%d x %d, %d bits',[HRes, VRes, Bits]); ModeNum := 0; EnumDisplaySettings(Nil, ModeNum, DM); Modes[ModeNum] := DM; // Add to array Ok := True; While Ok do Begin Inc(ModeNum); Ok := EnumDisplaySettings(Nil, ModeNum, DM); Modes[ModeNum] := DM; // Add to array End; // Now ModeNum contains # of supported modes For I := 0 to ModeNum-1 do Begin ComboBox1.Items.Add(Format('%d x %d, %d bits', [TDevMode(Modes[I]).dmPelsWidth, TDevMode(Modes[I]).dmPelsHeight, TDevMode(Modes[I]).dmBitsPerPel])); ComboBox1.ItemIndex := 0; End; end; procedure TForm1.TestClick(Sender: TObject); var NewMode : TDevMode; ChResult : LongInt; Msg : String; // Mode is TDevMode(Modes[ListBox1.ItemIndex]) begin NewMode := TDevMode(Modes[ComboBox1.ItemIndex]); NewMode.dmDisplayFrequency := 0; NewMode.dmDisplayFlags := DM_BITSPERPEL AND DM_PELSWIDTH AND DM_PELSHEIGHT AND DM_DISPLAYFLAGS; // In Win95 we should use CDS_UPDATEREGISTRY to change // number of bits per pixel and resolution. Also we need // to restart the computer to take effect of new settigs ChResult := ChangeDisplaySettings(NewMode, CDS_UPDATEREGISTRY); Msg := ''; Case ChResult of DISP_CHANGE_SUCCESSFUL : Msg := 'Success'; DISP_CHANGE_RESTART : Msg := 'Restart'; DISP_CHANGE_BADFLAGS : Msg := 'Bad Flags'; DISP_CHANGE_FAILED : Msg := 'Failed'; DISP_CHANGE_BADMODE : Msg := 'Bad Mode'; DISP_CHANGE_NOTUPDATED : Msg := 'Not updated'; End; ShowMessage(Msg); end; end. Получение списка логических устройств в W95 и их типов.
Воспользуйся ф-ями GetLogicalDrives и GetDriveType. Первая возвращает битовую маску 26-ти дисков, вторая - возвращает тип диска. Это может быть: DRIVE_UNKNOWN DRIVE_NO_ROOT_DIR DRIVE_REMOVABLE DRIVE_FIXED DRIVE_REMOTE DRIVE_CDROM DRIVE_RAMDISK Синтаксис: GetLogicalDrives: DWORD; GetDriveType( lpRootPathName: PChar; {Указатель на строку с корневым каталогом} ): UINT; Пример: W := GetLogicalDrivers; Root := '#:\' for i := 0 to 25 do begin Root[1] := Char(Ord('A')+i); if GetDriveType(Root) = DRIVE_CDROM then begin if (W and (1 shl i))>0 then Msg := Root+' is CD-ROM and It is inserted.' else Msg := Root+' is CD-ROM and It is not available.' ShowMessage(Msg); end; end; Да, посмотри на предмет корневых каталогов ф-ю GetLogicalDriveStrings. Как корректно проверить готовность дисковода?
You can use the Windows API function SetErrorMode() to suppress the Window's critical Error dialog. Example: function IsDriveReady(DriveLetter : char) : bool; var OldErrorMode : Word; OldDirectory : string; begin OldErrorMode := SetErrorMode(SEM_NOOPENFILEERRORBOX); GetDir(0, OldDirectory); {$I-} ChDir(DriveLetter + ':\'); {$I+} if IoResult <> 0 then Result := False else Result := True; ChDir(OldDirectory); SetErrorMode(OldErrorMode); end; procedure TForm1.Button1Click(Sender: TObject); begin if not IsDriveReady('A') then ShowMessage('Drive Not Ready') else ShowMessage('Drive is Ready'); end; Как определить тип устройства?
case GetDriveType('C:\') of 0 : ShowMessage('The drive type cannot be determined'); 1 : ShowMessage('The root directory does not exist'); DRIVE_REMOVABLE:ShowMessage('The disk can be removed'); DRIVE_FIXED : ShowMessage('The disk cannot be removed'); DRIVE_REMOTE : ShowMessage('The drive is remote (network) drive'); DRIVE_CDROM : ShowMessage('The drive is a CD-ROM drive'); DRIVE_RAMDISK : ShowMessage('The drive is a RAM disk'); end; Привязка к серийному номеру винта.
var VolumeName, FileSystemName : array [0..MAX_PATH-1] of Char; VolumeSerialNo : DWord; MaxComponentLength, FileSystemFlags : Integer; begin GetVolumeInformation('C:\',VolumeName,MAX_PATH,@VolumeSerialNo, MaxComponentLength,FileSystemFlags, FileSystemName,MAX_PATH); Memo1.Lines.Add('VName = '+VolumeName); Memo1.Lines.Add('SerialNo = $'+IntToHex(VolumeSerialNo,8)); Memo1.Lines.Add('CompLen = '+IntToStr(MaxComponentLength)); Memo1.Lines.Add('Flags = $'+IntToHex(FileSystemFlags,4)); Memo1.Lines.Add('FSName = '+FileSystemName); end; Минимальная инф-ия о состоянии модема.
var CommPort : string; hCommFile : THandle; ModemStat : DWord; begin CommPort := 'COM2'; {Open the comm port} hCommFile := CreateFile(PChar(CommPort), GENERIC_READ, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if hCommFile = INVALID_HANDLE_VALUE then begin ShowMessage('Unable to open '+ CommPort); exit; end; {Get the Modem Status} if GetCommModemStatus(hCommFile, ModemStat) <> false then begin if ModemStat and MS_CTS_ON <> 0 then ShowMessage('The CTS (clear-to-send) is on.'); if ModemStat and MS_DSR_ON <> 0 then ShowMessage('The DSR (data-set-ready) is on.'); if ModemStat and MS_RING_ON <> 0then ShowMessage('The ring indicator is on.'); if ModemStat and MS_RLSD_ON <> 0 then ShowMessage('The RLSD (receive-line-signal-detect) is on.'); end; {Close the comm port} CloseHandle(hCommFile); end; Как программно изменять громкость звука?
unit Volumes; interface uses Windows, Messages, Classes, ExtCtrls, ComCtrls, MMSystem; const CDVolume = 0; WaveVolume = 1; MidiVolume = 2; type TVolumeControl = class(TComponent) private FDevices : array[0..2] of Integer; FTrackBars : array[0..2] of TTrackBar; FTimer : TTimer; function GetInterval: Integer; procedure SetInterval(AInterval: Integer); function GetVolume(AIndex: Integer): Byte; procedure SetVolume(AIndex: Integer; aVolume: Byte); procedure InitVolume; procedure SetTrackBar(AIndex: Integer; ATrackBar: TTrackBar); { Private declarations } procedure Update(Sender: TObject); procedure Changed(Sender: TObject); protected { Protected declarations } procedure Notification(AComponent: TComponent; AOperation: TOperation); override; public { Public declarations } constructor Create(AOwner: TComponent); override; destructor Destroy; override; published { Published declarations } property Interval: Integer read GetInterval write SetInterval default 500; property CDVolume: Byte index 0 read GetVolume write SetVolume stored False; property CDTrackBar: TTrackBar index 0 read FTrackBars[0] write SetTrackBar; property WaveVolume: Byte index 1 read GetVolume write SetVolume stored False; property WaveTrackBar: TTrackBar index 1 read FTrackBars[1] write SetTrackBar; property MidiVolume: Byte index 2 read GetVolume write SetVolume stored False; property MidiTrackBar: TTrackBar index 2 read FTrackBars[2] write SetTrackBar; end; procedure Register; implementation procedure Register; begin RegisterComponents('Any', [TVolumeControl]); end; type TVolumeRec = record case Integer of 0: (LongVolume: Longint); 1: (LeftVolume, RightVolume : Word); end; function TVolumeControl.GetInterval: Integer; begin Result := FTimer.Interval; end; procedure TVolumeControl.SetInterval(AInterval: Integer); begin FTimer.Interval := AInterval; end; function TVolumeControl.GetVolume(AIndex: Integer): Byte; var Vol: TVolumeRec; begin Vol.LongVolume := 0; if FDevices[AIndex] <> -1 then case AIndex of 0: auxGetVolume(FDevices[AIndex], @Vol.LongVolume); 1: waveOutGetVolume(FDevices[AIndex], @Vol.LongVolume); 2: midiOutGetVolume(FDevices[AIndex], @Vol.LongVolume); end; Result := (Vol.LeftVolume + Vol.RightVolume) shr 9; end; procedure TVolumeControl.SetVolume(aIndex: Integer; aVolume: Byte); var Vol: TVolumeRec; begin if FDevices[AIndex] <> -1 then begin Vol.LeftVolume := aVolume shl 8; Vol.RightVolume := Vol.LeftVolume; case AIndex of 0: auxSetVolume(FDevices[AIndex], Vol.LongVolume); 1: waveOutSetVolume(FDevices[AIndex], Vol.LongVolume); 2: midiOutSetVolume(FDevices[AIndex], Vol.LongVolume); end; end; end; procedure TVolumeControl.SetTrackBar(AIndex: Integer; ATrackBar: TTrackBar); begin if ATrackBar <> FTrackBars[AIndex] then begin FTrackBars[AIndex] := ATrackBar; Update(Self); end; end; procedure TVolumeControl.Notification(AComponent: TComponent; AOperation: TOperation); var I: Integer; begin inherited Notification(AComponent, AOperation); if (AOperation = opRemove) then for I := 0 to 2 do if (AComponent = FTrackBars[I]) then FTrackBars[I] := Nil; end; procedure TVolumeControl.Update(Sender: TObject); var I: Integer; begin for I := 0 to 2 do if Assigned(FTrackBars[I]) then with FTrackBars[I] do begin Min := 0; Max := 255; if Orientation = trVertical then Position := 255 - GetVolume(I) else Position := GetVolume(I); OnChange := Self.Changed; end; end; constructor TVolumeControl.Create(AOwner: TComponent); begin inherited Create(AOwner); FTimer := TTimer.Create(Self); FTimer.OnTimer := Update; FTimer.Interval := 500; InitVolume; end; destructor TVolumeControl.Destroy; var I: Integer; begin FTimer.Free; for I := 0 to 2 do if Assigned(FTrackBars[I]) then FTrackBars[I].OnChange := Nil; inherited Destroy; end; procedure TVolumeControl.Changed(Sender: TObject); var I: Integer; begin for I := 0 to 2 do if Sender = FTrackBars[I] then with FTrackBars[I] do begin if Orientation = trVertical then SetVolume(I, 255 - Position) else SetVolume(I, Position); end; end; procedure TVolumeControl.InitVolume; var AuxCaps : TAuxCaps; WaveOutCaps : TWaveOutCaps; MidiOutCaps : TMidiOutCaps; I,J : Integer; begin FDevices[0] := -1; for I := 0 to auxGetNumDevs - 1 do begin auxGetDevCaps(I, @AuxCaps, SizeOf(AuxCaps)); if (AuxCaps.dwSupport and AUXCAPS_VOLUME) <> 0 then begin FTimer.Enabled := True; FDevices[0] := I; break; end; end; FDevices[1] := -1; for I := 0 to waveOutGetNumDevs - 1 do begin waveOutGetDevCaps(I, @WaveOutCaps, SizeOf(WaveOutCaps)); if (WaveOutCaps.dwSupport and WAVECAPS_VOLUME) <> 0 then begin FTimer.Enabled := True; FDevices[1] := I; break; end; end; FDevices[2] := -1; for I := 0 to midiOutGetNumDevs - 1 do begin MidiOutGetDevCaps(I, @MidiOutCaps, SizeOf(MidiOutCaps)); if (MidiOutCaps.dwSupport and MIDICAPS_VOLUME) <> 0 then begin FTimer.Enabled := True; FDevices[2] := I; break; end; end; end; end.Сообщения & события Как контролироавать число документов в очереди принтера?
... private procedure WM_SpoolerStatus(var Msg : TWMSPOOLERSTATUS); message WM_SPOOLERSTATUS; ... procedure TForm1.WM_SpoolerStatus(var Msg : TWMSPOOLERSTATUS); begin Lable1.Caption := IntToStr(msg.JobsLeft) + ' Jobs currenly in spooler'; msg.Result := 0; end; Как послать самостийное сообщение всем главным окнам в Windows?
Пример: Var FM_FINDPHOTO: Integer; // Для использовать hwnd_Broadcast нужно сперва зарегистрировать уникальное // сообщение Initialization FM_FindPhoto:=RegisterWindowMessage('MyMessageToAll'); // Чтобы поймать это сообщение в другом приложении (приемнике) нужно перекрыть DefaultHandler procedure TForm1.DefaultHandler(var Message); begin with TMessage(Message) do begin if Msg = Fm_FindPhoto then MyHandler(WPARAM,LPARAM) else Inherited DefaultHandler(Message); end; end; // А тепрь можно SendMessage(HWND_BROADCAST,FM_FINDPHOTO,0,0); Кстати, для посылки сообщения дочерним контролам некоего контрола можно использовать метод Broadcast. Andrey Burov (2:463/238.19) Как отследить изменение файловой системы и/или реестра ОС?
Отслеживание файловой системы через FindFirstFileNotification и прочие. Отслеживание реестра ОС - RegNotifyChangeKeyValue (только для NT). Alexey Mahotkin (2:5020/433) Обмен информацией между приложениями Win32 - Win16.
Пользуйтесь сообщением WM_COPYDATA. Для Win16 константа определена как $004A, в Win32 смотрите в WinAPI Help. #define WM_COPYDATA 0x004A /* * lParam of WM_COPYDATA message points to... */ typedef struct tagCOPYDATASTRUCT { DWORD dwData; DWORD cbData; PVOID lpData; } COPYDATASTRUCT, *PCOPYDATASTRUCT; Как пpинимать яpлыки пpи пеpетягивании их на контpол ?
TForm1 = class(TForm) ... private { Private declarations } procedure WMDropFiles(var M : TWMDropFiles); message WM_DROPFILES; ... end; var Form1: TForm1; implementation uses StrUtils, ShellAPI, ComObj, ShlObj, ActiveX;; procedure TForm1.FormCreate(Sender: TObject); begin ... DragAcceptFiles(Handle, True); ... end; procedure TForm1.FormDestroy(Sender: TObject); begin ... DragAcceptFiles(Handle, False); ... end; procedure TForm1.WMDropFiles(var M : TWMDropFiles); var hDrop: Cardinal; n: Integer; s: string; begin hDrop := M.Drop; n := DragQueryFile(hDrop, 0, nil, 0); SetLength(s, n); DragQueryFile(hDrop, 0, PChar(s), n + 1); DragFinish(hDrop); M.Result := 0; FileOpen(s); end; procedure TForm1.FileOpen(FileName: string); begin if CompareText(ExtractFileExt(FileName), '.lnk') = 0 then FileName := ResolveShortcut(Application.Handle, FileName); DocName := ExtractFileName(FileName); Caption := Application.Title + ' - ' + DocName; ... end; function ResolveShortcut(Wnd: HWND; ShortcutPath: string): string; var obj: IUnknown; isl: IShellLink; ipf: IPersistFile; pfd: TWin32FindDataA; begin Result := ''; obj := CreateComObject(CLSID_ShellLink); isl := obj as IShellLink; ipf := obj as IPersistFile; ipf.Load(PWChar(WideString(ShortcutPath)), STGM_READ); with isl do begin Resolve(Wnd, SLR_ANY_MATCH); SetLength(Result, MAX_PATH); GetPath(PChar(Result), Length(Result), pfd, SLGP_UNCPRIORITY); Result := PChar(Result); end; end; Как перехватить нажатие 'горячих клавиш' ОС?
... private procedure WMHotKey(var Msg : TWMHotKey); message WM_HOTKEY; ... var implementation const id_SnapShot = 101; procedure TForm1.WMHotKey (var Msg : TWMHotKey); begin if Msg.HotKey = id_SnapShot then ShowMessage('GotIt'); end; procedure TForm1.FormCreate(Sender: TObject); begin RegisterHotKey(Form1.Handle, id_SnapShot, 0, VK_SNAPSHOT); end; procedure TForm1.FormDestroy(Sender: TObject); begin UnRegisterHotKey (Form1.Handle, id_SnapShot); end;DLL Как написать DLL, которую можно было-бы выполнить с помощью RunDll, RunDll32?
Вы должны определить в программе вызываемую снаружи функцию. Функция должна быть __stdcall (или WINAPI, что то же самое ;)) и иметь четыре аргумента. Первый - HWND окна, порождаемого rundll32 (можно использовать в качестве owner'а своих dialog box'ов), второй - HINSTANCE задачи, третий - остаток командной строки (LPCSTR, даже под NT), четвертый - не знаю ;). Hапример, === int __stdcall __declspec(dllexport) Test ( HWND hWnd, HINSTANCE hInstance, LPCSTR lpCmdLine, DWORD dummy ) { MessageBox(hWnd, lpCmdLine, "Command Line", MB_OK); return 0; } === rundll32 test.dll,_Test@16 this is a command line === выдаст message box со строкой "this is a command line". Oleg Moroz (2:5020/701.22) Function Test( hWnd: Integer; hInstance: Integer; lpCmdLine: PChar; dummy: Longint ): Integer; StdCall; export; begin Windows.MessageBox(hWnd, lpCmdLine, 'Command Line', MB_OK); Result := 0; end; Akzhan Abdulin (2:5040/55) Давненько я ждал эту инфоpмацию! Сел пpовеpять и наткнулся на очень забавную вещь. А именно -- пусть у нас есть исходник на Си пpимеpно такого вида: int WINAPI RunDll( HWND hWnd, HINSTANCE hInstance, LPCSTR lpszCmdLine, DWORD dummy ) ...... int WINAPI RunDllW( HWND hWnd, HINSTANCE hInstance, LPCWSTR lpszCmdLine, DWORD dummy ) ...... и .def-файл пpимеpно такого вида: EXPORTS RunDll RunDllA=RunDll RunDllW то rundll32 становится pазбоpчивой -- под HТ вызывает UNICODE-веpсию. Под 95, pазумеется, ANSI. Rulez. Alexey A Popoff pvax@glas.apc.org, posp@ccas.ru http://www.ccas.ru/~posp/popov/pvax.html (2:5020/487.26)Администрирование [Win32] Как проверить, имеем ли мы административные привилегии в системе?
// Routine: check if the user has administrator provileges // Was converted from C source by Akzhan Abdulin. Not properly tested. type PTOKEN_GROUPS = TOKEN_GROUPS^; function RunningAsAdministrator (): Boolean; var SystemSidAuthority: SID_IDENTIFIER_AUTHORITY = SECURITY_NT_AUTHORITY; psidAdmin: PSID; ptg: PTOKEN_GROUPS = nil; htkThread: Integer; { HANDLE } cbTokenGroups: Longint; { DWORD } iGroup: Longint; { DWORD } bAdmin: Boolean; begin Result := false; if not OpenThreadToken(GetCurrentThread(), // get security token TOKEN_QUERY, FALSE, htkThread) then if GetLastError() = ERROR_NO_TOKEN then begin if not OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, htkThread) then Exit; end else Exit; if GetTokenInformation(htkThread, // get #of groups TokenGroups, nil, 0, cbTokenGroups) then Exit; if GetLastError() <> ERROR_INSUFFICIENT_BUFFER then Exit; ptg := PTOKEN_GROUPS( getmem( cbTokenGroups ) ); if not Assigned(ptg) then Exit; if not GetTokenInformation(htkThread, // get groups TokenGroups, ptg, cbTokenGroups, cbTokenGroups) then Exit; if not AllocateAndInitializeSid(SystemSidAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, psidAdmin) then Exit; iGroup := 0; while iGroup do // check administrator group begin if EqualSid(ptg^.Groups[iGroup].Sid, psidAdmin) then begin Result := TRUE; break; end; Inc( iGroup ); end; FreeSid(psidAdmin); end; Andy Nikolayev an@megatel.msk.su (2:5020/56) Как отследить изменение файловой системы и/или реестра ОС?
Отслеживание файловой системы через FindFirstFileNotification и прочие. Отслеживание реестра ОС - RegNotifyChangeKeyValue (только для NT). Alexey Mahotkin(2:5020/433)Ресурсы Как инсталлировать на время работы программы свои шрифты?
Добавить фонт (.fon, .fot, .fnt, .ttf) в систему можно след. образом: {$IFDEF WIN32} AddFontResource( PChar( my_font_PathName { AnsiString } ) ); {$ELSE} var ss : array [ 0..255 ] of Char; AddFontResource ( StrPCopy ( ss, my_font_PathName )); {$ENDIF} SendMessage ( HWND_BROADCAST, WM_FONTCHANGE, 0, 0 ); Убрать его по окончании работы: {$IFDEF WIN32} RemoveFontResource ( PChar(my_font_PathName) ); {$ELSE} RemoveFontResource ( StrPCopy ( ss, my_font_PathName )); {$ENDIF} SendMessage ( HWND_BROADCAST, WM_FONTCHANGE, 0, 0 ); При этом не надо никаких перезагрузок и прочего, после добавления фонт сразу можно использовать. my_font_PathName : string ( не string[nn] для D2+) - содержит полный путь с именем и расширением необходимого фонта. После удаления фонта форточки о нем забывают. Если его не удалить, он (кажется) так и останется проинсталенным, во всяком случае, я это не проверял. Andry Trushin (2:5020/474.7) Как локализовать (русифицировать) ресурсы какого-либо пакета (runtime package)?
1) Вынимаете pесуpсы из этого модуля. 2) Пеpеводите их на дpугой язык. (напpимеp pусский) 3) Создаете в Delphi свой пpоект Dll-ки (с именем того модуля, из котоpого вы вынули pесуpсы, напpимеp vcl30), в котоpый включаете _пеpеведенные_ pесуpсы: {$R vcl30rus.res} 4) Собиpаете все это. 5) Пеpеименовываете полученную vcl30.Dll в vcl30.rus и кидаете ее в System. Если вы хотите, пpиложение "говоpило" по pусски только тогда, когда в pегиональных установках стоит Russia - то тогда это все. Если же вы хотите, чтобы ваше пpиложение _всегда_ поднимало pусские pесуpсы, то необходимо сделать следующее добавление в Registry: HKEY_CURRENT_USER\SOFTWARE\Borland\Delphi\Locales "X:\MyProject\MyApp.exe" = "rus" Тепеpь, когда ваше пpиложение будет поднимать pakages, то всегда будут бpаться pусские pесуpсы. Дpугие пpиложения, напpимеp Delphi - это не затpонет. Таким обpазом можно заменять даже DFM-ки из пpоекта. Более подpобно об этом - см Help - Index - Localizing... Alexander Simonenko .alex@protec.kiev.ua.(2:463/249) Не горизонтальный шрифт.
function CreateRotatedFont(F : TFont; Angle : Integer) : hFont; {-create a rotated font based on the font object F} var LF : TLogFont; begin FillChar(LF, SizeOf(LF), #0); with LF do begin lfHeight := F.Height; lfWidth := 0; lfEscapement := Angle*10; lfOrientation := 0; if fsBold in F.Style then lfWeight := FW_BOLD else lfWeight := FW_NORMAL; lfItalic := Byte(fsItalic in F.Style); lfUnderline := Byte(fsUnderline in F.Style); lfStrikeOut := Byte(fsStrikeOut in F.Style); lfCharSet := DEFAULT_CHARSET; StrPCopy(lfFaceName, F.Name); lfQuality := DEFAULT_QUALITY; {everything else as default} lfOutPrecision := OUT_DEFAULT_PRECIS; lfClipPrecision := CLIP_DEFAULT_PRECIS; case F.Pitch of fpVariable : lfPitchAndFamily := VARIABLE_PITCH; fpFixed : lfPitchAndFamily := FIXED_PITCH; else lfPitchAndFamily := DEFAULT_PITCH; end; end; Result := CreateFontIndirect(LF); end; ... {create the rotated font} if FontAngle <> 0 then Canvas.Font.Handle := CreateRotatedFont(Font, FontAngle); ... Вращаются только векторные шрифты. Nikita Popov nix@tekton.dol.ru (2:5020/87.2) Выделение иконки из приложения.
How do I display the icon that is associated with a given file type? Answer: Use the ShellApi function ExtractAssociatedIcon() to retrieve the icon that is associated with the file. Example: uses ShellApi; procedure TForm1.Button1Click(Sender: TObject); var Icon : hIcon; IconIndex : word; begin Icon := ExtractAssociatedIcon(HInstance, 'C:\SomePath\SomeFile.ext', IconIndex); DrawIcon(Form1.Canvas.Handle, 10, 10, Icon); end;Расширения оболочки W95 А как поместить свою иконку в область индикаторов на taskbar?
Компонент TrxTrayIcon из библиотеки rxLib. Хотелось бы иметь возможность отмены вставки нового узла в TTreeView по нажатию кнопки Esc.
unit BetterTreeView; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ComCtrls, CommCtrl; type TTVNewEditCancelEvent = procedure( Sender: TObject; Node: TTreeNode; var Delete: Boolean) of object; TBetterTreeView = class(TTreeView) protected FIsEditingNew: Boolean; FOnEditCancel: TTVChangedEvent; FOnNewEditCancel: TTVNewEditCancelEvent; procedure Edit(const Item: TTVItem); override; public function NewChildAndEdit(Node: TTreeNode; const S: String) : TTreeNode; published property IsEditingNew: Boolean read FIsEditingNew; property OnEditCancel: TTVChangedEvent read FOnEditCancel write FOnEditCancel; property OnNewEditCancel: TTVNewEditCancelEvent read FOnNewEditCancel write FOnNewEditCancel; end; implementation procedure TBetterTreeView.Edit(const Item: TTVItem); var Node: TTreeNode; Action: Boolean; begin with Item do begin { Get the node } if (state and TVIF_PARAM) <> 0 then Node := Pointer(lParam) else Node := Items.GetNode(hItem); if pszText = nil then begin if FIsEditingNew then begin Action := True; if Assigned(FOnNewEditCancel) then FOnNewEditCancel(Self, Node, Action); if Action then Node.Destroy end else if Assigned(FOnEditCancel) then FOnEditCancel(Self, Node); end else inherited; end; FIsEditingNew := False; end; function TBetterTreeView.NewChildAndEdit (Node: TTreeNode; const S: String): TTreeNode; begin SetFocus; Result := Items.AddChild(Node, S); FIsEditingNew := True; Node.Expand(False); Result.EditText; SetFocus; end; end. Том Сван "Секреты..." Как добавить горизонтальную полосу прокрутки в TListBox?
Компонент VCL TListBox автоматически реализует вертикальную полосу прокрутки. Полоска прокрутки появляется, когда окно списка слишком мало для показа всех элементов списка. Однако окно списка не показывает горизонтальной полосы прокрутки, когда какие-либо элементы списка имеют большую ширину, чем само окно списка. Конечно, есть возможность добавить горизонтальную полосу прокрутки. Добавьте следующий код в обработчик события OnCreate Вашей формы: procedure TForm1.FormCreate(Sender: TObject); var i, MaxWidth: integer; begin MaxWidth := 0; for i := 0 to ListBox1.Items.Count - 1 do if MaxWidth then MaxWidth := ListBox1.Canvas.TextWidth(ListBox1.Items.Strings[i]); SendMessage(ListBox1.Handle, LB_SETHORIZONTALEXTENT, MaxWidth+2, 0); end; Этот код находит ширину, в пикселах, самой длинной строки в окне списка. Затем он использует сообщение LB_SETHORIZONTALEXTENT для установки горизонтальной прокручиваемой ширины, в пикселах, для окна списка. Два дополнительных пиксела добавлены к MaxWidth, чтобы сдвинуть оконечные символы от правой границы окна списка. Как создавать ярлыки на рабочем столе?
function CreateShortcut(const CmdLine, Args, WorkDir, LinkFile: string): IPersistFile; var MyObject : IUnknown; MySLink : IShellLink; MyPFile : IPersistFile; WideFile : WideString; begin MyObject := CreateComObject(CLSID_ShellLink); MySLink := MyObject as IShellLink; MyPFile := MyObject as IPersistFile; with MySLink do begin SetPath(PChar(CmdLine)); SetArguments(PChar(Args)); SetWorkingDirectory(PChar(WorkDir)); end; WideFile := LinkFile; MyPFile.Save(PWChar(WideFile), False); Result := MyPFile; end; procedure CreateShortcuts; var Directory, ExecDir: String; MyReg: TRegIniFile; begin MyReg := TRegIniFile.Create( 'Software\MicroSoft\Windows\CurrentVersion\Explorer'); ExecDir := ExtractFilePath(ParamStr(0)); Directory := MyReg.ReadString('Shell Folders', 'Programs', '') + '\' + ProgramMenu; CreateDir(Directory); MyReg.Free; CreateShortcut(ExecDir + 'Autorun.exe', '', ExecDir, Directory + '\Demonstration.lnk'); CreateShortcut(ExecDir + 'Readme.txt', '', ExecDir, Directory + '\Installation notes.lnk'); CreateShortcut(ExecDir + 'WinSys\ivi_nt95.exe', '', ExecDir, Directory + '\Install Intel Video Interactive.lnk'); end; Roman Ryltsov. ryltsov@geocities.com. ryltsov@kharkov.com. http://surf.to/ryltsov N.BВообще правильнее в процедуре CreateShortcuts пользовать Win32API::GetSpecialFolderLocation с нужным параметром (CSIDL_PROGRAMS в случае папки "Программы", или CSIDL_DESKTOP в случае "Рабочего стола"). Akzhan Abdulin (2:5040/55) Как получить имя папки pабочего стола?
==== id:ishellfolder; pi:pitemidlist; lpname:tstrret; [...] shgetspecialfolderlocation(0,CSIDL_PROGRAMS,pi) shgetdesktopfolder(id) id.getdisplaynameof(pi,0,lpname) ==== Denis Tanayev denis@demo.ru Хэндл рабочего стола для манипуляций с иконками рабочего стола?
Рабочий стол перекрыт сверху компонентом ListView. Вам просто необходимо взять хэндл этого органа управления. Пример: function GetDesktopListViewHandle: THandle; var S: String; begin Result := FindWindow('ProgMan', nil); Result := GetWindow(Result, GW_CHILD); Result := GetWindow(Result, GW_CHILD); SetLength(S, 40); GetClassName(Result, PChar(S), 39); if PChar(S) <> 'SysListView32' then Result := 0; end; После того, как Вы взяли тот хэндл, Вы можете использовать API этого ListView, определенный в модуле CommCtrl, для того, чтобы манипулировать рабочим столом. Смотрите тему "LVM_xxxx messages" в оперативной справке по Win32. К примеру, следующая строка кода: SendMessage( GetDesktopListViewHandle, LVM_ALIGN, LVA_ALIGNLEFT, 0 ); разместит иконки рабочего стола по левой стороне рабочего стола Windows. (Borland FAQ N687, переведен Акжаном Абдулиным) Очистка папки 'Документы'.
// // Clear contents of Documents menu // procedure TForm1.Button2Click(Sender: TObject); var Result : Integer; begin Result := Application.MessageBox ('Do you want to '+ #13#10+'clear Documents folder?', 'Warning!', MB_ICONSTOP OR MB_OKCANCEL); Case Result of IDOK : SHAddToRecentDocs(SHARD_PATH, Nil); IDCANCEL : ; End; end; Получение информыции о ярлыках.
{ Can't use Standard OpenDialog since it really opens .lnk file and returns the command string, associated with link. } unit SLI_Unit; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, OLE2, ShlObj, ComCtrls, Menus; type TForm1 = class(TForm) Edit0: TEdit; Button1: TButton; Panel1: TPanel; Label1: TLabel; Label2: TLabel; Label3: TLabel; Edit2: TEdit; Edit3: TEdit; Edit4: TEdit; Label7: TLabel; Edit1: TEdit; HotKey1: THotKey; procedure Button1Click(Sender: TObject); procedure ShowLinkInfo; private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.Button1Click(Sender: TObject); begin ShowLinkInfo; end; procedure TForm1.ShowLinkInfo; Var Desc : Array[0..MAX_PATH] of Char; SL : IShellLink; PF : IPersistFile; HRES : HRESULT; FD : TWin32FindData; begin CoInitialize(Nil); HRes := COCreateInstance(CLSID_ShellLink, Nil, CLSCTX_INPROC_SERVER, IID_IShellLink, SL); If Succeeded(HRes) Then Begin HRes := SL.QueryInterface(IID_IPersistFile, PF); If Succeeded(HRes) Then Begin Edit0.Text := 'D:\LINKDEMO.LNK'; PF.Load('D:\LINKDEMO.LNK', STGM_READ); SL.Resolve(Handle, SLR_ANY_MATCH); SL.GetPath(Desc, MAX_PATH, FD, SLGP_UNCPRIORITY); Edit1.Text := StrPas(Desc); SL.GetDescription(Desc, MAX_PATH); Edit2.Text := StrPas(Desc); SL.GetWorkingDirectory(Desc, MAX_PATH); Edit3.Text := StrPas(Desc); SL.GetArguments(Desc, MAX_PATH); Edit4.Text := StrPas(Desc); PF.Release; SL.Release; End; End; end; end. Как спрятать панель задач в Windows?
HWND hwndTaskbar; hwndTaskbar = FindWindow ("Shell_TrayWnd", NULL); SetWindowPos (hwndTaskbar, 0, 0, 0, 0, 0, SWP_HIDEWINDOW); // Hide taskbar //SetWindowPos (hwndTaskbar, 0, 0, 0, 0, 0, SWP_SHOWWINDOW);// Show it again Как очистить все файлы в меню Документы?
#include SHAddToRecentDocs (0, 0); ps: Чтобы добавить файлы в меню Документы см. WinAPI help ф-ии SHAddToRecentDocs (). ---------------- PASCAL: uses ShlOBJ; procedure TForm1.Button1Click(Sender: TObject); begin SHAddToRecentDocs(SHARD_PATH, nil); end; Удаление файлов в корзину
Answer: Use the ShellAPI function SHFileOperation().uses ShellAPI; procedure SendToRecycleBin(FileName: string); var SHF: TSHFileOpStruct; begin with SHF do begin Wnd := Application.Handle; wFunc := FO_DELETE; pFrom := PChar(FileName); fFlags := FOF_SILENT or FOF_ALLOWUNDO; end; SHFileOperation(SHF); end; procedure TForm1.Button1Click(Sender: TObject); begin SendToRecycleBin('c:\DownLoad\Test.gif'); end;Трюки Как эмулировать нажатие CTRL+ESC для показа стартового меню?
HWND hwndShell; hwndShell = FindWindow ("Progman", NULL); //hwndShell = FindWindow ("Shell_TrayWnd", NULL); // То же самое SendMessage (hwndShell, WM_SYSCOMMAND, SC_TASKLIST, 0); Как перезагрузить Explorer?
HWND hwndShell; hwndShell = FindWindow ("Progman", NULL); PostMessage (hwndShell, WM_QUIT, 0, 0L); ShellExecute (0, "open", "Explorer", NULL, NULL, SW_SHOWNORMAL); Как удалить кнопку 'Пуск' из панели задач (taskbar)?
HWND hwndTaskbar, hwndButton; hwndTaskbar= FindWindow ("Shell_TrayWnd", NULL); // Taskbar hwndButton = FindWindowEx (hwndTaskbar, 0, "Button", NULL); // Button SendMessage (hwndButton, WM_CLOSE, 0, 0); Как вставить в StatusPanel свои компоненты, например ProgressBar?
pgProgress положить на форму как Visible := false; StatusPanel надо OwnerDraw сделать и pефpешить, если Position меняется. >== Режем pаз ==<procedure TMainForm.stStatusBarDrawPanel(StatusBar: TStatusBar; Panel: TStatusPanel; const Rect: TRect); begin if Panel.Index = pnProgress then begin pgProgress.BoundsRect := Rect; pgProgress.PaintTo(stStatusBar.Canvas.Handle, Rect.Left, Rect.Top); end; end; >== Режем два ==Как консольное приложение может узнать что Винды завершаются?
Все процессы получают сигналы CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT и CTRL_SHUTDOWN_EVENT. А делается это (грубо говоря :) так: BOOL Ctrl_Handler( DWORD Ctrl ) { if( (Ctrl == CTRL_SHUTDOWN_EVENT) || (Ctrl == CTRL_LOGOFF_EVENT) ) { // Вау! Юзер обламывает! } else { } return TRUE; } А где-то в программе: SetConsoleCtrlHandler( Ctrl_Handler, TRUE ); Таких обработчиков можно навесить кучу. Если при обработке какого-то из сообщений обработчик возвращет FALSE, то вызывается следующий обработчик. Alexander V. Naumochkin (2:5020/59) Как сделать так, чтобы запущенная программа не была видна на панели задач?
[...] 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; --- Для воостановления : Application.Restore; Application.BringToFront; --- ( ! ) Обратите внимание на то, что выводимые скрытой таким образом программой диалоговые окна не видны,
что может привести к проблемам
в случае, если вы забыли воостановить окно перед выводом диалога. Как запрограммировать непрямоугольную форму?
SetWindowRgn(); ( Win32). [--cut--] var rgn:HRGN; [...] procedure TForm1.FormCreate(Sender: TObject); begin rgn := CreateEllipticRgn(0, 0, Width, Height); SetWindowRgn(Handle, rgn, True); end; procedure TForm1.FormDestroy(Sender: TObject); begin DeleteObject(rgn); end; [--cut--] Есть компонент TFormShaper, free for noncommercial use: http://www.wirtschaft.tu-ilmenau.de/~aeg/ Как получить иконку и имя Рабочего Стола?
SHGetSpecialFolderLocation Как изменить внешний вид хинтов (всплывающих подсказок)?
1. Создаем свой класс - потомок от THintWindow type TCustomHint = class (THintWindow) public constructor Create(AOwner: TComponent); override; end; Пpимечание 1. Этот способ не позволит изменить цвет шpифта - для этого пpидется пеpекpывать метод Paint; Пpимечание 2. Если пеpекpыть CreateParams, то можно, напpимеp, наpисовать Hint в фоpме облачка. Пpимечание 3. Для изменения цвета фона F1 TApplication.OnShowHint, HintInfo. 2. Меняем фонт: constructor TCustomHint.Create(AOwner: TComponent); begin inherited Create(AOwner); with Canvas.Font do // Именно так, а не пpосто Font! begin Name := 'Times New Roman Cyr'; Style := [fsBold, fsItalic]; Size := 40; end; end; 3. Устанавливаем новый хинт procedure TForm1.FormCreate(Sender: TObject); // Это может быть любой begin // обpаботчик HintWindowClass := TMyHint; // Устанавливаем глобальную пеpеменную Application.ShowHint := false; // Application.FHintWindow.Free Application.ShowHint := true; // Application.FHintWindow.Create end; Литеpатуpа: 1. <...>\Source\VCL\Forms.pas (TApplication). 2. <...>\Source\VCL\Controls.pas (THintWindow). 3. Delphi Help (OnShowHint, THintInfo). Dmitry Medved (2:464/58.7) Отключение CTRL-ALT-DEL
Бывают ситуации, когда вашей программе понадобится отключить реакцию на клавиши Ctrl-Alt-Del
(например, если вы не хотите, чтобы ее выгрузили из памяти).
Это можно сделать при помощи функции API SystemParametersInfo, которая позволяет узнать,
либо установить параметры операционной системы, такие как установки клавиатуры, дисплея, звука и т.д.
Она используется в Панели Управления. Синтакс функции следующий: BOOL SystemParametersInfo( UINT uiAction, // параметр, который нужно узнать или установить UINT uiParam, // зависит от действия PVOID pvParam, // зависит от действия UINT fWinIni // флаг обновления информации о пользователе (user profile) ); Значение каждого параметра объясняется в Win32 Developer's Reference. Теперь, чтобы сделать то, что мы хотим, вызываем следующую прцедуру: procedure DisableCtrlAltDel; var i : integer; begin i := 0; SystemParametersInfo(SPI_SCREENSAVERRUNNING, 1, @i, 0); end. Аналогично можно отключить Alt-Tab. Для этого нужно задать SPI_SETFASTTASKSWITCH в качестве первого параметра функции. Как создать приложение чтобы его не было видно в tasklist'е при нажатии CTRL+ALT+DEL?
#include "process.h" RegisterServiceProcess (NULL, RSP_SIMPLE_SERVICE); ps: RegisterServiceProcess не определена в WinAPI. См. файл process.h. Удаление запущенного процесса.
Under Win32, unless you are running from a removable drive, you cannot delete a running executable. You can have Windows delete the executable the next time Windows is ran by adding an entry to the RunOnce key in the Windows registry under: HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnce You can name the key anything you like, and specify a command line to another executable or to a dos command passed to command.com. Example: uses Registry; procedure TForm1.Button1Click(Sender: TObject); var reg: TRegistry; begin reg := TRegistry.Create; with reg do begin RootKey := HKEY_LOCAL_MACHINE; LazyWrite := false; OpenKey('Software\Microsoft\Windows\CurrentVersion\RunOnce', false); WriteString('Delete Me!','command.com /c del FILENAME.EXT'); CloseKey; free; end; end;Работа с файлами Как отловить события создания или удаления файлов другими программами?
(Win32:) FindFirstChangeNotification/FindNextChangeNotification/FindCloseChangeNotification (Win16:) FileCDR, но она плохо документирована. [Win32] Как удалить файл в корзину (Recycle Bin)?
program del; uses ShellApi; //function SHFileOperation(const lpFileOp: TSHFileOpStruct): Integer; stdcall; Var T:TSHFileOpStruct; P:String; begin P:='C:\Windows\System\EL_CONTROL.CPL'; With T do Begin Wnd:=0; wFunc:=FO_DELETE; pFrom:=Pchar(P); fFlags:=FOF_ALLOWUNDO End; SHFileOperation(T); End. Ed Lagerburg lagerbrg@euronet.nl Диалог выбора директории.
функция Shell32.dll SHBrowseForFolder. --- var Form1 : TForm1; Shell : IShellForlder; HRES : HResult; procedure CallBack(Wnd : HWnd; uMsg : Uint; lParam, lpData : LPARAM); stdcall; var S : String; begin S := 'Выберите папку для установки программы'; SendMessage(Wnd, BFFM_SetStatusText, 0, LongInt(@S[1])); end; procedure TForm1.Button1Click(Sender : TObject); var InfoType : Byte; BI : TBrowseInfo; S : PChar; Image : Integer; PIDL : PItemIDList; Path : array[0..MAX_PATH - 1] of WideChar; ResPIDL : PItemIDList; begin SHGetSpecialFolderLocation(Handle, CSIDL_PROGRAMS, PIDL); S := StrAlloc(128); with BI do begin hWndOwner := Form1.Handle; pszDisplayName := S; lpszTitle := 'Поиск Папки'; ulFlags := BIF_StatusText; pidlRoot := PIDL; lpfn := @CallBack; iImage := Image; end; ResPIDL := SHBrowseForFolder(BI); SHGetPathFormIDList(ResPIDL, @Path[0]); Edit1.Text := StrToPas(@PAth[0]); StrDispose(S); end; Вообщем вставляешь этот код куда надо, и все будет работать без ошибок... K.Grudnev@tnet.sochi.ru Копирование файлов средствами Windows.
procedure TForm1.Button1Click(Sender: TObject); var Fo : TSHFileOpStruct; buffer : array[0..4096] of char; p : pchar; begin FillChar(Buffer, sizeof(Buffer), #0); p := @buffer; p := StrECopy(p, 'C:\DownLoad\1.ZIP') + 1; p := StrECopy(p, 'C:\DownLoad\2.ZIP') + 1; p := StrECopy(p, 'C:\DownLoad\3.ZIP') + 1; StrECopy(p, 'C:\DownLoad\4.ZIP'); FillChar(Fo, sizeof(Fo), #0); Fo.Wnd := Handle; Fo.wFunc := FO_COPY; Fo.pFrom := @Buffer; Fo.pTo := 'D:\'; Fo.fFlags := 0; if ((SHFileOperation(Fo) <> 0) or (Fo.fAnyOperationsAborted <> false)) then ShowMessage('Cancelled') end;Мышь,клавиатура и таймер Как ограничить перемещение курсора мыши какой-либо областью экрана?
ClipCursor() Как переключать раскладку клавиатуры из своей программы?
ActivateKeyboardLayout. Как перехватывать клавиши, нажатые в окне другой программы? И любые события, поступающие другим программам?
SetWindowsHookEx(). Как отчитывать промежутки времени с точностью, большей чем 60 мсек?
Для начала описываешь процедуру, которая будет вызываться по сообщению от таймера : procedure FNTimeCallBack(uTimerID, uMessage: UINT;dwUser, dw1, dw2: DWORD) stdcall; begin // // Тело процедуры. end; создаешь Таймер и вешаешь на него созданную процедуру uTimerID:=timeSetEvent(10,500,@FNTimeCallBack,100,TIME_PERIODIC); Hу и в конце убиваешь таймер timeKillEvent(uTimerID); И все. Точность этого способа до 1 мсек. минимальный интервал времени можно задавать 1 мсек. Leonid Tserling tlv@f3334.dd.vaz.tlt.ruПроцессы Как мне запустить какую-нибудь программу?
WinExec() или ShellExecute. У второй больше возможностей. А как подождать, пока запущенная мной программа не отработает?
CreateProcess() в параметре process info возвращает handle запущенного процесса. Вот и делаешь WaitForSingleObject(pi.hProcess, INFINITE); ...или... === Cut === handle := WinExec(...); if handle >= 32 then while GetModuleUsage(handle) > 0 do Delay( nn ); else raise .... === Cut === ...или... ... используйте GetProcessTimes(), параметр lpExitTime. Принудительное завершение процесса.
(Win32) TerminateProcess. (Win16) Handle:=Winexec(App, 0); PostMessage(Handle, WM_QUIT, 0, 0); Как сделать так, чтобы программу можно было запустить только в одном экземпляре?
- Воспользуйтесь функцией ActivatePrevInstance из библиотеки rxLib. Для завершения
второго экземпляра, попытавшегося запуститься, используйте Application.Terminate; -or- X:\DELPHI2\DEMOS\IPCDEMOS\ipcthrd.pas, функция IsMonitorRunning(). -or- CreateSemaphore(nil,0,1,'MySemaphoreName'); [Win32] Как получить хэндлы всех пpоцессов, котоpые запущены на данный момент в системе?
Это возможно с использованием вспомогательных инфоpмационных функций (tool help functions). Для получения списка пpоцессов надо делать следующее: 1. Cпеpва вызывается фукция hSnapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) // - получение снимка состояния системы 2. Process32First() - получене инфоpмации о пеpвом пpоцессе в списке 3. Далее в цикле Process32Next() - получение инфоpмации о следующем пpоцессе в списке Dima Bogachev (2:5020/1056.18) Пример: >== Режем pаз ==<unit KernlUtl; interface uses TlHelp32, Windows, Classes, Sysutils; procedure GetProcessList(List: TStrings); procedure GetModuleList(List: TStrings); function GetProcessHandle(ProcessID: DWORD): THandle; procedure GetParentProcessInfo(var ID: DWORD; var Path: String); const PROCESS_TERMINATE = $0001; PROCESS_CREATE_THREAD = $0002; PROCESS_VM_OPERATION = $0008; PROCESS_VM_READ = $0010; PROCESS_VM_WRITE = $0020; PROCESS_DUP_HANDLE = $0040; PROCESS_CREATE_PROCESS = $0080; PROCESS_SET_QUOTA = $0100; PROCESS_SET_INFORMATION = $0200; PROCESS_QUERY_INFORMATION = $0400; PROCESS_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED or SYNCHRONIZE or $0FFF; implementation procedure GetProcessList(List: TStrings); var I: Integer; hSnapshoot: THandle; pe32: TProcessEntry32; begin List.Clear; hSnapshoot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hSnapshoot = -1) then Exit; pe32.dwSize := SizeOf(TProcessEntry32); if (Process32First(hSnapshoot, pe32)) then repeat I := List.Add(Format('%x, %x: %s', [pe32.th32ProcessID, pe32.th32ParentProcessID, pe32.szExeFile])); List.Objects[I] := Pointer(pe32.th32ProcessID); until not Process32Next(hSnapshoot, pe32); CloseHandle (hSnapshoot); end; procedure GetModuleList(List: TStrings); var I: Integer; hSnapshoot: THandle; me32: TModuleEntry32; begin List.Clear; hSnapshoot := CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0); if (hSnapshoot = -1) then Exit; me32.dwSize := SizeOf(TModuleEntry32); if (Module32First(hSnapshoot, me32)) then repeat I := List.Add(me32.szModule); List.Objects[I] := Pointer(me32.th32ModuleID); until not Module32Next(hSnapshoot, me32); CloseHandle (hSnapshoot); end; procedure GetParentProcessInfo(var ID: DWORD; var Path: String); var ProcessID: DWORD; hSnapshoot: THandle; pe32: TProcessEntry32; begin ProcessID := GetCurrentProcessID; ID := -1; Path := ''; hSnapshoot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hSnapshoot = -1) then Exit; pe32.dwSize := SizeOf(TProcessEntry32); if (Process32First(hSnapshoot, pe32)) then repeat if pe32.th32ProcessID = ProcessID then begin ID := pe32.th32ParentProcessID; Break; end; until not Process32Next(hSnapshoot, pe32); if ID <> -1 then begin if (Process32First(hSnapshoot, pe32)) then repeat if pe32.th32ProcessID = ID then begin Path := pe32.szExeFile; Break; end; until not Process32Next(hSnapshoot, pe32); end; CloseHandle (hSnapshoot); end; function GetProcessHandle(ProcessID: DWORD): THandle; begin Result := OpenProcess(PROCESS_ALL_ACCESS, True, ProcessID); end; end. >== Режем два == #include typedef long (*NtQSI)(LONG, PVOID,LONG, LONG); struct ThreadInfo { FILETIME ftCreationTime; DWORD dwUnknown1; DWORD dwStartAddress; DWORD dwOwningPID; DWORD dwThreadID; DWORD dwCurrentPriority; DWORD dwBasePriority; DWORD dwContextSwitches; DWORD dwThreadState; DWORD dwUnknown2; DWORD dwUnknown3; DWORD dwUnknown4; DWORD dwUnknown5; DWORD dwUnknown6; DWORD dwUnknown7; }; struct ProcessInfo { DWORD dwOffset; // an ofset to the next Process structure DWORD dwThreadCount; DWORD dwUnkown1[6]; FILETIME ftCreationTime; DWORD dwUnkown2; DWORD dwUnkown3; DWORD dwUnkown4; DWORD dwUnkown5; DWORD dwUnkown6; WCHAR* pszProcessName; DWORD dwBasePriority; DWORD dwProcessID; DWORD dwParentProcessID; DWORD dwHandleCount; DWORD dwUnkown7; DWORD dwUnkown8; DWORD dwVirtualBytesPeak; DWORD dwVirtualBytes; DWORD dwPageFaults; DWORD dwWorkingSetPeak; DWORD dwWorkingSet; DWORD dwUnkown9; DWORD dwPagedPool; // kbytes DWORD dwUnkown10; DWORD dwNonPagedPool; // kbytes DWORD dwPageFileBytesPeak; DWORD dwPageFileBytes; DWORD dwPrivateBytes; DWORD dwUnkown11; DWORD dwUnkown12; DWORD dwUnkown13; DWORD dwUnkown14; struct ThreadInfo ati[1]; }; NtQSI ntqsi; HANDLE h; int i; long j; long tt; char *vt; // UNICODE struct ThreadInfo *tinfo, *tinf2; struct ProcessInfo *pinfo; char buf[20480]; void main() { h=LoadLibrary("NTDLL.DLL"); ntqsi = (NtQSI)GetProcAddress(h,"NtQuerySystemInformation"); j = (*ntqsi)(5,buf,20480,0); pinfo = buf; for(;;){ vt = pinfo->pszProcessName; printf("%4lX|%13s|%8ld|%7lX|%7ld", pinfo->dwProcessID,vt, pinfo->dwThreadCount,pinfo->dwParentProcessID, pinfo->dwOffset); printf("|%4ld\n",pinfo->dwBasePriority); printf("\t| ID|Owner|State|Priority|Base Priority\n"); tinfo = &pinfo->ati[0]; for(i=0;idwThreadCount;++i){ tinf2 = &tinfo[i]; printf("\t|%4lX|%5lX|%5lX|%8s|%8s\n", tinf2->dwThreadID, tinf2->dwOwningPID, tinf2->dwThreadState, tinf2->dwCurrentPriority, tinf2->dwBasePriority); } if(pinfo->dwOffset==0) break; pinfo = (struct ProcessInfo*)((char *)pinfo + pinfo->dwOffset); } } Viktor Krapivin (2:450/102.13) ------------- Пример2: unit ML_Unit; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, TlHelp32; type TForm1 = class(TForm) ListBox1: TListBox; Button1: TButton; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1 : TForm1; implementation var Form1 : TForm1; implementation {$R *.DFM} procedure Module32List(S : TStrings); var Module32 : TModuleEntry32; SS : THandle; Next : Bool; begin // Module32.dwSize := SizeOf(TModuleEntry32); // SS := CreateToolHelp32Snapshot(TH32CS_SNAPMODULE, 0); // If Module32First(SS, Module32) then begin // S.Add(Module32.szExePath); Repeat // Next := Module32Next(SS, Module32); // If Next Then S.Add(Module32.szExePath); Until Not Next; end; CloseHandle(SS); end; procedure TForm1.FormCreate(Sender: TObject); begin // Module32List(ListBox1.Items); end; procedure TForm1.Button1Click(Sender: TObject); begin // ListBox1.Items.Clear; // Module32List(ListBox1.Items); end; end. Как запретить переключение на другие задачи?
=== Cut === Выключить Ctl-alt-del bool old; SystemParametersInfo (SPI_SCREENSAVERRUNNING,1,&old,0) Включить обратно SystemparametersInfo (SPI_ScreenSaverrunning,0,&old,0) === Cut === Konstantin Okolelyh (2:5025/77.23) Организация ожидания.
Пример #1. Загрузка процессора программой увеличивается приблизительно на 1-3% по сравнению с пустой системой.
Достоинства этого метода состоят в том, что благодаря использованию MsgWaitForMultipleObjects пустое ожидание может быть прервано, например, приходом сообщения (в отличие от SleepEx).
При весьма небольшом увеличении загрузки процессора dwSlice может быть уменьшено до 1. #include #include HANDLE hThread; VOID ReleaseTimeSlice( DWORD dwSlice ) { MsgWaitForMultipleObjects( 1, &hThread, FALSE, dwSlice, QS_ALLINPUT ); } VOID main( VOID ) { hThread = GetCurrentThread(); puts( "Press any key to terminate." ); while ( !_kbhit() ) { ReleaseTimeSlice( 10 ); } getch(); } Пример #2. Загрузка процессора программой увеличивается приблизительно на 3-4% по сравнению с пустой системой.
Hесомненное достоинство метода -ссылка на него в документации по Visual C++ и Win32 SDK. Однако, этот метод имеет ограничение, так как time slice отдается только нити с _таким же_ приоритетом. #include #include VOID main( VOID ) { puts( "Press any key to terminate." ); while ( !_kbhit() ) { Sleep( 10 ); } getch(); } Serge Popov Как выполнить перезагрузку (reboot) в Windows NT?
Даже если ты работаешь под Администратором, твоя программка должна запросить дополнительные привилегии. Вот как это делается (Си): void Reboot (void) { HANDLE hToken; TOKEN_PRIVILEGES* NewState; OSVERSIONINFO OSVersionInfo; OSVersionInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); GetVersionEx (&OSVersionInfo); if (OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) { OpenProcessToken (GetCurrentProcess (), TOKEN_ADJUST_PRIVILEGES, &hToken); NewState = (TOKEN_PRIVILEGES*) malloc (sizeof (TOKEN_PRIVILEGES) + sizeof (LUID_AND_ATTRIBUTES)); NewState->PrivilegeCount = 1; LookupPrivilegeValue (NULL, SE_SHUTDOWN_NAME, &NewState->Privileges[0].Luid); NewState->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; AdjustTokenPrivileges (hToken, FALSE, NewState, NULL, NULL, NULL); free (NewState); CloseHandle (hToken); } ExitWindowsEx (EWX_REBOOT, 0); } Andy Nikolayev an@megatel.ru (2:5020/56) Как спрятать окно приложения из списка задач и из таскбара?
Для NT - всё как обычно, для 95 так: #define RSP_SIMPLE_SERVICE 0x00000001 #define RSP_UNREGISTER_SERVICE 0x00000000 void SimpleServiceRegister (void) { HINSTANCE hInstKernel; DWORD (__stdcall *pRegisterServiceProcess) (DWORD, DWORD); hInstKernel = LoadLibrary ("KERNEL32.DLL"); if (hInstKernel) { pRegisterServiceProcess = (DWORD (__stdcall *) (DWORD, DWORD)) GetProcAddress (hInstKernel, "RegisterServiceProcess"); if (pRegisterServiceProcess) { pRegisterServiceProcess (NULL, RSP_SIMPLE_SERVICE); } FreeLibrary (hInstKernel); } } Andy Nikolayev an@megatel.ru (2:5020/56) Получение хэндла главного окна процесса по хэндлу процесса.
HWND WindWindowByProcessId(DWORD ProcessId) { HWND hwndCurrent=GetDesktopWindow(); do { DWORD WindowProcessId=0; GetWindowThreadProcessId(hwndCurrent, &WindowProcessId); if(WindowProcessId==ProcessId) return hwndCurrent; } while(GetWindow(hwndCurrent, GW_HWNDPREV)); return NULL; } ID пpоцесса ты смощешь найти там же где беpешь его хэндл - в стpуктуpе PROCESS_INFORMATION. Сам понимаешь, что это пpимеp. И у него есть масса непpиятных моментов: 1) Если у пpиложения будет откpыто несколько окон - веpнется пеpвое встpеченное на доpоге. 2) Если пpиложение написано на Delphi/C++Builder, то этим окном может запpосто оказаться TDataModule,
и что ты будешь делать с его хэндлом - непонятно. Alexander Simonenko 2:463/249fidonet Как получить результат работы консольной программы ?
Hужно использовать пайпы (CreatePipe), и работать с ними как с обычным файлом. const H_IN_READ = 1; H_IN_WRITE = 2; H_OUT_READ = 3; H_OUT_WRITE = 4; H_ERR_READ = 5; H_ERR_WRITE = 6; type TPipeHandles = array [1..6] of THandle; var hPipes: TPipeHandles; ProcessInfo: TProcessInformation; (************************************************************** CREATE HIDDEN CONSOLE PROCESS **************************************************************) function CreateHiddenConsoleProcess(szChildName: string; ProcPriority: DWORD; ThreadPriority: integer): Boolean; label error; var fCreated: Boolean; si: TStartupInfo; sa: TSecurityAttributes; begin // Initialize handles hPipes[ H_IN_READ ] := INVALID_HANDLE_VALUE; hPipes[ H_IN_WRITE ] := INVALID_HANDLE_VALUE; hPipes[ H_OUT_READ ] := INVALID_HANDLE_VALUE; hPipes[ H_OUT_WRITE ] := INVALID_HANDLE_VALUE; hPipes[ H_ERR_READ ] := INVALID_HANDLE_VALUE; hPipes[ H_ERR_WRITE ] := INVALID_HANDLE_VALUE; ProcessInfo.hProcess := INVALID_HANDLE_VALUE; ProcessInfo.hThread := INVALID_HANDLE_VALUE; // Create pipes // initialize security attributes for handle inheritance (for WinNT) sa.nLength := sizeof(sa); sa.bInheritHandle := TRUE; sa.lpSecurityDescriptor := nil; // create STDIN pipe if not CreatePipe( hPipes[ H_IN_READ ], hPipes[ H_IN_WRITE ], @sa, 0 ) then goto error; // create STDOUT pipe if not CreatePipe( hPipes[ H_OUT_READ ], hPipes[ H_OUT_WRITE ], @sa, 0 ) then goto error; // create STDERR pipe if not CreatePipe( hPipes[ H_ERR_READ ], hPipes[ H_ERR_WRITE ], @sa, 0 ) then goto error; // process startup information ZeroMemory(Pointer(@si), sizeof(si)); si.cb := sizeof(si); si.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES; si.wShowWindow := SW_HIDE; // assign "other" sides of pipes si.hStdInput := hPipes[ H_IN_READ ]; si.hStdOutput := hPipes[ H_OUT_WRITE ]; si.hStdError := hPipes[ H_ERR_WRITE ]; // Create a child process try fCreated := CreateProcess( nil, PChar(szChildName), nil, nil, True, ProcPriority, // CREATE_SUSPENDED, nil, nil, si, ProcessInfo ); except fCreated := False; end; if not fCreated then goto error; Result := True; CloseHandle(hPipes[ H_OUT_WRITE ]); CloseHandle(hPipes[ H_ERR_WRITE ]); // ResumeThread( pi.hThread ); SetThreadPriority(ProcessInfo.hThread, ThreadPriority); CloseHandle( ProcessInfo.hThread ); Exit; //----------------------------------------------------- error: ClosePipes( hPipes ); CloseHandle( ProcessInfo.hProcess ); CloseHandle( ProcessInfo.hThread ); ProcessInfo.hProcess := INVALID_HANDLE_VALUE; ProcessInfo.hThread := INVALID_HANDLE_VALUE; Result := False; end; Как поменять приоритет процесса?
procedure TForm1.Button1Click(Sender: TObject); var ProcessID : DWORD; ProcessHandle : THandle; ThreadHandle : THandle; begin ProcessID := GetCurrentProcessID; ProcessHandle := OpenProcess(PROCESS_SET_INFORMATION, false, ProcessID); SetPriorityClass(ProcessHandle, REALTIME_PRIORITY_CLASS); ThreadHandle := GetCurrentThread; SetThreadPriority(ThreadHandle, THREAD_PRIORITY_TIME_CRITICAL); end; ------- Можно и так: SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS); Запуск задач в качестве системных процессов.
program Service; uses Windows,Registry,TlHelp32,SysUtils; {$APPTYPE CONSOLE} var add_reg,del_reg,run_hidden,term_service,not_run,run_once:boolean; i:integer; reg:Tregistry; Function RegisterServiceProcess(dwProcessId,dwType:DWORD):DWORD;stdcall;external 'kernel32.dll'; Function GetProcessId(exename:string):integer; var hSnap:THandle; pe:TProcessEntry32; procid:integer; procexe:string; begin pe.dwSize:=SizeOf(pe); hSnap:=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); If Process32First(hSnap,pe) then begin While Process32Next(hSnap,pe) do begin procexe:=pe.szExeFile;procid:=pe.th32processid; if uppercase(procexe)<>uppercase(exename) then continue; result:=procid; closehandle(hSnap); exit; end; end; result:=0; closehandle(hSnap) end; Function GetProcessExe(var exename:string):integer; var hSnap:THandle; pe:TProcessEntry32; procid:integer; prochandle:integer; procexe:string; begin pe.dwSize:=SizeOf(pe); hSnap:=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); If Process32First(hSnap,pe) then begin While Process32Next(hSnap,pe) do begin procexe:=pe.szExeFile;procid:=pe.th32processid; if uppercase(procexe)<>uppercase(exename) then continue; prochandle:=openprocess(PROCESS_ALL_ACCESS,true,procid); result:=prochandle; closehandle(hSnap); exit; end; end; result:=0; closehandle(hSnap) end; Procedure Help; begin Writeln('RunService 1.0 for Windows95/98 by Anton Geleznyak (2:5000/106)'); Writeln('---------------------------------------------------------------'); Writeln('Syntax: Runserv [keys]'); Writeln('Possible keys are:'); WRiteln('/a - add to registry services startup.'); Writeln('/o - add to registry services startup to run once.'); Writeln('/h - run hidden.'); Writeln('/r - remove from registry services startup.'); Writeln('/t - terminate service.'); Writeln('/n - do not run.'); Writeln('/h - this help screen.'); Writeln(''); end; Procedure Add_to_Registry(exename:string); begin reg:=Tregistry.Create; reg.RootKey:=HKEY_LOCAL_MACHINE; if not run_once then reg.OpenKey('\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUNSERVICES\',true) else reg.OpenKey('\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUNSERVICESONCE\',true); reg.WriteString(exename,exename); reg.CloseKey; reg.Free end; Procedure Remove_from_Registry(exename:string); begin reg:=Tregistry.Create; reg.RootKey:=HKEY_LOCAL_MACHINE; reg.OpenKey('\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUNSERVICES\',true); if reg.ValueExists(exename) then
reg.DeleteValue(exename) else
begin
Writeln('ERROR: Service record not found in the registry.');halt(253);
end;
reg.CloseKey;
reg.Free
end;
Procedure Execute(exename:string); begin if run_hidden then WinExec(pchar(exename),sw_hide) else WinExec(pchar(exename),sw_show); RegisterServiceProcess(GetProcessId(exename),1); end; Procedure TerminateService(exename:string); begin if getprocessexe(exename)=0 then begin Writeln('ERROR: Cannot terminate process that is not started yet.');halt(254);end; terminateprocess(getprocessexe(exename),0); end; begin add_reg:=false; del_reg:=false; run_hidden:=false; term_service:=false; not_run:=false; run_once:=false; if (paramcount=0) or (lowercase(paramstr(1))='/h') then begin help;halt(0);end; if paramcount>1 then begin for i:=2 to paramcount do begin if lowercase(paramstr(i))='/a' then add_reg:=true; if lowercase(paramstr(i))='/h' then run_hidden:=true; if lowercase(paramstr(i))='/r' then del_reg:=true; if lowercase(paramstr(i))='/t' then term_service:=true; if lowercase(paramstr(i))='/n' then not_run:=true; if lowercase(paramstr(i))='/o' then run_once:=true; end; end; if not fileexists(paramstr(1)) then begin Writeln('ERROR: Exefile not found');halt(255);end; if add_reg or run_once then Add_To_Registry(paramstr(1)); if del_reg then Remove_From_Registry(paramstr(1)); if term_service then TerminateService(paramstr(1)); if not not_run then Execute(paramstr(1)); halt(0); end.Сетевые ф-ии Проверка подключения к сети.
if GetSystemMetrics(SM_NETWORK) AND $01 = $01 then ShowMessage('Machine is attached to network') else ShowMessage('Machine is not attached to network'); Как узнать список установленных cjm-портов?
var reg : TRegistry; ts : TStrings; i : integer; begin reg := TRegistry.Create; reg.RootKey := HKEY_LOCAL_MACHINE; reg.OpenKey('hardware\devicemap\serialcomm', false); ts := TStringList.Create; reg.GetValueNames(ts); for i := 0 to ts.Count -1 do begin Memo1.Lines.Add(reg.ReadString(ts.Strings[i])); end; ts.Free; reg.CloseKey; reg.free; end;Окна Перебор окон.
Using the Windows API function FindWindow() is the simplest and most straightforward method of locating a given window provided you know the exact window caption or class name. If you know only part of the window's caption (ie: 'Netscape - ' + 'Some Unknown URL', you need to use the Windows EnumWindows() function to enumerate all the active windows, then call the Windows API functions GetWindowsText() and GetClassName to see if you find a match for the window that you are searching for. The following example returns the window handle of the first window enumerated that contains a partial match of the window title and an exact match of the window's ClassName (if given) and brings that window to the foreground. type PFindWindowStruct = ^TFindWindowStruct; TFindWindowStruct = record Caption : string; ClassName : string; WindowHandle : THandle; end; function EnumWindowsProc(hWindow : hWnd; lParam : LongInt) : Bool {$IFDEF Win32} stdcall; {$ELSE} ; export; {$ENDIF} var lpBuffer : PChar; WindowCaptionFound : bool; ClassNameFound : bool; begin GetMem(lpBuffer, 255); Result := True; WindowCaptionFound := False; ClassNameFound := False; try if GetWindowText(hWindow, lpBuffer, 255) > 0 then if Pos(PFindWindowStruct(lParam).Caption, StrPas(lpBuffer)) > 0 then WindowCaptionFound := true; if PFindWindowStruct(lParam).ClassName = '' then ClassNameFound := True else if GetClassName(hWindow, lpBuffer, 255) > 0 then if Pos(PFindWindowStruct(lParam).ClassName, StrPas(lpBuffer)) > 0 then ClassNameFound := True; if (WindowCaptionFound and ClassNameFound) then begin PFindWindowStruct(lParam).WindowHandle := hWindow; Result := False; end; finally FreeMem(lpBuffer, sizeof(lpBuffer^)); end; end; function FindAWindow(Caption : string; ClassName : string) : THandle; var WindowInfo : TFindWindowStruct; begin with WindowInfo do begin Caption := Caption; ClassName := ClassName; WindowHandle := 0; EnumWindows(@EnumWindowsProc, LongInt(@WindowInfo)); FindAWindow := WindowHandle; end; end; procedure TForm1.Button1Click(Sender: TObject); var TheWindowHandle : THandle; begin TheWindowHandle := FindAWindow('Netscape - ', ''); if TheWindowHandle = 0 then ShowMessage('Window Not Found!') else BringWindowToTop(TheWindowHandle); end;Другое Переменные окружения
// // ENVIR. This sample shows how to get process environment strings and // values of individual environment variables. Uses GetEnvironmentStrings // and GetEnvironmentVariable functions from WIN32 API // unit EnvUnit; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Memo1: TMemo; Button1: TButton; Edit2: TEdit; ComboBox1: TComboBox; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.Button1Click(Sender: TObject); var DosEnv : PChar; I : Integer; SignPos : Integer; begin // // GetEnvironmentStrings = 32-bit version of GetDosEnvironment // Memo1.Lines.Clear; // Get all environment variables DosEnv := GetEnvironmentStrings; While DosEnv^ <> #0 do begin // Add one by one into memo Memo1.Lines.Add(StrPas(DosEnv)); // Get next one Inc(DosEnv, StrLen(DosEnv)+1); end; // Fill in ComboBox With Memo1 do begin for I := 0 to Lines.Count-1 do begin SignPos := Pos('=',Lines[I]); ComboBox1.Items.Add(Copy(Lines[I], 1, SignPos-1)); end; end; // Show 1st element ComboBox1.ItemIndex := 0; ComboBox1.OnChange(Self); end; procedure TForm1.Button2Click(Sender: TObject); var Name, Value : PChar; begin // Get memory Name := StrAlloc(255); Value:= StrAlloc(255); // Convert to PChar StrPCopy(Name, ComboBox1.Items[ComboBox1.ItemIndex]); // Get variable value GetEnvironmentVariable(Name, Value, 255); // Show it as Pascal string Edit2.Text := StrPas(Value); // Free memory StrDispose(Name); StrDispose(Value); end; end. Информация о виртуальной памяти.
unit VMUnit; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, ComCtrls; type TForm1 = class(TForm) Label1: TLabel; TabControl1: TTabControl; Panel1: TPanel; Label2: TLabel; Label3: TLabel; Label4: TLabel; Label5: TLabel; Label6: TLabel; Label7: TLabel; Label8: TLabel; procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1 : TForm1; MemoryStatus : TMemoryStatus; implementation {$R *.DFM} procedure TForm1.FormCreate(Sender: TObject); begin MemoryStatus.dwLength := SizeOf(MemoryStatus); GlobalMemoryStatus(MemoryStatus); With MemoryStatus do Begin dwTotalPhys := dwTotalPhys DIV 1024; {} Label2.Caption := 'Memory load : ' + IntToStr(dwMemoryLoad); Label3.Caption := 'Total phys : ' + IntToStr(dwTotalPhys); Label4.Caption := 'Avail phys : ' + IntToStr(dwAvailPhys); Label5.Caption := 'Total Page File : ' + IntToStr(dwTotalPageFile); Label6.Caption := 'Avail Page File : ' + IntToStr(dwAvailPageFile); Label7.Caption := 'Total Virtual : ' + IntToStr(dwTotalVirtual); Label8.Caption := 'Avail Virtual : ' + IntToStr(dwAvailVirtual); End; end; end. Как сделать MS-Style диалог "О программе" ?
Диалог можно нарисовать ручками (из калькулятора того же срисовать), а информацию об OS и количестве памяти можно взять следующим образом : type TAboutForm = class(TForm) OS: TLabel; Mem: TLabel; ... procedure TAboutForm.GetOSInfo; var Platform: string; BuildNumber: Integer; begin case Win32Platform of VER_PLATFORM_WIN32_WINDOWS: begin Platform := 'Windows 95'; BuildNumber := Win32BuildNumber and $0000FFFF; end; VER_PLATFORM_WIN32_NT: begin Platform := 'Windows NT'; BuildNumber := Win32BuildNumber; end; else begin Platform := 'Windows'; BuildNumber := 0; end; end; if (Win32Platform = VER_PLATFORM_WIN32_WINDOWS) or (Win32Platform = VER_PLATFORM_WIN32_NT) then begin if Win32CSDVersion = '' then OS.Caption := Format('%s %d.%d (Build %d)', [Platform, Win32MajorVersion, Win32MinorVersion, BuildNumber]) else OS.Caption := Format('%s %d.%d (Build %d: %s)', [Platform, Win32MajorVersion, Win32MinorVersion, BuildNumber, Win32CSDVersion]); end else OS.Caption := Format('%s %d.%d', [Platform, Win32MajorVersion, Win32MinorVersion]) end; procedure TAboutForm.InitializeCaptions; var MS: TMemoryStatus; begin GetOSInfo; MS.dwLength := SizeOf(TMemoryStatus); GlobalMemoryStatus(MS); Mem.Caption := FormatFloat('#,###" KB"', MS.dwTotalPhys div 1024); end; Информация о часовых поясах.
The following example lists the time zones known to Windows. Example: uses Registry; procedure TForm1.Button1Click(Sender: TObject); var reg : TRegistry; ts : TStrings; i : integer; begin reg := TRegistry.Create; reg.RootKey := HKEY_LOCAL_MACHINE; reg.OpenKey( 'SOFTWARE\Microsoft\Windows\CurrentVersion\Time Zones', false); if reg.HasSubKeys then begin ts := TStringList.Create; reg.GetKeyNames(ts); reg.CloseKey; for i := 0 to ts.Count -1 do begin reg.OpenKey( 'SOFTWARE\Microsoft\Windows\CurrentVersion\Time Zones\' + ts.Strings[i], false); Memo1.Lines.Add(ts.Strings[i]); Memo1.Lines.Add(reg.ReadString('Display')); Memo1.Lines.Add(reg.ReadString('Std')); Memo1.Lines.Add(reg.ReadString('Dlt')); Memo1.Lines.Add('----------------------'); reg.CloseKey; end; ts.Free; end else reg.CloseKey; reg.free; end; Как обновить ярлыки на рабочем столе?
SendMessage(FindWindow('Progman', 'Program Manager'), WM_COMMAND, $A065, 0); ЧТО ДЕЛАЕТ inf-файл?
Он позволяет осуществить: Создание элементов реестра Определение инициализационных параметров (INI-settings) Копирование файлов с дистрибутива и размещение их в системе Инсталляция устройств Управление другими INF-фаилами Конфигурирование опций устройств INF-файлы представляют собой инициализационные файлы, которые конфигурируют устройство или приложение в вашей системе и задают его элементы в реестре. INF-файлы обычно поставляются производителем продукта вместе с устройством или приложением. Кроме того, можно их найти на электронных досках объявле- ний и других on-line сервисах. INF-файлы понадобятся вам для многих обычных (не РпР) устройств, которые вам нужно будет конфигурировать для работы с Windows 95. Как правило, INF-файлы включают список допустимых логических конфигураций, имена файлов драйверов устройств и г. д. В ряде случаев вам потребуется самим писать INF-файлы для устройств или программного обеспече- ния. Формат lNF-файлов аналогичен формату INIфайлов, которые использовались в Windows З.х, включая квадратные скобки, ключи и разделы, используемые то- лько Windows 95. Структура INF-файла ------------------- Когда вы инсталлируете новое устройство. Windows ищет INF-фаилы для этого устройства, используя при этом идентификатор устройства (device ID). Собрав из INF-фаила всю необходимую информацию, система создает в реестре элемент для этого устройства под ключом HKEY_LOCAL_MACHINE. Значения из INF-файла копируются в элемент реестра, соответствующий драйверу устройства. Такие значения, как DevLoader= и Driverdesc= включаются в элемент аппаратного драйвера Driver=. Элемент Еnum содержит значения Driver= и ConfigFlags=. INF-фаилы представляют собой файлы в формате ASCII, состоящие из нескольких разделов. Каждый раздел предназначен для выполнения определенной задачи. Имена разделов обычно заключаются в квадратные скобки. Типичные элементы представляют собой ключ и значение, соединенные знаком равенства. В раздел можно включить одно или несколько значений. Кроме того, в состав элемента можно включать комментарии, отделяя их символом точки с запятой, например: [section] keyname=value ;эта часть строки является комментарием Поскольку INF-файлы являются файлами формата ASCII, должен существовать способ, с помощью которого они будут предоставлять реестру информацию в двоичном формате. Структура INF определяет двоичный файл, который преобра- зует ASCII-текст в двоичный формат при чтении его реестром. Типы информационных файлов: Layout (Формат). Определяет информацию о диске и номере версии, а также содержит список всех файлов с указанием диска, на котором они располагают- ся. Selective Install (Избирательная инсталляция). Определяет части инстал- ляции, являющиеся необязательными компонентами, а также те ее части, кото- рые зависят от инсталляции других компонентов. Например, Microsoft Fax тре- бует предварительной загрузки Microsoft Exchange. Вы имеете возможность уп- равлять инсталляцией компонент этих типов. Application/Installation, APPS.INF (Приложения/Инсталляция). Обнаружива- ет используемые вами приложения MS-DOS и устанавливает для них параметры окружения. Эти lNF-файлы содержат настройки и параметры для многих приложе- ний DOS. Как правило, это самый большой информационный файл в вашей систе- ме. В его состав входят многие виды настройки памяти, настройки расширенной памяти (XMS), а также другие параметры, которые в Windows З.х содержались в настройках PIF Device Installation and Configuration (Инсталляция и конфигуриро вание устройств). Это наиболее общий из всех информационных файлов на котором мы до сих пор концентрировали все внимание. Эти файлы описывают параметры на- стройки для конкретных физических устройств. Если вы имеете драйвер устрой- ства ранних версий, в INF-файле будет содержаться информация об этом уст- ройстве. Устройства Plug and Play, с другой стороны, помещают информацию о себе прямо в реестр. Общая организация lNF-файла --------------------------- Раздел каждого устройства в INF-файлс состоит из следующих разделов: Раздел [Version]. Идентифицирует INF и класс поддерживаемого устройства. Ниже перечислен список некоторых устройств, которые вы можете включить: adapter keyboard NetService CDROM MCADevices NetTrans (сетевые транспорты) diskdrive media nodriver dispaly modem PCMCIA EISADevices monitor ports Fdc mouse printer Hdc MTD SCSIAdapter Раздел [Manufacturer]. Идентифицирует производителя устройства (например, Link, Micro, и т.п.) и соответствующих продуктов. Каждый INF-файл должен иметь по крайней мере один раздел [ Manufacturer]. Раздел [Install]. Содержит информацию о физических атрибутах устройства и его драйверах. Раздел [Classlnstall]. Этот раздел необязателен. Он идентифицирует новый класс для указанного уст- ройства в INF-фаиле Раздел [String]. Идентифицирует локализованные строки в INF-фаиле Раздел [Miscellaneous]. Содержит информацию о том, как устройства управляются пользовательским ин- терфейсом W95. Элементы APPS.INF ----------------- В разделе [appname] файла APPS.INF вы найдете элементы, перечисленные в табл. Используя эти элементы вы сможете быстрее перенести в W95 настройки PIF из ваших старых инсталляций Windows. Многие из приложений, перечисленных в файле APPS.INF, представляют собой старые игры для MS-DOS. Если вы сталкиваетесь с тем, что игра не работает в среде W95, просмотрите этот файл. Возможно, вам удастся модифицировать ка- кой-либо из его элементов таким образом, чтобы игра запустилась или стала работать лучше. Если вы вносите изменения в файл APPS.INF, вам потребуется перезагрузить W95, чтобы внесенные изменения попали в реестр. Помимо редак- тирования файла APPS.INF, некоторые из параметров вы можете изменить, от- крыв страницу свойств конкретного приложения. Ниже приведен пример раздела [аррname]: [PRODIGY.EXE] LowMem=440 EMSMen=None XMSMem=None Enable=lml Disable=win,hma В этой части файла APPS.INF раздел [appname] замещается именем исполняемого модуля, например, PRODIGY.EXE, PARADOX.EXE и т.п. Имя элемента реестра Описание ключа Значение ALLOWSSAVER Позволяет появляться заставке sav (работает в REALMODE) при работающих программах DOS. Настройка по умолчанию ALTENTER Позволяет использовать клавиатурную аеn комбинацию + для переклю- чения между полноэкранным и оконным режимами. Настройка по умолчанию. ALTESC Позволяет использовать выход с помощью Aes клавиатурной комбинации -. Настройка по умолчанию. ALTPRTSCRN Позволяет выполнять моментальный снимок Psc экрана с помощью клавиатурной комбинации +. Настройка по умолчанию. ALTSPACE Позволяет использовать клавиатурную aps комбинацию + для отображения системного меню. Настройка по умолчанию. ALTTAB Позволяет использовать клавиатурную ком- Ata бинацию для переключения между приложе- ниями. Настройка по умолчанию. BACKGROUND Дает приложению указание работать в win фоновом режиме. Настройка по умолчанию. CDROM Позволяет использовать драйвер MSCDEX. cdr (работает в REALMODE) Настройка по умолчанию. CLOSEONEXIT Закрывает при выходе окно DOS. He явля- cwe ется настройкой по умолчанию. CRTLESC Позволяет закрывать приложение нажатием ces клавиатурной комбинации +. Настройка по умолчанию. DETECTIDLE Задает чувствительность в неактивном сос- dit тоянии. Настройка по умолчанию. DISKLOCK Позволяет осуществлять прямой доступ к dsk (работает в REALMODE) диску. EMS Активизирует EMS386 для программ DOS. ems (работает в REALMODE) Настройка по умолчанию. EMSLOCKED Указывает на блокировку памяти EMS eml EMULATEROM Указывает на необходимость использо- emt вания быстрой эмуляции ROM. Настройка по умолчанию. EXCLUSIVE Работает в эксклюзивном режиме. Этот exc параметр игнорируется. FASTPASTE Активизирует быструю вставку из прило- aft жения. Настройка по умолчанию. GLOBALMEM Активизирует глобальную защиту памяти gmp LOWLOCKED Указывает на то, что нижняя память lml (до 640 Кб) заблокирована. Этот параметр игнорируется. MOUSE Активизирует функции мыши. Настройка по mse (работает в REALMODE) умолчанию. NETWORK Разрешает программе DOS получать доступ net (работает в REALMODE) к сетевым дискам и принтерам. Настройка по умолчанию. PRIVATECFG Позволяет программе DOS использовать пер- cfg (работает в REALMODE) сональный файл CONFIG.SYS. He является настройкой по умолчанию. REALMODE Запускает программу в реальном режиме DOS. dos He является настройкой по умолчанию. RETAINVRAM Дает указание сохранить видеопамять. rvm Этот параметр игнорируется. UNIQUESETTINGS Запускает программы DOS в отдельных DOS- uus сеансах. Не является настройкой по умолчаний. USEHMA Дает указание использовать НМА (верхние hma адреса памяти). Значение по умолчанию. VESA Дает программам DOS получать доступ к vsa (работает в REALMODE) продвинутым графическим возможностям. WINDOWED Запускает приложение в окне, а не в win полноэкранном режиме. Настройка по умолчанию. WINLIE Не позволяет программам DOS обнаруживать lie W95. Не яаляется параметром по умолчанию. XMSLOCKED Дает указание блокировать память XMS. Xml В файле APPS.INF доступны, но не реализованы следующие параметры: DISPLAYTBAR (dtb) Отображает панель инструментов. EXCLMOUSE (exm) Разрешает режим монопольного использования мыши QUICKEDIT (qme) Активизирует для мыши режим быстрого редактирования WARNIFACTIVE (wia). Позволяет подавать предупреждения, если приложение DOS еще активно Справочник по разделам ---------------------- В нижеприведенных таблицах описаны все ключевые слова и значения, ассоци- ированные с конкретными разделами. Синтаксис раздела [Version] приведен ни- же. Квадратные скобки используются для обозначения начала нового раздела. Для того чтобы настройки INF были понятны W95 и реестру, квадратные скобки обязательно должны присутствовать. [Version] Signature=$CHICAGO$ Class=name_of_class Provider=%File_creator% LayoutFile=filename.inf Ключевое слово Значение Описание Signature $Chicago$ Задает операционную систему для INF-файла. На момент написания большинства INF-файлов кодовое название Windows 95 было следующим: Chicago. Class name_of_class Указывает класс, который будет определен в ре- естре. Список общих классов устройств, которые вы можете ввести сюда, приведен в данном при- ложении ранее. LayoutFile filename.inf Эта строка определяет имя INF-файла, содержа- щего имена исходного диска и файлов, которые должны быть включены для инсталляции этого устройства. Если его не определить, то по умол- чанию файл имеет имя LAYOUT.INF. Если вы не включите эти данные в раздел Version, то должны будете включить в файл APPS.INF разделы SourceDiskName и SourceDiskFiles. Синтаксис раздела [Manufacturer] приведен ниже. [Manufacturer] "manufacturer" %string_value%=manufacturer_section Информация раздела [Manufacturer] Ключевое слово Описание "manufacturer" Имя производителя этого устройства, заключенное в кавычки. Сюда можно включить любую строку. Это клю- чевое слозо является необязательным. %string_value% Указывает имя строки, включенной в раздел Stings INF-файла. Строки должны быть заключены в символы процента (%). manufacturer_section Указывает на раздел Manufacturer Name в INF-файле. Раздел [Manufacturer Name] включает описания устройства для указанного уст- ройства Ключевые слова, используемые в этом разделе, описаны в таблице. Синтаксис этого раздела выглядит следующим образом: [name_of_manufacturer] description of deviсe=install_section,ID_of_device[compatible_device_IDs,...] Информация раздела [Manufacturer Name] Ключевое слово Описание description_of_device Описание инсталлируемого устройства. install_section Указывает имя раздела Install для этого устройства. ID_of_device Идентификатор (ID) инсталлируемого устройства. [compatible_device_IDs,...] Содержит Ссылки на устройства, совместимые с данным. В этот список можно включить несколько устройств, разделив их запятыми. Раздел [File List] можно использовать для указания файлов, которые вы хоти- те скопировать, переименовать или удалить. В зависимости от элемента разде- ла [Install] вы можете использовать три следующих синтаксических параметра: [file_list section] new_filename, old_filename Эта конструкция используется для элементов RenFiles. Допускается вклююние любого количества элементов new_filename, old_filename. Для элементов DelFiles используется следующий синтаксис: [file_list section] filename Параметр filename обозначает имя файла, который вы хотите удалить. Для элемента CopyFiles используется следующий синтаксис. Параметры source_filename и temporary_filename в этой конструкции являются необязате- льными. [file_list section] destination_filename,source_filename,temporary_filename Ниже приведен образец синтаксиса раздела [Install]. Этот раздел включает дополнительные разделы INF-файла, которые содержат описания устройства. В правой части выражения, после знака равенства, можно указать несколько зна- чений, разделенных запятыми. [name_of_install_section] LogConfig=section_name Copyfiles=file_list_section Renfiles=file_list_section DelFiles=file_list_section UpdateInis=UpdateIni_section_name UpdateIniFields=UpdateIniFields_section_name AddReg=AddRegitry_section DelReg=DelRegitry_section Ini2Reg=IniToRegistry_section UpdateCfgSys=UpdateConfig_section UpdateAutoBat=UpdateAutoexec_section Reboot или Restart Информация раздела [Install] Ключевое слово Значение Описание [name_of_install_section] Содержит имя устройства, соответ- ствующего информации, приведен- ной в этом разделе. В разделе ManufacturerName INF-файла дол- жна присутствовать ссылка на этот раздел LogСonfig section_name Содержит информацию о разделах логической конфигурации уст- ройства. Значения section_name указывают на разделы INF-файла в которых содержится информа- ция о данном устройстве. CopyFiles file_list_section Содержит информацию, необходимую для копирования указанного файла или файлов в каталог, указанный в разделе File_List. Вы можете дать системе указание скопировать отдельный файл. Для этого перед именем файла необходимо включить символ @. При этом файл будет скопирован в каталог DefaultDestDir, определенный в разделе DestinationDir INF-файла. RenFiles fiie_list_section Позволяет переименовать указан- ный файл. Представляет собой указатель на раздел File_List INF-файла. DelFiles file_list_section Позволяет удалить указанный файл. Представляет собой указа- тель на раздел FileList INF-файла. UpdateInis UpdateIni_section_name Позволяет указать Значение INI- файла, которое вы хотите изме- нить через INF-файл. Представля- ет собой указатель на раздел Update INI. UpdatelniFields UpdateIniFields_section_name Позволяет изменять, замещать или удалять отдельные элементы значений INI-файла (в отличие от предыдущего параметра, который изменял все значение целиком). Этот параметр представляет со- бой указатель на раздел Update IniFields. AddReg AddRegistry_section Позволяет указать подключ или значение, которые требуется до- бавить в реестр. Представляет собой указатель на раздел Add Registry. DelReg Del_Registry_section Позволяет указать подключ или значение, которые требуется уда- лить из реестра. Представляет собой указатель на раздел Delete Registry Ini2Reg IniToRegistry_section Перемещает в реестр строки и разделы из INI-файла. Представ- ляет собой указатель на раздел Ini to Registry. UpdateCfgSys UpdateConfig_section Содержит указатель на раздел Update Config. в этом разделе находятся команды, которые должны быть добавлены, удалены или переименованы в файле CONFIG.SYS. UpdateAutoBat UpdateAutoexec_section Содержит указатель на раздел Update AutoExec. В этом разделе находятся команды, которые мо- дифицируют файл AUTOEXEC.BAT. Reboot или Restart Команды, вызывающие перезапуск системы или перезагрузку ком- пьютера после завершения про- граммы установки. Ниже приведен пример синтаксиса раздела [Logical Configuration]. Раздел [LogConfig] необходимо указать в разделе [Install]. Этот раздел содержит информацию о конфигурации системных ресурсов, включая IRQ, порты ввода/вы- вода, каналы DMA и т. д. Для каждого включаемого элемента программа Setup создает запись логической конфигурации в двоичном формате и включает эту информацию в реестр в раздел driver. INF-файлы могут содержать несколько (или ни одного) разделов [Logical Configuration]. Ключевые слова и значения этого раздела описаны в таблице. [LogConfig Section name] ConfigPriority=value_of_priority MemConfig=menory_range_settings I/OConfig=ioport_settings IRQConfig=irq_sectings DMAConfig=dma_settings Ключевое слово Значение Описание ConfigPriority value_of_priority Содержит значение приоритета конфигурации для данного устрой- ства. MemConfig memory_range_settings Указывает диапазон памяти для данного устройства. I/OConfig ioport_settings Позволяет указать для устройства конфигурацию портов ввода/вывода. IRQConfig irq_settings Содержит СПИСОК допустимых IRQ для данного устройства. Если устройство не использует IRQ, не следует включать эту строку в INF-файл. DMAConfig dma_settings Указывает допустимые значения DMA для данного устройства. Для параметров настройки, перечисленных в таблице, можно указывать не один, а несколько ресурсов. Однако, в процессе инсталляции будет использован то- лько один из ресурсов, приведенных в списке. Чтобы указать несколько ресур- сов для одного устройства, вам потребуется создать соответствующее число записей для каждого из ресурсов. Ниже приведен пример синтаксиса раздела [Update AutoExec]. Имя раздела [UpdateAutoBat] должно быть указано в разделе [Install]. Этот раздел соде- ржит команды, манипулирующие строками в файле AUTOEXEC.BAT. Ключевые слова и значения этого раздела приведены в таблице. [Update_autobat_section] CmdDelete=command CmdAdd=command UnSet=environmentvariablename PreFixPath=%ldid% RemOldPath=%ldid% TmpDir=%ldid% Ключевое слово Значение Описание CmdDelete command Указывает команду, которая должна быть удалена из файла AUTOEXEC.BAT. Эта строка обрабатывается перед строкой CmdAdd. CmdAdd command Указывает команду, которую требуется добавить в файл AUTOEXEC.BAT. UnSet environmentvariablename Указывает переменную окружения, кото- рую вы хотите удалить из файла AUTOEXEC.BAT. PreFixPath %ldid% Позволяет включить предопределенную фиксированную переменную path в форме логического идентификатора каталога (logical directory identificator, LDID). RemOldPath %ldid% Позволяет указать путь, который должен быть удален из файла AUTOEXEC.BAT. TmpDir %ldid% Позволяет указать временный каталог на время установки. Ниже приведен пример синтаксиса раздела [Update Config]. Имя раздела [Update_config_section] должно быть задано в разделе [Install]. Этот раздел содержит команды манипуляции со строками в файле CONFIG.SYS. Ключевые слова и значения этого раздела описаны в таблице. [Update_config_section] DevRename=current_name,new_name DevDelete=driver_name DevAddDev=driver_name,configkeyword Stacks=dos_stack_values Buffers=dos_buffer_values Files=dos_buffer_values LastDrive=dos_lastdrive_value Ключевое слово Значение Описание DevRename current_name,new_name Позволяет переименовать драйверы устройств, вызываемые из файла CONFIG.SYS. Раздел может содержать несколько строк DevRename. Записи DevRename обрабатываются первыми, прежде, чем начнется обработка каких-либо других записей раздела. DevDelete driver_name Позволяет указать драйверы устройств, которые должны быть удалены из файла CONFIG.SYS. Раздел может содержать несколько записей DevDelete. DevAddDev driver_name,configkeyword Позволяет указать новый драйвер, который должен быть добавлен в файл CONFIG.SYS. Раздел может содержать несколько записей DevAddDev. Stacks dos_stack_values Указывает значение Stacks= в файле CONFIG.SYS. Buffers dos_buffer_values Указывает значение Buffers= в файле CONFIG.SYS. Files dos_file_values Указывает значение Files= в файле CONFIG.SYS. LastDrive dos_lastdrive_value Указывает значение lastdrive= в файле CONFIG.SYS. Ниже приведен пример синтаксиса раздела [Update INI]. Раздел [Update INI] необходимо указать в разделе [Install] записью UpdateINIs. Этот раздел добавляет, удаляет или замещает записи в указанном INI-фаЙле. Ключевые слова и значения для этого раздела описаны в таблице. [Update_ini_section] ini-file,ini-section,original_entry,new_entry, options Значение Описание options Необязательные флаги операции, которые могут принимать одно из следующих значений 0 Значение по умолчанию. Ищет ключ (имя записи) original_entry, игнорируя его значение. Если ключ при- сутствует, соответствующая запись заменяется на new_entry. Если original_entry равна NULL, new_entry добавляется безусловно. Если new_entry равна NULL, original_entry удаляется. 1 Ищет запись original_entry по ключу и значению. Обнов- ление выполняется только в том случае, когда совпадают и ключ, и значение записи original_entry. 2 Ищет запись, ключ которой совпадает с указанным в original entry. Если запись уже существует, она не за- мещается значением, указанным вами в new_entry. 3 Ищет запись, ключ и значение которой совпадают с указанными в original_entry. Если такая запись существует, она замещается new_entry. Ниже приведена синтаксическая конструкция раздела [Update IniFields]. Имя раздела [UpdatelniFields] должно быть указано элементом [UpdatelniFieldsl в разделе [Install]. Утверждения этого замещают, добавляют или удаляют поля в указанной записи INI-файла. В отличие от раздела [Update INI], команды из данного раздела работают с фрагмента- ми записей, а не с записями в целом. [update_inifields_section] ini-file,ini-section,profile_name,old_field,new_field Если в строке INI-файла для указанной записи присутствовал комментарий, он удаляется. Модификаторы old_field и new_field являются необяза- тельными. Раздел [Add Registry] позволяет добавлять в реестр ключи и значения. Кроме того, существует необязательная возможность установить фактиче- ское значение. Имя раздела [add_registry_section] должно быть задано элементом AddReg раздела [Install]. Синтаксис раздела выглядит следую- щим образом: [add_registry_section] reg_root_string В этот раздел вы можете включить подключи, имена значений и (необязательно) сами значения. Раздел [Delete Registry] используется для удаления из реестра подклю- чен и имен значений. Синтаксис этого раздела выглядит следующим обра- зом: [del_registry_section] reg_root_string,subkey Имя этого раздела должно быть указано элементом DelReg в разделе [Install]. Каждый элемент, включенный в этот раздел, удалит из реестра подключ или значение. Раздел [Ini to Registry] позволяет перемещать в реестр строки и разде- лы из INI-файла. Эта операция или создает в реестре новый элемент, или подключ или значение. Имя раздела [ini_to_registry section] должно быть указано элементом lni2Reg в разделе [Install]. Раздел [DestinationDirsI позволяет определить каталог назначения для раздела [File_List]. Ссылка на имя раздела [DestinationDirs] должна присутствовать в одном из следующих трех элементов раздела [Install]: DelFiles, CopyFiles или RenFiles. Синтаксис раздела приведен ниже. Более подробную информацию можно найти в таблице. [DestinationDirs] file_list=ldid,subdirectory DefaultDestDir=ldid,subdirectory Ключевое слово Значение Описание file_list ldid,subdirectory Указывает имя раздела FileList. subdirectory Указывает каталог, находящийся в каталоге ldid. Это значение необязательно. ldid Указывает логический идентификатор диска. Список допустимых значений ldid приведен далее. DefaulDestDir Позволяет указать каталог-приемник по умолчанию для всех неупомянутых разделов File_List. Этот параметр не является обязательным. По умол- чанию W95 использует каталог LDID_WIN. Раздел [SourceDisksFilesj используется для указания исходных файлов, используемых в процессе инсталляции. Кроме того, с помощью этого разде- ла можно указать исходные диски, содержащие эти файлы. Синтаксис раз- дела очень прост: [SourceDisksFiles] name_of_source_disk=disk_number Элемент disk_number определяется в разделе [SourceDisksNames], кото- рый использует следующий синтаксис: [SourceDisksNames] disk_ordinal=description_of_disk,label,serial_number Раздел [ClassInstall] устанавливает новый класс устройства в разделе реестра [Class]. Синтаксис раздела [ClassInstall] приведен ниже. Подробную информацию о значениях и элементах, которые используются в этом разделе, можно найти в таблице выше. [ClassInstall] CopyFiles=fils_list_section RenFiles=fils_list_section DelFiles=fils_list_section UpdateInis=UpdateIni_section_name UpdateIniFields=UpdateIniFields_section_name AddReg=AddRegistry_section DelReg=DelRegistry_section Наконец, последним разделом INF-фаила является раздел [Strings]. Этот раздел определяет один или несколько строковых ключей. Синтаксис этого раздела приведен ниже. [Strings] string_key="valve" Ключевое слово string_key обозначает строковый ключ, формирующийся из буквенно-цифровых символов, например, MfgName. Хотя раздел [Strings] обычно является последним в INF-файле, строковые ключи можно использовать везде, где допустимо употребление строк. Программа Setup подставляет вместо строкового ключа строку, заданную элементом "value" и в дальнейшем использует именно ее, например: MSFT="Microsoft" Встпетив строку MSFT. поогоамма Setup интерпретирует ее как Microsoft Значения LDID ------------- В таблице перечислены допустимые значения LDID (logical disk identifier), которые вы можете использовать в INF-файлах. ID Обозначает 00 Пустой LDID; используется для создания нового LDID 01 Исходное устройство:\путь 02 Временный каталог Setup; используется только в процессе установки W95 03 Каталог Uninstall 04 Каталог Backup 10 Каталог Windows 11 Каталог SYSTEM 12 Каталог lOsubsys 13 Каталог COMMAND 14 Каталог Control Panel 15 Каталог Printers 16 Каталог Workgroup 17 Каталог INF 18 Каталог Help 19 Каталог Administration 20 Каталог Fonts 21 Каталог Viewers 22 Каталог VMM32 23 Каталог Color 25 Каталог Shared 26 Каталог Winboot 27 Машинно-зависимый каталог 28 Каталог Winboot Host 30 Корневой каталог загрузочного устройства 31 Корневой каталог хост-диска виртуального загрузочного устройства 32 Каталог с прежней версией Windows (если есть) 33 Каталог с прежней версией MS-DOS (если есть)DB Просмотр удаленных записей в DBase
При удалении записей в таблицах dBASE на самом деле происходит пометка записи на удаление, в то время как сами записи остаются в файле,
пока таблица не будет упакована. Поэтому "удаленные" записи можно просмотреть, и даже восстановить их. Чтобы показать помеченные на удаление записи, нужно использовать функцию BDE DbiSetProp. Ниже приведен пример функции-оболочки для DbiSetProp.
Ей передается в качестве параметра таблица и логическая переменная, означающая показывать удаленные записи, или нет.
Таблица может быть открыта или закрыта. procedure TForm1.ShowDeleted(Table: TTable; ShowDeleted: Boolean); var rslt: DBIResult; szErrMsg: DBIMSG; begin Table.DisableControls; try Check(DbiSetProp(hDBIObj(Table.Handle), curSOFTDELETEON, LongInt(ShowDeleted))); finally Table.EnableControls; end; Table.Refresh; end; Упаковка таблицы Paradox
function PackParadoxTable(Tbl: TTable; Db: TDatabase):DBIResult; var TblDesc: CRTblDesc; begin Result := DBIERR_NA; FillChar(TblDesc, SizeOf(CRTblDesc), 0); StrPCopy(TblDesc.szTblName, Tbl.TableName); TblDesc.bPack := True; Result := DbiDoRestructure(Db.Handle, 1, @TblDesc, nil, nil, nil,False); end; Таблица, передаваемая в качестве второго параметра, должна быть закрыта. Как заставить BDE производить запись изменений в таблицах Paradox на диск?
ОТВЕТ: // Сбрасывает табличные буфера, физически на диск function TMyUtil.flushBuf : Boolean; var tmpDM: TDataModule; i: LongInt; begin result:=3Dtrue; with YouDateModule or You table for i:=3D0 to ComponentCount-1 do begin if components[i] is TTable then begin with components[i] as TTable do begin if active then begin if (DbiSaveChanges(Handle)=3DDBIERR_NONE) then begin FlushBuffers; end //if else begin ShowMessage('Ошибка сброса на диск ' + TableName); result:=3Dfalse; end; end; //if active=20 end; //with end; //if end; //for end; //with end; Кроме того, не забывайте из той программы, которая хочет просмотреть изменения вызывать refresh для нужной таблицы. Ускорение работы с последовательностью записей.
var s: String; begin Table1.Open; ............ while not Table1.eof do begin s := Table1.FieldByName('...').AsString; ........ Table1.Next; end; Table1.Close; end; можно записать var s: String; f: TField; begin Table1.Open; f := Table1.FieldByName('...'); {!!!!!} ............ while not Table1.eof do begin s := f.AsString; {!!!!!} ........ Table1.Next; end; Table1.Close; end; Путь к локальной таблице.
implementation {$R *.DFM} uses DbiTypes, DbiProcs; function fDbiFormFullName(Tbl: TTable): String; var Props: CurProps; Buffer1 : array[0..DBIMAXPATHLEN] of char; Buffer2 : array[0..DBIMAXPATHLEN] of char; begin Check(DbiGetCursorProps(Tbl.Handle,Props)); StrPCopy(Buffer1, Tbl.TableName); Check(DbiFormFullName(Tbl.DBHandle, @Buffer1, Props.szTableType, @Buffer2)); Result := StrPas(Buffer2); end; Notes: Table_You_Are_Using.Active Must be True. Works on Local Tables. Создание алиасов.
procedure CheckAlias(const AliasName, AliasType, AliasPath: String); { Если алиас не существует, создать его } var SList: TStrings; i: Integer; AliasFound: Boolean; begin { Проверка существования алиса BDE } try SList := TStringList.Create; Session.GetAliasNames(SList); AliasFound := False; for i:=0 to SList.Count-1 do if SList[i]=AliasName then begin AliasFound := True; break; end; finally SList.Free; end; if AliasFound then begin try SList := TStringList.Create; Session.GetAliasParams(AliasName,SList); {А в 4-ой версии SList[2]!!! и без слова Path } if SList[0]<>'PATH='+AliasPath then { Правильно ли задан путь } begin SList[0] := 'PATH='+AliasPath; Session.ModifyAlias(AliasName,SList); end; finally SList.Free; end; end else Session.AddStandardAlias(AliasName,AliasPath,AliasType); { Создать новый алиас } Session.SaveConfigFile; end;SQL Как в DELPHI 3 заполнить поле одним и тем же значением сразу у многих записей?
ОТВЕТ: Для заполнения поля таблицы определенным значением сразу для многих записей необходимо воспользоваться командами SQL, а именно - командой UPDATE. Где в секции WHERE и определить условие, которому и отвечают эти записи.
В случае отсутствия секции WHERE будут заполнены все записи таблицы.
Чтобы выполнить этот запрос из Delphi, достаточно создать компоненту типа TQuery
(кстати, совершенно не обязательно делать ее визуальной, можно просто создать экземпляр этого типа) и заполнить свойство SQL
соответствующим текстом.
Или в инспекторе объектов или в коде программы. Например: Query.SQL.ADD('UPDATE Table SET DateToDay=:CurrentDate WHERE Sum > 0 '); Тогда для всех строк, у которых поле Sum положительно, будет произведена замена поля DateToDay значением переменной CurrentDate. Для исполнения этой замены необходимо задать значение параметра и выполнить запрос. Query.Close; Query.ParamByName('CurrentDate').AsDateTime:=Now; Query.Open; Замена произведена. Елена ФилипповаСетевые ф-ии WSAAsyncSelect: параметр handle при запускаете dll (init).
const WM_ASYNCSELECT = WM_USER+0; TNetConnectionsManager = class(TObject) protected FWndHandle : HWND; procedure WndProc( var MsgRec : TMessage ); ... end; constructor TNetConnectionsManager.Create begin inherited Create; FWndHandle := AllocateHWnd(WndProc); ... end; destructor TNetConnectionsManager.Destroy; begin ... if FWndHandle<>0 then DeallocateHWnd(FWndHandle); inherited Destroy; end; procedure TNetConnectionsManeger.WndProc( var MsgRec : TMessage ); begin with MsgRec do if Msg=WM_ASYNCSELECT then WMAsyncSelect(MsgRec) else DefWindowProc( FWndHandle, Msg, wParam, lParam ); end; Hо pекомендую посмотpеть WinSock2, в котоpом можно: WSAEventSelect( FSocket, FEventHandle, FD_READ or FD_CLOSE ); WSAWaitForMultipleEvents( ... ); WSAEnumNetworkEvents( FSocket, FEventHandle, lpNetWorkEvents ); То есть, обойтись без окон и без очеpеди сообщений windows, а заодно иметь возможность pаботать и с IPX/SPX, и с netbios. Свой winsock2.pas я вчеpа кинул в RU.DELPHI.DB, если кто имеет такой из дpугих источников - свистните погpомче. Alex Konshin alexk@msmt.spb.su (2:5030/217) Как сделать чтобы при событиях моя программа отпpавляла кому-либо сообщение на мой компьютеp.
Win32: F1 "NetMessageBufferSend" Win16: Почему-то неописан, но руками наковырял... function NetMessageBufferSend( Zero1, Zero2: Word; WhoTo: PChar; Buffer: PChar; BufSize: Word): Integer; external 'NETAPI' index 525; Александр Петросян(PAF, Alexander Petrosyan), Зеленоград.(2:5020/468.8) Как работать с поименованными каналами под W'95/NT в сети?
сервер : StrPCopy(buff,Edit1.Text); fPipeHandle:=CreateNamedPipe(buff, Pipe_Access_Duplex or File_Flag_Overlapped, Pipe_Type_Message or Pipe_ReadMode_Byte or Pipe_Wait, 5, $400, $400, 235, nil); клиент : StrPCopy(buff,Edit1.Text); fFileHandle:=CreateFile(buff, Generic_Read or Generic_Write, File_Share_Read or File_Share_Write, nil, Open_Existing, File_Attribute_Normal or File_Flag_Overlapped or Security_Anonymous, 0); if fFileHandle <> Invalid_Handle_Value then begin ... Jack Sinelnikov (2:5054/9.13) Как подключать сетевые диски?
Вот pабочий кусок кода из пpогpаммы "мэйлеpа" сетевой FIDO станции: var nw:TNetResource; ... nw.dwType:=RESOURCETYPE_DISK; nw.lpLocalName:=nil; nw.lpRemoteName:=PChar('\\'+MailServer.RemoteName+'\MAIL'); nw.lpProvider:=nil; if MailServer.Password<>'' then Err:=WNetAddConnection2(nw,PChar(MailServer.Password),nil,0) else Err:=WNetAddConnection2(nw,nil,nil,0); If Err=NO_ERROR then begin ... end; MailServer.RemoteName и Password -- имя удаленного компа в сети и паpоль доступа к pесуpсу соответвенно. ps.: так, как написано, ты будешь к pесуpсу обpащаться как к '\\Comp\Disc'. если хочешь подключить сетевой pесуpс как локальный диск -- меняй nw.lpLocalName. pps.: когда(если) закончишь юзать сетевой диск, ставь WNetCancelConnection2. Vadim Saitov (2:5011/76.13)Стандартные элементы управления Мне надо добавить много строк в TListbox или в TCombobox
или в TMemo или в TRichEdit, при этом сам объект постоянно мигает, перерисовываясь. Как избавиться от этого?

BeginUpdate/EndUpdate. Многоколоночный ListBox.
ListCtrl из common controls. У него есть такой стиль. ------------------------------ В книгах и других источниках по Delphi часто приводится пример создания компонента,
способного выводить текст в списке в несколько колонок.
Между тем, мало кому известен факт, что стандартный компонент TListBox уже содержит свойство, которое позволяет это делать.
Это свойство TabWidth (в Delphi 2 оно не описано в файлах помощи, хотя так же присутствует),
которое наследуется от класса TCustomListBox и задает величину табуляции в пикселах.
Установите его равным, скажем, половине ширины компонента ListBox, чтобы отображалось две колонки.
Когда будете добавлять строки, всавьте в нужных местах символ табуляции (^I): ListBox1.Items.Add('Колонка1'^I'Колонка2'); Недостаток такого подхода заключается в том, что ширина колонки не изменяется авоматически
в зависимости от ширины выводимых строк, что, впрочем, легко исправить.
Посмотрите на метод TextWidth класса TCanvas. Он возвращает ширину в пикселах передаваемой ему в качестве параметра строки.
Тогда перед добавлением каждого нового элемента в список проверяем, превышает ли его ширина ширину колонки: with ListBox do begin W := Canvas.TextWidth(Str); if W > TabWidth then TabWidth := W; end; Как указать максимальный размер текста для RichEdit Control?
У этого компонента есть свойство MaxLength, которое работает некорректно. Поэтому лучше пользоваться RichEdit.Perform(EM_LIMITTEXT, нужный размер, 0); Причем перед каждом открытии файла это действие необходимо повторять. Maxim Liverovskiy (2:5030/254.38) Если Вы передаете в качестве размера 0, то ОС ограничивает размер OS Specific Default Value. Реально, по результатам моих экспериментов, поставить можно размер, чуть меньший доступной виртуальной памяти. Я ограничился 90% от свободной виртуалки. Для того, чтобы не повторять этот вызов (EM_LIMITTEXT), можно воспользоваться сообщением EM_EXLIMITTEXT. Stas Mehanoshin (2:5030/143.23) Выделение стpочек в TTreeView жиpным или бледным.
procedure SetNodeState(node :TTreeNode; Flags: Integer); var tvi: TTVItem; begin FillChar(tvi, Sizeof(tvi), 0); tvi.hItem := node.ItemID; tvi.mask := TVIF_STATE; tvi.stateMask := TVIS_BOLD or TVIS_CUT; tvi.state := Flags; TreeView_SetItem(node.Handle, tvi); end; И вызываем: SetNodeState(TreeView1.Selected, TVIS_BOLD); // Текст жиpным SetNodeState(TreeView1.Selected, TVIS_CUT); // Иконкy бледной (Ctrl+X) SetNodeState(TreeView1.Selected, TVIS_BOLD or TVIS_CUT); // Текст жиpным SetNodeState(TreeView1.Selected, 0); // Hи того, ни дpyгого Dmitry Nogin (FidoNet 2:5020/611.15) Как в TMemo определить номер строки, в которой находится курсор и его местоположение в строке.
var X,Y: LongInt; ............ Y:=Memo1.Perform(EM_LINEFROMCHAR, Memo1.SelStart, 0); X:=Memo1.Parform(EM_LINEINDEX, Y, 0); inc(Y); X:=Memo1.SelStart-X+1; ........ Alexey Glotov (2:5020/382.18) Выделение стpок в TTreeView жиpным/бледным.
procedure SetNodeState(node :TTreeNode; Flags: Integer); var tvi: TTVItem; begin FillChar(tvi, Sizeof(tvi), 0); tvi.hItem := node.ItemID; tvi.mask := TVIF_STATE; tvi.stateMask := TVIS_BOLD or TVIS_CUT; tvi.state := Flags; TreeView_SetItem(node.Handle, tvi); end; И вызываем: SetNodeState(TreeView1.Selected, TVIS_BOLD); // Текст жиpным SetNodeState(TreeView1.Selected, TVIS_CUT); // Иконкy бледной (Ctrl+X) SetNodeState(TreeView1.Selected, TVIS_BOLD or TVIS_CUT); // Текст жиpным SetNodeState(TreeView1.Selected, 0); // Hи того, ни дpyгого Когда-то (мечтательно закатив глаза в потолок) в API было еще и TVIS_DISABLE. Снесли собаки.
А pекомендyемyю стилистикy yпотpебления этого добpа смотpи в MS Internet News. Dmitry Nogin (FidoNet 2:5020/611.15) Позициированиие в ListBox.
procedure TForm1.Edit1Change(Sender: TObject); var S : Array[0..255] of Char; begin StrPCopy(S, Edit1.Text); with ListBox1 do ItemIndex := Perform(LB_SELECTSTRING, 0, LongInt(@S)); end;Элементы VCL Отправка сообщений компонентам
Если вам необходимо послать сообщение Windows (или ваше собственное) какому-либо компоненту, воспользуйтесь методом Perform.
Этот метод вводится в классе TControl, поэтому его имеют все визуальные компоненты.
Метод Perform посылает сообщение непосредственно оконной процедуре компонента, минуя очередь сообщений Windows, в отличие от функций API SendMessage и PostMessage, которые посылают сообщения в очередь. Пример: Panel1.Perform(WM_LButtonDown, 0, MakeLong(1, 1)); Panel1.Perform(WM_LButtonUp, 0, MakeLong(1, 1)); Ускорение работы TMemo
Если в вашей программе происходит добавление большого количества строк в компонент Memo, то операцию можно значительно ускорить.
Для этого нужно вызвать метод BeginUpdate перед добавлением строк, и метод EndUpdate после добавления: Memo1.Lines.BeginUpdate; ... {добавляем множество строк ...} ... Memo1.Lines.EndUpdate; Вышесказанное в равной степени относится к компоненту ListBox и его свойству Items,
а также к другим компонентам, которые имеют свойства типа TStrings. Как привязать к конкретному компоненту дополнительную информацию?
Не забывайте про свойство Tag: его вполне хватит для размещения в нем указателя на произвольную информацию. Пример: --- динамическое создание и привязка текстовой строки. begin for i := 0 to ComponentCount - 1 do if Components[i] is TEdit then Components[i].Tag := LongInt(NewStr('Hello '+IntToStr(i))); end; ---освобождение памяти begin for i := 0 to ComponentCount - 1 do if Components[i] is TEdit then begin TEdit(Components[i]).Text := PString(Components[i].Tag)^; DisposeStr(PString(Components[i].Tag)); end; end; --- Cвойство Hint
Если Hint является полем Вашей компоненты, например FHint:THintWindow, тогда в конструкторе Create Вашей компоненты можно например его инициализировать: FHint:=THintWindow.Create(Self); FHint.Parent:=Self.Parent; далее при необходимости отобразить Hint: R:=Rect(x1,y1,x2,y2); FHint.ActivateHint(R,''); FHint.Caption:='my hint; Почему сразу не передать строку в качестве второго параметра метода ActiveHint? Вначале эта строка будет отображаться в прямоугольнике по умолчанию, левый верхний угол которого имеет координаты (0,0) в системе координат всего экрана (!) и только потом перемещаться в координаты (R.X , R.Y) - это приводит к не очень красивому "морганию" Hint'a, особенно если строка достаточно большая (>10 символов). при необходимости скрыть Hint: FHint.Caption:=''; R:=Rect(0,0,0,0); FHint.ActivateHint(R,''); такая последовательность действий объясняется теми же причинами, что и при показе Hint'a. - DIJ 1'95 Каким образом можно отследить вставку и удаление компонент в форму в design-time?
Для получения такой информации предназначен метод procedure Notification (AComponent: TComponent; Operation: TOperation); virtual; класса TComponent. Перекрыв его в своей компоненты Вы можете произвести необходимые действия,
в зависимости от значения параметра Operation типа TOperation = (opInsert, opRemove); объявленного в модуле Classes. Параметр AComponent - компонента, соответственно вставлемая или удаляемая, в зависимости от Operation. Как создать копию произвольного компонента?
{ Здесь пpоцедypа CreateClone, котоpая кpеатит компонентy ОЧЕHЬ ПОХОЖУЮ на входнyю. С такими же значениями свойств. Пpисваивается все, кpоме методов. } function CreateClone(Src: TComponent): TComponent; var F: TStream; begin F := nil; try F := TMemoryStream.Create; F.WriteComponent(Src); RegisterClass(TComponentClass(Src.ClassType)); F.Position := 0; Result := F.ReadComponent(nil); finally F.Free; end; end; Как использовать ChartFX.
with ChartFX do begin Visible := false; { Устанавливаем режим ввода значений } { 1 - количество серий (в нашем случае 1), 3 - количество значений } OpenData [COD_VALUES] := MakeLong (1,3); { Hомер текущей серии } ThisSerie := 0; { Value [i] - значение с индексом i } { Legend [i] - комментарий к этому значению } Value [0] := a; Legend [0] := 'Значение переменной A'; Value [1] := b; Legend [1] := 'Значение переменной B'; Value [2] := c; Legend [2] := 'Значение переменной C'; { Закрываем режим } CloseData [COD_VALUES] := 0; { Ширина поля с комментариями на экране (в пикселах) } LegendWidth := 150; Visible := true; end; end;Формы Как сделать так, чтобы по Alt-F4 форма не закрывалась, а выдавала запрос на сохранение?
Обрабатывать OnCloseQuery. Как правильно создавать компоненты в run-time?
---cut--- procedure TForm1.CreateButton; var btn : TButton; begin btn := TButton.Create(Self); { Уничтожать кнопку будет форма } btn.Parent := Self; { Родителем кнопки будет форма } btn.OnClick := ButtonClicked; { Процедура, которая будет исполняться при } btn.Visible := true; { нажатии на кнопку } end; ---cut--- Как можно перетаскивать форму не только за заголовок?
WM_NCHITTEST. === Cut === Как сделать так, чтобы в моей форме курсор перемещался по полям ввода по Enter, как по Tab?
Если вы хотите обрабатывать событие на уровне формы (а не в каждом отдельном компоненте),
уберите обработчики события у всех компонент и создайте FormKeyPress -- обработчик OnKeyPress для формы: ---cut--- procedure Form1.OnKeyPress(Sender : TObject; var Key : char); begin if Key = #13 then begin SelectNext(Sender as TWinControl, true, true); Key := #0; end; end; ---cut--- ( NB:нyжно выставлять y фоpмы KeyPreview = True; default-кнопки на фоpмy поместшать нельзя ). Как запретить кнопку Close [x] в заголовке окна.
Вот кусок, который делает все, что тебе нужно: procedure TForm1.FormCreate(Sender: TObject); var Style: Longint; begin Style := GetWindowLong(Handle, GWL_STYLE); SetWindowLong(Handle, GWL_STYLE, Style And Not WS_SYSMENU); end; procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if (Key = VK_F4) and (ssAlt in Shift) then begin MessageBeep(0); Key := 0; end; end; Alexander Petrushev (2:5001/88.10) 'а самом деле есть более простой способ (запрет на SC_CLOSE), но я уже деталей его не помню. Akzhan Abdulin (2:5040/55) === Cut === { Disable close button } procedure TForm1.Button1Click(Sender: TObject); var SysMenu: HMenu; begin SysMenu := GetSystemMenu(Handle, False); Windows.EnableMenuItem(SysMenu, SC_CLOSE, MF_DISABLED or MF_GRAYED); end; { Enable close button } procedure TForm1.Button2Click(Sender: TObject); begin GetSystemMenu(Handle, True); Perform(WM_NCPAINT, Handle, 0); end; === Cut === 'о это окно можно закрыть из TaskBar'а. Vlad Filyakov (2:5022/26.9) И все же, кажется, я делал иначе. :( Akzhan Abdulin (2:5040/55) Как отобразить некоторые окна своей программы в панели задач Windows (помимо главного окна)
Hапример, так: procedure TMyForm.CreateParams(var Params :TCreateParams); {override;} begin inherited CreateParams(Params); {CreateWindowEx} Params.ExStyle := Params.ExStyle or WS_Ex_AppWindow; end; Max Rusov (2:5030/456.1) Свертывание фоpмы при откpытом модальном окне.
function TMyModalForm.Execute: TModalResult; begin Show; try SendMessage(Handle, CM_ACTIVATE, 0, 0); ModalResult := 0; repeat Application.HandleMessage; if Application.Terminated then ModalResult := mrCancel; if ModalResult = mrCancel then CloseModal; until ModalResult <> 0; Hide; Result := ModalResult; SendMessage(Handle, CM_DEACTIVATE, 0, 0); finally Hide; end; end; ( TMyForm должно быть FormStyle := fsStayOnTop ) Eugeny D.Shtefanov shtefanov@usa.net -- Дорабатывайте ф-ию по вашему желанию. Имея имя фоpмы нyжно пеpебpать на ней все компоненты имеющие свойство font.
uses TypInfo; в цикле по всем объектам формы if GetPropInfo( nil then <твои действия> Необходимо, чтобы дочерняя форма не активизировала родительское окно.
Сделайте родительским окном рабочий стол. --- procedure TForm2.CreateParams(VAR Params: TCreateParams); begin Inherited CreateParams(Params); Params.WndParent := GetDesktopWindow; end; --- Как использовать форму из DLL ?
Это файл Form.dpr, из которого получается DLL: library Form; uses Classes, Unit1 in 'Unit1.pas' {Form1}; exports CreateMyForm, DestroyMyForm; end. Это его Unit1: unit Unit1; interface [раздел uses и определение класса Form1 поскипаны] procedure CreateMyForm(AppHandle : THandle); stdcall; procedure DestroyMyForm; stdcall; implementation {$R *.DFM} procedure CreateMyForm(AppHandle : THandle); begin Application.Handle:=AppHandle; Form1:=TForm1.Create(Application); Form1.Show end; procedure DestroyMyForm; begin Form1.Free end; end. Это UnitCall вызывающего EXE-шника: unit UnitCall; interface [раздел uses и определение класса Form1 поскипаны] procedure CreateMyForm(AppHandle : THandle); stdcall; external 'Form.dll'; procedure DestroyMyForm; stdcall; external 'Form.dll'; implementation {$R *.DFM} procedure TForm1.Button1Click(Sender: TObject); begin CreateMyForm(Application.Handle) end; procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin DestroyMyForm end; end.MDI MDI-приложение, в котором способны сливаться не только меню дочернего и главного окна,
но и полосы инструментов?

>Ваpиант 1. CoolBar. procedure TMainForm.SetBands(AControls: array of TWinControl; ABreaks: array of boolean); var i: integer; begin with CoolBar do begin for i:=0 to High(AControls) do begin if Bands.Count=succ(i) then TCoolBand.Create(Bands); with Bands[succ(i)] do begin if Assigned(Control) then Control.Hide; MinHeight:=AControls[i].Height; Break:=ABreaks[i]; Control:=AControls[i]; Control.Show; Visible:=true; end end; for i:=High(AControls)+2 to pred(Bands.Count) do Bands[i].Free end end; и procedure TMsgForm.FormActivate(Sender: TObject); begin MainForm.SetBands([ToolBar],[false]) end; Пpимечание: Оба массива pавны по длине. CoolBar.Bands[0] должен существовать всегда,.. на нём я pазмешаю "глобальные" кнопки. СoolBar[1] тоже можно сделать в DesignTime с Break:=false и пpидвинуть поближе с началу. Пpи CoolBar.AutoSize:=true возможно "мигании" (пpи добавлении на новую стpоку) так что можно добавить: AutoSize:=false; try ... finally AutoSize:=true; >Ваpиант 2. TMainForm ... object SpeedBar: TPanel ... Align = alTop BevelOuter = bvNone object ToolBar: TPanel ... Align = alLeft BevelOuter = bvNone end object RxSplitter1: TRxSplitter ... ControlFirst = ToolBar ControlSecond = ChildBar Align = alLeft BevelOuter = bvLowered end object ChildBar: TPanel .... Align = alClient BevelOuter = bvNone end end > TMdiChild {пpоподитель всех остальных} ... object pnToolBar: TPanel ... Align = alTop BevelOuter = bvNone Visible = False end procedure TMDIForm.FormActivate(Sender: TObject); begin pnToolBar.Parent:=MainForm.ChildBar; pnToolBar.Visible:=True; end; procedure TMDIForm.FormDeactivate(Sender: TObject); begin pnToolBar.Visible:=false; pnToolBar.Parent:=self {pnToolBar.Visible:=false} end; Jury Martynov (2:5020/800.21)Работа с принтером Простейший способ печати.
=== Cut === var file_ : textfile; begin AssignFile ( file_, 'prn' ); Rewrite ( file_ ); WriteLn ( file_, 'print me' ); CloseFile ( file_ ); end. === Cut === Как мне отправить на принтер чистый поток данных?
Под Win16 Вы можете использовать функцию SpoolFile, или Passthrough escape, если принтер поддерживает последнее. Под Win32 Вы можете использовать WritePrinter. 'иже пример открытия принтера и записи чистого потока данных в принтер. Учтите, что Вы должны передать корректное имя принтера, такое, как "HP LaserJet 5MP", чтобы функция сработала успешно. Конечно, Вы можете включать в поток данных любые необходимые управляющие коды, которые могут потребоваться. uses WinSpool; procedure WriteRawStringToPrinter(PrinterName:String; S:String); var Handle: THandle; N: DWORD; DocInfo1: TDocInfo1; begin if not OpenPrinter(PChar(PrinterName), Handle, nil) then begin ShowMessage('error ' + IntToStr(GetLastError)); Exit; end; with DocInfo1 do begin pDocName := PChar('test doc'); pOutputFile := nil; pDataType := 'RAW'; end; StartDocPrinter(Handle, 1, @DocInfo1); StartPagePrinter(Handle); WritePrinter(Handle, PChar(S), Length(S), N); EndPagePrinter(Handle); EndDocPrinter(Handle); ClosePrinter(Handle); end; procedure TForm1.Button1Click(Sender: TObject); begin WriteRawStringToPrinter('HP', 'Test This'); end; (Borland FAQ N714, переведен Акжаном Абдулиным) Как исправить ошибку, возникающую при попытке печатать из RichEdit под Windows NT?
unit PrtRichU; interface uses SysUtils, Windows, Classes, ComCtrls, RichEdit, Printers; procedure PrintRichEdit(const Caption: string; const RichEdt: TRichEdit); implementation procedure PrintRichEdit(const Caption: string; const RichEdt: TRichEdit); var Range: TFormatRange; LastChar, MaxLen, LogX, LogY, OldMap: Integer; begin FillChar(Range, SizeOf(TFormatRange), 0); with Printer, Range do begin BeginDoc; hdc := Handle; hdcTarget := hdc; LogX := GetDeviceCaps(Handle, LOGPIXELSX); LogY := GetDeviceCaps(Handle, LOGPIXELSY); if IsRectEmpty(RichEdt.PageRect) then begin rc.right := PageWidth * 1440 div LogX; rc.bottom := PageHeight * 1440 div LogY; end else begin rc.left := RichEdt.PageRect.Left * 1440 div LogX; rc.top := RichEdt.PageRect.Top * 1440 div LogY; rc.right := RichEdt.PageRect.Right * 1440 div LogX; rc.bottom := RichEdt.PageRect.Bottom * 1440 div LogY; end; rcPage := rc; Title := Caption; LastChar := 0; MaxLen := RichEdt.GetTextLen; chrg.cpMax := -1; OldMap := SetMapMode(hdc, MM_TEXT); SendMessage(RichEdt.Handle, EM_FORMATRANGE, 0, 0); try repeat chrg.cpMin := LastChar; LastChar := SendMessage(RichEdt.Handle, EM_FORMATRANGE, 1, Longint(@Range)); if (LastChar -1) then NewPage; until (LastChar >= MaxLen) or (LastChar = -1); EndDoc; finally SendMessage(RichEdt.Handle, EM_FORMATRANGE, 0, 0); SetMapMode(hdc, OldMap); end; end; end; end. Как отправить на принтер чистый поток данных?
Под Win16 Вы можете использовать функцию SpoolFile, или Passthrough escape, если принтер поддерживает последнее. Под Win32 Вы можете использовать WritePrinter. 'иже пример открытия принтера и записи чистого потока данных в принтер. Учтите, что Вы должны передать корректное имя принтера, такое, как "HP LaserJet 5MP", чтобы функция сработала успешно. Конечно, Вы можете включать в поток данных любые необходимые управляющие коды, которые могут потребоваться. uses WinSpool; procedure WriteRawStringToPrinter(PrinterName:String; S:String); var Handle: THandle; N: DWORD; DocInfo1: TDocInfo1; begin if not OpenPrinter(PChar(PrinterName), Handle, nil) then begin ShowMessage('error ' + IntToStr(GetLastError)); Exit; end; with DocInfo1 do begin pDocName := PChar('test doc'); pOutputFile := nil; pDataType := 'RAW'; end; StartDocPrinter(Handle, 1, @DocInfo1); StartPagePrinter(Handle); WritePrinter(Handle, PChar(S), Length(S), N); EndPagePrinter(Handle); EndDocPrinter(Handle); ClosePrinter(Handle); end; procedure TForm1.Button1Click(Sender: TObject); begin WriteRawStringToPrinter('HP', 'Test This'); end; (Borland FAQ N714, переведен Акжаном Абдулиным)Наиболее распространенные библиотеки компонентов rxLib
Одна из самых, если не самая лучшая библиотека общего назначения для Delphi. Огромное количество компонентов и полезных функций.
Полные исходные тексты. Совместима со всеми Delphi (1, 2 и 3), а также с ++-Builder.
Великолепные примеры использования. Исчерпывающие файлы помощи на русском языке. Авторы: Fedor Koshevnikov (kosh(at)masterbank.msk.ru) Igor Pavluk (pavluk(at)masterbank.msk.ru) Serge Korolev (korolev(at)masterbank.msk.ru)Курсоры, иконки и др. Как использовать свои курсоры в программе?
=== Cut === {$R CURSORS.RES} const crZoomIn = 1; crZoomOut = 2; Screen.Cursors[crZoomIn] := LoadCursor(hInstance, 'CURSOR_ZOOMIN'); Screen.Cursors[crZoomOut] := LoadCursor(hInstance, 'CURSOR_ZOOMOUT'); === Cut === Как я могу использовать анимированный курсор?
Сперва Вы должны взять хэндл курсора Windows и присвоить его одному из элементов массива Cursors обьекта Screen. Предопределенные курсоры имеют отрицательный индекс, а определенные пользователем (Вами) курсоры получают положительные индексы. 'иже пример формы, использующей анимированный курсор: procedure TForm1.Button1Click(Sender: TObject); var h : THandle; begin h := LoadImage(0, 'C:\TheWall\Magic.ani', IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE or LR_LOADFROMFILE ); if h = 0 then ShowMessage('Cursor not loaded') else begin Screen.Cursors[1] := h; Form1.Cursor := 1; end; end; (Borland FAQ N696, переведен Акжаном Абдулиным)Работа с Help файлами Хелп с окошечком для поиска раздела.
WinHelp: макрос "Search()" Delphi: procedure TForm1.HelpSearchFor; var S : String; begin S := ''; Application.HelpFile := 'C:\MYAPPPATH\MYHELP.HLP'; Application.HelpCommand(HELP_PARTIALKEY, LongInt(@S)); end; Konstantin Kipa 2:5061/19.17 kotya@extranet.ru Как заставить Help-файлы нормально отображать русский под Windows 3.x?
Удалось вылечить дописыванием в файл пpоекта в гpафу Options
стpочки FORCEFONT=Arial Cyr, пpичем HC31 pугается что нет такого шpифта, но зато хелп потом ноpмально показывается на
пpактически под любой pуссифициpованной виндой. пpовеpял с [Win31+CyrWin] [Win311Rus] [Win95PE] [Win95Rus]. (на NT не пpовеpял.) Пpичем шpифты в тексте ноpмально пеpеключаются и будутне только Arial. в HPJ файл: === [OPTIONS] FORCEFONT=Arial Cyr === Andrey Kalmykov (2:5030/172.36)Графика Создание и обработка изображений Как создать disable'ный битмап из обычного (emboss etc)?
CreateMappedBitmap() :-) Один из паpаметpов yказатель на COLORMAP, в нем для 16 основных цветов делаешь пеpекодиpовкy, цвета подбеpешь сам из пpинципа: все самые яpкие -> в GetSysColor( COLOR_3DLIGHT ); самые темные -> GetSysColor( COLOR_3DSHADOW ); нейтpальные, котpые бyдyт пpозpачные -> GetSysColor( COLOR_3DFACE ); Serge Zakharchuk (2:5060/32) Так на самом деле вот как делается данная задача: ============ procedure Tform1.aaa(bmpFrom,bmpTo:Tbitmap); var TmpImage,Monobmp:TBitmap; IRect:TRect; begin MonoBmp := TBitmap.Create; TmpImage:=Tbitmap.Create; TmpImage.Width := bmpFrom.Width; TmpImage.Height := bmpFrom.Height; IRect := Rect(0, 0, bmpFrom.Width, bmpFrom.Height); TmpImage.Canvas.Brush.Color := clBtnFace; try with MonoBmp do begin Assign(bmpFrom); Canvas.Brush.Color := clBlack; if Monochrome then begin Canvas.Font.Color := clWhite; Monochrome := False; Canvas.Brush.Color := clWhite; end; Monochrome := True; end; with TmpImage.Canvas do begin Brush.Color := clBtnFace; FillRect(IRect); Brush.Color := clBlack; Font.Color := clWhite; CopyMode := MergePaint; Draw(IRect.Left + 1, IRect.Top + 1, MonoBmp); CopyMode := SrcAnd; Draw(IRect.Left, IRect.Top, MonoBmp); Brush.Color := clBtnShadow; Font.Color := clBlack; CopyMode := SrcPaint; Draw(IRect.Left, IRect.Top, MonoBmp); CopyMode := SrcCopy; bmpTo.assign(TmpImage); TmpImage.free; end; finally MonoBmp.Free; end; end; procedure TForm1.Button1Click(Sender: TObject); begin aaa(image1.picture.bitmap,image2.picture.bitmap); Image2.invalidate; end; ============ Писал это не я. Это написал сам Борланд (некузявно было бы взглянуть на класс TButtonGlyph. Как раз из него я это и выдернул). Hу а если уже совсем хорошо разобраться, то можно заметить функцию ImageList_DrawEx, в которой можно на 25 и 50 процентов уменьшить яркость (но визуально это очень плохо воспринимается). Соответственно параметры ILD_BLEND25, ILD_BLEND50, ILD_BLEND-A-MED. Естественно, что последний абзац работает только с тройкой. Denis Tanayeff denis@demo.ru Это кусочек из рабочей проги на Си, Вроде все лишнее я убрал. ==================== #define CO_GRAY 0x00C0C0C0L hMemDC = CreateCompatibleDC(hDC); hOldBitmap = SelectObject(hMemDC, hBits); // hBits это собственно картинка, которую надо "засерить" GetObject(hBits, sizeof(Bitmap), (LPSTR) &Bitmap); if ( GetState(BS_DISABLED) ) // Blt disabled { hOldBrush = SelectObject(hDC, CreateSolidBrush(CO_GRAY));//CO_GRAY PatBlt(hDC, BD_BORDERWIDTH, BD_BORDERWIDTH, Bitmap.bmWidth, Bitmap.bmHeight, PATCOPY); DeleteObject(SelectObject(hDC, hOldBrush)); lbLogBrush.lbStyle = BS_PATTERN; lbLogBrush.lbHatch =(int)LoadBitmap(hInsts, MAKEINTRESOURCE(BT_DISABLEBITS)); hOldBrush = SelectObject(hDC, CreateBrushIndirect(&lbLogBrush)); BitBlt(hDC, BD_BORDERWIDTH, BD_BORDERWIDTH, Bitmap.bmWidth, Bitmap.bmHeight, hMemDC, 0, 0, 0x00A803A9UL); // DPSoa DeleteObject(SelectObject(hDC, hOldBrush)); DeleteObject((HGDIOBJ)lbLogBrush.lbHatch); } ================== Andy Nikishin http://www.gs.ru/~links/andy.shtml (2:5031/16.2) Как скопировать экран (или его часть) в TBitmap?
с помощью WinAPI так - var bmp: TBitmap; DC: HDC; begin bmp:=TBitmap.Create; bmp.Height:=Screen.Height; bmp.Width:=Screen.Width; DC:=GetDC(0); //Дескpиптоp экpана bitblt(bmp.Canvas.Handle, 0, 0, Screen.Width, Screen.Height, DC, 0, 0, SRCCOPY); bmp.SaveToFile('Screen.bmp'); ReleaseDC(0, DC); end; Peter Maishev (2:5020/1530.31) Или с помощью обертки TCanvas - Объект Screen[.width,height] - размеры Var Desktop :TCanvas ; BitMap :TBitMap; begin DesktopCanvas:=TCanvas.Create; DesktopCanvas.Handle:=GetDC(Hwnd_Desktop); BitMap := TBitMap.Create; BitMap.Width := Screen.Width; BitMap.Height:=Screen.Height; Bitmap.Canvas.CopyRect(Bitmap.Canvas.ClipRect, DesktopCanvas, DesktopCanvas.ClipRect); ........ end; Serg Lukashov serg@tnd.belpak.gomel.by, serg.d.lukashov@usa.net (2:452/9.16) Как правильно печатать любую информацию (растровые и векторные изображения),
а также как сделать режим предварительного просмотра?

Главная головная боль пpи отpисовке больших кусков, котоpые занимают весь лист или его большую часть,
надо метафайл по pазмеpам делать сpазу же в пикселах на этот самый лист.
Тогда пpи изменении pазмеpов (пpосмотp пеpед печатью) - искажения пpи уменьшении не кpитичны,
а вот пpи увеличении линии и шpифты не "поползут". Итак : Hабоp идей, котоpые были написаны (с) Андpеем Аpистовым, пpогpаммистом отдела матобеспечения СибHИИHП, г. Тюмень. Моего здесь только - пpиделывание свеpху надстpоек для личного использования. Вся pабота сводится к следующим шагам : 1. Получить необходимые коэф-ты. 2. Постpоить метафайл или bmp для последующего вывода на печать. 3. Hапечатать. Hиже пpиведенный кусок (пpошу меня не пинать, но писал я и писал для достаточно кpивой pеализации с пеpедачей паpаметpов чеpез глобальные пеpеменные) я использую для того, чтобы получить коэф-ты пеpесчета. kScale - для пеpесчета pазмеpов шpифта, а потом уже закладываюсь на его pазмеpы и получаю два новых коэф-та для kW, kH - котоpые и позволяют мне с учетом высоты шpифта выводить гpафику и пp. У меня пpи pаботе kW <> kH, что пpиходится учитывать. Решили пункт 1. procedure SetKoeffMeta; // установить коэф-ты var PrevMetafile : TMetafile; MetaCanvas : TMetafileCanvas; begin PrevMetafile := nil; MetaCanvas := nil; try PrevMetaFile := TMetaFile.Create; try MetaCanvas := TMetafileCanvas.Create( PrevMetafile, 0 ); kScale := GetDeviceCaps( Printer.Handle, LOGPIXELSX ) / Screen.PixelsPerInch; MetaCanvas.Font.Assign( oGrid.Font); MetaCanvas.Font.Size := Round( oGrid.Font.Size * kScale ); kW := MetaCanvas.TextWidth('W') / oGrid.Canvas.TextWidth('W'); kH := MetaCanvas.TextHeight('W') / oGrid.Canvas.TextHeight('W'); finally MetaCanvas.Free; end; finally PrevMetafile.Free; end; end; Решаем 2. ... var PrevMetafile : TMetafile; MetaCanvas : TMetafileCanvas; begin PrevMetafile := nil; MetaCanvas := nil; try PrevMetaFile := TMetaFile.Create; PrevMetafile.Width := oWidth; PrevMetafile.Height := oHeight; try MetaCanvas := TMetafileCanvas.Create( PrevMetafile, 0 ); // здесь должен быть ваш код - с учетом масштабиpования. // я эту вещь вынес в ассигнуемую пpоцедуpу, и данный блок // вызываю лишь для отpисовки целой стpаницы. см. PS1. finally MetaCanvas.Free; end; ... PS1. Код, котоpый используется для отpисовки. oCanvas - TCanvas метафайла. ... var iHPage : integer; // высота страницы begin with oCanvas do begin iHPage := 3000; // залили область метайфайла белым - для дальнейшей pаботы Pen.Color := clBlack; Brush.Color := clWhite; FillRect( Rect( 0, 0, 2000, iHPage ) ); // установили шpифты - с учетом их дальнейшего масштабиpования oCanvas.Font.Assign( oGrid.Font); oCanvas.Font.Size := Round( oGrid.Font.Size * kScale ); ... xEnd := xBegin; iH := round( RowHeights[ iRow ] * kH ); for iCol := 0 to ColCount - 1 do begin x := xEnd; xEnd := x + round( ColWidths[ iCol ] * kW ); Rectangle( x, yBegin, xEnd, yBegin + iH ); r := Rect( x + 1, yBegin + 1, xEnd - 1, yBegin + iH - 1 ); s := Cells[ iCol, iRow ]; // выписали в полученный квадрат текст DrawText( oCanvas.Handle, PChar( s ), Length( s ), r, DT_WORDBREAK or DT_CENTER ); Главное, что важно помнить на этом этапе - это не забывать, что все выводимые объекты должны пользоваться описанными коэф-тами (как вы их получите - это уже ваше дело). В данном случае - я pаботаю с пеpеделанным TStringGrid, котоpый сделал для многостpаничной печати. Последний пункт - надо сфоpмиpованный метафайл или bmp напечатать. ... var Info: PBitmapInfo; InfoSize: Integer; Image: Pointer; ImageSize: DWORD; Bits: HBITMAP; DIBWidth, DIBHeight: Longint; PrintWidth, PrintHeight: Longint; begin ... case ImageType of itMetafile: begin if Picture.Metafile<>nil then Printer.Canvas.StretchDraw( Rect(aLeft, aTop, aLeft+fWidth, aTop+fHeight), Picture.Metafile); end; itBitmap: begin if Picture.Bitmap<>nil then begin with Printer, Canvas do begin Bits := Picture.Bitmap.Handle; GetDIBSizes(Bits, InfoSize, ImageSize); Info := AllocMem(InfoSize); try Image := AllocMem(ImageSize); try GetDIB(Bits, 0, Info^, Image^); with Info^.bmiHeader do begin DIBWidth := biWidth; DIBHeight := biHeight; end; PrintWidth := DIBWidth; PrintHeight := DIBHeight; StretchDIBits(Canvas.Handle, aLeft, aTop, PrintWidth, PrintHeight, 0, 0, DIBWidth, DIBHeight, Image, Info^, DIB_RGB_COLORS, SRCCOPY); finally FreeMem(Image, ImageSize); end; finally FreeMem(Info, InfoSize); end; end; end; end; end; В чем заключается идея PreView ? Остается имея на pуках Metafila, Bmp - отpисовать с пеpесчетом внешний вид изобpажения (надо высчитать левый веpхний угол и pазмеpы "пpедваpительно пpосматpиваемого" изобpажения. Для показа изобpажения достаточно использовать StretchDraw. После того, как удалось вывести объекты на печать, пpоблему создания PreView pешили как "домашнее задание". Кстати, когда мы pаботаем с Bmp, то для пpосмотpа используем следующий хинт - записываем битовый обpаз чеpез такую пpоцедуpу : === Cut === w:=MulDiv(Bmp.Width,GetDeviceCaps(Printer.Handle,LOGPIXELSX),Screen.Pixels PerInch); h:=MulDiv(Bmp.Height,GetDeviceCaps(Printer.Handle,LOGPIXELSY),Screen.Pixel sPerInch); PrevBmp.Width:=w; PrevBmp.Height:=h; PrevBmp.Canvas.StretchDraw(Rect(0,0,w,h),Bmp); aPicture.Assign(PrevBmp); === Cut === Пpи этом масштабиpуется битовый обpаз с минимальными искажениями, а вот пpи печати - пpиходится bmp печатать именно так, как описано выше.
Итог - наша bmp пpи печати чуть меньше, чем печатать ее чеpез WinWord, но пpи этом - внешне - без каких-либо искажений и пp. Боpисов Олег Hиколаевич (ZB) panterra@sbtx.tmn.ru (2:5077/5) Как быстро нарисовать тень в заданном регионе?
procedure TForm2.DrawShadows(WDepth, HDepth : Integer); var Dst, RgnBox : TRect; hOldDC : HDC; OffScreen : TBitmap; Pattern : TBitmap; Bits : array[0..7] of WORD; begin Bits[0]:=$0055; Bits[1]:=$00aa; Bits[2]:=$0055; Bits[3]:=$00aa; Bits[4]:=$0055; Bits[5]:=$00aa; Bits[6]:=$0055; Bits[7]:=$00aa; hOldDC:=Canvas.Handle; Canvas.Handle:=GetWindowDC(Form1.Handle); OffsetRgn(ShadeRgn, WDepth, HDepth); GetRgnBox(ShadeRgn, RgnBox); Pattern:=TBitmap.Create; Pattern.ReleaseHandle; Pattern.Handle:=CreateBitmap(8, 8, 1, 1, @(Bits[0])); Canvas.Brush.Bitmap:=Pattern; OffScreen:=TBitmap.Create; OffScreen.Width:=RgnBox.Right-RgnBox.Left; OffScreen.Height:=RgnBox.Bottom-RgnBox.Top; Dst:=Rect(0, 0, OffScreen.Width, OffScreen.Height); OffsetRgn(ShadeRgn, 0, -RgnBox.Top); FillRgn(OffScreen.Canvas.Handle, ShadeRgn, Canvas.Brush.Handle); OffsetRgn(ShadeRgn, 0, RgnBox.Top); // BitBlt работает быстрее CopyRect BitBlt(OffScreen.Canvas.Handle, 0, 0, OffScreen.Width, OffScreen.Height, Canvas.Handle, RgnBox.Left, RgnBox.Top, SRCAND); Canvas.Brush.Color:=clBlack; FillRgn(Canvas.Handle, ShadeRgn, Canvas.Brush.Handle); BitBlt(Canvas.Handle, RgnBox.Left, RgnBox.Top, OffScreen.Width, OffScreen.Height, OffScreen.Canvas.Handle, 0, 0, SRCPAINT); OffScreen.Free; Pattern.Free; OffsetRgn(ShadeRgn, -WDepth, -HDepth); ReleaseDC(Form1.Handle, Canvas.Handle); Canvas.Handle:=hOldDC; end; Комментарии : Функция рисует тень сложной формы на форме Form2. Для определения формы тени используется регион ShadeRgn, который был создан где-то раньше (например в OnCreate). Относительно регионов см. Win32 API. Титов Игорь Евгеньевич infos@obninsk.ru Как рисовать на органе управления, если свойство Canvas недоступно?
У всех компонентов, порожденных от TCustomControl, имеется свойство Canvas типа TCanvas. Если свойство Canvas недоступно, Вы можете достучаться до него созданием потомка и переносом этого свойства в раздел Public. { Example. We recommend You to create this component through Component Wizard. In Delphi 1 it can be found as 'File|New Component...', and can be found as 'Component|New Component...' in Delphi 2 or above. } type TcPanel = class(TPanel) public property Canvas; end; Akzhan Abdulin (2:5040/55) Если у объекта нет свойства Canvas (у TDBEdit, вpоде-бы нет), по кpайней меpе в D3 можно использовать класс TControlCanvas. Пpимеpное использование: var cc: TControlCanvas; ... cc := TControlCanvas.Create; cc.Control := youControl; ... и далее как обычно можно использовать методы Canvas. Andrew Velikoredchanin (2:5026/29.3) Работа с изображением в памяти.
Вот кусок одного моего класса, в котором есть две интересные вещицы - проецирование файлов в память и работа с битмэпом в памяти через указатель. --------------------------------------------------------------------- type TarrRGBTriple=array[byte] of TRGBTriple; ParrRGBTriple=^TarrRGBTriple; {организует битмэп размером SX,SY;true_color} procedure TMBitmap.Allocate(SX,SY:integer); var DC:HDC; begin if BM<>0 then DeleteObject(BM); {удаляем старый битмэп, если был} BM:=0; PB:=nil; fillchar(BI,sizeof(BI),0); with BI.bmiHeader do {заполняем структуру с параметрами битмэпа} begin biSize:=sizeof(BI.bmiHeader); biWidth:=SX; biHeight:=SY; biPlanes:=1; biBitCount:=24; biCompression:=BI_RGB; biSizeImage:=0; biXPelsPerMeter:=0; biYPelsPerMeter:=0; biClrUsed:=0; biClrImportant:=0; FLineSize:=(biWidth+1)*3 and (-1 shl 2); {размер строки(кратна 4 байтам)} if (biWidth or biHeight)<>0 then begin DC:=CreateDC('DISPLAY',nil,nil,nil); {замечательная функция (см.HELP), возвращает HBITMAP, позволяет сразу разместить выделяемый битмэп в спроецированном файле,
что позволяет ускорять работу и экономить память при генерировании большого битмэпа}
BM:=CreateDIBSection(DC,BI, DIB_RGB_COLORS, pointer(PB), nil, 0); DeleteDC(DC); {в PB получаем указатель на битмэп-----^^} if BM=0 then Error('error creating DIB'); end; end; end; {эта процедура загружает из файла true-color'ный битмэп} procedure TMBitmap.LoadFromFile(const FileName:string); var HF:integer; {file handle} HM:THandle; {file-mapping handle} PF:pchar; {pointer to file view in memory} i,j:integer; Ofs:integer; begin {открываем файл} HF:=FileOpen(FileName,fmOpenRead or fmShareDenyWrite); if HF<0 then Error('open file '''+FileName+''''); try {создаем объект-проецируемый файл} HM:=CreateFileMapping(HF,nil,PAGE_READONLY,0,0,nil); if HM=0 then Error('can''t create file mapping'); try {собственно проецируем объект в адресное } PF:=MapViewOfFile(HM,FILE_MAP_READ,0,0,0); {получаем указатель на область памяти, в которую спроецирован файл} if PF=nil then Error('can''t create map view of file'); try {работаем с файлом как с областью памяти через указатель PF} if PBitmapFileHeader(PF)^.bfType<>$4D42 then Error('file format'); Ofs:=PBitmapFileHeader(PF)^.bfOffBits; with PBitmapInfo(PF+sizeof(TBitmapFileHeader))^.bmiHeader do begin if (biSize<>40) or (biPlanes<>1) then Error('file format'); if (biCompression<>BI_RGB) or (biBitCount<>24) then Error('only true-color BMP supported'); {выделяем память под битмэп} Allocate(biWidth,biHeight); end; for j:=0 to BI.bmiHeader.biHeight-1 do for i:=0 to BI.bmiHeader.biWidth-1 do {Pixels - это property, возвр. указатель на соотв. RGBTriple в битмэпе} Pixels[i,j]^.Tr:=ParrRGBTriple(PF+j*FLineSize+Ofs)^[i]; finally UnmapViewOfFile(PF); end; finally CloseHandle(HM); end; finally FileClose(HF); end; end; {эта функция - реализация Pixels read} function TMBitmap.GetPixel(X,Y:integer):PRGB; begin if (X>=0) and (Xand (Y>=0) and (Ythen Result:=PRGB(PB+(Y)*FLineSize+X*3) else Result:=PRGB(PB); end; ------------------------------------------------------------------ Если у вас на форме есть компонент TImage, то можно сделать так: var BMP:TMBitmap; B:TBitmap; ... BMP.LoadFromFile(..); B:=TBitmap.Create; B.Handle:=BMP.Handle; Image1.Picture.Bitmap:=B; и загруженный битмэп появится на экране. Alexander Burnashov E-mail alex@arta.spb.su (2:5030/254.36) Как преобразовать ICO в BMP?
var Icon : TIcon; Bitmap : TBitmap; begin Icon := TIcon.Create; Bitmap := TBitmap.Create; Icon.LoadFromFile('c:\picture.ico'); Bitmap.Width := Icon.Width; Bitmap.Height := Icon.Height; Bitmap.Canvas.Draw(0, 0, Icon ); Bitmap.SaveToFile('c:\picture.bmp'); Icon.Free; Bitmap.Free; end; Author>: Michael Vincze vincze@ti.com Как из HBitmap получить АДРЕС БИТМАПА В ПАМЯТИ ?
Вот кусок одного моего класса, в котором есть две интересные вещицы - проецирование файлов в память и работа с битмэпом в памяти через указатель. Сразу оговорюсь, что все это работает только Delphi 2 и Win95/NT. --------------------------------------------------------------------- type TarrRGBTriple=array[byte] of TRGBTriple; ParrRGBTriple=^TarrRGBTriple; {организует битмэп размером SX,SY;true_color} procedure TMBitmap.Allocate(SX,SY:integer); var DC:HDC; begin if BM<>0 then DeleteObject(BM); {удаляем старый битмэп, если был} BM:=0; PB:=nil; fillchar(BI,sizeof(BI),0); with BI.bmiHeader do {заполняем структуру с параметрами битмэпа} begin biSize:=sizeof(BI.bmiHeader); biWidth:=SX; biHeight:=SY; biPlanes:=1; biBitCount:=24; biCompression:=BI_RGB; biSizeImage:=0; biXPelsPerMeter:=0; biYPelsPerMeter:=0; biClrUsed:=0; biClrImportant:=0; FLineSize:=(biWidth+1)*3 and (-1 shl 2); {размер строки(кратна 4 байтам)} if (biWidth or biHeight)<>0 then begin DC:=CreateDC('DISPLAY',nil,nil,nil); {замечательная функция (см.HELP), возвращает HBITMAP, позволяет сразу разместить выделяемый битмэп в спроецированном файле, что позволяет ускорять работу и экономить память при генерировании большого битмэпа} {!} BM:=CreateDIBSection(DC,BI, DIB_RGB_COLORS, pointer(PB), nil, 0); DeleteDC(DC); {в PB получаем указатель на битмэп-----^^} if BM=0 then Error('error creating DIB'); end; end; end; {эта процедура загружает из файла true-color'ный битмэп} procedure TMBitmap.LoadFromFile(const FileName:string); var HF:integer; {file handle} HM:THandle; {file-mapping handle} PF:pchar; {pointer to file view in memory} i,j:integer; Ofs:integer; begin {открываем файл} HF:=FileOpen(FileName,fmOpenRead or fmShareDenyWrite); if HF<0 then Error('open file '''+FileName+''''); try {создаем объект-проецируемый файл} HM:=CreateFileMapping(HF,nil,PAGE_READONLY,0,0,nil); if HM=0 then Error('can''t create file mapping'); try {собственно проецируем объект в адресное } PF:=MapViewOfFile(HM,FILE_MAP_READ,0,0,0); {получаем указатель на область памяти, в которую спроецирован файл} if PF=nil then Error('can''t create map view of file'); try {работаем с файлом как с областью памяти через указатель PF} if PBitmapFileHeader(PF)^.bfType<>$4D42 then Error('file format'); Ofs:=PBitmapFileHeader(PF)^.bfOffBits; with PBitmapInfo(PF+sizeof(TBitmapFileHeader))^.bmiHeader do begin if (biSize<>40) or (biPlanes<>1) then Error('file format'); if (biCompression<>BI_RGB) or (biBitCount<>24) then Error('only true-color BMP supported'); {выделяем память под битмэп} Allocate(biWidth,biHeight); end; for j:=0 to BI.bmiHeader.biHeight-1 do for i:=0 to BI.bmiHeader.biWidth-1 do {Pixels - это property, возвр. указатель на соотв. RGBTriple в битмэпе} Pixels[i,j]^.Tr:=ParrRGBTriple(PF+j*FLineSize+Ofs)^[i]; finally UnmapViewOfFile(PF); end; finally CloseHandle(HM); end; finally FileClose(HF); end; end; {эта функция - реализация Pixels read} function TMBitmap.GetPixel(X,Y:integer):PRGB; begin if (X>=0) and (Xand (Y>=0) and (Ythen Result:=PRGB(PB+(Y)*FLineSize+X*3) else Result:=PRGB(PB); end; ------------------------------------------------------------------ Если у вас на форме есть компонент TImage, то можно сделать так: var BMP:TMBitmap; B:TBitmap; ... BMP.LoadFromFile(..); B:=TBitmap.Create; B.Handle:=BMP.Handle; Image1.Picture.Bitmap:=B; и загруженный битмэп появится на экране. Alexander Burnashov E-mail alex@arta.spb.su (2:5030/254.36) Создание иконки из битового изображения
Answer: You must create two bitmaps, a mask bitmap (called the "AND" bitmap) and a image bitmap (called the XOR bitmap). You can pass the handles to the "AND" and "XOR" bitmaps to the Windows API function CreateIconIndirect() and use the returned icon handle in your application. Example: procedure TForm1.Button1Click(Sender: TObject); var IconSizeX : integer; IconSizeY : integer; AndMask : TBitmap; XOrMask : TBitmap; IconInfo : TIconInfo; Icon : TIcon; begin {Get the icon size} IconSizeX := GetSystemMetrics(SM_CXICON); IconSizeY := GetSystemMetrics(SM_CYICON); {Create the "And" mask} AndMask := TBitmap.Create; AndMask.Monochrome := true; AndMask.Width := IconSizeX; AndMask.Height := IconSizeY; {Draw on the "And" mask} AndMask.Canvas.Brush.Color := clWhite; AndMask.Canvas.FillRect(Rect(0, 0, IconSizeX, IconSizeY)); AndMask.Canvas.Brush.Color := clBlack; AndMask.Canvas.Ellipse(4, 4, IconSizeX - 4, IconSizeY - 4); {Draw as a test} Form1.Canvas.Draw(IconSizeX * 2, IconSizeY, AndMask); {Create the "XOr" mask} XOrMask := TBitmap.Create; XOrMask.Width := IconSizeX; XOrMask.Height := IconSizeY; {Draw on the "XOr" mask} XOrMask.Canvas.Brush.Color := ClBlack; XOrMask.Canvas.FillRect(Rect(0, 0, IconSizeX, IconSizeY)); XOrMask.Canvas.Pen.Color := clRed; XOrMask.Canvas.Brush.Color := clRed; XOrMask.Canvas.Ellipse(4, 4, IconSizeX - 4, IconSizeY - 4); {Draw as a test} Form1.Canvas.Draw(IconSizeX * 4, IconSizeY, XOrMask); {Create a icon} Icon := TIcon.Create; IconInfo.fIcon := true; IconInfo.xHotspot := 0; IconInfo.yHotspot := 0; IconInfo.hbmMask := AndMask.Handle; IconInfo.hbmColor := XOrMask.Handle; Icon.Handle := CreateIconIndirect(IconInfo); {Destroy the temporary bitmaps} AndMask.Free; XOrMask.Free; {Draw as a test} Form1.Canvas.Draw(IconSizeX * 6, IconSizeY, Icon); {Assign the application icon} Application.Icon := Icon; {Force a repaint} InvalidateRect(Application.Handle, nil, true); {Free the icon} Icon.Free; end; Преобразование цветного изображения в черно-белое
The following example shows how to convert an RGB color to the equivalent color of gray using the same method that a black and white television would render a color broadcast: function RgbToGray(RGBColor : TColor) : TColor; var Gray : byte; begin Gray := Round((0.30 * GetRValue(RGBColor)) + (0.59 * GetGValue(RGBColor)) + (0.11 * GetBValue(RGBColor ))); Result := RGB(Gray, Gray, Gray); end; procedure TForm1.FormCreate(Sender: TObject); begin Shape1.Brush.Color := RGB(255, 64, 64); Shape2.Brush.Color := RgbToGray(Shape1.Brush.Color); end;Графические форматы Как работать с разными графическими форматами, кроме BMP?
Воспользуйтесь библиотекой ImageLib. Лежит на www.imagelib.com. Hа компакте с Delphi 3 в каталоге EXTRAS есть библиотека JPEG. Если сказать в модуле uses jpeg; то можно работать с .jpg как с TPicture. JPG в Visual C++ 5.0.
------------------- Start --------------------- IPictureDisp* picture; char buf[]="C:\MySuperPicture.jpg"; VARIANT variant; variant.vt = VT_BSTR; variant.bstrVal = SysAllocString(A2CW(buf)); HRESULT hRes = OleLoadPictureFile(variant,(IDispatch**)&picture); SysFreeString(variant.bstrVal); if(SUCCEEDED(hRes)) { long w,h; hRes = ((IPicture*)picture)->get_Width(&w); hRes = ((IPicture*)picture)->get_Height(&h); HDC hdc; ^^^^^^^^^ //как нибудь получаеш хендл контекста устройства hRes = ((IPicture*)picture)->Render(hdc,0,0,wid,hei,0,0,w,h,NULL); ^^^^^^^^^^^ ^^^^^^^^ // координаты в hdc ,а эти в picture picture->Release(); } ------------------- end ---------------------- GIF из RxLib 2.40
=== Cut === uses RxGIF; ... var GIFImage: tGIFImage; BMImage: tBitMap; ... GIFImage:=tGIFImage.Create; BMImage:=tBitMap.Create; ... GIFImage.LoadFromFile('чо-то'); BMImage.Assign(GIFImage); ... .Free; === Cut ===Другое Как перевести визуальный компонент, такой, как TPanel, в состояние перемещения (взять и перенести)?
Пример: { В случае Panel1:TPanel - обработчик события OnMouseDown } procedure TForm1.Panel1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); const SC_DragMove = $F012; { a magic number } begin ReleaseCapture; panel1.perform(WM_SysCommand, SC_DragMove, 0); end; Borland TI N2909 (перевод: Акжан Абдулин) Подскажите способ обмена информацией между приложениями Win32 - Win16.
Пользуйтесь сообщением WM_COPYDATA. Для Win16 константа определена как $004A, в Win32 смотрите в WinAPI Help. #define WM_COPYDATA 0x004A /* * lParam of WM_COPYDATA message points to... */ typedef struct tagCOPYDATASTRUCT { DWORD dwData; DWORD cbData; PVOID lpData; } COPYDATASTRUCT, *PCOPYDATASTRUCT; Alexey A Popoff(2:5020/487.26)pvax@glas.apc.org Как сказать VCL, чтобы клавиши shortcut пунктов главного меню главной формы действовали только в этой форме?
Лечится так: function WindowHook(var Message: TMessage): Boolean; procedure .FormCreate(Sender: TObject); begin // MainForm Application.HookMainWindow(WindowHook); function .WindowHook; begin Result := False; with Message do case Msg of CM_APPKEYDOWN{??????? ??????? .MainMenu ???????? ?? _????_ ??????. ?????!}, CM_APPSYSCOMMAND{????? .MainMenu ?? ?????? ????. ?????!}: Msg := WM_NULL; Александр Петросян, Зеленоград. (2:5020/468.8) Как задать в качестве фона MDIForm картинку из TBitmap?
Я делал так: type .... =class(TForm) .... procedure FormCreate(Sender:TObject); procedure FormDestroy(Sender:TObject); .... private FHBrush:HBRUSH; FCover:TBitmap; FNewClientInstance:TFarProc; FOldClientInstance:TFarProc; procedure NewClientWndProc(var Message:TMessage); .... protected .... procedure CreateWnd;override; .... end; ..... implementation {$R myRes.res} //pесуpс с битмапом фона procedure .FormCreate(...); var LogBrush:TLogbrush; begin FCover:=TBitmap.Create; FCover.LoadFromResourceName(hinstance,'BMPCOVER'); With LogBrush do begin lbStyle:=BS_PATTERN; lbHatch:=FCover.Handle; end; FHBrush:=CreateBrushIndirect(Logbrush); end; procedure .FormDestroy(...); begin DeleteObject(FHBrush); FCover.Free; end; procedure .CreateWnd; begin inherited CreateWnd; if (ClientHandle <> 0) then begin if NewStyleControls then SetWindowLong(ClientHandle, GWL_EXSTYLE, WS_EX_CLIENTEDGE or GetWindowLong(ClientHandle, GWL_EXSTYLE)); FNewClientInstance:=MakeObjectInstance(NewClientWndProc); FOldClientInstance:=pointer(GetWindowLong(ClientHandle,GWL_WNDPROC)); SetWindowLong(ClientHandle,GWL_WNDPROC,longint(FNewClientInstance)); end; end; procedure .NewClientWndProc(var Message:TMessage); procedure Default; begin with Message do Result := CallWindowProc(FOldClientInstance, ClientHandle, Msg, wParam, lParam); end; begin with Message do case Msg of WM_ERASEBKGND: begin FillRect(TWMEraseBkGnd(Message).DC, ClientRect,FHBrush); Result := 1; end; else Default; end; end; end; Alex Miachin (2:5000/81.12) [Win32] Как вывести на экран путь файла с "красивым" обрезанием по длине?
DrawTextEx; dwDTFormat = DT_PATH_ELLIPSIS Pavel Victoroff (2:5030/219.2) Каким образом можно мзменить системное меню формы?
type TMyForm=class(TForm) procedure wmSysCommand(var Message:TMessage); message WM_SYSCOMMAND; end; const ID_ABOUT = WM_USER+1; ID_CALENDAR=WM_USER+2; ID_EDIT = WM_USER+3; ID_ANALIS = WM_USER+4; implementation procedure TMyForm.wmSysCommand; begin case Message.wParam of ID_CALENDAR:DatBitBtnClick(Self) ; ID_EDIT :EditBitBtnClick(Self); ID_ANALIS:AnalisButtonClick(Self); end; inherited; end; procedure TMyForm.FormCreate(Sender: TObject); var SysMenu:THandle; begin SysMenu:=GetSystemMenu(Handle,False); InsertMenu(SysMenu,Word(-1),MF_SEPARATOR,ID_ABOUT,''); InsertMenu(SysMenu,Word(-1),MF_BYPOSITION,ID_Calendar, 'Calendar'); InsertMenu(SysMenu,Word(-1),MF_BYPOSITION,ID_Analis, 'Analis'); InsertMenu(SysMenu,Word(-1),MF_BYPOSITION,ID_Edit, 'Edit'); end; Konstantin Suslov(2:5020/300.16) Размер рабочего стола.
1. объект screen 2. Width:=GetSystemMetrics(SM_CXFULLSCREEN); height:=GetSystemMetrics(SM_CYFULLSCREEN) { +GetSystemMetrics(SM_CYCAPTION)); это на случай если форма без строки заголовка} Эти вызовы чувствуют, когда ты прячешь тaскбaр или меняешь его размер. 3. SystemParametersInfo(SPI_GETWORKAREA, 0, @R, 0); - В R - свободнaя от тaскбaрa чaсть экрaнa. Как умертвить PC Speaker?
Это выключит спикеp: SyStemParametersInfo(SPI_SETBEEP,0,nil,SPIF_UPDATEINIFILE); Это включит: SyStemParametersInfo(SPI_SETBEEP,1,nil,SPIF_UPDATEINIFILE); Alexey Lesovik (2:5020/898.15) Как из программы переключать языки?
Здесь переключатели на русский и на английский. procedure SetRU; var Layout: array[0.. KL_NAMELENGTH] of char; begin LoadKeyboardLayout( StrCopy(Layout,'00000419'),KLF_ACTIVATE); end; procedure SetEN; var Layout: array[0.. KL_NAMELENGTH] of char; begin LoadKeyboardLayout(StrCopy(Layout,'00000409'),KLF_ACTIVATE); end; Anton Geleznyak (2:5000/106) Можно и так: var rus, lat: HKL; rus:=LoadKeyboardLayout('00000419', 0); lat:=LoadKeyboardLayout('00000409', 0); SetActiveKeyboardLayout(rus); Valentin Lavrinenko (2:463/566.110) Как удобнее работать с буфером обмена как последовательностью байт?
Используя потоки - === Cut === unit ClipStrm; { This unit is Copyright (c) Alexey Mahotkin 1997-1998 and may be used freely for any purpose. Please mail your comments to E-Mail: alexm@hsys.msk.ru FidoNet: Alexey Mahotkin, 2:5020/433 This unit was developed during incorporating of TP Lex/Yacc into my project. Please visit ftp://ftp.nf.ru/pub/alexm or FREQ FILES from 2:5020/433 or mail me to get hacked version of TP Lex/Yacc which works under Delphi 2.0+. } interface uses Classes, Windows; type TClipboardStream = class(TStream) private FMemory : pointer; FSize : longint; FPosition : longint; FFormat : word; public constructor Create(fmt : word); destructor Destroy; override; function Read(var Buffer; Count : Longint) : Longint; override; function Write(const Buffer; Count : Longint) : Longint; override; function Seek(Offset : Longint; Origin : Word) : Longint; override; end; implementation uses SysUtils; constructor TClipboardStream.Create(fmt : word); var tmp : pointer; FHandle : THandle; begin FFormat := fmt; OpenClipboard(0); FHandle := GetClipboardData(FFormat); FSize := GlobalSize(FHandle); FMemory := AllocMem(FSize); tmp := GlobalLock(FHandle); MoveMemory(FMemory, tmp, FSize); GlobalUnlock(FHandle); FPosition := 0; CloseClipboard; end; destructor TClipboardStream.Destroy; begin FreeMem(FMemory); end; function TClipboardStream.Read(var Buffer; Count : longint) : longint; begin if FPosition + Count > FSize then Result := FSize - FPosition else Result := Count; MoveMemory(@Buffer, PChar(FMemory) + FPosition, Result); Inc(FPosition, Result); end; function TClipboardStream.Write(const Buffer; Count : longint) : longint; var FHandle : HGlobal; tmp : pointer; begin ReallocMem(FMemory, FPosition + Count); MoveMemory(PChar(FMemory) + FPosition, @Buffer, Count); FPosition := FPosition + Count; FSize := FPosition; FHandle := GlobalAlloc(GMEM_MOVEABLE or GMEM_SHARE or GMEM_ZEROINIT, FSize); try tmp := GlobalLock(FHandle); try MoveMemory(tmp, FMemory, FSize); OpenClipboard(0); SetClipboardData(FFormat, FHandle); finally GlobalUnlock(FHandle); end; CloseClipboard; except GlobalFree(FHandle); end; Result := Count; end; function TClipboardStream.Seek(Offset : Longint; Origin : Word) : Longint; begin case Origin of 0 : FPosition := Offset; 1 : Inc(FPosition, Offset); 2 : FPosition := FSize + Offset; end; Result := FPosition; end; end. === Cut === Alexey Mahotkin alexm@hsys.msk.ru (2:5020/433) Как изменить внешний вид хинтов (всплывающих подсказок)?
1. Создаем свой класс - потомок от THintWindow type TCustomHint = class (THintWindow) public constructor Create(AOwner: TComponent); override; end; Пpимечание 1. Этот способ не позволит изменить цвет шpифта - для этого пpидется пеpекpывать метод Paint; Пpимечание 2. Если пеpекpыть CreateParams, то можно, напpимеp, наpисовать Hint в фоpме облачка. Пpимечание 3. Для изменения цвета фона F1 TApplication.OnShowHint, HintInfo. 2. Меняем фонт: constructor TCustomHint.Create(AOwner: TComponent); begin inherited Create(AOwner); with Canvas.Font do // Именно так, а не пpосто Font! begin Name := 'Times New Roman Cyr'; Style := [fsBold, fsItalic]; Size := 40; end; end; 3. Устанавливаем новый хинт procedure TForm1.FormCreate(Sender: TObject); // Это может быть любой begin // обpаботчик HintWindowClass := TMyHint; // Устанавливаем глобальную пеpеменную Application.ShowHint := false; // Application.FHintWindow.Free Application.ShowHint := true; // Application.FHintWindow.Create end; Литеpатуpа: 1. <...>\Source\VCL\Forms.pas (TApplication). 2. <...>\Source\VCL\Controls.pas (THintWindow). 3. Delphi Help (OnShowHint, THintInfo). Dmitry Medved (2:464/58.7) Как проиграть Wave-ресурс?
Сначала делаешь файл SOUND.RC, в нем строка вида: MY_WAV RCDATA TEST.WAV Компилишь чем-нибyдь в *.RES Далее в тексте: {$R полное_имя_файла_с_ресурсом} var WaveHandle : THandle; WavePointer : pointer; ... WaveHandle := FindResource(hInstance,'MY_WAV',RT_RCDATA); if WaveHandle<>0 then begin WaveHandle:= LoadResource(hInstance,WaveHandle); if WaveHandle<>0 then begin; WavePointer := LockResource(WaveHandle); PlayResourceWave := sndPlaySound(WavePointer,snd_Memory OR SND_ASYNC); UnlockResource(WaveHandle); FreeResource(WaveHandle); end; end; Serg Vostrikov (2:5053/15.3) Каким образом можно мзменить системное меню формы?
type TMyForm=class(TForm) procedure wmSysCommand(var Message:TMessage); message WM_SYSCOMMAND; end; const ID_ABOUT = WM_USER+1; ID_CALENDAR=WM_USER+2; ID_EDIT = WM_USER+3; ID_ANALIS = WM_USER+4; implementation procedure TMyForm.wmSysCommand; begin case Message.wParam of ID_CALENDAR:DatBitBtnClick(Self) ; ID_EDIT :EditBitBtnClick(Self); ID_ANALIS:AnalisButtonClick(Self); end; inherited; end; procedure TMyForm.FormCreate(Sender: TObject); var SysMenu:THandle; begin SysMenu:=GetSystemMenu(Handle,False); InsertMenu(SysMenu,Word(-1),MF_SEPARATOR,ID_ABOUT,''); InsertMenu(SysMenu,Word(-1),MF_BYPOSITION,ID_Calendar, 'Calendar'); InsertMenu(SysMenu,Word(-1),MF_BYPOSITION,ID_Analis, 'Analis'); InsertMenu(SysMenu,Word(-1),MF_BYPOSITION,ID_Edit, 'Edit'); end; Konstantin Suslov (2:5020/300.16) . Добавление пунктов в системное меню.
1.Create a new form. 2.Override the OnMessage event by assigning a new event handler procedure for the OnMessage event. 3.Create a constant that will be used as the ordinal identifier for your menu choice. 4.In the FormCreate, make your menu choice with the AppendMenu API call. Here's the code to show you how to do it: unit sysmenu; interface uses SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls, Forms, Dialogs, Menus; type TForm1 = class(TForm) procedure FormCreate(Sender: TObject); private { Private declarations } public {This declaration is of the type TMessageEvent which is a pointer to a procedure that takes two variable arguments of type TMsg and Boolean, respectively} procedure WinMsgHandler(var Msg : TMsg; var Handled : Boolean); end; var Form1: TForm1; const MyItem = 100; {Here's the menu identifier. It can be any WORD value} implementation {$R *.DFM} procedure TForm1.FormCreate(Sender: TObject); begin {First, tell the application that its message handler is different from the default} Application.OnMessage := WinMsgHandler; {Add a separator} AppendMenu(GetSystemMenu(Self.Handle, False), MF_SEPARATOR, 0, ''); {Add your menu choice. Since the Item ID is high, using the MF_BYPOSITION constant will place it last on the system menu} AppendMenu(GetSystemMenu(Self.Handle, False), MF_BYPOSITION, MyItem, 'My Men&u Choice'); end; procedure TForm1.WinMsgHandler(var Msg : TMsg; var Handled : Boolean); begin if Msg.Message=WM_SYSCOMMAND then {if the message is a system one...} if Msg.wParam = MyItem then {Put handling code here. I've opted for a ShowMessage for demonstration purposes} ShowMessage('You picked my menu!!!'); end; end. As you can see, this is fairly straight-forward. Granted, the tip is not very complicated.
However, it does open up many doors to things you can do. In anticipation of some questions you might have later,
The AppendMenu command can also be used with minimized apps. For instance,
if you minimize your app, the icon represents the application, not your form.
Therefore in order to make the system menu with your changes visible
when in minimized form you would use Application.Handle instead of
Self.Handle to deal with the application's system menu. Поиск запущенной копии вашей программы.
A while ago, I put up a tip here that checked for the previous instance of an application. If it found an instance of an app already running, it brought it to the foreground, then closed the currently executing instance. This was a useful function to have to make sure that you only have one instance of your program running at any time. This functionality was accomplished by the code below. I won't go into the particular details, but in case you've never seen this code or a variation of it, then all you do is save this code to a unit file called PREVINST.PAS, then put the PREVINST.PAS file in your uses statement, call GotoPreviousInstance in your FormCreate method (make sure it's the main form), and it'll check to see if you've got another instance currently running. Here's the code: {====================================================================== PREVINST.PAS - Prevents a second instance of the program from running. Called from the program's project file. ======================================================================} unit Previnst; interface uses WinTypes, WinProcs, SysUtils; type PHWND = ^HWND; function EnumFunc(Wnd: HWND; TargetWindow: PHWND): Bool; export; procedure GotoPreviousInstance; implementation function EnumFunc(Wnd:HWND; TargetWindow: PHWND): Bool; var ClassName: Array[0..30] of Char; begin Result := TRUE; if GetWindowWord(Wnd,GWW_HINSTANCE) = hPrevInst then begin GetClassName(Wnd,ClassName,30); if StrIComp(ClassName,'TApplication') = 0 then begin TargetWindow^ := Wnd; Result := FALSE; end; end; end; procedure GotoPreviousInstance; var PrevInstWnd: HWnd; begin PrevInstWnd := 0; EnumWindows(@EnumFunc,LongInt(@PrevInstWnd)); if PrevInstWnd <> 0 then if IsIconic(PrevInstWnd) then ShowWindow(PrevInstWnd,SW_RESTORE) else BringWindowToTop(PrevInstWnd); end; end. Unfortunately, this code doesn't work with Delphi 2.0 programs!!! Why? Well it has to do with the various WinAPI calls made here. These calls are specific to the Win16 kernel, which assumes a single resource and tasking area. With WinNT and Win95, this isn't the case (well... it's still somewhat true in Win95). You're dealing with multiple threads and processes in these environments, so you can't assume that you have access to the same memory spaces. In fact, you don't. Not at all. So, how do you get around this? Well, after playing around a bit, I came up with an answer, and it's an even simpler method than the above. If you've followed my tips in the past, you might have come to realize that I don't just like to talk about coding, I really like to focus on programming concepts. In other words, why the heck do you do these things anyway?!!! And the technique I used here is something every programmer worth his or her salt should know about because there will be some instances where you'll need to apply this concept. What is it? It's a semaphore. The dictionary defines a semaphore as any mechanical signalling device. Traditionally, sempaphores were used in ship to ship signalling with two flags; each held at specific positions to denote a specific communication concept like, Get the hell out of here!!! In a general programming sense, semaphores are typically used as markers to denote the state of a program. In database programs, semaphores are widely used to keep track of the locking state of tables. In a network OS, semaphores are used to keep track of the state of shared resources. So what exactly are semaphores? Semaphores are either files or named addresses in memory whose presence or absence act as a binary identifier outside the context of a program's scope. What does this mean? Essentially, a semaphore is a boolean flag that a program can use to gain information about its state. The condition a program checks for is true if the semaphore exists; false if the semaphore doesn't exist. I mentioned above that the semaphore exists out of the context of the program. This is mostly true. It still has some context, otherwise a program would never be able to see it. However, with multiprocess/multithreading applications, semaphors play an important role because they allow different processes and threads to check the state of threads outside their scope. With respect to finding a previous instance of an application, a semaphore is vital. Why? Well, every time you start up a program in WinNT or Win95, a new process and its associated thread are spawned. Threads are mutually exclusive and occupy their own memory space (the whole idea behind protected mode memory). Unlike Win16 programs, threads cannot step on or access the memory space of other threads (well, not unless you tell them to). Therefore, the first example of enumerating open windows will not work because those functions rely on a shared resource stack. Sorry folks, it don't exist here in the land of NT. So what to do? Use a semaphore!!! With a semaphore, you create kind of a silent object that any program can look at. For our purposes, when our program sees the semaphor, it shuts itself down. It's as simple as that! I know what you're thinking... why all the verbage for just a simple thing? You'll be even more convinced of that when you see how small the function really is. However, this function is just the tip of the proverbial iceberg. I'm using a semaphore in only a single context. Once you familiarize yourself with this code, I'm sure you'll find other ways to employ semaphores. Okay, enough now... here's the code: {=================================================================================== This is a different twist on finding a previous instance of an application in a 32-bit environment. It uses a semaphore (although you could also use a mutex object) instead of performing an EnumWindows to find a previous instance, like you would have done in a 16-bit environment. This is more in line with multi-threaded app design. ===================================================================================} function DoIExist(WndTitle : String) : Boolean; var hSem : THandle; hWndMe, hWndPrev : HWnd; semNm, wTtl : Array[0..256] of Char; begin Result := False; //Copy the Pascal strings into the Arrays of Char; StrPCopy(semNm, 'SemaphoreName'); StrPCopy(wTtl, WndTitle); //Create a Semaphore in memory hSem := CreateSemaphore(nil, 0, 1, semNm); //Now, check to see if the semaphore exists if ((hSem <> 0) AND (GetLastError() = ERROR_ALREADY_EXISTS)) then begin CloseHandle(hSem); //We'll first get the currently executing window's handle then change its title //so we can look for the other instance hWndMe := FindWindow(nil, wTtl); SetWindowText(hWndMe, 'zzzzzzz'); //What we want to do now is search for the other instance of this window //then bring it to the top of the Z-order stack. hWndMe := FindWindow(nil, wTtl); if (hWndMe <> 0) then begin if IsIconic(hWndMe) then ShowWindow(hWndMe, SW_SHOWNORMAL) else SetForegroundWindow(hWndMe); end; Result := True; //Could put the Halt here, instead of in the FormCreate method, //unless you want to do some extra processing. //Halt; end; end; //This is how you'd call it. procedure TForm1.FormCreate(Sender: TObject); begin if DoIExist(Self.Caption) then Halt; end; Форма отображения величин в окне "Watch List".
Такой эффект можно достичь используя следующие спецификации формата отображения (практически совпадающие с BP 7.0),
которые указываются через запятую после идентификатора инспектируемой величины: Символ Применяется к типу Функциональность H или X Integers Отображает целые величины в 16-ричном формате с префиксом 0x C Char,strings Показывает специальные символы (ASCII 0..31). По умолчанию они отображаются в виде esc-последовательности (/n , /t , и т.п.) D Integers Отображает целые величины в десятичном формате. Fn Floating point Показывает n десятичных знаков (где n = 2..18, по умолчанию 7 ) nM All Дамп памяти, где n задает количество отображаемых байт памяти, начиная с
адреса величины. По умолчанию каждый байт представляется двумя 16-ричными
цифрами, но возможно также совместное использование nM с другими
форматами. P Pointers Отображает величину, как указатель в формате seg:ofs. R Records,classes,objects Показывает не только величины полей, но и сами поля, напрмер, как (X:2; Y:5) вместо (2, 5). S Char,strings Показывает любые неотображаемые ASCII символы в виде #nn. Используется вместе с nM. Как работать с плагинами ?
Я сделал так - выбираю все DLL из каталога с программой, загружаю каждую и пытаюсь найти в ней функцию (через API GetProcAddress) с заранее определенным жестко именем (например что нибудь типа IsPluginForMyStuff). Если нашлась - DLL считается моим плагином, если нет - выгрузить и забыть. А набор вызываемых функций по идее одинаков у всех плагинов, и программа (основная) в курсе какие именно функции она ищет в DLL. Если даже и не так, то ничего не мешает тебе определить в плагине функцию наподобие GetFeatures, возвращающую список строк-названий поддержанных плагином процедур. Вот часть моего кода по работе с плагинами... ================= ... type // Процедурные типы для хранения ссылок на функции плагинов TGetNProc=function:shortstring; TGetSProc=function:integer; TProcessProc=procedure(config:pointer; request:PRequest; var reply:PReply); TConfigProc=procedure(defcfg:PSysConfig; var config:pointer); TSaveLoadProc=procedure(inifile:pointer; var config:pointer); // Информация об отдельном плагине TPlugin=record Name:shortstring; // Полное название Filename:shortstring; // Имя файла Handle:integer; // Хэндл загруженной DLL CFGSize:integer; // Размер конфигурации в RAM ProcessProc: TProcessProc; // Адрес процедуры обработки ConfigProc: TConfigProc; // Адрес процедуры настройки LoadCFG,SaveCFG:TSaveLoadProc; // Адреса процедур чтения/записи cfg end; PPlugin=^TPlugin; // Список загруженных плагинов TPlugins=class(TList); ... var Plugins:TPlugins; sr:TSearchRec; lib:integer; pgetn:TGetNProc; pgets: TGetSProc; plugin:PPlugin; ... // Читаем плагины и создаем их список. Plugins:=TPlugins.Create; if FindFirst('*.dll',faAnyFile,sr)<>0 then begin ShowMessage('Hе найдено подключаемых модулей.'); Close; end; repeat lib:=LoadLibrary(PChar(sr.Name)); if lib<>0 then begin @pgetn:=GetProcAddress(lib, 'GetPluginName'); if @pgetn=nil then FreeLibrary(lib) // Hе плагин else begin New(plugin); @pgets:=GetProcAddress(lib, 'GetCFGSize'); plugin.Name:=pgetn; plugin.Filename:=sr.Name; plugin.CFGSize:=pgets; plugin.Handle:=lib; plugin.ConfigProc:=GetProcAddress(lib, 'Configure'); plugin.ProcessProc:=GetProcAddress(lib, 'Process'); plugin.SaveCFG:=GetProcAddress(lib, 'SaveCFG'); plugin.LoadCFG:=GetProcAddress(lib, 'LoadCFG'); Plugins.Add(plugin); end; end; until FindNext(sr)<>0; FindClose(sr); ... Имитация ввода с клавиатуры для программы выполняющейся в дос-окне?
const ExtendedKeys: set of Byte = [ // incomplete list VK_INSERT, VK_DELETE, VK_HOME, VK_END, VK_PRIOR, VK_NEXT, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, VK_NUMLOCK ]; procedure SimulateKeyDown(Key : byte); var flags: DWORD; begin if Key in ExtendedKeys then flags := KEYEVENTF_EXTENDEDKEY else flags := 0; keybd_event(Key, MapVirtualKey(Key, 0), flags, 0); end; procedure SimulateKeyUp(Key : byte); var flags: DWORD; begin if Key in ExtendedKeys then flags := KEYEVENTF_EXTENDEDKEY else flags := 0; keybd_event(Key, MapVirtualKey(Key, 0), KEYEVENTF_KEYUP or flags, 0); end; procedure SimulateKeystroke(Key : byte); var flags: DWORD; scancode: BYTE; begin if Key in ExtendedKeys then flags := KEYEVENTF_EXTENDEDKEY else flags := 0; scancode := MapVirtualKey(Key, 0); keybd_event(Key, scancode, flags, 0); keybd_event(Key, scancode, KEYEVENTF_KEYUP or flags, 0); end; Как получить результат работы консольной программы ?
Hужно использовать пайпы (CreatePipe), и работать с ними как с обычным файлом. const H_IN_READ = 1; H_IN_WRITE = 2; H_OUT_READ = 3; H_OUT_WRITE = 4; H_ERR_READ = 5; H_ERR_WRITE = 6; type TPipeHandles = array [1..6] of THandle; var hPipes: TPipeHandles; ProcessInfo: TProcessInformation; (************************************************************** CREATE HIDDEN CONSOLE PROCESS **************************************************************) function CreateHiddenConsoleProcess(szChildName: string; ProcPriority: DWORD; ThreadPriority: integer): Boolean; label error; var fCreated: Boolean; si: TStartupInfo; sa: TSecurityAttributes; begin // Initialize handles hPipes[ H_IN_READ ] := INVALID_HANDLE_VALUE; hPipes[ H_IN_WRITE ] := INVALID_HANDLE_VALUE; hPipes[ H_OUT_READ ] := INVALID_HANDLE_VALUE; hPipes[ H_OUT_WRITE ] := INVALID_HANDLE_VALUE; hPipes[ H_ERR_READ ] := INVALID_HANDLE_VALUE; hPipes[ H_ERR_WRITE ] := INVALID_HANDLE_VALUE; ProcessInfo.hProcess := INVALID_HANDLE_VALUE; ProcessInfo.hThread := INVALID_HANDLE_VALUE; // Create pipes // initialize security attributes for handle inheritance (for WinNT) sa.nLength := sizeof(sa); sa.bInheritHandle := TRUE; sa.lpSecurityDescriptor := nil; // create STDIN pipe if not CreatePipe( hPipes[ H_IN_READ ], hPipes[ H_IN_WRITE ], @sa, 0 ) then goto error; // create STDOUT pipe if not CreatePipe( hPipes[ H_OUT_READ ], hPipes[ H_OUT_WRITE ], @sa, 0 ) then goto error; // create STDERR pipe if not CreatePipe( hPipes[ H_ERR_READ ], hPipes[ H_ERR_WRITE ], @sa, 0 ) then goto error; // process startup information ZeroMemory(Pointer(@si), sizeof(si)); si.cb := sizeof(si); si.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES; si.wShowWindow := SW_HIDE; // assign "other" sides of pipes si.hStdInput := hPipes[ H_IN_READ ]; si.hStdOutput := hPipes[ H_OUT_WRITE ]; si.hStdError := hPipes[ H_ERR_WRITE ]; // Create a child process try fCreated := CreateProcess( nil, PChar(szChildName), nil, nil, True, ProcPriority, // CREATE_SUSPENDED, nil, nil, si, ProcessInfo ); except fCreated := False; end; if not fCreated then goto error; Result := True; CloseHandle(hPipes[ H_OUT_WRITE ]); CloseHandle(hPipes[ H_ERR_WRITE ]); // ResumeThread( pi.hThread ); SetThreadPriority(ProcessInfo.hThread, ThreadPriority); CloseHandle( ProcessInfo.hThread ); Exit; //----------------------------------------------------- error: ClosePipes( hPipes ); CloseHandle( ProcessInfo.hProcess ); CloseHandle( ProcessInfo.hThread ); ProcessInfo.hProcess := INVALID_HANDLE_VALUE; ProcessInfo.hThread := INVALID_HANDLE_VALUE; Result := False; end;Алгоритмы Как считать CRC-32 ?
unit ChkSumm; interface const CRC32INIT = $FFFFFFFF; {----------------------------------------------------------------} { Buffer - массив байтов, для которого подсчитывается CRC } { CRC - начальное значение CRC } { Count - длина буфера } {----------------------------------------------------------------} function CalculateBufferCRC32( CRC : Cardinal; const Buffer; Count : Cardinal ) : Cardinal; register; {----------------------------------------------------------------} { Расчет 32-битовой CRC, алгоритм аналогичен применяемому в } { архиваторах ZIP, ARJ. При этом начальное значение CRC должно } { быть равно CRC32INIT, а после окончания подсчета окончательная } { CRC вычисляется по формуле : } { CRC := CRC xor CRC32INIT; } { Hапример : } { var } { Buffer : array[1..8192] of Char; } { CRC : Cardinal; } { Count : Cardinal; } { ....... } { CRC := CRC32INIT; } { repeat } { BlockRead(F, Buffer, SizeOf( Buffer ), Count); } { CRC := CalculateBufferCRC32( CRC, Buffer, Count ); } { until Eof(F); } { CRC := CRC xor CRC32INIT; } { ....... } {----------------------------------------------------------------} implementation const CRC32Table : array[0..255] of Cardinal = ( $00000000, $77073096, $EE0E612C, $990951BA, $076DC419, $706AF48F, $E963A535, $9E6495A3, $0EDB8832, $79DCB8A4, $E0D5E91E, $97D2D988, $09B64C2B, $7EB17CBD, $E7B82D07, $90BF1D91, $1DB71064, $6AB020F2, $F3B97148, $84BE41DE, $1ADAD47D, $6DDDE4EB, $F4D4B551, $83D385C7, $136C9856, $646BA8C0, $FD62F97A, $8A65C9EC, $14015C4F, $63066CD9, $FA0F3D63, $8D080DF5, $3B6E20C8, $4C69105E, $D56041E4, $A2677172, $3C03E4D1, $4B04D447, $D20D85FD, $A50AB56B, $35B5A8FA, $42B2986C, $DBBBC9D6, $ACBCF940, $32D86CE3, $45DF5C75, $DCD60DCF, $ABD13D59, $26D930AC, $51DE003A, $C8D75180, $BFD06116, $21B4F4B5, $56B3C423, $CFBA9599, $B8BDA50F, $2802B89E, $5F058808, $C60CD9B2, $B10BE924, $2F6F7C87, $58684C11, $C1611DAB, $B6662D3D, $76DC4190, $01DB7106, $98D220BC, $EFD5102A, $71B18589, $06B6B51F, $9FBFE4A5, $E8B8D433, $7807C9A2, $0F00F934, $9609A88E, $E10E9818, $7F6A0DBB, $086D3D2D, $91646C97, $E6635C01, $6B6B51F4, $1C6C6162, $856530D8, $F262004E, $6C0695ED, $1B01A57B, $8208F4C1, $F50FC457, $65B0D9C6, $12B7E950, $8BBEB8EA, $FCB9887C, $62DD1DDF, $15DA2D49, $8CD37CF3, $FBD44C65, $4DB26158, $3AB551CE, $A3BC0074, $D4BB30E2, $4ADFA541, $3DD895D7, $A4D1C46D, $D3D6F4FB, $4369E96A, $346ED9FC, $AD678846, $DA60B8D0, $44042D73, $33031DE5, $AA0A4C5F, $DD0D7CC9, $5005713C, $270241AA, $BE0B1010, $C90C2086, $5768B525, $206F85B3, $B966D409, $CE61E49F, $5EDEF90E, $29D9C998, $B0D09822, $C7D7A8B4, $59B33D17, $2EB40D81, $B7BD5C3B, $C0BA6CAD, $EDB88320, $9ABFB3B6, $03B6E20C, $74B1D29A, $EAD54739, $9DD277AF, $04DB2615, $73DC1683, $E3630B12, $94643B84, $0D6D6A3E, $7A6A5AA8, $E40ECF0B, $9309FF9D, $0A00AE27, $7D079EB1, $F00F9344, $8708A3D2, $1E01F268, $6906C2FE, $F762575D, $806567CB, $196C3671, $6E6B06E7, $FED41B76, $89D32BE0, $10DA7A5A, $67DD4ACC, $F9B9DF6F, $8EBEEFF9, $17B7BE43, $60B08ED5, $D6D6A3E8, $A1D1937E, $38D8C2C4, $4FDFF252, $D1BB67F1, $A6BC5767, $3FB506DD, $48B2364B, $D80D2BDA, $AF0A1B4C, $36034AF6, $41047A60, $DF60EFC3, $A867DF55, $316E8EEF, $4669BE79, $CB61B38C, $BC66831A, $256FD2A0, $5268E236, $CC0C7795, $BB0B4703, $220216B9, $5505262F, $C5BA3BBE, $B2BD0B28, $2BB45A92, $5CB36A04, $C2D7FFA7, $B5D0CF31, $2CD99E8B, $5BDEAE1D, $9B64C2B0, $EC63F226, $756AA39C, $026D930A, $9C0906A9, $EB0E363F, $72076785, $05005713, $95BF4A82, $E2B87A14, $7BB12BAE, $0CB61B38, $92D28E9B, $E5D5BE0D, $7CDCEFB7, $0BDBDF21, $86D3D2D4, $F1D4E242, $68DDB3F8, $1FDA836E, $81BE16CD, $F6B9265B, $6FB077E1, $18B74777, $88085AE6, $FF0F6A70, $66063BCA, $11010B5C, $8F659EFF, $F862AE69, $616BFFD3, $166CCF45, $A00AE278, $D70DD2EE, $4E048354, $3903B3C2, $A7672661, $D06016F7, $4969474D, $3E6E77DB, $AED16A4A, $D9D65ADC, $40DF0B66, $37D83BF0, $A9BCAE53, $DEBB9EC5, $47B2CF7F, $30B5FFE9, $BDBDF21C, $CABAC28A, $53B39330, $24B4A3A6, $BAD03605, $CDD70693, $54DE5729, $23D967BF, $B3667A2E, $C4614AB8, $5D681B02, $2A6F2B94, $B40BBE37, $C30C8EA1, $5A05DF1B, $2D02EF8D ); function CalculateBufferCRC32( CRC : Cardinal; const Buffer; Count : Cardinal ) : Cardinal; assembler; asm PUSH ESI PUSH EDI MOV ESI, Buffer // MOV ECX, Count // uncomment these strings // MOV EAX, CRC // if not use REGISTER calling convention CLD @@Loop: MOV EDI, EAX // copy CRC into DI LODSB // load next byte into AL XOR EDI, EAX // put array index into DL SHR EAX, 8 // shift CRC one byte right SHL DI, 2 // correct DI XOR EAX, DWORD PTR CRC32Table[EDI] // calculate next CRC value LOOP @@Loop POP EDI POP ESI end; end. Преобразование сумм в выражения прописью.
Предлагается 3 варианта. ================== unit NToText; interface { Функция NumToText возвращает словесное выражение для суммы CurrValue. Если CurrWord=true, то добавляется слово "рубль" в соотв. склонении. Если IfKopeck=true и CurrWord=true, то в выражении учитываются копейки, если CurrWord=false, копейки не учитываются при любом IfKopeck.} function NumToText(CurrValue:Currency; CurrWord:boolean; IfKopeck:boolean):string; implementation uses SysUtils; function NumToText(CurrValue:Currency; CurrWord:boolean; IfKopeck:boolean):string; function GetNumInPos(CurrValue:Currency; PosNum: Integer):Integer; var tmpstr,tmpint,tmpfrac:string; pospoint:integer; begin Result:=0; tmpstr:=CurrToStr(CurrValue); pospoint:=Pos('.',tmpstr); if PosNum>0 then begin if pospoint>0 then tmpint:=Copy(tmpstr,1,pospoint-1) else tmpint:=tmpstr; if PosNum>Length(tmpint) then exit; Result:=StrToInt(Copy(tmpint,Length(tmpint)-PosNum+1,1)); end; if PosNum<0 then begin if pospoint>0 then tmpfrac:=Copy(tmpstr,pospoint+1,Length(tmpstr)-pospoint) else tmpfrac:='00'; if Length(tmpfrac)<(-PosNum) then exit; Result:=StrToInt(Copy(tmpfrac,-PosNum,1)); end; end; function GetKopeck(CurrValue:Currency):string; var Dig1,Dig2:Integer; KWord:string; begin Dig1:=GetNumInPos(CurrValue,-1); Dig2:=GetNumInPos(CurrValue,-2); case Dig2 of 0,5..9:KWord:='копеек'; 1:KWord:='копейка'; 2..4:KWord:='копейки'; end; Result:=' '+IntToStr(Dig1)+IntToStr(Dig2)+' '+KWord; end; function GetOneVal(CurrValue:Currency;CathNum:Integer):integer; begin Result:=StrToInt(IntToStr(GetNumInPos(CurrValue,CathNum*3)) +IntToStr(GetNumInPos(CurrValue,CathNum*3-1)) +IntToStr(GetNumInPos(CurrValue,CathNum*3-2))); Result:=Result-1+1; end; function OneCathegory(OneVal,CathNum:Integer):string; function Cath000(Val000:Integer):string; begin result:=''; case Val000 of 1: result:='сто '; 2: result:='двести '; 3: result:='триста '; 4: result:='четыреста '; 5: result:='пятьсот '; 6: result:='шестьсот '; 7: result:='семьсот '; 8: result:='восемьсот '; 9: result:='девятьсот '; end; end; function Cath_00(Val_00:Integer):string; begin result:=''; case Val_00 of 1: result:='десять '; 2: result:='двадцать '; 3: result:='тридцать '; 4: result:='сорок '; 5: result:='пятьдесят '; 6: result:='шестьдесят '; 7: result:='семьдесят '; 8: result:='восемьдесят '; 9: result:='девяносто '; end; end; function Cath__0(Val__0:Integer; IfThousand:boolean):string; begin result:=''; case Val__0 of 1: if IfThousand then result:='одна ' else result:='один '; 2: if IfThousand then result:='две ' else result:='два '; 3: result:='три '; 4: result:='четыре '; 5: result:='пять '; 6: result:='шесть '; 7: result:='семь '; 8: result:='восемь '; 9: result:='девять '; end; end; begin result:=''; if OneVal=0 then exit; result:=Cath000(OneVal div 100)+Cath_00((OneVal mod 100) div 10)+Cath__0(OneVal mod 10,(CathNum=2)); end; function GetWord(OneVal,CathNum:Integer;CurrWord:boolean):string; var OneDigit:0..9; begin result:=''; OneDigit:=OneVal mod 10; if ((CathNum=1) and (not CurrWord)) then exit; if ((OneVal=0) and (CathNum<>1)) then exit; case CathNum of 1:case OneDigit of 0,5..9:result:='рублей '; 1:result:='рубль '; 2..4:result:='рубля '; end; 2:case OneDigit of 0,5..9:result:='тысяч '; 1:result:='тысяча '; 2..4:result:='тысячи '; end; 3:case OneDigit of 0,5..9:result:='миллионов '; 1:result:='миллион '; 2..4:result:='миллиона '; end; 4:case OneDigit of 0,5..9:result:='миллиардов '; 1:result:='миллиард '; 2..4:result:='миллиарда '; end; 5:case OneDigit of 0,5..9:result:='триллионов '; 1:result:='триллион '; 2..4:result:='триллиона '; end; end; end; var CathNum:1..5; OneVal:0..999; tmpstr:string; begin result:=''; if CurrValue<0 then begin raise Exception.Create('Отрицательное значение!'); Exit; end; if CurrValue=0 then exit; if ((CurrValue<1.0) and (not IfKopeck)) then exit; for CathNum:=5 downto 1 do begin OneVal:=GetOneVal(CurrValue,CathNum); result:=result+OneCathegory(OneVal,CathNum)+GetWord(OneVal,CathNum,CurrWord); end; result:=trim(result); if ((CurrValue<1.0) and CurrWord and IfKopeck) then result:='Ноль '+result; if result<>'' then begin tmpstr:=AnsiUpperCase(Copy(result,1,1)); result[1]:=tmpstr[1]; end; if (CurrWord and IfKopeck) then Result:=Result+GetKopeck(CurrValue); end; end. =========================== unit Numinwrd; interface function sMoneyInWords( Nin: double ): string; export; function szMoneyInWords( Nin: double ): PChar; export; { Денежная сумма Nin в рублях и копейках прописью 1997, в.2.0, by О.В.Болдырев} implementation uses SysUtils,Dialogs,Math; type tri=string[4]; mood=1..2; gender=(m,f); uns =array[0..9] of string[7]; tns =array[0..9] of string[13]; decs=array[0..9] of string[12]; huns=array[0..9] of string[10]; nums=array[0..4] of string[8]; money=array[1..2] of string[5]; endings=array[gender,mood,1..3] of tri;{окончания числительных и денег} const units:uns =('','один ','два ','три ','четыре ','пять ', 'шесть ','семь ','восемь ','девять '); unitsf:uns=('','одна ','две ','три ','четыре ','пять ', 'шесть ','семь ','восемь ','девять '); teens:tns= ('десять ','одиннадцать ','двенадцать ','тринадцать ', 'четырнадцать ','пятнадцать ','шестнадцать ', 'семнадцать ','восемнадцать ','девятнадцать '); decades:decs=('','десять ','двадцать ','тридцать ','сорок ', 'пятьдесят ','шестьдесят ','семьдесят ','восемьдесят ', 'девяносто '); hundreds:huns=('','сто ','двести ','триста ','четыреста ', 'пятьсот ','шестьсот ','семьсот ','восемьсот ', 'девятьсот '); numericals:nums=('','тысяч','миллион','миллиард','триллион'); RusMon:money=('рубл','копе'); ends:endings=((('','а','ов'),('ь','я','ей')), (('а','и',''),('йка','йки','ек'))); threadvar str: string; function EndingIndex(Arg: integer): integer; begin if ((Arg div 10) mod 10) <> 1 then case (Arg mod 10) of 1: Result := 1; 2..4: Result := 2; else Result := 3; end else Result := 3; end; function sMoneyInWords( Nin: double ): string; { Число Nin прописью, как функция } var g: gender; //род Nr: comp; {целая часть числа} Fr: integer; {дробная часть числа} i,iTri,Order: longint; {триада} procedure Triad; var iTri2: integer; un, de, ce :byte; //единицы, десятки, сотни function GetDigit: byte; begin Result := iTri2 mod 10; iTri2 := iTri2 div 10; end; begin iTri := trunc(Nr/IntPower(1000,i)); Nr := Nr - int( iTri*IntPower(1000,i)); iTri2:=iTri; if iTri > 0 then begin un := GetDigit; de := GetDigit; ce := GetDigit; if i=1 then g:=f else g:=m; {женского рода только тысяча} str := TrimRight(str)+' '+Hundreds[ce]; if de = 1 then str := TrimRight(str)+' '+Teens[un] else begin str := TrimRight(str)+' '+Decades[de]; case g of m: str := TrimRight(str)+' '+Units[un]; f: str := TrimRight(str)+' '+UnitsF[un]; end; end; if length(numericals[i]) > 1 then begin str := TrimRight(str)+' '+numericals[i]; str := TrimRight(str)+ends[g,1,EndingIndex(iTri)]; end; end; //triad is 0 ? if i=0 then Exit; Dec(i); Triad; end; begin str := ''; Nr := int( Nin ); Fr := round(100*frac(Nin)+0.0000001); Order := trunc(Log10(Nr)/3); if Order > High(numericals) then raise Exception.Create('Слишком большое число для суммы прописью'); i:= Order; Triad; str := Format('%s %s%s %.2d %s%s', [Trim(str),RusMon[1],ends[m,2,EndingIndex(iTri)], Fr, RusMon[2],ends[f,2,EndingIndex(Fr)]]); str[1] := (ANSIUpperCase(copy(str,1,1)))[1]; str[Length(str)+1] := #0; Result := str; end; function szMoneyInWords( Nin: double ): PChar; begin sMoneyInWords(Nin); Result := @(str[1]); end; end. ======================== unit uSpecLib; //Copyright Zhitomirsky Mark, 1990-1997, Saratov //------------------- Russian version interface const DigNames : array[0..9,boolean,-1..4 ] of string = ({0}(('копеек','рублей ','тысяч ','миллионов ','миллиардов ','триллионов '), ('копеек','рублей ','тысяч ','миллионов ','миллиардов ','триллионов ')), {1}(('одна копейка','один рубль ','одна тысяча ','один миллион ','один миллиард ','один триллион '), ('одиннадцать копеек','одиннадцать рублей ','одиннадцать тысяч ','одиннадцать миллионов ','одиннадцать миллиардов ','одиннадцать триллионов' )), {2}(('две копейки','два рубля ','две тысячи ','два миллиона ','два миллиарда ','два триллиона '), ('двенадцать копеек','двенадцать рублей ','двенадцать тысяч ','двенадцать миллионов ','двенадцать миллиардов ','двенадцать триллионов ')), {3}(('три копейки','три рубля ','три тысячи ','три миллиона ','три миллиарда ','три триллиона '), ('тринадцать копеек','тринадцать рублей ','тринадцать тысяч ','тринадцать миллионов ','тринадцать миллиардов ','тринадцать триллионов ')), {4}(('четыре копейки','четыре рубля ','четыре тысячи ','четыре миллиона ','четыре миллиарда ','четыре триллиона '), ('четырнадцать копеек','четырнадцать рублей ','четырнадцать тысяч ','четырнадцать миллионов ','четырнадцать миллиардов ','четырнадцать триллионов ')), {5}(('пять копеек','пять рублей ','пять тысяч ','пять миллионов ','пять миллиардов ','пять триллионов '), ('пятнадцать копеек','пятнадцать рублей ','пятнадцать тысяч ','пятнадцать миллионов ','пятнадцать миллиардов ','пятнадцать триллионов ')), {6}(('шесть копеек','шесть рублей ','шесть тысяч ','шесть миллионов ','шесть миллиардов ','шесть триллионов '), ('шестнадцать копеек','шестнадцать рублей ','шестнадцать тысяч ','шестнадцать миллионов ','шестнадцать миллиардов ','шестнадцать триллионов ')), {7}(('семь копеек','семь рублей ','семь тысяч ','семь миллионов ','семь миллиардов ','семь триллионов '), ('семнадцать копеек','семнадцать рублей ','семнадцать тысяч ','семнадцать миллионов ','семнадцать миллиардов ','семнадцать триллионов ')), {8}(('восемь копеек','восемь рублей ','восемь тысяч ','восемь миллионов ','восемь миллиардов ','восемь триллионов '), ('восемнадцать копеек','восемнадцать рублей ','восемнадцать тысяч ','восемнадцать миллионов ','восемнадцать миллиардов ','восемнадцать триллионов ')), {9}(('девять копеек','девять рублей ','девять тысяч ','девять миллионов ','девять миллиардов ','девять триллионов '), ('девятнадцать копеек','девятнадцать рублей ','девятнадцать тысяч ','девятнадцать миллионов ','девятнадцать миллиардов ','девятнадцать триллионов '))); {0 - ед, 1 -тыс, 2 - млн, 3 - млрд, 4 - трл} DigNames999 : array[0..9,1..2] of string = ({0}('',''), {1}('десять ','сто '), {2}('двадцать ','двести '), {3}('тридцать ','триста '), {4}('сорок ','четыреста '), {5}('пятьдесят ','пятьсот '), {6}('шестьдесят ','шестьсот '), {7}('семьдесят ','семьсот '), {8}('восемьдесят ','восемьсот '), {9}('девяносто ','девятьсот ')); {1 -дес, 2 - сот} type TCentsType=(ctNone,ctDigit,ctSentence); function NumericToSentence(numeric: currency; CentsType: TCentsType):string; implementation uses SysUtils; function CurrInt(Curr: Currency): Currency; var ss:string; begin ss:=CurrToStrF(Curr,ffFixed,4); delete(ss,length(ss)-4,5); result:=StrToCurr(ss); end; function CurrFrac(Curr: Currency): integer; var ss:string; begin ss:=CurrToStrF(Curr,ffFixed,4); delete(ss,1,length(ss)-4); result:=StrToInt(ss); end; function GetRankGroup(Curr: Currency; RankGroupNo: shortint): integer; var i: integer; begin if RankGroupNo=-1 then result:=trunc(CurrFrac(Curr)/100) else begin for i:=0 to RankGroupNo do begin Curr:=CurrInt(Curr); Curr:=Curr/1000; end; result:=trunc(CurrFrac(Curr)/10); end; end; function NumericToSentence; var RankGroup,Dig0, Dig1, Dig2,Cents: integer; rank,rank0: shortint; begin result:=''; Cents:=CurrFrac(numeric) div 100; if CentsType=ctSentence then rank0:=-1 else rank0:=0; if CurrInt(numeric)>0 then for rank:=rank0 to 4 do begin RankGroup:=trunc(GetRankGroup(numeric,rank)); Dig0:=RankGroup mod 10; Dig1:=(RankGroup mod 100 - Dig0) div 10; Dig2:=(RankGroup mod 1000 - Dig1) div 100; if (RankGroup>0) or (rank=0) then result:=Trim(DigNames999[Dig2,2]+ DigNames999[Dig1*integer((Dig1<>1)or(Dig0=0)),1]+ DigNames[Dig0,Dig1=1,rank]+result); end else begin result:='Ноль рублей'; end; if (CentsType=ctSentence) and (Cents=0) then result:=result+' ноль копеек'; if CentsType=ctDigit then result:=trim(result+' '+IntToStr(Cents)+' коп'); if length(result)>0 then result:=AnsiUpperCase(copy(result,1,1))+ copy(result,2,length(result)-1); result:=result+'.'; end; end.Bugs Const из другого unit'а дает неверное значение.
DX.Bug: Const из другого unit'а дает неверное значение. Unit Main; | Unit VData; | ... Interface | Implementation | Uses VData; | Uses Main; | Const Wko=0.9; | Procedure ...; | Begin ... | { вот здесь Wko=...E+230 - наверное бесконечность } | End; | Похоже, это действительно bug, пpичем ОСОБО ОПАСHЫЙ, т.к. может исказить pезультаты pасчетов, не вызвав заметных наpушений pаботы пpогpаммы. В общем так. Экспеpимент показал, что любая вещественная константа, опpеделенная в интеpфейсе модуля, может быть невеpно (и не обязательно очень невеpно - напpимеp, вместо 0.7 может появиться 0.115) пpочитана в дpугом модуле. Баг особенно опасен тем, что он неустойчив и может пpопадать и возникать без видимых пpичин (напpимеp, возникнуть, если пpедыдущая компиляция была неудачной и исчезнуть после использования константы в модуле, где она опpеделена). Лечится (вpоде бы) указанием типа const Wko: double = 0.9; пpавда, тепеpь это уже не совсем константа... Dmitry Medved (2:464/58.7)