How to host HTML Help Viewer in MDI child form?

G

Guest

I am developing an MDI Windows Forms application using VS.NET 2003 in C#. I
want to display help for the application when the user presses the F1 key. I
have been able to get the HTML Help Viewer to display in a separate form as
shown below.

Is there a way to display the help viewer within an MDI child form (displays
in the main form's client area)?

Thanks,
Dave

###### Current code ######
public class HelpControlBase
{
protected const int HH_HELP_CONTEXT = 0x000F;
protected const string helpClassName = "HH Parent";
protected string appPath;

[DllImport( "HHCtrl.ocx" )]
public extern static int HtmlHelp( int hwnd, string pszFile, int cmd, int
data );

public HelpControlBase()
{
appPath = Application.StartupPath; // Get the application path string.
}

virtual protected int DisplayHelp( int helpID, string fileName )
{
// Open the HelpViewer window.
return HelpControlBase.HtmlHelp( 0, appPath + fileName, HH_HELP_CONTEXT,
helpID );
}
}
 
J

Jeffrey Tan[MSFT]

Hi Dave,

Thanks for your post!!

Based on my understanding, you p/invoke unmanaged HTML Help API to
implement the F1 help function in your application. But currently, you want
to display the CHM file window as a Child window of your MDI parent window.
If I misunderstand you, please feel free to tell me. Thanks

..Net provided a managed substitution for this, which is named HelpProvider
component. We may leverage this component to get the F1 help function.

Now, for your MDI child window issue, I think this is not build-in
supported. There is no interface for us to explicit make a Html Help Viewer
as the MDI child window. Normally, I think we have 2 workaround options for
it:

#1, Intercept the F1 key event in our MDI app, dynamically decompile the
CHM file, then display the decompiled html pages in a customized editor,
while we can make this customized editor a MDI child window. Maybe we can
use a webbrowser to display the decompiled html pages. This is what many
MDI applicaiton do in their application.
#2, After the CHM file is displayed, we explicitly find this CHM window,
change its window style as MDI child and set its parent to our MDI parent
window. For this way, I have writen a little sample:

private void Form1_Load(object sender, System.EventArgs e)
{
Form f=new Form();
f.MdiParent=this;
f.Show();
this.KeyPreview=true;
}

[DllImport("user32.dll")]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll")]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

private const int GWL_EXSTYLE=-20;
private const int GWL_STYLE=-16;
private const int WS_EX_MDICHILD=0x00000040;
private const int WS_CHILD=0x40000000;
private void Form1_KeyUp(object sender, System.Windows.Forms.KeyEventArgs e)
{
if(e.KeyData==Keys.F1)
{
System.Diagnostics.Process.Start(@"D:\Course ware\Programingwidnows.chm");
System.Threading.Thread.Sleep(500);
IntPtr hCHMWnd=FindWindow("HH Parent", "Programming Windows, Fifth
Edition");
if(!hCHMWnd.Equals(IntPtr.Zero))
{
SetWindowLong(hCHMWnd, GWL_STYLE,
GetWindowLong(hCHMWnd, GWL_STYLE)|WS_CHILD);
SetWindowLong(hCHMWnd, GWL_EXSTYLE,
GetWindowLong(hCHMWnd, GWL_EXSTYLE)|WS_EX_MDICHILD);
SetParent(hCHMWnd, this.Handle);
}
else
{
MessageBox.Show("Can not find the CHM file!!");
}
}
}
Hope this helps.
============================================
Thank you for your patience and cooperation. If you have any questions or
concerns, please feel free to post it in the group. I am standing by to be
of assistance.

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
G

Guest

Jeffrey,

Thanks for your reply. What you suggest seems close to what I need. My MDI
application uses child forms that all derive from a common base class so that
they all have common behaviors. This class is ChildFormBase. Is there a way
to get the hCHMWnd in your option #2 below to be contained within a form of
type ChildFormBase?

Thanks,
Dave

"Jeffrey Tan[MSFT]" said:
Hi Dave,

Thanks for your post!!

Based on my understanding, you p/invoke unmanaged HTML Help API to
implement the F1 help function in your application. But currently, you want
to display the CHM file window as a Child window of your MDI parent window.
If I misunderstand you, please feel free to tell me. Thanks

.Net provided a managed substitution for this, which is named HelpProvider
component. We may leverage this component to get the F1 help function.

Now, for your MDI child window issue, I think this is not build-in
supported. There is no interface for us to explicit make a Html Help Viewer
as the MDI child window. Normally, I think we have 2 workaround options for
it:

#1, Intercept the F1 key event in our MDI app, dynamically decompile the
CHM file, then display the decompiled html pages in a customized editor,
while we can make this customized editor a MDI child window. Maybe we can
use a webbrowser to display the decompiled html pages. This is what many
MDI applicaiton do in their application.
#2, After the CHM file is displayed, we explicitly find this CHM window,
change its window style as MDI child and set its parent to our MDI parent
window. For this way, I have writen a little sample:

private void Form1_Load(object sender, System.EventArgs e)
{
Form f=new Form();
f.MdiParent=this;
f.Show();
this.KeyPreview=true;
}

[DllImport("user32.dll")]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll")]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

private const int GWL_EXSTYLE=-20;
private const int GWL_STYLE=-16;
private const int WS_EX_MDICHILD=0x00000040;
private const int WS_CHILD=0x40000000;
private void Form1_KeyUp(object sender, System.Windows.Forms.KeyEventArgs e)
{
if(e.KeyData==Keys.F1)
{
System.Diagnostics.Process.Start(@"D:\Course ware\Programingwidnows.chm");
System.Threading.Thread.Sleep(500);
IntPtr hCHMWnd=FindWindow("HH Parent", "Programming Windows, Fifth
Edition");
if(!hCHMWnd.Equals(IntPtr.Zero))
{
SetWindowLong(hCHMWnd, GWL_STYLE,
GetWindowLong(hCHMWnd, GWL_STYLE)|WS_CHILD);
SetWindowLong(hCHMWnd, GWL_EXSTYLE,
GetWindowLong(hCHMWnd, GWL_EXSTYLE)|WS_EX_MDICHILD);
SetParent(hCHMWnd, this.Handle);
}
else
{
MessageBox.Show("Can not find the CHM file!!");
}
}
}
Hope this helps.
============================================
Thank you for your patience and cooperation. If you have any questions or
concerns, please feel free to post it in the group. I am standing by to be
of assistance.

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
J

Jeffrey Tan[MSFT]

Hi Dave,

Thanks for your feedback!!

No, I do not think there is way to place the chm file to be contained
within a form of type ChildFormBase. This is because chm file window is a
top level window, which can not be contained in another form. In #2, we can
only place chm window as the mdi child of the main MDI container.

For #1, if you can successfully decompile the CHM file, you can leverage
one child form of type ChildFormBase to display the chm file help content.
For #2, we can not display chm file viewer window as the child of
ChildFormBase, but place the chm viewer window at the same level of
ChildFormBase, as the MDI child window of main MDI container.

Hope I have clarifed the point. If you need further help, please feel free
to tell me, thanks

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
G

Guest

Jeffrey,

I am not suprised that we are not able to handle the HTML Help viewer as a
ChildFormBase. I merely hoped that you knew some magic that I didn't know;-)

As for option #1, this may be the option I need to use: contain a browser
"control" within a derived ChildFormBase and display the help topic using the
browser.

Can you point me to an example of decompiling a CHM file and displaying it
in an HTML browser?

Thanks,
Dave
 
J

Jeffrey Tan[MSFT]

Hi babel,

Thanks for your feedback!!

To decompile the CHM file, we should be familiar with CHM file format and
do it with HtmlHelp API, which goes out of our scope of Windows Forms. For
more information, please refer to the article below:
"Htmlhelp Forensics"
http://www.codeproject.com/winhelp/htmlhelp.asp

For #2, does my original workaround of finding the CHM window and
dynamically make it as MDI child window make sense to you? Although with
this option, our help window looks different from our other MDI Child
windows, this reuqests much less coding.

Anyway, you should make your decision on your design. Thanks
===========================================
Thank you for your patience and cooperation. If you have any questions or
concerns, please feel free to post it in the group. I am standing by to be
of assistance.

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
J

Jeffrey Tan[MSFT]

Hi Dave,

Does my reply make sense to you? Is your problem resolved? Please feel free
to tell me, Thanks. Actually, I still think #1 is somewhat complex to
implement. So I still suggest you go with the current .Net HelpProvider
support. I think the end user will not have much concern on the popup CHM
window. Thanks

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top