| View previous topic :: View next topic |
| Author |
Message |
AkulaBig
Joined: 03 Dec 2008 Posts: 592
|
(Separately) Posted: Wed Sep 09, 2026 16:04 Post subject: |
|
|
Понятно, что делалось. Ладно, сделаю сейчас колонки. Дольше говорю.
| Orion9 wrote: | | Кстати, концепция с заворачиванием объекта Plugin в отдельный поток тоже рабочая. |
Я проверял все варианты для ET. Правда отдельным потоком не запускал. Но и через объект Plugin и через утильку wdx тестил. То-есть все предоставляемые Ауторан варианты. Везде принцип работы одинаков.
Добавлено спустя 1 час 59 минут:
Orion9
Оказывается действительно и MI работает в ТС32 и ТС64 по разному. А я совсем забыл про это. Тогда вообще беда.
Я ваши намеки про сансея своеообразно понял. Может в лс чиркнете, что на самом деле происходит? |
|
| Back to top |
|
 |
AkulaBig
Joined: 03 Dec 2008 Posts: 592
|
(Separately) Posted: Tue Sep 15, 2026 20:49 Post subject: |
|
|
Orion9
Можно в системное контекстное меню добавить свои пункты? Вернее в системное меню ТС. Кажется это не одно и то-же, что системное меню Винды. |
|
| Back to top |
|
 |
Orion9

Joined: 01 Jan 2024 Posts: 1249
|
(Separately) Posted: Wed Sep 16, 2026 13:40 Post subject: |
|
|
AkulaBig
В системное меню главного окна ТС была попытка добавить новые пункты, но они не работают. Ниже есть ответ самого Loopback почему.
В контекстное меню можно таким же образом попробовать добавить, но для начала придется с болваном изрядно пообщаться
 Hidden text Для динамического изменения стандартных или сторонних контекстных меню в Win32 API (C++) используется перехват оконных сообщений через хук вызовов процедур (CBT hook или GetMessage hook). Основная задача — поймать момент создания окна меню класса #32768 (системный класс для всплывающих меню), получить его хэндл (HMENU) и встроить туда свой элемент.
Ниже представлен классический способ установки хука WH_CBT перед вызовом TrackPopupMenu для внедрения кастомного пункта.
Реализация на C++ (Win32 API)
cpp
#include <windows.h>
#include <iostream>
// Глобальные переменные для управления хуком
HHOOK g_hHook = NULL;
UINT_PTR g_MyCustomItemID = 9999; // Уникальный ID вашего пункта меню
// Процедура хука CBT (Computer Based Training)
LRESULT CALLBACK CbtMenuHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
// HCBT_CREATEWND вызывается в момент создания любого окна
if (nCode == HCBT_CREATEWND)
HWND hWndMenu = (HWND)wParam;
wchar_t className[32];
GetClassNameW(hWndMenu, className, 32);
// #32768 — это предопределенный атомарный класс для Windows Context Menu
if (wcscmp(className, L"#32768") == 0)
{
// Посылаем сообщение меню, чтобы получить его HMENU хэндл
// (или используем MN_GETHMENU = 0x01E5 начиная с Windows 2000)
HMENU hMenu = (HMENU)SendMessageW(hWndMenu, 0x01E5, 0, 0);
if (hMenu)
{
// Вставляем разделитель
AppendMenuW(hMenu, MF_SEPARATOR, 0, NULL);
// Вставляем наш кастомный элемент в конец меню
AppendMenuW(hMenu, MF_STRING, g_MyCustomItemID, L"Мой кастомный пункт");
}
}
}
// Передаем управление следующим хукам в цепочке
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}
// Пример функции вызова меню
void ShowMenuWithHook(HWND hWndOwner, HMENU hOriginalMenu, int x, int y)
{
// 1. Устанавливаем локальный WH_CBT хук на текущий поток
g_hHook = SetWindowsHookExW(WH_CBT, CbtMenuHookProc, NULL, GetCurrentThreadId());
// 2. Вызываем стандартный трекинг меню.
// Пока меню инициализируется, сработает наш хук CbtMenuHookProc.
TrackPopupMenu(hOriginalMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON, x, y, 0, hWndOwner, NULL);
// 3. Сразу после закрытия меню снимаем хук, чтобы не тратить ресурсы
if (g_hHook) {
UnhookWindowsHookEx(g_hHook);
g_hHook = NULL;
}
}
Используйте код с осторожностью.
Как обработать нажатие?
Когда пользователь нажмет на добавленный пункт меню, операционная система отправит стандартное уведомление WM_COMMAND в окно-владелец (hWndOwner). Обработайте его в оконной процедуре (WndProc):
cpp
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
// Проверяем, совпадает ли ID с нашим кастомным пунктом
if (LOWORD(wParam) == g_MyCustomItemID)
{
MessageBoxW(hWnd, L"Кастомный пункт меню нажат!", L"Успех", MB_OK);
return 0;
}
break;
// ... обработка других сообщений ...
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
Используйте код с осторожностью.
⚠️ Важные нюансы
• Глобальный vs Локальный хук: Приведенный пример использует локальный хук (GetCurrentThreadId()), который модифицирует меню только внутри вашего приложения. Если ваша цель — внедриться в чужой процесс (например, в контекстное меню Проводника Windows/Explorer), вам потребуется компилировать хук в отдельную .dll и внедрять его глобально через WH_GETMESSAGE или использовать официальные Shell Extension (IContextMenu).
• Сообщение MN_GETHMENU (0x01E5): Это системное недокументированное сообщение, стабильно работающее во всех версиях Windows, начиная с Windows XP и заканчивая Windows 11. Оно возвращает внутренний хэндл HMENU для окна всплывающего меню.
 Hidden text Когда в системе или приложении одновременно открывается множество меню, идентифицировать именно ваше окно меню #32768 внутри хука можно по контекстным признакам. Само по себе окно меню обезличено, но у него есть связи с другими элементами интерфейса.
Вот 4 основных способа со 100% точностью определить, что перехваченное меню — то, которое вам нужно:
1. Проверка по координатам мыши (Самый простой способ)
Контекстное меню почти всегда открывается там, где пользователь кликнул мышкой. Вы можете сравнить позицию курсора с координатами создаваемого окна меню.
cpp
if (wcscmp(className, L"#32768") == 0)
{
// Получаем текущие координаты курсора
POINT ptCursor;
GetCursorPos(&ptCursor);
// Получаем координаты создаваемого меню
RECT rcMenu;
GetWindowRect(hWndTarget, &rcMenu);
// Проверяем, находится ли курсор в пределах или вблизи точки создания меню
// (делаем небольшой задел в 5-10 пикселей на случай смещения)
if (abs(rcMenu.left - ptCursor.x) < 10 && abs(rcMenu.top - ptCursor.y) < 10)
{
// Это с высокой вероятностью ваше меню, вызванное кликом!
}
}
Используйте код с осторожностью.
2. Проверка окна-владельца (Owner Window)
Каждое всплывающее меню привязано к конкретному окну (кнопке, форме или главному окну программы), которое его вызвало. Через функцию GetWindow с флагом GW_OWNER можно узнать хэндл (HWND) этого родительского окна и сравнить его с вашим.
cpp
if (wcscmp(className, L"#32768") == 0)
{
// Находим окно, которое создало/владеет этим меню
HWND hWndOwner = GetWindow(hWndTarget, GW_OWNER);
// g_MyTargetWindow — HWND вашего конкретного текстового поля, кнопки или формы
if (hWndOwner == g_MyTargetWindow)
{
// Меню принадлежит вашему конкретному элементу управления!
}
}
Используйте код с осторожностью.
3. Анализ существующего содержимого меню (Фильтрация по тексту пунктов)
Если вы знаете, какие пункты должны быть в целевом меню по умолчанию, вы можете проверить их наличие с помощью функции GetMenuStringW. Если меню содержит специфическое слово (например, "Копировать", "Свойства" или уникальное имя из сторонней библиотеки), значит это оно.
cpp
HMENU hMenu = (HMENU)SendMessageW(hWndTarget, 0x01E5, 0, 0);
if (hMenu)
{
wchar_t menuText[256];
// Проверяем, например, самый первый пункт меню (индекс 0)
GetMenuStringW(hMenu, 0, menuText, 256, MF_BYPOSITION);
// Если там написано то, что мы ожидаем увидеть в целевом меню:
if (wcscmp(menuText, L"Ожидаемый Пункт") == 0)
{
// Это наше меню. Встраиваем кастомный элемент.
}
}
Используйте код с осторожностью.
4. Включение хука строго «по требованию» (Паттерн Guard)
Вместо того чтобы держать хук постоянно активным и гадать, чье меню открылось, включайте его строго за миллисекунду до вызова меню и выключайте сразу же после.
Если меню вызывается сторонней функцией (ThirdPartyShowMenu()), оберните её:
cpp
// 1. Включаем хук прямо перед вызовом
g_hMenuHook = SetWindowsHookExW(WH_CBT, CbtMenuHookProc, NULL, GetCurrentThreadId());
// 2. Вызываем функцию, которая триггерит появление меню
ThirdPartyShowMenu();
// 3. Выключаем хук. Все остальные меню в системе теперь будут игнорироваться.
UnhookWindowsHookEx(g_hMenuHook);
Используйте код с осторожностью.
Примечание: Поскольку TrackPopupMenu внутри сторонних библиотек обычно блокирует поток до тех пор, пока меню не закроется, хук гарантированно перехватит только это конкретное меню и снимется сразу после его закрытия.
Это только для примера. На практике с ним можно долго общаться, пока он не перестанет выдавать что-то полезное. |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|