I have a problem with Excel Interop objects. I can't seem to pinpoint the problem either. (My code is at the bottom). Basically, sometimes it reads the cells correctly, but sometimes it doesn't. After two passes, it stops reading entirely. I think I have a math issue, but I can't find it. I would get someone else to read my code, but I don't have anyone nearby. I'll be on for awhile to answer questions. Thanks for the help, its a bit frustrating on why it doesn't work.
if(requiredEnd == true && requiredPass == true && requiredPath == true && requiredStart == true && requiredUser == true && requiredSheet == true)
{
errorCheck = false;
try
{
//starting Excel
Excel.Application excelApp = new Excel.Application();
excelApp.Visible = false;
Excel.Workbook workBook = excelApp.Workbooks.Open(filePath);
Excel.Sheets sheet = workBook.Worksheets;
Excel.Worksheet workSheet = (Excel.Worksheet)sheet.get_Item(sheetName);
//Generating User and Password
int startCoordI = Int32.Parse(startCoord);
int endCoordI = Int32.Parse(endCoord);
int value = startCoordI;
string combinedUser = userCoord + startCoord;
string combinedPassword = passwordCoord + startCoord;
string Username = Convert.ToString(workSheet.Cells.Named(combinedUser).Value);
MessageBox.Show(Username);
string Password = Convert.ToString(workSheet.Cells.Named(combinedPassword).Value);
MessageBox.Show(Password);
try
{
System.Diagnostics.ProcessStartInfo proccessStartInfo = new System.Diagnostics.ProcessStartInfo("net", "user " + Username + " " + Password + " /add /passwordchg:no");
System.Diagnostics.Process proc = new System.Diagnostics.Process { StartInfo = proccessStartInfo };
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.UseShellExecute = false;
proccessStartInfo.CreateNoWindow = true;
for (I = startCoordI; I <= endCoordI; I++)
{
proc.Start();
//new user
value++;
combinedUser = userCoord + value;
combinedPassword = passwordCoord + value;
Username = Convert.ToString(workSheet.Cells.Named(combinedUser).Value);
MessageBox.Show(Username);
Password = Convert.ToString(workSheet.Cells.Named(combinedPassword).Value);
MessageBox.Show(Password);
}
//Clean up Excel
Marshal.ReleaseComObject(excelApp);
Marshal.ReleaseComObject(workBook);
Marshal.ReleaseComObject(sheet);
Marshal.ReleaseComObject(workSheet);
//Executing.Show
proc.WaitForExit();
//Executing.Close
if(proc.HasExited == true)
{
if(errorCheck == false)
{
MessageBox.Show("The Process Has Been Completed!");
}
else
{
MessageBox.Show("Operation Ended With Errors. Exiting Excel Reader.");
}
proc.Close();
this.Close();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
else
{
if(requiredEnd == false || requiredPass == false || requiredStart == false || requiredUser == false || requiredSheet == false)
{
MessageBox.Show("You Have Missing Required Fields!");
}
else
{
MessageBox.Show("That Is Not A Valid File!");
}
There is a lot of "un-needed" parts there, but I thought giving the whole thing would be more helpful. (Most of the textboxes are just debug things, BTW)
EDIT: I forgot .Named wasn't part of the normal code. Its a function someone made for me:
public static class ExcelExtensions
{
public static Range Named(this Range Cells, string CellName)
{
char cellLetter = CellName.Substring(0, 1).ToUpper()[0];
int xCoordinate = (cellLetter - 'A') + 1;
int yCoordinate = int.Parse(CellName.Substring(1));
return Cells[xCoordinate, yCoordinate];
}
}
It basically allows you to use PowerShell themed coordinates, i.e (A1, B3 etc.)
Gusman has answered my question in the comments, so I will explain here. My problem was that I had the x and y coordinates swapped, and that I didn't have the process inside the loop. Thank you Gusman!
Related
I hope I can explain my scenario the best I can.
I have code that when the "Load" button is clicked, all file names (if any) located in a predefined network directory path, are loaded to a text-area.
Currently there can be .txt, .xml files.
Contents could look like:
first_file_found.xml
second_file_found.xml
third_file_found.txt
Also, in the code there is another function "isCoValid" that performs an additional validation of the contents of these files, based on return value (true/false) of this function, the "Process" button is enabled:
if (IsFlatFile(fileName) || IsXMLFile(fileName))
{
if (isCoValid(fileName))
{
btnProcess.Enabled = true;
}
else
{
btnProcess.Enabled = false;
break;
}
}
Now I have to add a .csv file type, but this file does not required to perform the isCoValid function.
The text-area contents now look like:
first_file_found.xml
second_file_found.xml
third_file_found.txt
fourht_file_found.csv
My request for help is to ask how can the check to find out if there is a CSV file can be done, and also controlling the enabling of the "Process" button, but still respect the existing check for .txt, and .xml and the validation of contents?
I might have xml and text files, that aren't valid, but I still need to be able to process the .csv. file.
I did change it like this:
if (IsFlatFile(fileName) || IsXMLFile(fileName))
{
if (isCoValid(fileName))
{
btnProcess.Enabled = true;
}
else
{
btnProcess.Enabled = false;
break;
}
}
if (IsCSVFile(fileName))
{
btnProcess.Enabled = true;
}
But I am sure this is not correct and I would like to ask for some help if possible.
I hope I explained my problem with some clarity and straightforwardness, if not, please let me know and I can try to provide more information.
Thank you,
Erasmo
Additional Code Requested
public bool IsFlatFile(string FileName)
bool ReturnValue = false;
if (FileName.ToUpper().Right(4) == ".TXT")
{
if ((FileName.Substring(0, 2).ToUpper() == "MN") ||
(FileName.Substring(0, 2).ToUpper() == "CH"))
{
ReturnValue = true;
}
}
return ReturnValue;
}
public bool IsXMLFile(string FileName)
bool ReturnValue = false;
if (FileName.ToUpper().Right(4) == ".XML")
{
if ((FileName.Substring(0, 2).ToUpper() == "TR") ||
(FileName.Substring(0, 2).ToUpper() == "SK"))
{
ReturnValue = true;
}
}
return ReturnValue;
}
protected bool isCoValid(string fName)
{
bool retCode = false;
Parameters parms;
var reader = new AppSettingsReader();
Application app = new Application();
Package package = null;
try
{
package = app.LoadPackage(packagePath + "ValidateContents.dtsx", null);
parms = package.Parameters;
parms["ID"].Value = "";
parms["ImportFileName"].Value = fName;
parms["UserID"].Value = userName;
DTSExecResult results = package.Execute();
if (results == Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure)
{
foreach (Microsoft.SqlServer.Dts.Runtime.DtsError local_DtsError in package.Errors)
{
retCode = false;
resultText = resultText + "DTSX Package Execution results: " + local_DtsError.Description.ToString() + Environment.NewLine;
}
}
else
{
resultText = resultText + "Successful Process Completion." + Environment.NewLine + Environment.NewLine;
string sqlStr = "SELECT TOP 1 * FROM Validation WHERE Type = 'VALCO' AND CAST(CreatedDate AS DATE) = CAST(GETDATE() AS DATE)";
DataTable dt = new DataTable();
dt = GetDataSet(sqlStr);
if (dt.Rows.Count > 0)
{
foreach (DataRow row in dt.Rows)
{
if (row["Status"].ToString() == "Valid")
{
retCode = true;
resultText = "Output: Valid" + Environment.NewLine + "Press the 'Process' button to proceed.";
}
else
{
retCode = false;
resultText = "Output: " + row["Status"].ToString() + Environment.NewLine + "Validation Fail: " + row["Error"].ToString();
}
}
}
else
{
resultText = "Unable to read Validation Table for this file.";
retCode = false;
}
}
}
catch (Exception)
{
throw;
}
return retCode;
}
Your code will look like so:
if (IsFlatFile(fileName) || IsXMLFile(fileName) || IsCSVFile(fileName))
{
btnProcess.Enabled = isCoValid(fileName);
if (!btnProcess.Enabled) break;
}
public static bool IsCSVFile(string FileName) =>
Path.GetExtension(FileName).Equals(".csv", StringComparison.OrdinalIgnoreCase);
when you write your own IsCSVFile() method and update isCoValid() method to fit your needs.
Sorry, but I can't guess what happens inside classes that are used in isCoValid() method.
I want to check if the given Password is the password which is locking the Excel-File.
Here is how i tried it:
var DepartmentStream = new FileStream(Deparment, FileMode.Open);
var EmplyoeeStream = new FileStream(Employee, FileMode.Open);
var options = new LoadOptions {Password = "ExamplePassword123"};
DepartmentGrid = new Workbook(DepartmentStream); // set as a Workbook property and doesn't need a password
try
{
EmployeeGrid = new Workbook(EmplyoeeStream , options); // set as a Workbook property
}
catch (Exception ex)
{
EmployeeGrid= null;
}
if (EmployeeGrid == null)
{
MessageBox.Show("The given password is wrong!", "Wrong password",);
return;
}
How can i fix this, so that if the EmployeeGrid's (set as a Workbook property) password isn't the same as the given password the MessageBox get showed and the code leaves the method?
Your code looks to me OK, what's wrong with it? Your current code is trying to load an encrypted (password protected) file with the given password. If your code is not doing what you want, kindly do elaborate your needs, so we could help you accordingly. I will also write another sample code for your complete reference:
e.g
Sample code:
string m_documentFile = "e:\\test2\\EncryptedBook1j.xls";
//Get the password list to store into arrays.
string[] m_passwordList = { "001", "002", "003", "004", "005", "006", "007", "008" };
Workbook _workBook;
int i = 0;
int ncnt = 0;
//Check if the file is password protected.
FileFormatInfo fft = FileFormatUtil.DetectFileFormat(m_documentFile);
bool check = fft.IsEncrypted;
RetryLabel:
try
{
if (check)
{
LoadOptions loadOps = new LoadOptions();
for (i = ncnt; i < m_passwordList.Length; i++)
{
loadOps.Password = m_passwordList[i];
_workBook = new Workbook(m_documentFile, loadOps);
MessageBox.Show("Opened Successfully with the Password:" + m_passwordList[i]);
break;
}
}
}
catch (Exception ex)
{
if (ex.Message.CompareTo("Invalid password.") == 0)
{
MessageBox.Show("Invalid Password: " + m_passwordList[i] + " ,trying another in the list");
ncnt = i + 1;
goto RetryLabel;
}
}
PS. I am working as Support developer/ Evangelist at Aspose.
I have a WPF App that allows the user to choose one to many spreadsheets and performs a process to clean the data and write out a pipe delimited files. I am trying to use a Background Worker in order to display a progress bar. The problem I am having is that I have the backgroundworker_DoWork routine to perform the read the excel file, clean the data and write out the data. For each spreadsheet the user is allowed to specify the range for the data or to let Excel decided the range. I call a dialog for this input. I get the error "The calling thread must be STA, because many UI components require this." I have been trying to find a fix for this but everything I try doesn't work.
Here is my code. I have put comments where the offending code is and what I have tried so far.
private void ProcessFiles()
{
int intNumFiles = 0;
string strFileType = "";
int intPos = 0;
string strMsg = "";
intNumFiles = strExFileNames.Length;
foreach (string strInputFile in strExFileNames)
{
intPos = strInputFile.LastIndexOf(".");
strFileType = strInputFile.Substring(intPos + 1);
if(!blnEXTextFileFound)
{
strExcelInputFile = strInputFile;
if (blnExParamCancel || blnMWCancel)
{
strMsg = "Processing has been cancelled.";
System.Windows.MessageBox.Show(strMsg);
break;
}
prgExcelProgress.Visibility = Visibility.Visible;
txtExcelPercent.Visibility = Visibility.Visible;
EnterExcelStateRunning();
try
{
bgwExcelRunner.RunWorkerAsync(strInputFile);
}
catch (Exception ex)
{
System.Windows.MessageBox.Show("Trying to run the Excel/Text file clean process resulted in this error: " + ex.Message, " Error");
prgExcelProgress.Foreground = new SolidColorBrush(Colors.DarkRed);
prgExcelProgress.Value = 100;
}
//ReadWriteExcelData(strInputFile);
}
else
{
if (blnEXTextFileFound)
{
ProcessDelimitedFile(strInputFile);
}
else
{
strMsg = "File type " + strFileType + " is not supported.";
strMsg += " Please contact support.";
System.Windows.MessageBox.Show(strMsg);
}
}
}
prgExcelProgress.Value = 100;
//prgIndicator.Width = 400;
//lblPrctPrgrs.Content = "100%";
//grdProgressIndicator.InvalidateVisual();
//System.Windows.Forms.Application.DoEvents();
//Thread.Sleep(2000);
//txtIndicator.Text = "All files have been processed and created in " + strExOutputPath + ".";
blnDoForAll = false;
}
private void bgwExcelRunner_DoWork(object sender, DoWorkEventArgs e)
{
Excel.Application xlApp;
Excel.Workbook xlWorkBook;
Excel.Worksheet xlWorkSheet;
Excel.Range range, colrange, rowrange;
string strCellData, strMsg;
string strDataRow = "";
long lngNumRows, lngNumCols = 0;
long intModNumber, lngProgressPct = 0;
double dblProgress = 0;
double dblProgressPct = 0;
string strOutputFileName = "";
int intPos, intProgress = 0;
string strSubFileName = "";
string strFullOutputFileName = "";
string strOutName = "";
long lngColCnt;
string[] strWSNames = new string[0];
Type typCellType;
bool blnMultiWS = false;
string strNumberFormat;
string strFileName = (string)e.Argument;
//string strFileName = (string)((object[])e.Argument)[0];
intPos = strFileName.IndexOf(".");
strSubFileName = strFileName.Substring(0, intPos);
strOutputFileName = strFileName.Substring(strFileName.LastIndexOf("\\") + 1);
strOutName = strOutputFileName.Substring(0, strOutputFileName.IndexOf("."));
xlApp = new Excel.Application();
xlWorkBook = xlApp.Workbooks.Open(strFileName, 0, true, 5, "", "", true,
Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
Excel.Sheets excelSheets = xlWorkBook.Worksheets;
if (excelSheets.Count > 1)
{
blnMultiWS = CheckMultipleWorksheets(excelSheets);
if (!blnMultiWS)
{
Array.Clear(strChoosenNames, 0, strChoosenNames.Length);
Array.Resize(ref strChoosenNames, 1);
strChoosenNames[0] = strOutName;
}
}
else
{
Array.Resize(ref strChoosenNames, 1);
strChoosenNames[0] = strOutName;
}
if (blnMWCancel)
{
strMsg = "Processing has been cancelled.";
System.Windows.MessageBox.Show(strMsg);
goto ReadWriteExcelDataExit;
}
foreach (string strCurrWSName in strChoosenNames)
{
//grdProgressIndicator.Visibility = Visibility.Visible;
//txtIndicator.Text = "File: " + strCurrWSName;
//prgIndicator.Width = 0;
//lblPrctPrgrs.Content = "0%";
//System.Windows.Forms.Application.DoEvents();
//txtIndicator.Text = " Processing File: " + strCurrWSName + ". Please wait...";
strFullOutputFileName = strExOutputPath + "\\" + strCurrWSName + "_duc.txt";
//if (strChoosenNames.Length > 1)
//{
// xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets[strCurrWSName];
//}
//else
//{
// xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
//}
try
{
xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets[strCurrWSName];
}
catch (Exception exQuery)
{
xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
}
if (!blnDoForAll)
{
// I ALSO TRIED TO USE A THREAD. THIS SEEMS TO WORK EXCEPT THAT IT PROCESSING DOESN'T RUN IN THE FOREGROUND SO IT FALLS TO THE CODE AFTER BEFORE THE DIALOG IS DISPLAYED
//Thread thread = new Thread(() =>
//{
// ExcelRowColInfo ercWin = new ExcelRowColInfo(xlWorkSheet.Name);
// ercWin.Left = System.Windows.Application.Current.MainWindow.Left + 15;
// ercWin.Top = System.Windows.Application.Current.MainWindow.Top + 15;
// ercWin.ShowDialog();
// blnExParamCancel = ercWin.blnExCancel;
// strExcelStartCol = ercWin.strStartCol;
// strExcelEndCol = ercWin.strEndCol;
// lngExcelStartRow = ercWin.lngStartRow;
// lngExcelEndRow = ercWin.lngEndRow;
// blnLetExcelDecide = ercWin.blnExcelDecide;
// blnDoForAll = ercWin.blnDoForAll;
//});
//thread.SetApartmentState(ApartmentState.STA);
//thread.IsBackground = false;
//thread.Start();
// THIS IS ONE ATTEMPT TO USE A DISPATCHER, STILL GET THE STA ERROR
//ExcelRowColInfo ercWin = new ExcelRowColInfo(xlWorkSheet.Name);
//ercWin.Left = System.Windows.Application.Current.MainWindow.Left + 15;
//ercWin.Top = System.Windows.Application.Current.MainWindow.Top + 15;
//ercWin.Dispatcher.BeginInvoke
// (
// System.Windows.Threading.DispatcherPriority.Normal,
// (Action)(() =>
// {
// ercWin.ShowDialog();
// blnExParamCancel = ercWin.blnExCancel;
// }
// )
// );
// THIS IS WHERE THE ERROR OCCURS
ExcelRowColInfo ercWin = new ExcelRowColInfo(xlWorkSheet.Name);
ercWin.Left = System.Windows.Application.Current.MainWindow.Left + 15;
ercWin.Top = System.Windows.Application.Current.MainWindow.Top + 15;
ercWin.ShowDialog();
blnExParamCancel = ercWin.blnExCancel;
if (blnExParamCancel)
{
prgExcelProgress.Foreground = new SolidColorBrush(Colors.LightPink);
Dispatcher.BeginInvoke((Action)delegate
{
prgExcelProgress.Value = 100;
txtExcelPercent.Text = "Process has been cancelled";
});
blnExParamCancel = false;
goto ReadWriteExcelDataExit;
}
strExcelStartCol = ercWin.strStartCol;
strExcelEndCol = ercWin.strEndCol;
lngExcelStartRow = ercWin.lngStartRow;
lngExcelEndRow = ercWin.lngEndRow;
blnLetExcelDecide = ercWin.blnExcelDecide;
blnDoForAll = ercWin.blnDoForAll;
if (blnLetExcelDecide)
{
range = xlWorkSheet.UsedRange;
}
else
{
Excel.Range c1 = xlWorkSheet.Cells[lngExcelStartRow, strExcelStartCol];
Excel.Range c2 = xlWorkSheet.Cells[lngExcelEndRow, strExcelEndCol];
range = (Excel.Range)xlWorkSheet.get_Range(c1, c2);
}
colrange = range.Columns;
lngNumCols = colrange.Count;
rowrange = range.Rows;
lngNumRows = rowrange.Count;
if (lngNumRows < 10)
{
intModNumber = lngNumRows;
}
else
{
intModNumber = lngNumRows / 10;
}
if (System.IO.File.Exists(#strFullOutputFileName))
{
System.IO.File.Delete(#strFullOutputFileName);
}
object[,] values = (object[,])range.Value;
long NumRow = 1;
using (StreamWriter file = new StreamWriter(#strFullOutputFileName, true, Encoding.GetEncoding("iso-8859-1")))
{
while (NumRow <= values.GetLength(0))
{
strDataRow = "";
for (lngColCnt = 1; lngColCnt <= lngNumCols; lngColCnt++)
{
if (values[NumRow, lngColCnt] == null)
{
typCellType = typeof(System.String);
}
else
{
typCellType = values[NumRow, lngColCnt].GetType();
}
strCellData = Convert.ToString(values[NumRow, lngColCnt]);
if (typCellType == typeof(System.DateTime))
{
strCellData = strCellData.Substring(0, strCellData.IndexOf(" "));
}
else
{
if (typCellType == typeof(System.Decimal))
{
if (Convert.ToDecimal(values[NumRow, lngColCnt]) == 0)
{
strCellData = Convert.ToString(0);
}
else
{
strCellData = Convert.ToString(values[NumRow, lngColCnt]);
}
}
else
{
if (typCellType != typeof(System.String))
{
strNumberFormat = range[NumRow, lngColCnt].NumberFormat.ToString();
if (strNumberFormat != "General" && strNumberFormat != "Text" && strNumberFormat != "#")
{
if (typCellType == typeof(System.Double))
{
if (strNumberFormat.IndexOf("[Red]") > 0)
{
strCellData = Convert.ToString(range[NumRow, lngColCnt].Value2);
}
else
{
double dblCellValue = double.Parse(strCellData);
strCellData = dblCellValue.ToString(strNumberFormat);
}
}
}
}
}
}
if (strCellData == null)
{
strCellData = string.Empty;
}
else
{
strCellData = strCellData.Replace("\r\n", " ").Replace("\n", " ").Replace("\r", " ");
}
if (lngColCnt == lngNumCols)
{
strDataRow += strCellData;
}
else
{
strDataRow += strCellData + "|";
}
}
file.WriteLine(strDataRow);
if (NumRow % intModNumber == 0)
{
lngProgressPct = (NumRow / lngNumRows);
bgwExcelRunner.ReportProgress((int)lngProgressPct);
}
NumRow++;
}
}
releaseObject(xlWorkSheet);
}
xlWorkBook.Close(false, null, null);
ReadWriteExcelDataExit:
blnMWCancel = false;
xlApp.Quit();
releaseObject(xlWorkBook);
releaseObject(xlApp);
}
Here is the entry point for the ExcelRowColInfo window.
public ExcelRowColInfo(string strWSName)
{
InitializeComponent();
strCurrWSName = string.Copy(strWSName);
InitializeExcelParams();
}
I tried to put [STAThread] above this but get the error "Attributre 'STAThread' is not valid on this declaration type. It is only valid on 'Method' declaration.
How do I do this correctly?
I'm currently developing an mono application in c#, which I would like to start only once. I know, this can be achieved with mutex. But how can I bring the application to front using mono?
I tried getting the Process via
Process.GetProcessByName("AudioCuesheetEditor")
but couldn't access the MainWindowHandle.
How can I bring the running application to front?
Thanks for you answers.
EDIT:
Now I have been able to get the MainWindowHandle, but it's a IntPtr. How do I bring this handle to front? I tried
Window wRunning = new Window(handle);
wRunning.Present();
but that gave me an exception :(.
I have been able to fix it with a file system watcher:
FileSystemWatcher fswRunning = new FileSystemWatcher(Path.GetTempPath() + "AudioCuesheetEditor");
fswRunning.Filter = "*.txt";
fswRunning.Changed += delegate(object sender, FileSystemEventArgs e) {
log.debug("FileSystemWatcher called Changed");
if (pAudioCuesheetEditor != null)
{
log.debug("pAudioCuesheetEditor != null");
pAudioCuesheetEditor.getObjMainWindow().Present();
}
};
fswRunning.EnableRaisingEvents = true;
Boolean bAlreadyRunning = false;
Process[] arrPRunning = Process.GetProcesses();
foreach (Process pRunning in arrPRunning)
{
Boolean bCheckProcessMatch = false;
if (Environment.OSVersion.Platform == PlatformID.Unix)
{
if (pRunning.HasExited == false)
{
log.debug("pRunning.ProcessName = " + pRunning.ProcessName + " pRunning.MainWindowTitle = " + pRunning.MainWindowTitle);
if (pRunning.ProcessName.ToLower().Contains("mono"))
{
for (int i = 0; i < pRunning.Modules.Count;i++)
{
if (pRunning.Modules[i].ModuleName.Contains("AudioCuesheetEditor"))
{
bCheckProcessMatch = true;
i = pRunning.Modules.Count;
}
}
}
}
}
else
{
log.debug("pRunning.ProcessName = " + pRunning.ProcessName);
if (pRunning.ProcessName == Process.GetCurrentProcess().ProcessName)
{
bCheckProcessMatch = true;
}
}
log.debug("bCheckProcessMatch == " + bCheckProcessMatch);
if ((pRunning.Id != Process.GetCurrentProcess().Id) && (bCheckProcessMatch == true))
{
log.info("Writing to file " + Path.GetTempPath() + "AudioCuesheetEditor" + Path.DirectorySeparatorChar + "message.txt");
File.WriteAllText(Path.GetTempPath() + "AudioCuesheetEditor" + Path.DirectorySeparatorChar + "message.txt","Present");
bAlreadyRunning = true;
}
}
log.debug("bAlreadyRunning = " + bAlreadyRunning);
if (bAlreadyRunning == false)
{
//Start Application
}
Using a FSW for this seems like very hacky.
I think the most elegant solution is using IPC.
In particular, I would use DBus. In fact, it's what Banshee uses to avoid multiple instances of it being created. So go ahead and check out our source code if you're interested.
I have some code that I wanted to improve. It uses Process.Start and should be able to handle any input any argument, and still work.
I don't think I have covered all the bases. Can anyone suggest a better/more thorough approach?
ToMaybeUri is an extension method that tries to create a Uri.
ToValidMailToArgument is an extension method that adds "attachments="
IsValidEmail is an extension method that does a RegEx on the email address.
public static void RunProcess(string fileName, string Params)
{
var useProcessStart = true;
var validFile = false;
var validDir = false;
var validEmail = false;
var validURL = false;
var proc = new Process();
var info = new ProcessStartInfo(fileName);
info.UseShellExecute = true;
info.Arguments = Params;
//try catches here in case the syntax of the string has invalid characters for dir/file
try
{
var di = new DirectoryInfo(fileName);
validDir = di == null ? false : di.ExistsNow();
}
catch (Exception ex) { }
try
{
var fi = new FileInfo(fileName);
validFile = fi == null ? false : fi.Exists();
}
catch (Exception ex) { }
if (Params == "")
{
if (validFile)
{
if (Path.GetExtension(fileName).ToUpper() == ".CHM")
{
var helpProvider1 = new HelpProvider();
helpProvider1.HelpNamespace = fileName;
Help.ShowHelp(Application.OpenForms[0], helpProvider1.HelpNamespace);
MessageBox.Show(msg);
return;
}
}
else if (validDir)
{
//skip
}
else if (fileName.IsValidEmail())
{
validEmail = true;
info.FileName = "mailto:" + info.FileName;
info.Arguments = "";
}
else if (fileName.IsValidUrl())
{
validURL = true;
info.FileName = fileName.ToMaybeUri().Value.ToString();
info.Arguments = "";
}
else
{
MessageBox.Show(fileName + " does not exist.");
}
}
else
{
//and has params
if (Path.GetExtension(fileName).ToUpper() == ".PDF" && Params.ToLower().StartsWith("p"))
{
int pageNum = 0;
string pageNumString = Grazer.Utilities.Strings.Right(Params, Params.Length - 1);
int.TryParse(pageNumString, out pageNum);
//PDFLocation = "/A \"page=" + pageNum + "=OpenActions\" \"" + ssGlobals.ssStartDir + "\\Example.pdf\""
string app = GrRegistry.GetApplicationFromExtension(".PDF");
if (Path.GetFileNameWithoutExtension(app).ToUpper() == "ACROBAT" || Path.GetFileNameWithoutExtension(app).ToUpper() == "ACRORD32")
{
string PDFLocation = String.Format("/A \"page={0}=OpenActions\" \"{1}\"", pageNum, Path.GetFullPath(fileName));
info = new ProcessStartInfo(app);
info.Arguments = PDFLocation;
}
}
else if (fileName.IsValidEmail())
{
validFile = false;
try
{
var fi = new FileInfo(info.Arguments);
validFile = fi == null ? false : fi.ExistsNow();
}
catch (Exception ex) { }
info.FileName = String.Format("mailto:{0}{1}", fileName, new FileInfo(info.Arguments).ToValidMailToArgument());
info.Arguments = "";
}
}
if (useProcessStart)
{
proc.StartInfo = info;
try
{
if (validURL || validFile || validDir || validEmail)
proc.Start();
}
catch (Exception ex)
{
switch (ex.Message)
{
case "No process is associated with this object.":
break;
default:
MessageBox.Show(ex);
if (info.Arguments.ToEmptyIfNull().Length > 0)
MessageBox.Show(String.Format("{0} could not be opened with parameters: {1}", info.FileName, info.Arguments));
else
MessageBox.Show(String.Format("{0} could not be opened", info.FileName));
break;
}
}
}
}
To start with, you don't want to swallow exceptions. On your catch blocks, make sure you're doing something after catching an exception. Also, find out what specific exceptions can be thrown by methods you're calling in your try blocks and catch those specific exceptions, like so:
try
{
SomeMethod();
}
catch (SpecificExceptionType1)
{
//do something based on what this exception means
}
catch (SpecificExceptionType2)
{
//ditto here
}
catch
{
//handle unexpected exceptions here
}
Also, this smells suspiciously like homework - perhaps implementing a command shell? If so, retag it as homework. If not, just tell me to stuff it.