Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Окошко в отдельном потоке. Как? [D6, WinXP]


Страницы:   1 2

tga ©   (2003-01-23 12:09:00) 

У меня возникла трабла с открытием окна в отдельном потоке программы. Окно создаю вот так:

var
dialog:TForm;
...
dialog := CreateMessageDialog("...",mtConfirmation , [mbYes, mbYesToAll, mbNoToAll, mbNo]);


Если разделение на потоки не делать - то всё работает. А вот в отдельном потоке говорит следующее:
... rised exception class EInvalidOperation with message "Canvas does not allow drawing".

Подскажите как от этой ошибки избавиться.
P/S Работаю на D6 под WinXP


Бурундук   (2003-01-23 17:28:00) [1]

2Digitman © (23.01.03 16:50)

Пробовал (даже в VCL) - но "canvas does not allow drawing" не видел.

В VCL единственно вполне могут быть проблемы с глобальными объектами Application и Screen, в коде которых нет никаких
намёков на возможность использования их в нескольких потоках.

А вот все VCLные гди-манаджеры (FontManager etc), напротив,
выглядят вроде бы (с первого взгляда) вполне потокобезопасно -
все операции защищены критической секцией.

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


vuk   (2003-01-23 17:13:00) [2]

>вот и попробуй создать VCL-форму
Я ж сказал - не VCL. VCL окно создать не получится по той причине, что внутри будут обращения к глобальным объектам типа Application.
А вот на WinAPI - одной левой. Я ж сказал - зуб даю. :o)


unit Unit2;

interface
uses
Windows,
Messages,
sysutils,
Classes;
type
TWndThread = class(TThread)
procedure Execute; override;
end;
implementation

{ TWndThread }

function WindowProc(hWnd: THandle; uMsg, wParam, lParam: Integer): Integer;
stdcall;
procedure HandleWMPaint;
var
DC : HDC;
PS : TPaintStruct;
s : string;
begin
DC := BeginPaint(hWnd, PS );
Ellipse(DC, 0, 0, 100, 50);
s := FormatDateTime("hh:nn:ss", Now);
TextOut(DC, 20, 15, PChar(s), length(s) );
EndPaint(hWnd, PS);
end;
begin
Result := 0;
case uMsg of
WM_DESTROY:
PostQuitMessage(0);
WM_PAINT: HandleWMPaint;
WM_TIMER: RedrawWindow(hWND, nil, 0, RDW_INVALIDATE);
end;
Result := DefWindowProc(hWnd, uMsg, wParam, lParam);
end;


procedure TWndThread.Execute;
var
hWnd: THandle;
WndClass: TWndClass;
Msg: TMsg;
const
sClassName = "MyWND";
begin
FillChar(WndClass, SizeOf(WndClass), 0);
with WndClass do
begin
hInstance := hInstance;
lpszClassName := sClassName;
lpfnWndProc := @WindowProc;
hbrBackground := GetStockObject(LTGRAY_BRUSH);
end;
Windows.RegisterClass(WndClass);
hWnd := CreateWindow(sClassName, "", WS_OVERLAPPEDWINDOW, 200, 200, 300, 300, 0, 0, hInstance, nil);
if hWnd = 0 then
Exit;
ShowWindow(hWnd, SW_normal);
UpdateWindow(HWND);
//таймер будет имитировать бурную деятельность
SetTimer(HWND, 1, 1000, nil );
while GetMessage(Msg, 0, 0, 0) do
begin
if msg.message = WM_QUIT then
break;
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
KillTimer(HWND, 1);

end;

end.




Digitman   (2003-01-23 16:50:00) [3]

вот и попробуй создать VCL-форму в доп.потоке (чем не окно ?), организовать цикл приема и диспетчеризации сообщений ("рисующие" обработчики сообщений уже есть в объекте-форме) и тут же установить св-во Visible=True )

Чем такая схема отличается от организации того же средствами WinAPI ? Ничем. Окно индивидуально для потока, ни один другой поток не обращается к форме. Однако, "canvas does not allow drawing", надеюсь, ты увидишь)


vuk   (2003-01-23 16:33:00) [4]

>смотря что в обработчике WM_PAINT ты делать будешь
Рисовать, понятное дело. На DC.


Digitman   (2003-01-23 16:31:00) [5]

смотря что в обработчике WM_PAINT ты делать будешь)


vuk   (2003-01-23 16:22:00) [6]

>а об окнах, с которыми ассоциированы неразделяемые GDI-ресурсы
Хотите сказать, что я в отдельном потоке WM_PAINT не отработаю? :o)


Digitman   (2003-01-23 16:20:00) [7]

конечно, может) ... я и не отрицаю.
Любой код.поток может собственное создать окно и получать адресованные этому окну сообщения.
но я - не об окнах как приемниках сообщений ! а об окнах, с которыми ассоциированы неразделяемые GDI-ресурсы


vuk   (2003-01-23 16:02:00) [8]

>а что, по-твоему, здесь явно противоречит истине ?
Истине противоречит то, что окно (не VCL) в отдельном потоке жить может. Зуб даю. :o)


Digitman   (2003-01-23 15:54:00) [9]

а что, по-твоему, здесь явно противоречит истине ?


vuk   (2003-01-23 15:31:00) [10]

Я немного не про то, похоже не совсем то процитировал, что нужно. Моя вина.
Вы совершенно правы, DC окна для той же отрисовки существует только на период отработки WM_PAINT, а оно отрабатывается только в том потоке, который создал окно.

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


Digitman   (2003-01-23 15:20:00) [11]


> vuk


Мало ли какие ограничения в VCL ! Я не о них. Это само собой разумеется.

Ты хочешь сказать, что если в обработчиках оконных сообщений в двух или более код.потоках будет одновременно выполнена, скажем, та же SetTextColor() с одним и тем же hDC, то - никаких проблем ? И Win32 сериализует вызовы, непосредственно модифирующие поверхность ??

Убеди меня в этом.


vuk   (2003-01-23 14:37:00) [12]

to DigitmanL
>GDI-ресурсы - неразделяемые, запрос/обращение/освобождение их
>должно осуществляться в осн.код.потоке процесса
Не совсем так. Ограничение на работу с интерфейсом в одном потоке - это ограничение VCL, а не Windows. Если создать средствами WinAPI окно в отдельном потоке и расписать там же цикл обработки сообщений, то все замечательно будет жить.


Digitman   (2003-01-23 13:06:00) [13]

лучше вообще отказаться от непосредственной работы с объектами интерфейса в доп.код.потоке.

это не его задача.

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


tga   (2003-01-23 12:44:00) [14]

ага...
т.е. достаточно создавать объекты интерфейса в главном потоке, а их использование (вызов методов) исполнять через TThread.Synchronize() и всё должно работать , так? :)))

по хелпу похоже что так... :))


Digitman   (2003-01-23 12:37:00) [15]

см. > MBo © (23.01.03 12:27)

И не мог не поставить. Потому как басню "лебедь, рак и щука" наверняка читал.

Лебедь- 1-й поток процесса
Рак - 2-й поток процесса
Щука - 3-й поток процесса

Каждый из потоков параллельно (!), согласно твоей "парадигме" пытается тащить "воз" в свою сторону : один хочет нарисовать точку с координатами (0,0), другой - стереть, третий цвет изменить. И все это - одновременно !?

Вот MS и сказал разработчикам : буду исполнять такие команды последовательно для каждого процесса, а слушать буду только команды осн.потока каждого процесса. Кто не подчинится - хрен тому, а не "воз"))))


tga   (2003-01-23 12:34:00) [16]

Ух мужики!!!
вот так уже понятней :))

Я проблему немного подругому решил -
1 перед запуском потока создаю окошко и ссылочку запоминаю
2 в потоке его показываю
3 по завершении поток - грохаю окно...

работает, только вот "отображение" этого окна (исходяиз того что сказал Digitman ) нужно так-же синхронизировать, а вот с чем его синхронизировать я пока понять не могу...


MBo   (2003-01-23 12:27:00) [17]

>но такого долженствования никто в парадигмы параллельного программирования не ставил...
Microsoft ставил...


Digitman   (2003-01-23 12:26:00) [18]


> как это так должны?


А вот так !
Пользовательский интерфейс требует как минимум GDI-ресурсы системы
GDI-ресурсы - неразделяемые, запрос/обращение/освобождение их должно осуществляться в осн.код.потоке процесса
В VCL это делается через методы/св-ва объектов, скрыто работающих с этими ресурсами
Отсюда вывод : обращайся к методам/св-вам таких объектов ТОЛЬКО в осн.код.потоке

Таким объектом в дан.случае явл-ся MessageDialog, ты создаешь и пользуешь его не в осн., а в доп.потоке, вот тебе и "грабли")

Синхронизируй вызов CreateMessageDialog() с сообщениями окна осн.потока. См. TThread.Synchronize()


Reindeer Moss Eater   (2003-01-23 12:24:00) [19]

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


tga   (2003-01-23 12:18:00) [20]

Странный ответ.... как это так должны ?
Ты не обижайся - но такого долженствования никто в парадигмы параллельного программирования не ставил... в том чисе и для D6.


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо