Last days an annoying error was shown every time I close BDS 2006 (with CnWizards_0.8.2.356:
Exception error at ..... in module hhctrl.ocx.
After I played a little I found that error appears only if cnwizard is loaded. My problem was to find the error point (pretty hard).
Stepping over my digging researches, the problem is in this function:
function UnLoadHtmlHelp: Boolean;
begin
Result := True;
if HtmlHelpLoaded then
begin
if Assigned(HtmlHelp) then HtmlHelp(0, nil, HH_CLOSE_ALL, 0);
Result := FreeLibrary(HtmlHelpLib);
HtmlHelpLib := 0;
@HtmlHelpA := nil;
@HtmlHelpW := nil;
@HtmlHelp := nil;
end;
end;
and, more specific, in HtmlHelp(0, nil, HH_CLOSE_ALL, 0).
Seems is an known issue which is not solved by Microsoft.
see this link: http://www.helpware.net/FAR/far_faq.htmin section: HH_CLOSE_ALL Bug and HH_INITIALIZE
copy/paste the text:
Problem:
Marcel van Brakel has uncovered a real problem with HH_CLOSE_ALL. When you call HH_CLOSE_ALL on shut down, the HH API creates another thread and sometimes does not return until after you have performed UnLoadLibrary(hhctrl.ocx). In this case the HH_CLOSE_ALL thread returns to nothing and causes an access violation.
Discussion:
Ralph Walden (x-Microsoft) describes the problem:
The switch to a background thread was done after I left (the MS help team) in order to solve a problem with Visual Studio. I knew they should have fixed Visual Studio instead of "fixing" HTML Help (which wasn't broken). I've never actually tried it, but along with that change was a hack that allowed you to call the API in a way that it would create an interface, and then you'd call the API again to release that interface. You start off with HH_INITIALIZE and end with HH_UNINITIALIZE. Another alternative would be to set the HH_GPROPID_SINGLETHREAD property to TRUE -- that might get HTML Help back onto the parent's thread.
Fix:
- As described by Ralph above, you can try using the HH_INITIALIZE, HH_UNINITIALIZE commands. These are documented in the HH Workshop online help.
- Call HH_CLOSE_ALL earlier. Get more space between the HH_CLOSE_ALL and your call to UnloadLibrary. In VB and Delphi you would perform the call on the Form QueryUnload _not_ on the Form Close or Destroy.
- Marcel van Brakel seemed to fix it by calling Sleep(0); immediately after the call to HH_CLOSE_ALL. Again providing more time for the rogue thread to return.
More Tips:
Here is an alternative to using HH_CLOSE_ALL. What I do with my applications is keep the handle of the HH Windows when making a help call: _HHwinHwnd := htmlhelp(...) and on shutdown call: if IsWindow(_HHwinHwnd) then
SendMessage( _HHwinHwnd, wm_close, 0, 0 ); |
This is 10 times faster code, and eliminates the need for HH_CLOSE_ALL completely.
Also, as programming wizard Roland Mechling points out, don't blindly call HH_CLOSE_ALL on shutdown. If a user does not have HTML Help installed then this call will crash your application. Here is safer code. Notice we are checking if HH is installed before calling HtmlHelp(); procedure HHCloseAll;
begin
If @HH.HtmlHelp <> Nil then //HH API is available
begin
HH.HtmlHelp(0, nil, HH_CLOSE_ALL, 0);
Sleep(0);
end;
end; |
Also a Borland bug report: http://qc.borland.com/wc/qcmain.aspx?d=48983
I know that is not a cnWizard bug but maybe someone knows a better workaround and can change UnLoadHtmlHelp function.
I tried Sleep(0) but seems doesn't help.
I'll come back with more info.
[
Last edited by cata at 2008-1-6 04:01 ]