I have an application which currently provides the user with the ability to view a PDF file inside the application by using File->Open, browsing to the location of the PDF file using a Microsoft.Win32.OpenFileDialog
, and then displaying that PDF file in a System.Windows.Controls.WebBrowser
in the GUI.
I am creating the OpenFileDialog
and setting the file extensions it can open using:
/*Create Open File dialog */
Microsoft.Win32.OpenFileDialog OFDlg = new Microsoft.Win32.OpenFileDialog();
/*Set filter for file extension and default file extension */
OFDlg.DefaultExt = ".pdf";
OFDlg.Filter = "PDF Documents (.pdf)|*.pdf";
I now want to extend this, so that the user can open a ZIP folder containing a single PDF document, and display that PDF document in the same way that I am above.
I tried changing the filter to allow .zip files, i.e.
OFDlg.DefaultExt = ".pdf|.zip";
OFDlg.Filter = "PDF Documents (.pdf)|*.pdf|ZIP|*.zip";
but when I browse to the location of the .zip file in the OpenFileDialog
, the .zip folder is not displayed there- only normal folders and PDF documents (other documents in that directory, such as .doc & .xls are not displayed in the OpenFileDialog
).
My reason for wanting to be able to open the contents of a .zip file directly from the .zip, rather than navigating to that file itself, is so that I can add public/private key encryption to the .zip, so that its contents can only be read securely.
I know that there could in theory be problems if the .zip contains more than one file, but I intend to send each encrypted file in its own zip folder, so it can be assumed that any zip file that the user is trying to open contains a single .pdf, and nothing else.
So my questions are:
OpenFileDialog
?System.Window.Controls.WebBrowser
that I am currently using to display PDFs in my GUI?Edit 1
I tried changing my OpenFile()
method to the following code:
/*Set filter for file extension and default file extension */
OFDlg.DefaultExt = ".pdf";
OFDlg.DefaultExt = ".zip";
OFDlg.Filter = "PDF Documents (.pdf)|*.pdf";
OFDlg.Filter = "ZIP Folders (.ZIP)|*.zip";
but when I now run my application, and browse to the same location, although the .zip folder is now shown in the OpenFileDialog
, the .pdf files no longer are... and if I double click the .zip folder, my application breaks, and I get a runtime error on the line
PdfPanel.OpenFile(docFP);
which says:
An unhandled exception of type 'System.AccessViolationException' occurred in MoonPdfLib.dll
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
I guess that's to do with the MoonPDF library that I'm using to read the PDFs being unable to handle the .zip extension?
How would I resolve this to be able to open the PDF inside the ZIP?
Edit 2
Ok, so I've resolved the issue about only being able to see either the PDF files or the .ZIP folders (not both at the same time), by moving the functionality into two separate methods- one to display the PDF direct from the PDF's filepath, and another to display the PDF from the path of the .ZIP folder holding it.
The method for displaying the PDFs directly currently works (it is essentially the code in the first bit of code I've quoted). However the method for displaying the PDFs from the ZIP currently doesn't work...
I understand the reason for this- it's because I am passing a .zip
folder to the OpenFile
method... The code for this method currently looks like this:
private void openZipMenuItem_click(object sender, RoutedEventArgs e)
{
Microsoft.Win32.OpenFileDialog OZipDlg = new Microsoft.Win32.OpenFileDialog();
OZipDlg.DefaultExt = ".zip";
OZipDlg.Filter = "ZIP Folder (.zip)|*.zip";
Nullable<bool> result = OZipDlg.ShowDialog();
if (result == true)
{
/*Open document */
string filename = OZipDlg.FileName;
//fnTextBox.Text = filename;
zipFP = OZipDlg.FileName;
/*browser.Navigate(docFP); ERF (27/05/2016 @ 0935) Comment this line- I want to use PdfPanel to open docFP, not browser */
Console.WriteLine("Panel height: " + PdfPanel.ActualHeight);
PdfPanel.OpenFile(zipFP);
}
}
When I try to call this function to open a .zip, I get a runtime exception which says:
AccessViolationException was unhandled
An unhandled exception of type 'System.AccessViolationException' occurred in MoonPdfLib.dll
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
I understand that I can't display a Zip folder in the PdfPanel
(which is a MoonPdfPanel
that I am using from the MoonPdfLibrary
), so I know that I will get an exception here.
How can I pass the contents of zipFP
to the call to PdfPanel.OpenFile()
, rather than passing zipFP
itself to it?
Edit 3
Ok, so my code is currently extracting the PDF file successfully from the ZIP folder when I open it- I can see that it is copied to the directory I have specified. I am now trying to get the PDF to be displayed automatically in the PDF Panel on my application- I've done this by adding the following code:
try{
string extractPath = @"C:\Documents";
using(ZipArchivev zip = ZipFile.Open(zipFP, ZipArchiveMode.Read))
foreach(ZipArchiveEntry entry in zip.Entries){
try{
ZipFile.ExtractToDirectory(zipFP, extractPath);
Console.WriteLine("zipFP: " + zipFP);
}catch(System.IOException){
Console.WriteLine("File already exists...");
}
}
string ExtractedPDF = string.Concat(extractPath, zipFP);
PdfPanel.OpenFile(ExtractedPDF);
}catch(AccessViolationException ex){
Console.WriteLine("Can't display a zip in the PDF panel..." + ex.InnerException);
}
But when my code tries to execute the line PdfPanel.OpenFile(ExtracedPDF);
, I get an exception that says:
FileNotFoundException was unhandled | An unhandled exception of type 'System.IO.FileNotFoundException' occurred in MoonPdfLib.dll'
I understand that this is happening because the variable I am trying to display in the PDFPanel, ExtractedPDF
actually holds the path of the folder containing the PDF, and not the PDF itself- How do I give it the name of the PDF file, when I don't actually know what the PDF file will be called?
Here is something works similar to your requests, the logic behind the code is:
OpenFileDialog
OpenFileDialog
to the zip file(treat it like a folder)Example code (working code....):
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "PDF files (.pdf)|*.pdf;*.zip";
ofd.ShowDialog();
//reopen OpenFileDialog if it is zip file. this part can be improved.
if (ofd.FileName.EndsWith(".zip"))
{
ofd.InitialDirectory = ofd.FileName;
ofd.ShowDialog();
}
//if it's a PDF, note that you don't really need this check,
//as the only file can reache here will be a PDF,
//and it can be the temporary file that inside a zip.
if(ofd.FileName.EndsWith(".pdf"))
{
//show it in your PdfPanel
}
Edit, based on your new comments and added code. you need to change your code to the following as your current code is mistaken directory with the file:
try{
string extractPath = @"C:\Documents";
string ExtractedPDF ="";
using(ZipArchivev zip = ZipFile.Open(zipFP, ZipArchiveMode.Read))
foreach(ZipArchiveEntry entry in zip.Entries){
try{
ExtractedPDF= Path.Combine(extractPath, entry.FullName);
entry.ExtractToFile(ExtractedPDF,true);
}catch(System.IOException){
Console.WriteLine("error during extraction...");
}
}
if( System.IO.File.Exists(ExtractedPDF))
{
PdfPanel.OpenFile(ExtractedPDF);
}
}catch(AccessViolationException ex){
Console.WriteLine("Can't display a zip in the PDF panel..." + ex.InnerException);
}