robust_excel_ole 0.5.1 → 0.6
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|