Советы для написания программ-инсталляторов Советы для написания программ-инсталляторов
Регистрация программ в меню Пуск 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');
// Устанавливаем связь по DDE
DDEClient.OpenLink;
// Подготавливаем ASCIIZ строку
strPCopy(macrocmd,'['+Command+']');
ProgmanCommand :=DDEClient.ExecuteMacro(MacroCmd,false);
// Закрываем связь по DDE
DDEClient.CloseLink;
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\');
Как скопировать все файлы вместе с подкаталогами |
*
| *
|
| |
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
// Открыли библиотеку User
hInstUser := LoadLibrary('USER');
LoadString(hInstUser, 514, Buffer, 30);
// Имя пользователя
LabelUserName.Caption := StrPas(Buffer);
LoadString(hInstUser, 515, Buffer, 30);
FreeLibrary(hInstUser);
// Компания
LabelCompName.Caption := StrPas(Buffer);
WinVer := GetVersion;
// Версия Windows
LabelWinVer.Caption := Format('Windows %u.%.2u',
[LoByte(LoWord(WinVer)), HiByte(LoWord(WinVer))]);
// Версия DOS
LabelDosVer.Caption := Format('DOS %u.%.2u',
[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:\ARHIVERS\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;
Вполне очевидно, что вместо переименования можно запускать программу с различными ключами,
например /INSTALL и /UNINSTALL. Я очень часто пользуюсь таким приемом, особенно в тех
случаях, когда проект состоит из одного файла
Включение и выключение устройств ввода/вывода из программы на Delphi |
*
| *
|
| |
Решение для Delphi 1
Иногда может возникнуть необходимость в выключении на время устройств ввода
- клавиатуры и мыши. Например, это неплохо сделать на время выполнения кода
системы защиты от копирования, в играх, или в качестве "наказания"
при запуске программы по истечению срока ее бесплатного использования ... .
Однако наилучшее ее применение - отключение клавиатуры и мыши на время работы
демонстрационки, основанной на воспроизведении записанных заранее перемещений
мышки и клавиатурного ввода. Это элементарно сделать при помощи API:
EnableHardwareInput(Enable:boolean): boolean;
Enable - требуемое состояние устройств ввода (True - включены, false - выключены).
Если ввод заблокирован, то его можно разблокировать вручную - нажать Ctrl+Alt+Del,
при появлении меню "Завершение работы программы" ввод разблокируется.
Еще раз подчеркиваю, что это работает только в 16-ти разрядной D1. Исследования в
отладчике показали, что функция по сути ничего не делает, только устанавливает некий
флаг в памяти, явно отвечающий за блокировку клавиатуры/мыши.
Решение для Delphi 2+
По сложно объяснимым причинам фирма Microsoft удалила функцию EnableHardwareInput
из 32-рарядных реализаций Windows и, следовательно, EnableHardwareInput стала
недоступной в D2+. Однако научные изыскания (в ядре Windows при помощи отладчика)
помогли мне найти ее аналог. Он не документирован в справке Borland, но кажется есть
в последнем MSDN
Procedure BlockInput(ABlockInput : boolean); stdcall; external 'USER32.DLL';
Вызов данной функции c параметром true блокирует клавиатуру и мышь, с параметром
false - разблокирует). Как и в случае с EnableHardwareInput блокировка снимается при
нажатии Ctrl+Alt+Del.
Как программно создать ярлык? |
*
| *
|
| |
Создать ярлык можно при помощи данной функции:
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;
Наиболее распространенная задача - создание ярлыка на рабочем столе. Для
этого необходимо определить полный путь к системной папке
Windows Desctop через реестр и передать его
в качестве параметра PathLink.
Оповещение приложения (или всей системы) о изменении WIN.INI |
*
| *
|
| |
При изменении WIN.INI (например, изменении настроек хранителя экрана) необходимо уведомить
систему (или конкретное приложение) о том, что WIN.INI изменен. Это можно сделать при
помощи передачи приложению сообщения WM_WININICHANGE
SendMessage(HANDLE, WM_WININICHANGE, 0, PCHAR(SECT_NAME));
При этом HANDLE равен или HANDLE приложения, или HWND_BROADCAST - рассылка всем приложениям.
SECT_NAME задает имя секции WIN.INI, в которой произошли изменения. Если указать пустую строку
(#0), то считается, что изменялись все секции, что естественно увеличивает время обработки и нагрузку
на систему
Как удалить самого себя ?? |
*
| *
|
| |
Широко известна проблема, связанная с тем, что невозможно удалить запущенный
EXE файл. Следовательно, вознакает проблема при написании деинсталлятора - он
удалит файлы программы, но кто удалит его (сам себя он удалить не может). На
самом деле у данной проблемы есть два решения:
Решение при помощи BAT файла
1. Создаем в любой папке BAT файл del_prg.bat следующего содержания
@echo off
:del_loop
del [полное имя и путь к EXE файлу]
if exist [полное имя и путь к EXE файлу] goto del_loop
del [полное имя bat файла]
2. Запускаем его
3. Завершаем работу EXE файла. BAT файл будет крутится по циклу до тех пор,
пока ему не удатся удалить EXE файл. Затем он самоуничтожится - этому ничто не
препятствует, т.к. bat файлыв могут стирать сами себя без проблем
Решение при помощи реестра
1. Создаем ключ в ветви реестра HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnce
с любым именем, например del_self и значением del [полное имя и путь к EXE файлу]
2. Просим пользователя перезагрузить компьютер (или делаем это принудительно). Команда из
ключа сработает при следующей загрузке и будет автоматически удалена из реестра
Как проверить, откуда идет инсталляция (с дискеты, HDD, CD или сети) |
*
| *
|
| |
Данный вопрос бывает актуален при написании инсталлятора - в ряде случаев
необходимо разрешать инсталляцию только с CD диска или блокировать запуск
инсталлятора из сети.
Проблема решается следующим образом
1. При помощи ExtractFileDrive(Application.ExeName) определяем букву диска, с
которого запущена программа (возвращаемое значение содержит букву с двоеточием
после него, например "E:")
2. При помощи примера, описанного в разделе "Железо\Как определить тип диска" определяем
тип диска и принимаем решение, допустим ли запуск
Программная перезагрузка Windows |
*
| *
|
| |
Программная презагрузка Windows возможна при помощи функции API ExitWindows:
function ExitWindows(dwReserved: DWORD; Code: Word): BOOL;
Первый и второй параметр зарезервированы и должны быть равны 0. В Delphi6 вместо
вызова функции API вызывается следующий код:
function ExitWindows(dwReserved: DWORD; Code: Word): BOOL;
begin
Result := ExitWindowsEx(EWX_LOGOFF, 0);
end;
При этом функция ExitWindowsEx имеет вид:
function ExitWindowsEx(uFlags: UINT; dwReserved: DWORD): BOOL; stdcall;
Второй параметр заверзервирован, а вот первый определяет реакцию на вызов
функции и содержит битовые флаги:
- EWX_FORCE - форсированный режим перезагрузки. Система не передает
приложениям сообщения WM_QUERYENDSESSION и WM_ENDSESSION для уведомления
о необходимости завершения работы. В результате приложения могут потерять данные
из-за неожиданного завершения их работы
- EWX_LOGOFF - завершение всех процессов данного контекста безопасности и
завершение сессии текущего пользователя
- EWX_POWEROFF - завершение работы системы и выключение питания (под NT необходима
привилегия SE_SHUTDOWN_NAME )
- EWX_REBOOT - Завершение работы системы и перезагрузка (под NT необходима
привилегия SE_SHUTDOWN_NAME )
- EWX_SHUTDOWN - Завершение работы системы до момента, позволяющего безопасно
выключить питание системы. Все дисковые буфера сбрасываются на диск, все процессы
завершаются (под NT необходима привилегия SE_SHUTDOWN_NAME )
Пример вызова, приводящего к немедленному завершению работы системы:
ExitWindowsEx(EEWX_FORCE or EWX_POWEROFF or EWX_SHUTDOWN, 0);
© Зайцев Олег, "Программирование на Delphi - обмен опытом" 1999-2004. При использовании любых материалов данного сайта
необходимо указывать источник информации. Дата обновления: 22.11.2004. Сайт размещен на хостинге AGAVA - Хостинг от AGAVA.ru