Under The Hood: Excel hung on SaveAs

Under The Hood: Excel hung on SaveAs

  • Comments 1

I am sorry for being inactive for a long time, as a “come-back-gift” I am starting a few new sections on my blog, I am sure you’ll enjoy ’em all. This post marks the beginning of series named “Under The Hood” (yeah, sure … I am guilty for being inactive for a long time, and I will do a pleading filled post ASAP :) )

So, the case was, “Whenever you click on “Save As” in excel, it hangs. No dialog box pops up”

My initial troubleshooting was based on the fact that more then likely it’s caused because of an ill behaving addin. I disabled all the addins, xla’s etc but, guess what! Still he could reproduce the issue.

At this point I was stuck and needed some more clues desperately .. so I reviewed every point in the case again and I do see a few interesting things ..

1) Initially issues was exhibiting only on a few boxes, but now it’s on a few hundred boxes.
2) Issue is reproducible in excel as well as in word (Although, it’s not always reproducible in word …)

The first clue is something that might point to a danger – the issue is spreading! what could spread? either a planned deployment or a virus!! I kept my figures crossed that it’s not the latter …

The other clue points to a fact that the issue is in some common code base, the first-n-closest-to-office-common-code-base that I could think of is – mso.dll.

Now, to move further – customer helped me with a memory dump. Here is the stack

0:005> k100
ChildEBP RetAddr 
0b87e458 77f6946c
ole32!CoCreateInstance+0x32 <— Creating instance of something
0b87e480 7c9f1695 shlwapi!SHCoCreateInstanceAC+0x3a
0b87e864 7c9ef619 shell32!_SHCoCreateInstance+0x127
0b87e8a4 7ca025bc shell32!SHCoCreateInstance+0x40
0b87e8c0 7ca0253f shell32!DCA_CreateInstance+0x2c
0b87ee2c 7ca02379 shell32!CFSIconOverlayManager::_LoadIconOverlayIdentifiers+0xd7
0b87ee3c 7ca02319 shell32!CFSIconOverlayManager::_InitializeHdsaIconOverlays+0x33
0b87ee50 7c9ef3ac shell32!CFSIconOverlayManager::CreateInstance+0x3f
0b87ee64 7c9f29d2 shell32!CCF_CreateInstance+0x2b
0b87ee80 7c9f299c shell32!_CreateFromDllGetClassObject+0x2d
0b87ee9c 7c9f2961 shell32!_CreateFromShell+0x1b
0b87f27c 7c9ef619 shell32!_SHCoCreateInstance+0x4e
0b87f2bc 7ca022b7 shell32!SHCoCreateInstance+0x40
0b87f2dc 7c9f41f2 shell32!IconOverlayManagerInit+0x26 <— Icon Overlay Manager calls
0b87f2e8 7ca02864 shell32!GetIconOverlayManager+0x10

0b87f750 7ca02063 shell32!_ShellImageListInit+0x29b
0b87f794 7ca31618 shell32!FileIconInit+0x19b
0b87f7a0 7ca2d215 shell32!Shell_GetImageLists+0x14
0b87f7f0 7ca2b0cf shell32!_GetFileInfoSections+0xe4
0b87fc78 327403f0 shell32!SHGetFileInfoW+0x13a
WARNING: Stack unwind information not available. Following frames may be wrong.
0b87ff60 3274027b mso!Ordinal6579+0x2c5
0b87ff78 326172d1 mso!Ordinal6579+0x150
<— MSO Calls … most likely “save as”
0b87ffac 3261710f mso!Ordinal577+0x1bc
0b87ffb4 7c80b713 mso!Ordinal320+0x31

0b87ffec 00000000 kernel32!BaseThreadStart+0x37

Looking at this stack, I can tell a few things  …

1)  Initial mso callstack tells us that excel were doing something with mso, which lead to the call shell32!SHGetFileInfoW, and we know what it could be as we clicked on “Save As”.
2) Then we do something with IconOverlayManager, I don’t know why; yet ..
3) Then we go for creating an instance of something .. I don’t what what for; yet ..

Let’s find out the “don’t knows” ..

0:005> ub <— When ub Address is used, the disassembled range will be the eight or nine byte range ending with Address
ole32!CoCreateInstance+0x1e:
77500599 8945f4          mov     dword ptr [ebp-0Ch],eax
7750059c 8d45f4          lea     eax,[ebp-0Ch]
7750059f 50              push    eax
775005a0 6a01            push    1
775005a2 6a00            push    0
775005a4 ff7510          push    dword ptr [ebp+10h]
775005a7 ff750c          push    dword ptr [ebp+0Ch]
775005aa ff7508          push    dword ptr [ebp+8]
<— Pushing parameters on the stack

0:005>
u <— When u Address is used, the disassembly begins at the current Address and extends eight instructions
ole32!CoCreateInstance+0x32:
775005ad e874ffffff      call    ole32!CoCreateInstanceEx (77500526) <— Call CoCreateInstanceEx
775005b2 8b4df8          mov     ecx,dword ptr [ebp-8]
775005b5 890e            mov     dword ptr [esi],ecx
775005b7 5e              pop     esi
775005b8 c9              leave
775005b9 c21400          ret     14h
775005bc 90              nop
775005bd 90              nop

Looked up for the function definition of  CoCreateInstanceEx;

HRESULT CoCreateInstanceEx(
  REFCLSID rclsid, /*[in] CLSID of the object to be created.*/

  IUnknown * punkOuter, 
  /*[in] When non-NULL, indicates the instance 
  is being created as part of an aggregate, and punkOuter is to be 
  used as the new instance's controlling IUnknown. Aggregation is currently 
  not supported cross-process or cross-machine. When instantiating an object
  out of process, CLASS_E_NOAGGREGATION will be returned if punkOuter is non-NULL. */

  DWORD dwClsCtx, /*[in] Values taken from the CLSCTX enumeration.*/

  COSERVERINFO * pServerInfo,
  /*[in] Information about the computer on which to instantiate 
  the object. May be NULL, in which case the object is instantiated
  on the local computer or at the computer specified in the registry 
  under the class's RemoteServerName named value, according to the 
  interpretation of the dwClsCtx parameter. See the CLSCTX documentation
  for details).*/

  ULONG cmq,/*[in] Number of MULTI_QI structures in pResults. Must be greater than zero.*/

  MULTI_QI * pResults 
  /*[in] Array of MULTI_QI structures. Each structure has three members: the
  identifier for a requested interface (pIID), the location to return the 
  interface pointer (pItf) and the return value of the call to QueryInterface (hr).*/
);

Looking at this description, we can surely say that ebp+8 should contain the address of a _GUID structure variable (which contains the clsid of the object to be created) … let’s see what it is!

0:005> dt poi(ebp+8) _GUID
ntdll!_GUID
 {3cec3e6d-ecf2-4b49-8a41-3b16df8b9c3f}
   +0x000 Data1            : 0x3cec3e6d
   +0x004 Data2            : 0xecf2
   +0x006 Data3            : 0x4b49
   +0x008 Data4            : [8]  "???"

We’ve got it!!!

Now, I don’t know what this clsid refers to, I checked in my registry, it wasn’t there. Then I remembered that customer also gave me his procmon log (You might already know about procmon, but if not , please don’t forget to visit Sysinternals ).

I had a look at the procmon log with the following filters

image

and this is what I see …

image

So, I got the name of the dll that is being instantiated  (name doesn’t matter, it’s the one I removed from the picture above – say foo.dll). I suggested the customer to unregister this dll and see if it helps, he came back with the information that, the path and the dll name we gave him are not present on his machine, he told us that he did install this component (which is basically an Icon Overlay Handler), but they have uninstalled it ….

Next action plan is to know, how did we get the reference to this component, checked again in the promon, changing the filter a bit -

image

This tells me

image

Huh, that means this GUID was picked up from a subkey of “HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers”

Then I suggested the customer to take a backup of his registry, and remove this subkey from ShellIconOverlayIdentifiers and remove the GUID key ({3CEC3E6D-ECF2-4B49-8A41-3B16DF8B9C3F}” ) from “HKCR\CLSID”.

This worked like a charm!! The case is resolved!!

(btw, if you remember our first clue, this information is almost similar to our assumptions, we assumed deployments, this was uninstallation … so, maybe in this specific case, uninstaller wasn’t removing all the entries, this in turn rendered SaveAs useless for excel whenever you uninstalled this specific product!

Talk to you latter ..bye!

Leave a Comment
  • Please add 2 and 8 and type the answer here:
  • Post
  • You might want to reconsider calling this blog "Under the Hood". That sort of belongs to Matt Pietrek (http://blogs.msdn.com/matt_pietrek/) who wrote the "Under the Hood" column for MSDN magazine for so many years, and is still the name of his blog.

    Point taken! I will change the name of the section for all future posts to something else, the only problem is ..what? any suggestions?
    While we are on it, let me tell you that I am a big fan of Matt, hey matt - you don't know how many fans do you have, in and out of MS! In fact one of my reasonablly complicated case got solved just because of his posts "Under the hood: Just Enough Assembly To Get By, Part 1 and Part 2 ( .. and I am such a moron, that I forgot to thank him .. )

Page 1 of 1 (1 items)