Solved

APPBAR ShellAPI

Posted on 2008-10-29
10
972 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
  • 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
 
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
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 

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

What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

Join & Write a Comment

Suggested Solutions

Article by: SunnyDark
This article's goal is to present you with an easy to use XML wrapper for C++ and also present some interesting techniques that you might use with MS C++. The reason I built this class is to ease the pain of using XML files with C++, since there is…
Update (December 2011): Since this article was published, the things have changed for good for Android native developers. The Sequoyah Project (http://www.eclipse.org/sequoyah/) automates most of the tasks discussed in this article. You can even fin…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.

759 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

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now