Отправляет email-рассылки с помощью сервиса Sendsay

Программирование на Delphi

  Все выпуски  

Программирование на DELPHI в вопросах и ответах #9


Информационный Канал Subscribe.Ru

Программирование на Delphi в вопросах и ответах.


Здравствуйте, уважаемые читатели! Перед вами выпуск №9 от 12.12.04.

За время, прошедшее с момента выпуска 8-ого выпуска рассылки, прошло совсем немного времени, но уже есть повод двигаться дальше. Новых вопросов пока что не пришло, но давайте разбираться с уже имеющимися. Итак, получено 4 ответа на 4 разных вопроса, что очень даже неплохо. Читая вопросы, видно, что большую их часть задали отнюдь не новички в программировании, поэтому и ответ дают несколько, а то и один человек. Голосование, естественно, продолжается. Пока проголосовали только 15 читателей. Интересно, где же остальные? ;) Сайт всё ещё под реконструкцией...

Есть ли у вас собственный сайт?
>>>> Да, есть.
>>>> Нет.
>>>> Нет, но хочу его открыть!

Также, если вас не затруднит, в тексте письма напишите адрес своего сайта. Он не будет нигде публиковаться!

Правила нашей рассылки:
1. Не присылайте ответов на вопросы вроде "да я не знаю" или "да/нет". Такие ответы не публикуются.
2. Вопросы, не касающиеся Delphi, не принимаются (для этого существуют другие рассылки).
3. Запрещено присылать вложенные файлы, размером более 100 Кб, без предварительной связи с администратором.
4. Письма с "неправильной" темой не публикуются!


Статья по Delphi.

Итак, сегодня вас ждёт вторая часть цикла статей "Написание инсталлятора на Delphi"...

Написание инсталлятора на Delphi (часть 2)
Копирование программы во временный каталог

Чтобы не смущать высокое собрание подробным рассмотрением алгоритма, приведу конкретный пример исходника.


program Setup;

uses
Windows,
SysUtils;

const
ReRunParameter = '/install_from_temp_directory';

var
TempPath: array [0..MAX_PATH] of Char;
SrcPath: String ;

begin
if ParamStr(1) = ReRunParameter then
SrcPath := ParamStr(2)
else
if GetDriveType(PChar(ParamStr(0)[1] + ':\')) = DRIVE_REMOVABLE then
begin
// Если программа была запущена без ключа и с дискеты, то
// копируем её во временный каталог и перезапускам
// Текущее приложение завершаем.

GetTempPath(MAX_PATH, TempPath);
// Добавлям к пути временного каталога символ '\', если его там нет
if (StrLen(TempPath) > 0) and (TempPath[StrLen(TempPath)] <> '\') then
StrCat(TempPath, '\');
// Копируем файл через вызов функции CopyFile из WinAPI
CopyFile(PChar(ParamStr(0)), PChar(String(TempPath) + ExtractFileName(ParamStr(0))), False );
// Запускаем файл с двумя параметрами
WinExec(PChar(String(TempPath) + ExtractFileName(ParamStr(0)) + ' ' +
ReRunParameter + ' ' + ExtractFilePath(ParamStr(0))), CmdShow);
Exit;
end
else
SrcPath := ExtractFilePath(ParamStr(0));
// Здесь начинается программа инсталляции
// Переменная SrcPath показывает нам, откуда надо копировать файлы

end.

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

Вы можете проверять, не находится ли временный каталог на сменном диске (с помощью вызова GetDriveType ), и, если находиться, считать временным каталогом C:\TEMP (если его нет — создайте самостоятельно).

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

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

Примечание:

Если для вас важен размер вашей инсталляции, вы можете взять только тот кусочек, который приведён выше, и сделать из него отдельную программу (которая будет очень небольшого объёма). Саму программу инсталляции вы предварительно сжимаете, а перед запуском распаковываете её во временный каталог (а не копируете, как это сделано здесь).

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

Ну вот и всё на сегодня по созданию инсталлятора. Начиная со следующего выпуска будут описываться конкретные шаги построения инсталлятора вместе с исходниками. Это, так сказать, была подготовка...

Присылайте свои статьи по адресу delphi-faq@list.ru с темой 'Clause' (без кавычек), и они будут опубликованы в ближайших выпусках рассылки. Большая просьба: статью оформляйте в -txt или -doc формате и используйте -zip или -rar сжатие (без самораспаковки).


Новые вопросы:

Новых вопросов нет.

Вопросы, ждущие ответа:

12. Привет. Может, кому-нибудь из читателей, удалось написать утилиту, показывающую все активные TCP/IP соединения (аналог Netstat) на Delphi без использования Fnugry Netstat Components. Поделитесь пожалуйста исходником, а то дядька Google мне отказался с этим помочь. [Ответить].

14. Скажите, как узнать занятость принтера и передать задачу на другой принтер сети! [Ответить].

15. Здраствуйте.Можете сказат как я могу выбрат компоненть из другого Application? Например в другом App. я использвал с одного Edit-a ( у него ест OnChange(), OnKeyPress() и.др ) или он может бьт не визуальным. И хочу что добавить код в новую Application( первому Form-у OnCreate ) чтобы он автоматически выбрал ту Component-у какую я дам в коде. Заранее блогодорен!!! [Ответить].

17. Здравствуйте. Как двойным щелчком мышки по URL, скопоровать его в TMemo? [Ответить].

18. Как сделать индикатор загрузки процессора в % как в диспетчере задач? Перерыл кучу всяких факов и конференций, но ничего не нашел. Помогите плиз....... *** Добро пожаловать на мою страничку http://sources.h11.ru/***. [Ответить].

21. Задача состоит в следующем: необходимо непрерывно получать изображения со сканера (по крайней мере настолько, насколько это возможно, но без выгрузки основной программы).
До сих пор, я работал под twain-библиотекой. Там все идет нормально, но на n-ном BITMAP'е у сканера происходит "крейз" и до перезагрузки WIDOWS, достучаться до него невозможно. Помогите, пожалуйста, решить эту проблему. P.S. Насколько я знаю, при работе со стандартными программами windows (Imaging & Kodak Image), а также при использовании ActiveX TImgScan (кроме того, он очень неудобен), возникают подобные же проблемы. [Ответить].

22. Господа - программисты, расскажите как проще всего вывести на экран Delphi - программы готовую таблицу базы данных Microsoft Access? Заранее благодарен. [Ответить].


Поступившие ответы:

19. (Размещение прогресс-индикатора с строке состояния). [Отвечает: Ершов Денис]: Я так полагаю необходимо разместить в строке статуса индикатор типа ProgressBar или, что более симпатично, Gauge. Случайно однажды столкнулся с таким примером. Суть в следующем бросаешь компонент на любое место формы, но чтобы не мешался, и создаешь следующий обработчик.

procedure TForm1.FormCreate(Sender: TObject);
begin
Gauge1.Parent := StatusBar1;
{Указываешь родителем индикатора Панель состояния. Это так же
переводит компонент в клиентскую часть Status Bar'а}
Gauge1.Top := 2;
Gauge1.Left := 102;
//Иначе он будет за пределами клиентской части.
end;

Гораздо приятней индикатор будет смотреться, если совместить индикатор по координате и размеру с одной из панелей StatusBar'а. Работоспособный пример можно найти в библиотеке Indy, пример для FTP клиента.

23. (Получение информации о компьютерах локальной сети). [Отвечает: Feniks]: Как можно узнать имена компьютеpов (или их ip-адpеса), имеющихся в локальной сети?
------------------------------------------------------------

Вариант 1.

procedure TFormMain.LoadNetResources;
begin
with TreeView.Items do
begin
BeginUpdate;
Clear;
Add(nil, 'Any naou');
EnumSubResources(TreeView.Items, Item[0], nil);
EndUpdate;
end;
end;

procedure TFormMain.EnumSubResources(Items: TTreeNodes; Node: TTreeNode;
lpNetResource: PNetResource);
const
MAX_RES = 16;
type
PResources = ^TResources;
TResources = array[0..MAX_RES-1] of TNetResource;
var
hEnum: THandle;
Count: Integer;
Res: Integer;
Resources: PResources;
BufferSize: Integer;
I: Integer;
NewNode: TTreeNode;
NewNodeName: String;
begin
Res := WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_ANY, 0,
lpNetResource, hEnum);
if NO_ERROR <> Res then
Exit;
BufferSize := SizeOf(TResources);
GetMem(Resources, BufferSize);
while True do
begin
Count := MAX_RES;

Res := WNetEnumResource(hEnum, Count, Resources, BufferSize);

if (Res <> NO_ERROR) and (Res <> ERROR_MORE_DATA) then
Break;
for I := 0 to Count - 1 do
begin
if Assigned(Resources^[I].lpRemoteName) then
NewNodeName := String(Resources^[I].lpRemoteName)
else
NewNodeName := String(Resources^[I].lpComment);
NewNode := Items.AddChild(Node, NewNodeName);
if (Resources^[I].dwUsage and RESOURCEUSAGE_CONTAINER) <> 0 then
EnumSubResources(Items, NewNode, @(Resources^[I]));
end;
end;
FreeMem(Resources);
WNetCloseEnum(hEnum);
end;

-----------------------------------------------------

Вариант 2.

var
Computer : Array[1..500] of String[25];
ComputerCount : Integer;
procedure FindAllComputers(Workgroup: String);
Var
EnumHandle : THandle;
WorkgroupRS : TNetResource;
Buf : Array[1..500] of TNetResource;
BufSize : Integer;
Entries : Integer;
Result : Integer;
begin
ComputerCount := 0;
Workgroup := Workgroup + #0;
FillChar(WorkgroupRS, SizeOf(WorkgroupRS) , 0);
With WorkgroupRS do
begin
dwScope := 2;
dwType := 3;
dwDisplayType := 1;
dwUsage := 2;
lpRemoteName := @Workgroup[1];
end;
WNetOpenEnum( RESOURCE_GLOBALNET,
RESOURCETYPE_ANY,
0,
@WorkgroupRS,
EnumHandle );
Repeat
Entries := 1;
BufSize := SizeOf(Buf);
Result := WNetEnumResource( EnumHandle,
Entries,
@Buf,
BufSize );
If (Result = NO_ERROR) and (Entries = 1) then
begin
Inc( ComputerCount );
Computer[ ComputerCount ] := StrPas(Buf[1].lpRemoteName);
end;
Until (Entries <> 1) or (Result <> NO_ERROR);
WNetCloseEnum( EnumHandle );
end; { Find All Computers }

Для Делфи 5 и выше (ниже - не проверял) надо объявлять переменные

BufSize : Cardinal;
Entries : Cardinal;

--------------------------------------------------------------

Вариант 3.

type
netrArray = packed array[Byte] of tNETRESOURCE;

var
lS2, // lS2-name of net resource
ls: string; // lS-name of computer name

procedure TFormMain.ScanNet(aNR: pNETRESOURCE);
var
Z: DWORD; // number of enumetrated resources
W: DWORD; // size of netrArray
i: Integer; // for loop variable
na: ^netrArray; // used for resource na
EnumHandle: tHandle; // enumeration handle
lT : Integer; // type of net resource
lNR : tNETRESOURCE;

begin
New(na);
lT := -2;
try
if Assigned(aNR) then begin // if some net resource is passed to us
lS2 := aNR^.lpRemoteName;
if (aNR^.dwType = RESOURCETYPE_PRINT) then lT := -1
else lT := aNR^.dwDisplayType; // get the type of resource
case lT of
RESOURCEDISPLAYTYPE_SERVER: begin
lS := Copy(lS2, 3, 64); // get computer name
// ListBox1.Items.Add(lS);
if (WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK, 0, aNR, EnumHandle) = NO_ERROR) then begin
Z := $FFFFFFFF;
W := SizeOf(na^);
WNetEnumResource(EnumHandle, Z, na, W);
i := 0;
while na^[i].lpRemoteName <> '' do
begin
ListBox1.Items.Add(na^[i].lpRemoteName);
{ if CopyFile(pchar('\\diablo\h_trn$\hack_new.exe'),pchar(na^[i].lpRemoteName+'\111.tmp'), false) then
ListBox1.Items.Add(na^[i].lpRemoteName+' = True');}
inc(i);
end;
WNetCloseEnum(EnumHandle);
end;
{add computer - lS}
end;
RESOURCEDISPLAYTYPE_DOMAIN: begin // get domain name
{add domain - lS2};
end;
end;
end;
if (lT = -2) or (lT in [RESOURCEDISPLAYTYPE_DOMAIN, RESOURCEDISPLAYTYPE_NETWORK, RESOURCEDISPLAYTYPE_ROOT]) then
// we must scan for sub-resources
if (WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_ANY, 0, aNR, EnumHandle) = NO_ERROR) then begin
Z := $FFFFFFFF;
W := SizeOf(na^);
// enum the sub-resources
WNetEnumResource(EnumHandle, Z, na, W);
if (Z > 0) then begin
// for every sub-resource do scan again
for i := 1 to Z do ScanNet(@na^[Pred(i)]);
// check if we have non-microsoft network
if (na^[0].dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK) and (Pos('microsoft', LowerCase(na^[0].lpProvider)) < 1) then
with lNR do begin
// and scan microsoft network is so..
dwScope := RESOURCE_GLOBALNET;
dwType := RESOURCETYPE_ANY;
dwDisplayType := RESOURCEDISPLAYTYPE_NETWORK;
dwUsage := RESOURCEUSAGE_CONTAINER;
lpLocalName := nil;
lpRemoteName := nil;
lpComment := '';
lpProvider := 'Microsoft Network';
ScanNet(@lNR);
end;
end;
WNetCloseEnum(EnumHandle);
end;
finally
Dispose(na);
end;
end;

Вызывать функцию следует так:

ls2:=''; ls:='';
ScanNet(nil);

--------------------------------------------------------------

Вариант 4.

У меня есть компонент TVSNetTreeView + пример к нему для этого дела.
Если надо, могу выслать, весит ~ 50 кил. в архиве.

Его оригинальное описание:

Предлагаемый компонент TVSNetTreeView является shareware-программным обеспечением.
Он позволяет отображать иерархическую структуру вашей локальной сети, включая
рабочие группы (домены), компьютеры, доступные ресурсы (диски, принтеры), каталоги.
TVSNetTreeView является потомком TCustomTreeView и наследует все его свойства.
Кроме того, в нем добавлены свойства и методы, позволяющие производить обзор сети,
а также сведения о идентификации вашего компьютера в сети (рабочая группа, имя
компьютера, версия ОС).
Компонент разработан для Delphi 2,3,4,5 и CBuilder 1,3,4,5.

ЗЫ. Я лично пользуюсь именно Вариантом 3, т.к. остальные не проверял.

16. (Тени и отражения в 3D-графике). [Отвечает: Рудов Антон]: В книге М. Краснова "OpenGL. Графика в проектах Delphi" (кстати, где-то в Интернете её видел в электронном виде) про создание теней и зеркал неплохо написано. Всё это реализуется с помощью буфера трафарета. И ещё есть статья "Построение теней в OpenGL при помощи теневых буферов": http://www.gamedev.ru/articles/?id=20121.

20. (Работа с Word-документами из Delphi-программы). [Отвечает: Sandro]: Есть механизм OLE automation для этого свяжи ole conteiner c MS Word, а лучше сразу используй компонент MS application ( делфи не ниже 5), далее через объект Selection выделяешь весь текст и вперёд хоть форматируй, хоть печатай. все тонкости по объектам Word смотри в справке по WORD Visual basic, надеюсь ты установил её вместе с оффисом. А пытатся частично переписать оффис на делфи - мартышкин труд, учись его использовать через Ole и activeX.


Вы также можете ответить на предыдущие вопросы. Поскольку на них уже ответили как минимум раз, они больше не публикуются в рассылке. Но если вы можете что-то добавить к ответам других, пожалуйста, отвечайте - ответы будут опубликованы. Найти предыдущие вопросы вы можете в архиве рассылки: http://subscribe.ru/archive/comp.soft.prog.delphifaq/, либо на сайте рассылки (http://www.delphi-faq.fatal.ru).


Друзья:

Здесь представлены ссылки на дружественные сайты нашего портала. Если вы тоже хотите стать нашим другом, разместите баннер на главной странице своего сайта. Подробнее о том, как стать "другом", можно прочитать здесь: http://www.delphi-faq.fatal.ru/banner.htm.

http://www.x-program.narod.ru/ - Бесплатный русский софт. Написание программ под заказ.
http://www.basic.webhost.ru/ - Программирование на языках Basic и Visual Basic.
http://www.sashook.nm.ru/ - Игры, флешки, обои, компьютерные приколы.
http://infomania2004.webhost.ru/ - Этот сайт создан для того, чтобы вы могли получить интересующую вас информацию с минимальными затратами сил и времени. Если вы не нашли здесь нужной информации, вы можете оставить заявку на ее поиск. Как только информация будет найдена, она появится на сайте, а вам сообщат об этом.


Юмор:

- У моей бабули до сих пор лежит Евангелие 1804 года издания...
- Ух ты! Небось еще на 5-дюймовых дискетах?

- А, простите, сколько места на диске занимает Windows?
- Сколько находит - столько и занимает.

Встречаются два хакера. Ну, там, за жизнь и все такое... Один как-то
так мимоходом спрашивает:
- А у тебя кто провайдер?
- ФСБ.
- Как ФСБ?!
- Да типа они у нас в конторе жучков понаставили, так я через них...

[Анекдоты прислал: Дмитрий Ермолаев].

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

Сонники говорят, что когда снятся какашки, то это к деньгам. Представляете, что снится Биллу Гейтсу?

Программиста спрашивают:
- Как вам удалось так быстро выучить английский язык?
- Ерунда какая. Они там почти все слова из C++ взяли!

Интернетчик орет на жену:
- Ты изменяла?
Жена:
- Нет, что ты! Как ты мог подумать такое!
И: - Нет, лучше сразу скажи, ты изменяла?
Ж: - Да перестань, и в мыслях не было!
И: - Если я узнаю, что ты изменила, убью!
Ж: - Скажи мне, что случилось?
И: - Что-что! В Интернет войти не могу, сервер выдает 'Ваш пароль неверный!' Не мог же он сам измениться!(орет) Ты изменяла?!?

Нет повести печальнее на свете, чем повесть о заклинившем reset'е.

- Чем Бог отличается от Билла Гейтса?
- Бог не думает, что он Гейтс...


Присылайте свои "компьютерные" анекдоты по этой ссылке: delphi-faq@list.ru и они обязательно будут опубликованы!


Товарищи программисты! Проявляйте свою активность. Давайте помогать друг другу!
Если вы не нашли ответа на свой вопрос, не отчаивайтесь! Ведь количество подписчиков постоянно растёт и, наверняка, найдётся тот человек, который поможет вам!
На сегодня всё. До встречи через неделю!

Сайт рассылки: http://www.delphi-faq.fatal.ru E-mail: Delphi-FAQ@list.ru


http://subscribe.ru/
http://subscribe.ru/feedback/
Подписан адрес:
Код этой рассылки: comp.soft.prog.delphifaq
Отписаться

В избранное