Регистрация
программ в меню "Пуск" Windows
95.
Подобная проблема возникает
при создании инсталляторов и
деинсталляторов. Наиболее
простой и гибкий путь -
использование DDE. При этом
посылаются запросы к PROGMAN. Для
этого необходимо поместить на
форму компонент для посылки DDE
запросов - объект типа TDdeClientConv.
Для определенности назовем его
DDEClient. Затем добавим метод для
запросов к PROGMAN:
Function TForm2.ProgmanCommand(Command:string):boolean;
var
macrocmd:array[0..88] of char;
begin
DDEClient.SetLink('PROGMAN','PROGMAN');
DDEClient.OpenLink; { Устанавливаем связь по DDE }
strPCopy(macrocmd,'['+Command+']'); { Подготавливаем ASCIIZ строку }
ProgmanCommand :=DDEClient.ExecuteMacro(MacroCmd,false);
DDEClient.CloseLink; { Закрываем связь по DDE }
end;
При вызове ProgmanCommand
возвращает true, если посылка
макроса была успешна. Система
команд (основных) приведена
ниже:
Create(Имя группы, путь к GRP файлу)
Создать группу с именем "Имя
группы", причем в нем могут
быть пробелы и знаки
препинания. Путь к GRP файлу
можно не указывать, тогда он
создастся в каталоге Windows.
Delete(Имя группы)
Удалить группу с именем "Имя
группы"
ShowGroup(Имя группы, состояние)
Показать группу в окне,
причем состояние - число,
определяющее параметры окна:
1-нормальное состояние +
активация
2-миним.+ активация
3-макс. + активация
4-нормальное состояние
5-Активация
AddItem(командная строка, имя
раздела, путь к иконке, индекс
иконки (с 0), Xpos,Ypos, рабочий
каталог, HotKey, Mimimize)
Добавить раздел к активной
группе. В командной строке,
имени размера и путях
допустимы пробелы, Xpos и Ypos -
координаты иконки в окне, лучше
их не задавать, тогда PROGMAN
использует значения по
умолчанию для свободного места.
HotKey - виртуальный код горячей
клавиши. Mimimize - тип запуска, 0-в
обычном окне, <>0 - в
минимизированном.
DeleteItem(имя раздела)
Удалить раздел с указанным
именем в активной группе
Пример использования:
ProgmanCommand('CreateGroup(Комплекс
программ для каталогизации
литературы,)');
ProgmanCommand('AddItem('+path+'vbase.hlp,Справка
по VBase,'+ path +' vbase.hlp, 0, , , '+ path + ',,)');
где path - строка типа String,
содержащая полный путь к
каталогу ('C:\Catalog\');
Копирование
файлов
Копирование
методом TurboPascal
Type
TCallBack=procedure (Position,Size:Longint); {Для индикации процесса копирования}
procedure FastFileCopy(Const InfileName, OutFileName: String; CallBack: TCallBack);
Const BufSize = 3*4*4096; { 48Kbytes дает прекрасный результат }
Type
PBuffer = ^TBuffer;
TBuffer = array [1..BufSize] of Byte;
var
Size : integer;
Buffer : PBuffer;
infile, outfile : File;
SizeDone,SizeFile: Longint;
begin
if (InFileName <> OutFileName) then
begin
buffer := Nil;
AssignFile(infile, InFileName);
System.Reset(infile, 1);
try
SizeFile := FileSize(infile);
AssignFile(outfile, OutFileName);
System.Rewrite(outfile, 1);
try
SizeDone := 0; New(Buffer);
repeat
BlockRead(infile, Buffer^, BufSize, Size);
Inc(SizeDone, Size);
CallBack(SizeDone, SizeFile);
BlockWrite(outfile,Buffer^, Size)
until Size < BufSize;
FileSetDate(TFileRec(outfile).Handle,
FileGetDate(TFileRec(infile).Handle));
finally
if Buffer <> Nil then Dispose(Buffer);
System.close(outfile)
end;
finally
System.close(infile);
end;
end else
Raise EInOutError.Create('File cannot be copied into itself');
end;
Копирование методом потока
Procedure FileCopy(Const SourceFileName, TargetFileName: String);
Var
S,T : TFileStream;
Begin
S := TFileStream.Create(sourcefilename, fmOpenRead );
try
T := TFileStream.Create(targetfilename, fmOpenWrite or fmCreate);
try
T.CopyFrom(S, S.Size ) ;
FileSetDate(T.Handle, FileGetDate(S.Handle));
finally
T.Free;
end;
finally
S.Free;
end;
end;
Копирование методом LZExpand
uses LZExpand;
procedure CopyFile(FromFileName, ToFileName : string);
var
FromFile, ToFile: File;
begin
AssignFile(FromFile, FromFileName);
AssignFile(ToFile, ToFileName);
Reset(FromFile);
try
Rewrite(ToFile);
try
if LZCopy(TFileRec(FromFile).Handle, TFileRec(ToFile).Handle)<0 then
raise Exception.Create('Error using LZCopy')
finally
CloseFile(ToFile);
end;
finally
CloseFile(FromFile);
end;
end;
Копирование методами Windows
uses ShellApi; // !!! важно
function WindowsCopyFile(FromFile, ToDir : string) : boolean;
var F : TShFileOpStruct;
begin
F.Wnd := 0; F.wFunc := FO_COPY;
FromFile:=FromFile+#0; F.pFrom:=pchar(FromFile);
ToDir:=ToDir+#0; F.pTo:=pchar(ToDir);
F.fFlags := FOF_ALLOWUNDO or FOF_NOCONFIRMATION;
result:=ShFileOperation(F) = 0;
end;
// пример копирования
procedure TForm1.Button1Click(Sender: TObject);
begin
if not WindowsCopyFile('C:\UTIL\ARJ.EXE', GetCurrentDir) then
ShowMessage('Copy Failed');
end;
uses ShellApi; procedure TForm1.Button1Click(Sender: TObject); var OpStruc: TSHFileOpStruct; frombuf, tobuf: Array [0..128] of Char; Begin FillChar( frombuf, Sizeof(frombuf), 0 ); FillChar( tobuf, Sizeof(tobuf), 0 ); StrPCopy( frombuf, 'h:\hook\*.*' ); StrPCopy( tobuf, 'd:\temp\brief' ); With OpStruc DO Begin Wnd:= Handle; wFunc:= FO_COPY; pFrom:= @frombuf; pTo:=@tobuf; fFlags:= FOF_NOCONFIRMATION or FOF_RENAMEONCOLLISION; fAnyOperationsAborted:= False; hNameMappings:= Nil; lpszProgressTitle:= Nil; end; ShFileOperation( OpStruc ); end;
Удаление
каталога со всем содержимым
{ Удалить каталог со всем содержимым }
function DeleteDir(Dir : string) : boolean;
Var
Found : integer;
SearchRec : TSearchRec;
begin
result:=false;
if IOResult<>0 then ;
ChDir(Dir);
if IOResult<>0 then begin
ShowMessage('Не могу войти в каталог: '+Dir); exit;
end;
Found := FindFirst('*.*', faAnyFile, SearchRec);
while Found = 0 do
begin
if (SearchRec.Name<>'.')and(SearchRec.Name<>'..') then
if (SearchRec.Attr and faDirectory)<>0 then begin
if not DeleteDir(SearchRec.Name) then exit;
end else
if not DeleteFile(SearchRec.Name) then begin
ShowMessage('Не могу удалить файл: '+SearchRec.Name); exit;
end;
Found := FindNext(SearchRec);
end;
FindClose(SearchRec);
ChDir('..'); RmDir(Dir);
result:=IOResult=0;
end;
Определение
системной информации.
Часто при создании систем
привязки программ к компьютеру
или окон типа System Info или About Box
необходимо определить данные о
пользователе и о системе. Это
можно сделать следующим
образом (из примеров по Delphi -
программа COA):
Procedure GetInfo;
Var
WinVer, WinFlags : LongInt; { Версия Windows и флаги }
hInstUser, Fmt : Word; { Дескриптор }
Buffer : ARRAY[0..30] OF Char; { Буфер под ASCIIZ строку }
begin
hInstUser := LoadLibrary('USER'); { Открыли библиотеку User }
LoadString(hInstUser, 514, Buffer, 30);
LabelUserName.Caption := StrPas(Buffer); { Имя пользователя }
LoadString(hInstUser, 515, Buffer, 30);
FreeLibrary(hInstUser);
LabelCompName.Caption := StrPas(Buffer); { Компания }
WinVer := GetVersion;
LabelWinVer.Caption := Format('Windows %u.%.2u', { Версия Windows }
[LoByte(LoWord(WinVer)), HiByte(LoWord(WinVer))]);
LabelDosVer.Caption := Format('DOS %u.%.2u', { Версия DOS }
[HiByte(HiWord(WinVer)), LoByte(HiWord(WinVer))]);
WinFlags := GetWinFlags;
IF WinFlags AND WF_ENHANCED > 0 THEN
LabelWinMode.Caption := '386 Enhanced Mode' { Режим }
ELSE IF WinFlags AND WF_PMODE > 0 THEN
LabelWinMode.Caption := 'Standard Mode'
ELSE LabelWinMode.Caption := 'Real Mode';
IF WinFlags AND WF_80x87 > 0 THEN { Сопроцессор }
ValueMathCo.Caption := 'Present'
ELSE ValueMathCo.Caption := 'Absent';
Fmt := GetFreeSystemResources(GFSR_SYSTEMRESOURCES);
ValueFSRs.Caption := Format('%d%% Free', [Fmt1]); { Свободно ресурсов }
{ Свободно памяти}
ValueMemory.Caption := FormatFloat(',#######', MemAvail DIV 1024) + ' KB Free';
end;
Как
проинсталлировать свои шрифты?
Добавить фонт (.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+) - содержит
полный путь с именем и
расширением необходимого
фонта. После удаления фонта
форточки о нем забывают. Если
его не удалить, он (кажется) так
и останется проинсталенным, во
всяком случае, я это не
проверял.
Вставить
какую-нибудь программу внутрь
EXE файла
1. Пишем в блокноте RC-файл, куда
прописываем все нужные нам
программы, например:
ARJ EXEFILE C:\UTIL\ARJ.EXE
2. Компилируем его в ресурс при
помощи Brcc32.exe. Получаем RES-файл.
3. Далее в тексте нашей
программы:
implementation
{$R *.DFM}
{$R test.res} //Это наш RES-файл
procedure ExtractRes(ResType, ResName, ResNewName : String);
var
Res : TResourceStream;
begin
Res := TResourceStream.Create(Hinstance, Resname, Pchar(ResType));
Res.SavetoFile(ResNewName);
Res.Free;
end;
procedure TForm1.BitBtn1Click(Sender: TObject);
begin
// Записывает в текущую папку arj.exe
ExtractRes('EXEFILE', 'ARJ', 'ARJ.EXE');
end;
Как
написать маленький
инсталлятор ?
Мне понравился следующий
вариант: главное приложение
само выполняет функции
инсталлятора. Первоначально
файл называется Setup.exe. При
запуске под этим именем
приложение устанавливает себя,
после установки программа
переименовывает себя и
перестает быть инсталлятором.
Пример:
Application.Initialize; if UpperCase(ExtractFileName(Application.ExeName))='SETUP.EXE' then Application.CreateForm(TSetupForm, SetupForm) // форма инсталлятора else Application.CreateForm(TMainForm, MainForm); // форма основной программы Application.Run;
Procedure TForm1.Button1Click(Sender: TObject);
Begin
With Printer do Begin
BeginDoc; { Начало печати }
Canvas.Font:=label1.font; { Задали шрифт }
Canvas.TextOut(100,100,'Это тест принтера !!!'); { Печатаем текст }
EndDoc; { Конец печати }
end;
end;
Особенности
работы с TPrinter
1. После команды BeginDoc шрифт у
Canvas принтера сбрасывается и
его необходимо задавать заново
2. Все координаты даны в
пикселах, а для нормальной
работы необходимы миллиметры (по
двум очевидным причинам: очень
трудно произвести разметку
страницы в пикселах (особенно
если необходима точность), и ,
главное, при изменении
разрешающей способности
принтера будет изменяться
число точек на дюйм, и все
координаты "поедут".
3. У TPrinter информация о принтере,
по видимому, определяются один
раз - в момент запуска
программы (или смены принтера).
Поэтому изменение настроек
принтера в процессе работы
программы может привести к
некорректной работе, например,
неправильной печать шрифтов True
Type.
Определение параметров
принтера через API
Для определения информации о
принтере (плоттере, экране)
необходимо знать Handle этого
принтера, а его можно узнать
объекта TPrinter - Printer.Handle. Далее
вызывается функция API (unit WinProcs) :
GetDevice(Handle:HDC; Index:integer):integer;
Index - код параметра, который
необходимо вернуть. Для Index
существует ряд констант :
DriverVersion - вернуть версию
драйвера
Texnology - Технология вывода, их
много, основные
dt_Plotter - плоттер
dt_RasPrinter - растровый принтер
dt_Display - дисплей
HorzSize - Горизонтальный размер
листа (в мм)
VertSize - Вертикальный размер
листа (в мм)
HorzRes - Горизонтальный размер
листа (в пикселах)
VertRes - Вертикальный размер
листа (в пикселах)
LogPixelX - Разрешение по оси Х в dpi (пиксел
/дюйм)
LogPixelY - Разрешение по оси Y в dpi (пиксел
/дюйм)
Кроме перечисленных еще около
сотни, они позволяют узнать о
принтере практически все.
Параметры, возвращаемые по
LogPixelX и LogPixelY очень важны - они
позволяют произвести пересчет
координат из миллиметров в
пиксели для текущего
разрешения принтера. Пример
таких функций:
Procedure TForm1.GetPrinterInfo; { Получить информацию о принтере }
begin
PixelsX:=GetDeviceCaps(printer.Handle,LogPixelsX);
PixelsY:=GetDeviceCaps(printer.Handle,LogPixelsY);
end;
Function TForm1.PrinterCoordX(x:integer):integer; { переводит координаты из мм в пиксели }
begin
PrinterCoordX:=round(PixelsX/25.4*x);
end;
Function TForm1.PrinterCoordY(Y:integer):integer; { переводит координаты из мм в пиксели }
begin
PrinterCoordY:=round(PixelsY/25.4*Y);
end;
---------------------------------
GetPrinterInfo;
Printer.Canvas.TextOut(PrinterCoordX(30), PrinterCoordY(55),
'Этот текст печатается с отступом 30 мм от левого края и '+
'55 мм от верха при любом разрешении принтера');
Данную методику можно с
успехом применять для печати
картинок - зная размер картинки
можно пересчитать ее размеры в
пикселах для текущего
разрешения принтера,
масштабировать, и затем уже
распечатать. Иначе на
матричном принтере (180 dpi)
картинка будет огромной, а на
качественном струйнике (720 dpi) -
микроскопической.
Хранитель
экрана
1.В файл проекта (*.DPR) добавить
строку {$D SCRNSAVE <название
хранителя>} после строки
подключения модулей (Uses...).
2.У окна формы убрать системное
меню, кнопки и придать свойству
WindowState значение wsMaximize.
3.Предусмотреть выход из
хранителя при нажатии на
клавиши клавиатуры, мыши и при
перемещении курсора мыши.
4.Проверить параметры с которым
был вызван хранитель и если это
/c - показать окно настройки
хранителя, а иначе (можно
проверять на /s, а можно и не
проверять) сам хранитель. /p -
для отображения в окне
установок хранителя экрана.
5.Скомпилировать хранитель
экрана.
6.Переименовать *.EXE файл в файл *.SCR
и скопировать его в каталог
WINDOWS\SYSTEM\.
7.Установить новый хранитель в
настройках системы!
Название хранителя может
состоять из нескольких слов с
пробелами, на любом языке.
При работе хранителя
необходимо прятать курсор мыши,
только не забывайте
восстанавливать его после
выхода.
Все параметры и настройки
храните в файле .INI, так как
хранитель и окно настройки не
связаны друг с другом напрямую.
Старайтесь сделать свой
хранитель как можно меньше и
быстрее. Иначе ваши долго
работающие (в фоновом режиме)
приложения будут работать еше
дольше!
{в файле *.DPR}
{$D SCRNSAVE Пример хранителя экрана}
{проверить
переданные параметры}
IF (ParamStr(1) = '/c') OR (ParamStr(1) = '/C')
THEN
{скрыть курсор мыши}
ShowCursor(False);
{восстановить
курсор мыши}
ShowCursor(True);
Более подробно о
создании хранителя экрана "по
всем правилам"
Screen Saver in Win95
Главное о чем стоит упомянуть
это, что ваш хранитель экрана
будет работать в фоновом
режиме и он не должен мешать
работе других запущенных
программ. Поэтому сам
хранитель должен быть как
можно меньшего объема. Для
уменьшения объема файла в
описанной ниже программе не
используется визуальные
компоненты Delphi, включение хотя
бы одного из них приведет к
увеличению размера файла свыше
200кб, а так, описанная ниже
программа, имеет размер всего 20кб!!!
Технически, хранитель экрана
является нормальным EXE файлом (с
расширением .SCR), который
управляется через командные
параметры строки. Например,
если пользователь хочет
изменить параметры вашего
хранителя, Windows выполняет его с
параметром "-c" в командной
строке. Поэтому начать
создание вашего хранителя
экрана следует с создания
примерно следующей функции:
Procedure RunScreenSaver;
Var S : String;
Begin
S := ParamStr(1);
If (Length(S) > 1) Then Begin
Delete(S,1,1); { delete first char - usally "/" or "-" }
S[1] := UpCase(S[1]);
End;
LoadSettings; { load settings from registry }
If (S = 'C') Then RunSettings
Else If (S = 'P') Then RunPreview
Else If (S = 'A') Then RunSetPassword
Else RunFullScreen;
End;
Поскольку нам нужно
создавать небольшое окно
предварительного просмотра и
полноэкранное окно, их лучше
объединить используя
единственный класс окна.
Следуя правилам хорошего тона,
нам также нужно использовать
многочисленные нити. Дело в том,
что, во-первых, хранитель не
должен переставать работать
даже если что-то "тяжелое"
случилось, и во-вторых, нам не
нужно использовать таймер.
Процедура для запуска
хранителя на полном экране -
приблизительно такова:
Procedure RunFullScreen;
Var
R : TRect;
Msg : TMsg;
Dummy : Integer;
Foreground : hWnd;
Begin
IsPreview := False; MoveCounter := 3;
Foreground := GetForegroundWindow;
While (ShowCursor(False) > 0) do ;
GetWindowRect(GetDesktopWindow,R);
CreateScreenSaverWindow(R.Right-R.Left,R.Bottom-R.Top,0);
CreateThread(nil,0,@PreviewThreadProc,nil,0,Dummy);
SystemParametersInfo(spi_ScreenSaverRunning,1,@Dummy,0);
While GetMessage(Msg,0,0,0) do Begin
TranslateMessage(Msg);
DispatchMessage(Msg);
End;
SystemParametersInfo(spi_ScreenSaverRunning,0,@Dummy,0);
ShowCursor(True);
SetForegroundWindow(Foreground);
End;
Во-первых, мы
проинициализировали некоторые
глобальные переменные (описанные
далее), затем прячем курсор
мыши и создаем окно хранителя
экрана. Имейте в виду, что важно
уведомлять Windows, что это -
хранителя экрана через
SystemParametersInfo (это выводит из
строя Ctrl-Alt-Del чтобы нельзя было
вернуться в Windows не введя
пароль). Создание окна
хранителя:
Function CreateScreenSaverWindow(Width,Height : Integer;
ParentWindow : hWnd) : hWnd;
Var WC : TWndClass;
Begin
With WC do Begin
Style := cs_ParentDC;
lpfnWndProc := @PreviewWndProc;
cbClsExtra := 0; cbWndExtra := 0; hIcon := 0; hCursor := 0;
hbrBackground := 0; lpszMenuName := nil;
lpszClassName := 'MyDelphiScreenSaverClass';
hInstance := System.hInstance;
end;
RegisterClass(WC);
If (ParentWindow 0) Then
Result := CreateWindow('MyDelphiScreenSaverClass','MySaver',
ws_Child Or ws_Visible or ws_Disabled,0,0,
Width,Height,ParentWindow,0,hInstance,nil)
Else Begin
Result := CreateWindow('MyDelphiScreenSaverClass','MySaver',
ws_Visible or ws_Popup,0,0,Width,Height, 0,0,hInstance,nil);
SetWindowPos(Result,hwnd_TopMost,0,0,0,0,swp_NoMove or swp_NoSize or swp_NoRedraw);
End;
PreviewWindow := Result;
End;
Теперь окна созданы
используя вызовы API. Я удалил
проверку ошибки, но обычно все
проходит хорошо, особенно в
этом типе приложения.
Теперь Вы можете погадать, как
мы получим handle родительского
окна предварительного
просмотра ? В действительности,
это совсем просто: Windows просто
передает handle в командной
строке, когда это нужно. Таким
образом:
Procedure RunPreview;
Var
R : TRect;
PreviewWindow : hWnd;
Msg : TMsg;
Dummy : Integer;
Begin
IsPreview := True;
PreviewWindow := StrToInt(ParamStr(2));
GetWindowRect(PreviewWindow,R);
CreateScreenSaverWindow(R.Right-R.Left,R.Bottom-R.Top,PreviewWindow);
CreateThread(nil,0,@PreviewThreadProc,nil,0,Dummy);
While GetMessage(Msg,0,0,0) do Begin
TranslateMessage(Msg); DispatchMessage(Msg);
End;
End;
Как Вы видите, window handle
является вторым параметром (после
"-p").
Чтобы "выполнять"
хранителя экрана - нам нужна
нить. Это создается с
вышеуказанным CreateThread.
Процедура нити выглядит
примерно так:
Function PreviewThreadProc(Data : Integer) : Integer; StdCall;
Var R : TRect;
Begin
Result := 0; Randomize;
GetWindowRect(PreviewWindow,R);
MaxX := R.Right-R.Left; MaxY := R.Bottom-R.Top;
ShowWindow(PreviewWindow,sw_Show); UpdateWindow(PreviewWindow);
Repeat
InvalidateRect(PreviewWindow,nil,False);
Sleep(30);
Until QuitSaver;
PostMessage(PreviewWindow,wm_Destroy,0,0);
End;
Нить просто заставляет
обновляться изображения в
нашем окне, спит на некоторое
время, и обновляет изображения
снова. А Windows будет посылать
сообщение WM_PAINT на наше окно (не
в нить !). Для того, чтобы
оперировать этим сообщением,
нам нужна процедура:
Function PreviewWndProc(Window : hWnd; Msg,WParam,
LParam : Integer): Integer; StdCall;
Begin
Result := 0;
Case Msg of
wm_NCCreate : Result := 1;
wm_Destroy : PostQuitMessage(0);
wm_Paint : DrawSingleBox; { paint something }
wm_KeyDown : QuitSaver := AskPassword;
wm_LButtonDown, wm_MButtonDown, wm_RButtonDown, wm_MouseMove :
Begin
If (Not IsPreview) Then Begin
Dec(MoveCounter);
If (MoveCounter <= 0) Then QuitSaver := AskPassword;
End;
End;
Else Result := DefWindowProc(Window,Msg,WParam,LParam);
End;
End;
Если мышь перемещается,
кнопка нажала, мы спрашиваем у
пользователя пароль:
Function AskPassword : Boolean;
Var
Key : hKey;
D1,D2 : Integer; { two dummies }
Value : Integer;
Lib : THandle;
F : TVSSPFunc;
Begin
Result := True;
If (RegOpenKeyEx(hKey_Current_User,'Control Panel\Desktop',0,
Key_Read,Key) = Error_Success) Then
Begin
D2 := SizeOf(Value);
If (RegQueryValueEx(Key,'ScreenSaveUsePassword',nil,@D1,
@Value,@D2) = Error_Success) Then
Begin
If (Value 0) Then Begin
Lib := LoadLibrary('PASSWORD.CPL');
If (Lib > 32) Then Begin
@F := GetProcAddress(Lib,'VerifyScreenSavePwd');
ShowCursor(True);
If (@F nil) Then Result := F(PreviewWindow);
ShowCursor(False);
MoveCounter := 3; { reset again if password was wrong }
FreeLibrary(Lib);
End;
End;
End;
RegCloseKey(Key);
End;
End;
Это также демонстрирует
использование registry на уровне API.
Также имейте в виду как мы
динамически загружаем функции
пароля, используюя LoadLibrary.
Запомните тип функции?
TVSSFunc ОПРЕДЕЛЕН как:
Type
TVSSPFunc = Function(Parent : hWnd) : Bool; StdCall;
Теперь почти все готово, кроме
диалога конфигурации. Это
запросто:
Procedure RunSettings; Var Result : Integer; Begin Result := DialogBox(hInstance,'SaverSettingsDlg',0,@SettingsDlgProc); If (Result = idOK) Then SaveSettings; End;
Трудная часть -это создать
диалоговый сценарий (запомните:
мы не используем здесь Delphi
формы!). Я сделал это, используя
16-битовую Resource Workshop (остался
еще от Turbo Pascal для Windows). Я
сохранил файл как сценарий (текст),
и скомпилированный это с BRCC32:
SaverSettingsDlg DIALOG 70, 130, 166, 75
STYLE WS_POPUP | WS_DLGFRAME | WS_SYSMENU
CAPTION "Settings for Boxes"
FONT 8, "MS Sans Serif"
BEGIN
DEFPUSHBUTTON "OK", 5, 115, 6, 46, 16
PUSHBUTTON "Cancel", 6, 115, 28, 46, 16
CTEXT "Box &Color:", 3, 2, 30, 39, 9
COMBOBOX 4, 4, 40, 104, 50, CBS_DROPDOWNLIST | CBS_HASSTRINGS
CTEXT "Box &Type:", 1, 4, 3, 36, 9
COMBOBOX 2, 5, 12, 103, 50, CBS_DROPDOWNLIST | CBS_HASSTRINGS
LTEXT "Boxes Screen Saver for Win32 Copyright (c) 1996 Jani
Jдrvinen.", 7, 4, 57, 103, 16,
WS_CHILD | WS_VISIBLE | WS_GROUP
END
Почти также легко сделать
диалоговое меню:
Function SettingsDlgProc(Window : hWnd; Msg,WParam,LParam : Integer): Integer; StdCall;
Var S : String;
Begin
Result := 0;
Case Msg of
wm_InitDialog : Begin
{ initialize the dialog box }
Result := 0;
End;
wm_Command : Begin
If (LoWord(WParam) = 5) Then EndDialog(Window,idOK)
Else If (LoWord(WParam) = 6) Then EndDialog(Window,idCancel);
End;
wm_Close : DestroyWindow(Window);
wm_Destroy : PostQuitMessage(0);
Else Result := 0;
End;
End;
После того, как пользователь
выбрал некоторые установочные
параметры, нам нужно сохранить
их.
Procedure SaveSettings;
Var
Key : hKey;
Dummy : Integer;
Begin
If (RegCreateKeyEx(hKey_Current_User,
'Software\SilverStream\SSBoxes',
0,nil,Reg_Option_Non_Volatile,
Key_All_Access,nil,Key,
@Dummy) = Error_Success) Then Begin
RegSetValueEx(Key,'RoundedRectangles',0,Reg_Binary,
@RoundedRectangles,SizeOf(Boolean));
RegSetValueEx(Key,'SolidColors',0,Reg_Binary, @SolidColors,SizeOf(Boolean));
RegCloseKey(Key);
End;
End;
Загружаем параметры так:
Procedure LoadSettings;
Var
Key : hKey;
D1,D2 : Integer; { two dummies }
Value : Boolean;
Begin
If (RegOpenKeyEx(hKey_Current_User,
'Software\SilverStream\SSBoxes',0,
Key_Read,
Key) = Error_Success) Then Begin
D2 := SizeOf(Value);
If (RegQueryValueEx(Key,'RoundedRectangles',nil,@D1,
@Value, @D2) = Error_Success) Then
Begin
RoundedRectangles := Value;
End;
If (RegQueryValueEx(Key,'SolidColors',nil,@D1,
@Value,@D2) = Error_Success) Then
Begin
SolidColors := Value;
End;
RegCloseKey(Key);
End;
End;
Легко? Нам также нужно
позволить пользователю,
установить пароль. Я честно не
знаю почему это оставлено
разработчику приложений ? Тем
не менее:
Procedure RunSetPassword;
Var
Lib : THandle;
F : TPCPAFunc;
Begin
Lib := LoadLibrary('MPR.DLL');
If (Lib > 32) Then Begin
@F := GetProcAddress(Lib,'PwdChangePasswordA');
If (@F nil) Then F('SCRSAVE',StrToInt(ParamStr(2)),0,0);
FreeLibrary(Lib);
End;
End;
Мы динамически загружаем (недокументированную)
библиотеку MPR.DLL, которая имеет
функцию, чтобы установить
пароль хранителя экрана, так
что нам не нужно беспокоиться
об этом.
TPCPAFund ОПРЕДЕЛЕН как:
Type
TPCPAFunc = Function(A : PChar; Parent : hWnd; B,C :
Integer) : Integer; StdCall;
(Не спрашивайте меня что за
параметры B и C) Теперь
единственная вещь, которую нам
нужно рассмотреть, - самая
странная часть: создание
графики. Я не великий ГУРУ
графики, так что Вы не увидите
затеняющие многоугольники,
вращающиеся в реальном времени.
Я только сделал некоторые
ящики.
Procedure DrawSingleBox;
Var
PaintDC : hDC;
Info : TPaintStruct;
OldBrush : hBrush;
X,Y : Integer;
Color : LongInt;
Begin
PaintDC := BeginPaint(PreviewWindow,Info);
X := Random(MaxX); Y := Random(MaxY);
If SolidColors Then
Color := GetNearestColor(PaintDC,RGB(Random(255),Random(255),Random(255)))
Else Color := RGB(Random(255),Random(255),Random(255));
OldBrush := SelectObject(PaintDC,CreateSolidBrush(Color));
If RoundedRectangles Then
RoundRect(PaintDC,X,Y,X+Random(MaxX-X),Y+Random(MaxY-Y),20,20)
Else Rectangle(PaintDC,X,Y,X+Random(MaxX-X),Y+Random(MaxY-Y));
DeleteObject(SelectObject(PaintDC,OldBrush));
EndPaint(PreviewWindow,Info);
End;
Чтобы закончить создание
хранителя, я даю Вам некоторые
детали. Первые, глобальные
переменные:
Var IsPreview : Boolean; MoveCounter : Integer; QuitSaver : Boolean; PreviewWindow : hWnd; MaxX,MaxY : Integer; RoundedRectangles : Boolean; SolidColors : Boolean;
Затем исходная программа
проекта (.dpr). Красива, а!?
program MySaverIsGreat;
uses
windows, messages, Utility; { defines all routines }
{$R SETTINGS.RES}
begin
RunScreenSaver;
end.
Ох, чуть не забыл: Если, Вы
используете SysUtils в вашем
проекте (StrToInt определен там) Вы
получаете большой EXE чем
обещанный 20k. Если Вы хотите все
же иметь20k, Вы не можете
использовать SysUtils так, или Вам
нужно написать вашу
собственную StrToInt программу.
Конец.
Use Val... ;-)
перевод: Владимиров А.М.
От переводчика. Если все же
очень трудно обойтись без
использования Delphi-форм, то
можно поступить как в случае с
вводом пароля: форму изменения
параметров хранителя
сохранить в виде DLL и
динамически ее загружать при
необходимости. Т.о. будет
маленький и шустрый файл
самого хранителя экрана и
довеска DLL для
конфигурирования и прочего (там
объем и скорость уже не
критичны).
Включение
и выключение устройств ввода/вывода
из программы на Delphi
Иногда может возникнуть
необходимость в выключении на
время устройств ввода -
клавиатуры и мыши. Например,
это неплохо сделать на время
выполнения кода системы защиты
от копирования, в играх, или в
качестве "наказания" при
запуске программы по истечению
срока ее бесплатного
использования ... . Однако
наилучшее ее применение -
отключение клавиатуры и мыши
на время работы
демонстрационки, основанной на
воспроизведении записанных
заранее перемещений мышки и
клавиатурного ввода (см. об
этом отдельный раздел этой
книги). Это элементарно сделать
при помощи API:
EnableHadwareInput(Enable:boolean): boolean;
Enable - требуемое состояние
устройств ввода (True - включены,
false - выключены). Если ввод
заблокирован, то его можно
разблокировать вручную -
нажать Ctrl + Alt + Del, при появлении
меню "Завершение работы
программы" ввод
разблокируется.
А вот еще интересный прикол.
Включение/выключение монитора
программным способом.
Предупреждаю сразу! После того,
как вы отключите монитор,
просто так вы его уже не
включите (хотя это может быть
зависит от монитора, я, во
всяком случае, не смог). Только
после перезагрузки компьютера.
Отключить :
SendMessage(Application.Handle, WM_SYSCOMMAND, SC_MONITORPOWER,
0);
Включить :
SendMessage(Application.Handle, WM_SYSCOMMAND, SC_MONITORPOWER,
-1);
Переключение
языка из программы
Для переключения языка
применяется вызов LoadKeyboardLayout:
var russian, latin: HKL;
russian:=LoadKeyboardLayout('00000419', 0);
latin:=LoadKeyboardLayout('00000409', 0);
-- -- -- -- -- где то в программе --- --- ---
SetActiveKeyboardLayout(russian);
Как
отловить нажатия клавиш для
всех процессов в системе?
Вот, может поможет:
>1. Setup.bat
=== Cut ===
@echo off
copy HookAgnt.dll %windir%\system
copy kbdhook.exe %windir%\system
start HookAgnt.reg
=== Cut ===
>2.HookAgnt.reg
=== Cut ===
REGEDIT4
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run]
"kbdhook"="kbdhook.exe"
=== Cut ===
>3.KbdHook.dpr
=== Cut ===
program cwbhook;
uses Windows, Dialogs;
var
hinstDLL: HINST;
hkprcKeyboard: TFNHookProc;
msg: TMsg;
begin
hinstDLL := LoadLibrary('HookAgnt.dll');
hkprcKeyboard := GetProcAddress(hinstDLL, 'KeyboardProc');
SetWindowsHookEx(WH_KEYBOARD, hkprcKeyboard, hinstDLL, 0);
repeat until not GetMessage(msg, 0, 0, 0);
end.
=== Cut ===
>4.HookAgnt.dpr
=== Cut ===
library HookAgent;
uses Windows, KeyboardHook in 'KeyboardHook.pas';
exports KeyboardProc;
var
hFileMappingObject: THandle;
fInit: Boolean;
procedure DLLMain(Reason: Integer);
begin
if Reason = DLL_PROCESS_DETACH then begin
UnmapViewOfFile(lpvMem);
CloseHandle(hFileMappingObject);
end;
end;
begin
DLLProc := @DLLMain;
hFileMappingObject := CreateFileMapping(
THandle($FFFFFFFF), // use paging file
nil, // no security attributes
PAGE_READWRITE, // read/write access
0, // size: high 32 bits
4096, // size: low 32 bits
'HookAgentShareMem' // name of map object
);
if hFileMappingObject = INVALID_HANDLE_VALUE then begin
ExitCode := 1;
Exit;
end;
fInit := GetLastError() <> ERROR_ALREADY_EXISTS;
lpvMem := MapViewOfFile(
hFileMappingObject, // object to map view of
FILE_MAP_WRITE, // read/write access
0, // high offset: map from
0, // low offset: beginning
0); // default: map entire file
if lpvMem = nil then begin
CloseHandle(hFileMappingObject);
ExitCode := 1;
Exit;
end;
if fInit then FillChar(lpvMem, PASSWORDSIZE, #0);
end.
=== Cut ===
>5.KeyboardHook.pas
=== Cut ===
unit KeyboardHook;
interface
uses Windows;
const PASSWORDSIZE = 16;
var
g_hhk: HHOOK;
g_szKeyword: array[0..PASSWORDSIZE-1] of char;
lpvMem: Pointer;
function KeyboardProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM ): LRESULT; stdcall;
implementation
uses SysUtils, Dialogs;
function KeyboardProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM ): LRESULT;
var
szModuleFileName: array[0..MAX_PATH-1] of Char;
szKeyName: array[0..16] of Char;
lpszPassword: PChar;
begin
lpszPassword := PChar(lpvMem);
if (nCode = HC_ACTION) and (((lParam shr 16) and KF_UP) = 0) then begin
GetKeyNameText(lParam, szKeyName, sizeof(szKeyName));
if StrLen(g_szKeyword) + StrLen(szKeyName) >= PASSWORDSIZE then
lstrcpy(g_szKeyword, g_szKeyword + StrLen(szKeyName));
lstrcat(g_szKeyword, szKeyName);
GetModuleFileName(0, szModuleFileName, sizeof(szModuleFileName));
> if (StrPos(StrUpper(szModuleFileName),'__ТО_ЧЕГО_НАДО__') <> nil) and
(strlen(lpszPassword) + strlen(szKeyName) < PASSWORDSIZE) then
lstrcat(lpszPassword, szKeyName);
if StrPos(StrUpper(g_szKeyword), 'GOLDENEYE') <> nil then
begin
ShowMessage(lpszPassword);
g_szKeyword[0] := #0;
end;
Result := 0;
end
else Result := CallNextHookEx(g_hhk, nCode, wParam, lParam);
end;
end.
=== Cut ===
Информация
о состоянии клавиатуры
Я хотел бы узнать, при запуске
моего приложения, нажата ли
клавиша Ctrl. Просто хочется
сделать, что-то вроде пароля.
О состоянии клавиатуры дают
информацию следующие функции:
GetKeyState, GetAsyncKeyState, GetKeyboardState.
Чтобы упростить себе жизнь и не
возиться с этими функциями
снова и снова я написал
маленькие функции:
function AltKeyDown : boolean; begin result:=(Word(GetKeyState(VK_MENU)) and $8000)<>0; end; function CtrlKeyDown : boolean; begin result:=(Word(GetKeyState(VK_CONTROL)) and $8000)<>0; end; function ShiftKeyDown : boolean; begin result:=(Word(GetKeyState(VK_SHIFT)) and $8000)<>0; end; А заодно и для клавиш переключателей: function CapsLock : boolean; begin result:=(GetKeyState(VK_CAPITAL) and 1)<>0; end; function InsertOn : boolean; begin result:=(GetKeyState(VK_INSERT) and 1)<>0; end; function NumLock : boolean; begin result:=(GetKeyState(VK_NUMLOCK) and 1)<>0; end; function ScrollLock : boolean; begin result:=(GetKeyState(VK_SCROLL) and 1)<>0; end;
Управление
питанием из программы на Delphi
При написании разнообразны
программ типа заставок,
менеджеров управления
компьютером ... возникает
необходимость переводить
компьютер в режим "спячки".
Для включения этого режима в
Windows 95 (и только в ней !!)
предусмотрена команда API:
SetSystemPowerState(Suspended, Mode: Boolean):boolean;
Suspended должно быть TRUE для ухода в
спячку.
Mode - режим входа в спячку. Если
TRUE, то всем программам и
драйверам посылается Message PBT_APMSUSPEND,
по которому они должны
немедленно прекратить работу.
Если FALSE, то посылается Message PBT_APMQUERYSUSPEND
запроса на спячку, и драйвера в
ответ могут дать отказ на
включение режима спячки.
Возврат функции SetSystemPowerState: TRUE -
режим включен.
Пример
получения списка запущенных
приложений.
procedure TForm1.Button1Click(Sender: TObject);
VAR
Wnd : hWnd;
buff: ARRAY [0..127] OF Char;
begin
ListBox1.Clear;
Wnd := GetWindow(Handle, gw_HWndFirst);
WHILE Wnd <> 0 DO BEGIN {Не показываем:}
IF (Wnd <> Application.Handle) AND {-Собственное окно}
IsWindowVisible(Wnd) AND {-Невидимые окна}
(GetWindow(Wnd, gw_Owner) = 0) AND {-Дочернии окна}
(GetWindowText(Wnd, buff, sizeof(buff)) <> 0){-Окна без заголовков}
THEN BEGIN
GetWindowText(Wnd, buff, sizeof(buff));
ListBox1.Items.Add(StrPas(buff));
END;
Wnd := GetWindow(Wnd, gw_hWndNext);
END;
ListBox1.ItemIndex := 0;
end;
Как
отключить показ кнопки
программы в TaskBar и по Alt-Tab и в Ctrl-Alt-Del
Внеся изменения (выделенные
цветом) в свой проект вы
получите приложение, которое
не видно в TaskBar и на него нельзя
переключиться по Alt-Tab
program Project1;
uses
Forms,
Windows,
Unit1 in 'Unit1.pas' {Form1};
{$R *.RES}
var
ExtendedStyle : integer;
begin
Application.Initialize;
ExtendedStyle:=GetWindowLong(application.Handle, GWL_EXSTYLE);
SetWindowLong(Application.Handle, GWL_EXSTYLE,
ExtendedStyle or WS_EX_TOOLWINDOW {AND NOT WS_EX_APPWINDOW});
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
Если включить синий
коментарий, то получите очень
интересное приложение. Оно не
видно в TaskBar и на него нельзя
переключиться по Alt-Tab, но когда
приложение минимизируется оно
остается на рабочем столе в
виде свернутого заголовка (прямо
как в старом добром Windows 3.11)
Только сpазу пpедупpеждаю пpо гpабли,
на котоpые я наступал:
Будь готов к тому, что если пpи
попытке закpытия пpиложения в
OnCloseQuery или OnClose выводится вопpос
о подтвеpждении, то могут быть пpоблемы
с автоматическим завеpшением пpогpаммы
пpи shutdown - под Win95 пpосто
зависает, под WinNT не завеpшается.
Очевидно, что сообщение
выводится, но его не видно (пpичем
SW_RESTORE не сpабатывает). Решение -
ловить WM_QueryEndSession и после
всяких завеpшающих действий и
вызова CallTerminateProcs выдавать Halt.
А вот как отрубить
показ файла в Ctrl-Alt-Del
function RegisterServiceProcess(dwProcessID, dwType: Integer): Integer; stdcall; external 'KERNEL32.DLL'; implementation procedure TForm1.Button1Click(Sender: TObject); begin //Hide if not (csDesigning in ComponentState) then RegisterServiceProcess(GetCurrentProcessID, 1); end; procedure TForm1.Button2Click(Sender: TObject); begin //Show if not (csDesigning in ComponentState) then RegisterServiceProcess(GetCurrentProcessID, 0); end;
Добавление
программы в автозапуск
sProgTitle: Название для программы
sCmdLine: Имя EXE файла с путем доступа
bRunOnce: Запустить только один раз или постоянно при загрузке Windows
procedure RunOnStartup(sProgTitle, sCmdLine : string; bRunOnce : boolean );
var
sKey : string;
reg : TRegIniFile;
begin
if( bRunOnce )then sKey := 'Once'
else sKey := '';
reg := TRegIniFile.Create( '' );
reg.RootKey := HKEY_LOCAL_MACHINE;
reg.WriteString(
'Software\Microsoft'
+ '\Windows\CurrentVersion\Run'
+ sKey + #0,
sProgTitle,
sCmdLine );
reg.Free;
end;
// Например
RunOnStartup('Title of my program','MyProg.exe',False );
Примечание. Этот пример
удобно использовать при
написании деинсталляторов -
добавить однократный вызов
деинсталлятора и запросить от
пользователя перезагрузку.
Этот прием позволит
безболезненно удалять DLL и им
подобные файлы, которые
обычном способом удалить
невозможно (они загружены в
силу того, что использовались
деинсталлируемой программой
или работают в момент
деинсталляции).
uses ShellAPI;
function DeleteFileWithUndo( sFileName : string ) : boolean;
var fos : TSHFileOpStruct;
begin
sFileName:= sFileName+#0;
FillChar( fos, SizeOf( fos ), 0 );
with fos do begin
wFunc := FO_DELETE;
pFrom := PChar( sFileName );
fFlags := FOF_ALLOWUNDO or FOF_NOCONFIRMATION or FOF_SILENT;
end;
Result := ( 0 = ShFileOperation( fos ) );
end;
Добавить
ссылку на мой файл в меню Пуск|Документы
uses ShellAPI, ShlOBJ; procedure AddToStartDocumentsMenu( sFilePath : string ); begin SHAddToRecentDocs( SHARD_PATH, PChar( sFilePath ) ); end; // Например AddToStartDocumentsMenu( 'c:\windows\MyWork.txt' );
Устанавливаем
свой WallPaper для Windows
program wallpapr;
uses Registry, WinProcs;
procedure SetWallpaper(sWallpaperBMPPath : String; bTile : boolean );
var
reg : TRegIniFile;
begin
// Изменяем ключи реестра
// HKEY_CURRENT_USER
// Control Panel\Desktop
// TileWallpaper (REG_SZ)
// Wallpaper (REG_SZ)
reg := TRegIniFile.Create('Control Panel\Desktop' );
with reg do begin
WriteString( '', 'Wallpaper',
sWallpaperBMPPath );
if( bTile )then
begin
WriteString('', 'TileWallpaper', '1' );
end else begin
WriteString('', 'TileWallpaper', '0' );
end;
end;
reg.Free;
// Оповещаем всех о том, что мы
// изменили системные настройки
SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, Nil, SPIF_SENDWININICHANGE );
end;
begin
// пример установки WallPaper по центру рабочего стола
SetWallpaper('c:\winnt\winnt.bmp', False );
end.
Как
запретить кнопку 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;
Каким
образом можно изменить
системное меню формы?
Hе знаю как насчет
акселераторов, надо поискать, а
вот добавить Item - пожалуйста
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;
Запуск
внешней программы и ожидание
ее завершения
procedure TForm1.Button1Click(Sender: TObject); var si : Tstartupinfo; p : Tprocessinformation; begin FillChar( Si, SizeOf( Si ) , 0 ); with Si do begin cb := SizeOf( Si); dwFlags := startf_UseShowWindow; wShowWindow := 4; end; Application.Minimize; Createprocess(nil,'notepad.exe',nil,nil,false,Create_default_error_mode,nil,nil,si,p); Waitforsingleobject(p.hProcess,infinite); Application.Restore; end;
Как
узнать местоположение
специальных папок у Windows?
var
FolderPath :string;
Registry := TRegistry.Create;
try
Registry.RootKey := HKey_Current_User;
Registry.OpenKey('Software\Microsoft\Windows\'+
'CurrentVersion\Explorer\Shell Folders', False);
FolderName := Registry.ReadString('StartUp');
{Cache, Cookies, Desktop, Favorites,
Fonts, Personal, Programs, SendTo, Start Menu, Startp}
finally
Registry.Free;
end;
Как
засунуть в исполняемый файл wav-файл,
и затем проиграть этот звук?
В файл MyWave.rc пишешь:
MyWave RCDATA LOADONCALL MyWave.wav
Затем компилируешь
brcc32.exe MyWave.rc, получаешь MyWave.res.
В своей программе пишешь:
{$R MyWave.res}
procedure RetrieveMyWave;
var
hResource: THandle;
pData: Pointer;
begin
hResource:=LoadResource( hInstance, FindResource(hInstance, 'MyWave', RT_RCDATA));
try
pData := LockResource(hResource);
if pData = nil then raise Exception.Create('Cannot read MyWave');
// Здесь pData указывает на MyWave
// Теперь можно, например, проиграть его (Win32):
PlaySound('MyWave', 0, SND_MEMORY);
finally
FreeResource(hResource);
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
hTaskBar : THandle;
begin
hTaskbar := FindWindow('Shell_TrayWnd', Nil);
ShowWindow(hTaskBar, SW_HIDE);
end;
procedure TForm1.Button2Click(Sender: TObject);
var
hTaskBar : THandle;
begin
hTaskbar := FindWindow('Shell_TrayWnd', Nil);
ShowWindow(hTaskBar, SW_SHOWNORMAL);
end;
События
нажатия на системные кнопки
формы (минимизация, закрытие...)
Хотелось бы чтобы при нажатии
на кнопку minimize программа
исчезала из таскбара.
При нажатии на эти кнопки
происходит сообщение WM_SYSCOMMAND,
его то и надо перехватить.
При этом:
uCmdType = wParam; // type of system command requested
xPos = LOWORD(lParam); // horizontal postion, in screen
coordinates
yPos = HIWORD(lParam); // vertical postion, in screen
coordinates
Пример: Type TMain = class(TForm) .... protected Procedure WMGetSysCommand(var Message :TMessage); message WM_SYSCOMMAND; end; ..... //------------------------------------------------------------------------ // Обработка сообщения WM_SYSCOMMAND (перехват минимизации окна) //------------------------------------------------------------------------ Procedure TForm1.WMGetSysCommand(var Message : TMessage) ; Begin IF (Message.wParam = SC_MINIMIZE) Then Form1.Visible:=False Else Inherited; End;
Подключение
и отключение сетевых
дисководов
Есть первый вариант: procedure procname1(param1:type1; param2:type2... и т.д.) external 'dllname.dll' name 'procname_in_dllfile';
Но тут есть один
нюанс: при отсутствии DLL модуля,
либо при отсутствии в нем
указанной процедуры будет
выдаваться ошибка и запуск программы
будет отменен.
Второй вариант:
Type
prc1 = procedure (param1:type1; param2:type2... и т.д.) ;
var
proc1 : prc1;
head : integer ; // или что-то в этом роде
.....
var
p : pointer;
begin
head:= loadlibrary ('DLLFile.DLL'); // загружаем модуль в память
if head=0 then
begin
// Сообщаем о том что модуль не найден
end
else
begin
// Ищем в модуле наши процедуры и функции
p:=getprocaddress ('Имя_Искомой_Процедуры');
// Тут посмотри точно название этой
// функции в хелпе по LoadLibrary.
// Имя_Искомой_Процедуры должно
// быть один в один с именем процедуры
// в библиотеке с учетом регистров.
if p=nil then
begin
// Процедура не найдена
end else proc1:=prc1(p);
end;
К примеру, функция "прослушивает"
каталог на предмет файлов. Если
находит, то создает нить,
которая будет обрабатывать
файл. Потомку надо передать имя
файла, а вот как?
Странный вопрос. Я бы понял,
если бы требовалось передавать
данные во время работы нити. А
так обычно поступают следующим
образом.
В объект нити, происходящий от
TThread дописывают поля. Как
правило, в секцию PRIVATE. Затем
переопределяют конструктор
CREATE, который, принимая
необходимые параметры
заполняет соответствующие
поля. А уже в методе EXECUTE легко
можно пользоваться данными,
переданными ей при его
создании.
Например:
...... TYourThread = class(TTHread) private FFileName: String; protected procedure Execute; overrided; public constructor Create(CreateSuspennded: Boolean; const AFileName: String); end; ..... constructor TYourThread.Create(CreateSuspennded: Boolean; const AFileName: String); begin inherited Create(CreateSuspennded); FFIleName := AFileName; end; procedure TYourThread.Execute; begin try .... if FFileName = ... .... except .... end; end; .... TYourForm = class(TForm) .... private YourThread: TYourThread; procedure LaunchYourThread(const AFileName: String); procedure YourTreadTerminate(Sender: TObject); .... end; .... procedure TYourForm.LaunchYourThread( const AFileName: String); begin YourThread := TYourThread.Create(True, AFileName); YourThread.Onterminate := YourTreadTerminate; YourThread.Resume end; .... procedure TYourForm.YourTreadTerminate(Sender: TObject); begin .... end; .... end.
Имею тег Программа
должна выдавать в браузер
изображение. Прочитать JPeg,
указать ContentType=Image/jpeg и выдать
изображение в SaveToStream умею. Как
сделать тоже самое для файлов
GIF, в особенности анимационных?
Если можно просто перелить
дисковый файл (пусть он хоть
трижды GIF) в Response CGI-програмы, то
как это сделать?
Выдайте из скрипта следующее:
Content-type: image/gif
<содержимое gif-файла>
С помощью Image Editor из комплекта
Delphi3 создаю ресурс содержащий
иконки и добавляю его в свой
проект. Как известно, одна
иконка в ресурсе может иметь
два вида 32х32 и 16х16, которые
отображаются соответственно
при выборе крупных и мелких
значков. Я создаю оба
изображения, но после
компиляции отображается
только 16х16 (при крупных значках
оно растягивается). Как мне
сделать так, чтобы
отображались обе иконки?
1. Такая штука работает только
под Win 95-98, а в NT вторая икона не
учитывается
2. Для редактирования подобных
иконок лучше использовать либо
Borlad Resourse Workshop или Visual C++ (для
иконок годится но для всего
остального, извините!)
uses ShlObj, ComObj, ActiveX;
procedure CreateLink(const PathObj, PathLink, Desc, Param: string);
var
IObject: IUnknown;
SLink: IShellLink;
PFile: IPersistFile;
begin
IObject := CreateComObject(CLSID_ShellLink);
SLink := IObject as IShellLink;
PFile := IObject as IPersistFile;
with SLink do begin
SetArguments(PChar(Param));
SetDescription(PChar(Desc));
SetPath(PChar(PathObj));
end;
PFile.Save(PWChar(WideString(PathLink)), FALSE);
end;
Следующий текст убирает команду закрыть из системного меню и одновременно делает серой кнопку закрыть в заголовке формы:
procedure TForm1.FormCreate(Sender: TObject); var hMenuHandle:HMENU; begin hMenuHandle := GetSystemMenu(Handle, FALSE); IF (hMenuHandle <> 0) THEN DeleteMenu(hMenuHandle, SC_CLOSE, MF_BYCOMMAND); end;