Форум: "WinAPI";
Текущий архив: 2006.06.04;
Скачать: [xml.tar.bz2];
ВнизGetMessage в отдельном потоке Найти похожие ветки
← →
Crash Coredump © (2006-03-09 19:12) [40]Eraser © (09.03.06 18:57) [38]
Мне не хочешь верить, может, Рихтеру поверишь, который Джеффри:
"When a worker thread sends a message to your window, the SendMessage function internally queues up the message for the window, and then the worker thread suspends itself. The next time the user-interface thread calls GetMessage, PeekMessage, or WaitMessage, it sees the queued sent message, pulls it from the queue, and processes the window"s window procedure. "
http://www.microsoft.com/msj/1197/win321197.aspx
← →
Leonid Troyanovsky © (2006-03-09 19:28) [41]
> Crash Coredump © (09.03.06 18:51) [34]
> потока. Вот честно, не проверял, будут ли обрабатываться
> сообщения, если поток будет ждать какого-нибудь объекта
> ядра функцией WaitForSingleObject, а что Рихтер на эту тему
> писал, не помню.
Я, конечно, тоже не помню, но работоспособный цикл
можно построить на основе MsgWaitForMultipleObjects + PeekMessage.
Или WaitMessages + PeekMessage.
--
Regards, LVT.
← →
Eraser © (2006-03-09 21:02) [42]
> Crash Coredump © (09.03.06 19:12) [40]
к чему ты вообще тут WaitMessage приплёл... сабж не про это.
> Leonid Troyanovsky © (09.03.06 19:28) [41]
именно. обычно WaitMessage применяют балансировки нагрузки. И то довольно редко... видел применение только один раз - в WinVNC.
← →
Игорь Шевченко © (2006-03-09 21:14) [43]Eraser © (09.03.06 21:02) [42]
> обычно WaitMessage применяют балансировки нагрузки
Это как ? Расскажи, интересно.
Совет - спорь кодом, аргумент неубиенный. И эта..."будьте вежливы".
← →
Eraser © (2006-03-09 21:29) [44]
> Игорь Шевченко © (09.03.06 21:14) [43]
> Совет - спорь кодом, аргумент неубиенный.
vncDesktopThread::run_undetached(void *arg)
{
// Save the thread"s "home" desktop, under NT (no effect under 9x)
HDESK home_desktop = GetThreadDesktop(GetCurrentThreadId());
// Attempt to initialise and return success or failure
if (!m_desktop->Startup())
{
vncService::SelectHDESK(home_desktop);
ReturnVal(FALSE);
return NULL;
}
// Grab the initial display contents
// *** m_desktop->m_buffer.GrabRegion(m_desktop->m_bmrect);
// *** m_desktop->m_buffer.Clear(m_desktop->m_bmrect);
// Succeeded to initialise ok
ReturnVal(TRUE);
// START PROCESSING DESKTOP MESSAGES
// We set a flag inside the desktop handler here, to indicate it"s now safe
// to handle clipboard messages
m_desktop->SetClipboardActive(TRUE);
// All changes in the state of the display are stored in a local
// UpdateTracker object, and are flushed to the vncServer whenever
// client updates are about to be triggered
rfb::SimpleUpdateTracker clipped_updates;
rfb::ClippedUpdateTracker updates(clipped_updates, m_desktop->m_bmrect);
clipped_updates.enable_copyrect(true);
// Incoming update messages are collated into a single region cache
// The region cache areas are checked for changes before an update
// is triggered, and the changed areas are passed to the UpdateTracker
rfb::Region2D rgncache = m_desktop->m_bmrect;
// The previous cursor position is stored, to allow us to erase the
// old instance whenever it moves.
rfb::Point oldcursorpos;
// Set the hook thread to a high priority
// *** set_priority(omni_thread::PRIORITY_HIGH);
BOOL idle_skip = TRUE;
ULONG idle_skip_count = 0;
MSG msg;
while (TRUE)
{
if (!PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE)) {
//
// - MESSAGE QUEUE EMPTY
// Whenever the message queue becomes empty, we check to see whether
// there are updates to be passed to clients.
if (idle_skip) {
idle_skip = FALSE;
if (idle_skip_count++ < 4) {
Sleep(5);
continue;
}
}
idle_skip_count = 0;
// Clear the triggered flag
m_desktop->m_update_triggered = FALSE;
//
// CHECK SCREEN FORMAT
// First, we must check that the screen hasnt changed too much.
if (m_desktop->m_displaychanged || !vncService::InputDesktopSelected())
{
rfbServerInitMsg oldscrinfo = m_desktop->m_scrinfo;
m_desktop->m_displaychanged = FALSE;
// Attempt to close the old hooks
if (!m_desktop->Shutdown())
{
m_server->KillAuthClients();
break;
}
// Now attempt to re-install them!
if (!m_desktop->Startup())
{
m_server->KillAuthClients();
break;
}
// Check that the screen info hasn"t changed
vnclog.Print(LL_INTINFO, VNCLOG("SCR: old screen format %dx%dx%d\n"),
oldscrinfo.framebufferWidth,
oldscrinfo.framebufferHeight,
oldscrinfo.format.bitsPerPixel);
vnclog.Print(LL_INTINFO, VNCLOG("SCR: new screen format %dx%dx%d\n"),
m_desktop->m_scrinfo.framebufferWidth,
m_desktop->m_scrinfo.framebufferHeight,
m_desktop->m_scrinfo.format.bitsPerPixel);
if ((m_desktop->m_scrinfo.framebufferWidth != oldscrinfo.framebufferWidth) ||
(m_desktop->m_scrinfo.framebufferHeight != oldscrinfo.framebufferHeight))
{
m_server->KillAuthClients();
break;
} else if (memcmp(&m_desktop->m_scrinfo.format, &oldscrinfo.format, sizeof(rfbPixelFormat)) != 0)
{
m_server->UpdateLocalFormat();
}
// Adjust the UpdateTracker clip region
updates.set_clip_region(m_desktop->m_bmrect);
// Add a full screen update to all the clients
rgncache = rgncache.union_(rfb::Region2D(m_desktop->m_bmrect));
m_server->UpdatePalette();
}
//
// CALCULATE CHANGES
//
if (m_desktop->m_server->UpdateWanted())
{
// POLL PROBLEM AREAS
// We add specific areas of the screen to the region cache,
// causing them to be fetched for processing.
if (m_desktop->m_server->PollFullScreen())
{
rfb::Rect rect = m_desktop->m_qtrscreen;
rect = rect.translate(rfb::Point(0, m_desktop->m_pollingcycle * m_desktop->m_qtrscreen.br.y));
rgncache = rgncache.union_(rfb::Region2D(rect));
m_desktop->m_pollingcycle = (m_desktop->m_pollingcycle + 1) % 4;
}
if (m_desktop->m_server->PollForeground())
{
// Get the window rectangle for the currently selected window
HWND hwnd = GetForegroundWindow();
if (hwnd != NULL)
PollWindow(rgncache, hwnd);
}
if (m_desktop->m_server->PollUnderCursor())
{
// Find the mouse position
POINT mousepos;
if (GetCursorPos(&mousepos))
{
// Find the window under the mouse
HWND hwnd = WindowFromPoint(mousepos);
if (hwnd != NULL)
PollWindow(rgncache, hwnd);
}
}
← →
Eraser © (2006-03-09 21:29) [45]
// PROCESS THE MOUSE POINTER
// Some of the hard work is done in clients, some here
// This code fetches the desktop under the old pointer position
// but the client is responsible for actually encoding and sending
// it when required.
// This code also renders the pointer and saves the rendered position
// Clients include this when rendering updates.
// The code is complicated in this way because we wish to avoid
// rendering parts of the screen the mouse moved through between
// client updates, since in practice they will probably not have changed.
// Re-render the mouse"s old location if it"s moved
BOOL cursormoved = FALSE;
POINT cursorpos;
if (GetCursorPos(&cursorpos) &&
((cursorpos.x != oldcursorpos.x) ||
(cursorpos.y != oldcursorpos.y))) {
cursormoved = TRUE;
oldcursorpos = rfb::Point(cursorpos);
}
if (cursormoved) {
if (!m_desktop->m_cursorpos.is_empty())
rgncache = rgncache.union_(rfb::Region2D(m_desktop->m_cursorpos));
}
{
// Prevent any clients from accessing the Buffer
omni_mutex_lock l(m_desktop->m_update_lock);
// CHECK FOR COPYRECTS
// This actually just checks where the Foreground window is
m_desktop->CalcCopyRects(updates);
// GRAB THE DISPLAY
// Fetch data from the display to our display cache.
m_desktop->m_buffer.GrabRegion(rgncache);
// Render the mouse
m_desktop->m_buffer.GrabMouse();
if (cursormoved) {
// Inform clients that it has moved
m_desktop->m_server->UpdateMouse();
// Get the buffer to fetch the pointer bitmap
if (!m_desktop->m_cursorpos.is_empty())
rgncache = rgncache.union_(rfb::Region2D(m_desktop->m_cursorpos));
}
// SCAN THE CHANGED REGION FOR ACTUAL CHANGES
// The hooks return hints as to areas that may have changed.
// We check the suggested areas, and just send the ones that
// have actually changed.
// Note that we deliberately don"t check the copyrect destination
// here, to reduce the overhead & the likelihood of corrupting the
// backbuffer contents.
rfb::Region2D checkrgn = rgncache.subtract(clipped_updates.get_copied_region());
rgncache = clipped_updates.get_copied_region();
rfb::Region2D changedrgn;
m_desktop->m_buffer.CheckRegion(changedrgn, checkrgn);
// FLUSH UPDATES TO CLIENTS
// Add the bits that have really changed to their update regions
// Note that the cursor is NOT included - they must do that
// themselves, for the reasons above.
// This call implicitly kicks clients to update themselves
updates.add_changed(changedrgn);
clipped_updates.get_update(m_server->GetUpdateTracker());
}
// Clear the update tracker and region cache
clipped_updates.clear();
}
// Now wait for more messages to be queued
if (!WaitMessage()) {
vnclog.Print(LL_INTERR, VNCLOG("WaitMessage() failed\n"));
break;
весь код VNC приводить не буду ... много там )
> И эта..."будьте вежливы".
я и так вежлив, особенно когда со мной спорят не ради спора, а по сабжу )
← →
Игорь Шевченко © (2006-03-09 21:55) [46]Eraser © (09.03.06 21:29) [44]
Eraser © (09.03.06 21:29) [45]
> весь код VNC приводить не буду
Надо приводить код Windows.
А этот код ты зачем привел ?
> по сабжу
А по сабжу все сказано в посте [1]
С потоком в данной ситуации надо обмениваться через Post[Thread]Message
← →
Eraser © (2006-03-09 22:03) [47]
> Игорь Шевченко © (09.03.06 21:55) [46]
в [1] автор прав насчёт RTFM - согласен - это никогда не лишнее )
PostThreadMessage однако он не упаминул.. ну да Бог с ним с PostThreadMessage.
Далее ведь тов. Crash Coredump начал доказывать, что Get/PeekMessage не нужна в доп. потоке.
Crash Coredump © (09.03.06 16:08) [5]
Не ту справку читаешь, почитай еще. Сообщения по SendMessage никогда не будут выбраны вызовом GetMessage
на что Сергей М. вполне резонно заметил
Бред сивой кобылы.
:-)
> Надо приводить код Windows.
а где его взять? )
вот по этой теме хорошая ветка
http://www.rsdn.ru/Forum/Message.aspx?mid=1410117
← →
Игорь Шевченко © (2006-03-09 22:18) [48]Eraser © (09.03.06 22:03) [47]
> Сообщения по SendMessage никогда не будут выбраны вызовом
> GetMessage
Так, как ожидает автор (см. сабж) они выбраны не будут, разумеется. Автор (см. сабж), ожидает, что после того, как он послал окну сообщение, у него функция GetMessage возвратит результат.
А про то, как обрабатываются сообщения на самом деле, и автор поста [1] и я знаем довольно неплохо :)
Впрочем, окончательную точку ставит MSDN (VS 2005 beta 2)
"The GetMessage function retrieves a message from the calling thread"s message queue. The function dispatches incoming sent messages until a posted message is available for retrieval.
....
During this call, the system delivers pending messages that were sent to windows owned by the calling thread using the SendMessage, SendMessageCallback, SendMessageTimeout, or SendNotifyMessage function. The system may also process internal events. Messages are processed in the following order:
Sent messages
Posted messages
Input (hardware) messages and system internal events
Sent messages (again)
WM_PAINT messages
WM_TIMER messages "
в отличие от Win32.Hlp
"he GetMessage function retrieves a message from the calling thread"s message queue and places it in the specified structure. This function can retrieve both messages associated with a specified window and thread messages posted via the PostThreadMessage function. The function retrieves messages that lie within a specified range of message values. GetMessage does not retrieve messages for windows that belong to other threads or applications"
← →
Eraser © (2006-03-09 22:31) [49]
> Игорь Шевченко © (09.03.06 22:18) [48]
> GetMessage does not retrieve messages for windows that belong
> to other threads or applications"
странно.. не обращал внимание на этот ляп )
пользуюсь тоже MSDN.
> А про то, как обрабатываются сообщения на самом деле, и
> автор поста [1] и я знаем довольно неплохо :)
ну что ж... раз вы говорите, что тот товарисч вкурсе - приму на веру...
однако с формулировками по осторожнее быть надо.. а то тов. Crash Coredump раза 3 упамянул, что
> Сообщения по SendMessage никогда не будут выбраны вызовом
> GetMessage
...
← →
Игорь Шевченко © (2006-03-09 22:42) [50]Eraser © (09.03.06 22:31) [49]
Они будут, согласно MSDN, отдиспетчированы - непосредственно переданы оконной процедуре нужного окна. Но при этом GetMessage не закончит своего выполнения как того ожидает автор. Поэтому ему в данном случае лучше выполнять PostMessage, а для конкретного примера в [0] и вовсе PostQuitMessage.
Я советую кроме MSDN еще исходниками пользоваться. Например, ReactOS. Поскольку они ставят своей целью совместимость с Windows, то их исходники можно рассматривать, как отправную точку для углубленных знаний.
Из их исходников видно, что GetMessage (NtUserGetMessage), если в очереди потока нет сообщений, вызывает внутреннюю функцию WaitMessage, которая и осуществляет диспетчеризацию Sent-сообщений - это к спору о WaitMessage :)
← →
Eraser © (2006-03-09 22:50) [51]
> Игорь Шевченко © (09.03.06 22:42) [50]
> Из их исходников видно, что GetMessage (NtUserGetMessage),
> если в очереди потока нет сообщений, вызывает внутреннюю
> функцию WaitMessage, которая и осуществляет диспетчеризацию
> Sent-сообщений - это к спору о WaitMessage :)
ну я подозоевал, что-то вроде
while(true)
{
WaitMessage();
if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)
{
if(msg.message==WM_QUIT) break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
а исходники ReactOS доступны всем для скачивания?
ссылочку можно? )
← →
Игорь Шевченко © (2006-03-09 23:05) [52]Eraser © (09.03.06 22:50) [51]
Сначала проверка очереди, если пусто, то проверка, доставка и очистка Sent-сообщений, затем WaitMessage
> а исходники ReactOS доступны всем для скачивания?
> ссылочку можно? )
http://www.reactos.org
← →
Eraser © (2006-03-09 23:27) [53]
> Игорь Шевченко © (09.03.06 23:05) [52]
выделю трафик.. скачаю.
интересно однако:)
← →
Игорь Шевченко © (2006-03-09 23:31) [54]Eraser © (09.03.06 23:27) [53]
На самом деле интересно, так как дает представление о том, как реализуется поведение тех или иных функций Windows. Кроме того, если по механизмам ядра написана отличная книжка Руссиновича и Соломона, то по части оконной подсистемы довольно большое белое пятно. Даже по механизмам GDI написана книжка Фэня Юаня, а по USER и его ядерной части в Win32k.sys я ничего не видел.
← →
Leonid Troyanovsky © (2006-03-10 08:33) [55]
> Eraser © (09.03.06 22:50) [51]
> WaitMessage();
> if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)
Скорее уж while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)
--
Regards, LVT.
← →
msg (2006-03-10 12:45) [56]Ага, GetMessage действительно нужен, потому, что если
while GetMessage(Msg,wnd,0,0) do
begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
заменить на
while true do
sleep(1);
в оконную процедуру сообщение не передается, понял.
ранее SendMessage пытался заменить на PostMessage, но GetMessage управление всеравно не возвращала, щас возвращает... фиг с ним, спишем на собственную невнимательность.
С поведением GetMessage при PostMessage и SendMessage более менее разобрался.
Заметил еще одну интересную особенность, оконная процедура, при SendMessage(WM_QUIT) получает сообщение с кодом 18(WM_QUIT), а при PostMessage(WM_QUIT) оконная процедура получает два сообщения 2(WM_DESTROY) и 130(WM_NCDESTROY).
Теперь есть непонятки с PostQuitMessage, если ее вызываю в оконной процедуре в ответ на WM_DESTROY(PostMessage) или WM_QUIT(SendMessage), GetMessage возвращает управление, мы выходим из цикла...
Если же написать:
type
TTest=class(TThread)
...
public
Procedure ExitTest;
...
implementation
procedure TTest.ExitTest;
begin
PostQuitMessage(0);
end;
и из основного потока вызвать ExitTest:
T.ExitTest;
то мы вываливаемся из программы (т.е. завершает работу основной поток), почему? в справке написано:
Функция PostQuitMessage указывает Windows, что ПОТОК (в нашем случае не основной) послал запрос на завершение (выход).
← →
Сергей М. © (2006-03-10 12:49) [57]
> ПОТОК (в нашем случае не основной)
Ну как же не основной-то ?
Сам же говоришь , что
> и из основного потока вызвать ExitTest
← →
Crash Coredump © (2006-03-10 12:50) [58]
> и из основного потока вызвать ExitTest:
>
> T.ExitTest;
То процедура будет выполнена в контексте основного потока, что неудивительно.
msg (10.03.06 12:45) [56]
А что ты вообще хочешь сделать, если не секрет, в связи с чем вопрос ?
Может есть готовое решение.
← →
msg (2006-03-10 14:58) [59]Сергей М., Crash Coredump
а, да, точно, понял. этот вопрос снят.
Crash Coredump
Если вы спрашиваете о T.ExitTest;, то это просто эксперимент.
А вообще задача такая: есть консольное приложение в момент работы оно должно принимать и обрабатывать ряд команд данных сторонними программами. Т.е., к примеру, примерно так будет выглядеть команда моей программе из стороннего процесса:
const
WM_ASDASD_COMMAND = WM_USER + 3;
_ASDASD_TEST = 1;
...
h := FindWindow("asdasd", nil);
SendMessage(h, WM_ASDASD_COMMAND, _ASDASD_TEST, 0);
← →
Сергей М. © (2006-03-10 15:02) [60]
> msg (10.03.06 14:58) [59]
Насколько принципиален при решении этой задачи отказ от борландовских классов в пользу "чистого WinAPI" ?
← →
Сергей М. © (2006-03-10 15:03) [61]
> msg
Ведь так или иначе классы ты задействуешь, коль скоро задействовал TThread ..
← →
Leonid Troyanovsky © (2006-03-10 15:19) [62]
> msg (10.03.06 14:58) [59]
> А вообще задача такая: есть консольное приложение в момент
> работы оно должно принимать и обрабатывать ряд команд данных
> сторонними программами. Т.е., к примеру, примерно так будет
> выглядеть команда моей программе из стороннего процесса:
Для взаимодействия с консольным приложением можно взять, например,
pipes, memory mapped files, APC & etc.
Ну, а если уж так хочется GUI-thread можно, например,
http://www.rsdn.ru/Forum/?mid=883505
только, пользы от конгуевых гибридов значительно меньше.
--
Regards, LVT.
← →
Crash Coredump © (2006-03-10 15:32) [63]msg (10.03.06 14:58) [59]
> А вообще задача такая: есть консольное приложение в момент
> работы оно должно принимать и обрабатывать ряд команд данных
> сторонними программами. Т.е., к примеру, примерно так будет
> выглядеть команда моей программе из стороннего процесса
Не обязательно консольное:unit WorkerMain;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
type
TfWorker = class(TForm)
procedure FormCreate(Sender: TObject);
public
procedure DefaultHandler(var Message); override;
end;
var
fWorker: TfWorker;
implementation
uses
WorkerMessages;
{$R *.DFM}
{ TfWorker }
{ TfWorker }
procedure TfWorker.DefaultHandler(var Message);
begin
with TMessage(Message) do
if Msg = UM_WORKER1 then
MessageBeep (0)
else if Msg = UM_WORKER2 then
MessageBox(0, "message 2", "Worker", MB_OK)
else
inherited;
end;
procedure TfWorker.FormCreate(Sender: TObject);
begin
Application.ShowMainForm := false;
ShowWindow (Application.Handle, SW_HIDE);
end;
end.unit WorkerMessages;
interface
uses
Messages;
const
UM_WORKER1 = WM_USER + 100;
UM_WORKER2 = WM_USER + 101;
implementation
end.
Это один EXEшник.unit ControlMain;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ActnList;
type
TfWorkerControl = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
ActionList: TActionList;
actMessage1: TAction;
actMessage2: TAction;
actTerminate: TAction;
procedure FormCreate(Sender: TObject);
procedure ActionListUpdate(Action: TBasicAction; var Handled: Boolean);
procedure actMessage1Execute(Sender: TObject);
procedure actMessage2Execute(Sender: TObject);
procedure actTerminateExecute(Sender: TObject);
private
FWorkerWnd: HWND;
end;
var
fWorkerControl: TfWorkerControl;
implementation
uses
WorkerMessages;
{$R *.DFM}
procedure TfWorkerControl.FormCreate(Sender: TObject);
begin
FWorkerWnd := FindWindow ("TfWorker", "fWorker");
end;
procedure TfWorkerControl.ActionListUpdate(Action: TBasicAction;
var Handled: Boolean);
begin
actMessage1.Enabled := IsWindow(FWorkerWnd);
actMessage2.Enabled := IsWindow(FWorkerWnd);
actTerminate.Enabled := IsWindow(FWorkerWnd);
end;
procedure TfWorkerControl.actMessage1Execute(Sender: TObject);
begin
SendMessage(FWorkerWnd, UM_WORKER1, 0, 0);
end;
procedure TfWorkerControl.actMessage2Execute(Sender: TObject);
begin
SendMessage(FWorkerWnd, UM_WORKER2, 0, 0);
end;
procedure TfWorkerControl.actTerminateExecute(Sender: TObject);
begin
PostMessage(FWorkerWnd, WM_CLOSE, 0, 0);
end;
end.
Это второй EXEшник - та самая стороняя программа
← →
msg (2006-03-10 17:37) [64]Сергей М.
несомненно, VCL-ные библиотеки используются, но дело все в том, что само приложение мало по килобайтам, поэтому просто не хотелось бы его "утяжелять" использованием к примеру таких модулей как: Controls, Forms, Menus, Dialogs ...
Leonid Troyanovsky
В данном случае команды оч. простые и даже если будет какое-то расширение команд, ничего сложного не будет, максимум передача строки(пути), но эта проблема решается в моем случае с помощью CopyDataStruct, так же ни когда не потребуется удаленное управление. В связи с этим есть желание cделать все настолько просто, насколько это возможно (легче отлаживать, писать приложение(я) отдающее(ие) команды, модифицировать...).
а к примеру с тем же MMF надо решать проблему отслеживания изменившейся/пополнившейся информации, проблему синхронизации приложений, структуры размещаемой информации и пр.
AllocateHWND, ага, что может быть проще, вот только бы еще класс окна можно было бы определять самому.
Crash Coredump
Это понятно. Так бы и сделал если бы было бы гуишное приложение, но у консоли то ведь нет своей очереди оконных сообщений...
← →
Leonid Troyanovsky © (2006-03-10 18:19) [65]
> msg (10.03.06 17:37) [64]
> В данном случае команды оч. простые и даже если будет какое-
> то расширение команд, ничего сложного не будет, максимум
> передача строки(пути), но эта проблема решается в моем случае
> с помощью CopyDataStruct, так же ни когда не потребуется
> удаленное управление. В связи с этим есть желание cделать
> все настолько просто, насколько это возможно (легче отлаживать,
> писать приложение(я) отдающее(ие) команды, модифицировать.
> ..).
С помощью mmf оно решается не сложней.
Дополнительно потребуется лишь (тоже именованные) mutex и, возможно,
event (CreateEvent).
Читатель ждет (периодически проверяет) состояние event, и при
сигнале читает проекцию файла. Писатель пишет и устанавливает
событие по окончанию. Всякое чтение-запись в проекцию начинается
с захвата мьютекса и завершается его release. Вот, собс-но, и все.
Отладить оное взамодействие можно в обычном гуевом приложении
с кодом консоли, вынесенным в поток.
Т.е., для консольного приложения - это самое то, ничего лишнего
и громоздкого (включая TThread ;).
--
Regards, LVT.
← →
Leonid Troyanovsky © (2006-03-10 18:32) [66]
> msg (10.03.06 17:37) [64]
> AllocateHWND, ага, что может быть проще, вот только бы еще
> класс окна можно было бы определять самому.
Особенной нужды в этом нет. Для того, чтобы его можно было проще
найти среди дельфирожденных окон ему можно сделать SetWindowText
or SetProp с уникальным идентификатором.
Хотя, конечно, возможно, что лучше его сделать Message-Only Window
(see SetParent with HWND_MESSAGE)
--
Regards, LVT.
← →
Игорь Шевченко © (2006-03-10 20:42) [67]
> Так бы и сделал если бы было бы гуишное приложение, но у
> консоли то ведь нет своей очереди оконных сообщений...
А что, консоль является необходимым внешним условием ?
← →
msg (2006-03-10 21:21) [68]>Читатель ждет (периодически проверяет) состояние event, и при
>сигнале читает проекцию файла. Писатель пишет и устанавливает
>событие по окончанию. Всякое чтение-запись в проекцию начинается
>с захвата мьютекса и завершается его release. Вот, собс-но, и все.
>Отладить оное взамодействие можно в обычном гуевом приложении
>с кодом консоли, вынесенным в поток.
Здесь плохо, что "Читатель ждет (периодически проверяет)", потому как происходит дополнительная нагрузка на процессор (ни кто не спорт, она не значительна) и в зависимости от частоты проверки, получение сообщения у нас может занять какое-то время. Так же увеличение частоты проверки, ради сокращения времени получения сообщения, все больше увеличивает нагрузку на процессор.
Если же использовать WaitForSingleObject, то нужен дополнительный поток. Хотя в принципе, ожидание сообщений консольного буфера у меня построено на WaitForSingleObjectEx, можно попробовать объединить ожидание event и буфера функцией WaitForMultipleObjects, как считаете? Оба события же должны ожидаться бесконечно (INFINITE).
>Хотя, конечно, возможно, что лучше его сделать Message-Only Window
>(see SetParent with HWND_MESSAGE)
Кстати, действительно замечательный флаг. Благодарю.
← →
msg (2006-03-10 21:23) [69]>А что, консоль является необходимым внешним условием ?
Основное приложение: да. Приложение отдающее команды: нет, хотя оно и не важно от куда SendMessage слать.
← →
Игорь Шевченко © (2006-03-10 21:29) [70]msg (10.03.06 21:23) [69]
> Основное приложение: да.
Собственно, как уже отмечал LVT, в консольном приложении создать окно тоже труда не составит. Единственное, на мой взгляд, неудобное место будет с организацией выборки сообщений.
← →
begin...end © (2006-03-10 21:54) [71]> Игорь Шевченко © (10.03.06 21:29) [70]
Я, возможно, глупость сморожу, но у консоли разве затруднительно организовать цикл с GetMessage подобно тому, как это делается в GUI? Я, собсно, к тому, что не совсем понятно, зачем ещё окно создавать :)
← →
Игорь Шевченко © (2006-03-10 22:11) [72]begin...end © (10.03.06 21:54) [71]
А насколько я знаю, этот цикл уже организовывает тот, кто поддерживает ConsoleWindowClass для окна консоли, то есть, winsrv.dll
Я вот не знаю (если ты попробуешь, напиши, интересно), как интерференция с ним себя покажет, поэтому и спросил автора о необходимости именно консольного приложения.
← →
msg (2006-03-10 23:51) [73]У консольного приложения же как такового нет своего окна, консольное окно создаеться вызовом AllocConsole и заним следит система, к консольному окну может "приотачится" сколь угодо процессов (AttachConsole), и уничтожается оно после того, как все процессы от него отключатся вызвав FreeConsole.
Ну покрайней мере вот такой код не дает ни каких результатов:
в таймере (timeSetEvent):
h := FindWindow("ConsoleWindowClass", nil);
PostMessage(h, WM_PAINT, 0, 0);
или
SetConsoleTitle("{9F0C9451-118F-4A3E-9170-6C1989797463}");
h := FindWindow(nil, "{9F0C9451-118F-4A3E-9170-6C1989797463}");
PostMessage(h, WM_PAINT, 0, 0);
в цикле:
if PeekMessage(Mess,0,0,0,PM_REMOVE) then
begin
case Mess.message of
WM_PAINT: beep;
end;
end;
← →
begin...end © (2006-03-11 08:27) [74]> Игорь Шевченко © (10.03.06 22:11) [72]
Сообщения, посылаемые окну консоли через PostMessage, собственноручно организованным GetMessage-циклом не выбираются. Но у меня в [71] была мысль посылать не окнам (стандартному консольному или самостоятельно созданному), а потоку (через PostThreadMessage). Эти сообщения, на первый взгляд, нормально доходят.
← →
begin...end © (2006-03-11 08:51) [75]К [74]:
> Сообщения, посылаемые окну консоли...
Разумеется, имеется в виду стандартное консольное окно. Если создать дополнительное своё, то сообщения, адресованные ему, вроде бы, нормально принимаются в цикле (тоже на первый взгляд).
← →
Leonid Troyanovsky © (2006-03-13 09:06) [76]
> msg (10.03.06 21:21) [68]
> Если же использовать WaitForSingleObject, то нужен дополнительный
> поток. Хотя в принципе, ожидание сообщений консольного буфера
> у меня построено на WaitForSingleObjectEx, можно попробовать
> объединить ожидание event и буфера функцией WaitForMultipleObjects,
> как считаете? Оба события же должны ожидаться бесконечно
Конечно, WaitForMultipleObjects.
Если же используется WaitForSingleObjectEx, то можно извещать
ожидающий поток не с помощью event (SetEvent), а QueueUserAPC.
--
Regards, LVT.
Страницы: 1 2 вся ветка
Форум: "WinAPI";
Текущий архив: 2006.06.04;
Скачать: [xml.tar.bz2];
Память: 0.66 MB
Время: 0.045 c