LoadLibrary on OCX file fails in Windows 7 x64

2019-03-06 02:20发布

问题:

I need to open a html help file from within a legacy windows application written in old version of C++ Builder. HtmlHelp is loaded via HtmlHelp.ocx, which I am loading via LoadLibrary.

This has worked fine for years, but it does not work anymore in Windows 7 x64. It might also fail under Windows7 x86, but I don't have any computer with this OS, so I can't try it out at the moment.

I am loading hhctrl.ocx dynamically as follows:

#define HHPathRegKey "CLSID\\{adb880a6-d8ff-11cf-9377-00aa003b7a11}\\InprocServer32"

bool THTMLHelper::LoadHtmlHelp()
{
  HKEY HHKey;
  DWORD PathSize = 255;
  char Path[255];
  bool R = false;

  if (::RegOpenKeyExA(HKEY_CLASSES_ROOT, HHPathRegKey, 0, KEY_QUERY_VALUE, (void **)&HHKey) == ERROR_SUCCESS)
  {
    if (::RegQueryValueExA(HHKey, "", NULL, NULL, (LPBYTE)Path, &PathSize) == ERROR_SUCCESS)
    {
      //*****************************************
      //LOADING FAILS HERE
      //PATH IS %SystemRoot%\System32\hhctrl.ocx          
      //*****************************************
      HHLibrary = ::LoadLibrary(Path);
      if (HHLibrary != 0)
      {
        __HtmlHelp = (HTML_HELP_PROC) ::GetProcAddress(HHLibrary, "HtmlHelpA");
        R = (__HtmlHelp != NULL);
        if (!R)
        {
          ::FreeLibrary(HHLibrary);
          HHLibrary = 0;
        }
      }
    }
    ::RegCloseKey(HHKey);
  }
  return R;
}

I checked if %SystemRoot%\System32\hhctrl.ocx exists on the Windows 7 system and it does.

Why does loading it via LoadLibrary fail? How can I work around this problem?

EDIT: GetLastError says (in German, so I am just translating): "Could not find file." But I debugged the function and the path is "%SystemRoot%\System32\hhctrl.ocx" and the file does exist.

Also, since two answers point in the direction of 64-bit vs 32-bit problems: My application is a 32 bit executable compiled in C++ Builder 5, so it should be a 32 bit process if I'm not mistaken. Or am I wrong to assume that?

回答1:

Use ExpandEnvironmentStrings function to expand %SystemRoot%\System32\hhctrl.ocx to real path on user's intallation. 64bit OS will redirect expanded path to 32bit dll correctly.



回答2:

You can't load 32bit dlls in a 64bit process, and visa versa. ActiveX controls are, of course, Dlls.

You can sometimes work around this by getting the 32bit ActiveX to load as an out-of-process server - its then hosted in a seperate 32bit (or 64bit) process as appropriate. This requires that the ActiveX onlyuses interfaces the system already knows how to marshal, and/or the project built 64bit AND 32bit versions of the proxy stub dll.


Depends is a tool that is very useful when you need to figure out why Dlls wont load. Of course, as a 32 bit application on a 64bit OS you need to know that 32 bit applications do NOT get access to %SYSTEMROOT%\System32 and, also do NOT read and write from HKCR directly. System32 actually contains the 64bit OS binaries, and HKCR contains the registry entries for 64bit apps.

A kernel process called 'reflection' redirects 32bit apps completely transparently to from System32 to %SYSTEMROOT%\SysWow64. Likewise, registry access to HKEY_CLASSES_ROOT is redirected to `HKEY_CLASSES_ROOT\Wow6432Node'. You need to know this of course, because explorer and regedit are 64bit processes and will happily show you the 64bit contents of System32 and HKCR. You need to explicitly navigate to the 32bit nodes to double check the view your 32bit process is going to get.



回答3:

I have the exact same problem right now running W7 (x64).

I got it to work when I changed the "%SystemRoot%\System32\hhctrl.ocx" to "c:\windows\System32\hhctrl.ocx", but I guess I need to figure out why %SystemRoot% resolves wrong.

btw: I'm building a 32bit app on BCB2007.