Skip to content

ATL 3.0 (VS6.0) Control Creation Resource Leak

So yeah, this post isn’t about homeschooling.

There is a rare, weird bug in the old version of ATL (3.0, shipped with Visual Studio 6.0) where dynamically created ActiveX controls leak a single USER resource. This will not happen if you make an ATL Dialog class and place ActiveX controls on the dialog, but it will happen if you dynamically create new controls in child windows at runtime. As we need to do in our client’s application.

I’ve only seen it reported one other place, and the guy who ran into it didn’t find a fix. And I lost the reference to the place I found it. But if I find it again, I’ll link it.

Normally a leaked USER resource is going to be a window. So we spent a lot of time looking at the window creation code, trying to figure out what was wrong. But nothing was. Then we made sure that the control we were creating wasn’t leaking the resource, and it wasn’t. (It was leaking a directory handle, which we dutifully reported to the vendor, and got fixed the same day.)

Finally the light bulb went off and I remembered that there are USER objects that aren’t windows. So we systematically searched through the code for those and found the leak: an accelerator table.   I reproduce the working version below: change to ATLHOST.H in C:\Program Files\Microsoft Visual Studio\VC98\atl\include.

1390 //      ACCEL ac = { 0,0,0 };
1391 //      HACCEL hac = CreateAcceleratorTable(&ac, 1);
1392         pFrameInfo->cb = sizeof(OLEINPLACEFRAMEINFO);
1393         pFrameInfo->fMDIApp = m_bMDIApp;
1394         pFrameInfo->hwndFrame = GetParent();
1395 //      pFrameInfo->haccel = hac;
1396 //      pFrameInfo->cAccelEntries = 1;
1397         pFrameInfo->haccel = NULL;
1398         pFrameInfo->cAccelEntries = 0;

Apparently whoever wrote that code decided that it was more important to pass a valid accelerator table than to worry about, oh, cleaning up the resource you generated.  And couldn’t be bothered to see if the recipient of the pFrameInfo structure could deal with zero accelerator entries (yes it can, and MFC passes 0 just as I’ve now patched ATL to do.)