Attach to open Excel process

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

Is it possible to attach to an open process and perform automation on it?
I have an application that needs to manipulate Excel files extensively.
Most of the manipulation goes on with Excel application hidden.
But sometimes I need the user to edit the Excel files.
Before parsing the file again, I would like to check that it is not left
open and potentially unsaved in an Excel application window.

I know it is not possible to run this code:

Dim a As Excel.Application
For Each p As Process In Process.GetProcessesByName("Excel")
a = DirectCast(p, Excel.Application)
'Check if any of these processes:
'1) Are Hidden remnants from previous unsuccessful
automation and needs to be closed
'2) Have a specific file open that needs to be saved before
it is read
Next

But is there some similar method to attach to an Excel process and get hold
of it as an automation object that can be investigated?

Or is there any other workarounds to accomplish the same thing?
 
Hi,

I do this like the following:

Hi,

I do it like below:

Microsoft.Office.Interop.Excel.Application oXL;

try
{
//Try to reuse an excel application object
oXL = Marshal.GetActiveObject("Excel.Application") as
Microsoft.Office.Interop.Excel.Application;
}
catch(Exception)
{
//Create one
oXL = new Microsoft.Office.Interop.Excel.Application();
}


Regards,
Erik
 
Hi,

I do it like below:

Microsoft.Office.Interop.Excel.Application oXL;

try
{
//Try to reuse an excel application object
oXL = Marshal.GetActiveObject("Excel.Application") as
Microsoft.Office.Interop.Excel.Application;
}
catch(Exception)
{
//Create one
oXL = new Microsoft.Office.Interop.Excel.Application();
}


Regards,
Erik
 
Thanks for this suggestion.
It works fine if there is only one instance of Excel running ....
But as far as I understand it will only return one of the processes running
Excel.
So if any of the other processes is the one editing my file I will not
detect it.
 
There should not be more then one Excel process running. All workbooks
beeing open on the machine can be iterated through using the WoekBooks
property of the applcation object.
 
What do you mean with "should".
In fact I HAVE several Excel processes running, otherwise there would not be
a problem :)
If I use Marshal.GetActiveObject and then iterate the workbooks I DON'T get
hold of workbooks opened in other instances of Excel.
 
Ah, sorry for beeing unclear.

If I let Excel open workbooks either by the Excel UI or by double clicking
the xls files on disk I get no new Excel processes. They all open as new
workboos in the running instance of Excel. Earlier however in my solution
where I programmatically opened and closed workbooks I got leftover
processes hanging around. But with the code snipplet below and by keeping
track of if I need to clean up an Excel process I have started in the code
there is never more then one excel.exe running.
 
Hi Jakob,

It's possible to automate a running instance of an Office program. A .NET
client can get a reference to the running instance by calling the following:

System.Runtime.InteropServices.Marshal.GetActiveObject
-or-
System.Runtime.InteropServices.Marshal.BindToMoniker

COM servers can be classified as Multiuse (Single Instance) or Single Use
(Multiple Instances), depending on the number of instances of that server
that can run simultaneously on a single computer.

When a request for a new COM object comes to a Multiuse (Single Instance)
COM server, the server uses only one instance of the .exe file to create
that object. No matter how many clients request a new COM object, there
will be only one server .exe process. In the Single Use (Multiple
Instances) server, each request for a new COM object starts a separate
instance of the server .exe file. Therefore, more than one instance of the
server can run on the same computer.

Multiple instances of Word (Winword.exe), Excel (Excel.exe), and Microsoft
Access (MSAccess.exe) can run simultaneously. Therefore, these servers are
defined as Single Use (Multiple Instances) servers. Only one instance of
PowerPoint (Powerpnt.exe) can run at any given time. Therefore, PowerPoint
is a Multiuse (Single Instance) server.

Whether a COM server is Single Use (Multiple Instances) or Multiuse (Single
Instance) might affect your decision to use GetActiveObject to get
reference to that server. Because potentially more than one instance of
Word, Excel, or Microsoft Access can be running, GetActiveObject on a
particular server may return an instance that you did not expect. The
instance that is first registered in the ROT is typically the instance that
is returned by GetActiveObject. If you want to get an Automation Reference
to a specific running instance of Word, Excel, or Microsoft Access, use
BindToMoniker with the name of the file that is opened in that instance.
For a Multiuse (Single Instance) server like PowerPoint, it does not
matter, because the automation reference points to the same running
instance.

For more information on how to automate a running instance of an Office
program, please visit the following KB article. Althought the sample code
is written in C#, it should not be difficult to translate it into VB.NET.

http://support.microsoft.com/kb/316126

Hope this helps.
If you have any concerns, please feel free to let me know.



Sincerely,
Linda Liu
Microsoft Online Community Support

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
Thanks Linda for an excellent answer!!

In my case I would like to check whether a specific Excel file is open.
I came up with the following simple function that works fine:

Private Function IsOpen(ByVal fileName As String) As Boolean
Dim wb As Excel.Workbook

Try
wb = DirectCast(Marshal.BindToMoniker(fileName), Excel.Workbook)
Return True
Catch ex As Exception
Return False
End Try
End Function

Is that a good way to do it, or would there be a better way that avoids
throwing an exception?
Do I need to do a cleanup by setting wb = Nothing?
 
I was probably to quick in my initial positive response.
The function IsOpen mentioned in my previous answer will not work very well
.....
In fact it will always OPEN the file in Excel as long as the file exists.

It was still interesting to read about the monikers :)

Some other suggestion?
 
Hi Jakob,
Do I need to do a cleanup by setting wb = Nothing?

If you don't need to use the variable "wb" any more in your program, you
should set wb = Nothing to release the reference.

As for the question of checking whether a specific Excel file is open, I
don't think the BindToMoniker method is appropriate in this case, because
it will open the specified file if it has not been opened yet as you have
mentioned.

When we open a file with Excel, the file is opened exclusively. We could
make use of this feature to check if the file has been opened already. What
we need to do is to try to open the specified file. If an exception occurs,
it means that the file has been opened. Otherwise, the file hasn't been
opened.

The following is the sample code.

Private Function IsOpen(ByVal filename As String) As Boolean
Try
Dim fs As System.IO.FileStream =
System.IO.File.OpenWrite(filename)
fs.Close()
Return False
Catch ex As Exception
Return True
End Try
End Function

Hope this helps.
If you have anyting unclear, please feel free to let me know.


Sincerely,
Linda Liu
Microsoft Online Community Support
 
Back
Top