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

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

  Все выпуски  

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


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

Программирование на DELPHI
 
Разделы рассылки:
Разделы сайта:
Выпуск #26 (14 мая 2005 г.)


Доброго времени суток , уважаемые читатели!

Ничего говорить не буду :) Очередной укороченный выпуск. Сайт продолжает переезд.


Количество подписчиков: 2539.


Читатели, лидирующие по количеству баллов:

Место
Имя
Кол-во баллов
Место
Имя
Кол-во баллов
Таблица временно закрыта.


Основные правила нашей рассылки:

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


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


Вопрос #124. Автор вопроса: Андрей. Вопрос отправлен: 04.05.2005 10:31. Вопрос:

Здравствуйте! У меня Delphi 7, где мне найти QuickReport?

[Ответить на вопрос]. Ответ ожидается до 30.05.2005 10:31:00.


Вопрос #125. Автор вопроса: Денис. Вопрос отправлен: 07.05.2005 21:39. Вопрос:

Что такое записной тип данных?

[Ответить на вопрос]. Ответ ожидается до 30.05.2005 21:39:00.


Вопрос #126. Автор вопроса: Вениамин. Вопрос отправлен: 06.05.2005 14:37. Вопрос:

Есть текстовый документ и программа с 5-тью Label.
В текстовом документе содержится инфа:

+ВОПРОС1
ответ1
_ответ2
ответ3
ответ4
+ВОПРОС2
ответ1
ответ2
_ответ3
ответ4

Надо, чтобы при открытии программы Label1 превращался в вопрос1, Label2 в ответ1 и т.д. до Label5, который превращается в ответ4. Т.е. программа должна выбрать из блокнота ЛЮБУЮ строку, начинающуюся на \"+\" (пометка вопроса) и предоставить варианты ответов, задав переменной PRAVILNO значение 1, 2, 3 или 4. Перед каким ответом стоит \"_\", тот номер и будет значением переменной (Это будет правильный ответ).
P.S. Label правильного ответа не должен начинаться с \"_\"! (все варианты выходят одинаково без \"_\")

[Ответить на вопрос]. Ответ ожидается до 30.05.2005 14:37:00.

 


Ответы на вопросы.

104. (Проблема с путями при установке компонентов). Полный текст вопроса:
Довольно уверено создаю компоненты, но практически у всех есть одна проблема. При компиляции программы с добавленным моим компонентом компилятор не находит модуль компонента. Проблема решается, если указать в опциях проекта каталог с исходниками компонента в качестве пути поиска. Есть ли другое решение? И как сделать, чтобы при добавлении компонента в программу автоматически добавился не только модуль компонента, но и другие модули пакета?

[Отвечает: Акишин Андрей Владимирович, 04.05.2005 09:40]: Можно попробовать скопировать компоненты в папку с проектом, тогда Delphi обязательно их найдёт.

[Отвечает: Yurchik, 06.05.2005 02:47]: В первую очередь, Дельфи ищет все подключаемые файлы в папке <установленная Дельфи>\LIB. И именно туда и нужно скопировать все необходимые файлы нового компонента. Мною практическим способом установлено, что необходимыми являются такие файлы: *.dcu *.dfm *.res Может есть еще какие-то типы, но я с ними не сталкивался. Для удобства я создал файлик copy2lib.bat, и при создании нового компонента я добавляю его в папку с этим компонентом. Вот его содержание (Дельфи у меня установлена в Program Files\Borland\Delphi6):
copy *.dcu "%programfiles%\Borland\Delphi6\Lib"
copy *.dfm "%programfiles%\Borland\Delphi6\Lib"
copy *.res "%programfiles%\Borland\Delphi6\Lib"
pause

[Отвечает: Сергей Азачем , 10.05.2005 16:12]: Есть несколько вариантов. 1. Создавать компонент используя IDE: Component -> New Component. В этом случае нужные пути будут прописаны Delphi "автоматом". 2. Указать каталог с откомпилированным компонентом Tools -> Environment Options Закладка Library, поле Library path В нем нужно указать путь к файлам DCU. 3. Если использовались опции по умолчанию, то файлы DCU нужно скопировать в каталог %DELPHI%\Projects\Bpl (как правило "С:\Program Files\Borland\Delphi5Projects\Bpl\". Если комонент использует формы или дополнительные ресурсы, то соответствующие файлы нужно скопировать в каталог с файлами DCU.

106. (OnExit в ячейках StringGrid). Полный текст вопроса:
Можно ли в компоненте StringGrid отлавливать событие onExit для ячеек и просматривать перед потерей фокуса, было ли изменено содержимое данной ячейки?

[Отвечает: Dasha, 04.05.2005 17:05]: Предлагаю использовать событие OnSelectSell, происходит, когда меняется выделенная ячейка. При выделении сохранять номер и содержимое в какие-нибудь переменные, опять же при переходе сначала проверять соответствие ячейки под сохраненным номером сохраненному содержимому.

[Отвечает: Feniks, 05.05.2005 11:08]: На счет StringGrid точно сказать не могу, но зато могу посоветовать вместо него использовать компонент TVirtualStringTree. Этот компонет сочетает в себе такие стандартные компоненты, как TStringGrid, TTreeView, TListView. У него очень большой список событий, включая те, которые Вам нужны. И делается это очень легко. Компонент фриварный, с сорцами, ставится на Delphi 5 - Delphi 2005. А так же на C++Builder 5 и 6. И содержит Хелп и примеры. Родной сайт: www.delphi-gems.com. Там же есть и готовые Демо-проекты. Или же можно попробовать порытся в родительских классах компонента StringGrid. Возможно у какого-то его родителя есть такие события, но они не "зашарены" для своих детей, т.е. у родителя есть свойство и оно объявлено в секции Published, а у его детей это свойство не объявлено, таким образом, оно не видимо у детей. В этом случае, лучше всего, надо создать новый компонент от StringGrid и в этой секции объявить нужное свойство, поле или функцию.

[Отвечает: Андрей Лучников, 12.05.2005 08:20]: Насколько я понял - нет. Я из положения вышел таким образом: в OnSelectCell (в конце кода обрабочика) запоминаю текущую ячейку (записываю в глобальные переменные ARow,ACol и значение). Соответсвенно, вначале этого события, проверяю на условие предыдущую ячейку.

107. (Значок диаметра). Полный текст вопроса:
Друзья! Помогите в поле Edit вывести значок диаметра (перечёркнутая окружность). Заранее благодарен всем, кто откликнется.

[Отвечает: Тихонов Михаил, 04.05.2005 08:02]: Установить в фонте набор символов 'Baltic' для Edita'a и написать например процедуру procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
if Key = 'D' then Key := Chr(168);
if Key = 'd' then Key := Chr(168); end;

Насколько мне помнится, в технической документации диаметр обозначается буквой D. Т. е. например труба D 30 мм или d 30 мм.

[Отвечает: Dasha, 04.05.2005 17:14]: Сделай шрифт Symbol, в нем латинская f (маленькая) становится похожа на знак диаметра.

111. (Исходник чата для локальной сети). Полный текст вопроса:
Нужен исходник чата для локальной сети. Простенький и понятный.

[Отвечает: Садовников Владимир, 04.05.2005 07:33]: Посмотри Delphi\Examples\Internet. Там есть как раз пример чата с использованием всего лишь двух компонентов со вкладки Internet. Эти компоненты годятся как для локальной, так и для глобальной сети.

[Отвечает: Dasha, 04.05.2005 18:46]: Если бы не необходимость отслеживать присутствующих в чате, программа занимала бы несколько строк, а так получилась немного сложнее. //От ведущего: чат выслан автору вопроса, но скоро появится и на сайте.

[Отвечает: magicSasha, 05.05.2005 00:26]: Вот ссылка на исходник чата, котрый я когда то писал:
http://sun-rock.narod.ru/files/delphi/chat_source.rar (Delphi 7; Размер 19Kb).

[Отвечает: Evgeshka Vasilkov, 11.05.2005 22:15]: Уверен что ответ вы не опубликуете, но передайте вопрошающему, что проще чата, который есть в поставке delphi в $(delphi)\Demos\Internet\Chat\ найти нельзя.

121. (Работа с датами). Полный текст вопроса:
Всем привет! Подскажите пожалуйста, как в программе показывать, сколько осталось дней до определенной даты (например, до Нового Года)?

[Отвечает: mvp, 03.05.2005 20:27]:
var s : char
//-------------
s := DateSeparator;
DateSeparator := '.';
Label1.caption := 'До Нового Года осталось ' + intToStr(trunc(strToDate('01.01' + intToStr(currentYear + 1)) - now)) + ' дня (ей)'; DateSeparator := s;
//-------------
А ещё можно навесить таймер с периодом в минуту, например, и при каждом срабатывании посмотреть, не начало ли часа. Если да, то перевести период срабатывания на час, вместо минуты. И проверить, не является ли время началом нового дня. Если да, - пересчитать.

[Отвечает: Антон, 04.05.2005 10:16]:
procedure TForm1.Button1Click(Sender: TObject);
const
mj: array[1..12] of Integer=(31,28,31,30,31,30,31,31,30,31,30,31);
var d, m, y: word;
d1, m1, y1: word;
days1, days2, add, month, i: integer;
begin
DecodeDate(now, y, m, d); //Текущая дата
DecodeDate(DateTimePicker1.Date, y1, m1, d1); //Дата до которой нужно
посчитать кол-во дней

if ((y mod 4 = 0) and ((y mod 100<>0) or (y mod 400=0))) then
add:=1 //дополнительный день в феврале (проверка високосности года у
текущей даты)
else
add:=0;

month:=0;
for i:=1 to m-1 do
begin
if i=2 then month:=month+add; //Кол-во дней в феврале
month:=month+mj[i]
end;
days1:=d+month; //Кол-во дней с 01.01 до текщей даты

month:=0;
for i:=1 to m1-1 do
begin
if i=2 then month:=month+add; //Кол-во дней в феврале
month:=month+mj[i]
end;
days2:=d1+month; //Кол-во дней с 01.01 до заданной даты

Label1.Caption:='Прошло дней после Нового года до текущей даты
'+intToStr(days1);
Label2.Caption:='Прошло дней после Нового года до заданной даты
'+intToStr(days2);
Label3.Caption:='Осталось дней до заданной даты '+intToStr(days2-days1);

end;

Код работает только для текущего года т.е. текущая и заданная даты должны быть в одном и том же году. Суть заключается в том, что начальная (текущая) и заданная даты переводятся в кол-во дней, а потом считаются... Можно, конечно сделать специальную процедурку, но я не хочу - сделай сам ;-)

[Отвечает: Dasha, 04.05.2005 19:06]: Нужен юнит DateUtils.
procedure TForm1.FormCreate(Sender: TObject);
var Days: integer;
begin
Days:=DaysBetween(Now,EncodeDate(2005,12,31));
Label1.Caption:=IntToStr(Days);
end;

[Отвечает: Feniks, 05.05.2005 11:10]: С датой и временем можно оперировать как с обычным Integer-ом. И следовательно, можно из одной даты вычесть другую. Все это есть в Хелпе у Delphi. Там же есть и функции для работы с Датой и Временем (см. DateToStr, StrToDate, Date, Now). Поэтому, если из 31/12/05 вычесть текущую дату (функция Date), то можно получить искомый результат. Если Вы плохо дружите с англ. языком, вот Вам пример:

function DaysLeft(pDate1, pDate2 : TDate) : Integer;
var
n1, n2,
d1, d2,
m1, m2,
y1, y2 : Word;

begin
DecodeDate(pDate1, y1, m1, d1);
DecodeDate(pDate2, y2, m2, d2);
if m1 > 2 then
m1 := m1 + 1
else
begin
m1 := m1 + 13;
y1 := y1 - 1;
end;
n1 := 36525 * y1 div 100 + 306 * m1 div 10 + d1;
if m2 > 2 then
m2 := m2 + 1
else
begin
m2 := m2 + 13;
y2 := y2 - 1;
end;
n2 := 36525 * y2 div 100 + 306 * m2 div 10 + d2;
Result := n2 - n1;
end;

[Отвечает: Yurchik, 07.05.2005 00:23]: Используйте функцию DaysBetween из модуля DateUtils. Функции EncodeDate и TryEncodeDate возвращают значение TDateTime, которое соответствует указанному Году, Месяцу и Дню. Вот пример, показывающий, сколько осталось дней до Нового Года:

var
dl: integer; // искомое количество дней
ny: TDateTime; // дата ближайшего Нового Года
y, m, d: word;
begin
DecodeDate(Now, y, m, d); // распознаем текущую дату
if (m = 1) and (d = 1) then
dl:= 0 // Новый Год сегодня!
else
begin
if TryEncodeDate(y+1, 1, 1, ny) then // вычисляем дату ближайшего Нового Года
dl:= DaysBetween(Now, ny) // подсчитываем количество дней
else
dl:= -1; // произошла ошибка!
end;
end;

[Отвечает: Evgeshka Vasilkov, 07.05.2005 00:23]: Если вспомнить что тип tDateTime является типом Double, то вычитание из одной даты другой должно давать float число, в котором целая часть есть количество дней.
form1.caption:=format('осталось %d',[trunc(EncodeDate(2006,1,1)-date())]);

115. (Таймер). Полный текст вопроса:
Здравствуйте! Помогите, пожалуйста, написать процедуру, которая вставляет в программу таймер. Программа следующая: В форме меняются атрибуты элементов при нажатии на клавишу «ОК». Как можно ограничить интервалы между сменой формы? То есть, если за определенный временной промежуток не нажата кнопка «OK», то форма меняется автоматически. Можно ли вставить в форму индикацию этого времени, например, 30 точек, которые через каждую секунду исчезают друг за другом (соответственно переключение формы происходит сразу после исчезновения последней точки). Спасибо.

[Отвечает: Eujene Kuklev, 04.05.2005 04:58]: // Initializes the timer used to calculate the FPS
SetTimer(glh_Wnd, fTIMER, fINTERVAL, nil);
function WndProc(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
begin
case (Msg) of
WM_TIMER :
begin // Calculate time
end;
end;

[Отвечает: Dasha, 04.05.2005 18:56]: Можно поставить, например, ProgressBar, поставить в нем Max:=30; Потом поставить таймер, в нем по умолчанию интервал 1 сек. Тут количество полосочек ProgressBar-а не уменьшается, а наоборот увеличивается, можно поставить и наоборот.

procedure TForm1.Timer1Timer(Sender: TObject);
begin
if ProgressBar1.Position<>30 then
ProgressBar1.Position:=ProgressBar1.Position+1
else
begin
ProgressBar1.Position:=0;
// меняем атрибуты элементов
end;
end;

procedure TForm1.Button1Click(Sender: TObject); //это_на_нажатие_кнопки
begin
ProgressBar1.Position:=0;
//меняем атрибуты элементов
end;

[Отвечает: Садовников Владимир, 04.05.2005 20:44]: Пихаешь таймер на форму, задаёшь ему первоначальный счётчик (например, в свойстве OnCreate) и запускаешь таймер. Потом в обработчике таймера пишешь одну строку: OnYourButtonClick(Sender); В обработчике OnYourButtonClick снова выставляешь таймер при выходе (если надо). Всё будет так, как будто бы ты через определённые промежутки времени нажимал на кнопку. Чтобы добавить ещё и "точки", то усложни обработчик OnTimer: уменьши промежуток, введи счётчик срабатываний, и после 30-го вызывай OnYourButtonClick.

[Отвечает: AgentAniskin, 05.05.2005 09:26]: 1.Поставь на форму компонент Label, в его caption запиши 30 точек (сколько точек - столько секунд) без пробелов и сделай побольше шрифт. 2. Помести компонент Timer, в св-во Interval поставь 1000 (1 секунда). св-во Enabled - False; 3. В твоей кнопке OK после выполняемых действий включи Timer: Timer1.Enabled:=True; 4. В событие ONTimer таймера напиши:

procedure TForm1.Timer1Timer(Sender: TObject);
begin
Label1.Caption:=Copy(Label1.Caption, 1, StrLen(PChar(Label1.Caption))-1);
if StrLen(PChar(Label1.Caption))=0 then
begin
//прошло 30 секунд - точки исчезли
Timer1.Enabled:=False;
//
твои действия после истечения времени
//
end else
Timer1.Enabled:=True;
end;

[Отвечает: Feniks, 05.05.2005 11:09]: Все довольно просто... Кладете компонент TTimer на главную форму Вашего проекта. В его свойствах указываете интервал, он там в миллисекундах - 1000 = 1 сек. При появлении на экране Вашей формы включаете таймер (Enabled = True). Пишите обработчик события OnTimer этого таймера, где закрываете форму и показываете следующую. И так далее... Если надо более конкретно, тогда надо исходить из поставленной задачи... Присылайте сорцы, посмотрим... :)

[Отвечает: Evgeshka Vasilkov, 11.05.2005 22:21]: Это проще сделать стандартным компонентом tTimer: (пишу по памяти)

tmr:tTimer;
procedure form1.RemoveDot();
begin
dec(dotcount);//уменьшим количество точек
if dotcount<0 then begin
tmr.free;
do_something();
end else
... ; //перерисуем точки

end;
procedure form1.btnClik(sender:tobject);
tmr:=tTimer.create;
tmr.interval=1000;//интервал срабатывания 1 cек.
tmr.onTimer=removeDot;
tmr.enabled:=true;
end;

120. (Анимация). Полный текст вопроса:
Здравствуйте! Подскажите, пожалуйста, можно ли средствами Delphi сделать программу, в которой на экране будут появляться элементы (скажем, Label) с задержкой или мигать?

[Отвечает: Антон, 04.05.2005 09:27]: Как вариант, можно сделать так:
procedure TForm1.FormCreate(Sender: TObject);
begin
Label1.Visible:=False;
Timer1.Interval:=500;
Timer1.Enabled:=True;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
Label1.Visible:= not Label1.Visible;
end;
Через 0,5 сек. (Timer1.Interval:=500;) на форме появляется Лабел1, а потом через этот же интервал времени пропадает. И так далее до бесконечности. Для корректной работы, перед компиляцией проекта на форму желательно поместить компоненты TLabel и TTimer :-)

[Отвечает: AgentAniskin, 04.05.2005 17:18]: Здраствуйте. Такой простенький вариант МИГАНИЯ: Поставьте на форму 2 таймера c одинаковым интервалом . У первого (Timer1) enabled ставим в true, у второго - False; При выключении первого включается второй и т.д. события OnTimer:

procedure TForm1.Timer1Timer(Sender: TObject);
begin
Label1.Color:=clred;
Timer1.Enabled:=False;
Timer2.Enabled:=True;
end;

procedure TForm1.Timer2Timer(Sender: TObject);
begin
Label1.Color:=clYellow;
Timer2.Enabled:=False;
Timer1.Enabled:=True;
end;

[Отвечает: Dasha, 04.05.2005 19:00]: Чтобы компонент исчез, нужно сделать например: Label1.Hide, чтобы потом показать Label1.Show. Чтобы мигало, просто запустить это в цикле. Чтобы появлялось с задержкой можно перед запуском сделать его невидимым, а потом перед Label1.Show написать Sleep(кол-во милисекунд).

[Отвечает: Садовников Владимир, 04.05.2005 20:46]: Конечно, можно. На то есть класс TThread и компонент TTimer, а также событие OnIdle компонента ApplicationEvents. Все они позволяют с течением времени что-то менять. Остаётся только понять, что надо делать дальше (в плане дизайна).

[Отвечает: Yurchik, 07.05.2005 00:41]: Конечно можно!!! Смотри пример:

var
flag: Boolean; // признак мигания

procedure TForm1.FormCreate(Sender: TObject);
begin
flag:= false; // инициализация флага
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
flag:= not flag; // нажатие на кнопку разрешает/запрещает мигание
Timer1.Enabled:= flag; // запускаем либо останавливаем таймер
if not flag then
Label1.Visible:= true; // показываем метку, если мигание запрещено
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
Label1.Visible:= not Label1.Visible; // показываем/скрываем метку
Timer1.Enabled:= flag;
end;

Если что-то будет неясно, пиши мне на мыло, с радостью помогу :)

[Отвечает: Feniks, 10.05.2005 14:44]: Только что похожий вопрос проскочил в одной конфе...

Вариант 1.
procedure WriteDC(s: string);
var
c: TCanvas;
begin
c := TCanvas.Create;
c.Brush.Color := clBlue;
c.Font.color := clYellow;
c.Font.name := 'Fixedsys';
c.Handle := GetDC(GetWindow(GetDesktopWindow, GW_OWNER));
c.TextOut(screen.Width - c.TextWidth(s) - 2, screen.Height - 43, s);
c.free;
end;

Вариант 2.
program Name_on_screen;
{$APPTYPE CONSOLE}
uses
Windows, Graphics, SysUtils;

procedure Name_on_screen;
const
name='Delphi World';
var
ScreenDC: hDC;
begin
ScreenDC := GetDC(0);
settextcolor(screendc,clred); // Устанавливаем цвет текста, в данном случае
// clRed - красный.
SetBkMode(screendc, TRANSPARENT); // Рисуем на прозрачном фоне,
// без этой строчки фон - белый.
textout(screendc,100,100,name, Length(name)); // Устанавливаем
координаты вывода и длину строки
ReleaseDC(0,ScreenDC);
end;

begin
name_on_screen;
end.

86. (Книга по Delphi). Полный текст вопроса:
Друзья программисты! Порекомендуйте книгу по Delphi, рассчитанную на новичка.

[Отвечает: Акишин Андрей Владимирович, 04.05.2005 10:46]: Есть неплохая книга "Библия Delphi" Фленова М. с примерами на CD. В ней понятно и доходчиво описано программирование на Delphi с нуля.

109. (Dialog Box). Полный текст вопроса:
Собственно вопрос такой: Есть dll. (shell32.dll). Загружаю оттуда ресурс (в моем случае dialog box) функцией FindResource, потом LoadResource. Получаю в памяти адрес этого dialog box. Как мне теперь узнать caption этого dialog box? Можно наверное, записать все в memstream, потом в filestream и подсоединить к проекту. Но мне нужен только caption, использовать dialog box я не собираюсь. Заранее спасибо всем ответившим.

[Отвечает: Dasha, 04.05.2005 17:32]: Получается, у тебя есть его hwnd. Попробуй GetWindowText, находит заголовок окна по его hwnd.

117. (MS Agent's). Полный текст вопроса:
Как вставить в программу помощника (Agent) из программ MS Office?

[Отвечает: $T!13tT0, 04.05.2005 22:01]: Надо импортировать ActiveX компонент( Component->Import ActiveX Control ) Microsoft Agent Control. Далее - пример:

var
Form1:TForm1;
Koshka:IAgentCtlCharacter;
DATAPATH:string;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
DATAPATH:= 'offcat';
Agent1.Connected:=true;
Agent1.Characters.Load(DATAPATH,ExtractFileDir(Application.ExeName)+'\'+DATAPATH+'.acs');
Koshka:=Agent1.Characters[DATAPATH];
Koshka.Left:=Screen.Width-150;
Koshka.Top:=Screen.Height-150;
Koshka.Show(false);
try
Koshka.Play('Greeting');
except
Koshka.Speak('Greeting not available','');
end;
end;

//От ведущего: скоро на сайте будет неплохая документация по этой теме, правда, на английском языке :)

112. (Сетевая игра по TCP/IP). Полный текст вопроса:
Я создал текстовую стратегию и хотел бы реализовать в ней сетевую игру - посредством TCP/IP как это можно сделать? Заранее благодарен.

[Отвечает: BlackRat@list.ru, 05.05.2005 06:07]: Можно воспользоваться компонентами библиотеки DelphiX.

119. (Работа с функциями DLL). Полный текст вопроса:
Здравствуйте! У меня такая проблема: Я запихал несколько функций в DLL'ку. При вызове этих функций программа делает все правильно, но потом выдает "Invalid pointer operation". Из-за чего такое может быть, и как от этого избавиться? Заранее спасибо!

[Отвечает: Feniks, 05.05.2005 11:09]: Во-первых, при создании DLL надо учесть тот, что было Вам написано в уже готовом модуле на англ. языке. Если Вы не в ладах с ним, то перевожу... В DLL-ке, в принципе, может быть все что угодно. Но есть одно золотое правила: в DLL-ку, в качестве входных параметров для экспортируемых функций нельзя передавать String, и экспортируемая функция так же не должна в качестве своего результата возвращать String. Если это правило нарушается, тогда в DLL-ке в секции Uses первым модулем должен стоять ShareMem и в проекте, который юзает эту DLL-ку. Это Менеджер памяти. Этот модуль и есть не что иное, как сама DLL-ка от Borland - BORLNDMM.DLL. Которую, в таком случае, надо будет передать вместе с Вашим проектом конечному пользователю, а это не есть удобно. Тогда выход прост - не нарушать этого золотого правила и вместо String-а юзать PChar. И второй момент. Если DLL-ка написана на Delphi и ее будут юзать проекты писанные на других языках, тогда экспортируемые функции в DLL-ке надо объявлять как StdCall. Таковы правила Microsoft :( для совместимости и стыковке передаваемых параметров и возвращаемого результата. В Винде эти параметры передаются справа на лево (если я не ошибаюсь :) ), а в Паскале на оборот. Так вот этот StdCall выстраивает в стеке параметры так, как надо. Еще, функции в DLL-ке должны бать завернуты в блоки Try ... Except, Final ... End. Более точно, надо смотреть Вашу DLL-ку... Присылайте сорцы, поглядим.

[Отвечает: Yurchik, 07.05.2005 00:56]: Все экспортируемые функции библиотеки нужно объявлять с директивой stdcall. Например так: procedure MyProcedure; stdcall;Соответственно в своей программе пишешь:
interface
procedure MyProcedure; stdcall;
...
implementation
procedure MyProcedure; external 'mydll.dll';
Или при динамической загрузке библиотеки:
type TMyProcedure = procedure; stdcall; ...
var MyProcedure: TMyProcedure;
...
MyProcedure:= GetProcAddress(DllHandle, 'MyProcedure');
...
MyProcedure; // Вызов процедуры

[Отвечает: Evgeshka Vasilkov, 11.05.2005 22:21]: Чаще всего причина такой ошибки - /dev/hands . Анализируй деглюкером твой код. Наверняка где-нить что-нить пропустил, и DLL дохнет. Часто причиной ошибки бывает недообъявление некоторых указателей, или вторичное закрытие валидных pointer'ов, а также иногда влияют непроинициализированные глобальные указатели внутри DLL.
var ptr:tType;
...
procedure someproc;
begin
//new(ptr); этой строки-то нету!
ptr^.value:=7890;
end
;

[Отвечает: Сергей Азачем, 10.05.2005 16:29]: Скорее всего, вы используете длинные строки. В этом случае нужно добавить модуль ShareMem. Возможно используете оператор move или FillChar. Проверьте соответствие размеров пересылаемых (инициализируемых) данных. А вообще вопрос очень напоминает анекдот "Уважаемые ученые! у меня в подвале что-то скребет. Что бы это могло быть?" . Задавайте вопрос более конкретно.

110. (Модули Delphi в C Builder). Полный текст вопроса:
Возможно ли воспользоваться компонетом ProgressBar из библиотечного файла Delphi, запускаемого из модуля в C Builder?

[Отвечает: Feniks, 05.05.2005 11:08]: Да, можно, только это головная боль да и зачем, у С++Builder-а свои для этого есть компоненты, которые прекрасно с этим справляются. А вообще, в С++Builder встроен компилятор Delphi и он прекрасно компилит паскалевские юниты. Если посмотреть на сорцы всех библиотек С++Builder, то можно там увидеть и .pas файлы, которые компилятся постоянна вместе с Вашим проектом на С++Builder. Поэтому, если Вам нужен именно ProgressBar из библиотеки Delphi, то необходимо его выделить из библиотеки и сохранить в отдельный модуль, и уже этот модуль юзать на Билдере. Это если Вы хотите ProgressBar создавать динамически в Вашем проекте C++Builder-а. Если Вам необходимо его установить в IDE C++Builder-a как отдельный и независимы компонент, другими словами, просто перенести компонент ProgressBar с Delphi на C++Builder, тогда еще желательно переименовать класс ProgressBar в какой-нибудь другой, например, MyProgressBar, т.к. в C++Builder-е уже имеется такой класс и возникнет конфликт.

114. (Компонент TVSNetTreeView). Полный текст вопроса:
Нужен компонент TVSNetTreeView: подскажите, где его найти.

[Отвечает: Feniks, 05.05.2005 15:52]: //От ведущего: компонент отправлен задавшему вопрос. Скоро компонент появится на сайте.

99. (Ассоциация файлов с приложением). Полный текст вопроса:
Я начинающий програмист... Я создал программу для просмотра файлов с расширением dat, sys, cpp. Заинсталировал ее, установил, вроде все нормально... настроил... Но вот проблема в том, что при щелчке по файлу с расширением dat, она сразу не отображает его содержимое... Помогите, плииз, подскажите, что мне в ней прописать, и как, чтобы она при щелчке сразу отображала содержимое файла.

[Отвечает: Feniks, 05.05.2005 17:47]: Вот Вам функция, которой я пользуюсь. Я ее запускаю при старте моего приложения. Она регистрирует указанное расширение (FileExt) на мое приложение. Ваша прога должна обрабатывать командную строку, что бы через параметры командной строки можно было ее передать имя Ваших файлов для открытия (см. в Хелпе фун-ции ParamStr, ParamCount).

procedure CheckFileType(FileExt : String);
var
fReg : TRegistry;
Path : String;

begin
// -- определяем путь с которого запускается моя прога
Path := ExtractFilePath(ParamStr(0));

fReg := TRegistry.Create;
with fReg do
begin
RootKey := HKEY_CLASSES_ROOT;
OpenKey('.' + FileExt, True);
// -- MyAppFileExt -> тут нужен какой-нибудь идентификатор твоей проги
или ее название и тип файла. Этот идент-р уникален для каждого
расширения файла !!!
WriteString('', 'MyAppFileExt.Ext1');
CloseKey;
OpenKey('MyAppFileExt.Ext1', True);
WriteString('', 'Тут пишешь описание твоих фалов с расширением.
Это описание будет отображаться Виндой в графах и полях Тип
Файла.');
// -- прописываешь иконку на твои файлы
OpenKey('DefaultIcon', True);
WriteString('', Path + 'MyApp.exe,0');
CloseKey;
OpenKey('MyAppFileExt.Ext1\shell\open\command', True);
// -- В переменную Path пишешь полный путь к твой проге, которая
должна открывать твои файлы и в конце ставишь %1 - это для командной
строки. Вместо %1 будет подставляться файл с твоим расширением, когда
ты по нему мышой кликнешь в винде. Если твой путь к проге содержит
пробелы, то его надо брать в кавычки - "<путь>".
Path := Path + 'MyApp.exe %1';
WriteString('', Path);
CloseKey;
end;
fReg.Free;
end;

108. (Импорт из TXT в БД). Полный текст вопроса:
Можно ли импортировать данные из txt-документа определенного формата в базу данных (например, документ содержит баланс или налоговую декларацию)? Как проверить правильность заполнения документа?

[Отвечает: Evgeshka Vasilkov, 11.05.2005 22:24]: Вначале читаем текстовый файл в tmemo а затем парсим его на нужные теги данных, которые и заносим в базу. Кусок программы, которая ищет в тексте строку "#3456" (index) и заносит в базу этот номер вместе с некоторыми другими данными:

var Table1: TTable;
procedure TForm1.AnalyzeMemoBtn(Sender: TObject);
begin
table1.Insert;
if pos('#',s1)<>0 then begin
table1.findfield('Index').asstring:=copy(s1,pos('#',s1)+1,4);
table1.findfield('PartsNr').asinteger:=999;
end;
table1.post;
end;

123. (Отправка файла). Полный текст вопроса:
Я делаю PBEM игру и у меня такая проблема: как заставить программу отсылать автоматически при нажатии кнопки файл, который можно будет выбрать в OpenDialog'е?

[Отвечает: Evgeshka Vasilkov, 11.05.2005 22:20]: Вспоминая свои древние поделки ещё на Паскале...
var sendbuf:array[0..1023]of byte;//буфер с данными для игры.
begin
name:=opendialog1.filename;//выбрали файл, запишем имя в name
//откроем и прочитаем файл
assignfile(f1,name);
reset(f1,1);
blockread(f1,sendbuf,1023,res);
//отправим содержимое буфера
serversocket1.Socket.SendBuf(sendbuf,sizeof(sendbuf));
//закроем файл.
closefile(f1);
end.
Соли и перцу по вкусу. ;)


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


Статья по Delphi.

В связи с переездом сайта статьи сегодня нет.


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


Download.

Из данного раздела Вы можете скачать различные файлы: компоненты, plug-in'ы для Delphi, документацию по программированию, программы, игры, написанные на Delphi и всё остальное... Вы можете добавить свои файлы в данный раздел, будем очень признательны! Чтобы сделать это, пожалуйста, заполните форму на сайте. Когда администратор ответит Вам и даст согласие на добавление файла(ов), тогда Вы их и пришлёте. Убедительная просьба соблюдать все вышеописанные правила.

Название / описание файла
Объём
Ссылки
Обновлений нет. Всё будет на новом сайте, когда переедем.


Дружественные сайты.

Адрес раздела на сайте: http://www.delphi-faq.fatal.ru/modules.php?name=Friends.

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

http://infomania2004.webhost.ru/ - Этот сайт создан для того, чтобы вы могли получить интересующую вас информацию с минимальными затратами сил и времени. Если вы не нашли здесь нужной информации, вы можете оставить заявку на ее поиск. Как только информация будет найдена, она появится на сайте, а вам сообщат об этом.

http://www.basic.webhost.ru/ - Программирование на Basic & Visual Basic. На сайте Вы найдете множество примеров, статьи, исходники, ActiveX, а также многое другое!

http://www.sashook.nm.ru/ - Игры, флешки, обои, компьютерные приколы.

http://www.ssgroup.fatal.ru/ - Delphi 39. Ресурс для программистов. Статьи, исходники, компоненты, учебники, справочники, FAQ, программы и многое другое.

Дружественные рассылки:

Рассылки Subscribe.Ru
Интернет для Delphi-программиста
X-Program ПО, новости сайта и программирование в Delphi7
Visual Basic для новичков и профессионалов
 

 


 


Юмор.

Ничего нет.


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

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

 

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

В избранное