Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 2011.05.08;
Скачать: [xml.tar.bz2];

Вниз

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

 
начинающий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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.58 MB
Время: 0.005 c
15-1295853671
usrg
2011-01-24 10:21
2011.05.08
Вопрос о приобретении EhLib


2-1296592407
Тимоха111
2011-02-01 23:33
2011.05.08
ошибка AV при получении динамического массива из длл


15-1296070554
Super XML
2011-01-26 22:35
2011.05.08
Сравнение XML


11-1234297339
alex649
2009-02-10 23:22
2011.05.08
исчезает текст обработчика событий в Д7 при кпопытке компиляции


15-1295645386
Юрий
2011-01-22 00:29
2011.05.08
С днем рождения ! 22 января 2011 суббота





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский