Вверх ↑
Этот топик читают: Гость
Ответов: 2125
Рейтинг: 159
#16: 2008-05-13 17:23:42 ЛС | профиль | цитата
nesco писал(а):
для обмена сообщениями между своими приложениями

Собственно, DDE это оно и есть

nesco писал(а):
приаттачить к нему обработчик с выводом данных наружу

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

nesco писал(а):
простенький код завалялся по созданию пустых окон

Сначала нужно ответить на вопрос: какое окно нужно child или overlapped?
Control-ы, как я понимаю, в любом случае child, а в твоём случае для начала будут посылаться broadcast-cooбщения, которые обрабатывают окна, не имеющие родителя (то есть принадлежат desktop-у).

nesco писал(а):
Попробовал на CreateWindow, но нифига не получилось создать окно

Странно.
Add(MainForm,3118620,21,105)
{
Left=20
Top=105
link(onCreate,990011:doCreate,[])
}
Add(InlineCode,990011,91,119)
{
WorkPoints=#8:doCreate|
Code=#15:unit HiAsmUnit;|0:|9:interface|0:|29:uses kol,Share,Debug,Windows;|0:|4:type|28: THiAsmClass = class(TDebug)|10: private|17: FWnd:THandle;|4: |9: public|48: procedure doCreate(var dt:TData; idx:word);|5: end;|0:|14:implementation|0:|31:procedure THiAsmClass.doCreate;|5:begin|125: FWnd := CreateWindow('MyWindow','Hello, World!',WS_OVERLAPPEDWINDOW or WS_VISIBLE, 100,100, 200,100, 0, 0, hInstance, nil);|4:end;|0:|83:function MyWndProc(wnd:THandle; wMsg:cardinal; wParam,lParam:DWORD):DWORD; stdcall;|5:begin|50: Result := DefWindowProc(wnd,wMsg,wParam,lParam);|4:end;|0:|29:var MyWindowClass: TWndClass;|0:|14:initialization|0:|50: MyWindowClass.style := CS_HREDRAW or CS_VREDRAW;|42: MyWindowClass.lpfnWndProc := @MyWndProc;|32: MyWindowClass.cbClsExtra := 0;|32: MyWindowClass.cbWndExtra := 0;|39: MyWindowClass.hInstance := hInstance;|27: MyWindowClass.hIcon := 0;|52: MyWindowClass.hCursor := LoadCursor(0, IDC_ARROW);|60: MyWindowClass.hbrBackground := GetStockObject(GRAY_BRUSH);|36: MyWindowClass.lpszMenuName := nil;|44: MyWindowClass.lpszClassName := 'MyWindow';|31: RegisterClass(MyWindowClass);|0:|4:end.|
}

карма: 1

0
Разработчик
Ответов: 26067
Рейтинг: 2121
#17: 2008-05-13 18:51:53 ЛС | профиль | цитата
tsdima, а как можно в твоем примере из обработчика вызвать внешне событие, ведь обработчик не принадлежит классу. В контролах для этой цели передают в независимый обработчик LongInt(Self), для обращения к методам нашего класса. А как это здесь сделать

А про DDE -- всем хорош, но тормознутый слегка, при попытки создать линк тормозит все приложение конкретно.

tsdima писал(а):
а указатели на данные - нельзя

Интересно, а в TCP-модуле это как реализовано, там ссылка на строку передается в качестве параметра созданному пустому окну
------------ Дoбавленo:

А окно я пытался почти также создать, но пустое и скрытое, видимо, что-то упустил.
карма: 22

0
Ответов: 2125
Рейтинг: 159
#18: 2008-05-13 20:15:09 ЛС | профиль | цитата
nesco писал(а):
А как это здесь сделать

Точно также. У окна есть поле для записи произвольного DWORD, записать можно после создания окна:
SetWindowLong(FWnd,GWL_USERDATA,cardinal(Self));

В оконной процедуре можно его считать:
MySelf := THiAsmClass(GetWindowLong(wnd,GWL_USERDATA));
------------ Дoбавленo:

nesco писал(а):
Интересно, а в TCP-модуле это как реализовано

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

nesco писал(а):
видимо, что-то упустил

Со стилями надо было разобраться, небось WS_CHILD воткнул?

карма: 1

1
Голосовали:nesco
Разработчик
Ответов: 26067
Рейтинг: 2121
#19: 2008-05-13 21:15:27 ЛС | профиль | цитата
tsdima писал(а):
WS_CHILD

Да нет WS_POPUP, но без WS_OVERLAPPEDWINDOW

А за SetWindowLong/GetWindowLong спасибо, теперь запомню, как это делается

Еще вопрос -- а можно MyWindowClass не в секции initialization, а в конструкторе класса оформить, вместе с созданием окна? К тому же, я не увидел деструктора окна, разве он не нужен
------------ Дoбавленo:

Да и вот это


Result := DefWindowProc(wnd,wMsg,wParam,lParam);

для чего нужно, объясни пожалуйста.
карма: 22

0
Ответов: 2125
Рейтинг: 159
#20: 2008-05-13 21:17:22 ЛС | профиль | цитата
nesco писал(а):
а можно MyWindowClass не в секции initialization, а в конструкторе класса оформить

Регистрацию класса окна нужно делать только один раз. Можно и в конструкторе, но всё равно придётся сделать глобальный флаг, что регистрация уже была.
Хотя, повторная регистрация тоже ничего плохого не сделает, просто вернёт ошибку, что такой класс уже есть. Но это, ИМХО, плохой стиль, к нему легко привыкнуть, а в других случаях такое может дорого обойтись.

nesco писал(а):
я не увидел деструктора окна, разве он не нужен

В смысле "Где DestroyWindow?"
Ну надо, конечно, в деструкторе нашего класса окно уничтожить, а то будет обращение к несуществующему объекту из оконной процедуры.
Надо ещё отловить сообщение WM_DESTROY и обнулить FWnd, чтобы мы знали, что окна уже нет, в случае, если его крестиком закроют.

карма: 1

0
Разработчик
Ответов: 26067
Рейтинг: 2121
#21: 2008-05-14 00:50:02 ЛС | профиль | цитата
Вот смотри, что получилось



Add(MainForm,3118620,196,252)
{
Left=20
Top=105
Width=341
Height=144
}
Add(InlineCode,990011,343,245)
{
EventPoints=#8:Messages|6:WParam|6:LParam|
Code=#15:unit HiAsmUnit;|0:|9:interface|0:|29:uses Windows,kol,Share,Debug;|0:|4:type|28: THiAsmClass = class(TDebug)|10: private|17: FWnd:THandle;|9: public|24: Messages:THI_Event;|22: WParam:THI_Event;|27: LParam:THI_Event; |24: constructor Create;|34: destructor Destroy; override;|5: end;|0:|14:implementation|0:|83:function MyWndProc(wnd:THandle; wMsg:cardinal; wParam,lParam:DWORD):DWORD; stdcall;|26:var MySelf: THiAsmClass;|5:begin|57: MySelf := THiAsmClass(GetWindowLong(wnd,GWL_USERDATA));|46: _hi_onEvent(MySelf.WParam, integer(wParam));|48: _hi_onEvent(MySelf.LParam, integer(lParam)); |46: _hi_onEvent(MySelf.Messages, integer(wMsg));|50: Result := DefWindowProc(wnd,wMsg,wParam,lParam);|4:end;|0:|31:constructor THiAsmClass.Create;|5:begin|13: inherited;|114: FWnd := CreateWindow('ReceiveMessages','',{WS_OVERLAPPEDWINDOW or }WS_POPUP, 0, 0, 0, 0, 0, 0, hInstance, nil);|51: SetWindowLong(FWnd,GWL_USERDATA,cardinal(Self));|7:end; |0:|31:destructor THiAsmClass.Destroy;|5:begin|31: Windows.DestroyWindow(FWnd);|13: FWnd := 0;|13: inherited;|4:end;|0:|29:var MyWindowClass: TWndClass;|0:|14:initialization|0:|27: MyWindowClass.style := 0;|42: MyWindowClass.lpfnWndProc := @MyWndProc;|32: MyWindowClass.cbClsExtra := 0;|32: MyWindowClass.cbWndExtra := 0;|39: MyWindowClass.hInstance := hInstance;|27: MyWindowClass.hIcon := 0;|29: MyWindowClass.hCursor := 0;|35: MyWindowClass.hbrBackground := 0;|36: MyWindowClass.lpszMenuName := nil;|51: MyWindowClass.lpszClassName := 'ReceiveMessages';|31: RegisterClass(MyWindowClass);|0:|4:end.|
link(Messages,1535947:doCase,[])
link(WParam,11902145:doValue,[(415,258)(415,300)])
link(LParam,13613115:doValue,[(440,265)(440,391)])
}
Add(Button,1802014,196,301)
{
Left=20
Top=20
link(onClick,9300100:doFind,[])
}
Add(FindWindow,9300100,259,301)
{
ClassName="ReceiveMessages"
SkipParam=1
link(onFind,705416:doSendMessage,[(303,307)(303,335)(247,335)(247,363)])
}
Add(SendMessage,705416,259,357)
{
Message=1
WParam=123
LParam=456
link(Handle,9300100:Handle,[])
}
Add(Case,1535947,399,245)
{
Value=Integer(1024)
DataOnTrue=String(WM_USER)
link(onTrue,16042993:doEvent1,[])
}
Add(Edit,10247673,532,252)
{
Left=105
Top=20
Width=185
Text=""
}
Add(Edit,9970630,532,343)
{
Left=105
Top=45
Width=85
Text=""
link(Str,11902145:Value,[])
}
Add(Edit,3141866,532,434)
{
Left=105
Top=70
Width=85
Text=""
link(Str,13613115:Value,[])
}
Add(Memory,11902145,532,294)
{
}
Add(Memory,13613115,532,385)
{
}
Add(Hub,16042993,455,252)
{
OutCount=3
link(onEvent1,10247673:doText,[])
link(onEvent2,9970630:doText,[(509,265)(509,349)])
link(onEvent3,3141866:doText,[(509,272)(509,440)])
}


------------ Дoбавленo:


И еще -- как передавать указатель на строку (в LParam) при выполнении запроса WM_SETTEXT в компоненте SendMessage не применяя дополнительно IC-код, ведь компонент считывает данные типа Integer в LParam. Или этот компонент дорабатывать надо

Вот, что-то типа того проще нельзя сделать



Add(MainForm,3118620,301,245)
{
Left=20
Top=105
Width=341
Height=144
}
Add(Button,1802014,301,301)
{
Left=20
Top=20
link(onClick,9300100:doFind,[])
}
Add(FindWindow,9300100,364,301)
{
ClassName="ReceiveMessage"
SkipParam=1
link(onFind,705416:doSendMessage,[])
}
Add(SendMessage,705416,420,301)
{
Message=10
WParam=-1
link(LParam,7468057:LParam,[])
}
Add(InlineCode,7468057,434,245)
{
VarPoints=#6:LParam|
DataPoints=#4:Text|
Code=#15:unit HiAsmUnit;|0:|9:interface|0:|21:uses kol,Share,Debug;|0:|4:type|28: THiAsmClass = class(TDebug)|10: private|0:|9: public|19: Text:Thi_Event;|50: procedure LParam(var _Data:TData; Index:word);|5: end;|0:|14:implementation|0:|29:procedure THiAsmClass.LParam;|5:begin|57: dtInteger(_Data, Integer(PChar(ToStringEvent(Text))));|8:end; |0:|4:end.|
link(Text,10259976:Value,[])
}
Add(Memory,10259976,434,196)
{
Default=String(123456789)
}


------------ Дoбавленo:


Ну вот к нему и приемник для проверки.



Add(MainForm,3118620,182,231)
{
Left=20
Top=105
Width=341
Height=144
Point(Handle)
}
Add(InlineCode,990011,182,294)
{
EventPoints=#7:Message|6:WParam|6:LParam|
Code=#15:unit HiAsmUnit;|0:|9:interface|0:|29:uses Windows,kol,Share,Debug;|0:|4:type|28: THiAsmClass = class(TDebug)|10: private|17: FWnd:THandle;|9: public|23: Message:THI_Event;|22: WParam:THI_Event;|27: LParam:THI_Event; |24: constructor Create;|34: destructor Destroy; override;|5: end;|0:|14:implementation|0:|83:function MyWndProc(wnd:THandle; wMsg:cardinal; wParam,lParam:DWORD):DWORD; stdcall;|26:var MySelf: THiAsmClass;|5:begin|57: MySelf := THiAsmClass(GetWindowLong(wnd,GWL_USERDATA));|46: _hi_onEvent(MySelf.WParam, integer(wParam));|48: _hi_onEvent(MySelf.LParam, integer(lParam)); |45: _hi_onEvent(MySelf.Message, integer(wMsg));|50: Result := DefWindowProc(wnd,wMsg,wParam,lParam);|4:end;|0:|31:constructor THiAsmClass.Create;|5:begin|13: inherited;|113: FWnd := CreateWindow('ReceiveMessage','',{WS_OVERLAPPEDWINDOW or }WS_POPUP, 0, 0, 0, 0, 0, 0, hInstance, nil);|51: SetWindowLong(FWnd,GWL_USERDATA,cardinal(Self));|7:end; |0:|31:destructor THiAsmClass.Destroy;|5:begin|31: Windows.DestroyWindow(FWnd);|13: FWnd := 0;|13: inherited;|4:end;|0:|29:var MyWindowClass: TWndClass;|0:|14:initialization|0:|27: MyWindowClass.style := 0;|42: MyWindowClass.lpfnWndProc := @MyWndProc;|32: MyWindowClass.cbClsExtra := 0;|32: MyWindowClass.cbWndExtra := 0;|39: MyWindowClass.hInstance := hInstance;|27: MyWindowClass.hIcon := 0;|29: MyWindowClass.hCursor := 0;|35: MyWindowClass.hbrBackground := 0;|36: MyWindowClass.lpszMenuName := nil;|50: MyWindowClass.lpszClassName := 'ReceiveMessage';|31: RegisterClass(MyWindowClass);|0:|4:end.|
link(Message,15312136:doValue,[])
link(WParam,14681702:doValue,[])
link(LParam,12200622:doValue,[])
}
Add(SendMessage,9819632,308,420)
{
Message=10
Point(Message)
link(Handle,13275602:Handle,[])
link(WParam,14681702:Value,[(321,388)(244,388)])
link(LParam,12200622:Value,[(328,380)(293,380)])
link(Message,15312136:Value,[])
}
Add(Memory,15312136,329,294)
{
link(onData,9819632:doSendMessage,[(373,300)(373,363)(296,363)(296,426)])
}
Add(Memory,14681702,238,301)
{
}
Add(Memory,12200622,287,308)
{
}
Add(Label,13275602,301,238)
{
Left=65
Top=20
Width=205
Height=25
Font=[MS Sans Serif,12,1,0,1]
Caption=""
AutoSize=1
Alignment=2
Point(Handle)
}


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


карма: 22

0
Ответов: 2125
Рейтинг: 159
#22: 2008-05-14 13:38:43 ЛС | профиль | цитата
nesco писал(а):
как передавать указатель на строку

nesco писал(а):
можно управлять любыми своими приложениями

Можно, но передавать указатель на строку в другое приложение нельзя, я ж объяснял: в одном приложении по указанному адресу будет твоя строка, а в другом, по этому-же самому адресу - совсем другая информация, т.к. у каждого приложения своё адресное пространство. Есть, конечно, способы (открыть чужой процесс, запросить там память, записать туда информацию и передать адрес в чужом пространстве) и это будет даже работать, но к чему эти сложности?
Для межпроцессных комуникаций есть масса других возможностей, например mailslot-ы (для посылки не очень длинных строк), если сокеты так уж не нравятся.

карма: 1

0
Разработчик
Ответов: 26067
Рейтинг: 2121
#23: 2008-05-14 14:06:35 ЛС | профиль | цитата
tsdima писал(а):
Можно, но передавать указатель на строку в другое приложение нельзя

А я заметил, что можно, но только WM_SETTEXT'ом (похоже, в данном запросе применяется общее пространство памяти). Любой другой не катит. Ты запусти первый пример и приемник, это -- два разных процесса, и увидишь, что при нажатии на кнопку в одном приложении, в другом приложении появится текст.

карма: 22

0
Ответов: 2125
Рейтинг: 159
#24: 2008-05-14 15:02:10 ЛС | профиль | цитата
Да, про WM_SETTEXT винды знают, что это за событие, и какие параметры передаёт. Если потрассируешь, то увидишь, что LParam приходит вовсе не тот, который передаётся. Фактически, винды скопировали строку из одного процесса в другой. Есть ещё WM_GETTEXT и WM_COPYDATA. А вот для WM_USER такое уже не пройдёт.
карма: 1

0
Разработчик
Ответов: 26067
Рейтинг: 2121
#25: 2008-05-14 15:47:03 ЛС | профиль | цитата
tsdima, и тогда, кто мешает это дело применять Надо, просто подкорректировать компоненты под запросы и передавать то, что нужно. У нас получается, что компонент SendMessage какой-то недоделанный -- есть запросы, которые передают указатели, а как получить эти указатели, не сделано.
И вообще, есть смысл сделать компонент ReceiveMessagе и доделать SendMessage, как твое мнение по этому вопросу

На мой взгляд, что очень большое достоинство применения такого метода -- его быстродействие.
карма: 22

0
Ответов: 2125
Рейтинг: 159
#26: 2008-05-14 16:04:29 ЛС | профиль | цитата
nesco писал(а):
как твое мнение по этому вопросу

Моё мнение такое: раз уж WM_COPYDATA как раз и предназначен для передачи данных окну другого приложения, то предлагаю добавить в WinTools точку doCopyData, а в THIWin добавить событие onCopyData, которое получат и контролы, и MainForm и т.п. Можно даже тип данных сохранить, если это возможно. Даже если передаётся Stream, можно его как MemoryStream выдавать.

------------ Дoбавленo:

Проблема только одна: КОЛ не предоставляет обработчика WM_COPYDATA, то есть нужно будет свою оконную процедуру аттачить, а это не всегда нужно.
карма: 1

0
Разработчик
Ответов: 26067
Рейтинг: 2121
#27: 2008-05-14 16:41:13 ЛС | профиль | цитата
tsdima писал(а):
то есть нужно будет свою оконную процедуру аттачить, а это не всегда нужно


И какой из этого положения выход

Ну с эти понятно, можно еще и WM_SETTEXT добавить, тоже полезная штука, а вот что делать с приемником, если не хочется использовать ни один из существуюших контролов. Мне кажется, что создание скрытого окна с обработчиком и выводом данных наружу один из выходов -- потом эти данные можно использовать по своему усмотрению (туда же можно присобачить и обработчик WM_COPYDATA, и не надо в THIWin ничего пихать).
карма: 22

0
Ответов: 2125
Рейтинг: 159
#28: 2008-05-14 18:16:50 ЛС | профиль | цитата
В принципе, скрытое окно ничем не хуже. А если ему ещё и заголовок присвоить, тогда можно несколько штук в схему пихать.
Может оставить WinTools в покое и сделать нормальную пару компонентов клиент-сервер, передающие не только строки, а все имеющиеся в Хиасм типы данных?
карма: 1

0
Разработчик
Ответов: 26067
Рейтинг: 2121
#29: 2008-05-14 18:43:29 ЛС | профиль | цитата
tsdima писал(а):
А если ему ещё и заголовок присвоить

Про заголовое я то же просек, обязательно надо

tsdima писал(а):
а все имеющиеся в Хиасм типы данных

Это которых четыре, или которых целая куча

tsdima писал(а):
сделать нормальную пару компонентов клиент-сервер

И быстродействие (больше всего волнует отклик) этой пары будет гораздо быстрее DDE

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

------------ Дoбавленo:


ИМХО -- идея очень интересная

------------ Дoбавленo:


А может использовать только один запрос WM_SETTEXT, ведь конверторы у нас, типа StrToXXX и XXXToStr, давно уже отлажены, а тип данных передавать в WParam, но это так -- размышления вслух...
карма: 22

0
Ответов: 2125
Рейтинг: 159
#30: 2008-05-14 20:18:17 ЛС | профиль | цитата
nesco писал(а):
Это которых четыре, или которых целая куча

Которых целая куча.

nesco писал(а):
что будет являться сервером, а что клиентом

Сервер, это который обрабатывает запрос, т.е. принимает сообщения, а клиент - который запрос делает, то есть отправляет сообщение.

nesco писал(а):
А может использовать только один запрос WM_SETTEXT, ведь конверторы у нас, типа StrToXXX и XXXToStr, давно уже отлажены

Не, ну можно, конечно, подправить doCaption у WinTools, он ведь тоже из той же оперы (делает SetWindowText), реализовать его через посылку WM_SETTEXT и ограничиться этим.
А "сервер" будет просто реагировать на изменение текста в контроле.

карма: 1

0
Сообщение
...
Прикрепленные файлы
(файлы не залиты)