none
Shell_NotifyIcon fails, error is ERROR_NO_TOKEN RRS feed

  • Question

  • Hi

    I'm writing an app that runs in the background and would like to add an icon to the notification area to allow the user to interact with it occasionally. The app currently works fine on my desktop development machine, but I'm also developing on another latop machine as well, and I've noticed the call the Shell_NotifyIcon with NIM_ADD always fails, and GetLastError returns 1008: ERROR_NO_TOKEN. Both machines are running Windows 7 SP1

    Problems with this function are well documented:

    http://social.msdn.microsoft.com/Forums/zh/vcgeneral/thread/003ca6a1-e993-41a9-a3d5-d6219664889f

    http://msdn.microsoft.com/en-us/library/bb762159%28v=vs.85%29.aspx

    http://connect.microsoft.com/VisualStudio/feedback/details/296872/shell-notifyicon-fails-at-times-for-no-reason

    However the problem seems to centre around a timeout during startup. My application is failing whilst debugging, the machine is otherwise completely idle.

    What is the likely cause of this? I can't find any information about the error code itself, at least nothing relevant to Shell_NotifyIcon. I'm following what I think are the best practices for each targeted OS regarding the lpdata parameter, these values are set as follows:

    	// Initialize NOTIFYICONDATA
    	ZeroMemory(&m_nid, sizeof(NOTIFYICONDATA));
    
    	// Get Shell32 version number and set the size of the structure.
    	// http://msdn.microsoft.com/en-us/library/bb773352%28v=vs.85%29.aspx
    	ULONGLONG version = GetDllVersion(_T("Shell32.dll"));
    
    	if(version >= MAKEDLLVERULL(6,0,6,0))
    	{
    		m_nid.cbSize = sizeof(NOTIFYICONDATA);
    		m_nid.uVersion = NOTIFYICON_VERSION_4;
    	}
    	else if(version >= MAKEDLLVERULL(6,0,0,0))
    	{
    		m_nid.cbSize = NOTIFYICONDATA_V3_SIZE;
    		m_nid.uVersion = NOTIFYICON_VERSION_4;
    	}
    	else if(version >= MAKEDLLVERULL(5,0,0,0))
    	{
    		m_nid.cbSize = NOTIFYICONDATA_V2_SIZE;
    		m_nid.uVersion = NOTIFYICON_VERSION;
    	}
    	else
    	{
    		m_nid.cbSize = NOTIFYICONDATA_V1_SIZE;
    		m_nid.uVersion = 0;
    	}
    
    	m_nid.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE | NIF_SHOWTIP;
    
    	// Only Windows 7 systems or later may use a GUID to identify the notification icon.
    	if (IsWin7OrLater())
    	{
    		m_nid.uFlags |= NIF_GUID;
    		m_nid.guidItem = NOTIFICATION_ICON_GUID;
    	}
    	else
    		m_nid.uID = NOTIFICATION_ICON_ID;
    
    	// Set tray notification window:
    	m_nid.hWnd = m_hWnd;
    	m_nid.uCallbackMessage = UM_TRAYNOTIFY;
    
    	// Set tray icon and tooltip:
    	m_nid.hIcon = theApp.LoadIcon(IDR_MAINFRAME);
    
    	// Tooltip to be shown when mouse is over the icon. The NIF_TIP flag must be set , but on vista 
    	CString strToolTip = _T("Scheduler");
    	_tcsncpy_s(m_nid.szTip, strToolTip, strToolTip.GetLength());
    
    	// If the application was not shut down properly the icon may still be present,
    	// but attached to a now invalid hWnd. Remove it before re-adding.
    	Shell_NotifyIcon(NIM_DELETE, &m_nid);
    
    	//Add the icon.
    	bResult = Shell_NotifyIcon(NIM_ADD, &m_nid);
    	DWORD dw = GetLastError();
    	
    	// Specify the behaviour of the icon.
    	bResult = Shell_NotifyIcon(NIM_SETVERSION, &m_nid);
    Regards, Andrew




    • Edited by Andrew Polden Tuesday, March 27, 2012 12:14 PM Removed unnecessary code
    • Moved by Mike Dos Zhang Wednesday, March 28, 2012 3:21 PM Shell API question (From:General Windows Desktop Development Issues)
    Tuesday, March 27, 2012 12:13 PM

Answers

  • For what it's worth, I solved this problem by calling Shell_NotifyIcon(NIM_DELETE, &m_nid) before I set the hWnd. I guess it really only needs the GUID or ID to be set in order to delete the icon.
    • Marked as answer by Andrew Polden Monday, November 5, 2012 4:36 AM
    Monday, November 5, 2012 4:36 AM

All replies

  • This UI dev forum will show you more expert helps on Shell APIs programming problem.

    Best wishes,


    Mike Zhang[MSFT]
    MSDN Community Support | Feedback to us

    Wednesday, March 28, 2012 3:22 PM
  • Shell_NotifyIcon is not documented to set last error, so you can't rely on GetLastError() to return useful information. The ERROR_NO_TOKEN result may not be related to the Shell_NotifyIcon call and may not even refer to a real error. GetLastError() is only valid if called immediately after a function documented to set it returns failure. Calling it after a success or for a function (like Shell_NotifyIcon) which doesn't explicitly set it may return a stale value or a value set in case of error which isn't cleared.

    As you mention, the common failures for Shell_NotifyIcon are when the communication with Explorer times out or occurs before Explorer is listening. As mentioned in the comments for Shell_NotifyIcon, in the timeout case GetLastError will usually return ERROR_TIMEOUT (a stale error code inherited from the internal SendMessageTimeout call). Since you aren't getting that your error probably occurs earlier.

    You mention that this occurs when debugging on your laptop: does it only occur when debugging or does it occur always? Is there anything different about the debugging environment on the two systems? Are you running the debugger elevated on one but not the other? If ERROR_NO_TOKEN is relevant it sounds like something related to security tokens: is your app doing any impersonation here?

    Have you tried debugging into the call to Shell_NotifyIcon? It's a fairly simple call, and if you can step through and find which internal function fails it may suggest a solution. You can get Windows symbols from the Microsoft Symbol Server. If you're using VS 2010 then there is a checkbox to do this automatically on the Debugging Symbols property page. Otherwise see Using the Microsoft Symbol Server

    --Rob

    Tuesday, April 10, 2012 2:57 AM
  • Maybe a little late but I encountered a similar problem: I had two Projects using the same library to access the Shell_NotifyIcon API. Both on the same Windows 7 x64 machine. One project ALWAYS failed when trying to add the icon, the other one always succeeded.

    The Problem: I used the same GUID in both projects (debugging purposes) but with different Icons (actually the same file copied to each project folder). The notification icon was registered using the new GUID mechanism - and that caused the problem. The path to the Icon must always be the same for the same GUID.

    The documentation of the NOTIFYICONDATA structure has a Troubleshooting section:

    1. The binary file that contains the icon was moved. The path of the binary file is included in the registration of the icon's GUID and cannot be changed. Settings associated with the icon are preserved through an upgrade only if the file path and GUID are unchanged. If the path must be changed, the application should remove any GUID information that was added when the existing icon was registered. Once that information is removed, you can move the binary file to a new location and reregister it with a new GUID. Any settings associated with the original GUID registration will be lost.

      This also occurs in the case of a side-by-side installation. When dealing with a side-by-side installation, new versions of the application should update the GUID of the binary file.

      Note  The only exception to a moved file occurs when both the original and moved binary files are Authenticode-signed by the same company. In that case, settings are preserved through the move.

    Solutions:

    1. Use the Window Handle/ID combination to register the notification icon.
    2. Create a new GUID each time the path to the icon file changes.

    Best regards, Dominik

    Thursday, July 19, 2012 10:52 AM
  • I think I need time to read the topic of "Using the Microsoft Symbol Server". Thanks.
    Sunday, November 4, 2012 3:43 PM
  • For what it's worth, I solved this problem by calling Shell_NotifyIcon(NIM_DELETE, &m_nid) before I set the hWnd. I guess it really only needs the GUID or ID to be set in order to delete the icon.
    • Marked as answer by Andrew Polden Monday, November 5, 2012 4:36 AM
    Monday, November 5, 2012 4:36 AM
  • I experienced exactly the same problem with Shell_NotifyIcon( NIM_ADD, ...) returning FALSE and GetLastError() returning 1008: ERROR_NO_TOKEN with a Release Build of a C++ application that was developed in VS 2012. The platform was a 64-bit machine running Windows 7 Enterprise. No problems were experienced with the Debug version of the application though.

    I tried all the above suggestions including calling Shell_NotifyIcon( NIM_DELETE, ...) before calling Shell_NotifyIcon( NIM_ADD, ...) but nothing worked.

    I finally resolved the problem by using a different GUID for the Release Build of the application.

    Wednesday, March 6, 2013 12:14 PM
  • Thanks for the information. Couple of questions:

    1.  What do you mean by "the notification icon was registered using the new GUID mechanism"? How do we register a notification icon with a given GUID?

    2.  "Use the Window Handle/ID combination to register the notification icon" - did you mean the window handle that receives the notification message (the hWnd in NOTIFYICONDATA)? How do we register the icon in this case?

    Friday, January 17, 2014 4:52 PM
  • Just wanted to mention that this seems to happen if the "Shell_NotifyWnd" (system tray) window's handler of WM_COPYDATA returns FALSE, meaning that it didn't handle the WM_COPYDATA message sent as part of Shell_NotifyIcon.  There may be all variety of reasons for Explorer doing this so I won't speculate why.
    Wednesday, May 21, 2014 3:17 PM