Explorer.exe crashes due to ComCtrl32 when Destroying Button on a .Exe Window when a Deskband is open having button with same name/id?

0

I have a strange one. I have two forms of my x64 app, one is a DeskBand and one uses a normal Window. Both have their own class names that are registered (the normal Window version adds Exe to the class name). Several owner-draw buttons are created on the main Window. They have text, icon, and tooltip. Everything works fine if I run as the DeskBand or the Window version (on Win10), but if I have both the Deskband active (checked to show up on the TaskBar) and Window version running, when I close the Window (.exe) version, explorer.exe crashes on each ::DestroyWindow() called for each button (if full speed you get one crash, but if you step through it in debug mode, each one causes a crash). It's done on the WM_DESTROY message being sent to the app. I checked spy, each button has its own handle, the window class for the main windows are correct (different between deskband and window). The DeskBand version is still running fine afterwards.

The event viewer information is:

Faulting application name: explorer.exe, version: 10.0.18362.628, time stamp: 0xc3041aa6
Faulting module name: comctl32.dll, version: 6.10.18362.657, time stamp: 0xabe19732
Exception code: 0xc0000005
Fault offset: 0x000000000006fd23
Faulting process id: 0x4658
Faulting application start time: 0x01d5f510f0740d42
Faulting application path: C:\WINDOWS\explorer.exe
Faulting module path: C:\WINDOWS\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.18362.657_none_e6c5b579130e3898\comctl32.dll
Report Id: 37ac6912-eb7c-43c8-b566-821b53569f15
Faulting package full name: 
Faulting package-relative application ID: 

Here's the basic part that creates and destroys the buttons.

HWND CMyOwnerDrawButton::Create(int x, int y, int nwidth, int nheight, HWND hwndparent, HINSTANCE hresinstance, bool tintover, bool themed)
{
  // if duplicate just return existing handle
  if (m_hWnd) {
    return m_hWnd;
  }

  // set initial flags state
  SetThemed(themed);
  SetTintOver(tintover);

  // get text for button and tooltip
  CString buttontext;
  buttontext.LoadString(hresinstance, m_ResIDText);

  m_hWnd=::CreateWindowEx(0, 
                        WC_BUTTON, 
                        buttontext, 
                        BS_OWNERDRAW | BS_ICON | BS_NOTIFY | WS_VISIBLE | WS_CHILD | WS_TABSTOP, 
                        x, 
                        y,
                        nwidth, 
                        nheight, 
                        hwndparent, 
                        (HMENU) (INT_PTR) m_ID, 
                        NULL, 
                        NULL);
  if (m_hWnd) {
    // get width of icon to use
    int cx=0;
    int cy=0;

    // get the icon directory
    const GRPICONDIR *icondir;
    if ((icondir=::GetIconDirectory(hresinstance, m_ResIDIcon))!=NULL) {
      // search for the size we want - largest that is smaller than the button
      for (UINT i=0;i<icondir->idCount;i++) {
        // find x
        if (icondir->idEntries[i].bWidth>cx && icondir->idEntries[i].bWidth<nwidth) {
          cx=icondir->idEntries[i].bWidth;
          // find y
          if (icondir->idEntries[i].bHeight>cy && icondir->idEntries[i].bHeight<nheight) {
            cy=icondir->idEntries[i].bHeight;
          }
        }
      }
    }

    // load icon to use - presume all icons are the same size
    m_hIcon=(HICON) ::LoadImage(hresinstance, MAKEINTRESOURCE(m_ResIDIcon), IMAGE_ICON, cx, cy, LR_SHARED);
    if (m_ResIDIconOver) {
      m_hIconOver=(HICON) ::LoadImage(hresinstance, MAKEINTRESOURCE(m_ResIDIconOver), IMAGE_ICON, cx, cy, LR_SHARED);
    }

    // get icon size actually loaded
    if (!::GetIconSizeInfo(m_hIcon, &m_IconSizeInfo)) {
      // assume size
      m_IconSizeInfo.nBitsPerPixel=1;
      m_IconSizeInfo.nHeight=nheight;
      m_IconSizeInfo.nWidth=nwidth;
    }

    // subclass control 
    ::SetWindowSubclass(m_hWnd, SubclassProc, m_ID, (DWORD_PTR) this);

    // create tool tip
    ::CreateToolTip(m_ID, hwndparent, buttontext);
  }

  return m_hWnd;
}

//-------------------------------------------------------------------------
// Purpose: Destroy button created
// 
// Input:   na
//
// Output:  na
//
// Notes:
//
void CMyOwnerDrawButton::Destroy()
{
  if (m_hWnd) {
    ::ShowWindow(m_hWnd, SW_HIDE);
    ::DestroyWindow(m_hWnd);  // <<<< THIS IS WHERE EXPLORER.EXE CRASHES IF DESKBAND IS ACTIVE
    m_hWnd=NULL;
  }
}
windows
winapi
windows-shell
comctl32
asked on Stack Overflow Mar 8, 2020 by df234987

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0