Windows 7 x64 中 OCX 文件上的 LoadLibrary 失败
我需要从旧版 C++ Builder 编写的旧 Windows 应用程序中打开 html 帮助文件。 HtmlHelp 是通过 HtmlHelp.ocx 加载的,我是通过 LoadLibrary 加载的。
这多年来一直运行良好,但在 Windows 7 x64 中不再运行。在Windows7 x86下也可能会失败,但我没有安装此操作系统的计算机,所以目前无法尝试。
我按如下方式动态加载 hhctrl.ocx:
#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;
}
我检查了 %SystemRoot%\System32\hhctrl.ocx 是否存在于 Windows 7 系统上,并且确实存在。
为什么通过LoadLibrary加载失败?我该如何解决这个问题?
编辑: GetLastError 说(德语,所以我只是翻译):“找不到文件。”但我调试了该函数,路径为“%SystemRoot%\System32\hhctrl.ocx”,并且该文件确实存在。
另外,由于两个答案都指向 64 位与 32 位问题的方向:我的应用程序是在 C++ Builder 5 中编译的 32 位可执行文件,因此如果我没有记错的话,它应该是一个 32 位进程。或者我的假设是错误的?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
使用 ExpandEnvironmentStrings 函数展开 %SystemRoot% \System32\hhctrl.ocx 到用户安装的真实路径。 64位操作系统将正确地将扩展路径重定向到32位dll。
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.
您无法在 64 位进程中加载 32 位 dll,反之亦然。 ActiveX 控件当然是 Dll。
有时,您可以通过将 32 位 ActiveX 作为进程外服务器加载来解决此问题 - 然后根据需要将其托管在单独的 32 位(或 64 位)进程中。这要求 ActiveX 仅使用系统已经知道如何编组的接口,和/或项目构建的代理存根 DLL 的 64 位和 32 位版本。
Depends 是一个当您需要找出 Dll 无法加载的原因时非常有用的工具。当然,作为 64 位操作系统上的 32 位应用程序,您需要知道 32 位应用程序无法访问
%SYSTEMROOT%\System32
,并且也无法从HKCR 读取和写入直接。 System32 实际上包含 64 位操作系统二进制文件,HKCR 包含 64 位应用程序的注册表项。
称为“反射”的内核进程将 32 位应用程序完全透明地从 System32 重定向到
%SYSTEMROOT%\SysWow64
。同样,对
HKEY_CLASSES_ROOT
的注册表访问会重定向到“HKEY_CLASSES_ROOT\Wow6432Node”。你当然需要知道这一点,因为explorer和regedit是64位进程,并且会很高兴地向你展示System32和HKCR的64位内容。您需要显式导航到 32 位节点,以仔细检查 32 位进程将获得的视图。
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 fromHKCR
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.
我现在运行 W7 (x64) 时遇到完全相同的问题。
当我将“%SystemRoot%\System32\hhctrl.ocx”更改为“c:\windows\System32\hhctrl.ocx”时,它开始工作,但我想我需要弄清楚为什么 %SystemRoot% 解析错误。
顺便说一句:我正在 BCB2007 上构建一个 32 位应用程序。
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.