Article Options
Recently Viewed
Premium Sponsor
Premium Sponsor

 »  Home  »  .NET Framework  »  50 Ways to Kill Excel  »  Excel Inception
 »  Home  »  Windows Development  »  Interop  »  50 Ways to Kill Excel  »  Excel Inception
50 Ways to Kill Excel
by Scott Rutherford | Published  06/14/2006 | .NET Framework Interop | Rating:
Excel Inception

1. Open Excel

Before we can go on about stopping Excel, we’ll quickly look at how to start Excel. If this is nothing new you may move on to the next page. However, you need to be aware of one line that may not appear in your code: note where the Caption property of the Excel application is set. It is set to a unique identifier by creating a GUID string.

    Public Function OpenExcel(ByVal Interact As Boolean) As _
      Microsoft.Office.Interop.Excel.ApplicationClass
        Dim App As Microsoft.Office.Interop.Excel.ApplicationClass
        App = New Microsoft.Office.Interop.Excel.ApplicationClass
        App.DisplayAlerts = Interact
        App.Interactive = Interact
        App.Visible = Interact
        ' uniquely mark this instance of Excel
        App.Caption = System.Guid.NewGuid.ToString.ToUpper
        Return App
    End Function

The above code listing includes everything that is required to make an instance of the Excel Application in VB.NET.
If you need to instantiate a particular version of Excel, see “Achieving Backward Compatibility with .NET Interop: Excel as Case Study” first.

Depending on your platform, there may be additional steps required to get Excel running. One of the most common issues that will come up in an ASP.NET environment is listed below, along with the solution steps.

Common Error:

The single most common issue encountered when instantiating an automation object on the server in an ASP.NET environment looks something like this:

BEGIN
ERROR on Excel open [System.UnauthorizedAccessException]: Access is denied.
... DONE!

System Application Event Log reports:
Event Type: Error
Event Source: DCOM
Event Category: None
Event ID: 10016
User: MACHINENAME\ASPNET
Computer: MACHINENAME
Description:
The machine-default permission settings do not grant Local Activation permission for the COM Server application with CLSID {00024500-0000-0000-C000-000000000046} to the user MACHINENAME\ASPNET SID (S-1-5-21-##########-##########-#########-####). This security permission can be modified using the Component Services administrative tool.

Solution:

  1. Open “COM Config.” from mmc console (Control Panel | Administrative Tools | Component Services). For Windows 2000, run comcnfg from a command line.
  2. Find "Microsoft Excel Application" {00024500-0000-0000-C000-000000000046}
  3. Right-click and select Properties | Security tab
  4. Under "Launch and Activation Permissions", select "Customize" and click "Edit" button
  5. Add ASPNET Machine Account and allow "Local Launch" and "Local Activation"

2. The MAIN Sub

The following code listing shows what a simple Main() routine would look like for a console application that (a) creates an Excel automation object, (b) calls a couple procedures on it, and then (c) closes. If you are writing in ASP.NET, you can do something similar in the Page_Load method [please understand that this goes into your server code and thus will launch Excel on the server]. Note that the implementation of the CloseExcel() method will comprise the remainder of this article.

    Sub Main()
        Dim myExcel As Microsoft.Office.Interop.Excel.ApplicationClass
        Dim sh As Microsoft.Office.Interop.Excel.Worksheet
        myExcel = OpenExcel(True)
        sh = myExcel.Workbooks.Add().ActiveSheet
        sh.Range("A1:A1").Value = "Hello World"
        Console.WriteLine("... hit ENTER to close:")
        Console.ReadLine()
        CloseExcel(myExcel, True)
        Console.WriteLine("... hit ENTER to exit:")
        Console.ReadLine()
    End Sub
Comments    Submit Comment

Comment #1  (Posted by an unknown user on 06/15/2006)
Rating
This is an issue we have been trying to address at work with little success. This article provides both ways to accomplish the task as well as good explinations of how the different approaches work. Excellent article.
 
Comment #2  (Posted by an unknown user on 06/16/2006)
Rating
complete description including example.
 
Comment #3  (Posted by an unknown user on 06/29/2006)
Rating
It gives me a starting point for the automation of external apps from .Net and obviously closure and forced closure
 
Comment #4  (Posted by an unknown user on 07/11/2006)
Rating
I have been searching for ages how to control + kill excel. This article is great. Full detail explanation.
 
Comment #5  (Posted by an unknown user on 07/11/2006)
Rating
Really good job this text
 
Comment #6  (Posted by an unknown user on 07/18/2006)
Rating
sweet.
 
Comment #7  (Posted by Phil Mchenry on 07/21/2006)
Rating
Excellent article, we have spent awhile trying to solve this problem and now we have.
There was an error in the code snippet
proc = System.Diagnostics.Process.GetProcessById(ProcessID) should be
proc = System.Diagnostics.Process.GetProcessById(iProcID)
 
Comment #8  (Posted by an unknown user on 07/21/2006)
Rating
This article is excellent. Thank you very much for this great work... articles, forums and blogs are always a better reference than official documentation.

But where it says: "proc = System.Diagnostics.Process.GetProcessById(ProcessID)" Should be "proc = System.Diagnostics.Process.GetProcessById(iProcID)".
Isn't it?
 
Comment #9  (Posted by an unknown user on 07/29/2006)
Rating
Step by step instruction as to what
AND
explanation as to WHY!
 
Comment #10  (Posted by an unknown user on 09/12/2006)
Rating
Good article, but comment #8 is right, I think. It should be iProcID, not ProcessID.

This should be corrected, or else someone might read the article without checking out the comments.
 
Comment #11  (Posted by an unknown user on 09/20/2006)
Rating
that was my problem and you just solved it 10x
 
Comment #12  (Posted by an unknown user on 10/09/2006)
Rating
Congratulations...
This is a very good trick.
 
Comment #13  (Posted by an unknown user on 10/10/2006)
Rating
Okay i've been trying to solve this problem for months now but wasn't successful until i read this article. Killing a specific Process is the way to go (in my case). Great Explanation at all (though i've read similiar stuff over and over again - but there was one difference: the other solutions did not solve MY problem ;). Thank you!
 
Comment #14  (Posted by an unknown user on 10/16/2006)
Rating
I was looking for an article like this for ages... great job!
 
Comment #15  (Posted by an unknown user on 10/25/2006)
Rating
I just love your article. It's a good and great one
 
Comment #16  (Posted by an unknown user on 10/31/2006)
Rating
finally a way to kill excel, I needed the force-kill
 
Comment #17  (Posted by Hutch on 11/07/2006)
Rating
Excellent article, thanks!!!
 
Comment #18  (Posted by an unknown user on 11/21/2006)
Rating
I also have been searching for ages for a way to control + kill excel. This article is great; a fully detailed explanation w/code. Sweet!

 
Comment #19  (Posted by an unknown user on 11/22/2006)
Rating
It works!
 
Comment #20  (Posted by an unknown user on 11/30/2006)
Rating
It works.
 
Comment #21  (Posted by an unknown user on 12/02/2006)
Rating
Thank you very much! I almost went crazy trying to find a solution for this problem!
 
Comment #22  (Posted by an unknown user on 12/15/2006)
Rating
Arguably one of the best explained coding articles I have ever read. Not that is that much different, but I was able to easily convert to C# and I do not know VB at all. Finally the automation program here at work will once again be stable. Ever since I added the ability to run Excel macros there have been some strange issues. Thanks!!!
 
Comment #23  (Posted by Riccardo on 02/05/2007)
Rating
Tanks a lot for this great article it solves my problems but i had to change this line:

VB:
iHandle = New IntPtr(CType(App.Parent.Hwnd, Integer))
C# (My project):
_excelHandle = new IntPtr(App.Parent.Hwnd);

with this:
VB:
iHandle = New IntPtr(CType(App.Hwnd, Integer))
C#:
_excelHandle = new IntPtr(excelApp.Hwnd);

Now EndTask works fine and no more excel.exe in my server!!

Tanks again...



 
Comment #24  (Posted by an unknown user on 02/07/2007)
Rating
Very good article, very useful!
 
Comment #25  (Posted by Waseem Ishaq on 03/05/2007)
Rating
Excellent Article.
Scott I have one problem, would apreciate your help. The code to kill the excel process works fine on my dev environment (on my laptop with VS 2005 - I have administrative rights on my mchine), but when I deploy the site on my network server it runs under ASPNEt user account and I get the following access denied error. If i use a local user on the server and make it member of administrator group it works but our internal poicies prevent me to use administrator impersonation Any suggestions would be greatly appreciated. thanks in advance.

Server Error in '/CPR' Application.
--------------------------------------------------------------------------------

Access is denied
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.ComponentModel.Win32Exception: Access is denied

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace:


[Win32Exception (0x80004005): Access is denied]
System.Diagnostics.ProcessManager.OpenProcess(Int32 processId, Int32 access, Boolean throwIfExited) +662544
System.Diagnostics.Process.GetProcessHandle(Int32 access, Boolean throwIfExited) +376
System.Diagnostics.Process.get_HasExited() +74
reports_pmo.Page_Load(Object sender, EventArgs e) +201
System.Web.UI.Control.OnLoad(EventArgs e) +99
System.Web.UI.Control.LoadRecursive() +47
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1061




 
Comment #26  (Posted by [the author] on 03/05/2007)
Rating
Waseem, this looks very similar to the situation I discussed on page 2 of the article. Check the Event log for the event I described and follow the instructions for granting specific access to ASPNET user instead of general access.
 
Comment #27  (Posted by an unknown user on 03/15/2007)
Rating
Does Excel.Application have a Hwnd property in Excel 2000? I am 99% there, but my excel object does not have a Hwnd property, nor does object.Parent.Hwnd. Am I out of luck using Excel 2000?
 
Comment #28  (Posted by [the author] on 03/16/2007)
Rating
RE: Comment #27. No, Excel 2000 is version 9. Hence, I check for Excel version >10 before accessing this property. However the code will still work for you--FindWindow() will be called later on to get this value.
 
Comment #29  (Posted by an unknown user on 03/26/2007)
Rating
Excellent article,

Thanks!


 
Comment #30  (Posted by Steve Martin on 04/30/2007)
Rating
I was getting the same "Access is denied" error and it appears to be because I have set it up to run under another user in DCOMCNFG. I changed my code to impersonate the user specified in the Identity tab in DCOMCNFG. When I do this, it succeeds.

I have also seen that turning on the Debug permission in the Local Security Settings could help but that it is not by default adopted. (I have confirmed that just granting the permission is not sufficient) That the application has to explicitly take it on. I have not tried this. while there as a C++ non-.Net example, I did not try to port this to C#.
 
Comment #31  (Posted by an unknown user on 05/07/2007)
Rating
Great Article...
 
Comment #32  (Posted by an unknown user on 05/09/2007)
Rating
This has saved me alot of work. Thanks so much !
 
Comment #33  (Posted by sagar on 05/20/2007)
Rating
Hey, this article is very good.
I have one problem. Please help me for this.
I have asp.net website on my machine and I done the required changes about 'Acess Denied problem'. but when I run that page on the other machine, this code doesnt works. Is anything I am missing. Please help me for that,

 
Comment #34  (Posted by an unknown user on 05/22/2007)
Rating
Great article, exactly what i need! ??????? ??????!
 
Comment #35  (Posted by Martin Braaksma on 05/22/2007)
Rating
The instance of Excel launched by your application can also be killed with the Process class. No need for the API.

Private proc As System.Diagnostics.Process
Private procID As Integer

ExcelApp = New Excel.Application

'Get the process ID of this instance
Dim procArray As New ArrayList
For Each proc In System.Diagnostics.Process.GetProcessesByName("EXCEL")
procArray.Add(proc.Id)
Next
procArray.TrimToSize()
procArray.Sort()
procArray.Reverse()
procID = procArray.Item(0)
proc = System.Diagnostics.Process.GetProcessById(procID)
proc.Kill()
'GC.Collect()
'GC.WaitForPendingFinalizers()


 
Comment #36  (Posted by an unknown user on 05/24/2007)
Rating
YYYYYYYYYYYEEEEEEEEEEEEAAAAAAAAAAAAHHHHHHHHHHHHH!!!!!!!!!!
 
Comment #37  (Posted by an unknown user on 05/25/2007)
Rating
It's Really Great
-Hemang
 
Comment #38  (Posted by Bill Linker on 06/14/2007)
Rating
My solution was very similar to the one suggested by Martin Braaksma in Comment #36. However, I do not assume that the new proc ID will be higher than the pre-existing Excel proc ID's (it is not necessarily higher).

Just before I create the new Excel proc, I load all existing Excel proc ID's into an ArrayList:

C#:
ArrayList listExcelProcIDs = new ArrayList();
foreach (System.Diagnostics.Process proc in System.Diagnostics.Process.GetProcessesByName("EXCEL"))
{
listExcelProcIDs.Add(proc.Id);
}


When I am done with Excel (only takes a few seconds for me since I load the data into some arrays), I kill any Excel proc ID's that were not on the initial list:

foreach(System.Diagnostics.Process proc in System.Diagnostics.Process.GetProcessesByName("EXCEL"))
{
if(!listExcelProcIDs.Contains(proc.Id))
proc.Kill();
}

In my case, I can safely assume that no other instances will be created in the meantime. If you cannot (multiple threads for example, or need Excel for a longer period of time), you can use a synchronized function/object to create your Excel instances to restrict access to one thread at a time.

1. Build list of current proc ID's.2. Create new Excel proc
3. Determine new Excel instance's proc ID by comparison against list in step 1
4. Return / save this proc ID so your app can kill the appropriate proc ID when finished as done by Martin Braaksma in this section of his code:

"proc = System.Diagnostics.Process.GetProcessById(procID)
proc.Kill()"
 
Comment #39  (Posted by an unknown user on 06/15/2007)
Rating
I must be a complete dumbass because I cannot get this to work. I have another problem though.
The information that I export needs to be viewed so I can't close the application, else the user cannot see the information that was just exported.

So I finally figured out a way to do this.
Firstly I Find the PID of the session that I just created.

Dim Proc As System.Diagnostics.Process
For Each Proc In System.Diagnostics.Process.GetProcessesByName("EXCEL")
strAppID = Proc.Id
Next

After All the excel code I Save the file
dim strpath as string = "C:\Test.xls"
xlWk.SaveAs(strPath)

And then I kill it

With System.Diagnostics.Process.GetProcessById(strAppID)
.Kill()
End With
This also only kills the session that you have created herein as I dim my Application as follows
dim Xlapp as new Excel.Application

Then Since I need to open this again i use a Shell CommandShell("C:\Program Files\Microsoft Office\Office\Excel.exe C:\Progra~1\FrigaS~1\" & strTempNo & ".xls")
This saves, closes and opens the file so quickly you can hardly see it. Plus It removes excel from the processes. When it reopens it and the user closes it it closes it in the processes as well.
And that is how I did it.
 
Comment #40  (Posted by Spiage on 06/19/2007)
Rating
to Scott:
Your examples are excellent and fully expand the problem!!!
But I'd decided to create additional dynamically created tool to run "Macros-enabled" and "hard-formated" reports on a client side and to use SpreadsheetML on a server
Possible, I would look close to Excel 2007(serv)

to 40:
>For Each Proc In System.Diagnostics.Process.GetProcessesByName("EXCEL")
>strAppID = Proc.Id
>Next
It is amazing! ;0) I had not ever knew that LAST process from GetProcessesByName was always YOURTH...
Is it HACK??? ;0)
 
Comment #41  (Posted by an unknown user on 06/22/2007)
Rating
This must be Excel's easy-button! Can I buy you a beer?? Seriously...
 
Comment #42  (Posted by Richard Clarke on 06/26/2007)
Rating
Hi
Great article - solved a difficult issue for me. One question - you refer to a procedure called CloseExcel on one page, then don't mention it in subsequent pages. It is not difficult to piece together, but when when you call it, you pass a parameter of 'True'. What is this parameter for?
 
Comment #43  (Posted by an unknown user on 06/26/2007)
Rating
Very good!

Finally the evil empire of Excel has been slain!

Did I mention excel was evil... jump to page 4 everyone!

Many thanks for the code- I wouldn't vote you off the VB.NET island.
 
Comment #44  (Posted by an unknown user on 07/04/2007)
Rating
Awesome article, useful code helped solve the issue :)
 
Comment #45  (Posted by an unknown user on 07/07/2007)
Rating
Just cool, man! One little issue about EndTask function header. Actualy it should look like this:
... EndTask(hWnd, fShutDown, fForce);
I.e. 3 parameters, not one.

 
Comment #46  (Posted by an unknown user on 08/01/2007)
Rating
I wish I'd seen this article 6 months ago! Fantastic!!!
 
Comment #47  (Posted by an unknown user on 08/14/2007)
Rating
Wow! Works like charm! Now I really indulged in this Excel-masacre frenzy ^ ^ Thanks a lot!
 
Comment #48  (Posted by an unknown user on 08/23/2007)
Rating
thanks alot man this solved my problem.
 
Comment #49  (Posted by bushfoot on 08/24/2007)
Rating
This was an excellent article and I was very happy with it.. .until... when I run from a service the window handle is always 0 and therefore I end up killing valid instances of excel... Any thoughts on this?
 
Comment #50  (Posted by an unknown user on 09/05/2007)
Rating
Great article, it saved me from a lot of head aches.
 
Comment #51  (Posted by Kat on 09/05/2007)
Rating
I have tried this on 3 different servers now and EXCEL.EXE just won't go away. I have even put the KillallExcel in there. Nada. I also get several errors in the Event log for the MsiInstaller. Several "can not connect to server and then this:

Detection of product '{00010409-78E1-11D2-B60F-006097C998E7}', feature 'ExcelUserData', component '{8ADD2C96-C8B7-11D1-9C67-0000F81F1B38}' failed. The resource 'HKEY_CURRENT_USER\Software\Microsoft\Office\10.0\Excel\UserData' does not exist.

I went in and created that reg key still nothing, any ideas?
 
Comment #52  (Posted by an unknown user on 09/11/2007)
Rating
Thank you for publishing this.
It's informative, concise and has helped us out no end.
 
Comment #53  (Posted by an unknown user on 09/11/2007)
Rating
Thank you for publishing this.
It's informative, concise and has helped us out no end.
 
Comment #54  (Posted by an unknown user on 09/19/2007)
Rating
Thank you very much. You have helped a lot and closed this question for ever.
 
Comment #55  (Posted by an unknown user on 09/24/2007)
Rating
Though I found similar content in diff articles, this one gives complete and clear description
 
Comment #56  (Posted by an unknown user on 11/07/2007)
Rating
I quite literally spent days trying to work out why when I exported data to excel I could not no matter what, remove the instance of excel form the task manager…I tried every know method in every possible combination I could find on Google and ideas on these forums but it would not die

I didn’t want to use the known kill all excel instances loop as although an easy fix isn’t very user friendly as if the user has an instance of excel open, that will be close too and they probably wont like that too much…so I managed to come up with this solution which I hope or believe will finally solve the problem but has one perk to make it different

The code boasts that you can export data to excel…dispose of the excel instance in the task manager …BUT THEN ….opens the file for the user to view… with the difference being, when the user now closes the file, the instance of excel is removed from the tack manager unlike if when closing an instance of excel created though automation which will stay in the task manager

Vb.net 2005

Code Code:
Public Sub CreatExcel()
Dim priorSum As Integer = 0
Dim newSum As Integer = 0
Dim xlProcID As Integer = 0
For Each proc As Process In Process.GetProcessesByName("excel")
priorSum += proc.Id
Next proc
Dim excelApp As Object = Nothing
Dim excelBook As Object = Nothing
Dim excelWorksheet As Object = Nothing
Try
excelApp = New Application
excelBook = excelApp.Workbooks.Add
excelWorksheet = CType(excelBook.Worksheets(1), Worksheet)
excelApp.Visible = False
For Each proc As Process In Process.GetProcessesByName("excel")
newSum += proc.Id
Next proc
xlProcID = newSum - priorSum
With excelWorksheet
' Add/export some data to excel
' Handy hint
' This code will apply border ALL the way around a group of cells 'x,x' i.e. 'A1:A5'
.Range(x, x).Borders(XlBordersIndex.xlEdgeLeft).LineStyle = XlLineStyle.xlContinuous
.Range(x, x).Borders(XlBordersIndex.xlEdgeLeft).Weight = XlBorderWeight.xlThin
.Range(x, x).Borders(XlBordersIndex.xlEdgeLeft).ColorIndex = XlColorIndex.xlColorIndexAutomatic
.Range(x, x).Borders(XlBordersIndex.xlEdgeRight).LineStyle = XlLineStyle.xlContinuous
.Range(x, x).Borders(XlBordersIndex.xlEdgeRight).Weight = XlBorderWeight.xlThin
.Range(x, x).Borders(XlBordersIndex.xlEdgeRight).ColorIndex = XlColorIndex.xlColorIndexAutomatic
.Range(x, x).Borders(XlBordersIndex.xlEdgeTop).LineStyle = XlLineStyle.xlContinuous
.Range(x, x).Borders(XlBordersIndex.xlEdgeTop).Weight = XlBorderWeight.xlThin
.Range(x, x).Borders(XlBordersIndex.xlEdgeTop).ColorIndex = XlColorIndex.xlColorIndexAutomatic
.Range(x, x).Borders(XlBordersIndex.xlEdgeBottom).LineStyle = XlLineStyle.xlContinuous
.Range(x, x).Borders(XlBordersIndex.xlEdgeBottom).Weight = XlBorderWeight.xlThin
.Range(x, x).Borders(XlBordersIndex.xlEdgeBottom).ColorIndex = XlColorIndex.xlColorIndexAutomatic
.Range(x, x).Borders(XlBordersIndex.xlInsideHorizontal).LineStyle = XlLineStyle.xlContinuous
.Range(x, x).Borders(XlBordersIndex.xlInsideHorizontal).Weight = XlBorderWeight.xlThin
.Range(x, x).Borders(XlBordersIndex.xlInsideHorizontal).ColorIndex = XlColorIndex.xlColorIndexAutomatic

End With


' Hany hint you can remove grid lines and name your sheets like so
With excelApp
.ActiveWindow.DisplayGridlines = False
.ActiveSheet.name = "My Export"
End With


' Edit as required:
excelApp.ActiveWorkbook.SaveAs("My File Location Path\My File Name.xls")

' You must save the file here are some ideas for saving the file so as not to
' have any issues with existing files that you previously exported that may have
' the same file name as your new exported file which of cause would throw errors


'Method 1 Unqueek File name when saving :=
'You don’t have to use this but this is just my way of ensuring file names is never
'the same as an old version export
'###############
Dim PublishDate As Date
PublishDate = Now()
Dim FormattedDateAsString As String
FormattedDateAsString = Format(PublishDate, "F") & " " & Format(PublishDate, "(h:mtt)")
Dim FixString As String = FormattedDateAsString
Dim GetDate As Date = Format(PublishDate, "d")
Dim TestString As String = GetDate.Day.ToString
If TestString.EndsWith("1") And TestString <> "11" Then
FormattedDateAsString = FixString.Insert(FixString.IndexOf(TestString) + 2, "st ")
ElseIf TestString.EndsWith("3") And TestString <> "13" Then
FormattedDateAsString = FixString.Insert(FixString.IndexOf(TestString) + 2, "rd ") 'FixString.Replace(TestString, (TestString & "rd"))
Else
FormattedDateAsString = FixString.Insert(FixString.IndexOf(TestString) + 2, "th ")
End If
TestString = GetDate.Year.ToString
FormattedDateAsString = FormattedDateAsString.Replace(TestString, (TestString & " at"))
FormattedDateAsString = FormattedDateAsString.Replace(":", ".")
' Save the file
excelApp.ActiveWorkbook.SaveAs("C:\My Report Created on - " & FormattedDateAsString & ".xls")
'###############



'Method 2 remove old file :=
'You could also delete and replace old file if you rather
'#############################
If File.Exists("C:\My Report.xls") Then
File.Delete("C:\My Report.xls")
End If
'#############################


' You don’t have to have this but I do to be sure everything is saved
For Each w In excelApp.Application.Workbooks
'save all the work sheets
w.Save()
Next w
' close the work sheets with out prompting...may not need this either
excelApp.ActiveWorkbook.Close(SaveChanges:=False)


'Now kill excel but only the excel instance we created and NOT any other excel applications running at the same time
If Not excelApp Is Nothing Then
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
GC.WaitForPendingFinalizers()
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(excelWorksheet)
excelWorksheet = Nothing
If Not excelBook Is Nothing Then
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(excelBook)
End If
excelApp.Quit()
excelBook = Nothing
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(excelApp)
excelApp = Nothing
Dim proc As Process = Process.GetProcessById(xlProcID)
proc.Kill()
End If

' Now if you want you can open the excel file view. The advantage of this code is that
' when the user closes the excel it wont get stuck in the system task manager
Dim p As New System.Diagnostics.Process

' Set this to the file location and file name of ythe excel you just exported
' Example: "My File Location Path\My File Name.xls" or "C:\My Report.xls" or "C:\My Report Created on - " & FormattedDateAsString & ".xls"
' Edit as required:
p.StartInfo.FileName = "C:\My Report Created on - " & FormattedDateAsString & ".xls"
p.StartInfo.WindowStyle = ProcessWindowStyle.Minimized
p.Start()

'Wait until the process passes back an exit code add if you want but your application
'wont run untill the user closes the excel down
'p.WaitForExit()

' Free the recources ...may not need this line as will work with out but added to be save
' Remove if you add the line above 'WaitForExit()'
p = Nothing

'Free resources associated with this process
' add this if you add the line above 'WaitForExit()'
' p.Close()


Catch ex As Exception
MsgBox(ex.Message & vbTab & ex.Source & vbTab & ex.HelpLink)
End Try
End Sub

:end code

All comments welcome

 
Comment #57  (Posted by an unknown user on 11/07/2007)
Rating
I quite literally spent days trying to work out why when I exported data to excel I could not no matter what, remove the instance of excel form the task manager…I tried every know method in every possible combination I could find on Google and ideas on these forums but it would not die

I didn’t want to use the known kill all excel instances loop as although an easy fix isn’t very user friendly as if the user has an instance of excel open, that will be close too and they probably wont like that too much…so I managed to come up with this solution which I hope or believe will finally solve the problem but has one perk to make it different

The code boasts that you can export data to excel…dispose of the excel instance in the task manager …BUT THEN ….opens the file for the user to view… with the difference being, when the user now closes the file, the instance of excel is removed from the tack manager unlike if when closing an instance of excel created though automation which will stay in the task manager

Vb.net 2005

Code Code:
Public Sub CreatExcel()
Dim priorSum As Integer = 0
Dim newSum As Integer = 0
Dim xlProcID As Integer = 0
For Each proc As Process In Process.GetProcessesByName("excel")
priorSum += proc.Id
Next proc
Dim excelApp As Object = Nothing
Dim excelBook As Object = Nothing
Dim excelWorksheet As Object = Nothing
Try
excelApp = New Application
excelBook = excelApp.Workbooks.Add
excelWorksheet = CType(excelBook.Worksheets(1), Worksheet)
excelApp.Visible = False
For Each proc As Process In Process.GetProcessesByName("excel")
newSum += proc.Id
Next proc
xlProcID = newSum - priorSum
With excelWorksheet
' Add/export some data to excel
' Handy hint
' This code will apply border ALL the way around a group of cells 'x,x' i.e. 'A1:A5'
.Range(x, x).Borders(XlBordersIndex.xlEdgeLeft).LineStyle = XlLineStyle.xlContinuous
.Range(x, x).Borders(XlBordersIndex.xlEdgeLeft).Weight = XlBorderWeight.xlThin
.Range(x, x).Borders(XlBordersIndex.xlEdgeLeft).ColorIndex = XlColorIndex.xlColorIndexAutomatic
.Range(x, x).Borders(XlBordersIndex.xlEdgeRight).LineStyle = XlLineStyle.xlContinuous
.Range(x, x).Borders(XlBordersIndex.xlEdgeRight).Weight = XlBorderWeight.xlThin
.Range(x, x).Borders(XlBordersIndex.xlEdgeRight).ColorIndex = XlColorIndex.xlColorIndexAutomatic
.Range(x, x).Borders(XlBordersIndex.xlEdgeTop).LineStyle = XlLineStyle.xlContinuous
.Range(x, x).Borders(XlBordersIndex.xlEdgeTop).Weight = XlBorderWeight.xlThin
.Range(x, x).Borders(XlBordersIndex.xlEdgeTop).ColorIndex = XlColorIndex.xlColorIndexAutomatic
.Range(x, x).Borders(XlBordersIndex.xlEdgeBottom).LineStyle = XlLineStyle.xlContinuous
.Range(x, x).Borders(XlBordersIndex.xlEdgeBottom).Weight = XlBorderWeight.xlThin
.Range(x, x).Borders(XlBordersIndex.xlEdgeBottom).ColorIndex = XlColorIndex.xlColorIndexAutomatic
.Range(x, x).Borders(XlBordersIndex.xlInsideHorizontal).LineStyle = XlLineStyle.xlContinuous
.Range(x, x).Borders(XlBordersIndex.xlInsideHorizontal).Weight = XlBorderWeight.xlThin
.Range(x, x).Borders(XlBordersIndex.xlInsideHorizontal).ColorIndex = XlColorIndex.xlColorIndexAutomatic

End With


' Hany hint you can remove grid lines and name your sheets like so
With excelApp
.ActiveWindow.DisplayGridlines = False
.ActiveSheet.name = "My Export"
End With


' Edit as required:
excelApp.ActiveWorkbook.SaveAs("My File Location Path\My File Name.xls")

' You must save the file here are some ideas for saving the file so as not to
' have any issues with existing files that you previously exported that may have
' the same file name as your new exported file which of cause would throw errors


'Method 1 Unqueek File name when saving :=
'You don’t have to use this but this is just my way of ensuring file names is never
'the same as an old version export
'###############
Dim PublishDate As Date
PublishDate = Now()
Dim FormattedDateAsString As String
FormattedDateAsString = Format(PublishDate, "F") & " " & Format(PublishDate, "(h:mtt)")
Dim FixString As String = FormattedDateAsString
Dim GetDate As Date = Format(PublishDate, "d")
Dim TestString As String = GetDate.Day.ToString
If TestString.EndsWith("1") And TestString <> "11" Then
FormattedDateAsString = FixString.Insert(FixString.IndexOf(TestString) + 2, "st ")
ElseIf TestString.EndsWith("3") And TestString <> "13" Then
FormattedDateAsString = FixString.Insert(FixString.IndexOf(TestString) + 2, "rd ") 'FixString.Replace(TestString, (TestString & "rd"))
Else
FormattedDateAsString = FixString.Insert(FixString.IndexOf(TestString) + 2, "th ")
End If
TestString = GetDate.Year.ToString
FormattedDateAsString = FormattedDateAsString.Replace(TestString, (TestString & " at"))
FormattedDateAsString = FormattedDateAsString.Replace(":", ".")
' Save the file
excelApp.ActiveWorkbook.SaveAs("C:\My Report Created on - " & FormattedDateAsString & ".xls")
'###############



'Method 2 remove old file :=
'You could also delete and replace old file if you rather
'#############################
If File.Exists("C:\My Report.xls") Then
File.Delete("C:\My Report.xls")
End If
'#############################


' You don’t have to have this but I do to be sure everything is saved
For Each w In excelApp.Application.Workbooks
'save all the work sheets
w.Save()
Next w
' close the work sheets with out prompting...may not need this either
excelApp.ActiveWorkbook.Close(SaveChanges:=False)


'Now kill excel but only the excel instance we created and NOT any other excel applications running at the same time
If Not excelApp Is Nothing Then
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
GC.WaitForPendingFinalizers()
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(excelWorksheet)
excelWorksheet = Nothing
If Not excelBook Is Nothing Then
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(excelBook)
End If
excelApp.Quit()
excelBook = Nothing
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(excelApp)
excelApp = Nothing
Dim proc As Process = Process.GetProcessById(xlProcID)
proc.Kill()
End If

' Now if you want you can open the excel file view. The advantage of this code is that
' when the user closes the excel it wont get stuck in the system task manager
Dim p As New System.Diagnostics.Process

' Set this to the file location and file name of ythe excel you just exported
' Example: "My File Location Path\My File Name.xls" or "C:\My Report.xls" or "C:\My Report Created on - " & FormattedDateAsString & ".xls"
' Edit as required:
p.StartInfo.FileName = "C:\My Report Created on - " & FormattedDateAsString & ".xls"
p.StartInfo.WindowStyle = ProcessWindowStyle.Minimized
p.Start()

'Wait until the process passes back an exit code add if you want but your application
'wont run untill the user closes the excel down
'p.WaitForExit()

' Free the recources ...may not need this line as will work with out but added to be save
' Remove if you add the line above 'WaitForExit()'
p = Nothing

'Free resources associated with this process
' add this if you add the line above 'WaitForExit()'
' p.Close()


Catch ex As Exception
MsgBox(ex.Message & vbTab & ex.Source & vbTab & ex.HelpLink)
End Try
End Sub

:end code

All comments welcome

 
Comment #58  (Posted by Rabid Lemming on 11/07/2007)
Rating
I quite literally spent days trying to work out why when I exported data to excel I could not no matter what, remove the instance of excel form the task manager…I tried every know method in every possible combination I could find on Google and ideas on these forums but it would not die

I didn’t want to use the known kill all excel instances loop as although an easy fix isn’t very user friendly as if the user has an instance of excel open, that will be close too and they probably wont like that too much…so I managed to come up with this solution which I hope or believe will finally solve the problem but has one perk to make it different

The code boasts that you can export data to excel…dispose of the excel instance in the task manager …BUT THEN ….opens the file for the user to view… with the difference being, when the user now closes the file, the instance of excel is removed from the tack manager unlike if when closing an instance of excel created though automation which will stay in the task manager

Vb.net 2005

Code Code:
Public Sub CreatExcel()
Dim priorSum As Integer = 0
Dim newSum As Integer = 0
Dim xlProcID As Integer = 0
For Each proc As Process In Process.GetProcessesByName("excel")
priorSum += proc.Id
Next proc
Dim excelApp As Object = Nothing
Dim excelBook As Object = Nothing
Dim excelWorksheet As Object = Nothing
Try
excelApp = New Application
excelBook = excelApp.Workbooks.Add
excelWorksheet = CType(excelBook.Worksheets(1), Worksheet)
excelApp.Visible = False
For Each proc As Process In Process.GetProcessesByName("excel")
newSum += proc.Id
Next proc
xlProcID = newSum - priorSum
With excelWorksheet
' Add/export some data to excel
' Handy hint
' This code will apply border ALL the way around a group of cells 'x,x' i.e. 'A1:A5'
.Range(x, x).Borders(XlBordersIndex.xlEdgeLeft).LineStyle = XlLineStyle.xlContinuous
.Range(x, x).Borders(XlBordersIndex.xlEdgeLeft).Weight = XlBorderWeight.xlThin
.Range(x, x).Borders(XlBordersIndex.xlEdgeLeft).ColorIndex = XlColorIndex.xlColorIndexAutomatic
.Range(x, x).Borders(XlBordersIndex.xlEdgeRight).LineStyle = XlLineStyle.xlContinuous
.Range(x, x).Borders(XlBordersIndex.xlEdgeRight).Weight = XlBorderWeight.xlThin
.Range(x, x).Borders(XlBordersIndex.xlEdgeRight).ColorIndex = XlColorIndex.xlColorIndexAutomatic
.Range(x, x).Borders(XlBordersIndex.xlEdgeTop).LineStyle = XlLineStyle.xlContinuous
.Range(x, x).Borders(XlBordersIndex.xlEdgeTop).Weight = XlBorderWeight.xlThin
.Range(x, x).Borders(XlBordersIndex.xlEdgeTop).ColorIndex = XlColorIndex.xlColorIndexAutomatic
.Range(x, x).Borders(XlBordersIndex.xlEdgeBottom).LineStyle = XlLineStyle.xlContinuous
.Range(x, x).Borders(XlBordersIndex.xlEdgeBottom).Weight = XlBorderWeight.xlThin
.Range(x, x).Borders(XlBordersIndex.xlEdgeBottom).ColorIndex = XlColorIndex.xlColorIndexAutomatic
.Range(x, x).Borders(XlBordersIndex.xlInsideHorizontal).LineStyle = XlLineStyle.xlContinuous
.Range(x, x).Borders(XlBordersIndex.xlInsideHorizontal).Weight = XlBorderWeight.xlThin
.Range(x, x).Borders(XlBordersIndex.xlInsideHorizontal).ColorIndex = XlColorIndex.xlColorIndexAutomatic

End With


' Hany hint you can remove grid lines and name your sheets like so
With excelApp
.ActiveWindow.DisplayGridlines = False
.ActiveSheet.name = "My Export"
End With


' Edit as required:
excelApp.ActiveWorkbook.SaveAs("My File Location Path\My File Name.xls")

' You must save the file here are some ideas for saving the file so as not to
' have any issues with existing files that you previously exported that may have
' the same file name as your new exported file which of cause would throw errors


'Method 1 Unqueek File name when saving :=
'You don’t have to use this but this is just my way of ensuring file names is never
'the same as an old version export
'###############
Dim PublishDate As Date
PublishDate = Now()
Dim FormattedDateAsString As String
FormattedDateAsString = Format(PublishDate, "F") & " " & Format(PublishDate, "(h:mtt)")
Dim FixString As String = FormattedDateAsString
Dim GetDate As Date = Format(PublishDate, "d")
Dim TestString As String = GetDate.Day.ToString
If TestString.EndsWith("1") And TestString <> "11" Then
FormattedDateAsString = FixString.Insert(FixString.IndexOf(TestString) + 2, "st ")
ElseIf TestString.EndsWith("3") And TestString <> "13" Then
FormattedDateAsString = FixString.Insert(FixString.IndexOf(TestString) + 2, "rd ") 'FixString.Replace(TestString, (TestString & "rd"))
Else
FormattedDateAsString = FixString.Insert(FixString.IndexOf(TestString) + 2, "th ")
End If
TestString = GetDate.Year.ToString
FormattedDateAsString = FormattedDateAsString.Replace(TestString, (TestString & " at"))
FormattedDateAsString = FormattedDateAsString.Replace(":", ".")
' Save the file
excelApp.ActiveWorkbook.SaveAs("C:\My Report Created on - " & FormattedDateAsString & ".xls")
'###############



'Method 2 remove old file :=
'You could also delete and replace old file if you rather
'#############################
If File.Exists("C:\My Report.xls") Then
File.Delete("C:\My Report.xls")
End If
'#############################


' You don’t have to have this but I do to be sure everything is saved
For Each w In excelApp.Application.Workbooks
'save all the work sheets
w.Save()
Next w
' close the work sheets with out prompting...may not need this either
excelApp.ActiveWorkbook.Close(SaveChanges:=False)


'Now kill excel but only the excel instance we created and NOT any other excel applications running at the same time
If Not excelApp Is Nothing Then
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
GC.WaitForPendingFinalizers()
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(excelWorksheet)
excelWorksheet = Nothing
If Not excelBook Is Nothing Then
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(excelBook)
End If
excelApp.Quit()
excelBook = Nothing
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(excelApp)
excelApp = Nothing
Dim proc As Process = Process.GetProcessById(xlProcID)
proc.Kill()
End If

' Now if you want you can open the excel file view. The advantage of this code is that
' when the user closes the excel it wont get stuck in the system task manager
Dim p As New System.Diagnostics.Process

' Set this to the file location and file name of ythe excel you just exported
' Example: "My File Location Path\My File Name.xls" or "C:\My Report.xls" or "C:\My Report Created on - " & FormattedDateAsString & ".xls"
' Edit as required:
p.StartInfo.FileName = "C:\My Report Created on - " & FormattedDateAsString & ".xls"
p.StartInfo.WindowStyle = ProcessWindowStyle.Minimized
p.Start()

'Wait until the process passes back an exit code add if you want but your application
'wont run untill the user closes the excel down
'p.WaitForExit()

' Free the recources ...may not need this line as will work with out but added to be save
' Remove if you add the line above 'WaitForExit()'
p = Nothing

'Free resources associated with this process
' add this if you add the line above 'WaitForExit()'
' p.Close()


Catch ex As Exception
MsgBox(ex.Message & vbTab & ex.Source & vbTab & ex.HelpLink)
End Try
End Sub

:end code

All comments welcome
 
Comment #59  (Posted by an unknown user on 12/19/2007)
Rating
Well I probably have a new problem hopefully someone can assist with.
I am able to successfully remove Excel from the Task manager using the example here. The memory doesn’t go up but after a while I get an error telling me there isn’t enough memory to open Excel. Its strange because in task manager I watch the Excel open and close as desired and memory not go up. But even if I leave the development environment I have to reboot to correct this. My process is creating hundreds of Excel documents.

Also as a note here is a good way to find the PID of the Excel you open so it is easy to close later

When you create your Excel object have this

DataTable tblProcessID = new DataTable();
DataColumn colID = new DataColumn("ID", typeof(int));
tblProcessID.Columns.Add(colID);

foreach (System.Diagnostics.Process proc in System.Diagnostics.Process.GetProcessesByName("EXCEL"))
{
DataRow newRow = tblProcessID.NewRow();
newRow["ID"] = proc.Id;
tblProcessID.Rows.Add(newRow);
}

this.myEApp = new Excel.ApplicationClass();

DataView dvProcessID = new DataView(tblProcessID);


foreach (System.Diagnostics.Process proc in System.Diagnostics.Process.GetProcessesByName("EXCEL"))
{
dvProcessID.RowFilter = "ID = " + proc.Id;

if (dvProcessID.Count == 0)
this.intExcelProcessID = proc.Id;
}

Then when you dispose add this in (Only use the kill all Excel process if you have an issue with the ID)


if (this.intExcelProcessID < 0)
this.KillAllExcelProcesses();
else
{

foreach (System.Diagnostics.Process proc in System.Diagnostics.Process.GetProcessesByName("EXCEL"))
{
if (proc.Id == this.intExcelProcessID)
{
proc.Kill();
break;
}
}
}






 
Comment #60  (Posted by an unknown user on 01/03/2008)
Rating
In Asp.Net(IIS 6), I use "GetWindowThreadProcessId(MainWindowHandle, iProcID)" to get the iProcID , but after this method been called, the value of iProcID is Zero! The newwork service Account HAS NOT Accesse Pemissions?

thanks
 
Comment #61  (Posted by an unknown user on 01/03/2008)
Rating
In Asp.Net(IIS 6), I use "GetWindowThreadProcessId(MainWindowHandle, iProcID)" to get the iProcID , but after this method been called, the value of iProcID is Zero! The newwork service Account HAS NOT Accesse Pemissions?

thanks
 
Comment #62  (Posted by an unknown user on 01/14/2008)
Rating
When I use this article's method of killing Excel, Excel saves document recovery information for the file. I've turned off document recovery in Excel Options (2007) and Excel still saves the file in document recovery mode. As a result, anytime I programatically kill Excel and open Excel for general use, I get the document recovery panel. If I use the kill excel feature a lot, the number of documents to be recovered accumulates. After a while, it completely bogs down Excel so that load time takes forever. Has anyone else seen/had to deal with this problem?
 
Comment #63  (Posted by Sharon on 02/19/2008)
Rating
It is a very helpful article that almost solve my problem. However, I have the same issue with GetWindowThreadProcessId(MainWindowHandle, out iProcID), when iprocID is 0. It has got me almost crazy trying to make it work, as i am so close to success almost! Please help!!!! I added the ASPNET user also, but no difference. Thanks!!
 
Comment #64  (Posted by jjsauma on 03/10/2008)
Rating
This doesn't work in Excel 2007. Does anybody know what is the problem?
 
Comment #65  (Posted by an unknown user on 03/14/2008)
Rating
ok verry nice I'll priciate this artical very much , but happens if we have never open excel file as window and property MainWindowHandle is awlays "0".
 
Comment #66  (Posted by an unknown user on 04/05/2008)
Rating
Sub KillAllExcels() >> works well for me TQ!! Excellent article.
 
Comment #67  (Posted by an unknown user on 05/22/2008)
Rating
The article gave a full detailed explanation. I've looked for ways to kill the Excel process and this one got it
 
Comment #68  (Posted by an unknown user on 06/06/2008)
Rating
Cool!!!!!!!!!!!!!!!!!
 
Comment #69  (Posted by an unknown user on 10/06/2008)
Rating
Yeah... This article is useful as what being said by everyone here. It would be better if it is written is C# though...
 
Comment #70  (Posted by an unknown user on 12/31/2008)
Rating
Excellent Article
 
Comment #71  (Posted by an unknown user on 03/16/2009)
Rating
Very nice. Thank you!
 
Comment #72  (Posted by Ido on 04/16/2009)
Rating
Great article.
i do have a simple question that's been annoying me for a while - if i'm programming this in ASP.NET on server side, how can i make sure only the Excel sheets a certain user openned will close instead of the process for ALL users on the server?
 
Comment #73  (Posted by Stephen Melvin on 05/14/2009)
Rating
I tried this all ways and still could not get it to function. The only absolute way I could get it to work which is this way. It verifies also if the users have exising excel apps open and keeps that process ID until the end.

//creates a list of the existing Excel processes
//before the excel object is created if any

List existingprocList = new List();

foreach (Process existingproc in System.Diagnostics.Process.GetProcessesByName("EXCEL"))
{
existingprocList.Add (existingproc.Id);
}

//creates new microsoft excel application
Microsoft.Office.Interop.Excel.Application exc = new Microsoft.Office.Interop.Excel.Application();

//Method to get the excel applications proc id
int excelsprocessid = GetProgramExcelProcID(existingprocList);


//Heres the method that gets the does the magic
//Gets the difference of the new list and the before
//list and gets your app's process id :)
public int GetProgramExcelProcID(List existingXLSArr)
{
existingXLSArr.Sort();

List newXLSArr = new List();
foreach (Process proc in System.Diagnostics.Process.GetProcessesByName("EXCEL"))
{
newXLSArr.Add(proc.Id);
}

newXLSArr.Sort();

IEnumerable differencequery = newXLSArr.Except(existingXLSArr);

int processid=0;
foreach (int record in differencequery)
{
processid = record;
}


return processid;
}


//Gets the bastard programs excel processid and
//kills it since microsoft interopt can't do it :(

Process p = Process.GetProcessById(excelsprocessid);
p.Kill();



 
Comment #74  (Posted by Sanga on 10/30/2009)
Rating
The C# version :-

[DllImport("user32.dll")]
private static extern int GetWindowThreadProcessId(IntPtr hWnd, out int ProcessId);

[DllImport("user32.dll")]
private static extern IntPtr FindWindow(string lpClassName, String lpWindowName);

[DllImport("user32.dll")]
private static extern int EndTask(IntPtr hWnd);

[DllImport("kernel32.dll")]
private static extern IntPtr SetLastError(int dwErrCode);

public void EnsureProcessKilled(IntPtr MainWindowHandle, string Caption)
{
SetLastError(0);
// for Excel versions <10, this won't be set yet
if (IntPtr.Equals(MainWindowHandle, IntPtr.Zero)) MainWindowHandle = FindWindow(null, Caption);
if (IntPtr.Equals(MainWindowHandle, IntPtr.Zero)) return;

// at this point, presume the window has been closed.
int iRes = 0;
int iProcID = 0;
iRes = GetWindowThreadProcessId(MainWindowHandle, out iProcID);
if (iProcID == 0)
{
// can’t get Process ID
if (EndTask(MainWindowHandle) != 0) return;

// success
throw new ApplicationException("Failed to close.");
}
System.Diagnostics.Process proc = default(System.Diagnostics.Process);
proc = System.Diagnostics.Process.GetProcessById(iProcID);
proc.CloseMainWindow();
proc.Refresh();
if (proc.HasExited) return;

proc.Kill();
}
 
Comment #75  (Posted by rk on 04/16/2010)
Rating
Thanks Sanga for sharing the C# code. That really helped.
 
Comment #76  (Posted by Adinath on 10/12/2010)
Rating
Hi Friends,

Please some one help me out for Excel Application

I am storing more than 200 rows of data into Excel Sheet, while storing the data if I open Any Existing Excel File my excel object(Excel file which is created by .Net Code) is getting visible.

My Question is How to Hide the Excel file which is created by Program.

Its very urgent..........
 
Comment #77  (Posted by Paul Berry on 04/18/2011)
Rating
We were having problems generating an Excel spreadsheet server side. This article explained the issue perfectly. Just what we were looking for.
 
Comment #78  (Posted by Buy oem on 09/27/2011)
Rating
hieERV Yeah? I read and I understand that I do not understand anything what it is about:D
 
Sponsored Links