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.
Files changed (48) hide show
  1. data/Changelog +13 -0
  2. data/README.rdoc +70 -21
  3. data/README_detail.rdoc +60 -27
  4. data/examples/edit_sheets/example_access_sheets_and_cells.rb +2 -2
  5. data/examples/edit_sheets/example_adding_sheets.rb +2 -2
  6. data/examples/edit_sheets/example_concating.rb +2 -3
  7. data/examples/edit_sheets/example_copying.rb +2 -3
  8. data/examples/edit_sheets/example_expanding.rb +2 -3
  9. data/examples/edit_sheets/example_naming.rb +2 -3
  10. data/examples/edit_sheets/example_ranges.rb +2 -2
  11. data/examples/edit_sheets/example_saving.rb +2 -3
  12. data/examples/open_save_close/example_control_to_excel.rb +3 -3
  13. data/examples/open_save_close/example_default_excel.rb +4 -4
  14. data/examples/open_save_close/example_force_excel.rb +2 -2
  15. data/examples/open_save_close/example_if_obstructed_closeifsaved.rb +2 -2
  16. data/examples/open_save_close/example_if_obstructed_forget.rb +2 -2
  17. data/examples/open_save_close/example_if_obstructed_save.rb +2 -2
  18. data/examples/open_save_close/example_if_unsaved_accept.rb +2 -2
  19. data/examples/open_save_close/example_if_unsaved_forget.rb +2 -2
  20. data/examples/open_save_close/example_if_unsaved_forget_more.rb +4 -5
  21. data/examples/open_save_close/example_read_only.rb +2 -2
  22. data/examples/open_save_close/example_rename_cells.rb +3 -3
  23. data/examples/open_save_close/example_reuse.rb +2 -2
  24. data/examples/open_save_close/example_simple.rb +3 -4
  25. data/examples/open_save_close/example_unobtrusively.rb +2 -2
  26. data/lib/robust_excel_ole/book.rb +84 -78
  27. data/lib/robust_excel_ole/bookstore.rb +5 -1
  28. data/lib/robust_excel_ole/excel.rb +165 -188
  29. data/lib/robust_excel_ole/reo_common.rb +4 -0
  30. data/lib/robust_excel_ole/sheet.rb +15 -6
  31. data/lib/robust_excel_ole/version.rb +1 -1
  32. data/spec/book_spec.rb +104 -77
  33. data/spec/book_specs/book_close_spec.rb +9 -8
  34. data/spec/book_specs/book_misc_spec.rb +367 -26
  35. data/spec/book_specs/book_open_spec.rb +375 -94
  36. data/spec/book_specs/book_save_spec.rb +137 -112
  37. data/spec/book_specs/book_sheet_spec.rb +1 -1
  38. data/spec/book_specs/book_subclass_spec.rb +2 -1
  39. data/spec/book_specs/book_unobtr_spec.rb +87 -96
  40. data/spec/bookstore_spec.rb +8 -5
  41. data/spec/cell_spec.rb +1 -1
  42. data/spec/data/another_workbook.xls +0 -0
  43. data/spec/data/book_with_blank.xls +0 -0
  44. data/spec/data/workbook.xls +0 -0
  45. data/spec/excel_spec.rb +484 -72
  46. data/spec/range_spec.rb +1 -1
  47. data/spec/sheet_spec.rb +47 -1
  48. 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
- # more specific: connects to the first opened Excel instance
23
- # if this Excel instance is being closed, then Excel creates a new Excel instance that has the same Hwnd
24
- # creates a new one, otherwise
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] :displayalerts
35
- # @option options [Boolean] :visible
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) (default: true)
39
- # :displayalerts allows display alerts in Excel (default: false)
40
- # :visible makes the Excel visible (default: false)
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
- excel = options
54
+ ole_xl = options
46
55
  else
47
56
  options = {:reuse => true}.merge(options)
48
57
  if options[:reuse] == true then
49
- excel = current_excel
58
+ ole_xl = current_excel
50
59
  end
51
60
  end
52
- if not (excel)
53
- excel = WIN32OLE.new('Excel.Application')
61
+ #puts "options: #{options}"
62
+ if not (ole_xl)
63
+ ole_xl = WIN32OLE.new('Excel.Application')
54
64
  options = {
55
- :displayalerts => false,
65
+ :displayalerts => :if_visible,
56
66
  :visible => false,
57
67
  }.merge(options)
58
68
  end
59
- unless options.is_a? WIN32OLE
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, excel)
72
- WIN32OLE.const_load(excel, RobustExcelOle) unless RobustExcelOle.const_defined?(:CONSTANTS)
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: false)
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
- :displayalerts => @displayalerts ? @displayalerts : false,
94
- :visible => @visible ? @visible : false
106
+ :visible => @visible ? @visible : false,
107
+ :displayalerts => @displayalerts ? @displayalerts : :if_visible
95
108
  }.merge(opts)
96
- new_excel = WIN32OLE.new('Excel.Application')
97
- new_excel.DisplayAlerts = opts[:displayalerts]
98
- new_excel.Visible = opts[:visible]
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 (connects to) a running Excel instance
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 that has the same Hwnd
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, :alert, or :keep_open
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: true)
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(5) {
156
- while current_excel do
157
- close_one_excel(options)
158
- GC.start
159
- sleep 0.3
160
- current_excels_number = excel_processes.size
161
- if current_excels_number == excels_number && excels_number > 0
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
- excels_number = current_excels_number
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 self.init
176
- @@hwnd2excel = {}
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 self.manage_unsaved_workbooks(excel, options) # :nodoc: #
182
- unsaved_workbooks = []
242
+ def managed_unsaved_workbooks(options)
243
+ unsaved_workbooks = []
183
244
  begin
184
- excel.Workbooks.each {|w| unsaved_workbooks << w unless (w.Saved || w.ReadOnly)}
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
- begin
203
- excel.DisplayAlerts = true
204
- yield
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
- yield
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
- #t [:Name, (o.Name rescue (o.Count rescue "no_name"))]
265
- #t [:ole_object_name, (o.ole_object_name rescue nil)]
266
- #t [:methods, (o.ole_methods rescue nil)] unless (o.Name rescue false)
267
- #t o.ole_type rescue nil
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
- # closes the Excel
282
- # @param [Hash] options the options
283
- # @option options [Symbol] :if_unsaved :raise, :save, :forget, or :keep_open
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
- Process.kill('KILL', p.processid) if p.name == "EXCEL.EXE"
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
- #t $!.message
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 = @ole_excel.DisplayAlerts
476
- @ole_excel.DisplayAlerts = displayalerts_value
447
+ old_displayalerts = self.displayalerts
448
+ self.displayalerts = displayalerts_value
477
449
  begin
478
450
  yield self
479
451
  ensure
480
- @ole_excel.DisplayAlerts = old_displayalerts if alive?
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 = @ole_excel.DisplayAlerts = displayalerts_value
487
- end
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
- @visible = @ole_excel.Visible = visible_value
497
- end
464
+ @ole_excel.Visible = @visible = visible_value
465
+ @ole_excel.DisplayAlerts = @visible if @displayalerts == :if_visible
466
+ end
498
467
 
499
- # returns whether the current Excel instance is visible
500
- def visible
501
- @visible = @ole_excel.Visible
502
- end
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)