1

Using C++ Builder 10 Seattle (CX10).

I have a .chm with map IDs for certain topics. I can load the topics into an external window like this:

#include "Vcl.HTMLHelpViewer.hpp"

#pragma link "Vcl.HTMLHelpViewer"

// In the main form constructor:
Application->HelpFile = ExtractFilePath(Application->ExeName) + "MyHelp.chm";

// In button click event handler:
Application->HelpContext(10001);

This is great for many situations, but sometimes I want to embed the context-specific help within my TForm, such as on a TPanel. I found pieces of information about using WinAPI functions FindWindow and SetParent. So I tried this:

HWND t_hwnd = FindWindow(NULL, "My Help File");
if (t_hwnd)
{
    // HelpPanel is a TPanel with no properties adjusted from default
    ::SetParent(t_hwnd, HelpPanel->Handle);
}

Which compiles, links, runs and doesn't crash... but the subsequent call to Application->HelpContext(10001) still displays the topic in the external window, and not in the HelpPanel.

I am guessing that the easy-to-use Application->HelpContext call isn't what I need for redirecting to a VCL control, but I don't know where to look next.

Following up on the comments, here is where I am: I found out the ilink32 error (see my comment, below) was because I need to load HHCTRL.ocx in order to make a call to HtmlHelpA. So here is my test project code, a form with a TRadioGroup and TPanel. Only one radio button attempts to place the topic on the TPanel; the rest use Application->HelpContext. All of this compiles, links and runs, but the call to place the help on TPanel doesn't do anything visible.

Really hoping somebody can help... thanks.

// MainFrm.dfm
object MainForm: TMainForm
  Left = 0
  Top = 0
  Caption = 'MainForm'
  ClientHeight = 486
  ClientWidth = 686
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object FunctionsRadioGroup: TRadioGroup
    Left = 8
    Top = 8
    Width = 185
    Height = 105
    Caption = 'EDITS Language Functions'
    Items.Strings = (
      'LOOKUP'
      'RLOOKUP'
      'ILOOKUP'
      'STRCPY')
    TabOrder = 0
    OnClick = FunctionsRadioGroupClick
  end
  object HelpPanel: TPanel
    Left = 199
    Top = 8
    Width = 490
    Height = 477
    Caption = 'HelpPanel'
    TabOrder = 1
  end
end

// MainFrm.h
#ifndef MainFrmH
#define MainFrmH
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include <Vcl.ExtCtrls.hpp>
//---------------------------------------------------------------------------

typedef HWND (WINAPI *FPHH) (HWND, LPCSTR, UINT,  DWORD);

// Map IDs in my CHM
#define LANG_FUNC_LOOKUP    10001
#define LANG_FUNC_RLOOKUP   10002
#define LANG_FUNC_STRCPY    10004
#define LANG_FUNC_ILOOKUP   10003

class TMainForm : public TForm
{
__published:    // IDE-managed Components
    TRadioGroup *FunctionsRadioGroup;
    TPanel *HelpPanel;
    void __fastcall FunctionsRadioGroupClick(TObject *Sender);
private:    // User declarations
    HINSTANCE FHHCTRL_OCX_INST;
    FPHH htmlHelp;

    bool __fastcall load_HHCTRL_OCX();

public:        // User declarations
    __fastcall TMainForm(TComponent* Owner);
    __fastcall ~TMainForm();

    void __fastcall DoShowEmbeddedHelp(TPanel* ThePanel, NativeInt TheTopicID);
};
//---------------------------------------------------------------------------
extern PACKAGE TMainForm *MainForm;
//---------------------------------------------------------------------------
#endif

// MainFrm.cpp
#include <vcl.h>
#pragma hdrstop

#include "MainFrm.h"
#include <Vcl.HTMLHelpViewer.hpp>
#include <HtmlHelp.h>

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "Vcl.HTMLHelpViewer"
//#pragma link "htmlhelp.lib"
#pragma resource "*.dfm"
TMainForm *MainForm;
//---------------------------------------------------------------------------
__fastcall TMainForm::TMainForm(TComponent* Owner)
    : TForm(Owner)
{
    Application->HelpFile = ExtractFilePath(Application->ExeName) +
        "MyHelpFile.chm";

    FHHCTRL_OCX_INST = 0;

} // ctor
//---------------------------------------------------------------------------
__fastcall TMainForm::~TMainForm()
{
    if (FHHCTRL_OCX_INST > 0)
    {
        FreeLibrary(FHHCTRL_OCX_INST);
    }
}// dtor
//---------------------------------------------------------------------------
void __fastcall TMainForm::FunctionsRadioGroupClick(TObject *Sender)
{
    TRadioGroup* t_radio = dynamic_cast<TRadioGroup*>(Sender);

    if (t_radio)
    {

        switch (t_radio->ItemIndex)
        {
            case 0:
                //Application->HelpContext(LANG_FUNC_LOOKUP);
                DoShowEmbeddedHelp(HelpPanel, LANG_FUNC_LOOKUP);
                break;

            case 1:
                Application->HelpContext(LANG_FUNC_RLOOKUP);
                break;

            case 2:
                Application->HelpContext(LANG_FUNC_ILOOKUP);
                break;

            case 3:
                Application->HelpContext(LANG_FUNC_STRCPY);
                break;

        }
    }
}
//---------------------------------------------------------------------------
bool __fastcall TMainForm::load_HHCTRL_OCX()
{
    bool t_is_loaded = (FHHCTRL_OCX_INST > 0);
    if (!t_is_loaded)
    {
        FHHCTRL_OCX_INST = LoadLibrary("HHCTRL.OCX");
        if (FHHCTRL_OCX_INST > 0)
        {
            (FARPROC&) htmlHelp = GetProcAddress(FHHCTRL_OCX_INST, "HtmlHelpA");
            if (htmlHelp)
            {
                t_is_loaded = true;
            }
        }
    }

    return t_is_loaded;
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::DoShowEmbeddedHelp(TPanel* ThePanel, NativeInt TheTopicID)
{
    HH_WINTYPE wintypedef;
    AnsiString t_helpfile = ExtractFilePath(Application->ExeName) + "MyHelpFile.chm";
    AnsiString TheWinName = "HelpPanel";

    if (!FileExists(t_helpfile))
    {
        MessageDlg(AnsiString("Help file not found: ") + t_helpfile,
            mtError, TMsgDlgButtons() << mbOK, 0);
        return;
    }

    // Zero the structure
    memset(&wintypedef, 0, sizeof(HH_WINTYPE));
    // Prepare the properties
    wintypedef.cbStruct = sizeof(wintypedef);
    wintypedef.fUniCodeStrings = false;
    wintypedef.pszType = TheWinName.c_str();
    wintypedef.fsValidMembers =
            HHWIN_PARAM_PROPERTIES |
            HHWIN_PARAM_STYLES |
            HHWIN_PARAM_EXSTYLES |
            HHWIN_PARAM_RECT |
            HHWIN_PARAM_NAV_WIDTH |
            HHWIN_PARAM_SHOWSTATE |
            HHWIN_PARAM_TB_FLAGS |
            HHWIN_PARAM_EXPANSION;

    wintypedef.fsWinProperties =
            HHWIN_PROP_NOTITLEBAR |
            HHWIN_PROP_NO_TOOLBAR |
            HHWIN_PROP_NODEF_STYLES |
            HHWIN_PROP_NODEF_EXSTYLES |
            HHWIN_PROP_TRI_PANE;

    wintypedef.pszCaption = "";
    wintypedef.dwStyles = WS_VISIBLE | WS_CHILDWINDOW;
    wintypedef.dwExStyles = WS_EX_LEFT;
    wintypedef.rcWindowPos =
        Rect(0, 0, ThePanel->ClientWidth, ThePanel->ClientHeight);

    wintypedef.nShowState = SW_SHOW;
    wintypedef.fsToolBarFlags = HHWIN_BUTTON_PRINT | HHWIN_BUTTON_BACK ;
    wintypedef.fNotExpanded = true;

    if (load_HHCTRL_OCX())
    {
        if ((int)htmlHelp(0, NULL, HH_SET_WIN_TYPE, (DWORD)&wintypedef) < 0)
        {
            ShowMessage("Help failed on topic");
        }
        else
        {
            /* NOTE: This was close, but wrong. 
            int HelpWinHandle =
                (int)htmlHelp(ThePanel->Handle, "HelpPanel", HH_HELP_CONTEXT, TheTopicID);
             */

            AnsiString t_fn = t_helpfile + AnsiString(">HelpPanel");
            int HelpWinHandle =
               (int)htmlHelp(ThePanel->Handle, t_fn.c_str(), HH_HELP_CONTEXT, TheTopicID);


        }


    }
} // DoShowEmbeddedHelp
//---------------------------------------------------------------------------
Kathleen
  • 108
  • 7

2 Answers2

0

This is deep going into HTMLHelp API (written in C++ 20 years ago by Ralph Walden). You maybe warned ...

I have experience in help authoring and I'm not a C++ programmer. So, the HTMLHelp Viewer hh.exe is a wrapper for Internet Explorer API showing the CHM's HTML topics in the content pane on the right.

You know "Application->HelpContext(10001);" is calling the Help Viewer with the specified topicId "10001" always. Embedded help is less in use and today not what the users want. A second help window is easier of course.

Some ideas and a trick e.g. to shrink the viewer done by the help author (creator of the CHM file) you'll see at: Microsoft HTML Help - Get the topic page URL from the topic ID

Further information - sorry Delphi - you'll find at: How to control/remove borders of embedded chm help file in delphi windows/vcl application?

HTH

Community
  • 1
  • 1
help-info.de
  • 6,695
  • 16
  • 39
  • 41
  • Thanks for this. I agree that the second help window is desirable for many/most situations, but I have one form that lists topics and wanted the associated help for each to appear in an adjacent panel as the user moves up/down the list. I can work out another way to get there, though. I _will_ take a swing at translating the Delphi example to C++... if I get the sucker working, I'll post it here. Thanks again. – Kathleen Jan 21 '16 at 14:03
  • I have a translation of the Delphi code (in the same test app that uses Vcl.HtmlHelpViewer.hpp), Added #include and it compiles, but now get **[ilink32 Error]: Unresolved external 'HtmlHelpA'** Added to my Libraries path **$(BDSLIB)\win32\release\psdk** where I _see_ htmlhelp.lib, but no change. What do I need to do? – Kathleen Jan 21 '16 at 16:07
0

All right, I finally figured it out.

In the code I posted for function TMainForm::DoShowEmbeddedHelp, I did not properly prepare the second parameter to HtmlHelpA. It SHOULD be this:

AnsiString t_fn = t_helpfile + AnsiString(">HelpPanel");
HelpWinHandle =
    (int)htmlHelp(ThePanel->Handle, t_fn.c_str(), HH_HELP_CONTEXT, TheTopicID);

Now I am getting the result I wanted.

Kathleen
  • 108
  • 7