robust_excel_ole 0.5.1 → 0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Changelog +13 -0
- data/README.rdoc +70 -21
- data/README_detail.rdoc +60 -27
- data/examples/edit_sheets/example_access_sheets_and_cells.rb +2 -2
- data/examples/edit_sheets/example_adding_sheets.rb +2 -2
- data/examples/edit_sheets/example_concating.rb +2 -3
- data/examples/edit_sheets/example_copying.rb +2 -3
- data/examples/edit_sheets/example_expanding.rb +2 -3
- data/examples/edit_sheets/example_naming.rb +2 -3
- data/examples/edit_sheets/example_ranges.rb +2 -2
- data/examples/edit_sheets/example_saving.rb +2 -3
- data/examples/open_save_close/example_control_to_excel.rb +3 -3
- data/examples/open_save_close/example_default_excel.rb +4 -4
- data/examples/open_save_close/example_force_excel.rb +2 -2
- data/examples/open_save_close/example_if_obstructed_closeifsaved.rb +2 -2
- data/examples/open_save_close/example_if_obstructed_forget.rb +2 -2
- data/examples/open_save_close/example_if_obstructed_save.rb +2 -2
- data/examples/open_save_close/example_if_unsaved_accept.rb +2 -2
- data/examples/open_save_close/example_if_unsaved_forget.rb +2 -2
- data/examples/open_save_close/example_if_unsaved_forget_more.rb +4 -5
- data/examples/open_save_close/example_read_only.rb +2 -2
- data/examples/open_save_close/example_rename_cells.rb +3 -3
- data/examples/open_save_close/example_reuse.rb +2 -2
- data/examples/open_save_close/example_simple.rb +3 -4
- data/examples/open_save_close/example_unobtrusively.rb +2 -2
- data/lib/robust_excel_ole/book.rb +84 -78
- data/lib/robust_excel_ole/bookstore.rb +5 -1
- data/lib/robust_excel_ole/excel.rb +165 -188
- data/lib/robust_excel_ole/reo_common.rb +4 -0
- data/lib/robust_excel_ole/sheet.rb +15 -6
- data/lib/robust_excel_ole/version.rb +1 -1
- data/spec/book_spec.rb +104 -77
- data/spec/book_specs/book_close_spec.rb +9 -8
- data/spec/book_specs/book_misc_spec.rb +367 -26
- data/spec/book_specs/book_open_spec.rb +375 -94
- data/spec/book_specs/book_save_spec.rb +137 -112
- data/spec/book_specs/book_sheet_spec.rb +1 -1
- data/spec/book_specs/book_subclass_spec.rb +2 -1
- data/spec/book_specs/book_unobtr_spec.rb +87 -96
- data/spec/bookstore_spec.rb +8 -5
- data/spec/cell_spec.rb +1 -1
- data/spec/data/another_workbook.xls +0 -0
- data/spec/data/book_with_blank.xls +0 -0
- data/spec/data/workbook.xls +0 -0
- data/spec/excel_spec.rb +484 -72
- data/spec/range_spec.rb +1 -1
- data/spec/sheet_spec.rb +47 -1
- metadata +4 -5
@@ -28,11 +28,15 @@ module RobustExcelOle
|
|
28
28
|
weakref_books = @filename2books[filename_key]
|
29
29
|
return nil unless weakref_books
|
30
30
|
result = open_book = closed_book = nil
|
31
|
+
weakref_books = weakref_books.map {|wr_book| wr_book if wr_book.weakref_alive? }.compact
|
32
|
+
@filename2books[filename_key] = weakref_books
|
31
33
|
weakref_books.each do |wr_book|
|
32
34
|
if (not wr_book.weakref_alive?)
|
35
|
+
trace "warn: this should never happen"
|
33
36
|
begin
|
34
37
|
@filename2books[filename_key].delete(wr_book)
|
35
|
-
rescue
|
38
|
+
rescue
|
39
|
+
trace "#{$!.message}"
|
36
40
|
trace "Warning: deleting dead reference failed: file: #{filename.inspect}"
|
37
41
|
end
|
38
42
|
else
|
@@ -2,76 +2,89 @@
|
|
2
2
|
|
3
3
|
require 'timeout'
|
4
4
|
|
5
|
+
def ka
|
6
|
+
Excel.kill_all
|
7
|
+
end
|
8
|
+
|
9
|
+
|
5
10
|
module RobustExcelOle
|
6
11
|
|
7
12
|
class Excel < REOCommon
|
8
13
|
|
9
14
|
attr_accessor :ole_excel
|
15
|
+
attr_accessor :visible
|
16
|
+
attr_accessor :displayalerts
|
10
17
|
|
11
18
|
alias ole_object ole_excel
|
12
19
|
|
13
20
|
@@hwnd2excel = {}
|
14
21
|
|
15
22
|
# creates a new Excel instance
|
23
|
+
# @param [Hash] options the options
|
24
|
+
# @option options [Variant] :displayalerts
|
25
|
+
# @option options [Boolean] :visible
|
16
26
|
# @return [Excel] a new Excel instance
|
17
|
-
def self.create
|
18
|
-
new(:reuse => false)
|
27
|
+
def self.create(options = {})
|
28
|
+
new(options.merge({:reuse => false}))
|
19
29
|
end
|
20
30
|
|
21
|
-
# returns (connects to) the current Excel instance, if such a running Excel instance exists
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
31
|
+
# returns (connects to) the current (first opened) Excel instance, if such a running Excel instance exists
|
32
|
+
# returns a new Excel instance, otherwise
|
33
|
+
# @option options [Variant] :displayalerts
|
34
|
+
# @option options [Boolean] :visible
|
25
35
|
# @return [Excel] an Excel instance
|
26
|
-
def self.current
|
27
|
-
new(:reuse => true)
|
36
|
+
def self.current(options = {})
|
37
|
+
new(options.merge({:reuse => true}))
|
28
38
|
end
|
29
39
|
|
30
40
|
# returns an Excel instance
|
31
41
|
# given a WIN32OLE object representing an Excel instance, or a Hash representing options
|
32
42
|
# @param [Hash] options the options
|
33
|
-
# @option options [Boolean] :reuse
|
34
|
-
# @option options [Boolean] :
|
35
|
-
# @option options [
|
43
|
+
# @option options [Boolean] :reuse
|
44
|
+
# @option options [Boolean] :visible
|
45
|
+
# @option options [Variant] :displayalerts
|
36
46
|
# options:
|
37
47
|
# :reuse connects to an already running Excel instance (true) or
|
38
|
-
# creates a new Excel instance (false)
|
39
|
-
# :
|
40
|
-
# :
|
41
|
-
# if :reuse => true, then DisplayAlerts and Visible are set only if they are given
|
48
|
+
# creates a new Excel instance (false) (default: true)
|
49
|
+
# :visible makes the Excel visible (default: false)
|
50
|
+
# :displayalerts enables or disables DisplayAlerts (true, false, :if_visible (default))
|
42
51
|
# @return [Excel] an Excel instance
|
43
52
|
def self.new(options = {})
|
44
53
|
if options.is_a? WIN32OLE
|
45
|
-
|
54
|
+
ole_xl = options
|
46
55
|
else
|
47
56
|
options = {:reuse => true}.merge(options)
|
48
57
|
if options[:reuse] == true then
|
49
|
-
|
58
|
+
ole_xl = current_excel
|
50
59
|
end
|
51
60
|
end
|
52
|
-
|
53
|
-
|
61
|
+
#puts "options: #{options}"
|
62
|
+
if not (ole_xl)
|
63
|
+
ole_xl = WIN32OLE.new('Excel.Application')
|
54
64
|
options = {
|
55
|
-
:displayalerts =>
|
65
|
+
:displayalerts => :if_visible,
|
56
66
|
:visible => false,
|
57
67
|
}.merge(options)
|
58
68
|
end
|
59
|
-
|
60
|
-
excel.DisplayAlerts = options[:displayalerts] unless options[:displayalerts].nil?
|
61
|
-
excel.Visible = options[:visible] unless options[:visible].nil?
|
62
|
-
end
|
63
|
-
|
64
|
-
hwnd = excel.HWnd
|
69
|
+
hwnd = ole_xl.HWnd
|
65
70
|
stored = hwnd2excel(hwnd)
|
66
|
-
|
67
71
|
if stored
|
68
72
|
result = stored
|
69
73
|
else
|
70
74
|
result = super(options)
|
71
|
-
result.instance_variable_set(:@ole_excel,
|
72
|
-
WIN32OLE.const_load(
|
75
|
+
result.instance_variable_set(:@ole_excel, ole_xl)
|
76
|
+
WIN32OLE.const_load(ole_xl, RobustExcelOle) unless RobustExcelOle.const_defined?(:CONSTANTS)
|
73
77
|
@@hwnd2excel[hwnd] = WeakRef.new(result)
|
74
78
|
end
|
79
|
+
unless options.is_a? WIN32OLE
|
80
|
+
reused = options[:reuse] && (not stored.nil?)
|
81
|
+
visible_value = (reused && options[:visible].nil?) ? result.visible : options[:visible]
|
82
|
+
displayalerts_value = (reused && options[:displayalerts].nil?) ? result.displayalerts : options[:displayalerts]
|
83
|
+
ole_xl.Visible = visible_value
|
84
|
+
ole_xl.DisplayAlerts = (displayalerts_value == :if_visible) ? visible_value : displayalerts_value
|
85
|
+
result.instance_variable_set(:@visible, visible_value)
|
86
|
+
result.instance_variable_set(:@displayalerts, displayalerts_value)
|
87
|
+
end
|
75
88
|
result
|
76
89
|
end
|
77
90
|
|
@@ -85,18 +98,17 @@ module RobustExcelOle
|
|
85
98
|
# @option opts [Boolean] :displayalerts
|
86
99
|
# @option opts [Boolean] :visible
|
87
100
|
# options: reopen_workbooks (default: false): reopen the workbooks in the Excel instances
|
88
|
-
# :visible (default: false), :displayalerts (default:
|
101
|
+
# :visible (default: false), :displayalerts (default: :if_visible)
|
89
102
|
# @return [Excel] an Excel instance
|
90
103
|
def recreate(opts = {})
|
91
104
|
unless self.alive?
|
92
105
|
opts = {
|
93
|
-
:
|
94
|
-
:
|
106
|
+
:visible => @visible ? @visible : false,
|
107
|
+
:displayalerts => @displayalerts ? @displayalerts : :if_visible
|
95
108
|
}.merge(opts)
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
@ole_excel = new_excel
|
109
|
+
@ole_excel = WIN32OLE.new('Excel.Application')
|
110
|
+
self.visible = opts[:visible]
|
111
|
+
self.displayalerts = opts[:displayalerts]
|
100
112
|
if opts[:reopen_workbooks]
|
101
113
|
books = book_class.books
|
102
114
|
books.each do |book|
|
@@ -109,9 +121,9 @@ module RobustExcelOle
|
|
109
121
|
|
110
122
|
private
|
111
123
|
|
112
|
-
# returns
|
124
|
+
# returns a Win32OLE object that represents a Excel instance to which Excel connects
|
113
125
|
# connects to the first opened Excel instance
|
114
|
-
# if this Excel instance is being closed, then Excel creates a new Excel instance
|
126
|
+
# if this Excel instance is being closed, then Excel creates a new Excel instance
|
115
127
|
def self.current_excel # :nodoc: #
|
116
128
|
result = WIN32OLE.connect('Excel.Application') rescue nil
|
117
129
|
if result
|
@@ -127,9 +139,27 @@ module RobustExcelOle
|
|
127
139
|
|
128
140
|
public
|
129
141
|
|
142
|
+
# closes the Excel
|
143
|
+
# @param [Hash] options the options
|
144
|
+
# @option options [Symbol] :if_unsaved :raise, :save, :forget, or :keep_open
|
145
|
+
# @option options [Boolean] :hard
|
146
|
+
# :if_unsaved if unsaved workbooks are open in an Excel instance
|
147
|
+
# :raise (default) -> raises an exception
|
148
|
+
# :save -> saves the workbooks before closing
|
149
|
+
# :forget -> closes the Excel instance without saving the workbooks
|
150
|
+
# :keep_open -> keeps the Excel instance open
|
151
|
+
# :hard kill the Excel instance hard (default: false)
|
152
|
+
def close(options = {})
|
153
|
+
options = {
|
154
|
+
:if_unsaved => :raise,
|
155
|
+
:hard => false
|
156
|
+
}.merge(options)
|
157
|
+
close_excel(options) if managed_unsaved_workbooks(options)
|
158
|
+
end
|
159
|
+
|
130
160
|
# closes all Excel instances
|
131
161
|
# @param [Hash] options the options
|
132
|
-
# @option options [Symbol] :if_unsaved :raise, :save, :forget,
|
162
|
+
# @option options [Symbol] :if_unsaved :raise, :save, :forget, or :alert
|
133
163
|
# @option options [Boolean] :hard
|
134
164
|
# @option options [Boolean] :kill_if_timeout
|
135
165
|
# options:
|
@@ -137,10 +167,9 @@ module RobustExcelOle
|
|
137
167
|
# :raise (default) -> raises an exception
|
138
168
|
# :save -> saves the workbooks before closing
|
139
169
|
# :forget -> closes the excel instance without saving the workbooks
|
140
|
-
# :keep_open -> let the workbooks open
|
141
170
|
# :alert -> give control to Excel
|
142
171
|
# :hard closes Excel instances soft (default: false), or, additionally kills the Excel processes hard (true)
|
143
|
-
# :kill_if_timeout: kills Excel instances hard if the closing process exceeds a certain time limit (default:
|
172
|
+
# :kill_if_timeout: kills Excel instances hard if the closing process exceeds a certain time limit (default: false)
|
144
173
|
# @raise ExcelError if time limit has exceeded, some Excel instance cannot be closed, or
|
145
174
|
# unsaved workbooks exist and option :if_unsaved is :raise
|
146
175
|
def self.close_all(options={})
|
@@ -148,21 +177,19 @@ module RobustExcelOle
|
|
148
177
|
:if_unsaved => :raise,
|
149
178
|
:hard => false,
|
150
179
|
:kill_if_timeout => false
|
151
|
-
}.merge(options)
|
152
|
-
excels_number = excel_processes.size
|
180
|
+
}.merge(options)
|
153
181
|
timeout = false
|
182
|
+
number = excels_number
|
154
183
|
begin
|
155
|
-
status = Timeout::timeout(
|
156
|
-
while
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
raise ExcelError, "some Excel instance cannot be closed"
|
184
|
+
status = Timeout::timeout(15) {
|
185
|
+
while (excels_number > 0) do
|
186
|
+
ole_xl = current_excel
|
187
|
+
begin
|
188
|
+
(Excel.new(ole_xl).close(options); Excel.new(ole_xl).close(options)) if ole_xl # two times necessary ?!
|
189
|
+
rescue RuntimeError => msg
|
190
|
+
raise msg unless msg.message =~ /failed to get Dispatch Interface/
|
163
191
|
end
|
164
|
-
|
165
|
-
end
|
192
|
+
end
|
166
193
|
}
|
167
194
|
rescue Timeout::Error
|
168
195
|
raise ExcelError, "close_all: timeout" unless options[:kill_if_timeout]
|
@@ -170,18 +197,52 @@ module RobustExcelOle
|
|
170
197
|
end
|
171
198
|
kill_all if options[:hard] || (timeout && options[:kill_if_timeout])
|
172
199
|
init
|
200
|
+
number
|
173
201
|
end
|
174
202
|
|
175
|
-
def
|
176
|
-
|
203
|
+
def close_excel(options) # :nodoc:
|
204
|
+
ole_xl = @ole_excel
|
205
|
+
begin
|
206
|
+
if options[:if_unsaved] == :alert
|
207
|
+
with_displayalerts(true) {ole_xl.Workbooks.Close}
|
208
|
+
else
|
209
|
+
ole_xl.Workbooks.Close
|
210
|
+
end
|
211
|
+
rescue WIN32OLERuntimeError => msg
|
212
|
+
raise ExcelUserCanceled, "close: canceled by user" if msg.message =~ /80020009/ &&
|
213
|
+
options[:if_unsaved] == :alert && (not unsaved_workbooks.empty?)
|
214
|
+
end
|
215
|
+
excel_hwnd = ole_xl.HWnd
|
216
|
+
ole_xl.Quit
|
217
|
+
weak_excel_ref = WeakRef.new(ole_xl)
|
218
|
+
ole_xl = @ole_excel = nil
|
219
|
+
GC.start
|
220
|
+
sleep 0.2
|
221
|
+
if weak_excel_ref.weakref_alive? then
|
222
|
+
begin
|
223
|
+
weak_excel_ref.ole_free
|
224
|
+
#trace "successfully ole_freed #{weak_excel_ref}"
|
225
|
+
rescue => msg
|
226
|
+
trace "#{msg.message}"
|
227
|
+
trace "could not do ole_free on #{weak_excel_ref}"
|
228
|
+
end
|
229
|
+
end
|
230
|
+
@@hwnd2excel.delete(excel_hwnd)
|
231
|
+
if options[:hard] then
|
232
|
+
process_id = Win32API.new("user32", "GetWindowThreadProcessId", ["I","P"], "I")
|
233
|
+
pid_puffer = " " * 32
|
234
|
+
process_id.call(excel_hwnd, pid_puffer)
|
235
|
+
pid = pid_puffer.unpack("L")[0]
|
236
|
+
Process.kill("KILL", pid) rescue nil
|
237
|
+
end
|
177
238
|
end
|
178
239
|
|
179
240
|
private
|
180
241
|
|
181
|
-
def
|
182
|
-
unsaved_workbooks = []
|
242
|
+
def managed_unsaved_workbooks(options)
|
243
|
+
unsaved_workbooks = []
|
183
244
|
begin
|
184
|
-
|
245
|
+
@ole_excel.Workbooks.each {|w| unsaved_workbooks << w unless (w.Saved || w.ReadOnly)}
|
185
246
|
rescue RuntimeError => msg
|
186
247
|
trace "RuntimeError: #{msg.message}"
|
187
248
|
raise ExcelErrorOpen, "Excel instance not alive or damaged" if msg.message =~ /failed to get Dispatch Interface/
|
@@ -194,77 +255,30 @@ module RobustExcelOle
|
|
194
255
|
unsaved_workbooks.each do |workbook|
|
195
256
|
workbook.Save
|
196
257
|
end
|
258
|
+
return true
|
197
259
|
when :forget
|
198
260
|
# nothing
|
199
|
-
when :keep_open
|
200
|
-
return
|
201
261
|
when :alert
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
ensure
|
206
|
-
begin
|
207
|
-
excel.DisplayAlerts = false
|
208
|
-
rescue RuntimeError => msg
|
209
|
-
trace "RuntimeError: #{msg.message}" if msg.message =~ /failed to get Dispatch Interface/
|
210
|
-
end
|
211
|
-
end
|
212
|
-
return
|
262
|
+
# nothing
|
263
|
+
when :keep_open
|
264
|
+
return false
|
213
265
|
else
|
214
266
|
raise ExcelErrorClose, ":if_unsaved: invalid option: #{options[:if_unsaved].inspect}"
|
215
267
|
end
|
216
268
|
end
|
217
|
-
|
218
|
-
end
|
219
|
-
|
220
|
-
# closes one Excel instance to which one was connected
|
221
|
-
def self.close_one_excel(options={})
|
222
|
-
excel = current_excel
|
223
|
-
return unless excel
|
224
|
-
manage_unsaved_workbooks(excel, options) do
|
225
|
-
weak_ole_excel = WeakRef.new(excel)
|
226
|
-
excel = nil
|
227
|
-
close_excel_ole_instance(weak_ole_excel.__getobj__)
|
228
|
-
end
|
229
|
-
end
|
230
|
-
|
231
|
-
def self.close_excel_ole_instance(ole_excel) # :nodoc: #
|
232
|
-
@@hwnd2excel.delete(ole_excel.Hwnd)
|
233
|
-
excel = ole_excel
|
234
|
-
ole_excel = nil
|
235
|
-
begin
|
236
|
-
excel.Workbooks.Close
|
237
|
-
excel_hwnd = excel.HWnd
|
238
|
-
excel.Quit
|
239
|
-
weak_excel_ref = WeakRef.new(excel)
|
240
|
-
excel = nil
|
241
|
-
GC.start
|
242
|
-
sleep 0.2
|
243
|
-
if weak_excel_ref.weakref_alive? then
|
244
|
-
begin
|
245
|
-
weak_excel_ref.ole_free
|
246
|
-
trace "successfully ole_freed #{weak_excel_ref}"
|
247
|
-
rescue
|
248
|
-
trace "could not do ole_free on #{weak_excel_ref}"
|
249
|
-
end
|
250
|
-
end
|
251
|
-
@@hwnd2excel.delete(excel_hwnd)
|
252
|
-
rescue => e
|
253
|
-
trace "Error when closing Excel: #{e.message}"
|
254
|
-
#t e.backtrace
|
255
|
-
end
|
256
|
-
free_all_ole_objects
|
269
|
+
return true
|
257
270
|
end
|
258
271
|
|
259
272
|
# frees all OLE objects in the object space
|
260
273
|
def self.free_all_ole_objects # :nodoc: #
|
261
274
|
anz_objekte = 0
|
262
|
-
ObjectSpace.each_object(WIN32OLE) do |o|
|
275
|
+
ObjectSpace.each_object(WIN32OLE) do |o|
|
263
276
|
anz_objekte += 1
|
264
|
-
#
|
265
|
-
#
|
266
|
-
#
|
267
|
-
#
|
277
|
+
#trace "#{anz_objekte} name: #{(o.Name rescue (o.Count rescue "no_name"))} ole_object_name: #{(o.ole_object_name rescue nil)} type: #{o.ole_type rescue nil}"
|
278
|
+
#trace [:Name, (o.Name rescue (o.Count rescue "no_name"))]
|
279
|
+
#trace [:ole_object_name, (o.ole_object_name rescue nil)]
|
280
|
+
#trace [:methods, (o.ole_methods rescue nil)] unless (o.Name rescue false)
|
281
|
+
#trace o.ole_type rescue nil
|
268
282
|
begin
|
269
283
|
o.ole_free
|
270
284
|
#trace "olefree OK"
|
@@ -276,62 +290,10 @@ module RobustExcelOle
|
|
276
290
|
trace "went through #{anz_objekte} OLE objects"
|
277
291
|
end
|
278
292
|
|
279
|
-
public
|
280
293
|
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
# @option options [Boolean] :hard
|
285
|
-
# :if_unsaved if unsaved workbooks are open in an Excel instance
|
286
|
-
# :raise (default) -> raises an exception
|
287
|
-
# :save -> saves the workbooks before closing
|
288
|
-
# :forget -> closes the Excel instance without saving the workbooks
|
289
|
-
# :keep_open -> keeps the Excel instance open
|
290
|
-
# :hard kill the Excel instance hard (default: false)
|
291
|
-
def close(options = {})
|
292
|
-
options = {
|
293
|
-
:if_unsaved => :raise,
|
294
|
-
:hard => false
|
295
|
-
}.merge(options)
|
296
|
-
self.class.manage_unsaved_workbooks(@ole_excel, options) do
|
297
|
-
close_excel(options)
|
298
|
-
end
|
299
|
-
end
|
300
|
-
|
301
|
-
private
|
302
|
-
|
303
|
-
def close_excel(options)
|
304
|
-
excel = @ole_excel
|
305
|
-
begin
|
306
|
-
excel.Workbooks.Close
|
307
|
-
rescue WIN32OLERuntimeError => msg
|
308
|
-
raise ExcelUserCanceled, "close: canceled by user" if msg.message =~ /80020009/ &&
|
309
|
-
options[:if_unsaved] == :alert && (not self.unsaved_workbooks.empty?)
|
310
|
-
end
|
311
|
-
excel_hwnd = excel.HWnd
|
312
|
-
excel.Quit
|
313
|
-
weak_excel_ref = WeakRef.new(excel)
|
314
|
-
excel = nil
|
315
|
-
GC.start
|
316
|
-
sleep 0.2
|
317
|
-
if weak_excel_ref.weakref_alive? then
|
318
|
-
begin
|
319
|
-
weak_excel_ref.ole_free
|
320
|
-
trace "successfully ole_freed #{weak_excel_ref}"
|
321
|
-
rescue => msg
|
322
|
-
trace "#{msg.message}"
|
323
|
-
trace "could not do ole_free on #{weak_excel_ref}"
|
324
|
-
end
|
325
|
-
end
|
326
|
-
@@hwnd2excel.delete(excel_hwnd)
|
327
|
-
if options[:hard] then
|
328
|
-
process_id = Win32API.new("user32", "GetWindowThreadProcessId", ["I","P"], "I")
|
329
|
-
pid_puffer = " " * 32
|
330
|
-
process_id.call(excel_hwnd, pid_puffer)
|
331
|
-
pid = pid_puffer.unpack("L")[0]
|
332
|
-
Process.kill("KILL", pid) rescue nil
|
333
|
-
end
|
334
|
-
end
|
294
|
+
def self.init
|
295
|
+
@@hwnd2excel = {}
|
296
|
+
end
|
335
297
|
|
336
298
|
public
|
337
299
|
|
@@ -342,12 +304,21 @@ module RobustExcelOle
|
|
342
304
|
processes = procs.InstancesOf("win32_process")
|
343
305
|
number = processes.select{|p| (p.name == "EXCEL.EXE")}.size
|
344
306
|
procs.InstancesOf("win32_process").each do |p|
|
345
|
-
|
307
|
+
begin
|
308
|
+
Process.kill('KILL', p.processid) if p.name == "EXCEL.EXE"
|
309
|
+
rescue
|
310
|
+
trace "kill error: #{$!}"
|
311
|
+
end
|
346
312
|
end
|
347
313
|
init
|
348
314
|
number
|
349
315
|
end
|
350
316
|
|
317
|
+
def self.excels_number
|
318
|
+
WIN32OLE.connect("winmgmts:\\\\.").InstancesOf("win32_process").select{|p| (p.name == "EXCEL.EXE")}.size
|
319
|
+
end
|
320
|
+
|
321
|
+
=begin
|
351
322
|
# provide Excel objects
|
352
323
|
# (so far restricted to all Excel instances opened with RobustExcelOle,
|
353
324
|
# not for Excel instances opened by the user)
|
@@ -376,6 +347,7 @@ module RobustExcelOle
|
|
376
347
|
end
|
377
348
|
result
|
378
349
|
end
|
350
|
+
=end
|
379
351
|
|
380
352
|
def excel # :nodoc: #
|
381
353
|
self
|
@@ -419,7 +391,7 @@ module RobustExcelOle
|
|
419
391
|
@ole_excel.Name
|
420
392
|
true
|
421
393
|
rescue
|
422
|
-
#
|
394
|
+
#trace $!.message
|
423
395
|
false
|
424
396
|
end
|
425
397
|
|
@@ -472,34 +444,39 @@ module RobustExcelOle
|
|
472
444
|
|
473
445
|
# sets DisplayAlerts in a block
|
474
446
|
def with_displayalerts displayalerts_value
|
475
|
-
old_displayalerts =
|
476
|
-
|
447
|
+
old_displayalerts = self.displayalerts
|
448
|
+
self.displayalerts = displayalerts_value
|
477
449
|
begin
|
478
450
|
yield self
|
479
451
|
ensure
|
480
|
-
|
452
|
+
self.displayalerts = old_displayalerts if alive?
|
481
453
|
end
|
482
454
|
end
|
483
455
|
|
484
456
|
# enables DisplayAlerts in the current Excel instance
|
485
457
|
def displayalerts= displayalerts_value
|
486
|
-
@displayalerts =
|
487
|
-
|
488
|
-
|
489
|
-
# return whether DisplayAlerts is enabled in the current Excel instance
|
490
|
-
def displayalerts
|
491
|
-
@displayalerts = @ole_excel.DisplayAlerts
|
458
|
+
@displayalerts = displayalerts_value
|
459
|
+
@ole_excel.DisplayAlerts = (@displayalerts == :if_visible) ? @ole_excel.Visible : displayalerts_value
|
492
460
|
end
|
493
461
|
|
494
462
|
# makes the current Excel instance visible or invisible
|
495
463
|
def visible= visible_value
|
496
|
-
@
|
497
|
-
|
464
|
+
@ole_excel.Visible = @visible = visible_value
|
465
|
+
@ole_excel.DisplayAlerts = @visible if @displayalerts == :if_visible
|
466
|
+
end
|
498
467
|
|
499
|
-
#
|
500
|
-
def
|
501
|
-
|
502
|
-
|
468
|
+
# make all workbooks visible or invisible
|
469
|
+
def workbooks_visible= visible_value
|
470
|
+
begin
|
471
|
+
@ole_excel.Workbooks.each do |ole_wb|
|
472
|
+
workbook = Book.new(ole_wb)
|
473
|
+
workbook.visible = visible_value
|
474
|
+
end
|
475
|
+
rescue RuntimeError => msg
|
476
|
+
trace "RuntimeError: #{msg.message}"
|
477
|
+
raise ExcelErrorOpen, "Excel instance not alive or damaged" if msg.message =~ /failed to get Dispatch Interface/
|
478
|
+
end
|
479
|
+
end
|
503
480
|
|
504
481
|
# sets calculation mode in a block
|
505
482
|
def with_calculation(calculation_mode = :automatic)
|