I'm trying to determine whether or not an instance of Excel of running with a particular file open, and if so attach to it so I can control that instance.
I've searched around and the majority of what I've got have come from this question. It has a reference to another site, but unfortunately it's dead for me so I cannot read up on it.
My code so far is;
//Is Excel open?
if (Process.GetProcessesByName("EXCEL").Length != 0)
{
Process[] processes = Process.GetProcesses();
foreach (Process process in processes)
{
//Find the exact Excel instance
if (process.ProcessName.ToString() == "EXCEL" && process.MainWindowTitle == ("Microsoft Excel - " + fileName))
{
//Get the process ID of that instance
int processID = (int)Process.GetProcessById(process.Id).MainWindowHandle;
//Attach to the instance...
Excel.Application existingExcel = (Excel.Application)System.Runtime.InteropServices.Marshal.GetActiveObject(process.Id);
}
}
}
So far I've managed to get the process ID of the instance I want to attach to, but I'm lost when it comes to using that ID.
Any ideas on how to proceed?
Marshal.GetActiveObject() doesn't take a process ID as a parameter. What you want is:
Marshal.GetActiveObject("Excel.Application");
Note that this doesn't require keeping track of the process at all, there just needs to be one.
It gets a lot more complicated if you can have multiple processes and want to attach to a specific one. That is where the answer to the other question comes in.
There is also a good article at http://blogs.msdn.com/b/andreww/archive/2008/11/30/starting-or-connecting-to-office-apps.aspx with a more full description of different ways of launching excel. Note that not all of them are necessarily up to date with Excel 2013, where having a single process for all Excel windows complicates things. For your purposes though, the GetActiveObject solution should be fine.
Related
For learning purposes and mere curiosity I have been trying somehow to kill a process with the characteristics explained above in the title:
1. The name of the file changes every time it is downloaded.
2. Window without a name.
(I can't use PID because I need something that doesn't change to make it automatic)
(The exe name always start with DaxSS-
Example names:
DaxSS-TSFGR
DaxSS-RFDUC
DaxSS-GFFRS
Is there a way to do that?
The downloaded exe name always start with DaxSS
That's your ticket right there!
string start = "DaxSS".ToUpper();
Process P = Process.GetProcesses().Where((p) => p.ProcessName.ToUpper().StartsWith(start)).FirstOrDefault();
if (P != null)
{
P.Kill();
}
I have a small issues which i was not able to find any solution on StackOverFlow.
The Situation:
I have an application that automatically opens up EXCEL application. When it opens it right away gives a dialog box that says "The file format and extension of xxx don't match. The file could be corrupted or unsafe..."
I am trying to create an application that focus on this running EXCEL application and hit the "YES" and resave the excel with VERSION 2007 so this error message will not come up again.
Here is what i have so far:
var excelApp = (Excel.Application)Marshal.GetActiveObject("Excel.Application");
var c = excelApp.ActiveDialog;
Not sure how to do a click event on the YES using the excelApp variable.
I also tried through
foreach (Process proc in Process.GetProcesses())
{
if (proc.MainWindowTitle.Contains("Excel"))
....
}
Nov. 06 2017:
This is what i have so far now:
var oExcelApp = (Excel.Application)Marshal.GetActiveObject("Excel.Application");
Process[] processlist = Process.GetProcessesByName("Excel"); //Shows number of running Excel apps
foreach (Process theprocess in processlist) //foreach Excel app running
{
if (oExcelApp.Workbooks.Count >= 0) //for worbooks in each Excel app
{
foreach (Excel.Workbook wkb in oExcelApp.Application.Workbooks)
{
wkb.SaveAs(filePath, Excel.XlFileFormat.xlExcel8);
wkb.Close(true, null, null);
Marshal.FinalReleaseComObject(wkb);
}
oExcelApp.Workbooks.Close();
}
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
oExcelApp.Quit();
Marshal.ReleaseComObject(oExcelApp);
}
This works ONLY If there was no error message at the beginning. If the process automatically opens excel and has error message showing this will throw an exception because the application is busy on the error message.
I don't know of a way to do exactly what you describe -- to intercept a dialog box within the application.
What I think you want to do is have Excel suspend warnings in the first place. You can do this by modifying the DisplayAlerts property to false.
var excelApp = (Excel.Application)Marshal.GetActiveObject("Excel.Application");
excelApp.DisplayAlerts = false;
// This should not give you any warnings
excelApp.Workbooks.Open("c:/cdh/test.xls");
And when you are done, put things back as they were:
excelApp.DisplayAlerts = true;
hi you can create another application in which you can write logic of close alert box of Excel and execute from your main application
foreach (Process proc in Process.GetProcesses())
{
if (proc.MainWindowTitle.Contains("Excel"))
....
},
so no need to user interaction for close this alert box,
and you can save different alert message in database and check if this message come in alert box you can close
Thanks all for your help. I was able to go around this and disable all alerts for Microsoft Excel Application using the REGEDIT. This was the only way to go around this situation. Just posting an answer to help others in the same situation:
REGEDIT Solution (Read near the bottom)
I'm trying to make a .net 4.0 program which will get the filename of a PowerPoint Show (PPS) that is being viewed on the same machine. The purpose is to time how long a particular presentation takes to go through without any user action.
I've tried the following:
oPPTApp = (PowerPoint.Application)System.Runtime.InteropServices.Marshal.
GetActiveObject("PowerPoint.Application");
string ppsname = oPPTApp.ActivePresentation.Name.ToLower();
The program runs minimized while the presentation is being viewed. Even while interacting with the PPS (scrolling through slides, clicking, etc), I get the following error from Microsoft.Office.Interop.PowerPoint._Application:
Application (unknown member) : Invalid request. There is no active presentation.
After searching through http://support.microsoft.com/kb/285472, I tried adding:
oPPTApp.Visible = Microsoft.Office.Core.MsoTriState.msoTrue;
However, this started a new instance of PowerPoint, followed by the same error.
I'll also mention I'm using Microsoft PowerPoint 14.0 Object Library and the IOleMessageFilter error handler from here: http://msdn.microsoft.com/en-us/library/vstudio/ms228772(v=vs.110).aspx
Does ActivePresentation.Name not apply to PPS files? Is there a better way of getting the filename of an open PPS?
Why not use plain old System.Diagnostics.Process?
The following code will give you the name of the active window of all processes with a given friendly name (process name without extension; in your case "POWERPNT").
using System.Diagnostics;
public static IEnumerable<string> GetActiveMainWindowsTitle(string processName)
{
var ps = Process.GetProcessesByName(processName);
foreach (var p in ps)
yield return p.MainWindowTitle;
}
The MainWindowTitle of a MS PowerPoint process is the name of the active presentation so if you are only looking for that info, this should do (you might need to clean the title a little if you are running, for example, a Home and Student version; usually there is a "non comercial use" tag on the main window title)
my application creates a new instance of winword embedded in a windows form.
new Microsoft.Office.Interop.Word.ApplicationClass()
Once the user finishes editing I close the window but the winword instance is still running in the background.
How can I kill that particular instance? I know how to kill all instances running on a machine but this isn't an option.
You need to call
application.Quit()
In your code.
One thing I had to do on my system (it's an excel processing tool) is do a process kill if after the Quit things were still going on.
var openedExcel = System.Diagnostics.Process.GetProcessesByName("EXCEL");
if (openedExcel.Any())
{
foreach (var excel in openedExcel)
{
try { excel.Kill(); }
catch { }
}
}
There are different methods for this (Marshal.ReleaseComObject is the most used I believe).
I suggest you should read the official documentation about releasing Office applications instances. it's available here: Microsoft .NET Development for Microsoft Office / Releasing COM Objects
I Suggest you combine / add to Flaviotsf's answer the following code - which will determine what actual process is on the run:
Process[] myProcList = Process.GetProcesses();
for (int i = 0; i <= myProcList.Length - 1; i ++) {
string strProcessName = myProcList [i].ProcessName;
string strProcessTitle = myProcList [i].MainWindowTitle();
//check for your process name.
if (strProcessName.ToLower().Trim().Contains("access")) {
myProcList [i].Kill();
}
}
Kill particular instance of Winword Document.
foreach (var process in Process.GetProcessesByName("WINWORD"))
{
if (process.MainWindowTitle.Contains("Temp")) // Temp is document name.
process.Kill();
}
How do I retrieve the starting time of a process using c# code? I'd also like to know how to do it with the functionality built into Widows, if possible.
public DateTime GetProcessStartTime(string processName)
{
Process[] p = Process.GetProcessesByName(processName);
if (p.Length <= 0) throw new Exception("Process not found!");
return p[0].StartTime;
}
If you know the ID of the process, you can use Process.GetProcessById(int processId). Additionaly if the process is on a different machine on the network, for both GetProcessesByName() and GetProcessById() you can specify the machine name as the second paramter.
To get the process name, make sure the app is running. Then go to task manager on the Applications tab, right click on your app and select Go to process. In the processes tab you'll see your process name highlighted. Use the name before .exe in the c# code. For e.g. a windows forms app will be listed as "myform.vshost.exe". In the code you should say
Process.GetProcessesByName("myform.vshost");
Process has a property "StartTime":
http://msdn.microsoft.com/en-us/library/system.diagnostics.process.starttime.aspx
Do you want the start time of the "current" process? Process.GetCurrentProcess will give you that:
http://msdn.microsoft.com/en-us/library/system.diagnostics.process.getcurrentprocess.aspx
In Code
Suppose you want to find the start time of Notepad, currently running with PID 4548. You can find it, using the PID or the process name, and print it to the debug window like this:
//pick one of the following two declarations
var procStartTime = System.Diagnostics.Process.GetProcessById(4548).StartTime;
var procStartTime = System.Diagnostics.Process.GetProcessesByName("notepad").FirstOrDefault().StartTime;
System.Diagnostics.Debug.WriteLine(procStartTime.ToLongTimeString());
In Windows
You can use Process Explorer, which has an option to display the process start time, or you can list all the currently running processes, and their start times, from the command line with the following:
wmic process get caption,creationdate
You can get process metadata by inspecting the Process object returned by Process.GetProcessesByName().
System.Diagnostics.Process.GetProcessById(xxx).StartTime;//fails for certain processes with access denied