How to host CHM help viewer in an MDI child form?

G

Guest

I am writing a Windows Forms application using VS.NET 2003 and C#. The
application uses the Multi-Document Interface (MDI) style. Our customer
education team requires that the application display context-sensitive help
using the common CHM file format. We are currently using P/Invoke as follows
to display the help file:

[DllImport( "HHCtrl.ocx" )]
public extern static int HtmlHelp( int hwnd, string pszFile, int cmd, int
data );
protected const int HH_HELP_CONTEXT = 0x000F;

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

This launches a new form in a child process. We now need to have the CHM
help content be hosted in an MDI child form so that the child form can be
managed like all of the other child forms. I have searched without success
for information on how to do this.

How can I display the CHM help content in an MDI child form?
Is there a .NET solution for this?

Thanks,
Dave
 
L

Linda Liu [MSFT]

Hi Dave,

This is a quick note to let you know that I am researching on this issue
and will get back to you as soon as possible. I appreciate your patience.


Sincerely,
Linda Liu
Microsoft Online Community Support

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
L

Linda Liu [MSFT]

Hi Dave,

From the version 4.0, IE supports html help link. That's to say, we could
type a html help link like
"ms-help://MS.MSDNQTR.v80.en/dnmsdn2/html/msdnstart.htm" into the address
bar in an instance of IE and browse the help html page.

AxBrowser is a COM component which is an instance of IE. You could use
Microsoft Web Browser to navigate the html help pages of a chm file in your
program.

By default, Microsoft Web Browser does't appear in the Toolbox. To add it
to the ToolBox, right-click on the Toolbox and select Choose Items from the
shortcut menu. In the Choose Toolbox Items window, switch to the COM
Components tab and select the checkbox before the Microsoft Web Browser
item and press the OK button.

Drag&drop Microsoft Web Browser onto the form in your project. You may call
the Navigate method of the brower control passing the html help page link
to display a html page in the browser control.

The following is a sample.

private void Form1_Load(object sender, EventArgs e)
{

this.axWebBrowser1.Navigate(@"mk:mad:MSITStore:C:\Program%20Files\Kingsoft\Powe
rWord%202005\xdict.chm::/htm/huanying.htm");
}

To get the url of a html page in a chm file, open the chm file and
right-click on the displayed html help page and select Properties from the
shortcut menu. In the property window, you will see the URL of the html
page. You could copy it to your code.

Hope this helps.
If you have any concerns, please feel free to let me know.

Sincerely,
Linda Liu
Microsoft Online Community Support
 
G

Guest

Linda,

Using the axWebBrowser1 as described below, I get the following error when I
try to build my solution:

error CS1577: Assembly generation failed -- Referenced assembly
'AxInterop.SHDocVw' does not have a strong name

What do I need to do to resolve this?

Thanks,
Dave
 
L

Linda Liu [MSFT]

Hi Dave,

When we add an ActiveX control to a VS project, VS generates a managed
wrapper assembly around it. If unfortunately VS doesn't sign that assembly,
we will get compiler error along the line of:

error CS1577 Assembly generation failed -- Referenced assembly
'Interop.SHDocVw' does not have a strong name

The solution to the problem is to generate the wrapper assemblies with a
strong name. We can use the SDK tool AxImp to accomplish this. For
instance, if we wanted to wrap the IE engine, we would use:

sn -k shdocvw.snk
AxImp %WINDIR%\System32\shdocvw.dll /keyfile:shdocvw.snk

Which would create a pair of assemblies AxSHDocVw.dll and SHDocVw.dll you
can use in place of the versions that Visual Studio generates on its own.

Hope this helps.

If you have anything unclear, please feel free to let me know.


Sincerely,
Linda Liu
Microsoft Online Community Support
 
G

Guest

Linda,

Okay, I now have it building and running successfully. However, there are
several problems with the results:

1. The links imbedded in a displayed topic do not work. The page is
replaced with the "The page cannot be displayed" error.

2. The appearance of the displayed help is very plain. The embedded font
and color information apparently is not be used correctly.

3. If I hide the MDI child form, then show the child form and execute the
axHelpWebBrowser.Navigate( url ) command, the browser control paints itself
outside of the child form (at screen location 0,0).

Any idea on what is going on?

Thanks,
Dave
 
L

Linda Liu [MSFT]

Hi Dave,
1. The links imbedded in a displayed topic do not work. The page is
replaced with the "The page cannot be displayed" error.

Are the links relative url paths, such as "mk:mad:MSITStore:
\xdict.chm::/htm/copyright.htm"? Only when Web Browser control uses
absolute url paths, it could open the pages.

If the chm file is also made by your company, you may ensure all the links
on all the html pages in the chm file to be absolute paths and recompile
the chm file.
2. The appearance of the displayed help is very plain. The embedded font
and color information apparently is not be used correctly.

You may have a try open the html help page in IE to see if the font and
color are used correctly. If not, perhaps IE or Web Browser couldn't find
the CSS file that the html page uses.
3. If I hide the MDI child form, then show the child form and execute the
axHelpWebBrowser.Navigate( url ) command, the browser control paints itself
outside of the child form (at screen location 0,0).

I performed a test, but I didn't reproduce the problem. I put a Web Browser
control onto the MDI child form and make it public. Then I put two buttons,
i.e button1 and button2 on the MDI parent form. Clicking on button1opens
MDI child form and clicking on button2 make the MDI child form visible or
invisible.

Below is the code of the Click event handlers of button1 and button2.

Form2 frm = null;
private void button1_Click(object sender, EventArgs e)
{
frm = new Form2();
frm.MdiParent = this;
frm.Show();
}

private void button2_Click(object sender, EventArgs e)
{
if (frm.Visible)
frm.Visible = false;
else
{
frm.Visible = true;

frm.axWebBrowser1.Navigate(@"mk:mad:MSITStore:C:\Program%20Files\Kingsoft\Power
Word%202005\xdict.chm::/htm/huanying.htm");
}
}

Running the program, after I click button1 and then button2, the MDI child
form is hidden. When I click button2 again, the MDI child form shows up and
the Web Browser on it opens the html page correctly.

If there're differences between my test and yours, please point them out.

Hope this helps.


Sincerely,
Linda Liu
Microsoft Online Community Support
 
G

Guest

Linda,

I have created a small VS 2003 C# MDI solution that demonstrates the problem
with the AxBrowser showing up at screen location 0,0.

Do you have an email address that I can send you the solution?

Regards,
Dave
 
L

Linda Liu [MSFT]

Hi Dave,

Thank you for your reply.

Have you solved the first two questions mentioned in the previous message?

To get my actual email address, remove the "online" from my displayed email
address.


Sincerely,
Linda Liu
Microsoft Online Community Support
 
G

Guest

Linda,

The status of the other two issues are as follows:
1. We do currently use relative links. So if we get issue 3 resolved then I
can pursue having the links changed to absolute.
2. I am not as worried about this issue as issue 3. I am having a small chm
file created that has color and font changes and will test with it once issue
three is resolved.

I will send the issue 3 example solution to your email addres right after I
complete this reply.

Regards,
Dave
 
L

Linda Liu [MSFT]

Hi Dave,

Thank you for sending your sample project to me. I did see the problem when
the sample program is running on my machine.

I find that if the HelpChildForm is not shown as a MDI child form, this
problem doesn't exist.

I also performed a test in VS 2005 and didn't see the problem. So this is a
limitation of VS.net 2003, which has been fixed in VS 2005.

As for a workaround, I think you may create a new HelpChildForm instance
whenever you show a help child form and close it when you want to hide it
previously.

Hope this helps.

If you have anything unclear, please feel free to let me know.


Sincerely,
Linda Liu
Microsoft Online Community Support
 
G

Guest

Linda,

We do not plan to move to VS 2005 for several months yet, so I do need a VS
2003 solution. Also, the design of our application requires the MDI child
forms to be created once and registered once with the application's
infrastructure. So creating and destroying the help child form is not a
desirable solution.

What is the root cause of the problem that my sample program demonstrated?
What is different in VS 2005 that allows it to work correctly?

Without understanding this issue better I am hesitant to redesign our
application to allow the help child form to be created and destroyed as a
workaround.

Regards,
Dave
 
L

Linda Liu [MSFT]

Hi Dave,

I look this issue up in our inner database and find a record about this
problem.

This is a bug in the Framework 1.0, 1.1. When a MDI child form containing a
WebBrowser ActiveX control in it is hidden, this MDI child form is actually
being destroyed but the ActiveX control is not destroyed. So this causes
problems for some ActiveX controls that isn't expecting its window to be
destroyed during the lifetime of the control intance.

The composition in our inner database also provides an UNSUPPORTED
workaround involving hiding the MDI child form by removing the WS_VISIBLE
style. The basic technique is to implement an UNMANAGED Windows DLL which
will add and remove the window styles for you.

extern "C" _declspec(dllexport) BOOL APIENTRY RemoveWindowStyle(HWND hWnd,
int style)
{
long currStyle;
currStyle = GetWindowLong(hWnd, GWL_STYLE);
SetWindowLong(hWnd, GWL_STYLE, currStyle & (~style));
InvalidateRect(GetParent(hWnd), NULL, TRUE);
UpdateWindow(GetParent(hWnd));
return TRUE;
}

extern "C" _declspec(dllexport) BOOL APIENTRY AddWindowStyle(HWND hWnd, int
style)
{
long currStyle;
currStyle = GetWindowLong(hWnd, GWL_STYLE);
SetWindowLong(hWnd, GWL_STYLE, currStyle | style);
RedrawWindow(hWnd, NULL, NULL, RDW_FRAME | RDW_ERASE | RDW_INVALIDATE);
UpdateWindow(hWnd);
return TRUE;
}

Then from the managed code, instead of calling Form.Show or Form.Hide, you
need to call these functions. In addition you need to refresh the control
after showing it.

namespace TestMDI
{
public class Form1 : System.Windows.Forms.Form
{
...

private void menuItem1_Click(object sender, System.EventArgs e)
{
if (this.MdiChildren.Length > 0)
foreach(Form child in this.MdiChildren)
if (child is Form2)
{
RemoveWindowStyle(child.Handle.ToInt32(), 0x10000000);
//child.Hide();
//MethodInvoker mih = new MethodInvoker(((Form2)child).Hide);
//this.BeginInvoke(mih);


}

}
private void menuItem2_Click(object sender, System.EventArgs e)
{
if (this.MdiChildren.Length > 0)
foreach(Form child in this.MdiChildren)
if (child is Form2)
{
AddWindowStyle(child.Handle.ToInt32(), 0x10000000);
((Form2)child).UpdateWB();
}

}


[DllImport("C:\\Inetpub\\wwwroot\\aProjects\\aCustomers\\November\\TestDLL\\
Debug\
\testDLL.dll")]
public static extern int AddWindowStyle(int hWnd, uint style);

[DllImport("C:\\Inetpub\\wwwroot\\aProjects\\aCustomers\\November\\TestDLL\\
Debug\
\testDLL.dll")]
public static extern int RemoveWindowStyle(int hWnd, uint style);
}

namespace TestMDI
{
...
public class Form2 : System.Windows.Forms.Form, DWebBrowserEvents
{
public void UpdateWB()
{
axWebBrowser1.CtlRefresh();
}

}
}

Since this is not a supported workaround, I recommend you to adopt the
workaround I gave you in my previous reply.

Thank you for your understanding.


Sincerely,
Linda Liu
Microsoft Online Community Support
 

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