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

Вниз

как можно создать такой класс?   Найти похожие ветки 

 
начинающий2   (2011-01-18 14:52) [0]

Как класс который создает поток на WinAPI
hThread:=BeginThread(Nil,0,Addr(ThreadProc),NewClass,CREATE_SUSPENDED,ConslThrId);
и в качестве параметра указывает себя, чтобы процедура потока WinApi ThreadProc затем по указателю обращалась к данным этого класса?

Заранее скажу класс TThread не планируется использовать, так же не используется модуль Classes, только windows.


 
Игорь Шевченко ©   (2011-01-18 15:06) [1]

RTFS: Classes.TThread


 
DiamondShark ©   (2011-01-18 15:08) [2]


> Заранее скажу класс TThread не планируется использовать,
>  так же не используется модуль Classes, только windows.

*пожимая плечами*
Скопипасти класс TThread (исходники-то есть) и выкини всё, что требует ссылок на Classes.

*с ленинским прищуром*
А может вы, батенька, ещё и SysUtils, не планируете использовать?


 
han_malign   (2011-01-18 15:38) [3]

- нечестный, но работающий метод(хак):
type
TNewClass = class(TOldClass)
  function ThreadProc: DWORD; stdcall;
  function start: boolean;
  hThread: Thandle;
end;

function TNewClass.ThreadProc: DWORD;
begin
  //self is implicit parameter of ThreadProc passed over stack(because stdcall)
  ...
end;

function TNewClass.start: boolean;
begin
  hThread:=BeginThread(Nil,0,Addr(TNewClass.ThreadProc),self,CREATE_SUSPENDED,ConslThrId);
  Result:= hThread <> 0;
end;

- честный:
function ThreadProc(lpParameter: pointer): DWORD; stdcall;
begin
  Result:= TNewClass(lpParameter).ThreadProc;
end;


 
начинающий2   (2011-01-18 15:57) [4]


> han_malign   (18.01.11 15:38) [3]


почему "- нечестный"?

Кстати при TNewClass.Free созданный поток все равно работает если есть ему что делать.
Я так полагаю что и деструктор то же нужно делать чтобы прибить запущенный поток? А hThread нужно в десрукторе через CloseHandle закрывать или это делается само?


 
начинающий2   (2011-01-19 00:02) [5]


> han_malign   (18.01.11 15:38) [3]


Неработающий метод.
Доступа к данным класса то нету из самого потока т.е. function ThreadProc и function TNewClass.ThreadProc


 
Servy ©   (2011-01-19 04:03) [6]


> Доступа к данным класса то нету из самого потока

Куда это он делся то?


 
начинающий2   (2011-01-19 20:36) [7]


> han_malign   (18.01.11 15:38) [3]


> Servy ©   (19.01.11 04:03) [6]


Да вот туда куда то и девается. Непонятно куда девается.
Вот модуль в котором все проблемы.
В потоке читается ID и отправляется отладчику
Что получает отладчик вместо 111 Thr := TNewClass.Create(111);
00000050 98.58939362 [3932] 2088810288 <- это говорит о том, что поток работает, но параметр ID не читается или не инициализирован. Но при трассировке через F7 я то вижу, что в классе параметр инициализирован как 111.

Unit NewClass;

interface

Uses Windows, SysUtils, dialogs;

type
 TNewClass = class(TObject)
 hThread: Thandle;
 FID    : Integer;
 ThrID : DWORD;
 function ThreadProc: DWORD; stdcall;
 function start: boolean;
 function Resume: Boolean;
 Constructor Create(ClassID: DWORD); reintroduce;
 Procedure SetID(Value: Integer);
 Property ID: Integer Read FID Write SetID;
end;

implementation

Constructor TNewClass.Create(ClassID: DWORD);
begin
 inherited Create;
 ID := ClassID;
end;

function TNewClass.ThreadProc: DWORD;
var i: WORD;
begin
 //self is implicit parameter of ThreadProc passed over stack(because stdcall)
 ShowMessage(IntToStr(ID));
 for i:=1 to 100 do begin
   OutputDebugStringA(PChar(IntToStr(ID)));
Sleep(100);
 end;
end;

function TNewClass.Resume: Boolean;
begin
 ResumeThread(hThread);
end;

procedure TNewClass.SetID(Value: Integer);
begin
 FID:=Value;
end;

Function ThreadProc(lpParameter: Pointer); stdcall;
begin
 Result:=TNewClass(lpParameter).ThreadProc;
end;

function TNewClass.start: boolean;
begin
 hThread:=BeginThread(Nil,0,Addr(TNewClass.ThreadProc),self,CREATE_SUSPENDED,ThrI d);
 Result:= hThread <> 0;
 Resume;
end;


 
Leonid Troyanovsky ©   (2011-01-19 22:34) [8]


> начинающий2   (19.01.11 20:36) [7]

Отметил несгибаемость:

> так же не используется модуль Classes


> Uses Windows, SysUtils, dialogs;


> function TNewClass.Resume: Boolean;

Тоже понравилась.
Как и

>  hThread:=BeginThread(Nil,0,Addr(TNewClass.ThreadProc),self,
> CREATE_SUSPENDED,ThrI d);
>  Result:= hThread <> 0;
>  Resume;

Уважаемый, ты б почитал хоть чего-ни-ть про потоки.
stdcall.

--
Regards, LVT.


 
DVM ©   (2011-01-19 22:39) [9]


> нечестный, но работающий метод(хак):

Нету нормального способа сделать метод класса функцией, которую можно было бы передать в WinAPI.  Есть различные выкрутасы, которые даже могут быть работоспособны, пока не наткнутся на DEP, который прибьет сразу такое приложение. Если бы такая возможность была, то скажем TService и прочие классы, где это надо были бы организованы по другому.


 
DVM ©   (2011-01-19 22:46) [10]


> начинающий2

не уверен что все ниже верно, неохота вникать, но как то так:

unit Threads;

interface

uses Windows;

////////////////////////////////////////////////////////////////////////////////
// TThread
////////////////////////////////////////////////////////////////////////////////

type

 TThreadMethod = procedure of object;
 TThreadPriority = (tpIdle, tpLowest, tpLower, tpNormal, tpHigher, tpHighest,
   tpTimeCritical);

const

 Priorities: array [TThreadPriority] of Integer =
   (THREAD_PRIORITY_IDLE,
    THREAD_PRIORITY_LOWEST,
    THREAD_PRIORITY_BELOW_NORMAL,
    THREAD_PRIORITY_NORMAL,
    THREAD_PRIORITY_ABOVE_NORMAL,
    THREAD_PRIORITY_HIGHEST,
    THREAD_PRIORITY_TIME_CRITICAL);

type

 TThread = class
 private
   FHandle: THandle;
   FThreadID: THandle;
   FTerminated: Boolean;
   FSuspended: Boolean;
   FFreeOnTerminate: Boolean;
   FFinished: Boolean;
   FReturnValue: DWORD;
   function GetPriority: TThreadPriority;
   procedure SetPriority(Value: TThreadPriority);
   procedure SetSuspended(Value: Boolean);
 protected
   procedure Execute; virtual; abstract;
   property ReturnValue: DWORD read FReturnValue write FReturnValue;
   property Terminated: Boolean read FTerminated;
 public
   constructor Create(CreateSuspended: Boolean);
   destructor Destroy; override;
   procedure Resume;
   procedure Suspend;
   procedure Terminate;
   procedure WaitFor;
   property FreeOnTerminate: Boolean read FFreeOnTerminate write FFreeOnTerminate;
   property Handle: THandle read FHandle;
   property Priority: TThreadPriority read GetPriority write SetPriority;
   property Suspended: Boolean read FSuspended write SetSuspended;
   property ThreadID: THandle read FThreadID;
 end;

implementation

////////////////////////////////////////////////////////////////////////////////
// TThread
////////////////////////////////////////////////////////////////////////////////

function ThreadProc(Thread: TThread): DWORD;
var
 FreeThread: Boolean;
begin
 Thread.Execute;
 FreeThread := Thread.FFreeOnTerminate;
 Result := Thread.FReturnValue;
 Thread.FFinished := True;
 if FreeThread then Thread.Free;
 EndThread(Result);
end;

//------------------------------------------------------------------------------

constructor TThread.Create(CreateSuspended: Boolean);
var
 Flags: DWORD;
begin
 inherited Create;
 FSuspended := CreateSuspended;
 Flags := 0;
 if CreateSuspended then Flags := CREATE_SUSPENDED;
 FHandle := BeginThread(nil, 0, @ThreadProc, Pointer(Self), Flags, FThreadID);
end;

//------------------------------------------------------------------------------

destructor TThread.Destroy;
begin
 if FHandle <> 0 then CloseHandle(FHandle);
 inherited Destroy;
end;

//------------------------------------------------------------------------------

function TThread.GetPriority: TThreadPriority;
var
 P: Integer;
 I: TThreadPriority;
begin
 P := GetThreadPriority(FHandle);
 Result := tpNormal;
 for I := Low(TThreadPriority) to High(TThreadPriority) do
   if Priorities[I] = P then Result := I;
end;

//------------------------------------------------------------------------------

procedure TThread.SetPriority(Value: TThreadPriority);
begin
 SetThreadPriority(FHandle, Priorities[Value]);
end;

//------------------------------------------------------------------------------

procedure TThread.SetSuspended(Value: Boolean);
begin
 if Value <> FSuspended then
   if Value then
     Suspend
   else
     Resume;
end;

//------------------------------------------------------------------------------

procedure TThread.Suspend;
begin
 FSuspended := True;
 SuspendThread(FHandle);
end;

//------------------------------------------------------------------------------

procedure TThread.Resume;
begin
 if ResumeThread(FHandle) = 1 then FSuspended := False;
end;

//------------------------------------------------------------------------------

procedure TThread.Terminate;
begin
 FTerminated := True;
end;

//------------------------------------------------------------------------------

procedure TThread.WaitFor;
begin
 WaitForSingleObject(FHandle, INFINITE);
end;

//------------------------------------------------------------------------------

end.



 
Leonid Troyanovsky ©   (2011-01-19 22:47) [11]


> DVM ©   (19.01.11 22:39) [9]

> Нету нормального способа сделать метод класса функцией

М.б. оно и не совсем нормально, но MakeObjectInstance делает
примерно такое.
Сейчас главное - на стеке код не размещать :)

--
Regards, LVT.


 
Leonid Troyanovsky ©   (2011-01-19 22:52) [12]


> DVM ©   (19.01.11 22:46) [10]

> не уверен что все ниже верно, неохота вникать, но как то
> так:

Нет охоты вникать, но ОРД оно не спасет, IMHO.

--
Regards, LVT.


 
DVM ©   (2011-01-19 23:04) [13]


> Leonid Troyanovsky ©   (19.01.11 22:52) [12]


> оно не спасет

Да вроде нормально там, стандартный подход использован, по мотивам Classes.Tthread

Работать должно вроде.


 
Leonid Troyanovsky ©   (2011-01-19 23:09) [14]


> DVM ©   (19.01.11 23:04) [13]

> Работать должно вроде

В умелых руках и стеклянный член пригодится.

--
Regards, LVT.


 
начинающий2   (2011-01-19 23:30) [15]


> Leonid Troyanovsky ©   (19.01.11 22:47) [11]

Почему на стеке не размещать? Раньше можно было а сейчас нельзя?


> Leonid Troyanovsky ©   (19.01.11 22:34) [8]


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


 
DVM ©   (2011-01-19 23:32) [16]


> начинающий2   (19.01.11 23:30) [15]


>  Раньше можно было а сейчас нельзя?

Раньше DEP не было.


 
Leonid Troyanovsky ©   (2011-01-19 23:39) [17]


> начинающий2   (19.01.11 23:30) [15]

> Почему на стеке не размещать? Раньше можно было а сейчас
> нельзя?

Т.е., таки размещаем? Ну, и как? Любопытно.

>
>  да это так было сделано лижбы запускался поток.

Дык, а что ж прочитано? Резюм в студию.

--
Regards, LVT.


 
начинающий2   (2011-01-20 00:04) [18]


> Leonid Troyanovsky ©   (19.01.11 23:39) [17]


> Дык, а что ж прочитано? Резюм в студию.

чего то совсем не понял вас... чего нужно то?

вы бы сперва обратили бы внимание на на это > "начинающий2"


 
Leonid Troyanovsky ©   (2011-01-20 07:19) [19]


> начинающий2   (20.01.11 00:04) [18]

> чего то совсем не понял вас... чего нужно то?

Книжку почитать.

--
Regards, LVT.


 
начинающий2   (2011-01-20 08:22) [20]

Удалено модератором


 
Anatoly Podgoretsky ©   (2011-01-20 09:03) [21]

> начинающий2  (20.01.2011 08:22:20)  [20]

Сходи ко мне на сайт и хоть обкачайся этими книжками.


 
начинающий2   (2011-01-20 09:30) [22]


> Anatoly Podgoretsky ©   (20.01.11 09:03) [21]
> > начинающий2  (20.01.2011 08:22:20)  [20]
>
> Сходи ко мне на сайт и хоть обкачайся этими книжками.


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


 
KSergey ©   (2011-01-20 09:49) [23]

> начинающий2   (20.01.11 09:30) [22]
> какой древностью тянет..

Так это не журнал "хакер"
Эти книги не тухнут.


 
Anatoly Podgoretsky ©   (2011-01-20 10:08) [24]

> начинающий2  (20.01.2011 09:30:22)  [22]

Наше дело предложить, ваше отказаться.


 
Игорь Шевченко ©   (2011-01-20 10:27) [25]

начинающий2   (20.01.11 09:30) [22]

lamer vulgaris


 
начинающий2   (2011-01-20 10:48) [26]


> KSergey ©   (20.01.11 09:49) [23]


> Так это не журнал "хакер"
> Эти книги не тухнут.


А при чем здесь этот быдло журнал. Он же просто отстойный слив кто его вообще читает? Не, нет, нет, вспомнил кто его  читает - наш админ, ну так он же полный ... и вообще просто улетевший.


> Anatoly Podgoretsky ©   (20.01.11 10:08) [24]


Нашёл все-таки нужную книЖечку "Многопоточность - как это делается в Дельфи. Мартин Харви  
хоть и дата размещения 18.08.2010 но в самой книге указан год издания Перевод: ©  Борис Новгородов, Новосибирск, 2002 г. С
Ох как долго же она шла ;-)


 
DiamondShark ©   (2011-01-20 11:08) [27]


> пока не наткнутся на DEP

Щито?


 
DiamondShark ©   (2011-01-20 11:11) [28]


> А когда вы последний раз обновляли или чего-нибудь новенького
> добавляли?

Напомни, когда Win32 последний раз обновился, в плане управления потоками?


 
начинающий2   (2011-01-20 11:23) [29]


> DiamondShark ©   (20.01.11 11:11) [28]


> Напомни, когда Win32 последний раз обновился, в плане управления
> потоками?


С выходом новой windows, а вы все еще на старой?
У мну так:
win7 64bit,
6Gb SDRAM DDR-III 1333Mz,
HDD 1T(512Gbx2 Read) speed 200mb/s
Sli NVida 2xGTX-470 - два мощный физик-акселератора

Ну разве не круто?


 
DiamondShark ©   (2011-01-20 12:54) [30]


> начинающий2   (20.01.11 11:23) [29]

Крутотой перед девочками тряси, хотя у слона всё равно длиннее.

Я про Win32 API спрашивал. Как ты думаешь, в части управления потоками, когда и насколько сильно он обновлялся?


 
cwl ©   (2011-01-20 13:29) [31]

> начинающий2   (20.01.11 11:23) [29]
Хочу по пунктам - чиво там изменилось со времён ХР?


 
DVM ©   (2011-01-20 16:51) [32]


> DiamondShark ©   (20.01.11 11:08) [27]
>
> > пока не наткнутся на DEP
>
> Щито?

Что не понятно? Многие способы по превращению метода класса в процедуру вызывают возмущение аппарата DEP и прибиение программы мгновенное. (http://ru.wikipedia.org/wiki/Data_Execution_Prevention)

Например такой:


type
 { .: TMethodToProc :. }
 TMethodToProc = packed record
   popEax: Byte;
   pushSelf: record
     opcode: Byte;
     Self: Pointer;
   end;
   pushEax: Byte;
   jump: record
     opcode: Byte;
     modRm: Byte;
     pTarget: ^Pointer;
     target: Pointer;
   end;
 end;

{ .: MethodToProcedure :. }
function MethodToProcedure(self: TObject; methodAddr: Pointer): Pointer;
var
 mtp: ^TMethodToProc absolute Result;
begin
 New(mtp);
 with mtp^ do
 begin
   popEax := $58;
   pushSelf.opcode := $68;
   pushSelf.Self := Self;
   pushEax := $50;
   jump.opcode := $FF;
   jump.modRm := $25;
   jump.pTarget := @jump.target;
   jump.target := methodAddr;
 end;
end;

...

constructor TWindow.Create;
begin
 inherited Create();
 ...
 WndProcPtr := MethodToProcedure(Self, @TWindow.WndProc);
 ...
end;


Особенно это хорошо проявляется в Windows 2003 Server.


 
han_malign   (2011-01-20 17:15) [33]


> DVM ©
> метода класса в процедуру вызывают возмущение аппарата DEP

- при чем тут DEP и стек, в приведенном вами приеме - должно использоваться VirtualAlloc(..., PAGE_EXECUTE_READWRITE), и все приложения написанные с использованием VCL это делают(с оптимизацией в виде микро-менеджера памяти, чтобы на каждое окно 64К не отжирать) - и все прекрасно везде работает, хоть с DEP, хоть с NX...

В указанном мной приеме - используется документированное правило передачи указателя на экземпляр класса в его метод, я просто не проверил как какое соглашение о вызовах использует обертка BeginThread:
type
 TThreadFunc = function(Parameter: Pointer): Integer;

- то есть, в данном случае(в отличие от CreateThread)  - stdcall нужно убрать и указатель на экземпляр класса, указанный в качестве пользовательского контекста потока, будет спокойно передаваться через EAX в соответствии с соглашением о вызове register и вышеуказанным правилом...


 
DVM ©   (2011-01-20 17:27) [34]


> han_malign   (20.01.11 17:15) [33]


> и все приложения написанные с использованием VCL это делают

Не все, в TService + TServiceApplication так не сделано (процедуры ServiceMain и ServiceController не сделаны методами класса). Кстати, интересно по какой причине.

Собственно, я когда то пытался именно данным способом засунуть их внутрь класса (сделал свои классы TService и TServiceApplication), получил предупреждение от DEP и закрытие приложения. Причем оно возникало не всегда, но регулярно даже в ничего не делающих сервисах.


 
DVM ©   (2011-01-20 17:42) [35]

Кстати, в новых версиях Delphi появилась другой вариант, использовать ключевое слово static:

type
 TMyThread = class
 private
   FHandle: THandle;
   FID: Cardinal;
   class function ThreadProc(Param: Pointer): DWord; stdcall; static;
   function Execute: DWord;
 public
   constructor Create;
   destructor Destroy; override;
 end;

{ TMyThread }

constructor TMyThread.Create;
begin
 IsMultiThread := True;
 FHandle := CreateThread(nil, 0, @ThreadProc, Self, 0, FID);
end;

destructor TMyThread.Destroy;
begin
 CloseHandle(FHandle);
 FHandle := 0;
 FID := 0;
 inherited;
end;

class function TMyThread.ThreadProc(Param: Pointer): DWord;
begin
 Result := TMyThread(Param).Execute;
end;

function TMyThread.Execute: DWord;
begin
 MessageBox(0, "Hello from thread", "Information", MB_OK or MB_ICONINFORMATION);
 Result := 0;
end;


http://www.gunsmoker.ru/2008/12/static-delphi.html


 
han_malign   (2011-01-20 17:44) [36]


> Кстати, интересно по какой причине.

- надо было интересоваться по какой обоснованной причине это было сделано в TWinControl...
А сделано это потому, что единственный нативный способ связать окно с пользовательским контекстом - это SetWindowLong(,GWL_USERDATA,), а это гипотетически могло быть использовано программистом для своих целей(а скорее всего уже кем то использовалось) - поэтому, видимо после долгого разглядывания GWL_xxx, разработчики VCL и обратили внимание на GWL_WNDPROC...


 
han_malign   (2011-01-20 17:50) [37]


> использовать ключевое слово static

- да на здоровье, это все, включая прием с соглашением о передаче параметров - синтаксический сахар...


 
Игорь Шевченко ©   (2011-01-20 17:54) [38]


> А сделано это потому, что единственный нативный способ связать
> окно с пользовательским контекстом - это SetWindowLong(,
> GWL_USERDATA,),


Вовсе не единственный


 
DVM ©   (2011-01-20 17:58) [39]


> han_malign   (20.01.11 17:44) [36]

Здесь то как раз более-менее понятно. И объективная причина есть.


> han_malign   (20.01.11 17:50) [37]


> это все, включая прием с соглашением о передаче параметров
> - синтаксический сахар...

Наверное...сахар. Но именно смотрится лучше.


 
han_malign   (2011-01-20 18:18) [40]


> Вовсе не единственный

- хэш(SetProp/GetProp в том числе), отдельный поток(в VCL :))) - не в счет...



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

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

Наверх




Память: 0.59 MB
Время: 0.01 c
2-1296648381
NieL
2011-02-02 15:06
2011.05.08
Сформировать список


2-1296587747
Тимоха111
2011-02-01 22:15
2011.05.08
копировать массив в другой массив


2-1296650084
Гражданин
2011-02-02 15:34
2011.05.08
Экран


3-1258364954
DelphiN!
2009-11-16 12:49
2011.05.08
Проверка корректности даты в TSQL


2-1296564138
Сергей
2011-02-01 15:42
2011.05.08
Как расширить атрибуты файла?