Powerpoint could not open file - c#

I am developping a C# programm which creates a PowerPoint presentation. However, I am running into a problem with the following instruction:
Presentation pres = pres_set.Open(path,
Microsoft.Office.Core.MsoTriState.msoFalse,
Microsoft.Office.Core.MsoTriState.msoTrue,
Microsoft.Office.Core.MsoTriState.msoTrue);
This instruction works only sometimes. If it doesn't, it throws a exception with the message "PowerPoint could not open file". When I then manually open the template file, close it and execute the function again, most of the time it will execute correctly.
I have used the Microsoft Powerpoint 14.0 and the Microsoft Powerpoint 12.0 libraries, but both have the same problem.
Is there any way to avoid this strange problem?

The answer is much simpler: The Powerpoint-application expects an existing file.
I just had the same exception because I used a relative path, and PowerPoint tried to open the file relative to PowerPoint.exe instead of your Program.exe.
This problem can quickly be fixed by adding something like this before calling the open-method:
// Start Powerpoint
var powerpointApp = new Microsoft.Office.Interop.PowerPoint.Application();
// Get a fileInfo object to generate the full path
FileInfo fileInfo = new FileInfo(#"RelativeDir\YourPresentation.pptx");
// Use the full path
powerpointApp.Presentations.Open(fileInfo.FullName, MsoTriState.msoTrue, WithWindow: MsoTriState.msoFalse);

Have you tried not setting the TriState, like this?
Object oMiss = System.Reflection.Missing.Value;
Presentation pres = pres_set.Open(ref path, ref oMiss, ref oMiss, ref oMiss);

I had the same problem while trying to open an existing PowerPoint presentation until I found out that Visual Basic for Applications (VBA) was not installed on my Office installation options as described here:
http://www.debugging.com/bug/22261
Apparently, this problem only happens when working with PowerPoint as I have no problems manipulating Excel and Word files.
The problemĀ“s gone away as soon as I repaired my Office, including the VBA to the installation.
Hope it helps!

I had a similar problem with PowerPoint. I found my Presentations.Open method was failing unless I had PowerPoint open.
One potential solution is to set PowerPointApplication.Visible = MsoTriState.msoTrue However, this will cause PowerPoint to physically open which is likely to be undesirable.
I resolved my issue by setting the final argument of the Open method to msoFalse, which specifies that the PowerPoint window should not open on the server which is more desirable.
Presentations.Open(inputFileName,
MsoTriState.msoFalse,
MsoTriState.msoTrue,
MsoTriState.msoFalse);
Take a look at this MSDN KB article for more information on the different parameters of the Open method.

ProcessStartInfo ten_ct = new ProcessStartInfo();
ten_ct.FileName = "POWERPNT.EXE";
ten_ct.Arguments = #"D:\project\GiaoAn\GiaoAn\MyPpt.pptx";
Process.Start(ten_ct);

I've seen problems like this with Excel, even when I try to launch it as a user with a command-line file to open. So it may not be anything wrong with your program. When I do this as a user, usually it works the second time.
So my advice would be either
1) For your program to try opening Power Point first without the file, wait (start with 5 seconds), and then have it try to load the file.
or
2) Your program can catch the exception, and simply try opening the file again if it fails (and if you find this works, you should add a maximum number of tries, so the program doesn't loop trying to do this all day). You could optionally also check to see if the file exists (if that's a possibility in your scenario - but it doesn't sound like this is currently the problem you are facing).

Try this:
Presentation pres = pres_set.Open(path,
Microsoft.Office.Core.MsoTriState.msoFalse,
Microsoft.Office.Core.MsoTriState.msoTrue,
Microsoft.Office.Core.MsoTriState.msoFalse);

I solve this problem using:
var app = new PP.Application();
PP.Presentation pres = null;
try
{
Process.Start(inputFile);
var presCol = app.Presentations;
// Waiting for loading
Thread.Sleep(2000);
pres = presCol[inputFile];
// Your code there
// ...............
}
catch (System.Exception ex)
{
Log.Error(ex.Message);
throw;
}
finally
{
if (pres != null)
{
pres.Close();
}
if (app != null)
{
app.Quit();
}
pres = null;
app = null;
}

Related

How-To: Stop adding files to "Recent files" in Quick Access when opening/saving files with Microsoft.Office.Interop

When opening and saving Word/Excel documents using the following code, the files that are opened and saved are being added to the Recent Files of Windows File Explorer (see screenshot). The code itself works fine for my purposes; I've only copied a small portion with surround relevant code. However, I am having difficulties in stopping this undesired behavior and searching the internet only seems to give me results on how to keep the files from showing up in the "Recent Files" list of the office applications themselves, not Windows File Explorer.
I am running this code on directories that contain in the upper thousands, some even break into 5 digit counts, of Office files in the old non-xml format. When .Open() is called, the original file shows up in the list and when .SaveAs()/.SaveAs2() is called the new file shows up in the list. This happens in real-time as I step through the code and it causes the CPU usage spike from the explorer.exe process. The act of opening and re-saving the old format office files happens rather quickly, and I suspect this causes a large CPU usage load due to explorer.exe constant processing the recent files. Other symptoms that I think are related is that the cursor constantly has the spin-wheel under it when the code is running and the whole OS GUI seems to become somewhat unresponsive.
To be clear, I believe that a proactive solution which keeps Windows from adding files to the list will be the best path to take, rather than a retroactive solution which only does cleanup of the list after the fact.
using WORD = Microsoft.Office.Interop.Word;
using EXCEL = Microsoft.Office.Interop.Excel;
//==============================================================================
try
{
if (newFileExt == FileExt.NEW_Word)
{
//open the doc
var document = WordApp.Documents.Open(FileName: fdesc.FileInfo.FullName, ConfirmConversions: false, ReadOnly: true, AddToRecentFiles: false, Visible: false);
//save the doc
document.SaveAs2(FileName: newname, FileFormat: WORD.WdSaveFormat.wdFormatXMLDocument, CompatibilityMode: WORD.WdCompatibilityMode.wdCurrent, AddToRecentFiles: false);
// close the doc
document.Close(WORD.WdSaveOptions.wdDoNotSaveChanges);
}
else if (newFileExt == FileExt.NEW_Excel)
{
// open the workbook
/// https://learn.microsoft.com/en-us/dotnet/api/microsoft.office.interop.excel.workbooks.open?view=excel-pia#Microsoft_Office_Interop_Excel_Workbooks_Open_System_String_System_Object_System_Object_System_Object_System_Object_System_Object_System_Object_System_Object_System_Object_System_Object_System_Object_System_Object_System_Object_System_Object_System_Object_
EXCEL.Workbook workbook = ExcelApp.Workbooks.Open(Filename: fdesc.FileInfo.FullName, ReadOnly: true, IgnoreReadOnlyRecommended: true, AddToMru: false);
// save the doc
/// https://learn.microsoft.com/en-us/dotnet/api/microsoft.office.interop.excel._workbook.saveas?view=excel-pia
if (workbook.HasVBProject)
{
FileInfo newFile = new FileInfo(newname);
newname = newFile.DirectoryName + Path.DirectorySeparatorChar + Path.GetFileNameWithoutExtension(newFile.Name) + FileExt.NEW_Excel_Macro;
UpateNewFileNameConsole(new FileInfo(newname));
workbook.SaveAs(Filename: newname, FileFormat: EXCEL.XlFileFormat.xlOpenXMLWorkbookMacroEnabled, ReadOnlyRecommended: false, AddToMru: false);
}
else
{
workbook.SaveAs(Filename: newname, FileFormat: EXCEL.XlFileFormat.xlOpenXMLWorkbook, ReadOnlyRecommended: false, AddToMru: false);
}
// close the Workbook
workbook.Close(SaveChanges: false);
}
else { throw new Exception("unkown File in conversion"); }
//move the old file
File.Move(fdesc.FileInfo.FullName, moveDir.FullName + Path.DirectorySeparatorChar + fdesc.FileInfo.Name);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
//==============================================================================
public static class FileExt
{
public const string OLD_Word = ".doc";
public const string NEW_Word = ".docx";
public const string OLD_Excel = ".xls";
public const string NEW_Excel = ".xlsx";
public const string NEW_Excel_Macro = ".xlsm";
public const string RichTextFormat = ".rtf";
public const string OldFormatDir = "!old_format";
}
}
Screenshot of Windows File Explorer after running the code for a bit:
This may vary slightly depending on the client Operating System version.
To clear File Explorer history in Windows 10 manually open the Registry Editor app.
Go to the following Registry key:
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer
Delete the subkey named TypedPaths:
Open File Explorer, go to the folder %APPDATA%\Microsoft\Windows\Recent\
and delete all files and folders you see.
Although the history folder is hidden you can still fetch the files you created and delete them programmatically, eg:
string[] recentFiles = System.IO.Directory.GetFiles(Environment.GetFolderPath(Environment.SpecialFolder.History), "*", SearchOption.AllDirectories);
foreach (var file in recentFiles)
{
System.IO.File.Delete(file);
}
To delete the registry key using code:
string keyName = #"Software\Microsoft\Windows\CurrentVersion\Explorer";
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(keyName, true))
{
if (key == null)
{
// Key doesn't exist. Do whatever you want to handle this case
}
else
{
key.DeleteValue("TypedPaths");
}
}
Make a backup of your registry before trying this.
I am facing poor run-time performance due to CPU spikes from explorer.exe when the file entries are added to the Recent Files list.
The act of opening and re-saving the old format office files happens rather quickly, and I suspect this causes a large CPU usage load due to explorer.exe constant processing the recent files. Other symptoms that I think are related is that the cursor constantly has the spin-wheel under it when the code is running and the whole OS GUI seems to become somewhat unresponsive.
Can you first check these common causes - close background processes, in Device Mgr check the IO driver is OK and temporarily disable anti-virus:
Too many background processes
Driver
Anti-virus
Malware
WmiPrvSE.exe
Downloaded Microsoft's Process Explorer to see what's causing the CPU spikes. See here the high CPU consuming threads, it's this Audioses.DLL+0x1141b0. Can you show/tell me what DLL is taking up the highest CPU when you perform the operation? If its Explorer.EXE not Audioses.DLL consuming the CPU goto step 2 for your solution. If it's something else we may need a PerfCounter trace.
Run System File Checker (SFC) scan on the computer to scan for corrupt system files and replace them: http://support.microsoft.com/kb/929833
"I can't believe that a broken icon would cause explorer.exe to go into a loop, eating up all of the CPU it can."
and ..
"I had an exe with an corrupted icon on my desktop, moving it into a folder solved the problem"
If the issue persists create a new user account, login as that user and check if the problem goes away, then you know your profile is corrupt.
Throw better hardware at the problem: Hardware is Cheap, Programmers are Expensive
Ref's:
https://www.techspot.com/community/topics/explorer-exe-high-cpu-usage-probably-not-malware.240788/
https://answers.microsoft.com/en-us/windows/forum/all/explorerexe-high-cpu-usage-tried-everything-i-can/28cf8431-f9db-4169-9237-8e6521ef4c1c
https://linustechtips.com/main/topic/939842-solvedexplorerexe0xa8150-high-cpu-usage/

Replacing PDF fails. Even with File.Delete() success when opened in Edge-Browser

The goal is to replace a PDF-File which is currently saved on disk.
I am deleting the current PDF file from disk, then recreating a new one. This works fine unless the PDF is currently opened in the Microsoft Edge Browser.
// Try delete PDF-File (which is opened in Edge Browser)
var info = new FileInfo(pathToPdf);
if (info.Exists)
{
try
{
info.Delete();
// Same thing with the File.Delete call
//File.Delete(path);
Console.WriteLine("Success.");
}
catch (Exception)
{
Console.WriteLine("Failed.");
return;
}
}
We get a "Success" print out even though the file is opened in Edge. If it were opened in Adobe Reader it would throw an exception (File in use).
Let's create a new file. (For demonstration purposes a text file with a .pdf ending)
try
{
using (var writer = File.CreateText(pathToPdf))
{
writer.Write("Foo");
writer.Flush();
Console.WriteLine("Success.");
}
}
catch (Exception e)
{
Console.WriteLine("Failed.");
return;
}
I expected to be able to create a new file, since the Delete() didn't fail. Yet I get an UnauthorizedAccessException: "Access to the path 'XYZ' is denied."
As a workaround I can recheck if the file exists after deleting it.
var newInfo = new FileInfo(pathToPdf);
if (newInfo.Exists)
// Delete failed
But why would I need to do this? Shouldn't FileInfo.Delete() or File.Delete(path) fail in the first place?
Notes:
Tested on Windows 10 Pro with .Net Framework 4.5.1
The file is still visible in the File-Explorer with its original filesize after it was deleted by code (while opened in Edge).
When closing the Edge Browser after deleting the file by code, the file vanishes from the File-Explorer and I can create a new file programatically.
This problem occurs only with PDFs being opened in Edge. When using a Text-File instead the Text-File gets deleted properly.
Any clarification and help is appreciated.
Best Chris
If the file does not exist, FileInfo.Delete() does nothing.
From msdn
WinNt4Family
Delete does not delete a file that is open for normal I/O or a file that is memory-mapped.
You get an UnauthorizedAccessException when the path is a directory.
If FILE_SHARE_DELETE is set on the handle by Edge, then File.delete() can be called with success by another process even when the handle exists. The file is then marked for deletion and deleted after the handle is closed. Until then, it is still visible in the Explorer, but not accessible anymore.
For a more detailed explanation, see this SO post:
Odd behaviour when deleting Files with Files.delete()

Read Excel file with OleDB c#, when it is used by other process

I am trying to read an excel file every 2 seconds, This file is getting updated by other RTD application.
I am able to read this file by Oledb connection, but problem comes when i am trying to read it every 2 seconds. Out of 10 attempts it is able to read 4-5 times only and at other attempts ,it throws exception.
Connection String
Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\nids\shes.xlsm;Extended Properties="Excel 12.0 Macro;HDR=Yes;IMEX=1"
Code
//opening connection to excel file
using (OleDbConnection connection = new OleDbConnection(constr))//constr = connection string
{
try
{
connection.Open();
isconopen = true;
}
catch
{
dispatcherTimer2.Start();
connection.Close();
isconopen = false;
}
// If connection is ok , then query sheet
if (isconopen == true)
{
strcon = "SELECT * FROM [" + dsheet + "]";
using (OleDbDataAdapter adapter = new OleDbDataAdapter(strcon, connection))
{
try
{
adapter.Fill(result);
isread = true;
adapter.Dispose();
connection.Close();
}
catch
{
isread = false;
dispatcherTimer2.Start();
adapter.Dispose();
connection.Close();
}
}
}
//if able to retrieve data then call some other function
if (isread == true)
{
converToCSV(0);// for further processing
}
Please help me , i am trying this from last 1 month. Please please please please help me out
Sadly OleDB driver by default will open file exclusively then you can't open it when it's in use by someone else, even just for reading.
Two considerations:
Other application may finalize its work with the file within milliseconds so it's good to try again
Driver will always open file locked for writing (so you can't open it twice via OleDB) but it's shared for reading (so you can copy it).
That said I suggest you should first try to open it after a short pause, if it's still in use (and you can't wait more) then you can make a copy and open that.
Let me assume you have your code in a HandlExcelFile() function:
void HandleExcelFile(string path)
{
try
{
// Function will perform actual work
HandleExcelFileCore(path);
}
catch (Exception) // Be more specific
{
Thread.Sleep(100); // Arbitrary
try
{
HandleExcelFileCore(path);
}
catch (Exception)
{
string tempPath = Path.GetTempFileName();
File.Copy(path, tempPath);
try
{
HandleExcelFileCore(tempPath);
}
finally
{
File.Delete(tempPath);
}
}
}
}
Code is little bit ugly so just consider it a starting point to write your own function.
Considerations:
Retry isn't such bad thing and it's a common way to solve this kind of problems. It's, for example, what Windows shell does (and it's even more normal with networks).
If application didn't close the file then you may copy (and read) old data. If you always need most up-to-date data then you have only one choice: wait. If you can assume that unsaved data belongs to the previous time frame (T - 1, as in digital electronic when signal edge is on clock edge) then just do it and live happy.
Untested solution:
I didn't try this so you have to do it by yourself. Actuallly (I was initially wrong) you can open a read-only connection (through extended properties). It's not documented if this apply to connection only or both file handle and connection. Anyway let's try to change your connection string to:
Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\nids\shes.xlsm;Extended Properties="Excel 12.0 Macro;HDR=Yes;IMEX=1;ReadOnly=true"
Just added a ReadOnly=true at the end of Extended Properties.
Other solutions:
The only alternative solution that comes to my mind is to...manually read Excel file (so you can open it just for reading). That said even in this case the other application may have not written new data (so you'll read old one).
Don't use a timer at all. Change your design to use a FileSystemWatcher, you'll read the file only when notified it has been changed.
When applicable...just do not use a shared file as IPC mechanism! Well, you may not be able to change 2nd application so this may not be your case.
Do not use OleDB to read Microsoft Excel files, there are many 3rd part free libraries that don't open file with exclusive lock, for example this one.
Do not read data directly from files, if Microsoft Excel instance is always running you can use COM interop to get notifications. Check this general article about COM add-ins and this to see how you can attach your C# application with Office Interop to an existing Microsoft Excel instance.
Not sure , why do you want to read the excel the way you are doing.
You can try LinqToExcel for excel reading , its a nice little library for reading excel files also if you need to create excel then try to EPPLUS library. These library i personally found really effective when working with Excels
I had similar problem. Below fixes worked for me
1) Don't hold your connection to sheet. Instead open connection read data and close the connection immediately.
2) If you are using managed code in the unmanaged application then consider using object of managed type instead of pointer(using gcnew) and use Stack Semantics to make sure that memory is cleaned up when object goes out of scope.

check if a text file is opened in notepad

how to find whether specific .txt file is opened in notepad?
I have tried solutions mentioned here
Is there a way to check if a file is in use?
But they work fine for Word and pdf file but not working for txt file opened in Notepad.
here is code I have wrote.
public bool IsFileOpen(string strFileName)
{
bool retVal = false;
try
{
if (File.Exists(pstrFileName))
{
using (FileStream stream = File.OpenWrite(pstrFileName))
{
try
{
}
catch (IOException)
{
retVal = true;
}
finally
{
stream.Close();
stream.Dispose();
}
}
}
}
catch (IOException)
{ //file is opened at another location
retVal = true;
}
catch (UnauthorizedAccessException)
{ //Bypass this exception since this is due to the file is being set to read-only
}
return retVal;
}
am i missing somthing here.??
My requirement:
I have application which works similar to VSS. When user checks out specific file and opens ,and try to check in the same, while it has opened. Application is suppose to throw a warning message.For that i have used the above functionality.Its working fine for word and pdf.
To expand on my comment. A file is only locked if a handle is kept open by an application. Word for example will open the file, read in the stream and maintain the handle so that other applications cannot delete that file while the user is working on it.
Notepad, and other applications, just open the file, read in the entire stream and then close the file releasing the lock they have. This means that the file is no longer locked and can be edited by another application or even deleted and Notepad will not care as it has its own copy in memory.
You could try and hack around with getting instances of Notepad and checking if a file is open but this is ultimately not a great idea. If the file is not locked then you should be free to do what you want with it.
This is a hack solution I just came up with, but it should work for you. This makes use of System.Diagnostics.
Process[] processes = Process.GetProcessesByName("notepad");
for (int i = 0; i < processes.Length; i++)
{
Console.WriteLine(processes[i].MainWindowTitle);
if (processes[i].MainWindowTitle.Equals("myFile.txt - Notepad"))
{
Console.WriteLine("The file myFile is Open!");
}
}
Console.ReadLine();
Hopefully that should do the trick. My example looks to see if an instance of notepad is open with the window title "myFile.txt - Notepad". The window name is always "filename.extension - Notepad" so you can handle that however you might need to.
I suppose you could make a call to System.IO.File.GetLastAccessTime(filePath). You could then poll the file every so often and when the access time changes you know the file has been opened, you can then fire an event that the file has been opened. See Jeffs post here:
Detect File Read in C#
You could also do this using the following tactic: It seems that notepad does hold some kind of lock on the hosting folder (try to delete the folder and you'll see you can't).
you could use the following code Using C#, how does one figure out what process locked a file? to check list of processes that lock the folder.
one of the processes will be your notepad.
you could them compare by Title as another answers mentioned.
if you're issuing the open of the file - you could save the PID and comapre it with one of the processes that returned.

NullReferenceException only when opening images from database

I have a table in my database that stores all kind of files.
File names are shown in a ListView and when an user clics on one of them then it's opened by the registered application based on file extension.
This is the code:
if (listViewArchivos.HasItems)
{
dynamic result = listViewArchivos.SelectedItem;
var nombre = Path.GetTempPath() + admin.buscarNombreArchivo((int)result.Id);
var bytes = admin.buscarArchivo((int)result.Id);
try
{
using (var writer = new BinaryWriter(File.Open(nombre, FileMode.Create)))
{
writer.Write(bytes);
}
var p = Process.Start(nombre);
p.WaitForExit();
}
catch (Exception exc)
{
InterfazUtil.error(exc.Message); // This shows a MessageBox
}
finally
{
File.Delete(nombre);
}
}
It's working fine for docx, pdf, txt, etc. But when I try to open an image the file is successfully opened by Window Photo Viewer (Windows 7) but a NullReferenceException is thrown.
If I close WPV first and then the MessageBox the file is deleted from temp folder.
If I close the MessageBox first then the image disappears from WPV and after I close WPV the file is not deleted from temp folder.
Now, if I remove the catch block then the file is successfully opened by WPV and after closing it the file is not deleted from temp folder. Obviously the application crashes because the exception isn't managed.
Looks like the problem is WPV.
Any idea of what is wrong?
TIA
EDIT:
The exception is thrown at
p.WaitForExit();
When you close the MessageBox first the temp file is not deleted because WPV uses it and doesn't allow it.
According to this MSDN: http://msdn.microsoft.com/en-us/library/53ezey2s.aspx
...you will not get back a Process object when the process is already running.
I found this on a forum relating to the nature of WindowsPhotoViewer:
Actually, the Windows Photo Viewer is part of Windows Explorer, and
generally runs in the Explorer.exe process. In fact, what you're
calling the Photo Viewer is really just the "preview" verb for images.
It isn't a standalone application, and opening it without an image or
images doesn't really make any sense.
Thus, you are not getting back a Process object because it is already running by virtue of the fact that explorer.exe is already running.
In the end, I think it means that if your images open in WindowsPhotoViewer, you will not be able to make WaitForExit() work because the owner process will never exit.

Categories