Orphan excel process started via automation
Orphan excel process started via automation
Orphan excel process started via automation
Orphan excel process started via automation
Orphan excel process started via automation
Orphan excel process started via automation Orphan excel process started via automation Orphan excel process started via automation Orphan excel process started via automation Orphan excel process started via automation Orphan excel process started via automation Orphan excel process started via automation Orphan excel process started via automation
Orphan excel process started via automation Orphan excel process started via automation
Orphan excel process started via automation
Go Back  Xtreme Visual Basic Talk > > > Orphan excel process started via automation


Reply
 
Thread Tools Display Modes
  #21  
Old 06-30-2009, 10:02 AM
Mike Rosenblum's Avatar
Mike Rosenblum Mike Rosenblum is offline
Microsoft Excel MVP

Forum Leader
* Guru *
 
Join Date: Jul 2003
Location: New York, NY, USA
Posts: 7,848
Default


Quote:
Originally Posted by CMF View Post
Code:
                eBook = wb.Open(S_Directory + FileName, 2, false,
                    5, "", "", true, xls.XlPlatform.xlWindows, "",
                    false, false, 0, false, true, 0);
I guess one of these options must be set incorrectly, but from what I recall, none of these are documented very well.
Hmmm... that is interesting.

But this runs clean on one machine and not the other, right? This suggests to me that the code is fine and that it is the environment that it is running on that is not clean in one of your cases.

When you open a workbook like this, anti-virus gets involved, so this is suggestive that it *could* be that. Don't know, but could be.

You could try creating a new workbook instead of opening one, this could be further evidence.

Overall, though, it does sound like it will be difficult to automate on the machine that is causing problems without generating a hang. You might have to resort to the Process.Kill() approach. It sounds ugly, but I haven't found any problems with it in practice.
__________________
My Articles:
| Excel from .NET | Excel RibbonX using VBA | Excel from VB6 | CVErr in .NET | MVP |
Avatar by Lebb
Reply With Quote
  #22  
Old 07-13-2009, 01:56 PM
yoshijg yoshijg is offline
Newcomer
 
Join Date: Jun 2009
Posts: 7
Talking Solution to Killing Excel Process

I have a reliable solution, but it's in C#. I was searching for something to solve this problem, but there was no information out there. And I stumbled on to this forum, which had the most information. Anyway...I want to give, but it's in C#.

.....Ok....

Application.Quit() and Process.Kill() as suggested in previous posts are possible solutions, but have proven to be unreliable. When your main application dies, you are still left with Excel processes running. What we really want is for the Excel process to die as soon as the main application dies.

Well, after much reading...and a co-worker's suggestion. I came upon "job objects" http://msdn.microsoft.com/en-us/libr...09(VS.85).aspx .

The idea is to create a "job object" for your main application. Then configure the job object to kill-process upon close. If the application dies, the OS will take care of cleaning up your processes.

Code:
	public enum JobObjectInfoType
	{
		AssociateCompletionPortInformation = 7,
		BasicLimitInformation = 2,
		BasicUIRestrictions = 4,
		EndOfJobTimeInformation = 6,
		ExtendedLimitInformation = 9,
		SecurityLimitInformation = 5,
		GroupInformation = 11
	}

	[StructLayout(LayoutKind.Sequential)]
	public struct SECURITY_ATTRIBUTES
	{
		public int nLength;
		public IntPtr lpSecurityDescriptor;
		public int bInheritHandle;
	}

	[StructLayout(LayoutKind.Sequential)]
	struct JOBOBJECT_BASIC_LIMIT_INFORMATION
	{
		public Int64 PerProcessUserTimeLimit;
		public Int64 PerJobUserTimeLimit;
		public Int16 LimitFlags;
		public UInt32 MinimumWorkingSetSize;
		public UInt32 MaximumWorkingSetSize;
		public Int16 ActiveProcessLimit;
		public Int64 Affinity;
		public Int16 PriorityClass;
		public Int16 SchedulingClass;
	}

	[StructLayout(LayoutKind.Sequential)]
	struct IO_COUNTERS
	{
		public UInt64 ReadOperationCount;
		public UInt64 WriteOperationCount;
		public UInt64 OtherOperationCount;
		public UInt64 ReadTransferCount;
		public UInt64 WriteTransferCount;
		public UInt64 OtherTransferCount;
	}

	[StructLayout(LayoutKind.Sequential)]
	struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION
	{
		public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
		public IO_COUNTERS IoInfo;
		public UInt32 ProcessMemoryLimit;
		public UInt32 JobMemoryLimit;
		public UInt32 PeakProcessMemoryUsed;
		public UInt32 PeakJobMemoryUsed;
	}

	public class Job : IDisposable
	{
		[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
		static extern IntPtr CreateJobObject(object a, string lpName);

		[DllImport("kernel32.dll")]
		static extern bool SetInformationJobObject(IntPtr hJob, JobObjectInfoType infoType, IntPtr lpJobObjectInfo, uint cbJobObjectInfoLength);

		[DllImport("kernel32.dll", SetLastError = true)]
		static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process);

		private IntPtr m_handle;
		private bool m_disposed = false;

		public Job()
		{
			m_handle = CreateJobObject(null, null);

			JOBOBJECT_BASIC_LIMIT_INFORMATION info = new JOBOBJECT_BASIC_LIMIT_INFORMATION();
			info.LimitFlags = 0x2000;

			JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION();
			extendedInfo.BasicLimitInformation = info;

			int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
			IntPtr extendedInfoPtr = Marshal.AllocHGlobal(length);
			Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false);

			if (!SetInformationJobObject(m_handle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, (uint)length))
				throw new Exception(string.Format("Unable to set information.  Error: {0}", Marshal.GetLastWin32Error()));
		}

		#region IDisposable Members

		public void Dispose()
		{
			Dispose(true);
			GC.SuppressFinalize(this);
		}

		#endregion

		private void Dispose(bool disposing)
		{
			if (m_disposed)
				return;

			if (disposing) {}

			Close();
			m_disposed = true;
		}

		public void Close()
		{
			Win32.CloseHandle(m_handle);
			m_handle = IntPtr.Zero;
		}

		public bool AddProcess(IntPtr handle)
		{
			return AssignProcessToJobObject(m_handle, handle);
		}

	}
Looking at the constructor ...

Code:
JOBOBJECT_BASIC_LIMIT_INFORMATION info = new JOBOBJECT_BASIC_LIMIT_INFORMATION();
info.LimitFlags = 0x2000;
The key here is to setup the job object properly. In the constructor I'm setting the "limits" to 0x2000, which is the numeric value for:

JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE

MSDN defines this flag as:

Quote:
Causes all processes associated with the job to terminate when the last handle to the job is closed.
Once this class is setup...you just have to register Excel process to the job. For example:

Code:
...

[DllImport("user32.dll", SetLastError = true)]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

...


	Excel.Application app = new Excel.ApplicationClass();

	uint pid = 0;
	Win32.GetWindowThreadProcessId(new IntPtr(app.Hwnd), out pid);
	 job.AddProcess(Process.GetProcessById((int)pid).Handle);
Your "Job object" can be a static object, or whatever your desire. Note, we are basically letting the OS take care of our cleanup. So it's pretty much a guarantee that the Excel processes will be cleaned up after the main application process closes or CRASHES!!

- Josh
Reply With Quote
  #23  
Old 07-13-2009, 02:45 PM
Mike Rosenblum's Avatar
Mike Rosenblum Mike Rosenblum is offline
Microsoft Excel MVP

Forum Leader
* Guru *
 
Join Date: Jul 2003
Location: New York, NY, USA
Posts: 7,848
Default

Hey Josh,

That looks VERY cool! Big thanks for sharing.

In theory, by the way, the Excel process *should* shut-down on it's own when the last reference to it terminates, so long as Excel was controlled by Automation the whole time and not touched by the user. See the Application.UserControl property, or this article for more on this. The UserControl property defaults to 'false' so the Application *should* close on its own. This is just theory, however; as we all know, the reality can be something different, especially when called from .NET.

Your 'CreateJobObject' function idea looks very, very promising. But I don't understand how to call it from C#. In your code example, above, what is the data type for your 'job' variable? (In other words, the AddProcess method applies to which type? I can't find it.)

This looks like a great concept Josh. Could you show a more of your code or explain a bit more?

Mike
__________________
My Articles:
| Excel from .NET | Excel RibbonX using VBA | Excel from VB6 | CVErr in .NET | MVP |
Avatar by Lebb

Last edited by Mike Rosenblum; 07-13-2009 at 02:52 PM.
Reply With Quote
  #24  
Old 07-14-2009, 12:22 PM
yoshijg yoshijg is offline
Newcomer
 
Join Date: Jun 2009
Posts: 7
Default

Quote:
Originally Posted by Mike_R View Post
Hmmm... that is interesting.
. You might have to resort to the Process.Kill() approach. It sounds ugly, but I haven't found any problems with it in practice.
Did you look at my post? That successfully cleans up any hanging process when your application dies unexpectedly.
Reply With Quote
  #25  
Old 07-14-2009, 12:47 PM
Mike Rosenblum's Avatar
Mike Rosenblum Mike Rosenblum is offline
Microsoft Excel MVP

Forum Leader
* Guru *
 
Join Date: Jul 2003
Location: New York, NY, USA
Posts: 7,848
Default

Hey Josh,

Yes I did! You are quoting me from my reply to CMF two weeks ago... My reply to you is the one just *before* your most recent post. (It's located here.)

It begins with:

Quote:
Hey Josh,

That looks VERY cool! Big thanks for sharing.
But I did have a couple of questions for you, in particular, regarding the data type for your 'job' variable. Could you give it a read?

Mike
__________________
My Articles:
| Excel from .NET | Excel RibbonX using VBA | Excel from VB6 | CVErr in .NET | MVP |
Avatar by Lebb
Reply With Quote
  #26  
Old 07-14-2009, 01:48 PM
yoshijg yoshijg is offline
Newcomer
 
Join Date: Jun 2009
Posts: 7
Default

If you look at the first chunk of code, that's where the "Job" class is defined.

In my usage example (the last snippet of code), "job" is of the "Job" type.

AddProcess takes a IntPtr. Basically a handle to the Excel process.

Look through the top portion. I didn't submit the entire code file... just the relevant sections.

When I have time I'll repost the entire section, and/or possibly put it in codeproject.

- Josh
Reply With Quote
  #27  
Old 07-14-2009, 02:25 PM
Mike Rosenblum's Avatar
Mike Rosenblum Mike Rosenblum is offline
Microsoft Excel MVP

Forum Leader
* Guru *
 
Join Date: Jul 2003
Location: New York, NY, USA
Posts: 7,848
Default

Ah, ok, I missed that. Very cool. (Not that I understand it, mind you! But I trust you.) I'll have to digest this for a while...

This could be an excellent CodeProject article. (Post a link here, if you do!)

Cool stuff Josh, thanks for sharing.
__________________
My Articles:
| Excel from .NET | Excel RibbonX using VBA | Excel from VB6 | CVErr in .NET | MVP |
Avatar by Lebb
Reply With Quote
  #28  
Old 07-14-2009, 02:50 PM
yoshijg yoshijg is offline
Newcomer
 
Join Date: Jun 2009
Posts: 7
Default

A lot of it is just understanding the Win32 API. I didn't really leverage any .Net classes...all it does is just make a bunch of Win32 calls.

I wouldn't have stumbled on this solution if it wasn't for my co-worker, who is a wiz programmer.

- Josh
Reply With Quote
  #29  
Old 07-14-2009, 03:12 PM
Mike Rosenblum's Avatar
Mike Rosenblum Mike Rosenblum is offline
Microsoft Excel MVP

Forum Leader
* Guru *
 
Join Date: Jul 2003
Location: New York, NY, USA
Posts: 7,848
Default

Yes, definitely impressive PInvoke coding... And hopefully a big help to those that need a solution like this.

Thanks for sharing, and thanks to your wiz co-worker. Great stuff.
__________________
My Articles:
| Excel from .NET | Excel RibbonX using VBA | Excel from VB6 | CVErr in .NET | MVP |
Avatar by Lebb
Reply With Quote
  #30  
Old 07-15-2009, 08:12 AM
yoshijg yoshijg is offline
Newcomer
 
Join Date: Jun 2009
Posts: 7
Default

Quote:
Originally Posted by Mike_R View Post
Yes, definitely impressive PInvoke coding...
I was about to wrap every win32 function, but I found this site: http://www.pinvoke.net/

Great site/resource!!!
Reply With Quote
  #31  
Old 07-15-2009, 09:31 AM
Mike Rosenblum's Avatar
Mike Rosenblum Mike Rosenblum is offline
Microsoft Excel MVP

Forum Leader
* Guru *
 
Join Date: Jul 2003
Location: New York, NY, USA
Posts: 7,848
Default

Yes, PInvoke.net is a great resource.

I don't use PInvoke all that often, but when I do I wrap all my Win32 API calls into a separate, static class. That way each API is well considered and there isn't any code duplication (multiple declarations).
__________________
My Articles:
| Excel from .NET | Excel RibbonX using VBA | Excel from VB6 | CVErr in .NET | MVP |
Avatar by Lebb
Reply With Quote
  #32  
Old 11-22-2009, 08:09 PM
todoc todoc is offline
Newcomer
 
Join Date: Nov 2009
Posts: 3
Default SetInformationJobObject always returns false

Hi Josh,

I've used your code converted to VB.Net but the SetInformationJobObject method always returns False. Also, the Marshal.GetLastWin32Error() always returns zero. Any idea why this would happen?

Code:
                
            Public Sub New()
                Dim info As New JOBOBJECT_BASIC_LIMIT_INFORMATION()
                info.LimitFlags = CShort(&H2000)

                Dim extendedInfo As New JOBOBJECT_EXTENDED_LIMIT_INFORMATION()
                extendedInfo.BasicLimitInformation = info

                Dim length As Integer = Marshal.SizeOf(GetType(JOBOBJECT_EXTENDED_LIMIT_INFORMATION))
                Dim extendedInfoPtr As IntPtr = Marshal.AllocHGlobal(length)
                Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, False)

                Me._handle = CreateJobObject(Nothing, Nothing)
                If Not SetInformationJobObject(Me._handle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, CUInt(length)) Then
                    Throw New Exception(String.Format("Unable to set information. Error: {0}", Marshal.GetLastWin32Error()))
                End If
            End Sub
Reply With Quote
  #33  
Old 11-22-2009, 08:26 PM
todoc todoc is offline
Newcomer
 
Join Date: Nov 2009
Posts: 3
Default

Problem fixed. I had some structure properties out of order.
Reply With Quote
  #34  
Old 11-26-2009, 12:07 AM
todoc todoc is offline
Newcomer
 
Join Date: Nov 2009
Posts: 3
Default

OK, I am trying to be adventurous and use this on a Win 2008 x64 server or Win XP x64 PC but SetInformationJobObject returns False and the Win32Error is error code 1008, "An attempt was made to reference a token that does not exist. ERROR_NO_TOKEN".

I can confirm that the CreateJobObject method returns a handle.

I hope someone can help!
Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off

Forum Jump

Advertisement:





Free Publications
The ASP.NET 2.0 Anthology
101 Essential Tips, Tricks & Hacks - Free 156 Page Preview. Learn the most practical features and best approaches for ASP.NET.
subscribe
Programmers Heaven C# School Book -Free 338 Page eBook
The Programmers Heaven C# School book covers the .NET framework and the C# language.
subscribe
Build Your Own ASP.NET 3.5 Web Site Using C# & VB, 3rd Edition - Free 219 Page Preview!
This comprehensive step-by-step guide will help get your database-driven ASP.NET web site up and running in no time..
subscribe
Orphan excel process started via automation
Orphan excel process started via automation
Orphan excel process started via automation Orphan excel process started via automation
Orphan excel process started via automation
Orphan excel process started via automation
Orphan excel process started via automation Orphan excel process started via automation Orphan excel process started via automation Orphan excel process started via automation Orphan excel process started via automation Orphan excel process started via automation Orphan excel process started via automation
Orphan excel process started via automation
Orphan excel process started via automation
 
Orphan excel process started via automation
Orphan excel process started via automation
 
-->