How to show my own context menu in Internet Explorer - c++

I'm writing add-on for Internet Explorer 9 and I have to change default context menu to my own. I'm writing a BHO in C++ and I'm using ATL. I managed to handle event of showing context menu (HTMLDocumentEvents2::oncontextmenu), but I can't display my own one. Here is the code fired when you click right mouse button:
VARIANT_BOOL STDMETHODCALLTYPE CSpellCheckerBHO::OnContextMenu( IHTMLEventObj *pEvtObj)
{
HMENU contextMenu = CreatePopupMenu();
MENUITEMINFO item_info = { 0 };
item_info.cbSize = sizeof(MENUITEMINFO);
item_info.fMask = MIIM_TYPE | MIIM_ID;
item_info.fType = MFT_STRING;
item_info.wID = 0;
item_info.dwTypeData = L"TEST";
item_info.cch = 4;
BOOL result = InsertMenuItem(contextMenu, 0, FALSE, &item_info);
HWND browserHandle = 0;
HRESULT hr = _webBrowser->get_HWND((LONG_PTR*)&browserHandle);
result = TrackPopupMenuEx(contextMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON, 0,0, browserHandle , NULL);
return VARIANT_FALSE;
}
_webBrowser is a pointer to IWebBrowser2 object, I got it from SetSite function.
The standard context menu is not displayed (due to returning VARIANT_FALSE), but TrackPopupMenuEx does nothing and returns 0.
Do you know what I am doing wrong? I need simple menu with some text items.

I fgured it out. Igor Tandetnik helped me on IE addon forum. HWND was from different proccess and TrackPopupMenuEx expects HWND belonging to the calling thread. Here's the code that works:
VARIANT_BOOL STDMETHODCALLTYPE CSpellCheckerBHO::OnContextMenu( IHTMLEventObj *pEvtObj)
{
HMENU contextMenu = CreatePopupMenu();
MENUITEMINFO item_info = { 0 };
item_info.cbSize = sizeof(MENUITEMINFO);
item_info.fMask = MIIM_ID | MIIM_STRING;
item_info.wID = 0;
item_info.dwTypeData = L"TEST";
item_info.cch = 4;
BOOL result = InsertMenuItem(contextMenu, 0, TRUE, &item_info);
CComPtr<IDispatch> dispDoc;
_webBrowser->get_Document(&dispDoc);
CComQIPtr<IOleWindow> oleWindow = dispDoc;
HWND browserHandle;
oleWindow->GetWindow(&browserHandle);
CComQIPtr<IHTMLEventObj2> htmlEventObj = pEvtObj;
long x, y;
htmlEventObj->get_screenX(&x);
htmlEventObj->get_screenY(&y);
result = TrackPopupMenuEx(contextMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON, x, y, browserHandle , NULL);
return VARIANT_FALSE;
}

Related

Tiling menuItems in win32 as per particular design

I am creating a pop up menu item in win32 . I was able to create a popup menu item and then I added few icons to it. This is how its looking
sameple code
HMENU Controls = CreatePopupMenu();
InsertMenu(Controls, 0 , MF_STRING, 1, L"FirstMenu00");;
static HBITMAP bmpSource = NULL;
bmpSource = (HBITMAP)LoadImage(NULL, L"C:\\Users\\mac\\bit.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
MENUITEMINFO mii{};
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_ID | MIIM_BITMAP | MIIM_DATA;
mii.wID = 1;
mii.hbmpItem = bmpSource;// &paHbm[i];
bool st = InsertMenuItem(Controls, 10, TRUE, &mii);
std::string errSTr = GetLastErrorAsString();
TrackPopupMenuEx(Controls, TPM_LEFTALIGN | TPM_BOTTOMALIGN | TPM_LEFTBUTTON | TPM_HORPOSANIMATION, xPos, yPos, hwnd, NULL);
I am trying to arrange the menu icons in the following fashion
Ie I am trying to create a pattern where first row has 2 icons and the next row has 3 icons .
How can I achieve the same ?
You can use MF_MENUBREAK or MF_MENUBARBREAK flag in AppendMenu function to create a multi-column menu item. It seems that each raw has the same columns.
Here is a sample you can refer to:\
HMENU hmenuPopup = CreatePopupMenu();
// Add the bitmap menu items to the menu.
bool st = AppendMenu(hmenuPopup, MF_BITMAP, uID, (LPCWSTR)paHbm);
if (!st)
{
ErrorExit(L"AddBitmapMenu");
}
st = AppendMenu(hmenuPopup, MF_BITMAP | MF_MENUBARBREAK, uID + 1, (LPCWSTR)LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_BITMAP2)));
if (!st)
{
ErrorExit(L"AddBitmapMenu");
}
More reference: Menu Item Separators and Line Breaks, Displaying menu items in multiple columns

How to made JAWS readout ListView Item use Server Annotation

I have write a windows client, which UI framework is ATL/WTL. And There is a ListView (CListViewCtrl in ATL) with LVS_OWNERDRAWFIXED style.
For support Accessibility tool JAWS.I Want Jaws read ListView item.
I follow the doc:https://learn.microsoft.com/en-us/windows/win32/winauto/server-annotation-sample
0.Impl of IAccPropServer for support GetPropValue .
class ListViewAccServer : public IAccPropServer
{
ULONG m_Ref;
IAccPropServices * m_pAccPropSvc;
public:
/* skip over ListViewAccServer/ ~ListViewAccServer
*/
static ListViewAccServer * CreateProvider(HWND hControl)
{
ATL::CComPtr<IAccPropServices> pAccPropSvc;
HRESULT hr = pAccPropSvc.CoCreateInstance(CLSID_AccPropServices, NULL, CLSCTX_SERVER);
if (hr == S_OK && pAccPropSvc)
{
ListViewAccServer * pLVServer = new (std::nothrow) ListViewAccServer(pAccPropSvc);
if (pLVServer)
{
MSAAPROPID propid = PROPID_ACC_NAME;
//pAccPropSvc->SetHwndPropServer(hControl, (DWORD)OBJID_CLIENT, CHILDID_SELF, &propid, 1, pLVServer, ANNO_CONTAINER);
pAccPropSvc->SetHwndPropServer(hControl, (DWORD)OBJID_CLIENT, CHILDID_SELF, &propid, 1, pLVServer, ANNO_CONTAINER);
pLVServer->Release();
}
return pLVServer;
}
return NULL;
}
/* skip over: Addref/Release/QI
*/
HRESULT STDMETHODCALLTYPE GetPropValue(const BYTE * pIDString,
DWORD dwIDStringLen, MSAAPROPID idProp, VARIANT * pvarValue,
BOOL * pfGotProp)
{
if (!pfGotProp)
return E_POINTER;
pvarValue->vt = VT_EMPTY;
*pfGotProp = FALSE;
//HWND hwnd;
DWORD idObject;
DWORD idChild;
HWND dwHcontrol;
if (S_OK != m_pAccPropSvc->DecomposeHwndIdentityString(pIDString,
dwIDStringLen, &dwHcontrol, &idObject, &idChild))
{
return S_OK;
}
HWND Hwnd = dwHcontrol;
// Only supply name string for child elements, not the listview itself
if (idChild != CHILDID_SELF)
{
if (idProp == PROPID_ACC_NAME)//Jaws should read acc name?
{
CString str;
str.Format(L"Line index %d", idChild);
OutputDebugPrintfW(_T("GetPropValue str =%s\n"), str);
BSTR bstr = ::SysAllocString((LPCTSTR)str.GetString());
pvarValue->vt = VT_BSTR;
pvarValue->bstrVal = bstr;
*pfGotProp = TRUE;
}
}
return S_OK;
}
};
1.initUI
//if Set 'LVS_OWNERDRAWFIXED',JAWS will read onDraw Item "Dummy List Item"
m_lvMain.Create(m_hWnd, rc, NULL,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
LVS_REPORT | LVS_AUTOARRANGE | LVS_SHOWSELALWAYS | LVS_SHAREIMAGELISTS | WS_TABSTOP|LVS_OWNERDRAWFIXED,
WS_EX_CLIENTEDGE, LIST_ID);
/*
m_lvMain.Create(m_hWnd, rc, NULL,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
LVS_REPORT | LVS_AUTOARRANGE | LVS_SHOWSELALWAYS | LVS_SHAREIMAGELISTS | WS_TABSTOP ,
WS_EX_CLIENTEDGE, LIST_ID);
*/
//otherwise JAWS will read Hello,Hello1,Hello2...
m_lvMain.InsertColumn(0, _T("Column"), LVCFMT_LEFT, 200);
m_lvMain.InsertItem(0, _T("Hello"));
m_lvMain.InsertItem(0, _T("Hello1"));
m_lvMain.InsertItem(0, _T("Hello2"));
m_lvMain.InsertItem(0, _T("Hello3"));
2.Bind Listview m_hwnd with ListViewAccServer
m_pAccServer = ListViewAccServer::CreateProvider(m_lvMain.m_hWnd);
3
LRESULT OnDrawItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
//LRESULT onDraw(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
LPDRAWITEMSTRUCT pDIS = (LPDRAWITEMSTRUCT)(lParam);
//OutputDebugPrintfW(_T("OnDrawItem i = %d, %d, %08x \n"), pDIS->itemID, pDIS->itemData, pDIS->hwndItem);
BOOL bSelected = ((pDIS->itemState & ODS_SELECTED) == ODS_SELECTED);
BOOL bFocus = ((pDIS->itemState & ODS_FOCUS) == ODS_FOCUS);
HDC hDC = pDIS->hDC;
RECT rc = pDIS->rcItem;
HBRUSH bg = (HBRUSH)(::GetStockObject(WHITE_BRUSH));
if (bSelected)
{
bg = (HBRUSH)(::GetStockObject(LTGRAY_BRUSH));
}
if (bFocus)
{
bg = (HBRUSH)(::GetStockObject(LTGRAY_BRUSH));
}
HPEN pn = (HPEN)(::GetStockObject(BLACK_PEN));
::SelectObject(hDC, bg);
::SelectObject(hDC, pn);
::SetTextColor(hDC, RGB(0, 0, 0));
const wchar_t *text = L"Dummy List Item";
::Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
::DrawText(hDC, text, wcslen(text), &rc, DT_SINGLELINE | DT_VCENTER);
return S_OK;
}
When use UP and down array By Keyboard alert in ListView items.I want Jaws read out "Line index i" in GetPropValue.
But
1: If I set ListView with style:LVS_OWNERDRAWFIXED.On some PC, Jaws will read out "Dummy List Item". On Some PC, It read nothing.
2: If remove style:LVS_OWNERDRAWFIXED. Jaws will read out 'Hello','Hello1'...
both 1 or 2 do not read out GetPropValue give string"Line index i".
The log shows GetPropValue is be called:
GetPropValue str =Line index 1
GetPropValue str =Line index 2
My test PC machine OSs are Win10,Win7
So what's the problem?
Thanks a lot.
PS:At last , I found this:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=73496
I can use Insert+6 to bring up the JAWS Configuration Manager.
- click OK to Add a New Configuration (for your application)
- in the Configuration Manager dialog, type "listv" in the filter to see the page containing the "Rely on MSAA for ListViews" checkbox.
- check "Rely on MSAA for ListViews"
- click OK to save and exit the Configuration Manager.
So Jaws default do not use MSAA to get information?

CreateWindow - window is not shown in IE

I have this BHO in C++ that I'm writing,
Basically what I'm trying to do is open a window, but it is not shown, I think it might have something to do with the HINSTANCE I passed to it. This is the code I use, anyone recognizing what's not right in this snippet?
Thanks :)
IServiceProvider* pServiceProvider = NULL;
if (SUCCEEDED(m_pWebBrowser->QueryInterface(
IID_IServiceProvider,
(void**)&pServiceProvider)))
{
IOleWindow* pWindow = NULL;
if (SUCCEEDED(pServiceProvider->QueryService(
SID_SShellBrowser,
IID_IOleWindow,
(void**)&pWindow)))
{
HWND hwndBrowser = NULL;
if (SUCCEEDED(pWindow->GetWindow(&hwndBrowser)))
{
HWND g_hwndMain;
g_hwndMain = CreateWindow(TEXT ("AnxJTest Class"),TEXT("My Window"),WS_POPUP | WS_VISIBLE,0, 0, 200, 300,NULL, NULL, (HINSTANCE)hwndBrowser, NULL);
ShowWindow(g_hwndMain, SW_SHOW);
}
pWindow->Release();
}
pServiceProvider->Release();
}

Add tooltip to a CStatic

I haven't been able to find a concise chunk of code that allows me to add/display tooltips to a CStatic (and CLed) control. Obviously, the standard code to do so does not apply for this type of control. Can someone post code snippets?
I hope this code will solve your problem .One important thing make NOTIFY property of CStatic =TRUE.
if( !m_ToolTip.Create(this))
{
TRACE0("Unable to create the ToolTip!");
}
else
{
CWnd* pWnd = GetDlgItem(IDC_STATIC_MASTER_PWD);
m_ToolTip.AddTool(pWnd,"Ok");
m_ToolTip.Activate(TRUE);
}
Let me know if any problem.
I don't know if this is still needed, but here's what I used to solve the problem:
just add SS_NOTIFY to dwStyle when creating the static label. (or simply set "Nofity" "True" in the properties). That worked fine for me.
When I add CStatic on Dialog based autocreated mfc application, tooltips don't show until I add RelayEvent in pretranslate dialog message
BOOL CTooltipStaticDlg::PreTranslateMessage(MSG* pMsg)
{
m_ToolTip.RelayEvent(pMsg);
return CDialog::PreTranslateMessage(pMsg);
}
I've had success with multiline tooltips using this simple class:
Create a class for ToolTips:
class ToolTip
{
public:
static HWND CreateToolTip(int toolID, HWND hDlg, UINT id);
};
Next, implement a tooltip creation function:
HWND ToolTip::CreateToolTip(int toolID, HWND hDlg, UINT id)
{
if (!toolID || !hDlg || !id)
{
return FALSE;
}
CString strTTText;
strTTText.LoadString( id );
// Get the window handle of the control to attach the TT to.
HWND hwndTool = ::GetDlgItem(hDlg, toolID);
// Create the tooltip window
HWND hwndTip = CreateWindowEx(NULL, TOOLTIPS_CLASS, NULL,
WS_POPUP |TTS_ALWAYSTIP,// | TTS_BALLOON,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
hDlg, NULL,
AfxGetInstanceHandle() , NULL);
if (!hwndTool || !hwndTip)
{
return (HWND)NULL;
}
// Associate the tooltip with the tool.
TOOLINFO toolInfo = { 0 };
toolInfo.cbSize = sizeof(toolInfo);
toolInfo.hwnd = hDlg;
toolInfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
toolInfo.uId = (UINT_PTR)hwndTool;
toolInfo.lpszText = (char*)(LPCTSTR)strTTText;
::SendMessage(hwndTip, TTM_ADDTOOL, 0, (LPARAM)&toolInfo);
::SendMessageA(hwndTip, TTM_SETMAXTIPWIDTH, 0, 40); // force multi-line
return hwndTip;
}
Call it somewhere in your InitDialog:
CMyDialog::InitDialog()
{
ToolTip::CreateToolTip( PickAUniqueNumber, m_hWnd, IDS_MY_RESOURCE_STRING );
}
I've had on my dialog label with assigned custom ID IDC_PATH. I needed to turn on Notify flag (SS_NOTIFY) of the label and I needed to overload CWnd method OnToolHitTest and handle tooltip hit test like this:
INT_PTR CPath::OnToolHitTest(CPoint point, TOOLINFO* pTI) const
{
INT_PTR r = CWnd::OnToolHitTest(point,pTI);
this->ClientToScreen(&point);
CRect rcLbl;
GetDlgItem(IDC_PATH)->GetWindowRect(&rcLbl);
if( rcLbl.PtInRect(point) )
{
pTI->uFlags |= TTF_IDISHWND;
pTI->uFlags &= ~TTF_NOTBUTTON;
pTI->uId = (UINT_PTR)GetDlgItem(IDC_PATH)->m_hWnd;
return IDC_PATH;
}
return r;
}
Then my dialog started to receive TTN_NEEDTEXT notification, which I handled and dynamicaly set text for tooltip.
BOOL CPath::OnTtnNeedText(UINT id, NMHDR *pNMHDR, LRESULT *pResult)
{
UNREFERENCED_PARAMETER(id);
TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;
UINT_PTR nID = pNMHDR->idFrom;
BOOL bRet = FALSE;
if (pTTT->uFlags & TTF_IDISHWND)
{
// idFrom is actually the HWND of the tool
nID = ::GetDlgCtrlID((HWND)nID);
if(nID == IDC_PATH)
{
pTTT->lpszText = (LPSTR)(LPCTSTR)m_FullDestPath;
bRet = TRUE;
}
}
*pResult = 0;
return bRet;
}

Replacement for SHDOCLC.DLL file to customize the context menu of a webbrowser

I'm using the code, from this article to customize the context menu of a webbrowser.
but when i run this code
HRESULT CBrowserHost::ShowContextMenu(DWORD dwID,
POINT *ppt,
IUnknown *pcmdTarget,
IDispatch *pdispObject)
{
#define IDR_BROWSE_CONTEXT_MENU 24641
#define SHDVID_GETMIMECSETMENU 27
#define SHDVID_ADDMENUEXTENSIONS 53
HRESULT hr;
HINSTANCE hinstSHDOCLC;
HWND hwnd;
HMENU hMenu;
CComPtr<IOleCommandTarget> spCT;
CComPtr<IOleWindow> spWnd;
MENUITEMINFO mii = {0};
CComVariant var, var1, var2;
hr = pcmdTarget->QueryInterface(IID_IOleCommandTarget, (void**)&spCT);
hr = pcmdTarget->QueryInterface(IID_IOleWindow, (void**)&spWnd);
hr = spWnd->GetWindow(&hwnd);
hinstSHDOCLC = LoadLibrary(TEXT("SHDOCLC.DLL")); //here the exception is raised
if (hinstSHDOCLC == NULL)
{
// Error loading module -- fail as securely as possible.
return;
}
hMenu = LoadMenu(hinstSHDOCLC,
MAKEINTRESOURCE(IDR_BROWSE_CONTEXT_MENU));
hMenu = GetSubMenu(hMenu, dwID);
// Get the language submenu.
hr = spCT->Exec(&CGID_ShellDocView, SHDVID_GETMIMECSETMENU, 0, NULL, &var);
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_SUBMENU;
mii.hSubMenu = (HMENU) var.byref;
// Add language submenu to Encoding context item.
SetMenuItemInfo(hMenu, IDM_LANGUAGE, FALSE, &mii);
// Insert Shortcut Menu Extensions from registry.
V_VT(&var1) = VT_INT_PTR;
V_BYREF(&var1) = hMenu;
V_VT(&var2) = VT_I4;
V_I4(&var2) = dwID;
hr = spCT->Exec(&CGID_ShellDocView, SHDVID_ADDMENUEXTENSIONS, 0, &var1, &var2);
// Remove View Source.
DeleteMenu(hMenu, IDM_VIEWSOURCE, MF_BYCOMMAND);
// Show shortcut menu.
int iSelection = ::TrackPopupMenu(hMenu,
TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD,
ppt->x,
ppt->y,
0,
hwnd,
(RECT*)NULL);
// Send selected shortcut menu item command to shell.
LRESULT lr = ::SendMessage(hwnd, WM_COMMAND, iSelection, NULL);
FreeLibrary(hinstSHDOCLC);
return S_OK;
}
This error is raised
"The specified module could not be found"
I search on my system (Windows 7 x64, IE9) and I not found the SHDOCLC.DLL file, the question is exist any replacement for this file in the newers versions of IE or I must use another way to load the context menu and customize it?
You shouldn't use or rely on the Internet Explorer's internal resources anymore. As it's stated in the article you've pointed out:
In Internet Explorer 7, the technique for overriding the context menu
from a DocObject host is the same as Internet Explorer 6; however, the
host must implement its own menu resources. The internal resources of
Internet Explorer should not be used as they may change or move (as
has been done in Internet Explorer 7).
if the Windows version is newer than VISTA(included), try LoadLibrary("IEFRAME.DLL") instead.
And you can find more infomation here