Click to See Complete Forum and Search --> : Open Help file......


rocky_upadhaya
January 22nd, 2010, 09:28 PM
Hello! Here I have a project! what I want to do is open .chm help file if i click on the Button.
Let me explain what I have Done. I have created a resource folder where i have placed desired help file. I have have used folowing code


private void button1_Click(object sender, EventArgs e)
{
System.Diagnostics.Process.Start(@"global::Open_HelpFile.Resource1.SkinCrafter_Net");
}


this returns with runtime error of access is denied..is there any way of solving this Problem??
If no Please help me out here...I want to later create Installer so that that help file installs with the project and open when placed in any folder....

PS..Arjay earlier gave me an idea to do the same...i understood your idea but hard time implementing it..and I continued this because i felt so close to succeed because if found the exact file but didn't had correct permission to open it.....

glourung
January 23rd, 2010, 04:24 PM
Hello!

I have looked at your code. Wile execution it gives me a Win32Exception with code 0x80041002. As far as I remember 8 means that it is Warning and 1002 - hex code of error. 0x1002 = 4098 - but I can't find this code in winerror.h. I have found it in the article:
http://msdn.microsoft.com/en-us/library/aa394559(VS.85).aspx

"WBEM_E_NOT_FOUND 2147749890 (0x80041002): Object cannot be found."

As Far as I understand you have include a file .chm into resource section of your assembly - so, if you will look at Resource1.Designer.cs, you will see that
byte[] SkinCrafter_Net

means that this resource is a simple binary presentation of this file, but according to MSDN Process.Start(string) takes one parameter:
fileName
Type: System.String
The name of a document or application file to run in the process.

But instead of file name you have specified a link to the binary resource file. So it can't find it.

As far as I can understand Process.Start will call WinAPI native function ShellExecute, wich can take as an argument a path to the *.chm file and works fine. But conceprion of resources like global::Resource... is C# stuff. Btw I have tried to specify just wrong file name and I get another error "File not found". So Seems like Process.Start have resolve resource name "global::Open_HelpFile.Resource1.SkinCrafter_Net" and provide this resource content to the ShellExecute function, so it tries to use binary presentation of .chm file as a file name - so it can be some random and unpredictable behavior here.

So, to solve the problem you need to specify a file path to *.chm file. like:

System.Diagnostics.Process.Start(Environment.CurrentDirectory + @"\Resources\SkinCrafter.Net.chm");

And this code works for me when I have copy Resources folder to the bin\Debug\.

Good luck!

Arjay
January 23rd, 2010, 05:32 PM
Hello! Here I have a project! what I want to do is open .chm help file if i click on the Button.
Let me explain what I have Done. I have created a resource folder where i have placed desired help file. I have have used folowing code


private void button1_Click(object sender, EventArgs e)
{
System.Diagnostics.Process.Start(@"global::Open_HelpFile.Resource1.SkinCrafter_Net");
}


this returns with runtime error of access is denied..is there any way of solving this Problem??
If no Please help me out here...I want to later create Installer so that that help file installs with the project and open when placed in any folder....

PS..Arjay earlier gave me an idea to do the same...i understood your idea but hard time implementing it..and I continued this because i felt so close to succeed because if found the exact file but didn't had correct permission to open it.....Embedded a resource into the application is a harder way to do it. Btw, if you are given advice on a forum and don't understand it, ask specific questions to what you are having trouble with. Posting another approach because you didn't understand the advice, isn't going to get you to the answer sooner. I avoided posting the exact code and instead included the steps on what to do because I had hoped you would try doing what I suggested and ask questions on specifics of what you didn't understand. Learning this stuff requires hands on coding and thinking, not just copying and pasting code.

That being said, here's the complete code:



using System;
using System.IO;
using System.Windows.Forms;
using System.Diagnostics;
namespace Open_HelpFile
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
Process.Start( Path.Combine( GetAppFolder( ), @"Resources\SkinCrafter.Net.chm" ) );
}

/// <summary>
/// Gets the folder location of the application
/// </summary>
private string GetAppFolder( )
{
string appFolder = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
return appFolder.Substring( 0, appFolder.LastIndexOf( @"\" ) );
}
}
}



Take a look at the GetAppFolder( ) method. This method uses the current AppDomain to locate the config file. Since the config file is always located in the same folder as the app exe, we can search for the last backslash and strip off all the characters after that. This will give us the app folder. From there we append the chm file and its relative path. I explained this approach before but I suggested using GetEntryAssembly and Location.

You may wonder why I didn't use the Environment.CurrentDirectory property. The reason is that the current directory property can change at any time while the app is running (and even without the programmer knowing). This can be a source of hard to find bugs. A reliable way to do this sort of thing is to retrieve the location of the app exe and use it to form the complete path to the file you need to access.

The one last remaining detail is to get the chm file copied to the output directory. You do this by right clicking on the chm file, choosing properties..., and set the "Copy to Output Directory" property to "Copy Always".

rocky_upadhaya
January 24th, 2010, 01:54 AM
Thanks for the Help both Of You . I Understand Your point too. But being realistic all the solutions are not there on the books and e-books and its is equally hard too to find the way of implementing in the internet unless you have the right key word, Trying new syntaxes that were not in the Book wont help either. I have spend my last semester understanding C# and worked on Console application for about 4-5 months but it was hard for me to start on the GUI part. But now I have worked on GUI and is still learning I sometimes catch the Hints but sometime it is hard to implement some ideas even if you have understood the basic flow of your idea . I do strongly agree on your point too.......
("You Solve His Problem once, He will come to you and ask for your help again, But if you teach him how to solve this Problem He will solve On his own from next Time") Thank You.....

rocky_upadhaya
January 24th, 2010, 03:51 AM
Does this code given by arjay requires GetEntryAssembly method too? because it returned with "Error 1 The name 'Path' does not exist in the current context" Error

Arjay
January 24th, 2010, 01:16 PM
Does this code given by arjay requires GetEntryAssembly method too? because it returned with "Error 1 The name 'Path' does not exist in the current context" ErrorIf you see this error, it means that it can't resolve which namespace the entity 'Path' is in. If you right click on the word 'Path', and choose 'Resolve...', you'll see two menu entries. Choose the 1st one, "using System.IO;' and this using directive will be inserted into your code.

Btw, msdn will specify what namespace these classes are in and what assembly. If you find a .net class where the "Resolve..." menu item doesn't appear, then most likely you don't have the correct assembly referenced. If it's a .net class, you can find which assembly needs to be added by looking up the class in msdn and then add a reference to the assembly by right clicking on the "References" item in the Solution Explorer and choose, "Add Reference...". From there, you can right click on the class, choose "Resolve", and add the using statement.

In msdn, the Path (http://msdn.microsoft.com/en-us/library/system.io.path.aspx) class is listed as:

.NET Framework Class Library
Path Class

Performs operations on String (http://msdn.microsoft.com/en-us/library/system.string.aspx) instances that contain file or directory path information. These operations are performed in a cross-platform manner.



Namespace: System.IO (http://msdn.microsoft.com/en-us/library/system.io.aspx)
Assembly: mscorlib (in mscorlib.dll)

The namespace above tells you what using statement you need. The assembly tells you what assembly you need to reference. In this case, the mscorlib.dll is always referenced in a .net project, so you don't need to a an assembly reference (but you do need to add "using System.IO;" to your code).


Lastly, what exactly does Path.Combine do? It just simply takes two strings and joins them putting a '\' between them.

So if we have the following two path components:


string folder = @"C:\myFolder\myAppFolder";
string appName = "myApp.exe";

instead of joining them, like this
string fullPath = folder + @"\" + appName;
we can use the Path.Combine method
string fullPath = Path.Combine( folder, appName );

The benefit of using Path.Combine is that it will 'fix' up the strings as necessary with regard to any backslash characters.

So it will remove the extra backslash chars when combining the following:

string folder = @"C:\myFolder\myAppFolder\";
string appName = "\myApp.exe";