This is an archive post of content I wrote for the NTDebugging Blog on MSDN. Since the MSDN blogs are being retired, I’m transferring my posts here so they aren’t lost. The post has been back-dated to its original publication date.
A customer recently reported a rather peculiar problem. They were working on a roll out of Windows 7, and one of the policies they employed on their domain was the “Show only specified control panel applets” setting. As its name implies, this policy allows an administrator to specify the names of any Control Panel icons they want their users to see, and all others are not shown. This company chose to allow a few of the Control Panel items included with Windows as well as the Mail icon that is added when Microsoft Office (specifically Outlook) is installed, which allows users to configure their Outlook profiles.
The problem the customer noticed was that, with the policy was in place, the first time a user opened the Control Panel on a computer, all of the allowed icons appeared except for Mail. If the user closed Control Panel and reopened it, the icon suddenly appeared. In fact, from that point on, the Mail icon would appear for that user on that computer. However, if that user logged on to a different computer, or a different user logged in to the first user’s computer, the icon was missing until Control Panel was opened for a second time.
Control Panel isn’t something we get many cases on, so I had to figure out how it worked, and what would cause it to fail only the first time. One of the first things I discovered as I debugged the issue was that the Control Panel is actually loaded in two passes – a “fast” pass and a “slow” pass. This is done so icons we know will be loaded quickly can be displayed first so a user doesn’t get stuck with an empty window waiting for some of the slower icons to load. What makes an icon fast or slow? It turns out shell maintains a cache of Control Panel items, so it can display them quickly without having to query the actual item for its name, description, icon, etc. If we have to ask the item for its information, that will take longer, so it is loaded during the second, slow phase:
shell32!CControlPanelDataWorkItem::_LoadSlowData
shell32!CControlPanelDataWorkItem::DoWork
shell32!CFrameTask::InternalResumeRT
shell32!CRunnableTask::Run
shell32!CShellTask::TT_Run
shell32!CShellTaskThread::ThreadProc
shell32!CShellTaskThread::s_ThreadProc
shlwapi!ExecuteWorkItemThreadProc
ntdll!RtlpTpWorkCallback
ntdll!TppWorkerThread
kernel32!BaseThreadInitThunk
ntdll!__RtlUserThreadStart
ntdll!_RtlUserThreadStart
Luckily for these icons, they won’t stay relegated to slow loading status forever. During the slow loading phase, one of the things we do is add the item’s information to the Control Panel cache, so we can load it during the fast phase in the future.
shell32!CPLD_AddControlToReg
shell32!CControlPanelEnum::_NextNonCachedCpl
shell32!CControlPanelEnum::Next
shell32!CRegFolderEnum::Next
shell32!CControlPanelAppletList::_AddAppletsToCategories
shell32!CControlPanelAppletList::LoadSlowApplets
shell32!CControlPanelDataWorkItem::_LoadSlowData
shell32!CControlPanelDataWorkItem::DoWork
shell32!CFrameTask::InternalResumeRT
shell32!CRunnableTask::Run
shell32!CShellTask::TT_Run
shell32!CShellTaskThread::ThreadProc
shell32!CShellTaskThread::s_ThreadProc
shlwapi!ExecuteWorkItemThreadProc
ntdll!RtlpTpWorkCallback
ntdll!TppWorkerThread
kernel32!BaseThreadInitThunk
ntdll!__RtlUserThreadStart
ntdll!_RtlUserThreadStart
This explains why the item was being loaded on subsequent opens of Control Panel – the item was added to the user’s cache on the first run, so the next time, it was loaded during the fast pass:
shell32!CControlPanelEnum::_NextCachedCpl
shell32!CControlPanelEnum::Next
shell32!CRegFolderEnum::Next
shell32!CControlPanelAppletList::_AddAppletsToCategories
shell32!CControlPanelAppletList::EnsureLoaded
shell32!CControlPanelDataWorkItem::_LoadFastData
shell32!CControlPanelDataWorkItem::DoWork
shell32!CFrameTask::InternalResumeRT
shell32!CRunnableTask::Run
shell32!CShellTask::TT_Run
shell32!CShellTaskThread::ThreadProc
shell32!CShellTaskThread::s_ThreadProc
shlwapi!ExecuteWorkItemThreadProc
ntdll!RtlpTpWorkCallback
ntdll!TppWorkerThread
kernel32!BaseThreadInitThunk
ntdll!__RtlUserThreadStart
ntdll!_RtlUserThreadStart
But that only answers half the question – while we now know why the icon appears every other time, we still don’t know why it doesn’t show up the first time. To figure this out, I debugged a system with the “Show only specified control panel applets” policy applied and one without the policy set, both as they opened Control Panel for the first time, and compared where the return codes from the functions diverged.
Starting with CControlPanelEnum::_NextNonCachedCpl, in the non-working case, we can see that it returns 0:
0:003> bp shell32!CControlPanelEnum::_NextNonCachedCpl
0:003> g
Breakpoint 0 hit
eax=14c5fa8c ebx=14c5fa7c ecx=11224630 edx=00000000 esi=11224630 edi=14c5fa8c
eip=76977e11 esp=14c5f9b4 ebp=14c5f9c8 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
shell32!CControlPanelEnum::_NextNonCachedCpl:
76977e11 8bff mov edi,edi
0:020> k
ChildEBP RetAddr
14c5f9b0 76977dff shell32!CControlPanelEnum::_NextNonCachedCpl
14c5f9c8 768a854d shell32!CControlPanelEnum::Next+0x5a
14c5fa18 769710d2 shell32!CRegFolderEnum::Next+0x22e
14c5fa94 769783e7 shell32!CControlPanelAppletList::_AddAppletsToCategories+0x35
14c5fac4 76978353 shell32!CControlPanelAppletList::LoadSlowApplets+0x68
14c5faec 76974db4 shell32!CControlPanelDataWorkItem::_LoadSlowData+0x2e
14c5fb00 769e06ad shell32!CControlPanelDataWorkItem::DoWork+0x4b
14c5fb18 768d83a6 shell32!CFrameTask::InternalResumeRT+0x14
14c5fb38 7691639b shell32!CRunnableTask::Run+0xce
14c5fb54 76918c1f shell32!CShellTask::TT_Run+0x167
14c5fb9c 76918d53 shell32!CShellTaskThread::ThreadProc+0xa3
14c5fba4 760cb2b1 shell32!CShellTaskThread::s_ThreadProc+0x1b
14c5fbb4 77c8d877 shlwapi!ExecuteWorkItemThreadProc+0xe
14c5fc28 77c90842 ntdll!RtlpTpWorkCallback+0x11d [d:\w7rtm\minkernel\threadpool\compat\worker.c @ 284]
14c5fd80 00000000 ntdll!TppWorkerThread+0x572
0:020> gu * <------------- This steps out to the instruction after the call to CControlPanelEnum::_NextNonCachedCpl in CControlPanelEnum::Next.
ModLoad: 35c70000 35c8b000 c:\progra~1\common~1\system\msmapi\1033\mlcfg32.cpl
eax=00000000 ebx=14c5fa7c ecx=bea347f1 edx=006d2904 esi=11224630 edi=14c5fa8c
eip=76977dff esp=14c5f9bc ebp=14c5f9c8 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
shell32!CControlPanelEnum::Next+0x5a:
76977dff 84c0 test al,al
But on the machine without the policy set, it returns 1:
eax=0c83fc34 ebx=0c83fc24 ecx=04ab1060 edx=00000000 esi=04ab1060 edi=0c83fc34
eip=76977e11 esp=0c83fb5c ebp=0c83fb70 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
shell32!CControlPanelEnum::_NextNonCachedCpl:
76977e11 8bff mov edi,edi
0:012> k
ChildEBP RetAddr
0c83fb58 76977dff shell32!CControlPanelEnum::_NextNonCachedCpl
0c83fb70 768a854d shell32!CControlPanelEnum::Next+0x5a
0c83fbc0 769710d2 shell32!CRegFolderEnum::Next+0x22e
0c83fc3c 769783e7 shell32!CControlPanelAppletList::_AddAppletsToCategories+0x35
0c83fc6c 76978353 shell32!CControlPanelAppletList::LoadSlowApplets+0x68
0c83fc94 76974db4 shell32!CControlPanelDataWorkItem::_LoadSlowData+0x2e
0c83fca8 769e06ad shell32!CControlPanelDataWorkItem::DoWork+0x4b
0c83fcc0 768d83a6 shell32!CFrameTask::InternalResumeRT+0x14
0c83fce0 7691639b shell32!CRunnableTask::Run+0xce
0c83fcfc 76918c1f shell32!CShellTask::TT_Run+0x167
0c83fd44 76918d53 shell32!CShellTaskThread::ThreadProc+0xa3
0c83fd4c 760cb2b1 shell32!CShellTaskThread::s_ThreadProc+0x1b
0c83fd5c 77c8d877 shlwapi!ExecuteWorkItemThreadProc+0xe
0c83fdd0 77c90842 ntdll!RtlpTpWorkCallback+0x11d
0c83ff30 778b3c45 ntdll!TppWorkerThread+0x572
0c83ff3c 77cc37f5 kernel32!BaseThreadInitThunk+0xe
0c83ff7c 77cc37c8 ntdll!__RtlUserThreadStart+0x70
0c83ff94 00000000 ntdll!_RtlUserThreadStart+0x1b
0:012> gu
ModLoad: 35c70000 35c8b000 c:\progra~1\common~1\system\msmapi\1033\mlcfg32.cpl
eax=00000001 ebx=0c83fc24 ecx=bea347f1 edx=00002bba esi=04ab1060 edi=0c83fc34
eip=76977dff esp=0c83fb64 ebp=0c83fb70 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
shell32!CControlPanelEnum::Next+0x5a:
76977dff 84c0 test al,al
So we know something in this function is causing us to return FALSE in the failing case and TRUE in the working case. An easy way to see where the return result of function calls is the wt (watch trace) debugger command with the -oR switch to see the return values. I set the level (-l) to 1 so I’d only see functions directly called from CControlPanelEnum::_NextNonCachedCpl. Here were the results.
Failing case:
eax=14c5fa8c ebx=14c5fa7c ecx=11224630 edx=00000000 esi=11224630 edi=14c5fa8c
eip=76977e11 esp=14c5f9b4 ebp=14c5f9c8 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
shell32!CControlPanelEnum::_NextNonCachedCpl:
76977e11 8bff mov edi,edi
0:020> wt -oR -l 1
Tracing shell32!CControlPanelEnum::_NextNonCachedCpl to return address 76977dff
31 0 [ 0] shell32!CControlPanelEnum::_NextNonCachedCpl
10 0 [ 1] shell32!DSA_GetItemPtr
17 0 [ 1] comctl32!DSA_GetItemPtr eax = 1123aa78
48 27 [ 0] shell32!CControlPanelEnum::_NextNonCachedCpl
ModLoad: 35c70000 35c8b000 c:\progra~1\common~1\system\msmapi\1033\mlcfg32.cpl
34 0 [ 1] shell32!CPLD_InitModule eax = 1
55 61 [ 0] shell32!CControlPanelEnum::_NextNonCachedCpl
15 0 [ 1] shell32!CDPA_Base<RESULT_FOLDER_ITEM,CTContainer_PolicyUnOwned<RESULT_FOLDER_ITEM> >::AppendPtr eax = 0
59 76 [ 0] shell32!CControlPanelEnum::_NextNonCachedCpl
14 0 [ 1] shell32!CPL_AddModuleReference eax = 0
61 90 [ 0] shell32!CControlPanelEnum::_NextNonCachedCpl
21 0 [ 1] shell32!CPL_ReleaseModuleReference eax = 0
76 111 [ 0] shell32!CControlPanelEnum::_NextNonCachedCpl
128 0 [ 1] shell32!CPLD_AddControlToReg eax = 1
78 239 [ 0] shell32!CControlPanelEnum::_NextNonCachedCpl
12 0 [ 1] shell32!FindCPLModuleInList eax = c666998
84 251 [ 0] shell32!CControlPanelEnum::_NextNonCachedCpl
10 0 [ 1] shell32!DSA_GetItemPtr
17 0 [ 1] comctl32!DSA_GetItemPtr eax = c5e7410
91 278 [ 0] shell32!CControlPanelEnum::_NextNonCachedCpl
90 0 [ 1] shell32!CControlPanelEnum::_CanEnumerateApplet eax = 0
97 368 [ 0] shell32!CControlPanelEnum::_NextNonCachedCpl
21 0 [ 1] shell32!CPL_ReleaseModuleReference eax = 0
108 389 [ 0] shell32!CControlPanelEnum::_NextNonCachedCpl
143 0 [ 1] shell32!CPLD_FlushRegModules eax = 0
116 532 [ 0] shell32!CControlPanelEnum::_NextNonCachedCpl
3 0 [ 1] shell32!__security_check_cookie eax = 0
118 535 [ 0] shell32!CControlPanelEnum::_NextNonCachedCpl
Working case:
eax=0c83fc34 ebx=0c83fc24 ecx=04ab1060 edx=00000000 esi=04ab1060 edi=0c83fc34
eip=76977e11 esp=0c83fb5c ebp=0c83fb70 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
shell32!CControlPanelEnum::_NextNonCachedCpl:
76977e11 8bff mov edi,edi
0:012> wt -oR -l 1
Tracing shell32!CControlPanelEnum::_NextNonCachedCpl to return address 76977dff
31 0 [ 0] shell32!CControlPanelEnum::_NextNonCachedCpl
10 0 [ 1] shell32!DSA_GetItemPtr
17 0 [ 1] comctl32!DSA_GetItemPtr eax = 4a732c8
48 27 [ 0] shell32!CControlPanelEnum::_NextNonCachedCpl
ModLoad: 35c70000 35c8b000 c:\progra~1\common~1\system\msmapi\1033\mlcfg32.cpl
34 0 [ 1] shell32!CPLD_InitModule eax = 1
55 61 [ 0] shell32!CControlPanelEnum::_NextNonCachedCpl
15 0 [ 1] shell32!CDPA_Base<RESULT_FOLDER_ITEM,CTContainer_PolicyUnOwned<RESULT_FOLDER_ITEM> >::AppendPtr eax = 0
59 76 [ 0] shell32!CControlPanelEnum::_NextNonCachedCpl
14 0 [ 1] shell32!CPL_AddModuleReference eax = 0
61 90 [ 0] shell32!CControlPanelEnum::_NextNonCachedCpl
21 0 [ 1] shell32!CPL_ReleaseModuleReference eax = 0
76 111 [ 0] shell32!CControlPanelEnum::_NextNonCachedCpl
128 0 [ 1] shell32!CPLD_AddControlToReg eax = 1
78 239 [ 0] shell32!CControlPanelEnum::_NextNonCachedCpl
12 0 [ 1] shell32!FindCPLModuleInList eax = 2ff3968
84 251 [ 0] shell32!CControlPanelEnum::_NextNonCachedCpl
10 0 [ 1] shell32!DSA_GetItemPtr
17 0 [ 1] comctl32!DSA_GetItemPtr eax = 4aa81a8
91 278 [ 0] shell32!CControlPanelEnum::_NextNonCachedCpl
111 0 [ 1] shell32!CControlPanelEnum::_CanEnumerateApplet eax = 1
104 389 [ 0] shell32!CControlPanelEnum::_NextNonCachedCpl
21 0 [ 1] shell32!CPL_ReleaseModuleReference eax = 0
112 410 [ 0] shell32!CControlPanelEnum::_NextNonCachedCpl
3 0 [ 1] shell32!__security_check_cookie eax = 1
114 413 [ 0] shell32!CControlPanelEnum::_NextNonCachedCpl
Here, we can see that the function CControlPanelEnum::_CanEnumerateApplet returns true in the working case, but false in the failing case. This is what is causing the return value from _NextNonCachedCpl to differ, which is ultimately what causes the icon to load/not load. So let’s take a look at _CanEnumerateApplet. Using wt inside this function showed something rather interesting:
Failing:
eax=0c5e7410 ebx=769298fd ecx=11224630 edx=00000000 esi=11224630 edi=0c666998
eip=7693a72f esp=14c5f980 ebp=14c5f9b0 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
shell32!CControlPanelEnum::_CanEnumerateApplet:
7693a72f 8bff mov edi,edi
0:020> wt -oR -l 1
Tracing shell32!CControlPanelEnum::_CanEnumerateApplet to return address 7693a68e
27 0 [ 0] shell32!CControlPanelEnum::_CanEnumerateApplet
737 0 [ 1] shlwapi!PathFindFileNameW eax = c6669f8
40 737 [ 0] shell32!CControlPanelEnum::_CanEnumerateApplet
59 0 [ 1] shell32!IDControlCreate eax = 0
44 796 [ 0] shell32!CControlPanelEnum::_CanEnumerateApplet
43 0 [ 1] shlwapi!SHWindowsPolicy eax = 1
53 839 [ 0] shell32!CControlPanelEnum::_CanEnumerateApplet
2 0 [ 1] shell32!CRegFolder::QueryInterface
5 0 [ 1] shell32!CKnownFoldersFolder::QueryInterface
12 0 [ 1] shell32!CAggregatedUnknown::QueryInterface eax = 0
71 858 [ 0] shell32!CControlPanelEnum::_CanEnumerateApplet
48 0 [ 1] shell32!CRegFolder::GetDetailsEx eax = ffffffff`80070002
77 906 [ 0] shell32!CControlPanelEnum::_CanEnumerateApplet
24 0 [ 1] shell32!CRegFolder::Release eax = 3
79 930 [ 0] shell32!CControlPanelEnum::_CanEnumerateApplet
6 0 [ 1] shell32!ATL::CComVariant::Clear eax = 0
88 936 [ 0] shell32!CControlPanelEnum::_CanEnumerateApplet
3 0 [ 1] shell32!__security_check_cookie eax = 0
90 939 [ 0] shell32!CControlPanelEnum::_CanEnumerateApplet
Working:
0:012> wt -oR -l 1
Tracing shell32!CControlPanelEnum::_CanEnumerateApplet to return address 7693a68e
27 0 [ 0] shell32!CControlPanelEnum::_CanEnumerateApplet
737 0 [ 1] shlwapi!PathFindFileNameW eax = 2ff39c8
40 737 [ 0] shell32!CControlPanelEnum::_CanEnumerateApplet
59 0 [ 1] shell32!IDControlCreate eax = 0
44 796 [ 0] shell32!CControlPanelEnum::_CanEnumerateApplet
43 0 [ 1] shlwapi!SHWindowsPolicy eax = 1
53 839 [ 0] shell32!CControlPanelEnum::_CanEnumerateApplet
2 0 [ 1] shell32!CRegFolder::QueryInterface
5 0 [ 1] shell32!CKnownFoldersFolder::QueryInterface
12 0 [ 1] shell32!CAggregatedUnknown::QueryInterface eax = 0
71 858 [ 0] shell32!CControlPanelEnum::_CanEnumerateApplet
48 0 [ 1] shell32!CRegFolder::GetDetailsEx eax = 0
77 906 [ 0] shell32!CControlPanelEnum::_CanEnumerateApplet
28 0 [ 1] shell32!CPL_DoesPolicyAllow eax = 1
82 934 [ 0] shell32!CControlPanelEnum::_CanEnumerateApplet
24 0 [ 1] shell32!CRegFolder::Release eax = 3
84 958 [ 0] shell32!CControlPanelEnum::_CanEnumerateApplet
6 0 [ 1] shell32!ATL::CComVariant::Clear eax = 0
98 964 [ 0] shell32!CControlPanelEnum::_CanEnumerateApplet
358 0 [ 1] shell32!CControlPanelFolder::GetCustomAttributes eax = 0
109 1322 [ 0] shell32!CControlPanelEnum::_CanEnumerateApplet
3 0 [ 1] shell32!__security_check_cookie eax = 1
111 1325 [ 0] shell32!CControlPanelEnum::_CanEnumerateApplet
Looking at the two, we can see that they both call GetDetailsEx, but in the failing case we seem to get an error result: 80070002, and in the working case we get 0, and then proceed to call CPL_DoesPolicyAllow. CPL_DoesPolicyAllow is not called on the machine with the policy applied. A quick code review of CPL_DoesPolicyAllow showed that this function checks if a policy prevents or allows an item from being displayed. So if we can just get to that function, the icon will load. Now we need to know why GetDetailsEx fails, preventing us from calling CPL_DoesPolicyAllow. If we look up the error code, it is pretty generic:
0:020> !error 80070002
Error code: (HRESULT) 0x80070002 (2147942402) - The system cannot find the file specified.
Next I stepped through and into GetDetailsEx. I’ll save you the tedious steps and output, since the procedure is similar to what I’ve already shown above. Anyway, I was able to trace the error 2 as being returned by a call to the registry a few functions deep into GetDetailsEx:
kernel32!RegOpenKeyExW
shell32!CControlPanelFolder::_GetExtPropRegKey
shell32!CControlPanelFolder::_InitExtPropRegValNameCache
shell32!CControlPanelFolder::_PropertyFromPidl
shell32!CControlPanelFolder::GetDetailsEx
shell32!CRegFolder::GetDetailsEx
shell32!CControlPanelEnum::_CanEnumerateApplet
shell32!CControlPanelEnum::_NextNonCachedCpl
This is good news, because it means we can find out what we’re looking for that we aren’t finding. First I stepped out to get back to CControlPanelFolder::_InitExtPropRegValNameCache. Sure enough, eax was 2, which is our ‘cannot find the file’ error.
0:020> gu
eax=00000002 ebx=00000000 ecx=778ac2da edx=00000002 esi=14c5eff0 edi=00000000
eip=76975ead esp=14c5ed40 ebp=14c5efc4 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
shell32!CControlPanelFolder::_GetExtPropRegKey+0xb1:
76975ead 50 push eax
0:020> !error 2
Error code: (Win32) 0x2 (2) - The system cannot find the file specified
Since we know that RegOpenKeyEx takes the subkey it is looking for as the second parameter, let’s look back at the assembly before the call to see what we passed in:
0:020> ub @eip
shell32!CControlPanelFolder::_GetExtPropRegKey+0x98:
76975e94 7c1f jl shell32!CControlPanelFolder::_GetExtPropRegKey+0xb9 (76975eb5)
76975e96 56 push esi
76975e97 6a01 push 1
76975e99 53 push ebx
76975e9a 8d8590fdffff lea eax,[ebp-270h]
76975ea0 50 push eax
76975ea1 ffb588fdffff push dword ptr [ebp-278h]
76975ea7 ff15a0128776 call dword ptr [shell32!_imp__RegOpenKeyExW (768712a0)]
Remember that function parameters are passed in in reverse order, so the second parameter is the second to last value passed to the function. In this case, we can see that it was stored in eax. Of course, eax has been overwritten by our return value of 2, but we can see that just before pushing eax, we get the value from ebp-0x270. Dumping that out as a Unicode string, we get the key we were looking for:
0:020> du @ebp-270h
14c5ed54 "Software\Microsoft\Windows\Curre"
14c5ed94 "ntVersion\Control Panel\Extended"
14c5edd4 " Properties\System.ApplicationNa"
14c5ee14 "me"
The first parameter is the root key, which was:
0:020> dc @ebp-278h L1
14c5ed4c 80000002
We can look up this value in the Windows SDK header files and see that it is for HKLM:
#define HKEY_LOCAL_MACHINE (( HKEY ) (ULONG_PTR)((LONG)0x80000002) )
Aha! So now we know we were trying to access “HKLM\ Software\Microsoft\Windows\CurrentVersion\Control Panel\Extended Properties\System.ApplicationName” which didn’t exist, so we were unable to proceed with loading the icon.
What’s that key for, you ask? MSDN tells us that it is used to store the Canonical Name of the Control Panel item. Canonical Names were added to the Control Panel in Windows Vista as a better way to organize and name the items in the Control Panel. By convention, the canonical name of “Mail” is “Microsoft.Office.Outlook.Profiles.” Because the “Show only specified control panel applets” policy can now accept either the legacy name (“Mail”) or the canonical name, we are checking the registry for this string. Since the key is not present, GetDetailsEx cannot determine the canonical name, and the icon does not load.
As a test, I created the key HKLM\ Software\Microsoft\Windows\CurrentVersion\Control Panel\Extended Properties\System.ApplicationName and added a REG_SZ to it with a name of the file location of the Mail CPL file (“C:\Program Files\Common Files\SYSTEM\MSMAPI\1033\MLCFG32.CPL”) and a value of “Microsoft.Office.Outlook.Profiles”. Sure enough, the icon loads up on the first try for new users.
While new Control Panel items should implement a canonical name, that doesn’t work for existing CPLs, like Mail from Outlook 2003. Since the canonical name isn’t actually required (CPL_DoesPolicyAllow works with both name formats), we’re following up with the development team to allow CPL_DoesPolicyAllow to be called even if a canonical name is not found.
-Matt Burrough