title: OCX AfxOleRegisterTypeLib fails with error 0x80040200
body: <p>I upgraded an OCX library from VS2010/Win7 to VS2019/Win10. The project builds, however when I try and use <code>RegSvr32.exe</code> from an elevated command prompt, I receive error 0x0040200. I did a bit of debugging and the offending call is the call to <code>AfxOleRegisterTypeLib</code>.</p>
  
  <p><a href="https://i.stack.imgur.com/gRxhm.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/gRxhm.png" alt="RegSvr32.exe OCX error 0x80040200"></a></p>
  
  <p>Yes, I saw <a href="https://stackoverflow.com/questions/45877162/cannot-register-my-ocx-with-error-code-0x80040200">this</a> SO article, which states that "absence of a tlb file near the dll". Other searches state to run from an administrative command prompt.</p>
  
  <p>I do NOT have a TLB near the OCX control. If I try and create one using <code>tlbexp.exe</code>, I get the following error:</p>
  
  <blockquote>
    <p>TlbExp : error TX0000 : Could not load file or assembly 'file:///C:\pathto.ocx' or one of its dependencies. The module was expected to contain an assembly manifest.</p>
  </blockquote>
  
  <p>TlbExp command line (used Run as Administrator for all cmd.exe):</p>
  
  <pre><code>"C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.7.2 Tools\x64\tlbexp.exe" /VERBOSE "&lt;path to OCX file&gt;" /out:"&lt;path to .tlb output file&gt;"
  </code></pre>
  
  <p>I downloaded <code>Resource Tuner</code> and that shows the manifest nicely. The manifest does not have any TLB information.</p>
  
  <p><a href="https://i.stack.imgur.com/o49Lu.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/o49Lu.png" alt="Manifest for OCX file"></a></p>
  
  <p>I am thinking that maybe the OCX manifest needs something more that helps <code>TlbExp</code> get at the information that it wants, just a thought.</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"&gt;
    &lt;assemblyIdentity version="1.0.0.0" name="DriveOps.ocx"/&gt;
    &lt;trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"&gt;
      &lt;security&gt;
        &lt;requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3"&gt;
          &lt;requestedExecutionLevel level="requireAdministrator" uiAccess="false" /&gt;
        &lt;/requestedPrivileges&gt;
      &lt;/security&gt;
    &lt;/trustInfo&gt;
    &lt;compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"&gt;
      &lt;application&gt;
        &lt;!-- Windows 7 --&gt;
        &lt;supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" /&gt;
        &lt;!-- Windows 8 --&gt;
        &lt;supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" /&gt;
        &lt;!-- Windows 8.1 --&gt;
        &lt;supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" /&gt;
        &lt;!-- Windows 10 --&gt;
        &lt;supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" /&gt;
      &lt;/application&gt;
    &lt;/compatibility&gt;
    &lt;application xmlns="urn:schemas-microsoft-com:asm.v3"&gt;
          &lt;windowsSettings&gt;
        &lt;dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings"&gt;true&lt;/dpiAware&gt;
      &lt;/windowsSettings&gt;
    &lt;/application&gt;
  &lt;/assembly&gt;
  </code></pre>
  
  <p>I did use <code>Depends64</code> (aka <code>Dependency Walker 64-bit</code>) and there are no missing components DLLs. It finds all of them nicely, as does RegSvr32.exe.</p>
  
  <p><a href="https://i.stack.imgur.com/yOGi8.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/yOGi8.png" alt="Dependency Walker 64 output of 64-bit OCX (debug version)"></a></p>
  
  <p>Placing the OCX file in C:\Windows\System32 does not help.</p>
  
  <p>To anyone looking at the DLLs, these same DLLs work fine on the Win7 box. Here is some more information on the non-Windows DLLs</p>
  
  <ul>
  <li>PlxApi720_x64.dll:    PLX v7.2 API (The Broadcom PLX chip is a PCIe switch (think USB/network switch, just w/PCIe lanes)</li>
  <li>LSIDirectAccess.dll:  The LSI API is a self-contained DLL that allows the software to talk to the LSI HBA RAID adapter</li>
  <li>Ipp*.dll: The <code>Ipp</code> prefix are the DLLs used by the Intel Code Composer Studio redistribution (x64) files, here version 2011, an older one that needs to be updated to the latest and greatest, not to mention now free API. These are all in the <code>System32</code> folder.</li>
  </ul>
  
  <p>Here is the code:</p>
  
  <pre><code>// DllRegisterServer - Adds entries to the system registry
  STDAPI DllRegisterServer(void)
  {
      AFX_MANAGE_STATE(_afxModuleAddrThis);
  
      if (!AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid))
          return ResultFromScode(SELFREG_E_TYPELIB);           // &lt;- failure line, through debugging
  
      if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE))
          return ResultFromScode(SELFREG_E_CLASS);
  
      return NOERROR;
  }
  </code></pre>
  
  <p>The <code>Intel Code Composer Studio 2011</code> files are in the <code>C:\Windows\System32</code> directory, just like on the Win7 box.</p>
  
  <p>For what it is worth, <code>TlbExp</code> fails on the Win7 box too, just it registers, which is probably why the UI can add the control. As I recall, I once replaced the OCX on the Win7 project and VS2010 automatically created the TLB and prefixed Ax in front, but that was a couple of years ago, so my memory may not be the most accurate. Attempting to add the OCX to the UI (.Net WinForms) fails miserably and just says could not be added.</p>
  
  <p>The OCX does use the latest platform tool set (<code>Visual Studio 2019 (v142)</code>).</p>
  
  <p><a href="https://i.stack.imgur.com/1Qwyb.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/1Qwyb.png" alt="OCX property page"></a></p>
  
  <p>A comment for developer newbies, <code>regasm.exe</code> is for .Net Assemblies. <code>RegSvr32.exe</code> is for <code>ActiveX Controls (OCX/DLL)</code>, which is what I have. RegSvr32 is for dynamically loaded modules, hence the DllRegister entry point.</p>
  
  <p>Thoughts?</p>
  
  <p>Notes From Further Testing</p>
  
  <ol>
  <li><p>(Saturday 9/21/2019) When I upgraded, I created an empty C++ DLL project and then added all the files, changing the target extension to OCX going through the old project settings and when reasonable aligning them to the new project file wanting to keep things the same. I wanted to do a test and see what happens with a brand new OCX project. I saw that there was such a thing as "MFC ActiveX Control" for a project type in VS2019. I created that and saw that I got different base files, but more importantly RegSvr32.exe works. That means that either the mistake was the initial project file, so I need to import to a clean project or import piece by piece, if that is possible, and see where things break.</p></li>
  <li><p>(Saturday 9/21/2019) The new test project did not come with a manifest file and <code>TlbExp.exe</code> failed with the same error message like my real project. I went to add new item and saw "Package Manifest". That manifest file, though still produces the same TlbExp.exe error, looks quite different from the application manifest file from above. I created yet another new <code>MFC ActiveX Control</code> project and added in the manifest from above just changing names and saw that the project refused to build throwing 1) Error  c1010001 Values of attribute "level" not equal in different manifest snippets. and 2) LNK1327   failure during running mt.exe. That tells me that the original Win7 project and my Win10 project files probably have some error in it, otherwise VS should have thrown these errors to me. That does not answer why even on the test project <code>TlbExp.exe</code> fails. Maybe some attributes in the manifest are required. I just left the defaults.</p></li>
  </ol>
  
  <p>Package Manifest
  (It is the first time that I ever saw one of these. I always saw the app.manifest kind.)</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;!-- TODO: Make sure to set the Package attributes --&gt;
  &lt;Package xmlns="urn:Microsoft.WindowsPhone/PackageSchema.v8.00"
    Owner=""
    OwnerType="OEM"
    Platform=""
    Component=""
    SubComponent="Package"
    ReleaseType="Test" &gt;
  
    &lt;Components&gt;
      &lt;Driver InfSource="$(_RELEASEDIR)$(TARGETNAME).inf"&gt;
        &lt;Reference Source="$(_RELEASEDIR)$(TARGETNAME)$(TARGETEXT)" /&gt;
        &lt;Files&gt;
          &lt;!-- For kernel mode drivers, $(DRIVER_DEST) evaluates to "drivers" by default --&gt;
          &lt;!-- For user mode drivers, $(DRIVER_DEST) evaluates to "drivers\umdf" by default --&gt;
          &lt;File Source="$(_RELEASEDIR)$(TARGETNAME)$(TARGETEXT)" DestinationDir="$(runtime.system32)\$(DRIVER_DEST)" /&gt;
        &lt;/Files&gt;
      &lt;/Driver&gt;
  
    &lt;/Components&gt;
  &lt;/Package&gt;
  </code></pre>
  
  <ol start="3">
  <li>This <a href="https://cdivilly.wordpress.com/2008/03/14/debugging-com-dll-registration-problems/" rel="nofollow noreferrer">article</a> has an interesting approach, namely create a C++ DLL and then call <code>LoadLibrary(dll)</code> and after that <code>GetProcAddress(module, "DllRegisterServer")</code> to see which one fails. Well, in my case the both functions succeed. That means that the author missed one other failure branch and these two API calls are not the only thing that <code>RegSvr32.exe</code> does.</li>
  </ol>