0

I need to use the (undocumented) ITrayNotify interface. It's working fine when run as a normal/UAC-restricted process in Windows 7. However, when I run it elevated ("Run as Administrator") the CoCreateInstance call returns -2147221164 = $80040154 = REGDB_E_CLASSNOTREG = "Class not registered". I've tested it on 4 different Windows 7 systems with the same result. It's the same for x64 and x86.

How is this possible? Is this interface blocked for elevated processes? Is there a workaround for that?

For what it matters, heres the relevant part of the code. It's in Delphi, but I don't think that's relevant, since it works fine non-elevated.

classGuid := StringToGUID('{25DEAD04-1EAC-4911-9E3A-AD0A4AB560FD}');
interfaceGuid := StringToGUID('{FB852B2C-6BAD-4605-9551-F15F87830935}');
result := CoCreateInstance(classGuid, nil, CLSCTX_LOCAL_SERVER, interfaceGuid, trayNotify);

Edit/Notice: The problem isn't present in Windows 10 or 8. The interface is slightly different there and it works fine both elevated and non-elevated. The problem only applies to Windows 7 (don't know about Vista, not relevant for XP).

CodeX
  • 717
  • 7
  • 23
  • 2
    *"I need to use the (undocumented) ITrayNotify interface."* That is doubtful. – David Heffernan Apr 24 '16 at 14:48
  • 1
    How is this a useful commend or a reply to the actual question? I understand that undocumented interfaces aren't to be recommended. But this is not the question here. I don't think the circumstances that require the use of this interface are of any relevance here. This interface works from XP to 10, just not in the described constellation. Downvoting the question because it aims at an undocumented interface is absurd. – CodeX Apr 24 '16 at 15:26
  • I didn't down vote the question. And my comment is meant to make you consider that you might be taking the wrong path to solve your problem. – David Heffernan Apr 24 '16 at 15:42
  • Works fine when I try it. But using Win10 and not Delphi. REGDB_E_CLASSNOTREG is just not the kind of error you'd ever expect when you tinker with UAC. Maybe you can see something with SysInternals' Process Monitor, disabling anti-malware is never a bad idea. – Hans Passant Apr 24 '16 at 16:13
  • The likely explanation is that the `ITrayNotify` CLSID is not registered for all users, and the app is being elevated using an admin user that the CLSID is not registered for. – Remy Lebeau Apr 24 '16 at 16:16
  • @Hans Passant: It works fine with Windows 10 and 8, both elevated and non-elevated (notice, that the interface is slightly different for Win8/10). That's why I'm targeting the question explicitly at Windows 7 (don't know about Vista, and not relevant for XP). – CodeX Apr 24 '16 at 16:18
  • @Remy Lebeau: The user is the same in both cases (Administrator with UAC enabled). The only difference is that the application is run either normally or elevated. For what it's worth: it makes no difference whether the elevation is triggered by right-click > "Run as Administrator" or by applying a manifest that directly requires Administrator privileges. In both cases the UAC prompt has to be confirmed and CoCreateInstance fails. It's a mystery to me how this might be possible. – CodeX Apr 24 '16 at 16:21

1 Answers1

1

This type of UAC restriction is mentioned on the following site:

ITrayNotify

Implementation

The only known implementation of the ITrayNotify interface is by EXPLORER for an internal class, named CTrayNotify, which supports the notification area on the Windows taskbar. One instance is created internally. This same instance is also exposed as a creatable COM class with the following CLSID:

CLSID_TrayNotify {25DEAD04-1EAC-4911-9E3A-AD0A4AB560FD}

Availability

The ITrayNotify interface is implemented by EXPLORER version 6.00 and higher.

ITrayNotify :: RegisterCallback

As an aside, note that the program fails if User Account Control (UAC) is enabled and the program is run with elevated privilege. EXPLORER is the COM server and TRAYNOT is a COM client. Yet EXPLORER has only medium integrity. Though Microsoft’s notes on UAC—they’re really not substantial enough to count as programming documentation—deal with the situation of a lower-integrity COM client trying to communicate with a higher-integrity COM server, curiously little is said about the reverse. A higher-integrity COM client is protected from a lower-integrity COM server, much as a higher-integrity program is protected from receiving window messages from a lower-integrity program. For the latter, Microsoft provides the higher-integrity program with explicit means to open itself to expected messages from a lower-integrity source. Finding the analogous provision for COM may be a worthwhile exercise for another time.

When your app is elevated with UAC, it is running with higher privileges than the app that hosts the ITrayNotify object, and so COM does not allow your app to create the object.

I suspect Microsoft probably encountered the same problem in their own software in Windows 7 and tweaked the implementation so it would work in Windows 8 onwards. Remember, you are accessing a private interface, afterall. So any behavioral changes are going to be because Microsoft needed different behavior.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Thanks a lot for your detailed analysis! This helps understanding the background of this problem. I was hoping that there might be some easy way to work around this problem (sth. like an alternative CLSID to be used by elevated processes). So would you say the only way is to execute the code in a non-elevated process then? I know how to run a new non-elevated process (http://stackoverflow.com/questions/514968/how-to-run-a-process-non-elevated-with-delphi2007) but to my knowlege it's not possible to just call a procedure non-elevated. You don't happen to know if this is possible? – CodeX Apr 24 '16 at 16:53
  • @CodeX given this information, I would have to say yes, you likely need to run code in a low/medium integrity process to use the interface on Win7. So spawn a new process and have it communicate back with your main app as needed. – Remy Lebeau Apr 24 '16 at 16:57
  • Thank you. I'm going to leave this open for a couple of days in case someone else comes along with a different solution. After that I'm going to mark your reply as the accepted answer as it describes why there's probably no other solution to this problem. – CodeX Apr 24 '16 at 17:22