Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.11.14;
Скачать: CL | DM;

Вниз

Dll и TThread   Найти похожие ветки 

 
dms_main ©   (2004-10-29 10:02) [0]

Уважаемые мастера, обнаружил такой глюк.
Есть класс на основе стандартного Tthread,
креатится так:

constructor tmythread.create;
begin
   inherited create(false);
end;

Проблема в том , что в dll невызывается execute, хотя в console Application все работало замечательно.
Как лечить?


 
Sandman25 ©   (2004-10-29 10:04) [1]

В execute стоит Synchronized(MyMethod)?


 
dms_main ©   (2004-10-29 10:05) [2]

нет есть только CriticalSection....


 
Reindeer Moss Eater ©   (2004-10-29 10:12) [3]

Проблема в том , что в dll невызывается execute,
Потому что Resume не вызван


 
Reindeer Moss Eater ©   (2004-10-29 10:14) [4]

Или вообще не создан экземпляр


 
dms_main ©   (2004-10-29 10:15) [5]

TO Reindeer Moss Eater
1.кретиться не suspended
2.креатил с suspended , потом делал resume - непомогает.....


 
dms_main ©   (2004-10-29 10:17) [6]

все действия записанные в креате (с инкрементом threadcount(integer)) в critical section)проходят , а вот execute не вызывается....:-(


 
Reindeer Moss Eater ©   (2004-10-29 10:17) [7]

Чем получено знание, что Execute не вызывается?


 
dms_main ©   (2004-10-29 10:18) [8]

дебагом


 
Reindeer Moss Eater ©   (2004-10-29 10:20) [9]

Оптимизация или неправильный "дебаг"


 
Reindeer Moss Eater ©   (2004-10-29 10:21) [10]

Либо все таки не вызван конструктор.
Код вызова констсруктора написан, но он не вызывается.


 
dms_main ©   (2004-10-29 10:23) [11]

ну насчет дебага : при креате создается файл (свой для каждого трэда),при execute он заполняется. Итог файл создан но незаполнен.


 
Reindeer Moss Eater ©   (2004-10-29 10:24) [12]

код Execute показывай


 
Reindeer Moss Eater ©   (2004-10-29 10:25) [13]

Итог файл создан но незаполнен.

Создается один файл, а execute пишет в другой.


 
Reindeer Moss Eater ©   (2004-10-29 10:26) [14]

хотя в console Application все работало замечательно.

Глобальные переменные тому виной.
Как пить дать.
Имя файла например.


 
dms_main ©   (2004-10-29 10:28) [15]

имя файла предается трэду через параметр в креате.
в каждом трэде - уникальное


 
Reindeer Moss Eater ©   (2004-10-29 10:29) [16]

Код давай уже, да?


 
Reindeer Moss Eater ©   (2004-10-29 10:30) [17]

имя файла предается трэду через параметр в креате.

Что-то я не вижу, что передается.
Читая твой первый постинг.


 
dms_main ©   (2004-10-29 10:33) [18]


var
List:textfile;
       assignfile(list,drive+".txt");
       rewrite(list);
       FindFile(drive+":\round.txt");
       closefile(list);
       checkList:=TStringList.Create;
       checklist.Duplicates:=dupIgnore;
       checklist.Sorted:=true;
       checkList.LoadFromFile(drive+".txt");
       checklist.SaveToFile(drive+".txt");
       checklist.Clear;
       parseFile(drive+".txt");
  end;
   mycountsection:=TcriticalSection.Create;
   mycountsection.Enter;
   try
   threadcount:=threadcount-1;
   finally
   mycountsection.Leave;
   mycountsection.Free;
   end;


 
dms_main ©   (2004-10-29 10:34) [19]


constructor tmythread.create(drive:char);
begin
  inherited create(false);
end;


было б в нем дело......


 
Reindeer Moss Eater ©   (2004-10-29 10:37) [20]

Это что? код Execute?

И нафик тогда там критическая секция которая создается при входе и уничтожается при выходе?
Кого она синхронизирует?

Что такое Drive? Поле класса или переменная модуля?

В общем бред какой-то.

И где все же передается имя файла?


 
dms_main ©   (2004-10-29 10:40) [21]


> Что такое Drive? Поле класса или переменная модуля?

Drive : char - смотри след. пост

> И нафик тогда там критическая секция которая создается при
> входе и уничтожается при выходе?
> Кого она синхронизирует?

пременная threadcount:integer - счетчик трэдов...
и вообще мы от темы ушли - дело не в том что выскакивает ошибка - дело в том что execute метод не вызывается вообще.....


 
Reindeer Moss Eater ©   (2004-10-29 10:42) [22]

Drive : char - смотри след. пост

Да пофик чар она или стринг!
Переменная это или член класса потока?!


 
dms_main ©   (2004-10-29 10:43) [23]


> Да пофик чар она или стринг!
> Переменная это или член класса потока?!

член класса потока - естественно...


 
Reindeer Moss Eater ©   (2004-10-29 10:47) [24]

В общем так.
Твоя критическая секция - полный бред.

А что бы убедиться, что Execute все же вызывается, вставь первой строкой в него:

with TFileStream.Create(Format("%d-log.txt",[GetCurrentThreadID]),fmCreate) do
try
 WriteBuffer("А все таки она вертиться",24);
finally
  Free;
end;


 
Reindeer Moss Eater ©   (2004-10-29 10:49) [25]

constructor tmythread.create(drive:char);
begin
 inherited create(false);
end;

было б в нем дело......


И где сохранение параметра в классе?


 
Reindeer Moss Eater ©   (2004-10-29 10:50) [26]

Обсуждается какой-то мифический несуществующий код.
На кофейной гуще и то эффективнее гадать получается.


 
dms_main ©   (2004-10-29 10:52) [27]


> В общем так.
> Твоя критическая секция - полный бред.

это для тебя бред
я туда messagebox и MessageBeep($FFFFFFFF) вставлял пофиг...
дело не в том бред или нет -  там все проверено....
дело в том что метод create вызывается, а execute нет....
вот где загвоздка....


 
dms_main ©   (2004-10-29 10:53) [28]

млин ща весь выложу...


 
Reindeer Moss Eater ©   (2004-10-29 10:54) [29]

это для тебя бред

Это бред не только для меня.

а execute нет....

Читай [24] и не свисти MessageBeep"ом


 
Reindeer Moss Eater ©   (2004-10-29 10:55) [30]

млин ща весь выложу...

Уже не надо.


 
dms_main ©   (2004-10-29 10:55) [31]


TMyThread = class(TTHread)
 drive:char;
 list:textfile;
 checkList,sum:TStringList;
 mysection:TcriticalSection;
 mycountsection:TcriticalSection;
 constructor create(adrive:char);
 destructor free;
 procedure execute;override;
 procedure FindFile(path:string);
 procedure parseFile(name:string);

end;
constructor tmythread.create(adrive:char);
var
p:pointer;
begin
   inherited create(false);
   assignfile(list,adrive+".txt");
   rewrite(list);
   drive:=adrive;
   FreeOnTerminate:=true;
   Priority:=tpNormal;
   mycountsection:=TcriticalSection.Create;
   mycountsection.Enter;
   try
   threadcount:=threadcount+1;
   finally
   end;
   mycountsection.Leave;
   mycountsection.Free;

end;

destructor tmythread.free;
begin
   inherited free;
end;

procedure TMythread.execute;
begin
      assignfile(list,drive+".txt");
      rewrite(list);
      FindFile(drive+":\round.txt");
      closefile(list);
      checkList:=TStringList.Create;
      checklist.Duplicates:=dupIgnore;
      checklist.Sorted:=true;
      checkList.LoadFromFile(drive+".txt");
      checklist.SaveToFile(drive+".txt");
      checklist.Clear;
      parseFile(drive+".txt");
 end;
  mycountsection:=TcriticalSection.Create;
  mycountsection.Enter;
  try
  threadcount:=threadcount-1;
  finally
  mycountsection.Leave;
  mycountsection.Free;
  end;
end;



 
Reindeer Moss Eater ©   (2004-10-29 10:58) [32]

Все твои критические секции только пожирают ресурсы и никого нахрен не синхронизируют.
Они - бред сивой кобылы.

А про вызов Execute читай в 24 посте.


 
dms_main ©   (2004-10-29 11:04) [33]

1:

> А что бы убедиться, что Execute все же вызывается, вставь
> первой строкой в него:
>
> with TFileStream.Create(Format("%d-log.txt",[GetCurrentThreadID]),fmCreate)
> do
> try
>  WriteBuffer("А все таки она вертиться",24);
> finally
>   Free;
> end;

нифига непишется
2:
в taskmanager есчетчик трэдов - их там в проге нужное кол-во
так execute и не вызвался......  :-((


 
Reindeer Moss Eater ©   (2004-10-29 11:06) [34]

Вставил не первой строкой, либо конструктор не вызван.

Аналогичный код в конструктор.


 
Reindeer Moss Eater ©   (2004-10-29 11:07) [35]

Либо процесс вообще не имет прав на томе на создание файлов


 
Digitman ©   (2004-10-29 11:08) [36]

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


 
sniknik ©   (2004-10-29 11:08) [37]

> Обсуждается какой-то мифический несуществующий код.
> На кофейной гуще и то эффективнее гадать получается.
не расстраивайся, все просто, учись отвечать. ;о)

2 dms_main
у тебя ошибка в 17-й (семнадцатой) строке! че ты сюда 18-е (восемнадцатые) лепиш?

> я туда messagebox и MessageBeep($FFFFFFFF) вставлял пофиг...
VCL-ные или системные?

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


 
Reindeer Moss Eater ©   (2004-10-29 11:09) [38]

не расстраивайся, все просто, учись отвечать. ;о)

Я и других еще научу.


 
dms_main ©   (2004-10-29 11:10) [39]


> Вставил не первой строкой, либо конструктор не вызван.
>
> Аналогичный код в конструктор.

работает

> Либо процесс вообще не имет прав на томе на создание файлов

почему тогда это код в апликухе работает?
Апликуха которая грузит dll имеет права на создание файлов....


 
Reindeer Moss Eater ©   (2004-10-29 11:11) [40]

почему тогда это код в апликухе работает?

Потому что там работает другой код


 
dms_main ©   (2004-10-29 11:11) [41]


> это даже скомпилировано быть не может

делфа у меня (5 и 7) кривые - компилят кривой код.... :-)))


 
dms_main ©   (2004-10-29 11:12) [42]


> Потому что там работает другой код

как это понимать?


 
Reindeer Moss Eater ©   (2004-10-29 11:15) [43]

Слева направо


 
dms_main ©   (2004-10-29 11:17) [44]

Воощем тут все ясно ......
все ушли от темы - помочь в итоге никто не в состоянии .....


 
Reindeer Moss Eater ©   (2004-10-29 11:18) [45]

Иногда и медицина бессильна


 
Digitman ©   (2004-10-29 11:20) [46]


> делфа у меня (5 и 7) кривые - компилят кривой код


дурью маешься, да ?
при чем здесь версия Делфи ? ты прявила Паскаля нарушил !

procedure TMythread.execute;
begin
     assignfile(list,drive+".txt");
     rewrite(list);
     FindFile(drive+":\round.txt");
     closefile(list);
     checkList:=TStringList.Create;
     checklist.Duplicates:=dupIgnore;
     checklist.Sorted:=true;
     checkList.LoadFromFile(drive+".txt");
     checklist.SaveToFile(drive+".txt");
     checklist.Clear;
     parseFile(drive+".txt");
end;
 mycountsection:=TcriticalSection.Create;
 mycountsection.Enter;
 try
 threadcount:=threadcount-1;
 finally
 mycountsection.Leave;
 mycountsection.Free;
 end;
end;


то что подчеркнуто, это к чему относится ?
тело процедуры Execute - это то что между begin..end у тебя, а следом что за галиматься идет, скажи на милость ?


 
sniknik ©   (2004-10-29 11:21) [47]

> как это понимать?
ты не то показываеш, хочеш чтобы по 18й строке нашли глюк в 17й. а то что показываеш нельзя назвать кодом, это один сплошной глюк, не скомпилится.
либо здесь урезано так что принимает другой вид.


 
sniknik ©   (2004-10-29 11:23) [48]

> Иногда и медицина бессильна
ага, и тогда больной выживает. ;о)) (в смысле глюк, в этом случае)


 
dms_main ©   (2004-10-29 14:44) [49]

Хорошо - мы пойдем другим путем - если руки у меня кривые, то подскажите где именно:

library finer_lib;

uses
 SysUtils,windows,
 Classes;

type TMyThread = class (TThread)
a:integer;
b:integer;
c:integer;
constructor create(a0,b0:integer);
destructor free;
procedure execute;override;
end;

constructor TMyThread.create(a0,b0:integer);
begin
   inherited create(false);
   a:=a0;
   b:=b0;
   FreeOnTerminate:=true;
end;

destructor TMyThread.free;
begin
   inherited free;
end;

procedure TMyThread.execute;
var
t:TstringList;
begin
  c:=a*b;
  t:=TStringList.Create;
  t.Add("Result = "+inttostr(c));
  t.SaveToFile("c:\result.nfo");
  t.Free;
end;

{$R *.RES}
var
thread:TMyThread;
begin
thread:=TMyThread.create(2,2);
thread.WaitFor;
end.

Execute попрежнему не вызывается.....


 
dms_main ©   (2004-10-29 14:46) [50]

загрузка dll-ки :

program Project1;
{$APPTYPE CONSOLE}
uses
 SysUtils,
 windows;
begin
 readln;
 LoadLibrary("finer_lib.dll");
 readln;
end.


 
Reindeer Moss Eater ©   (2004-10-29 14:48) [51]

Зашибись!

А где запуск чего либо из DLL?


 
Reindeer Moss Eater ©   (2004-10-29 14:50) [52]

Reindeer Moss Eater ©   (29.10.04 10:14) [4]
Или вообще не создан экземпляр


 
dms_main ©   (2004-10-29 14:51) [53]

а зачем после загрузки сразу выполняется begin...end.

begin
thread:=TMyThread.create(2,2);
thread.WaitFor;
end.

Можешь проверить.....


 
dms_main ©   (2004-10-29 14:52) [54]


> Reindeer Moss Eater ©   (29.10.04 10:14) [4]
> Или вообще не создан экземпляр

создается - проверено дэбагом....


 
Reindeer Moss Eater ©   (2004-10-29 14:52) [55]

Можешь проверить.....

Для начала надо проверить результат LoadLibrary


 
dms_main ©   (2004-10-29 14:54) [56]

возвращает хэндл....


 
Reindeer Moss Eater ©   (2004-10-29 14:59) [57]

Код между бегин енд выполнятеся при загрузке процессом.
А выполняется ли он если библиотека грузится вторичным потоком этого процесса?


 
dms_main ©   (2004-10-29 15:02) [58]

Судя по тому что здесь>
inherited create(false);
  a:=a0;
  b:=b0;
  FreeOnTerminate:=true;
брэкпоинты - и на них выполнение останавливается, то грузит...


 
Reindeer Moss Eater ©   (2004-10-29 15:05) [59]

Поток грузит библиотеку. И Хендл валидный.

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


 
dms_main ©   (2004-10-29 15:07) [60]

так бы и сразу - а то "руки кривые","медицина бессильна".... :-(
подскажите хоть в каком направлении копать.


 
Reindeer Moss Eater ©   (2004-10-29 15:09) [61]

Экспортируй функцию из DLL и вызывай её явно, а не полагайся на Windows


 
dms_main ©   (2004-10-29 15:11) [62]

щас попробую..


 
Digitman ©   (2004-10-29 15:17) [63]


> dms_main


цитирую тебя :

constructor TMyThread.create(a0,b0:integer);
begin
  inherited create(false);
  a:=a0;
  b:=b0;
  FreeOnTerminate:=true;
end;

какого шута ты делаешь
inherited create(false);

!?

ведь доп.поток при этом начинает работать практически немедленно !

на основании чего ты уверен, что строка в конструкторе

   a:=a0;

выполнится заведомо раньше, чем строка

 c:=a*b;

в теле Execute ?

мозжечком-то пошевели малясь !


 
Reindeer Moss Eater ©   (2004-10-29 15:20) [64]

Все проще оказалось.

Код между бегин-енд в модуле библиотеки вызывается один раз на весь процесс.


 
dms_main ©   (2004-10-29 15:23) [65]


> на основании чего ты уверен, что строка в конструкторе

на основании того что execute вызывается ПОСЛЕ create
кстати от темы опять уходим.....


> Все проще оказалось.
>
> Код между бегин-енд в модуле библиотеки вызывается один
> раз на весь процесс.

и что из этого следует???


 
Reindeer Moss Eater ©   (2004-10-29 15:25) [66]

и что из этого следует???

То, что кто-то до сих пор с ручника не снялся.


 
dms_main ©   (2004-10-29 15:26) [67]


library finer_lib;

uses
 SysUtils,windows,
 Classes;

type TMyThread = class (TThread)
a:integer;
b:integer;
c:integer;
constructor create(a0,b0:integer);
destructor free;
procedure execute;override;
end;

constructor TMyThread.create(a0,b0:integer);
begin
   inherited create(false);
   a:=a0;
   b:=b0;
   FreeOnTerminate:=true;
end;

destructor TMyThread.free;
begin
   inherited free;
end;

procedure TMyThread.execute;
var
t:TstringList;
begin
  c:=a*b;
  t:=TStringList.Create;
  t.Add("Result = "+inttostr(c));
  t.SaveToFile("c:\result.nfo");
  t.Free;
end;

{$R *.RES}
procedure run;stdcall;export;
var
thread:TMyThread;
begin
thread:=TMyThread.create(2,2);
thread.WaitFor;
end;
exports run;
begin
end.

program Project1;
{$APPTYPE CONSOLE}
uses
 SysUtils,
 windows;
var
run : procedure;
handle:THandle;
begin
 readln;
 @run:=nil;
 handle:=LoadLibrary("finer_lib.dll");
 if  handle>= 32 then
       begin
       @run:=GetProcAddress(Handle,"run");
        if @run <> nil then
       run; ;
        end;
 FreeLibrary(Handle);
 writeln("ok");
 readln;
 readln;
end.



Всем спасибо - все заработало, но всетаки интересен вопрос
- реально ли запустить этот трэд в begin..end библиотеки???


 
dms_main ©   (2004-10-29 15:27) [68]


> Reindeer Moss Eater ©   (29.10.04 15:25) [66]
> и что из этого следует???
>
> То, что кто-то до сих пор с ручника не снялся.

весь день на нервах , так что уж извиняйте.... :-)


 
Reindeer Moss Eater ©   (2004-10-29 15:28) [69]

Реально.
Один раз за все время существования процесса.


 
Digitman ©   (2004-10-29 15:31) [70]


> все заработало


да не будет это работать как положено !
см. [63]


> реально ли запустить этот трэд в begin..end библиотеки


запустить любой код реально !
только вот будет ли он (конкретный твой код) делать то, что от него ожидается - это еще бабушка надвое сказала ...


 
dms_main ©   (2004-10-29 15:32) [71]


> То, что кто-то до сих пор с ручника не снялся.

- это точно......
Может объясните????
мне собственно и надо 1 раз , а не 2 и не 10.....
как заставить это работать без экспорта?


 
dms_main ©   (2004-10-29 15:33) [72]


> да не будет это работать как положено !
> см. [63]

с экспортом уже работает...


 
Reindeer Moss Eater ©   (2004-10-29 15:34) [73]

как заставить это работать без экспорта?

Чё, пошлины экспортные давят?


 
dms_main ©   (2004-10-29 15:35) [74]


> Чё, пошлины экспортные давят?

ага причем сильно..... :-))


 
Reindeer Moss Eater ©   (2004-10-29 15:37) [75]

Все это напоминает ток-шоу с приглашенными актерами.
Но актеры эти приглашенные, надо отдать должное здешним спецам по кастингу, иногда просто гениальные попадаются.
Именно гениальные. Снимаю шляпу.


 
dms_main ©   (2004-10-29 15:39) [76]

А если серьезно?


 
Reindeer Moss Eater ©   (2004-10-29 15:39) [77]

Так ведь работает уже


 
Digitman ©   (2004-10-29 15:40) [78]

просто вызови конструктор трэда в теле begin..end библиотеки.
что этому мешает ?


 
dms_main ©   (2004-10-29 15:41) [79]


> Так ведь работает уже

с экспортом - да ,а без экспорта - нет.
Я и спросил можно ли без экспорта и если да - то как.


 
dms_main ©   (2004-10-29 15:42) [80]


> просто вызови конструктор трэда в теле begin..end библиотеки.
> что этому мешает ?

А я что сделал?

begin
thread:=TMyThread.create(2,2);
thread.WaitFor;
end.


 
Digitman ©   (2004-10-29 15:46) [81]


> dms_main ©   (29.10.04 15:42) [80]


> А я что сделал?


и что ? и продолжаешь утверждать, что управление методу Execute не передается в ходе старта трэда ?


 
Добрый дядька ©   (2004-10-29 15:48) [82]

>dms_main

Вопрос:

Зачем нужна такая библиотека, которая загружается в приложение, выполняя код один раз, затем висит, занимая ресурсы?


 
dms_main ©   (2004-10-29 15:48) [83]

ДА именно так
Делаю LoadLibrary - креатиться, а execute не вызывается - из-за этого и вся проблема.


 
Reindeer Moss Eater ©   (2004-10-29 15:50) [84]

Который поток первый загрузил DLL - того и тапки.
Для него и будет выполнен код между begin/end.

Остальные отдыхают.


 
dms_main ©   (2004-10-29 15:53) [85]


> Который поток первый загрузил DLL - того и тапки.
> Для него и будет выполнен код между begin/end.
>
> Остальные отдыхают.

это все понятно - begin..end - вызывается 1 раз
при loadlibrary выполняется begin..end? креатится трэд, прыгает на Waitfor и ждет пока тред завершится - а метод execute в трэде так и не вызывается.... :-(


 
Digitman ©   (2004-10-29 15:54) [86]


> dms_main ©   (29.10.04 15:48) [83]


ерунду не городи.

ставь брейкпойнты на строчках

 c:=a*b;

и

 thread:=TMyThread.create(2,2);

и лови эти брейкпойнты !

и попробуй только сказать, что ни один из них не "ловится"


 
Reindeer Moss Eater ©   (2004-10-29 15:55) [87]

при loadlibrary выполняется begin..end?

Чё, еще раз?
Ну давай еще один раз:

Сто раз вызови LoadLibrary - код межу begin end выполнится ровно один раз.


 
dms_main ©   (2004-10-29 15:57) [88]


> ерунду не городи.
>
> ставь брейкпойнты на строчках
>
>  c:=a*b;
>
> и
>
>  thread:=TMyThread.create(2,2);
>
> и лови эти брейкпойнты !
>
> и попробуй только сказать, что ни один из них не "ловится"

именно это и говорю......
И вообще тема разговора именно эта!!!
не веришь - скомпиляй код (сообщение 67) - без экспорта и
через loadlibrary.....


 
dms_main ©   (2004-10-29 15:59) [89]


> Чё, еще раз?
> Ну давай еще один раз:
>
> Сто раз вызови LoadLibrary - код межу begin end выполнится
> ровно один раз.

спасибо - это я уже давно понял...... оно и вызывается 1 раз  - креатит но execute не вызывает....


 
Reindeer Moss Eater ©   (2004-10-29 16:00) [90]

креатит но execute не вызывает....

Это потому что хэллоуин на носу.
Подожди до понедельника, будет тебе execute


 
Digitman ©   (2004-10-29 16:00) [91]


> без экспорта


да экспорт-то тут причем ?!
хоть он есть, хоть его нет - ну никак это не влияет на сабж !


> не веришь


представь себе - не верю !
и даже проверять не буду ..
и глубоко фиолетово к тому же, КАК грузится твоя ДЛЛ - статически или динамически ..

давай-ка рассказывай, как ты "ловишь" брейкпойнты ..


 
dms_main ©   (2004-10-29 16:03) [92]

Run>Parameters>Host Application>F9
"MyLib">Reload Symbol Table


 
dms_main ©   (2004-10-29 16:18) [93]

проверить кстати можно еще проще :

procedure TMyThread.execute;
var
t:TstringList;
begin
 c:=a*b;
 t:=TStringList.Create;
 t.Add("Result = "+inttostr(c));
 t.SaveToFile("c:\result.nfo");
 t.Free;
end;


в "Экспортном" варианте файл создается, в Loadlibrary - не создается.


 
Добрый дядька ©   (2004-10-29 16:20) [94]

Все прекрасно работает как в таком виде:

library ThrDll;

uses
 Classes,
 windows;

type
 TMyThread=class(TThread)
   FX: String;
 protected
   procedure Execute; override;
 public
   constructor Create(const X: String);
 end;

{ MyThread }

constructor TMyThread.Create(const X: String);
begin
 inherited Create(True);
 FX := X;
 FreeOnTerminate := True;
 Resume;
 ResumeThread(Self.Handle);
end;

procedure TMyThread.Execute;
var
 i: Integer;
begin
 for i := 0 to 10 do
 begin
   Sleep(200);
   Write(FX+#13#10);
 end;
 Terminate;
end;

procedure DllMain(fdwReason:DWORD);
begin
  case fdwReason of
    DLL_THREAD_ATTACH: ;
    DLL_THREAD_DETACH: ;
    DLL_PROCESS_ATTACH:
      begin
        TMyThread.Create("Hehe");
      end;
    DLL_PROCESS_DETACH:
      begin
      end;
  end;
end;

begin
 DllProc:=@DllMain;
 DllMain(DLL_PROCESS_ATTACH);
end.


Вызывающий код:

program test;

{$APPTYPE CONSOLE}

uses
 Windows;
begin
 LoadLibrary("ThrDll.dll");
 ReadLn;
end.


так и если убрать DLLMain, а просто вставить в DLL всекцию после begin

TMyThread.CrReate("Hehe");


 
Digitman ©   (2004-10-29 16:21) [95]


> dms_main ©   (29.10.04 16:03) [92]


в Д5 в настройках Host Application нет никаких Reload Symbol Table

это раз.

второе.

ты стартовал отладку ДЛЛ, поймал брейкпойнт на строчке

thread:=TMyThread.create(2,2);

почему не прошел конструктор пошагово ?
ведь если BeginThread() выполнилась успешно, то признаков фактического старта трэда более чем достаточно !

это и ненулевой ThreadId и ненулевой Handle ... То что Handle ненулевой - это уже гарантировано, иначе WaitFor немедленно возвратил бы управление, чего, как ты говоришь, не наблюдается у тебя .. .

а если так, то рано или поздно процедура Execute обязана была бы получить управление ! Ведь поточная ф-ция успешно стартовала !


 
Добрый дядька ©   (2004-10-29 16:21) [96]

Сорри, строка ResumeThread в конструкторе не нужна.


 
dms_main ©   (2004-10-29 16:25) [97]

I>
> Все прекрасно работает как в таком виде:

как было так и есть...<


 
Добрый дядька ©   (2004-10-29 16:25) [98]

А вот ошибка в твоем коде:

constructor TMyThread.create(a0,b0:integer);
begin
  inherited create(false);
  a:=a0;
  b:=b0;
  FreeOnTerminate:=true;
end;


Это первая.

{$R *.RES}
var
thread:TMyThread;
begin
thread:=TMyThread.create(2,2);
thread.WaitFor;
end.


Это вторая.


 
dms_main ©   (2004-10-29 16:26) [99]


>
> {$R *.RES}
> var
> thread:TMyThread;
> begin
> thread:=TMyThread.create(2,2);
> thread.WaitFor;
> end.
>
> Это вторая.

а если мне надо дождаться его завершения?


 
Reindeer Moss Eater ©   (2004-10-29 16:27) [100]

Добрый дядька ©   (29.10.04 16:20) [94]
Все прекрасно работает как в таком виде:


Если делать это в одном потоке.


 
Добрый дядька ©   (2004-10-29 16:28) [101]

Вторая ошибка потому, что

FreeOnTerminate:=true;

Не может использоваться с

thread.WaitFor;


 
Добрый дядька ©   (2004-10-29 16:29) [102]

>Reindeer Moss Eater ©   (29.10.04 16:27)

Если делать это в одном потоке.

По условиям задачи разве не это нужно?


 
Reindeer Moss Eater ©   (2004-10-29 16:29) [103]

Добрый дядька ©   (29.10.04 16:28) [101]

Это не объясняет феномен невызова Execute


 
Reindeer Moss Eater ©   (2004-10-29 16:30) [104]

По условиям задачи разве не это нужно?

не это нужно по условиям задачи


 
Добрый дядька ©   (2004-10-29 16:30) [105]

В случае, если нужно дождаться завершения потока, то используется FreeOnTerminate := True,
затем
WaitFor
Free

Это из-за особенностей реализации TThread


 
Reindeer Moss Eater ©   (2004-10-29 16:31) [106]

Добрый дядька ©   (29.10.04 16:30) [105]

Это не объясняет феномен невызова Execute


 
dms_main ©   (2004-10-29 16:31) [107]

Digitman ©  
сорри забыл дописать перед пелодом ctrl+alt+m


 
Digitman ©   (2004-10-29 16:33) [108]


> dms_main ©   (29.10.04 16:26) [99]


> а если мне надо дождаться его завершения?


да ёшкин кот !!

мы тут о чем говорим ? о твоем утверждении, что Execute у тебя якобы не вызывается !

какого рожна ты стрелки переводишь на не имеющее отношения к проблеме строчку ? мало ли что там у тебя торчит в коде следом за конструктором потока ! ты стартовал поток как not suspended, исключения ты не получил при вызове конструктора, значит  Execute обязан был получить управление ! И абсолютно неважно, что у тебя там стоит следующей строчкой ! Правильность логики вызова WaitFor в данноим контексте - это совершенно иной вопрос !


 
Добрый дядька ©   (2004-10-29 16:35) [109]

[103] Reindeer Moss Eater ©   (29.10.04 16:29)
Добрый дядька ©   (29.10.04 16:28) [101]

Это не объясняет феномен невызова Execute

Именно объясняет.

Поток создается с Inherited(False), поточная функция просто не успевает начать выполняться.


 
dms_main ©   (2004-10-29 16:35) [110]


> мы тут о чем говорим ? о твоем утверждении, что Execute
> у тебя якобы не вызывается !

смотри 93 мессагу


 
Digitman ©   (2004-10-29 16:36) [111]


> ctrl+alt+m


ЭТО к чему ? опять стрелки переводишь ?
какое отношение состояние открытости IDE-окна имеет к проблеме ?


 
dms_main ©   (2004-10-29 16:37) [112]


>
> ЭТО к чему ? опять стрелки переводишь ?
> какое отношение состояние открытости IDE-окна имеет к проблеме
> ?

открывается окно загруженных модулей - так в своем делаешь Reload Symbol Table


 
Reindeer Moss Eater ©   (2004-10-29 16:40) [113]

Поток создается с Inherited(False), поточная функция просто не успевает начать выполняться.

И что же ей мешает?


 
dms_main ©   (2004-10-29 16:41) [114]


> Поток создается с Inherited(False), поточная функция просто
> не успевает начать выполняться.
>
> И что же ей мешает?

Да же если create(true) а потом resume - толку нет. :-(


 
Добрый дядька ©   (2004-10-29 16:42) [115]

>Reindeer Moss Eater ©   (29.10.04 16:40)

И что же ей мешает?

Я думаю, возникающий Exception, в результате чего процесс успешно терминируется системой вместе с вновь созданным(или не успевшим создаться) потоком.


 
Добрый дядька ©   (2004-10-29 16:43) [116]

>dms_main ©   (29.10.04 16:41)

Ты мой код попробовал? Выполняется?


 
Reindeer Moss Eater ©   (2004-10-29 16:44) [117]

в результате чего процесс успешно терминируется

Что-то мы про это не слышали от приглашенного актера


 
dms_main ©   (2004-10-29 16:44) [118]


> Добрый дядька ©   (29.10.04 16:43) [116]
> >dms_main ©   (29.10.04 16:41)
>
> Ты мой код попробовал? Выполняется?

выполняется  create, а execute - нет.


 
Добрый дядька ©   (2004-10-29 16:45) [119]

>Reindeer Moss Eater ©   (29.10.04 16:44)

Что-то мы про это не слышали от приглашенного актера

А что же вы слышали от приглашенного актера? что его консольное приложение стартует и тут же заканчивается? Так на это можно было не обратить внимание.


 
Добрый дядька ©   (2004-10-29 16:46) [120]

>dms_main ©   (29.10.04 16:44)

Т.е. ты в точности создал проект с кодом библиотеки и вызовом?


 
dms_main ©   (2004-10-29 16:46) [121]


> >Reindeer Moss Eater ©   (29.10.04 16:40)
>
> И что же ей мешает?
>
> Я думаю, возникающий Exception, в результате чего процесс
> успешно терминируется системой вместе с вновь созданным(или
> не успевшим создаться) потоком.

Странно - никаких исключений и ошибок я не наблюдаю......


 
Reindeer Moss Eater ©   (2004-10-29 16:47) [122]

Добрый дядька ©

Он в IDE его отлаживает если помнишь.


 
dms_main ©   (2004-10-29 16:48) [123]

> Добрый дядька - нет исправил свой в точности с указаниями
(зачем смысл то тотже)


 
Добрый дядька ©   (2004-10-29 16:50) [124]

>dms_main ©   (29.10.04 16:48)
(зачем смысл то тотже)

А ты не думаешь, что у тебя может быть проблема в коде, который ты используешь? Например, при работе с файлом?


 
dms_main ©   (2004-10-29 16:50) [125]

Мастера - насчет отладки - в execute создается файл - нету этого файла - несоздается он > execute не выполняется.


 
dms_main ©   (2004-10-29 16:51) [126]

В console Application тотже код работает без проблем.


 
Reindeer Moss Eater ©   (2004-10-29 16:54) [127]

Парень, сколько раз можно повторять, что у тебя не создается экземпляр, потому и нет execute.

А в отладчике есть создание потому что IDE загружает библиотеку первая.


 
dms_main ©   (2004-10-29 16:57) [128]


> Reindeer Moss Eater ©   (29.10.04 16:54) [127]
> Парень, сколько раз можно повторять, что у тебя не создается
> экземпляр, потому и нет execute.
>
> А в отладчике есть создание потому что IDE загружает библиотеку
> первая.

ok - тоесть без экспорта работать небудет?(файла то создаваемого нет)


 
Digitman ©   (2004-10-29 16:59) [129]

я, кажись, начинаю понимать, в чем дело ..
это, видимо, известный глюк на стыке встроенного дебаггера и ВинХРю без апдейта ...

т.е. Execute-то как раз выполняется, но вот из-за глюка дебаггер не может отработать брэйкпойнт в теле поточной ф-ции

но даже если так, то MessageBox (ПЕРВОЙ же строчкой после begin в Execute)  обязан зафиксировать факт успешного старта поточной ф-ции... если, конечно же, не умудриться напортачить еще и с параметрами MessageBox..


 
dms_main ©   (2004-10-29 17:04) [130]

> Digitman ©
винда ХР со всеми патчами,D7 без мудрежа дэббагит,
нету ни файла ни месседж бокса ни меесадж бипа.


 
Digitman ©   (2004-10-29 17:09) [131]


> dms_main ©   (29.10.04 17:04) [130]


да ну не верю я !

ты что-то существенное скрываешь, то что упорно не приводишь в примерах своего кода ..

почему ты до сих пор не оттрассировал пошагово тело конструктора TThread ?


 
dms_main ©   (2004-10-29 17:15) [132]

вот те другой мой код в котором таже беда - невижу смысла выкладывать 14к кода если в 0,7к таже беда:

library finer_lib;

uses
 SysUtils,windows,
 Classes;

type TMyThread = class (TThread)
a:integer;
b:integer;
c:integer;
constructor create(a0,b0:integer);
destructor free;
procedure execute;override;
end;

constructor TMyThread.create(a0,b0:integer);
begin
   inherited create(true);
   a:=a0;
   b:=b0;
  // FreeOnTerminate:=true;
   resume;

end;

destructor TMyThread.free;
begin
   inherited free;
end;

procedure TMyThread.execute;
var
t:TstringList;
begin
  c:=a*b;
  t:=TStringList.Create;
  t.Add("Result = "+inttostr(c));
  t.SaveToFile("c:\result.nfo");
  t.Free;
end;

{$R *.RES}

var
thread:TMyThread;
begin
delete
thread:=TMyThread.create(2,2);
thread.WaitFor;
end.


 
Добрый дядька ©   (2004-10-29 17:16) [133]

Так тоже дебаггер не заходит в поточную функцию?


library ThrDll;

uses
 windows;

type
 TParm=record
   X,Y: Integer;
 end;
var
 Parm: TParm;
 ThreadId: THandle;

procedure ThreadFunc(aParm: Pointer); cdecl;
var
 i: Integer;
begin
 for i := 0 to TParm(aParm^).X do
 begin
   Write("Test"+#13#10);
 end;
end;

begin
 Parm.X := 2;
 Parm.Y := 2;
 CreateThread(nil,0,@ThreadFunc,@Parm,0,ThreadId);
end.


 
Reindeer Moss Eater ©   (2004-10-29 17:18) [134]

Код приглашенного актера прекрасно работает в консольном приложении (читай - в однопоточном) - давайте верить в это.

В многопоточном не работает как надо. - давайте тоже верить в это.

Значит где трабл зарыт?
Правильно. В особенности парочки DLL + вторичный поток.

Не понимаю, как можно в течении 130 постов обсуждать очевидное.


 
dms_main ©   (2004-10-29 17:18) [135]

Добрый дядька © >
это - совершенно другая песня здесь заходит.


 
Digitman ©   (2004-10-29 17:19) [136]


> dms_main ©   (29.10.04 17:15) [132]


и долго ты еще будешь постить сюда один и тот же код в разных вариациях ?

я тебе вопрос задал - ЧТО показала пошаговая трассировка TThread.Create() ?


 
dms_main ©   (2004-10-29 17:20) [137]

Reindeer Moss Eater © > несогласен только с одним - "приглашенный актер" интересно это к чему? :-(


 
Reindeer Moss Eater ©   (2004-10-29 17:21) [138]

ЧТО показала пошаговая трассировка TThread.Create() ?

Ничего полезного она не покажет.

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


 
dms_main ©   (2004-10-29 17:21) [139]


> Digitman ©

весь код который в create выполнился, в execute не заходит.


 
Reindeer Moss Eater ©   (2004-10-29 17:24) [140]

Reindeer Moss Eater © > несогласен только с одним - "приглашенный актер" интересно это к чему? :-(

Потому что программер на форуме решает реальные проблемы, а приглашенный актер играет роль.


 
Digitman ©   (2004-10-29 17:25) [141]


> Reindeer Moss Eater ©   (29.10.04 17:18) [134]


что-то я тебя не понял ..
какая разница, откуда будет вызвана в дан.случае LoadLibrary - из основного или доп.трэда хост-процесса ? та же CreateThread в конечном итоге вызывается, что мешает ее успешному выполнению, даже если вызвана она из доп.трэда ?

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

или ты намекаешь на то, что до CreateThread даже дело не доходит ? но в Д5, по кр.мере, обязано доходить !


 
dms_main ©   (2004-10-29 17:26) [142]


> Reindeer Moss Eater ©

то есть получается я от нефиг делать тут весь день торчу ? :-(

> Потому что программер на форуме решает реальные проблемы

и трабла моя вымышлена?


 
Reindeer Moss Eater ©   (2004-10-29 17:28) [143]

Разница такая.

Мы ставим BP.
И мы попадем на эту BP.
Но это не та нить, которую мы отлаживаем.

У него нет следов файла, который должен появиться в результате загрузки либы вторичным потоком.

Точка останова есть, и мы туда попадаем.
Но только не тогда, когда вторичный поток делает LoadLobrary


 
dms_main ©   (2004-10-29 17:30) [144]


> Но только не тогда, когда вторичный поток делает LoadLobrary

Я это все давно понял - можно не повторяться.
Лечиться это или нет - вот в чем вопрос.


 
dms_main ©   (2004-10-29 17:30) [145]


> Но только не тогда, когда вторичный поток делает LoadLobrary

Я это все давно понял - можно не повторяться.
Лечиться это или нет - вот в чем вопрос.


 
Reindeer Moss Eater ©   (2004-10-29 17:32) [146]

Лечиться это или нет - вот в чем вопрос.

Устал я. Домой иду.


 
Digitman ©   (2004-10-29 17:35) [147]


> Reindeer Moss Eater ©   (29.10.04 17:21) [138]


с какой стати отладчик автоматом загрузит ДЛЛ, если она в хост-приложении грузится искл-но динамически ? и если никаких Reload Symbol Table и иже с ним сомнительных фич не задействовать явно ?


 
Добрый дядька ©   (2004-10-29 17:37) [148]

>dms_main ©   (29.10.04 17:30)
WAitFor убери. Совсем.


 
Reindeer Moss Eater ©   (2004-10-29 17:41) [149]

с какой стати отладчик автоматом загрузит ДЛЛ, если она в хост-приложении грузится искл-но динамически ?
Динамически. Да.
Но не из единственного потока.

какая разница, откуда будет вызвана в дан.случае LoadLibrary - из основного или доп.трэда хост-процесса ?

Никакой разницы нет. Можно из основного, можно из вторичного.

Разница есть какой поток делает это первым в процессе.

Потому что у него код создания потока, создающего файлы привязан к блоку begin/end библиотеки.

А блок этот вызывается один раз за весть процесс сколько бы ни вызывали LoadLibrary в этом процессе.

А актер экспортировать и явно вызывать из библиотеки ничего не хочет, бо пошлины экспортные ему мешают.


 
Reindeer Moss Eater ©   (2004-10-29 17:52) [150]

И вообще не понятно, откуда берутся параметры для конструктора того потока, если его запуск заточен под автоматическое выполнение кода между begin/end библиотеки при простой загрузке библиотеки.

Получается, что они вообще хардкодед.


 
Defunct ©   (2004-10-29 19:07) [151]

Ну и развели..

Надо было сказать:

> Лечиться это или нет - вот в чем вопрос.

Лечится только в военном госпитале.


 
Reindeer Moss Eater ©   (2004-11-01 10:40) [152]

Что бы "работало" без экспорта

library lib;

uses Windows;
{$R *.res}

procedure DllProcedure(AReason : integer);
begin
case AReason of
 DLL_PROCESS_ATTACH,
 DLL_THREAD_ATTACH  : begin
                       //Создание экземпляров TThread
                       ....  
                      end;
 DLL_PROCESS_DETACH :;
 DLL_THREAD_DETACH  :;
end;
end;

begin
DllProc := DllProcedure;
DllProc(DLL_PROCESS_ATTACH);
end.


 
Digitman ©   (2004-11-01 11:50) [153]


> Reindeer Moss Eater ©   (29.10.04 17:41) [149]


DLL_THREAD_ATTACH здесь к делу никоим образом не относится

как только любой трэд процесса в самый первый раз будет грузить ДЛЛ (явно или неявно), системой будет вызвана DllEntryPoint(DLL_PROCESS_ATTACH), что в конечном счете должно привести к передаче управления в блок begin..end библиотеки, где у автора вызывается конструктор TMyThread.Create (он и вызывается в действительности - автор это подтверждает) .. если в ходе работы конструктора не возникло исключений, то поточная ф-ция обязана стартовать и вызвать при этом Execute, и брейкпойнт в самом начале тела Execute ну просто обязан быть пойманным отладчиком ..


 
DiamondShark ©   (2004-11-01 12:41) [154]

Балин...
Любите хелп -- источник знаний:

During process startup and DLL initialization routines, new threads can be created, but they do not begin execution until DLL initialization is done for the process.


 
Reindeer Moss Eater ©   (2004-11-01 12:43) [155]

Он (автор) хочет, что бы бегин/енд выполнялся при LoadLibrary из любого потока хост приложения.

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


 
Reindeer Moss Eater ©   (2004-11-01 12:57) [156]

DiamondShark ©

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


 
Digitman ©   (2004-11-01 12:57) [157]


> Reindeer Moss Eater ©   (01.11.04 12:43) [155]


я ОДНОГО не понял - автор утверждает, что ВР в теле Execute он ВООБЩЕ не ловит в ходе самого первого обращения к ДЛЛ ... хотя тело конструктора хотя бы однократно получает управление ...

этого быть не может - рано или поздно поточная ф-ция все равно стартует


> DiamondShark ©   (01.11.04 12:41) [154]


ну и что ? рано или поздно ВР должна сработать !


 
DiamondShark ©   (2004-11-01 13:04) [158]


> Reindeer Moss Eater ©   (01.11.04 12:57) [156]

Это ты к чему?


> Digitman ©   (01.11.04 12:57) [157]
> ну и что ? рано или поздно ВР должна сработать !

Не-а. У него там WaitFor стоит.


 
DiamondShark ©   (2004-11-01 13:14) [159]

Объясняю.

Вызываем LoadLidrary, LoadLidrary не возвращается, пока не отработает DLL entry point.
В DLL entry point создаётся поток, который будет подвешен, пока не завершится DLL entry point.
К контексте DLL entry point вызывается поток.WaitFor, которая не вернётся, пока не закончится поток, который не запустится пока не закончится DLL entry point, которая не закончится пока не вернётся WaitFor... в доме который построил Джек.

Если убрать WaitFor, то поток начнёт работь сразу, как вернётся DLL entry point. Тут, правда автором заботливо подложены другие грабли в виде FreeLibrary сразу после LoadLibrary.


 
Юрий Зотов ©   (2004-11-01 13:22) [160]

Всю ветку читать не стал - слишком длинная. Поэтому просто скажу, в чем тут, похоже, дело и сорри, если повторю кого-то или скажу "не в кассу".

Проблема XP-DLL-отладчик известная (хоть в однопоточном, хоть в многопоточном приложении). По какой-то причине отладчик не подгружает отладочную символьную информацию из DLL и поэтому брейкпойнты в DLL не срабатывают (хотя код работает). Лечится это либо установкой эксперта IDE (встречал в сети, но где - не помню), либо так.

1. В DLL сразу после главного begin пишем любой MesssageBox  -что угодно, лишь бы тормознуть программу.

2. Когда этот MessageBox появится, переключаемся в Delphi, жмем Ctrl-Alt-M, в появившемся окне (слева внизу) находим свою DLL, жмакаем по ней правой кнопкой мыши и выбираем Reload Symbol Table. Если все прошло ОК, то справа увидим, что отладочная информация подгрузилась.

3. В MessageBox жмем OK - теперь брейкпойнты должны работать.


 
DiamondShark ©   (2004-11-01 13:24) [161]

Да нет там никаких проблем икспи-отладчик...


 
Digitman ©   (2004-11-01 13:32) [162]


> DiamondShark ©   (01.11.04 13:04) [158]
> Не-а. У него там WaitFor стоит.


WaitFor в таком контексте [см. 154] д.б. бы вызвать дэдлок, однако автор ничего не говорит на тему якобы "зависания" приложения, вызывающего ДЛЛ по LoadLibrary.


 
DiamondShark ©   (2004-11-01 13:40) [163]


> Digitman ©   (01.11.04 13:32) [162]

Мало ли что автор не говорит, он свой реальный код тоже долго не говорил.
Тем не менее, его код на LoadLibrary именно зависает.


 
Reindeer Moss Eater ©   (2004-11-01 13:50) [164]

Тем не менее, его код на LoadLibrary именно зависает.

А еще он говорит, что в консольном приложении все нормально.
И никакой waitfor ему не помеха.


 
Digitman ©   (2004-11-01 13:58) [165]

что-то подустал я тут из пустого в порожнее переливать ..

автор давно уже ни мычит ни телится


 
DiamondShark ©   (2004-11-01 14:28) [166]


> Reindeer Moss Eater ©   (01.11.04 13:50) [164]
> А еще он говорит, что в консольном приложении все нормально.
> И никакой waitfor ему не помеха.

А мы на слово никому не верим.

Проблема воспроизведена, причина описана, пути решения намечены.
Ждём-с реакции автора...


 
dms_main ©   (2004-11-02 22:11) [167]

Господа! Все оказалось намного проще....
Execute выполняется после begin...end. библиотеки, правда есть одно но - но это не важно.
Решается так :
Создаем еще один класс потока,
create его ставим в begin...end. библиотеки, на его execute забиваем create того кода что был в begin ... end. библиотеки -
и все у нас работает прекрасно.
Спасибо всем кто принял участие в решении вопроса.....



Страницы: 1 2 3 4 5 вся ветка

Текущий архив: 2004.11.14;
Скачать: CL | DM;

Наверх




Память: 0.92 MB
Время: 0.049 c
14-1098964364
SeVTov
2004-10-28 15:52
2004.11.14
Delphi глючит


1-1098942384
CrazyHacKeRs
2004-10-28 09:46
2004.11.14
Виртуальный DataSet


3-1097958612
saNat
2004-10-17 00:30
2004.11.14
"Архивация" БД Access


4-1096311805
SergeV
2004-09-27 23:03
2004.11.14
Загрузка процессора!


3-1097811979
Kair()
2004-10-15 07:46
2004.11.14
TTable