I use TaskDialogIndirect() to display more advanced Error Messages. I can customize the buttons, icons, and more.
The problem is that, sometimes it makes these invisible empty dialog boxes.
I need it to be reliable. I am wondering why this is even happening in the first place.
Example of it failing (there is no visible window):
Here is the code that makes the dialogs (not production code):
int MessageBoxPosL(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType, int X, int Y)
{
TaskDialogData data;
data.X = X;
data.Y = Y;
TASKDIALOGCONFIG config = {};
config.cbSize = sizeof(config);
config.hwndParent = hWnd;
config.pszWindowTitle = lpCaption;
config.pszContent = lpText;
// configure other settings as desired, based on uType...
config.pfCallback = &TaskDialogCallback;
config.lpCallbackData = (LONG_PTR)&data;
config.dwFlags = TDF_ENABLE_HYPERLINKS;
config.hFooterIcon = LoadIcon(NULL, IDI_ERROR);
config.dwCommonButtons = ButtonActive(TDCBF_YES_BUTTON) | ButtonActive(TDCBF_NO_BUTTON) | ButtonActive(TDCBF_OK_BUTTON) | ButtonActive(TDCBF_RETRY_BUTTON) | ButtonActive(TDCBF_CLOSE_BUTTON);
config.pszMainIcon = SetIcon();
int button = 0;
TaskDialogIndirect(&config, &button, NULL, NULL);
return button;
}
The problem was the flag TDF_ENABLE_HYPERLINKS. Adding hyperlinked text that is too long caused the dialog to spawn outside of the desktop view.
Related
This question already has answers here:
Why are icons in property sheets rendered with so few colors?
(2 answers)
Closed 6 years ago.
I'm using Win32 API C++ Property Sheets in my application, and icons used in page headers have low quality compared to main header for example or other icons in application.
http://i.imgur.com/goiF7Je.png
On attached image both house icons are from same resource.
Is there a way to change it to 32bit color icons?
const int Sheets = 2;
PROPSHEETPAGE psp[Sheets];
for (int i=0; i<Sheets; ++i)
{
psp[i].dwSize = sizeof(PROPSHEETPAGE);
psp[i].dwFlags = PSP_USEICONID | PSP_USETITLE;
psp[i].lParam = 0;
psp[i].pfnCallback = NULL;
psp[i].hInstance = m_hInst;
}
psp[0].pszTemplate = MAKEINTRESOURCE(IDDNEW_IS0);
psp[0].pszIcon = MAKEINTRESOURCE(IDI_GENERAL_TAB);
psp[0].pfnDlgProc = IntegrationServer::tabGeneral;
psp[0].pszTitle = "General";
psp[1].pszTemplate = MAKEINTRESOURCE(IDDNEW_IS1);
psp[1].pszIcon = MAKEINTRESOURCE(IDI_GENERAL_REQUESTS);
psp[1].pfnDlgProc = IntegrationServer::tabRequests;
psp[1].pszTitle = "Requests";
PROPSHEETHEADER psh;
psh.dwSize = sizeof(PROPSHEETHEADER);
psh.dwFlags = PSH_USEICONID | PSH_PROPSHEETPAGE | PSH_NOCONTEXTHELP | PSH_NOAPPLYNOW;
psh.hInstance = m_hInst;
psh.pszIcon = MAKEINTRESOURCE(IDI_GENERAL_TAB);
psh.pszCaption = (LPSTR) "Integration Server configuration";
psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE);
psh.nStartPage = 0;
psh.ppsp = (LPCPROPSHEETPAGE) &psp;
psh.hwndParent = m_hWnd;
PropertySheet(&psh);
Finally, I have found a solution for above problem. Instead of Property Sheets, I have used Tab Control to create similar window.
Benefits of use Tab Control:
easier to maintain the content of each tab (just show/hide HWND),
icons are 32 bits,
it is a standard control like button, static text etc., so it works in same way.
Defects:
need to write more code.
Here is an example window:
http://i.imgur.com/4AcXvSz.png
And source code:
/*
Need this:
#include <commctrl.h >
#pragma comment(lib, "Comctl32.lib")
#pragma comment(linker,"/manifestdependency:\"type='win32' "
"name='Microsoft.Windows.Common-Controls' version='6.0.0.0' "
"processorArchitecture='*' publicKeyToken='6595b64144ccf1df' "
"language='*'\"")
*/
// get HWND of Tab Control
HWND tab = GetDlgItem(hDlg, IDC_TAB1);
// get current instance
HINSTANCE hInst = (HINSTANCE) GetModuleHandle(NULL);
// insert 7 tabs in our Tab Control
TCITEM tie;
tie.mask = TCIF_TEXT | TCIF_IMAGE;
LPSTR item[] = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" };
for (int i = 0; i < 7; i++)
{
tie.pszText = item[i];
tie.iImage = i;
if (TabCtrl_InsertItem(tab, i, &tie) == -1)
break;
}
// insert 7 icons for each Tab
HIMAGELIST hi = ImageList_Create(16, 16, ILC_COLOR32, 0, 7);
if (hi != NULL)
{
int icons[] = {IDI_ACTIONADD, IDI_ACTIONDELETE, IDI_ACTIONEDIT,
IDI_ACTIONIMPORT, IDI_ACTIONVIEW, IDI_CONFIGURATION,
IDI_CONF_CLEANUP};
for (int i =0; i<7; ++i)
{
HICON icon = (HICON) LoadImage(hInst, MAKEINTRESOURCE(icons[i]), IMAGE_ICON, 16, 16, 0);
ICONINFO iconinfo;
GetIconInfo(icon, &iconinfo);
HBITMAP bitmap = iconinfo.hbmColor;
ImageList_Add(hi, bitmap, NULL);
DestroyIcon(icon);
}
}
TabCtrl_SetImageList(tab, hi);
// Set position and size of child window to
// put it on the entire surface of tab display window
RECT rect;
GetClientRect(tab, &rect);
// This will collect entire Tab window and will return rectangle, which will
// fulfill display space
TabCtrl_AdjustRect(tab, FALSE, &rect);
// Create child window, which will be inserted into Tab display space
HWND child = CreateDialog(hInst, MAKEINTRESOURCE(IDD_IS_COMMON_CLEANUP),
tab, IntegrationServer::empty);
// Set child window position and size to fulfill Tab Control
// those "-2", "-1" etc. are just for me - I don't like white space :)
SetWindowPos(child, NULL,
rect.left-2, rect.top-1, rect.right-rect.left+2, rect.bottom-rect.top+2,
SWP_NOZORDER);
// Show child window
ShowWindow(child, SW_SHOW);
After that you have to look for Tab Control notifications, when user is going to change currently displayed tab, and load new HWND into Tab Control's display space.
Notifications for Tab Control can be found here:
http://msdn.microsoft.com/en-us/library/windows/desktop/bb760548(v=vs.85).aspx
I have a straight win32 c++ app and I'm filling the window with a ListView whose view type is set to LV_VIEW_TILE and I'm also setting the style to LVS_OWNERDATA.
I'm having trouble trying to work out how to get the subitems to show. This code creates the view.
DWORD exstyle =WS_EX_CLIENTEDGE|LVS_EX_DOUBLEBUFFER|LVS_EX_JUSTIFYCOLUMNS|LVS_EX_INFOTIP;
g_hwndList = CreateWindowEx(exstyle, WC_LISTVIEW, NULL, WS_CHILD | WS_VISIBLE | LVS_ICON | LVS_OWNERDATA, 0, 0, 0, 0, hWnd, (HMENU) 2702, hInst, NULL);
ListView_SetView(g_hwndList, LV_VIEW_TILE);
LVTILEVIEWINFO tileViewInfo = { };
tileViewInfo.cbSize = sizeof(LVTILEVIEWINFO);
tileViewInfo.dwFlags = LVTVIF_AUTOSIZE;
tileViewInfo.dwMask = LVTVIM_COLUMNS;
tileViewInfo.cLines = 1;
BOOL tst = ListView_SetTileViewInfo(g_hwndList, &tileViewInfo);
I only want one more subitem/column to appear. In my LVN_GETDISPINFO I currently have this:
static int colfmt[1];
colfmt[0] = LVCFMT_LEFT;
static int order[1];
order[0] = 1;
if ((nimfo->item.mask & LVIF_COLUMNS) == LVIF_COLUMNS) {
nimfo->item.cColumns = 1;
nimfo->item.piColFmt = PINT(colfmt);
nimfo->item.puColumns = PUINT(order);
}
if ((nimfo->item.mask & LVIF_TEXT) == LVIF_TEXT) {
nimfo->item.pszText = di->LABEL;
}
if ((nimfo->item.mask & LVIF_IMAGE) == LVIF_IMAGE) {
nimfo->item.iImage = di->IMAGE_INDEX;
}
I can't work out at what point and where I need to supply the subitem/column text, I'm never seeing the nimfo->item.subitem changing from 0 and for each call for LVIF_TEXT the structure values are always the same.
So at what point do I need to supply the extra textual data?
Many thanks.
I, rather stupidly, wasn't adding any columns and therefore wasn't being asked for the other items.
added this and everything works
LVCOLUMN col = {};
col.mask = LVCF_SUBITEM;
col.iSubItem = 0;
ListView_InsertColumn(g_hwndList, 0, &col);
I want to load an animated cursor stored in .ani format, which is described to be a RIFF archive/container, from memory without writing the memory to a temporary file. Thus far I am able to parse the .ani file structure and load the individual frames as a normal icon with the aid of CreateIconFromResourceEx LookupIconIdFromDirectoryEx
One of the problems that proofs difficult is the actual composition of these frames and the animation data (jiffy-rate etc) as there appears to be no entries in the Windows API to do so. Documentation or written knowledge over the subject seems to be limited to loading non-animated icons/cursors from memory.
Similar questions such as 'Load an embedded animated Cursor from the Resource' express the desire to load an animated cursor from an embeddable resource. However i am not able to reproduce a workable solution from that either. Partly because the resource compiler in visual studio 2008 & 2010 doesn't support .ani (only ico and cur) files and therefor embedding it simply results in a 1:1 copy of the bytes as they were in the original file as opposed to .cur and .ico files which get decomposed into multiple resources. The subsequent call to CreateIconFromResource as shown in both answers does not work because the data it expects is the icon/cursor data of a single directive in a icon archive and not a RIFF-based file structure.
To summarize I'm interested in any information regarding the structures of animated cursors (in memory) or otherwise relevant pointers that could assist me in pursuing my goal.
After re-evaluating loading an animated cursor from an embeddable resource as pointed out by mfc I have found a solution that allows me to load the cursors from an arbitrary memory address.
Data from an embeddable resource and data read from a file into memory are exactly identical. Therefor it suggests that CreateIconFromResource should work on normal regular memory as well. However there is one fundamental difference. Memory of the embeddable resources reside in special sections in the executable which are often padded to the nearest 4096-byte boundary. Memory allocated at runtime contains garbage values.
Now the solution that I found working exploits this by simply allocating a guard-band of zero-filled bytes. In my own test cases I have found that 8 is the minimum which also happens to be the size of a chunk in the riff container. Coincidence? What i suspect is that this is a bug and the algorithm happens to work for embeddable resources due to it's alignment restrictions within the dll/executable.
const int guardbandSize = 8;
FILE* fs = fopen("action.ani", "rb");
fseek(fs, 0,SEEK_END); int dwSize = ftell(fs); fseek(fs, 0,SEEK_SET);
char* memory = new char[dwSize + guardbandSize];
fread(memory, 1, dwSize, fs); memset(memory + dwSize, 0, guardbandSize);
fclose(fs);
cursor = (HCURSOR)CreateIconFromResource((PBYTE)memory,dwSize,FALSE,0x00030000);
delete memory;
Here is an overview of various ways to load an animated cursors.
#include <Windows.h>
#include <stdio.h>
#include "resource2.h"
void* hWnd;
bool visible = true;
bool running = true;
LRESULT CALLBACK WndProcInternal( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) ;
HCURSOR cursor = 0;
void main()
{
//Setup configuration
const int Width = 640, Height = 480;
const int Method = 4;
//Setup window class
WNDCLASS wcd;
wcd.style = CS_PARENTDC | CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wcd.lpfnWndProc = (WNDPROC)WndProcInternal;
wcd.cbClsExtra = 0;
wcd.cbWndExtra = 0;
wcd.hInstance = GetModuleHandle(NULL);
wcd.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wcd.hCursor = LoadCursor(NULL, IDC_ARROW);
wcd.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
wcd.lpszMenuName = NULL;
wcd.lpszClassName = TEXT("AnimatedIcon");
//Register the window class
if(!RegisterClass(&wcd))
{
MessageBox(NULL, TEXT("Window Registration Failed!"), TEXT("Error!"),MB_ICONEXCLAMATION | MB_OK);
FatalExit(-1);
}
//Create a window
if (!(hWnd=CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("AnimatedIcon"), TEXT("AnimatedIcon"),
WS_VISIBLE | WS_CAPTION | WS_MINIMIZEBOX | WS_THICKFRAME | WS_MAXIMIZEBOX | WS_SYSMENU,
0, 0, Width, Height, NULL, NULL, NULL, NULL)))
{
MessageBoxA(NULL,"Window Creation Error.","ERROR",MB_OK|MB_ICONEXCLAMATION);
FatalExit(-1);
}
if( Method == 1 )
{
//Method 1: Load cursor directly from a file
cursor = LoadCursorFromFileA("action.ani");
}
if( Method == 2 )
{
//Method 2: Load cursor from an resource section in the executable.
cursor = LoadCursor(0, MAKEINTRESOURCE(IDR_ANICURSORS1));
}
if( Method == 3 )
{
//Method 3: Manually locate the resource section in the executable & create the cursor from the memory.
HINSTANCE hInst=GetModuleHandle(0);
HRSRC hRes=FindResourceA(hInst,MAKEINTRESOURCEA(IDR_ANICURSORS1),"ANICURSORS");
DWORD dwSize=SizeofResource(hInst,hRes);
HGLOBAL hGlob=LoadResource(hInst,hRes);
LPBYTE pBytes=(LPBYTE)LockResource(hGlob);
cursor = (HCURSOR)CreateIconFromResource(pBytes,dwSize,FALSE,0x00030000);
}
if( Method == 4 )
{
//Method 4: Load the cursor from a file into memory & create the cursor from the memory.
const int guardbandSize = 8;
FILE* fs = fopen("action.ani", "rb");
fseek(fs, 0,SEEK_END); int dwSize = ftell(fs); fseek(fs, 0,SEEK_SET);
char* memory = new char[dwSize + guardbandSize];
fread(memory, 1, dwSize, fs); memset(memory + dwSize, 0, guardbandSize);
fclose(fs);
cursor = (HCURSOR)CreateIconFromResource((PBYTE)memory,dwSize,FALSE,0x00030000);
delete memory;
}
//Set the cursor for the window and display it.
SetClassLong((HWND)hWnd, GCL_HCURSOR, (LONG)cursor);
while (running)
{
MSG wmsg;
if (PeekMessage(&wmsg, (HWND)hWnd, 0, 0, PM_REMOVE))
{
TranslateMessage(&wmsg);
DispatchMessage(&wmsg);
}
}
}
LRESULT CALLBACK WndProcInternal( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if( uMsg == WM_DESTROY )
{
PostQuitMessage(1);
running = false;
}
return (long)DefWindowProc((HWND)hWnd,uMsg,(WPARAM)wParam,(LPARAM)lParam);
}
Import your animated cursor as a custom resource.
Give it a text name, eg "MyType".
Then load the cursor with:
HCURSOR hCursor = LoadAnimatedCursor(IDR_MYTYPE1, _T("MyType"));
/* ======================================================== */
HCURSOR LoadAnimatedCursor(UINT nID, LPCTSTR pszResouceType)
{
HCURSOR hCursor = NULL;
HINSTANCE hInstance = AfxGetInstanceHandle();
if (hInstance)
{ HRSRC hResource = FindResource(hInstance, MAKEINTRESOURCE(nID), pszResouceType);
DWORD dwResourceSize = SizeofResource(hInstance, hResource);
if (dwResourceSize>0)
{ HGLOBAL hRsrcGlobal = LoadResource(hInstance, hResource);
if (hRsrcGlobal)
{ LPBYTE pResource = (LPBYTE)LockResource(hRsrcGlobal);
if (pResource)
{ hCursor = (HCURSOR)CreateIconFromResource(pResource, dwResourceSize, FALSE, 0x00030000);
UnlockResource(pResource);
}
FreeResource(hRsrcGlobal);
}
}
}
return hCursor;
}
I am creating a modeless property sheet using the following settings:
PROPSHEETHEADER pshdr = { 0 };
pshdr.dwSize = sizeof(PROPSHEETHEADER);
pshdr.dwFlags = PSH_NOAPPLYNOW | PSH_PROPSHEETPAGE |
PSH_MODELESS | PSH_USECALLBACK;
pshdr.pfnCallback = PropSheetProc;
pshdr.hwndParent = mGlobalState->trayWin;
pshdr.pszCaption = L"My Settings";
pshdr.nPages = mPages.size();
pshdr.ppsp = mWinPages;
In PropSheetProc, I catch the PSCB_PRECREATE message and modify the dialog template so that it gets the DS_CENTER style:
static int CALLBACK
PropSheetProc(HWND hwndDlg, // IN
UINT uMsg, // IN
LPARAM lParam) // IN
{
// Before the dialog is created, bless it with the DS_CENTER style.
if (uMsg == PSCB_PRECREATE) {
DLGTEMPLATE *dlgTemplate = (DLGTEMPLATE *)lParam;
_ASSERT(dlgTemplate);
dlgTemplate->style |= DS_CENTER;
}
return 0;
}
However this doesn't succeed in centering the dialog. I tried to catch PSCB_INITIALIZED instead and call a CenterWindow method on the hwnd passed to the PropSheetProc:
void
CenterWindow(HWND hwndWindow) // IN
{
int nX, nY, nScreenWidth, nScreenHeight;
RECT rectWindow;
nScreenWidth = GetSystemMetrics(SM_CXSCREEN);
nScreenHeight = GetSystemMetrics(SM_CYSCREEN);
GetWindowRect(hwndWindow, &rectWindow);
nX = (nScreenWidth - (rectWindow.right - rectWindow.left)) / 2;
nY = (nScreenHeight - (rectWindow.bottom - rectWindow.top)) / 2;
SetWindowPos(hwndWindow, 0, nX, nY, 0, 0,
SWP_NOZORDER | SWP_NOSIZE);
}
But that doesn't work either!
Finally, I moved the CenterWindow call to directly after the PropSheet call:
mHwnd = (HWND)PropertySheet(&pshdr);
CenterWindow(mHwnd);
return mHwnd != NULL;
And this DOES work, though on a heavily loaded system, the dialog flashes from its initial position over to its final position, which is suboptimal.
Using the PropSheetProc to modify the DLGTEMPLATE structure seems intuitive. Actually, I can apply other window styles. But DS_CENTER seems to have no effect. So what am I doing wrong? There's many ways I can work around this brokennness but why is it broken in the first place?
Overload the InitialUpdate() of the CPropertySheet, and place the CenterWindow() call there. This happens before the window is drawn on the screen, but after it is created, so it's hwnd will be valid. There is nothing broken. The dialog has to be Created to have a valid HWND. Alternatively, if your working with the resource editor you can set it's property to centered, and it will achieve the same result. Why are you overloading the WinProc for the propertysheet? The whole reason MFC uses message maps was to eliminate the need to even touch WinProc's.
If your using raw win api in a SDK style application ::
Handle WM_CREATE in the WinProc of the property sheet. The LPCREATE struct in the LPARAM will contain a valid HWND from the create call. Just make sure you pass the proper parameters back to WndProcDefault() otherwise window creation will fail.
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;
}