Obscure OLE Control Question

Dear Dr. GUI:

I am working with a client who is trying to make a call to a DLL from within an OCX. Since the OCX is using OCX30.DLL and the DLL is using MFC30.DLL, this seems to be a problem. The problem occurs with memory allocation between the two parts. Something allocated by the OCX cannot be freed by the DLL, and vice versa. Is this supposed to work?

As a workaround, we've made the DLL use OCX30.DLL instead of MFC30.DLL by changing the linker settings. This seems to work fine, but we always get a memory leak at termination (DYNALINK.LIB at 490A94). What's going on here? Which approach should we use, and how do we use it properly?

Dr. GUI replies:

I have been asked to include more obscure and really amazing questions. This one really fills the bill. However, before you question the usefulness of this question, consider that it will likely save at least one company from totally hitting the skids, laying off all employees, and filing Chapter 11.

MFC30.DLL can be used (directly or indirectly) only from Microsoft Foundation Class Library (MFC) applications. That means that an OLE control (.OCX file) cannot use MFC30.DLL or any dynamic-link library (DLL) that uses MFC30.DLL, since there is no guarantee that the application that is using the OCX is an MFC application using MFC30.DLL.

Using OC30.DLL in your DLL instead is okay, but be sure to compile with _AFXCTL instead of _AFXEXT.

In addition, be sure to set up the right module context in your DLL. Here is the code from OCD30.DLL (which contains the database classes for OCX controls) from MFC 3.1.

extern "C" BOOL WINAPI
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
{
   if (dwReason == DLL_PROCESS_ATTACH)
   {
      // NOTE: Important call to _AfxSetCurrentModuleTlsIndex.
      _AfxSetCurrentModuleTlsIndex(NULL_TLS);

      // Call DisableThreadLibraryCalls if available.
      BOOL (WINAPI* pfnDisableThreadLibraryCalls)(HMODULE);
      HMODULE hMod = GetModuleHandleA("KERNEL32.DLL");
      ASSERT(hMod != NULL);
      (FARPROC&)pfnDisableThreadLibraryCalls =
         GetProcAddress(hMod, "DisableThreadLibraryCalls");
      if (pfnDisableThreadLibraryCalls != NULL)
         (*pfnDisableThreadLibraryCalls)(hInstance);

      // Shared initialization.
      if (!AfxInitExtensionModule(extensionDLL, hInstance))
         return FALSE;   // failure

      // Wire up this DLL into the resource chain.
      // (In the Win32 version it is OK to create this in DllMain.)

      CDynLinkLibrary* pDLL = new CDynLinkLibrary(extensionDLL);
      if (pDLL == NULL)
         return FALSE;   // failure
      pDLL->m_bSystem = TRUE;

      // NOTE: Important call to AfxPopModuleContext.
      // Save a copy of our module data for later use.
      AfxPopModuleContext(NULL, TRUE);
   }
   else if (dwReason == DLL_PROCESS_DETACH)
   {
      TRACE0("OCD30D.DLL Terminating!\n\r");
   }
   return TRUE;    // ok
}

Doing something similar in your own OCX extension DLL should eliminate your memory leak.