Перейти к основному контенту
Центр разработки для Windows

 none
Как добавить элемент в контекстное мню Windows 10? RRS feed

  • Вопрос

  • Здравствуйте, при разработке приложения возникла нужда добавить свой элемент в контекстное меню windows 10 которое  открывается при нажатии ПКМ на тексте, как это можно реализовать? Поиски в интернете результаты не дали, нашел лишь как добавить элемент в контекстное меню Folder, Directory и любого файла. 
    14 декабря 2019 г. 15:38

Ответы

  • Какой элемент управления вы используете, чтобы отображать текст? В общем случае, вам нужно установить с помощью SetWinEventHook хук на событие появления меню EVENT_SYSTEM_MENUPOPUPSTART и в обработчике этого события добавить в меню элемент через AppendMenu. Вот так будет выглядеть код для стандартного Edit Control:

    #include <stdlib.h> 
    #include <stdio.h>
    #include <windows.h>
    
    bool Enabled = false;
    UINT CurrentItemID;
    
    HWND GetMenuOwner(DWORD thid) { //получает владельца активного меню UI-потока
    	GUITHREADINFO info;
    	memset(&info, 0, sizeof(info));
    	info.cbSize = sizeof(info);
    	GetGUIThreadInfo(thid, &info);
    	if ((info.flags & GUI_POPUPMENUMODE) != 0) {		
    		return info.hwndMenuOwner;
    	}
    	else {		
    		return NULL;
    	}
    }
    
    //Обработка появления меню
    void CALLBACK HandleMenuPopup(HWINEVENTHOOK hook, DWORD event, HWND hwnd,
    	LONG idObject, LONG idChild,
    	DWORD dwEventThread, DWORD dwmsEventTime)
    {
    	HWND hOwner = GetMenuOwner(dwEventThread);
    
    	//получаем имя класса окна
    	WCHAR buf[100] = L"";
    	GetClassNameW(hOwner, buf, 100);
    	
    	if (wcscmp(buf, L"Edit") == 0) {
    		//если это Edit Control, получаем меню
    		HMENU hMenu = (HMENU)SendMessage(hwnd, MN_GETHMENU, 0, 0);
    		int c = GetMenuItemCount(hMenu);
    		UINT id_max = 0;
    
    		//найдем максимальный ID элемента...
    		for (int i = 0; i < c; i++) {
    			UINT id = GetMenuItemID(hMenu, i);
    
    			//Значения больше 10000, видимо, зарезервированы для особых целей - с ними не работает
    			if (id >= 10000) continue; 
    
    			if (id > id_max) id_max = id;
    		}
    		CurrentItemID = id_max + 1; //получаем уникальный ID для нового элемента
    
    		//добавляем новый элемент Test
    		BOOL res = AppendMenu(hMenu, MF_STRING | MF_POPUP, CurrentItemID, L"Test");
    		if (res == FALSE) {
    			printf("AppendMenu error %d", GetLastError());
    			Enabled = false;
    			return;
    		}
    		Enabled = true;
    	}
    	else Enabled = false;
    }
    
    //обработка нажатия элемента
    void CALLBACK HandleMenuClick(HWINEVENTHOOK hook, DWORD event, HWND hwnd,
    	LONG idObject, LONG idChild,
    	DWORD dwEventThread, DWORD dwmsEventTime)
    {	
    	if (Enabled && idChild == CurrentItemID) {		
    				
    		HWND hOwner = GetMenuOwner(dwEventThread);
    		
    		//выполнить необходимые действия...
    	}
    }
    
    void InitializeHook()
    {
    	CoInitialize(NULL);
    	HWINEVENTHOOK hook = SetWinEventHook(
    		EVENT_SYSTEM_MENUPOPUPSTART, EVENT_SYSTEM_MENUPOPUPSTART,  // Range of events
    		NULL,                                          // Handle to DLL.
    		HandleMenuPopup,                                // The callback.
    		GetCurrentProcessId(), 0,              // Process and thread IDs of interest (0 = all)
    		WINEVENT_OUTOFCONTEXT); // Flags.
    	if (hook == 0) printf("SetWinEventHook HandleMenuPopup error %d", GetLastError());
    
    	hook = SetWinEventHook(
    		EVENT_OBJECT_INVOKED, EVENT_OBJECT_INVOKED,  // Range of events
    		NULL,                                          // Handle to DLL.
    		HandleMenuClick,                                // The callback.
    		GetCurrentProcessId(), 0,              // Process and thread IDs of interest (0 = all)
    		WINEVENT_OUTOFCONTEXT); // Flags.
    	if (hook == 0) printf("SetWinEventHook HandleMenuClick error %d", GetLastError());
    }

     

    Основано на ответе https://stackoverflow.com/a/32998022/8674428



    16 декабря 2019 г. 10:02
  • Текст через сообщение WM_GETTEXT, выделение - через EM_GETSEL.

    WCHAR buf[256]=L"";
    SendMessage(hOwner, WM_GETTEXT, sizeof(buf)/sizeof(WCHAR), (LPARAM)buf);
    DWORD start, end;
    SendMessage(hOwner, EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
    WCHAR selection[256] = L"";
    wcsncpy_s(selection, sizeof(selection) / sizeof(WCHAR), &(buf[start]), end - start);

    17 декабря 2019 г. 3:19

Все ответы

  • Какой элемент управления вы используете, чтобы отображать текст? В общем случае, вам нужно установить с помощью SetWinEventHook хук на событие появления меню EVENT_SYSTEM_MENUPOPUPSTART и в обработчике этого события добавить в меню элемент через AppendMenu. Вот так будет выглядеть код для стандартного Edit Control:

    #include <stdlib.h> 
    #include <stdio.h>
    #include <windows.h>
    
    bool Enabled = false;
    UINT CurrentItemID;
    
    HWND GetMenuOwner(DWORD thid) { //получает владельца активного меню UI-потока
    	GUITHREADINFO info;
    	memset(&info, 0, sizeof(info));
    	info.cbSize = sizeof(info);
    	GetGUIThreadInfo(thid, &info);
    	if ((info.flags & GUI_POPUPMENUMODE) != 0) {		
    		return info.hwndMenuOwner;
    	}
    	else {		
    		return NULL;
    	}
    }
    
    //Обработка появления меню
    void CALLBACK HandleMenuPopup(HWINEVENTHOOK hook, DWORD event, HWND hwnd,
    	LONG idObject, LONG idChild,
    	DWORD dwEventThread, DWORD dwmsEventTime)
    {
    	HWND hOwner = GetMenuOwner(dwEventThread);
    
    	//получаем имя класса окна
    	WCHAR buf[100] = L"";
    	GetClassNameW(hOwner, buf, 100);
    	
    	if (wcscmp(buf, L"Edit") == 0) {
    		//если это Edit Control, получаем меню
    		HMENU hMenu = (HMENU)SendMessage(hwnd, MN_GETHMENU, 0, 0);
    		int c = GetMenuItemCount(hMenu);
    		UINT id_max = 0;
    
    		//найдем максимальный ID элемента...
    		for (int i = 0; i < c; i++) {
    			UINT id = GetMenuItemID(hMenu, i);
    
    			//Значения больше 10000, видимо, зарезервированы для особых целей - с ними не работает
    			if (id >= 10000) continue; 
    
    			if (id > id_max) id_max = id;
    		}
    		CurrentItemID = id_max + 1; //получаем уникальный ID для нового элемента
    
    		//добавляем новый элемент Test
    		BOOL res = AppendMenu(hMenu, MF_STRING | MF_POPUP, CurrentItemID, L"Test");
    		if (res == FALSE) {
    			printf("AppendMenu error %d", GetLastError());
    			Enabled = false;
    			return;
    		}
    		Enabled = true;
    	}
    	else Enabled = false;
    }
    
    //обработка нажатия элемента
    void CALLBACK HandleMenuClick(HWINEVENTHOOK hook, DWORD event, HWND hwnd,
    	LONG idObject, LONG idChild,
    	DWORD dwEventThread, DWORD dwmsEventTime)
    {	
    	if (Enabled && idChild == CurrentItemID) {		
    				
    		HWND hOwner = GetMenuOwner(dwEventThread);
    		
    		//выполнить необходимые действия...
    	}
    }
    
    void InitializeHook()
    {
    	CoInitialize(NULL);
    	HWINEVENTHOOK hook = SetWinEventHook(
    		EVENT_SYSTEM_MENUPOPUPSTART, EVENT_SYSTEM_MENUPOPUPSTART,  // Range of events
    		NULL,                                          // Handle to DLL.
    		HandleMenuPopup,                                // The callback.
    		GetCurrentProcessId(), 0,              // Process and thread IDs of interest (0 = all)
    		WINEVENT_OUTOFCONTEXT); // Flags.
    	if (hook == 0) printf("SetWinEventHook HandleMenuPopup error %d", GetLastError());
    
    	hook = SetWinEventHook(
    		EVENT_OBJECT_INVOKED, EVENT_OBJECT_INVOKED,  // Range of events
    		NULL,                                          // Handle to DLL.
    		HandleMenuClick,                                // The callback.
    		GetCurrentProcessId(), 0,              // Process and thread IDs of interest (0 = all)
    		WINEVENT_OUTOFCONTEXT); // Flags.
    	if (hook == 0) printf("SetWinEventHook HandleMenuClick error %d", GetLastError());
    }

     

    Основано на ответе https://stackoverflow.com/a/32998022/8674428



    16 декабря 2019 г. 10:02
  • Огромное спасибо, а не мог ли бы вы еще подсказать как получить выделенный текст в элементе управлении при нажатии на новый элемент в контекстном меню? 
    16 декабря 2019 г. 18:13
  • Текст через сообщение WM_GETTEXT, выделение - через EM_GETSEL.

    WCHAR buf[256]=L"";
    SendMessage(hOwner, WM_GETTEXT, sizeof(buf)/sizeof(WCHAR), (LPARAM)buf);
    DWORD start, end;
    SendMessage(hOwner, EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
    WCHAR selection[256] = L"";
    wcsncpy_s(selection, sizeof(selection) / sizeof(WCHAR), &(buf[start]), end - start);

    17 декабря 2019 г. 3:19