Detect when PowerPoint has finished saving a file - c#

I am having problems saving a PowerPoint file in an add-in I am writing.
Basically, I need to save the currently open presentation as a wmv and then FTP it to an external server... sounds easy eh?
I have worked out how to save the currently open presentation as a wmv.
I have also got code to check if a file is open so I can tell when the "save" process is complete.
But the code just goes into an infinite loop. The wmv starts for get written but never goes beyond 0kb.
If I remove the line
checkfile(exportPath, exportName);
it works just fine... otherwise it just stays in a loop.
This is the code I have so far...
using System;
using System.Windows.Forms;
using Office = Microsoft.Office.Core;
using PowerPoint = Microsoft.Office.Interop.PowerPoint;
using System.IO;
namespace PowerPointAddIn2
{
public partial class LoginPanel : UserControl
{
public LoginPanel()
{
InitializeComponent();
}
private void LoginPanel_Load(object sender, EventArgs e)
{
}
private void btnLogin_Click(object sender, EventArgs e)
{
string exportName = "video_of_presentation";
string exportPath = #"C:\{0}.wmv";
// Export the currently open presentation
PowerPoint.Application ppApplication = null;
ppApplication = new PowerPoint.Application();
ppApplication.Activate();
ppApplication.ActivePresentation.SaveAs(String.Format(exportPath, exportName), PowerPoint.PpSaveAsFileType.ppSaveAsWMV, Office.MsoTriState.msoTrue);
checkfile(exportPath, exportName);
MessageBox.Show("Finished");
}
protected void checkfile(string exportPath, string exportName)
{
FileInfo f = new FileInfo(String.Format(exportPath, exportName));
while (IsFileLocked(f) == true) { System.Threading.Thread.Sleep(5000); }
MessageBox.Show("Finished");
}
protected virtual bool IsFileLocked(FileInfo file)
{
FileStream stream = null;
try
{
stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
}
catch (IOException)
{
//the file is unavailable because it is:
//still being written to
//or being processed by another thread
//or does not exist (has already been processed)
return true;
}
finally
{
if (stream != null)
stream.Close();
}
//file is not locked
return false;
}
}
}
Based on a previous thread I posted I also tried Thread.Join() to see if I could simply wait for the save thread to finish before I continued but it didn't pause at all while the file was being saved so I ended up with the same result.
Any help/pointers would be very much appreciated.
Thanks

The PowerPoint Application object has a ppMediaTaskStatus property that should return the info you need for this. You can get the various values using the Object Browser in the PPT VBA IDE .

Related

How to close an access made by unknown proccess to a file through WPF, C#?

I'm trying to access a file with my WPF project and I get an exception saying it couldn't access the file because another process is using it.
I don't see any reason because the only process which used it was syncronized and it should close the file after it used it. I tried the "client.Dispose();" below, but it didn't help.
Any advice may be a help! Thanks.
I'm trying to access "currentQr" file in local url. Here's my code:
private void BtnScanQR(object sender, RoutedEventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
if (openFileDialog.ShowDialog() == true)
{
currentQr= System.IO.Path.GetFullPath(openFileDialog.FileName).Replace(#"\\", #"\");
if (!bL.IsQRExist(currentQr))
{
/////// some code
}
}
}
It calls "bL.IsQRExist(currentQr)" which calls "dal" :
public bool IsQRExist(string currentQr)
{
return Dal.IsQRExist(currentQr);
}
Here's my Dal.IsQRExist function, Which calls directly to "DecodeQR" function:
public bool IsQRExist(string currentQr)
{
Product p = Tools.ConvertQRToProduct(currentQr);
if (GetProductID(p) == -1)
return false;
return true; }
And in "Tools.DecodeQR" there's the Actual access to the file:
public static string DecodeQR(string downloadUrl) //'unzip' qrCode from url and interperts its meaning
{
string imageUrl = downloadUrl;
// Install-Package ZXing.Net -Version 0.16.5
var client = new WebClient();
var stream = client.OpenRead(imageUrl);
if (stream == null) return "";
var bitmap = new Bitmap(stream);
IBarcodeReader reader = new BarcodeReader();
var result = reader.Decode(bitmap);
client.Dispose();
return result.Text;
}
After this only access to the file, I'm trying to access the file again in another proccess but it says that another proccess (must be this one i descibed here, cause when i cancled this it didn't throw the exception).
So how can I make sure the file isn't being accessed anymore after this code above?
And I also thinks maybe is there a way to close all accesses to a file, whether they were made in this code or any other code.
Thanks
Since Bitmap is an IDisposable, you have to make sure that you properly dispose of it after usage, which is usually done by creating it in a using statement.
In addition, when you load a Bitmap from a local file, you would not have to deal with Streams at all.
This should be sufficient:
public static string DecodeQR(string imageFilePath)
{
using (var bitmap = new Bitmap(imageFilePath))
{
return new BarcodeReader().Decode(bitmap).Text;
}
}
I think the file handle, that isn't closed, is held by the variable stream which receives the file opened by WebClient.OpenRead. You will need to dispose the stream resource as well.
With a using block it's disposed automatically when the block is exited - where using guarantees to invoke Dispose even in case of exceptions thrown inside the using block. Which is quite good, when you want to open that same file later again.
Also I think you don't need a WebClient if you deal with a local file. Just opening that file as a FileStream seems more straight forward.
using System.IO;
...
public static string DecodeQR(string localImageFile)
{
using (var stream = new FileStream(localImageFile,
FileMode.Open, FileMode.Read))
{
if (stream == null) return "";
var bitmap = new Bitmap(stream);
// Install-Package ZXing.Net -Version 0.16.5
var reader = new BarcodeReader();
var result = reader.Decode(bitmap);
return result.Text;
}
}

FileSystemWatcher: System.IO.IOException ("File used by another process")

Currently i'm working on an application, that should watch a specific directory for changes (say a new file was created) and then in turn upload the file to Sharepoint. Thatfore i'm using the FileSystemWatcher class which throws an event with the path to the created file, which in turn i use in another method to upload the file. The problem is: While in debug mode in Visual Studio i realized that the first file i create in the watched directory gets uploaded perfectly, even if i drag multiple files into the directory at once all are uploaded, BUT when i do it one file after another i get an exception that the second file is already in use. So i drag File1.txt into the directory, it works, but then, when i drag file2.txt into the directory right after i get a System.IO.IOException while trying to create a filestream to upload to Sharepoint telling me that file2.txt is in use by another process.
The code for the FileSystemWatcher:
public void StartWatcher()
{
FileSystemWatcher fsw = new FileSystemWatcher(this.path);
fsw.IncludeSubdirectories = true;
fsw.EnableRaisingEvents = true;
fsw.Created += new FileSystemEventHandler(CreateFile);
try
{
while (true)
{
fsw.WaitForChanged(WatcherChangeTypes.All);
}
}
catch
{ }
fsw.EnableRaisingEvents = false;
}
The CreateFile() method called by
fsw.Created += new FileSystemEventHandler(CreateFile);
looks like this:
private void CreateFile(object sender, FileSystemEventArgs e)
{
path = String.Format(e.FullPath);
filename = Path.GetFileName(path);
Stream fs = File.OpenRead(#path);
SPAPI spobj = new SPAPI();
spobj.SPUploader(fs, filename);
fs.Close();
}
The exception is thrown at
Stream fs = File.OpenRead(#path);
BUT only when a second file is dragged into the directory after the first one. The strange thing is that not the first file is in use, but the second one that i want to open as a stream. So it's not the stream that is still open and causing the exception. It seems that the second file is in use by the FileSystemWatcher. But why does the first file work just fine but the exception is just thrown when a second file is dragged into the directory?
You can modify and use like this. I hope this helps you
private void CreateFile(object sender, FileSystemEventArgs e)
{
int until = 5;
int i = 0;
bool success = false;
while (!success && i < until)
{
try
{
path = String.Format(e.FullPath);
filename = Path.GetFileName(path);
using (Stream fs = File.OpenRead(#path);)
{
SPAPI spobj = new SPAPI();
spobj.SPUploader(fs, filename);
}
success = true;
}
catch
{
i++;
Thread.Sleep(TimeSpan.FromSeconds(1));
}
}
}

System.IO.IOException: 'The process cannot access the file '#.txt' because it is being used by another process.'

I am new to programming and I have a question. If I have two functions, one creates a text file and writes into it, while the other opens the same text file and reads from it.
The error I get is:
System.IO.IOException: 'The process cannot access the file '#.txt'
because it is being used by another process.'
I have tried setting seperate timers to each of the functions but it still does not work. I think the best way would be that the function two does not start until function one ends.
Can you help me achieve this?
Thank you very much!
Mike
Source code:
public Form1() {
InitializeComponent();
System.Timers.Timer timerButtona1 = new System.Timers.Timer();
timerButtona1.Elapsed += new ElapsedEventHandler(tickTimera1);
timerButtona1.Interval = 3003;
timerButtona1.Enabled = true;
}
private async void tickTimera1(object source, ElapsedEventArgs e) {
function1();
function2();
}
void function1() {
List<string> linki = new List<string>();
linki.Add("https://link1.net/");
linki.Add("https://link2.net/");
linki.Add("https://link3.net/");
List<string> fileNames = new List<string>();
fileNames.Add("name1");
fileNames.Add("name2");
fileNames.Add("name3");
for (int x = 0; x < fileNames.Count; x++) {
GET(linki[x], fileNames[x]);
//System.Threading.Thread.Sleep(6000);
}
}
async void GET(string link, string fileName) {
var ODGOVOR = await PRENOS_PODATKOV.GetStringAsync(link);
File.WriteAllText(#"C:\Users\...\" + fileName + ".txt", ODGOVOR);
}
void function2() {
string originalText = File.ReadAllText(#"C:\Users\...\fileName.txt", Encoding.Default);
dynamic modifiedText = JsonConvert.DeserializeObject(originalText);
//then i then i read from the same text files and use some data from it..
}
You will have to close the file after editing it.
var myFile = File.Create(myPath);
//myPath = "C:\file.txt"
myFile.Close();
//closes the text file for eg. file.txt
//You can write your reading functions now..
After closing it you can again use it(for reading)
The issue is sometimes file locks don't get released immediately after they are closed.
You can try run a loop to read the file. Inside the loop put a try catch statement and if the file reads successfully break from the loop. Otherwise, wait a few milliseconds and try to read the file again:
string originalText = null;
while (true)
{
try
{
originalText = File.ReadAllText(#"C:\Users\...\fileName.txt", Encoding.Default);
break;
}
catch
{
System.Threading.Thread.Sleep(100);
}
}
after writing your text file, you should close it first before proceeding to your second function:
var myFile = File.Create(myPath);
//some other operations here like writing into the text file
myFile.Close(); //close text file
//call your 2nd function here
Just to elaborate:
public void Start() {
string filename = "myFile.txt";
CreateFile(filename); //call your create textfile method
ReadFile(filename); //call read file method
}
public void CreateFile(string filename) {
var myFile = File.Create(myPath); //create file
//some other operations here like writing into the text file
myFile.Close(); //close text file
}
public void ReadFile(string filename) {
string text;
var fileStream = new FileStream(filename, FileMode.Open,
FileAccess.Read); //open text file
//vvv read text file (or however you implement it like here vvv
using (var streamReader = new StreamReader(fileStream, Encoding.UTF8))
{
text = streamReader.ReadToEnd();
}
//finally, close text file
fileStream.Close();
}
The point is, you have to close the FileStream after you are done with any operations with your file. You can do this via myFileStream.Close().
Moreover, File.Create(filename) returns a FileStream object which you can then Close().
Actually this is not a problem of closing/disposing the stream, File.WriteAllText and File.ReadAllText does that internally.
The issue is because a wrong use of the async/await pattern.
GET is async but never awaited, thus causing function1 to finish and move on to function2 before all content was actually written to the file.
The way it is written GET is not awaitable because it is async void which should never be used unless you're dealing with event or really know what you're doing.
So, either remove the use of async/await completely or be async all the way:
Change GET to be awaitable:
async Task GET(string link, string fileName)
await it in the now async function1:
async Task function1()
{
...
for (int x = 0; x < fileNames.Count; x++)
{
await GET(linki[x], fileNames[x]);
//System.Threading.Thread.Sleep(6000);
}
...
await function1 in the Elapsed event:
private async void tickTimera1(object source, ElapsedEventArgs e)
{
await function1();
function2();
}
Create a file and then close it. After can save data into that file.
I did as below.
if (!File.Exists(filePath))
{
File.Create(filePath).Close();
}
File.WriteAllText(filePath, saveDataString)
In one of the unit tests, I had to create a temp file and then remove it after, and I was getting the above error.
None of the answers worked.
Solution that worked was:
var path = $"temp.{extension}";
using (File.Create(path))
{
}
File.Delete(path);

File access error with FileSystemWatcher

I am using File Watcher (.NET) and always getting an below error-
file is being used by another process.
The above error only comes in Network sharing, i.e. Watch Directory is shared and if someone puts the file into that directory then only this error occurs. It works fine when I put the file from my m/c to watch directory(locally).
This is how my below code looks, the error comes in first line itself. I have tried all the solutions given on net but nothing seems to working. The only solution worked when I put Thread.Sleep(500), but after that it is unable to pick the next file. Any suggestion would be a great help.
try
{
using (Stream stream = File.Open(xmlPath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
XmlTextReader xmlTextReader = new XmlTextReader(stream);
document = XDocument.Load(xmlTextReader);
........ // my code
xmlTextReader.Close();
stream.Close();
}
}
catch (Exception exception)
{
EventLog.WriteEntry("Application", exception.ToString(), EventLogEntryType.Error);
}
I think you will find that the the file is not acessable hence why the wait works..
Take a look at this code and see if this helps...
// Consider having a List<String> named _changedFiles
private void OnChanged(object source, FileSystemEventArgs e)
{
lock (_changedFiles)
{
if (_changedFiles.Contains(e.FullPath))
{
return;
}
}
// do your stuff
System.Timers.Timer timer = new Timer(1000) { AutoReset = false };
timer.Elapsed += (timerElapsedSender, timerElapsedArgs) =>
{
lock (_changedFiles)
{
_changedFiles.Remove(e.FullPath);
}
};
timer.Start();
}
from:
FileSystemWatcher Changed event is raised twice

Write data from Textbox into text file in ASP.net with C#

I have a textbox where a user can input their email, what I want to do is make it so that when they click a submit button. That email will be saved into a text file ( on my server ) called emails.txt
I managed to get this working using System.IO and then using the File.WriteAll method. However I want to make it so that it will add the email to the list ( on a new line ) rather then just overwriting whats already in there.
I've seen people mention using Append, but I can't quite grasp how to get it working.
This is my current code (that overwrites instead of appending).
public partial class _Default : Page
{
private string path = null;
protected void Page_Load(object sender, EventArgs e)
{
path = Server.MapPath("~/emails.txt");
}
protected void emailButton_Click(object sender, EventArgs e)
{
File.WriteAllText(path, emailTextBox.Text.Trim());
confirmEmailLabel.Text = "Thank you for subscribing";
}
}
You can use StreamWriter to get working with text file. The WriteLine method in true mode append your email in new line each time....
using (StreamWriter writer = new StreamWriter("email.txt", true)) //// true to append data to the file
{
writer.WriteLine("your_data");
}
From the official MSDN documentation:
using (StreamWriter w = File.AppendText("log.txt"))
{
MyWriteFunction("Test1", w);
MyWriteFunction("Test2", w);
}
Use StreamWriter in Append mode. Write your data with WriteLine(data).
using (StreamWriter writer = new StreamWriter("emails.txt", true))
{
writer.WriteLine(email);
}
Seems like a very easy question with a very easy answer: Open existing file, append a single line
If you post the current code, we can modify that to append instead of overwrite.

Categories