How to completely terminate a WIN32OLE Excel object?

S

Sven Suska

Hello,

I can't get rid of Excel, if I have ever called it,
even with such a simple script:

---------- code starts --------------
require 'win32ole'

def puts_win32ole_objects
res = []
ObjectSpace.each_object do |o|
res << o if o.is_a? WIN32OLE
end
puts res.inspect
end

puts_win32ole_objects # --> empty
xl = WIN32OLE.new('Excel.Application')
puts_win32ole_objects # --> one object
xl.Quit
xl = nil
GC.start # anything else I could do???
puts_win32ole_objects # --> the object is still there
sleep 5
---------------------------------------------
And also the Excel process remains running in Windows.

Btw, even after the xl.Quit, the object remains fully functional,
so I could call o.Visible, o.Workbooks.Open(...) etc., it o were
the object (retrieved from ObjectSpace).

When the Ruby process is terminated (after sleep), the
Excel process will also terminate.

So, what's the proper way to handle this?

I've found the WIN32OLE.ole_free method, but they say
that it is for debugging only.


Thanks for your help

Sven
 
J

James Tucker

Sven said:
Hello James,

James said:
I can't replicate this:
require 'win32ole'
[... skipping irb session ...]


This is truely strange!

Thanks for pointing this out!

When I tried this with IRB on my machine,
I got the same result:
Excel termination worked normally.

So there must be some difference
when the is executed as a Ruby file vs. via IRB.

Interesting indeed!

I can replicate from a .rb file.

In fact, loading the .rb in irb also works in the correct manner, on the contrary, if I load the .rb in my hacked version of IRB, it does not. This seems almost like it is hardcoded to work for irb, or it is something to do with the way in which handles are being processed.

I have also noticed a similar behavior with shell execution.

A GC.start will clear used file handles from `` and system() calls in IRB, and if documentation I have read elsewhere is correct, this is not the case for 'normal execution'. Time to plough through IRBs source tree, and start tracing.
So far, I have no idea what it could be.
I have set both RUBYOPT and RUBLIB to empty strings,
I've run the file via SciTe and on the console (ruby filename.rb)
-- the Excel object persists under all those conditions.
It's only within IRB that it is cleaned up properly.

Both my Ruby186 and 185 installations were done with
the one-click installer. (if that is of any significance)


I would appreciate any further help on this issue.

Thank you
Sven

Sven said:
Hello,

I can't get rid of Excel, if I have ever called it,
even with such a simple script:

---------- code starts --------------
require 'win32ole'

def puts_win32ole_objects
res = []
ObjectSpace.each_object do |o|
res << o if o.is_a? WIN32OLE
end
puts res.inspect
end

puts_win32ole_objects # --> empty
xl = WIN32OLE.new('Excel.Application')
puts_win32ole_objects # --> one object
xl.Quit
xl = nil
GC.start # anything else I could do???
puts_win32ole_objects # --> the object is still there
sleep 5
---------------------------------------------
And also the Excel process remains running in Windows.

Btw, even after the xl.Quit, the object remains fully functional,
so I could call o.Visible, o.Workbooks.Open(...) etc., it o were
the object (retrieved from ObjectSpace).

When the Ruby process is terminated (after sleep), the
Excel process will also terminate.

So, what's the proper way to handle this?

I've found the WIN32OLE.ole_free method, but they say
that it is for debugging only.


Thanks for your help

Sven
 
M

Masaki Suketa

Hello,

In message "How to completely terminate a WIN32OLE Excel object?"
When the Ruby process is terminated (after sleep), the
Excel process will also terminate.

So, what's the proper way to handle this?

I've found the WIN32OLE.ole_free method, but they say
that it is for debugging only.

I am not sure, but it seems to me because of GC behavior.
I tested your script using Foo class instead of WIN32OLE.
And I've got same result as WIN32OLE.

--- code starts ---
class Foo
def initialize(arg)
@arg = arg
end
def Quit
end
end

def puts_win32ole_objects
res = []
ObjectSpace.each_object do |o|
res << o if o.is_a? Foo
end
puts res.inspect
end

puts_win32ole_objects # --> empty
xl = Foo.new('Excel.Application')
puts_win32ole_objects # --> one object
xl.Quit
xl = nil
GC.start # anything else I could do???
puts_win32ole_objects # --> the object is still there
sleep 5
puts_win32ole_objects # --> the object is still there
--- code end ---

The Excel process is terminated when the WIN32OLE object is GCed.
But in this case, the WIN32OLE object is not GCed, so the Excel
process is not terminated.

I recommend that you do not use WIN32OLE#ole_free(See following REMARK!).
But if you want to terminate the process before the WIN32OLE object GCed,
you can use WIN32OLE#ole_free.

REMARK!
WIN32OLE#ole_free terminates the Excel process but
the WIN32OLE object is not GCed.
You should not access the WIN32OLE object after WIN32OLE#ole_free
called.

Regards
Masaki Suketa
 
S

Sven Suska

Masaki said:
I am not sure, but it seems to me because of GC behavior.
I tested your script using Foo class instead of WIN32OLE.
And I've got same result as WIN32OLE.
I cannot confirm that.
The last two outputs give the empty list on my system.
Independent of the Ruby version (1.8.6 or 1.8.5).
--- code starts ---
class Foo
def initialize(arg)
@arg = arg
end
def Quit
end
end

def puts_win32ole_objects
res = []
ObjectSpace.each_object do |o|
res << o if o.is_a? Foo
end
puts res.inspect
end

puts_win32ole_objects # --> empty
xl = Foo.new('Excel.Application')
puts_win32ole_objects # --> one object
xl.Quit
xl = nil
GC.start # anything else I could do???
puts_win32ole_objects # --> the object is still there
sleep 5
puts_win32ole_objects # --> the object is still there
--- code end ---
The Excel process is terminated when the WIN32OLE object is GCed.
But in this case, the WIN32OLE object is not GCed, so the Excel
process is not terminated.
I see: it is all a matter of garbage collection.
But if you want to terminate the process before the WIN32OLE object GCed,
you can use WIN32OLE#ole_free.
Thanks for telling me -- this worked indeed, contrary to WIN32OLE.ole_free.
It would be a dirty solution.

However, The point you made about GC, has inspired me towards further
experiments.
First, I created a second WIN32OLE.new('Excel Application'), just to see
if the first object might get 'recycled'.
What I found was, that two objects existed after the second object creation,
but after the three terminating statements (quit -- nil -- GC),
only the second object remained. (Lazy recycling, ... :) )

Encouraged by this surprising result, I tried other things, and then this:
xl = Foo.new('Excel.Application')
puts_win32ole_objects
xl = nil
GC.start

Just not calling xl.Quit anymore, and -- the object is gone!
Simplest of all!

This looks like an easy solution, but no no, too early to jump for joy:
I encountered this behaviour for _any_ method I called on the xl object.
OK, so, the easy destruction only works for "virgin" objects.

Thus, so far, we have not yet found a gentle
way to finish a WIN32OLE/Excel object.
For the time being, I think I'll resort to
(not-so-gentle) WIN32OLE#ole_free.


Regards,
Sven
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top