Solved

APPBAR ShellAPI

Posted on 2008-10-29
10
1,019 Views
Last Modified: 2013-12-14
I am creating an APPBAR in c++ and I can do all that just fine.  I wanted to test what would happen if my application just straight up crashed without being able to unregister itself from the system list... so I just hit shift + f5 and found out what happens.  My actual app bar disappears but the space that it was taken up is still taken up.  I Did this several times and now on my test box all I have is maybe 200 pixels left for windows/desktop icons on a 1680x1200 dimension screen.  I have tried to look for some way to access this internal list that I see referenced in the MSDN but I cannot find anything on how to do this?

How can I access this list so that I can get a handle and then send the SHAppBarMessage(ABM_REMOVE, &AppBarData); command?  Thanks in advance, and code samples would be most appreciated.

Below is some code snippet which just creates a blank bar.  Hit alt + f5 in the IDE (VS) while the application is running to see what I mean.  The space the toolbar took up stays around.
// AppBar32.cpp : Defines the entry point for the console application.
//
 
#include "stdafx.h"
#include "windows.h"
 
HINSTANCE InstanceHandle;
bool First = true;
RECT CurrentRect;
 
enum WindowsId
{
   GoButtonId = 256,
   LinkComboId,
   ExitButtonId,
   AppMsg = WM_APP + 111
};
 
bool operator != (const RECT &lhs, const RECT &rhs)
{
	return lhs.top != rhs.top || lhs.bottom != rhs.bottom || lhs.left != rhs.left || lhs.right != rhs.left;
}
 
void AddApp(HWND aHwnd)
{
	APPBARDATA AppBarData;
	memset(&AppBarData, 0, sizeof(AppBarData));
	AppBarData.cbSize = sizeof(AppBarData);
	AppBarData.hWnd = aHwnd;
	AppBarData.uCallbackMessage = AppMsg;
	AppBarData.uEdge = ABE_TOP;
	SHAppBarMessage(ABM_NEW, &AppBarData);
}
 
void RemoveApp(HWND aHwnd)
{
	APPBARDATA AppBarData;
	memset(&AppBarData, 0, sizeof(AppBarData));
	AppBarData.cbSize = sizeof(AppBarData);
	AppBarData.hWnd = aHwnd;
	AppBarData.uCallbackMessage = AppMsg;
	AppBarData.uEdge = ABE_TOP;
	UINT_PTR ret = SHAppBarMessage(ABM_REMOVE, &AppBarData);
}
 
void RepositionBar(HWND aHwnd)
{
	APPBARDATA AppBarData;
	memset(&AppBarData, 0, sizeof(AppBarData));
	AppBarData.cbSize = sizeof(AppBarData);
	AppBarData.uEdge = ABE_TOP;
	AppBarData.hWnd = aHwnd;
 
	AppBarData.rc.left = 0;
	AppBarData.rc.top = 0;
	AppBarData.rc.right = GetSystemMetrics(SM_CXFULLSCREEN);
	AppBarData.rc.bottom = 30;
	SHAppBarMessage(ABM_QUERYPOS, &AppBarData);
 
	AppBarData.uEdge = ABE_TOP;
	AppBarData.hWnd = aHwnd;
 
	SHAppBarMessage(ABM_SETPOS, &AppBarData);
	if(CurrentRect != AppBarData.rc)
	{
		MoveWindow(aHwnd,
					AppBarData.rc.left,
					AppBarData.rc.top,
					AppBarData.rc.right - AppBarData.rc.left,
					AppBarData.rc.bottom - AppBarData.rc.top,
					TRUE);
		CurrentRect = AppBarData.rc;
	}
}
 
LRESULT CALLBACK DialogProc(HWND aHwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch(msg)
	{
	case WM_CREATE:
		
		break;
	case AppMsg:
		RepositionBar(aHwnd);
		if(First)
		{
			ShowWindow(aHwnd, SW_SHOW);
			First = false;
		}
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(aHwnd, msg, wParam, lParam);
}
 
int _tmain(int argc, _TCHAR* argv[])
{
	/*
	// Following code was test code to see if refreshing toolbar would get it to fix itself... it doesn't
	HWND hShellTrayWnd = ::FindWindow(_T("Shell_TrayWnd"), NULL);
	if(hShellTrayWnd)
	{	
		UpdateWindow(hShellTrayWnd);
	}
	*/
	HINSTANCE hInstance = NULL;
	InstanceHandle = hInstance;
	WNDCLASS wc;
	memset(&wc, 0, sizeof(WNDCLASS));
	wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
	wc.lpfnWndProc = DialogProc;
	wc.hInstance = InstanceHandle;
	wc.hbrBackground = (HBRUSH )(COLOR_BTNFACE + 1);
	wc.lpszClassName = "WhateverClass";
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	if(!RegisterClass(&wc))
		return FALSE;
 
	HWND WindowHandle = CreateWindowEx(WS_EX_TOOLWINDOW,
										"TestSomething",
										"",
										WS_MINIMIZEBOX | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
										100, 100, 140, 160,
										NULL,
										NULL,
										InstanceHandle,
										0);
 
	SetWindowLong(WindowHandle, GWL_STYLE, GetWindowLong(WindowHandle, GWL_STYLE) & ~(WS_CAPTION | WS_SYSMENU | WS_BORDER));
 
	AddApp(WindowHandle);
	MSG Msg;
	while(GetMessage(&Msg, 0, 0, 0xFFFF) > 0)
	{
		if(!IsDialogMessage(WindowHandle, &Msg))
		{
			TranslateMessage(&Msg);
			DispatchMessage(&Msg);
		}
	}
	RemoveApp(WindowHandle);
	
	return 0;
}

Open in new window

0
Comment
Question by:cc_dev
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 4
10 Comments
 

Author Comment

by:cc_dev
ID: 22831997
Also, I don't even need to necessarily access the list, I just need a good way of removing these items beyond closing down visual studio and then right clicking the task bar and causing it to refresh somehow... this is the only way currently I can get it to go away which seems a little unacceptable.
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 22839395
When I run your code, the CreateWindow function fails. GetLastError returns 1407 (Cannot find window class.) If the HWND is null, then not much is going to work...
And when I fix the classname, the program does what is expected: When I kill the console window, the (empty) appbar correctly disappears from the top of the screen.
I am running WinXP SP3 and using VS 6 for testing. I created the app by using the App Wizard to create a Win32 console app that supports MFC.

0
 

Author Comment

by:cc_dev
ID: 22881015
On all of our test cases running xp sp2 and sp3 and other lab boxes the appbar disappears but the space the appbar was taking up is not freed.  I understand that the handle will no longer be available to actually remove... but apparently the list still has this reservation for space.  If you maximize something even though the appbar is gone the space it took up is still reserved as if it were still there (if you exit the application without allowing it to unregister itself from the internal list).  

It also does this with the google desktop.  If you bring up task manager and kill the process the appbar disappears but the space it reserved is still taken up.  When you re-initialize goole desktop it clears out that space and then re-initializes the appbar and registers the space.  I am assuming they do this to prevent what we encountered in our lab, which is windows getting confused and stacking multiple instances on one another.  

This is what I want to do.  I want to access that "internal" list that is listed on the MSDN site.
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 49

Accepted Solution

by:
DanRollins earned 500 total points
ID: 22881322
Ah, I see the effect now. At least in part. If I run the program twice, it does not keep adding appbars or consuming desktop realestate.
I found that by using the sequence:
    AddApp(WindowHandle);
    RemoveApp(WindowHandle);
and then immediately exiting, that the system would remove the previously-added appbar (icons move back up and maximized window go to the top). Perhaps the system identifies the owner by its executable name or by the window class or message value (AppMsg) becasue the second run did not use the same HWND. Anyway rather than try to find some undocumented internal appbar list, you should see if this technqiue does what you need.
-- Dan
0
 

Author Comment

by:cc_dev
ID: 22881361
Ah cool.  I will try that now.  Yeah, i was only able to do multiple appbars twice... the rest of the time it just resumes with the same real estate.  I think it somehow got confused when I did it over and over again when I was testing code and then started stacking on top of one another.  If I was confident that it would always just resume and take over the real estate I wouldn't have any worries, but after seeing that effect I definitely don't want to risk having that happen to a clients machine.  Thanks for your help.  Let me try that and i will let know.
0
 

Author Comment

by:cc_dev
ID: 22881407
That absolutely works!  Thanks, I don't know why I didn't try that before lol.  I am just going to go ahead and call this sequence whenever my program starts up to make sure it clears it out.. as it causes no ill effect that I can see by adding it and then removing it again:

   AddApp(WindowHandle);
   RemoveApp(WindowHandle);
   AddApp(WindowHandle);
   MSG Msg;
   while(GetMessage(&Msg, 0, 0, 0xFFFF) > 0)

Thanks again.
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 22881419
It's also possible that the system itself does an integrity check at the time that a new appbar is added.  If the associated notif window no longer exists, it might decide to kill the appbar.  
I know that duplicate tray icons tend to pile up during debugging, but that the system removes an old one when I pass the mouse over it.  Perhaps there is a similar failsafe for appbars.
0
 

Author Comment

by:cc_dev
ID: 22881441
I think there might be, as one way I also found in removing it was to right click the task bar and then choose to lock or unlock it and it would disappear.  I tried grabbing the handle of the taskbar and then forcing a refresh on it but that didn't clear it out but I think you are on to something there.  The only oddity though, is i can completely restart my machine and the appbar is still there when it boots back up, so that is why I think it is something more.
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 22881460
Glad to help.  Thanks for the points and the grade.  You provided enough code to enable testing and that simplified my task considerably :-)
0
 

Author Comment

by:cc_dev
ID: 22881483
I try to do that with all questions I ask.  Even if the what I am working on is proprietary it is simple enough to make a really small test app that demonstrates the problem ;).  Makes communications on these problems so much easier.
0

Featured Post

Instantly Create Instructional Tutorials

Contextual Guidance at the moment of need helps your employees adopt to new software or processes instantly. Boost knowledge retention and employee engagement step-by-step with one easy solution.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

With most software applications trying to cater to multiple user needs nowadays, the focus is to make them as configurable as possible. For e.g., when creating Silverlight applications which will connect to WCF services, the service end point usuall…
Jaspersoft Studio is a plugin for Eclipse that lets you create reports from a datasource.  In this article, we'll go over creating a report from a default template and setting up a datasource that connects to your database.
The viewer will learn how to use and create keystrokes in Netbeans IDE 8.0 for Windows.
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question