robust_excel_ole 1.4 → 1.5
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.
- checksums.yaml +4 -4
- data/Changelog +6 -0
- data/README.rdoc +7 -1
- data/docs/README_ranges.rdoc +1 -1
- data/lib/reo_console.rb +19 -17
- data/lib/robust_excel_ole.rb +1 -2
- data/lib/robust_excel_ole/bookstore.rb +45 -45
- data/lib/robust_excel_ole/cell.rb +11 -12
- data/lib/robust_excel_ole/cygwin.rb +11 -11
- data/lib/robust_excel_ole/excel.rb +218 -201
- data/lib/robust_excel_ole/general.rb +23 -21
- data/lib/robust_excel_ole/range.rb +18 -19
- data/lib/robust_excel_ole/reo_common.rb +95 -82
- data/lib/robust_excel_ole/version.rb +1 -1
- data/lib/robust_excel_ole/workbook.rb +199 -205
- data/lib/robust_excel_ole/worksheet.rb +33 -56
- data/lib/spec_helper.rb +3 -3
- data/spec/workbook_spec.rb +18 -0
- data/spec/workbook_specs/workbook_misc_spec.rb +2 -2
- data/spec/worksheet_spec.rb +18 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1d86cf14a83a7f64c9c81e1a5473a13e66ac8be2
|
4
|
+
data.tar.gz: d7f78aba06eac6432722f36b4d753ed1b1cc94a7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5c97c2fe5da0196f6021ad6a4bf1f62b1a1b7b1dd7c35df1699fd6f61894b5f1394ef8950cc2f1588775188a2909afe341400d1b7574c461b6990abb06c9ed4d
|
7
|
+
data.tar.gz: e639929ed6031c0c4e041350a95d5b95aca527b956a917b4cad5ee578d301925599927d4c532dd80958a5306dce543fd4b27dbd2a0a6e36280484a3bd43ab23b
|
data/Changelog
CHANGED
@@ -1,10 +1,16 @@
|
|
1
1
|
# Change Log
|
2
2
|
All notable changes to this project will be documented in this file.
|
3
3
|
|
4
|
+
## [1.4.1]
|
5
|
+
|
6
|
+
### Changed
|
7
|
+
- renamed Worksheet#name2range to ReoCommon#range
|
8
|
+
|
4
9
|
## [1.4]
|
5
10
|
|
6
11
|
### Changed
|
7
12
|
- renamed Book to Workbook, Sheet to Worksheet
|
13
|
+
- General#to_reo
|
8
14
|
|
9
15
|
## [1.3.1]
|
10
16
|
|
data/README.rdoc
CHANGED
@@ -285,6 +285,12 @@ and set another value to that range.
|
|
285
285
|
|
286
286
|
For more details about reading and writing contents of cells and ranges see {README_ranges}[https://github.com/Thomas008/robust_excel_ole/blob/master/docs/README_ranges.rdoc]
|
287
287
|
|
288
|
+
=== More things
|
289
|
+
|
290
|
+
You can convert a win32ole object into a RobustExcelOle object.
|
291
|
+
|
292
|
+
range = sheet.Names.Item("firstcell").to_reo
|
293
|
+
|
288
294
|
=== Examples
|
289
295
|
|
290
296
|
You can run the examples included in the directory +examples+, e.g.
|
@@ -297,7 +303,7 @@ This project RobustExcelOle is work in progress. We are happy to implement furth
|
|
297
303
|
|
298
304
|
RobustExcelOle is being tested for Excel 2010. It can be used for any recent Excel Office version.
|
299
305
|
|
300
|
-
|
306
|
+
RobustExcelOle has been optimised with help of the rubocop and the rcov tool.
|
301
307
|
|
302
308
|
== Support
|
303
309
|
|
data/docs/README_ranges.rdoc
CHANGED
data/lib/reo_console.rb
CHANGED
@@ -1,52 +1,54 @@
|
|
1
|
-
#require '../robust_excel_ole/lib/robust_excel_ole'
|
1
|
+
# require '../robust_excel_ole/lib/robust_excel_ole'
|
2
2
|
include REO
|
3
|
-
#include RobustExcelOle
|
3
|
+
# include RobustExcelOle
|
4
4
|
include General
|
5
5
|
|
6
6
|
require 'irb/completion'
|
7
7
|
require 'irb/ext/save-history'
|
8
8
|
|
9
|
-
ARGV.concat [
|
10
|
-
|
11
|
-
|
9
|
+
ARGV.concat ['--readline',
|
10
|
+
'--prompt-mode',
|
11
|
+
'simple']
|
12
12
|
|
13
13
|
# 250 entries in the list
|
14
14
|
IRB.conf[:SAVE_HISTORY] = 250
|
15
15
|
|
16
16
|
# Store results in home directory with specified file name
|
17
|
-
#IRB.conf[:HISTORY_FILE] = "#{ENV['HOME']}/.irb-history"
|
17
|
+
# IRB.conf[:HISTORY_FILE] = "#{ENV['HOME']}/.irb-history"
|
18
18
|
IRB.conf[:HISTORY_FILE] = "#{ENV['HOME']}/.reo-history"
|
19
19
|
|
20
20
|
module Readline # :nodoc: #
|
21
21
|
module Hist # :nodoc: #
|
22
22
|
LOG = IRB.conf[:HISTORY_FILE]
|
23
|
-
# LOG = "#{ENV['HOME']}/.irb-history"
|
23
|
+
# LOG = "#{ENV['HOME']}/.irb-history"
|
24
24
|
|
25
25
|
def self.write_log(line)
|
26
|
-
File.open(LOG, 'ab')
|
27
|
-
"}
|
26
|
+
File.open(LOG, 'ab') do |f|
|
27
|
+
f << "#{line}
|
28
|
+
"
|
29
|
+
end
|
28
30
|
end
|
29
31
|
|
30
32
|
def self.start_session_log
|
31
|
-
timestamp = proc{ Time.now.strftime(
|
32
|
-
class <<timestamp
|
33
|
-
|
34
|
-
end
|
35
|
-
write_log(
|
33
|
+
timestamp = proc { Time.now.strftime('%Y-%m-%d, %H:%M:%S') }
|
34
|
+
class <<timestamp # :nodoc: #
|
35
|
+
alias_method :to_s, :call
|
36
|
+
end
|
37
|
+
write_log("###### session start: #{timestamp}")
|
36
38
|
at_exit { write_log("###### session stop: #{timestamp}") }
|
37
39
|
end
|
38
40
|
end
|
39
41
|
|
40
|
-
alias
|
42
|
+
alias old_readline readline
|
41
43
|
def readline(*args)
|
42
44
|
ln = old_readline(*args)
|
43
45
|
begin
|
44
46
|
Hist.write_log(ln)
|
45
|
-
rescue
|
47
|
+
rescue StandardError
|
46
48
|
end
|
47
49
|
ln
|
48
50
|
end
|
49
51
|
end
|
50
52
|
|
51
53
|
Readline::Hist.start_session_log
|
52
|
-
puts
|
54
|
+
puts 'REO console started'
|
data/lib/robust_excel_ole.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'win32ole'
|
2
2
|
require File.join(File.dirname(__FILE__), 'robust_excel_ole/reo_common')
|
3
3
|
require File.join(File.dirname(__FILE__), 'robust_excel_ole/general')
|
4
4
|
require File.join(File.dirname(__FILE__), 'robust_excel_ole/excel')
|
@@ -10,4 +10,3 @@ require File.join(File.dirname(__FILE__), 'robust_excel_ole/range')
|
|
10
10
|
require File.join(File.dirname(__FILE__), 'robust_excel_ole/cygwin') if RUBY_PLATFORM =~ /cygwin/
|
11
11
|
#+#require "robust_excel_ole/version"
|
12
12
|
require File.join(File.dirname(__FILE__), 'robust_excel_ole/version')
|
13
|
-
#
|
@@ -1,12 +1,10 @@
|
|
1
|
-
|
2
1
|
# -*- coding: utf-8 -*-
|
3
2
|
|
4
3
|
module RobustExcelOle
|
5
4
|
|
6
5
|
class Bookstore < REOCommon
|
7
|
-
|
8
6
|
def initialize
|
9
|
-
@filename2books ||= Hash.new {|hash, key| hash[key] = [] }
|
7
|
+
@filename2books ||= Hash.new { |hash, key| hash[key] = [] }
|
10
8
|
@hidden_excel_instance = nil
|
11
9
|
end
|
12
10
|
|
@@ -20,50 +18,53 @@ module RobustExcelOle
|
|
20
18
|
# options: :prefer_writable returns the writable book, if it is open (default: true)
|
21
19
|
# otherwise returns the book according to the preference order mentioned above
|
22
20
|
# :prefer_excel returns the book in the given Excel instance, if it exists,
|
23
|
-
# otherwise proceeds according to prefer_writable
|
24
|
-
def fetch(filename, options = {:prefer_writable => true })
|
21
|
+
# otherwise proceeds according to prefer_writable
|
22
|
+
def fetch(filename, options = { :prefer_writable => true })
|
25
23
|
return nil unless filename
|
26
|
-
|
27
|
-
|
24
|
+
|
25
|
+
filename = General.absolute_path(filename)
|
26
|
+
filename_key = General.canonize(filename)
|
28
27
|
weakref_books = @filename2books[filename_key]
|
29
28
|
return nil unless weakref_books
|
30
|
-
|
31
|
-
|
29
|
+
|
30
|
+
result = open_book = closed_book = nil
|
31
|
+
weakref_books = weakref_books.map { |wr_book| wr_book if wr_book.weakref_alive? }.compact
|
32
32
|
@filename2books[filename_key] = weakref_books
|
33
33
|
weakref_books.each do |wr_book|
|
34
|
-
if
|
35
|
-
#trace "warn: this should never happen"
|
36
|
-
begin
|
34
|
+
if !wr_book.weakref_alive?
|
35
|
+
# trace "warn: this should never happen"
|
36
|
+
begin
|
37
37
|
@filename2books[filename_key].delete(wr_book)
|
38
|
-
rescue
|
39
|
-
#trace "#{$!.message}"
|
40
|
-
#trace "Warning: deleting dead reference failed: file: #{filename.inspect}"
|
38
|
+
rescue
|
39
|
+
# trace "#{$!.message}"
|
40
|
+
# trace "Warning: deleting dead reference failed: file: #{filename.inspect}"
|
41
41
|
end
|
42
42
|
else
|
43
43
|
book = wr_book.__getobj__
|
44
44
|
next if book.excel == try_hidden_excel
|
45
|
+
|
45
46
|
if options[:prefer_excel] && book.excel == options[:prefer_excel]
|
46
47
|
result = book
|
47
|
-
break
|
48
|
+
break
|
48
49
|
end
|
49
50
|
if book.alive?
|
50
51
|
open_book = book
|
51
|
-
break if
|
52
|
+
break if book.writable && options[:prefer_writable]
|
52
53
|
else
|
53
54
|
closed_book = book
|
54
55
|
end
|
55
56
|
end
|
56
57
|
end
|
57
|
-
result
|
58
|
-
result
|
58
|
+
result ||= (open_book || closed_book)
|
59
|
+
result
|
59
60
|
end
|
60
61
|
|
61
62
|
# stores a workbook
|
62
63
|
# @param [Workbook] book a given book
|
63
64
|
def store(book)
|
64
|
-
filename_key = General
|
65
|
+
filename_key = General.canonize(book.filename)
|
65
66
|
if book.stored_filename
|
66
|
-
old_filename_key = General
|
67
|
+
old_filename_key = General.canonize(book.stored_filename)
|
67
68
|
# deletes the weak reference to the book
|
68
69
|
@filename2books[old_filename_key].delete(book)
|
69
70
|
end
|
@@ -72,9 +73,9 @@ module RobustExcelOle
|
|
72
73
|
end
|
73
74
|
|
74
75
|
# creates and returns a separate Excel instance with Visible and DisplayAlerts equal false
|
75
|
-
def hidden_excel
|
76
|
-
unless
|
77
|
-
@hidden_excel_instance = WeakRef.new(Excel.create)
|
76
|
+
def hidden_excel # :nodoc: #
|
77
|
+
unless @hidden_excel_instance && @hidden_excel_instance.weakref_alive? && @hidden_excel_instance.__getobj__.alive?
|
78
|
+
@hidden_excel_instance = WeakRef.new(Excel.create)
|
78
79
|
end
|
79
80
|
@hidden_excel_instance.__getobj__
|
80
81
|
end
|
@@ -83,50 +84,49 @@ module RobustExcelOle
|
|
83
84
|
def books
|
84
85
|
result = []
|
85
86
|
if @filename2books
|
86
|
-
@filename2books.each do |
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
87
|
+
@filename2books.each do |_filename,books|
|
88
|
+
next if books.empty?
|
89
|
+
|
90
|
+
books.each do |wr_book|
|
91
|
+
result << wr_book.__getobj__ if wr_book.weakref_alive?
|
91
92
|
end
|
92
|
-
end
|
93
|
+
end
|
93
94
|
end
|
94
95
|
result
|
95
96
|
end
|
96
97
|
|
97
|
-
|
98
|
+
private
|
98
99
|
|
99
|
-
def try_hidden_excel
|
100
|
-
@hidden_excel_instance.__getobj__ if
|
100
|
+
def try_hidden_excel # :nodoc: #
|
101
|
+
@hidden_excel_instance.__getobj__ if @hidden_excel_instance && @hidden_excel_instance.weakref_alive? && @hidden_excel_instance.__getobj__.alive?
|
101
102
|
end
|
102
103
|
|
103
|
-
|
104
|
+
public
|
104
105
|
|
105
106
|
# prints the book store
|
106
|
-
def print
|
107
|
-
#trace "@filename2books:"
|
107
|
+
def print # :nodoc: #
|
108
|
+
# trace "@filename2books:"
|
108
109
|
if @filename2books
|
109
|
-
@filename2books.each do |
|
110
|
-
#trace " filename: #{filename}"
|
111
|
-
#trace " books:"
|
112
|
-
if books.empty?
|
113
|
-
#trace " []"
|
110
|
+
@filename2books.each do |_filename,books|
|
111
|
+
# trace " filename: #{filename}"
|
112
|
+
# trace " books:"
|
113
|
+
if books.empty?
|
114
|
+
# trace " []"
|
114
115
|
else
|
115
116
|
books.each do |book|
|
116
117
|
if book.weakref_alive?
|
117
|
-
#trace "#{book}"
|
118
|
+
# trace "#{book}"
|
118
119
|
else # this should never happen
|
119
|
-
#trace "weakref not alive"
|
120
|
+
# trace "weakref not alive"
|
120
121
|
end
|
121
122
|
end
|
122
123
|
end
|
123
124
|
end
|
124
125
|
end
|
125
126
|
end
|
126
|
-
|
127
127
|
end
|
128
128
|
|
129
129
|
class BookstoreError < WIN32OLERuntimeError # :nodoc: #
|
130
130
|
end
|
131
|
-
|
131
|
+
|
132
132
|
end
|
@@ -5,28 +5,27 @@ module RobustExcelOle
|
|
5
5
|
attr_reader :cell
|
6
6
|
|
7
7
|
def initialize(win32_cell)
|
8
|
-
if win32_cell.MergeCells
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
8
|
+
@cell = if win32_cell.MergeCells
|
9
|
+
win32_cell.MergeArea.Item(1,1)
|
10
|
+
else
|
11
|
+
win32_cell
|
12
|
+
end
|
13
13
|
end
|
14
14
|
|
15
|
-
def method_missing(name, *args)
|
16
|
-
if name.to_s[0,1] =~ /[A-Z]/
|
15
|
+
def method_missing(name, *args) # :nodoc: #
|
16
|
+
#if name.to_s[0,1] =~ /[A-Z]/
|
17
17
|
begin
|
18
18
|
@cell.send(name, *args)
|
19
19
|
rescue WIN32OLERuntimeError => msg
|
20
20
|
if msg.message =~ /unknown property or method/
|
21
21
|
raise VBAMethodMissingError, "unknown VBA property or method #{name.inspect}"
|
22
|
-
else
|
22
|
+
else
|
23
23
|
raise msg
|
24
24
|
end
|
25
25
|
end
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
# else
|
27
|
+
# super
|
28
|
+
# end
|
29
29
|
end
|
30
|
-
|
31
30
|
end
|
32
31
|
end
|
@@ -11,27 +11,27 @@ module RobustExcelOle
|
|
11
11
|
@conv_to_win32_path =
|
12
12
|
Win32API.new('cygwin1.dll', 'cygwin_conv_to_win32_path', 'PP', 'I')
|
13
13
|
|
14
|
-
def cygpath(options, path)
|
14
|
+
def cygpath(options, path) # :nodoc: #
|
15
15
|
absolute = shortname = false
|
16
16
|
func = nil
|
17
|
-
options.delete(" \t-").chars
|
17
|
+
options.delete(" \t-").chars do |opt|
|
18
18
|
case opt
|
19
|
-
when
|
19
|
+
when 'u'
|
20
20
|
func = [@conv_to_full_posix_path, @conv_to_posix_path]
|
21
|
-
when
|
21
|
+
when 'w'
|
22
22
|
func = [@conv_to_full_win32_path, @conv_to_win32_path]
|
23
|
-
when
|
23
|
+
when 'a'
|
24
24
|
absolute = true
|
25
|
-
when
|
25
|
+
when 's'
|
26
26
|
shortname = true
|
27
27
|
end
|
28
|
-
|
29
|
-
raise
|
28
|
+
end
|
29
|
+
raise 'first argument must contain -u or -w' if func.nil?
|
30
|
+
|
30
31
|
func = absolute ? func[0] : func[1]
|
31
32
|
buf = "\0" * 300
|
32
|
-
if func.Call(path, buf) == -1
|
33
|
-
|
34
|
-
end
|
33
|
+
raise 'cannot convert path name' if func.Call(path, buf) == -1
|
34
|
+
|
35
35
|
buf.delete!("\0")
|
36
36
|
buf
|
37
37
|
end
|
@@ -3,17 +3,15 @@
|
|
3
3
|
require 'weakref'
|
4
4
|
require 'Win32API'
|
5
5
|
|
6
|
-
def ka
|
6
|
+
def ka
|
7
7
|
Excel.kill_all
|
8
8
|
end
|
9
9
|
|
10
|
-
|
11
|
-
module RobustExcelOle
|
10
|
+
module RobustExcelOle
|
12
11
|
|
13
12
|
# see https://docs.microsoft.com/en-us/office/vba/api/excel.application(object)#methods
|
14
13
|
|
15
|
-
class Excel < RangeOwners
|
16
|
-
|
14
|
+
class Excel < RangeOwners
|
17
15
|
attr_accessor :ole_excel
|
18
16
|
attr_accessor :created
|
19
17
|
attr_accessor :workbook
|
@@ -23,75 +21,75 @@ module RobustExcelOle
|
|
23
21
|
attr_reader :displayalerts
|
24
22
|
attr_reader :calculation
|
25
23
|
attr_reader :screenupdating
|
26
|
-
|
24
|
+
|
27
25
|
alias ole_object ole_excel
|
28
26
|
|
29
|
-
@@hwnd2excel = {}
|
27
|
+
@@hwnd2excel = {}
|
30
28
|
|
31
29
|
# creates a new Excel instance
|
32
30
|
# @param [Hash] options the options
|
33
|
-
# @option options [Variant] :displayalerts
|
31
|
+
# @option options [Variant] :displayalerts
|
34
32
|
# @option options [Boolean] :visible
|
35
33
|
# @option options [Symbol] :calculation
|
36
34
|
# @option options [Boolean] :screenupdating
|
37
35
|
# @return [Excel] a new Excel instance
|
38
36
|
def self.create(options = {})
|
39
|
-
new(options.merge(
|
37
|
+
new(options.merge(:reuse => false))
|
40
38
|
end
|
41
39
|
|
42
|
-
# connects to the current (first opened) Excel instance, if such a running Excel instance exists
|
40
|
+
# connects to the current (first opened) Excel instance, if such a running Excel instance exists
|
43
41
|
# returns a new Excel instance, otherwise
|
44
|
-
# @option options [Variant] :displayalerts
|
45
|
-
# @option options [Boolean] :visible
|
42
|
+
# @option options [Variant] :displayalerts
|
43
|
+
# @option options [Boolean] :visible
|
46
44
|
# @option options [Symbol] :calculation
|
47
45
|
# @option options [Boolean] :screenupdating
|
48
46
|
# @return [Excel] an Excel instance
|
49
47
|
def self.current(options = {})
|
50
|
-
new(options.merge(
|
48
|
+
new(options.merge(:reuse => true))
|
51
49
|
end
|
52
50
|
|
53
|
-
# returns an Excel instance
|
51
|
+
# returns an Excel instance
|
54
52
|
# @param [Win32Ole] (optional) a WIN32OLE object representing an Excel instance
|
55
53
|
# @param [Hash] options the options
|
56
|
-
# @option options [Boolean] :reuse
|
54
|
+
# @option options [Boolean] :reuse
|
57
55
|
# @option options [Boolean] :visible
|
58
|
-
# @option options [Variant] :displayalerts
|
59
|
-
# @option options [Boolean] :screenupdating
|
56
|
+
# @option options [Variant] :displayalerts
|
57
|
+
# @option options [Boolean] :screenupdating
|
60
58
|
# @option options [Symbol] :calculation
|
61
|
-
# options:
|
59
|
+
# options:
|
62
60
|
# :reuse connects to an already running Excel instance (true) or
|
63
61
|
# creates a new Excel instance (false) (default: true)
|
64
62
|
# :visible makes the Excel visible (default: false)
|
65
|
-
# :displayalerts enables or disables DisplayAlerts (true, false, :if_visible (default))
|
63
|
+
# :displayalerts enables or disables DisplayAlerts (true, false, :if_visible (default))
|
66
64
|
# :calculation calculation mode is being forced to be manual (:manual) or automatic (:automtic)
|
67
65
|
# or is not being forced (default: nil)
|
68
66
|
# :screenupdating turns on or off screen updating (default: true)
|
69
67
|
# @return [Excel] an Excel instance
|
70
|
-
def self.new(win32ole_excel = nil, options = {
|
68
|
+
def self.new(win32ole_excel = nil, options = {})
|
71
69
|
if win32ole_excel.is_a? Hash
|
72
70
|
options = win32ole_excel
|
73
71
|
win32ole_excel = nil
|
74
72
|
end
|
75
73
|
ole_xl = win32ole_excel unless win32ole_excel.nil?
|
76
|
-
options = {:reuse => true}.merge(options)
|
74
|
+
options = { :reuse => true }.merge(options)
|
77
75
|
ole_xl = current_excel if options[:reuse] == true
|
78
76
|
ole_xl ||= WIN32OLE.new('Excel.Application')
|
79
77
|
hwnd = ole_xl.HWnd
|
80
78
|
stored = hwnd2excel(hwnd)
|
81
|
-
if stored
|
79
|
+
if stored && stored.alive?
|
82
80
|
result = stored
|
83
|
-
else
|
81
|
+
else
|
84
82
|
result = super(options)
|
85
|
-
result.instance_variable_set(:@ole_excel, ole_xl)
|
83
|
+
result.instance_variable_set(:@ole_excel, ole_xl)
|
86
84
|
WIN32OLE.const_load(ole_xl, RobustExcelOle) unless RobustExcelOle.const_defined?(:CONSTANTS)
|
87
85
|
@@hwnd2excel[hwnd] = WeakRef.new(result)
|
88
86
|
end
|
89
|
-
|
87
|
+
|
90
88
|
unless options.is_a? WIN32OLE
|
91
89
|
begin
|
92
90
|
reused = options[:reuse] && stored && stored.alive?
|
93
91
|
unless reused
|
94
|
-
options = {:displayalerts => :if_visible, :visible => false, :screenupdating => true}.merge(options)
|
92
|
+
options = { :displayalerts => :if_visible, :visible => false, :screenupdating => true }.merge(options)
|
95
93
|
end
|
96
94
|
result.visible = options[:visible] unless options[:visible].nil?
|
97
95
|
result.displayalerts = options[:displayalerts] unless options[:displayalerts].nil?
|
@@ -99,12 +97,11 @@ module RobustExcelOle
|
|
99
97
|
result.screenupdating = options[:screenupdating] unless options[:screenupdating].nil?
|
100
98
|
result.created = !reused
|
101
99
|
end
|
102
|
-
end
|
100
|
+
end
|
103
101
|
result
|
104
102
|
end
|
105
103
|
|
106
|
-
def initialize(options= {})
|
107
|
-
end
|
104
|
+
def initialize(options = {}); end
|
108
105
|
|
109
106
|
# reopens a closed Excel instance
|
110
107
|
# @param [Hash] opts the options
|
@@ -115,72 +112,80 @@ module RobustExcelOle
|
|
115
112
|
# options: reopen_workbooks (default: false): reopen the workbooks in the Excel instances
|
116
113
|
# :visible (default: false), :displayalerts (default: :if_visible), :calculation (default: false)
|
117
114
|
# @return [Excel] an Excel instance
|
118
|
-
def recreate(opts = {})
|
119
|
-
unless
|
115
|
+
def recreate(opts = {})
|
116
|
+
unless alive?
|
120
117
|
opts = {
|
121
|
-
:visible => @visible
|
122
|
-
:displayalerts => @displayalerts
|
118
|
+
:visible => @visible || false,
|
119
|
+
:displayalerts => @displayalerts || :if_visible
|
123
120
|
}.merge(opts)
|
124
121
|
@ole_excel = WIN32OLE.new('Excel.Application')
|
125
122
|
self.visible = opts[:visible]
|
126
|
-
self.displayalerts = opts[:displayalerts]
|
123
|
+
self.displayalerts = opts[:displayalerts]
|
127
124
|
self.calculation = opts[:calculation]
|
128
125
|
if opts[:reopen_workbooks]
|
129
126
|
books = workbook_class.books
|
130
127
|
books.each do |book|
|
131
|
-
book.reopen if
|
132
|
-
end
|
128
|
+
book.reopen if !book.alive? && book.excel.alive? && book.excel == self
|
129
|
+
end
|
133
130
|
end
|
134
131
|
end
|
135
|
-
self
|
132
|
+
self
|
136
133
|
end
|
137
134
|
|
138
|
-
|
139
|
-
|
135
|
+
private
|
136
|
+
|
140
137
|
# returns a Win32OLE object that represents a Excel instance to which Excel connects
|
141
138
|
# connects to the first opened Excel instance
|
142
139
|
# if this Excel instance is being closed, then Excel creates a new Excel instance
|
143
|
-
def self.current_excel
|
144
|
-
result =
|
140
|
+
def self.current_excel # :nodoc: #
|
141
|
+
result = begin
|
142
|
+
WIN32OLE.connect('Excel.Application')
|
143
|
+
rescue
|
144
|
+
nil
|
145
|
+
end
|
145
146
|
if result
|
146
147
|
begin
|
147
|
-
result.Visible
|
148
|
-
rescue
|
149
|
-
trace
|
148
|
+
result.Visible # send any method, just to see if it responds
|
149
|
+
rescue
|
150
|
+
trace 'dead excel ' + (begin
|
151
|
+
"Window-handle = #{result.HWnd}"
|
152
|
+
rescue
|
153
|
+
'without window handle'
|
154
|
+
end)
|
150
155
|
return nil
|
151
156
|
end
|
152
157
|
end
|
153
158
|
result
|
154
159
|
end
|
155
160
|
|
156
|
-
|
161
|
+
public
|
157
162
|
|
158
163
|
# retain the saved status of all workbooks
|
159
164
|
def retain_saved_workbooks
|
160
165
|
saved = []
|
161
|
-
@ole_excel.Workbooks.each {|w| saved << w.Saved}
|
166
|
+
@ole_excel.Workbooks.each { |w| saved << w.Saved }
|
162
167
|
begin
|
163
168
|
yield self
|
164
169
|
ensure
|
165
170
|
i = 0
|
166
171
|
@ole_excel.Workbooks.each do |w|
|
167
172
|
w.Saved = saved[i] if saved[i]
|
168
|
-
i
|
173
|
+
i += 1
|
169
174
|
end
|
170
175
|
end
|
171
176
|
end
|
172
177
|
|
173
178
|
def self.contains_unsaved_workbooks?
|
174
|
-
|
179
|
+
!Excel.current.unsaved_workbooks.empty?
|
175
180
|
end
|
176
181
|
|
177
182
|
# returns unsaved workbooks (win32ole objects)
|
178
183
|
def unsaved_workbooks
|
179
|
-
unsaved_workbooks = []
|
180
|
-
begin
|
181
|
-
@ole_excel.Workbooks.each {|w| unsaved_workbooks << w unless
|
184
|
+
unsaved_workbooks = []
|
185
|
+
begin
|
186
|
+
@ole_excel.Workbooks.each { |w| unsaved_workbooks << w unless w.Saved || w.ReadOnly }
|
182
187
|
rescue RuntimeError => msg
|
183
|
-
raise ExcelDamaged,
|
188
|
+
raise ExcelDamaged, 'Excel instance not alive or damaged' if msg.message =~ /failed to get Dispatch Interface/
|
184
189
|
end
|
185
190
|
unsaved_workbooks
|
186
191
|
end
|
@@ -188,25 +193,26 @@ module RobustExcelOle
|
|
188
193
|
# closes workbooks
|
189
194
|
# @option options [Symbol] :if_unsaved :raise, :save, :forget, :alert, Proc
|
190
195
|
# :if_unsaved if unsaved workbooks are open in an Excel instance
|
191
|
-
# :raise (default) -> raises an exception
|
196
|
+
# :raise (default) -> raises an exception
|
192
197
|
# :save -> saves the workbooks before closing
|
193
|
-
# :forget -> closes the Excel instance without saving the workbooks
|
198
|
+
# :forget -> closes the Excel instance without saving the workbooks
|
194
199
|
# :alert -> let Excel do it
|
195
|
-
def close_workbooks(options = {:if_unsaved => :raise})
|
196
|
-
return
|
200
|
+
def close_workbooks(options = { :if_unsaved => :raise })
|
201
|
+
return unless alive?
|
202
|
+
|
197
203
|
weak_wkbks = @ole_excel.Workbooks
|
198
|
-
|
204
|
+
unless unsaved_workbooks.empty?
|
199
205
|
case options[:if_unsaved]
|
200
206
|
when Proc
|
201
207
|
options[:if_unsaved].call(self, unsaved_workbooks)
|
202
208
|
when :raise
|
203
|
-
raise UnsavedWorkbooks,
|
209
|
+
raise UnsavedWorkbooks, 'Excel contains unsaved workbooks'
|
204
210
|
when :alert
|
205
|
-
#nothing
|
211
|
+
# nothing
|
206
212
|
when :forget
|
207
|
-
unsaved_workbooks.each {|m| m.Saved = true}
|
213
|
+
unsaved_workbooks.each { |m| m.Saved = true }
|
208
214
|
when :save
|
209
|
-
unsaved_workbooks.each {|m| m.Save}
|
215
|
+
unsaved_workbooks.each { |m| m.Save }
|
210
216
|
else
|
211
217
|
raise OptionInvalid, ":if_unsaved: invalid option: #{options[:if_unsaved].inspect}"
|
212
218
|
end
|
@@ -215,11 +221,11 @@ module RobustExcelOle
|
|
215
221
|
@ole_excel.Workbooks.Close
|
216
222
|
rescue WIN32OLERuntimeError => msg
|
217
223
|
if msg.message =~ /800A03EC/
|
218
|
-
raise ExcelREOError,
|
219
|
-
else
|
224
|
+
raise ExcelREOError, 'user canceled or runtime error'
|
225
|
+
else
|
220
226
|
raise UnexpectedREOError, "unknown WIN32OLERuntimeError: #{msg.message}"
|
221
227
|
end
|
222
|
-
end
|
228
|
+
end
|
223
229
|
weak_wkbks = nil
|
224
230
|
weak_wkbks = @ole_excel.Workbooks
|
225
231
|
weak_wkbks = nil
|
@@ -233,12 +239,12 @@ module RobustExcelOle
|
|
233
239
|
# @option options [Symbol] :if_unsaved :raise, :save, :forget, or :alert
|
234
240
|
# options:
|
235
241
|
# :if_unsaved if unsaved workbooks are open in an Excel instance
|
236
|
-
# :raise (default) -> raises an exception
|
242
|
+
# :raise (default) -> raises an exception
|
237
243
|
# :save -> saves the workbooks before closing
|
238
|
-
# :forget -> closes the excel instance without saving the workbooks
|
244
|
+
# :forget -> closes the excel instance without saving the workbooks
|
239
245
|
# :alert -> give control to Excel
|
240
246
|
# @option options [Proc] block
|
241
|
-
def self.close_all(options = {:if_unsaved => :raise}, &blk)
|
247
|
+
def self.close_all(options = { :if_unsaved => :raise }, &blk)
|
242
248
|
options[:if_unsaved] = blk if blk
|
243
249
|
finished_number = error_number = overall_number = 0
|
244
250
|
first_error = nil
|
@@ -248,8 +254,8 @@ module RobustExcelOle
|
|
248
254
|
overall_number += 1
|
249
255
|
finished_number += excel.close(:if_unsaved => options[:if_unsaved])
|
250
256
|
rescue
|
251
|
-
first_error =
|
252
|
-
#trace "error when finishing #{$!}"
|
257
|
+
first_error = $ERROR_INFO
|
258
|
+
# trace "error when finishing #{$!}"
|
253
259
|
error_number += 1
|
254
260
|
end
|
255
261
|
end
|
@@ -264,22 +270,26 @@ module RobustExcelOle
|
|
264
270
|
finishing_action.call(excel)
|
265
271
|
end
|
266
272
|
else
|
267
|
-
@@hwnd2excel.delete(hwnd)
|
273
|
+
@@hwnd2excel.delete(hwnd)
|
268
274
|
end
|
269
275
|
end
|
270
276
|
|
271
277
|
# unknown Excel-instances
|
272
278
|
old_error_number = error_number
|
273
|
-
9.times do |
|
279
|
+
9.times do |_index|
|
274
280
|
sleep 0.1
|
275
|
-
excel =
|
281
|
+
excel = begin
|
282
|
+
new(WIN32OLE.connect('Excel.Application'))
|
283
|
+
rescue
|
284
|
+
nil
|
285
|
+
end
|
276
286
|
finishing_action.call(excel) if excel
|
277
|
-
free_all_ole_objects unless error_number > 0
|
278
|
-
break
|
279
|
-
break if error_number > old_error_number # + 3
|
287
|
+
free_all_ole_objects unless (error_number > 0) && (options[:if_unsaved] == :raise)
|
288
|
+
break unless excel
|
289
|
+
break if error_number > old_error_number # + 3
|
280
290
|
end
|
281
291
|
|
282
|
-
raise first_error if (options[:if_unsaved] == :raise
|
292
|
+
raise first_error if ((options[:if_unsaved] == :raise) && first_error) || (first_error.class == OptionInvalid)
|
283
293
|
|
284
294
|
[finished_number, error_number]
|
285
295
|
end
|
@@ -287,47 +297,51 @@ module RobustExcelOle
|
|
287
297
|
# closes the Excel
|
288
298
|
# @param [Hash] options the options
|
289
299
|
# @option options [Symbol] :if_unsaved :raise, :save, :forget, :alert
|
290
|
-
# @option options [Boolean] :hard
|
300
|
+
# @option options [Boolean] :hard
|
291
301
|
# :if_unsaved if unsaved workbooks are open in an Excel instance
|
292
|
-
# :raise (default) -> raises an exception
|
302
|
+
# :raise (default) -> raises an exception
|
293
303
|
# :save -> saves the workbooks before closing
|
294
|
-
# :forget -> closes the Excel instance without saving the workbooks
|
295
|
-
# :alert -> Excel takes over
|
296
|
-
def close(options = {:if_unsaved => :raise})
|
297
|
-
finishing_living_excel =
|
298
|
-
if finishing_living_excel
|
299
|
-
hwnd = (
|
304
|
+
# :forget -> closes the Excel instance without saving the workbooks
|
305
|
+
# :alert -> Excel takes over
|
306
|
+
def close(options = { :if_unsaved => :raise })
|
307
|
+
finishing_living_excel = alive?
|
308
|
+
if finishing_living_excel
|
309
|
+
hwnd = (begin
|
310
|
+
@ole_excel.HWnd
|
311
|
+
rescue
|
312
|
+
nil
|
313
|
+
end)
|
300
314
|
close_workbooks(:if_unsaved => options[:if_unsaved])
|
301
315
|
@ole_excel.Quit
|
302
|
-
if false
|
316
|
+
if false && defined?(weak_wkbks) && weak_wkbks.weakref_alive?
|
303
317
|
weak_wkbks.ole_free
|
304
318
|
end
|
305
319
|
weak_xl = WeakRef.new(@ole_excel)
|
306
320
|
else
|
307
321
|
weak_xl = nil
|
308
|
-
end
|
322
|
+
end
|
309
323
|
@ole_excel = nil
|
310
324
|
GC.start
|
311
325
|
sleep 0.1
|
312
|
-
if finishing_living_excel
|
313
|
-
if hwnd
|
314
|
-
process_id = Win32API.new(
|
315
|
-
pid_puffer =
|
326
|
+
if finishing_living_excel
|
327
|
+
if hwnd
|
328
|
+
process_id = Win32API.new('user32', 'GetWindowThreadProcessId', %w[I P], 'I')
|
329
|
+
pid_puffer = ' ' * 32
|
316
330
|
process_id.call(hwnd, pid_puffer)
|
317
|
-
pid = pid_puffer.unpack(
|
331
|
+
pid = pid_puffer.unpack('L')[0]
|
318
332
|
begin
|
319
|
-
Process.kill(
|
320
|
-
rescue
|
321
|
-
#trace "kill_error: #{$!}"
|
333
|
+
Process.kill('KILL', pid)
|
334
|
+
rescue
|
335
|
+
# trace "kill_error: #{$!}"
|
322
336
|
end
|
323
337
|
end
|
324
338
|
@@hwnd2excel.delete(hwnd)
|
325
|
-
if weak_xl.weakref_alive?
|
326
|
-
|
339
|
+
if weak_xl.weakref_alive?
|
340
|
+
# if WIN32OLE.ole_reference_count(weak_xlapp) > 0
|
327
341
|
begin
|
328
342
|
weak_xl.ole_free
|
329
343
|
rescue
|
330
|
-
#trace "weakref_probl_olefree"
|
344
|
+
# trace "weakref_probl_olefree"
|
331
345
|
end
|
332
346
|
end
|
333
347
|
end
|
@@ -335,43 +349,42 @@ module RobustExcelOle
|
|
335
349
|
end
|
336
350
|
|
337
351
|
# frees all OLE objects in the object space
|
338
|
-
def self.free_all_ole_objects
|
352
|
+
def self.free_all_ole_objects # :nodoc: #
|
339
353
|
anz_objekte = 0
|
340
|
-
ObjectSpace.each_object(WIN32OLE) do |o|
|
354
|
+
ObjectSpace.each_object(WIN32OLE) do |o|
|
341
355
|
anz_objekte += 1
|
342
|
-
#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}"
|
343
|
-
#trace [:Name, (o.Name rescue (o.Count rescue "no_name"))]
|
344
|
-
#trace [:ole_object_name, (o.ole_object_name rescue nil)]
|
345
|
-
#trace [:methods, (o.ole_methods rescue nil)] unless (o.Name rescue false)
|
346
|
-
#trace o.ole_type rescue nil
|
356
|
+
# 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}"
|
357
|
+
# trace [:Name, (o.Name rescue (o.Count rescue "no_name"))]
|
358
|
+
# trace [:ole_object_name, (o.ole_object_name rescue nil)]
|
359
|
+
# trace [:methods, (o.ole_methods rescue nil)] unless (o.Name rescue false)
|
360
|
+
# trace o.ole_type rescue nil
|
347
361
|
begin
|
348
362
|
o.ole_free
|
349
|
-
#trace "olefree OK"
|
363
|
+
# trace "olefree OK"
|
350
364
|
rescue
|
351
|
-
#trace "olefree_error: #{$!}"
|
352
|
-
#trace $!.backtrace.first(9).join "\n"
|
365
|
+
# trace "olefree_error: #{$!}"
|
366
|
+
# trace $!.backtrace.first(9).join "\n"
|
353
367
|
end
|
354
368
|
end
|
355
|
-
#trace "went through #{anz_objekte} OLE objects"
|
356
|
-
end
|
357
|
-
|
369
|
+
# trace "went through #{anz_objekte} OLE objects"
|
370
|
+
end
|
358
371
|
|
359
372
|
def self.init
|
360
373
|
@@hwnd2excel = {}
|
361
|
-
end
|
374
|
+
end
|
362
375
|
|
363
376
|
# kill all Excel instances
|
364
377
|
# @return [Integer] number of killed Excel processes
|
365
378
|
def self.kill_all
|
366
379
|
number = 0
|
367
|
-
WIN32OLE.connect(
|
380
|
+
WIN32OLE.connect('winmgmts:\\\\.').InstancesOf('win32_process').each do |p|
|
368
381
|
begin
|
369
|
-
if p.name ==
|
370
|
-
Process.kill('KILL', p.processid)
|
382
|
+
if p.name == 'EXCEL.EXE'
|
383
|
+
Process.kill('KILL', p.processid)
|
371
384
|
number += 1
|
372
385
|
end
|
373
|
-
rescue
|
374
|
-
|
386
|
+
rescue
|
387
|
+
# trace "kill error: #{$!}"
|
375
388
|
end
|
376
389
|
end
|
377
390
|
init
|
@@ -379,53 +392,53 @@ module RobustExcelOle
|
|
379
392
|
end
|
380
393
|
|
381
394
|
def self.excels_number
|
382
|
-
processes = WIN32OLE.connect(
|
383
|
-
processes.select{ |p| p.name ==
|
395
|
+
processes = WIN32OLE.connect('winmgmts:\\\\.').InstancesOf('win32_process')
|
396
|
+
processes.select { |p| p.name == 'EXCEL.EXE' }.size
|
384
397
|
end
|
385
398
|
|
386
399
|
# returns all Excel objects for all Excel instances opened with RobustExcelOle,
|
387
400
|
def self.known_excel_instances
|
388
401
|
pid2excel = {}
|
389
402
|
@@hwnd2excel.each do |hwnd,wr_excel|
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
403
|
+
next unless wr_excel.weakref_alive?
|
404
|
+
|
405
|
+
excel = wr_excel.__getobj__
|
406
|
+
process_id = Win32API.new('user32', 'GetWindowThreadProcessId', %w[I P], 'I')
|
407
|
+
pid_puffer = ' ' * 32
|
408
|
+
process_id.call(hwnd, pid_puffer)
|
409
|
+
pid = pid_puffer.unpack('L')[0]
|
410
|
+
pid2excel[pid] = excel
|
398
411
|
end
|
399
|
-
processes = WIN32OLE.connect(
|
400
|
-
#excel_processes = processes.select{ |p| p.name == "EXCEL.EXE" && pid2excel.include?(p.processid)}
|
401
|
-
#excel_processes.map{ |p| Excel.new(pid2excel[p.processid]) }
|
402
|
-
processes.select{ |p| Excel.new(pid2excel[p.processid]) if p.name ==
|
412
|
+
processes = WIN32OLE.connect('winmgmts:\\\\.').InstancesOf('win32_process')
|
413
|
+
# excel_processes = processes.select{ |p| p.name == "EXCEL.EXE" && pid2excel.include?(p.processid)}
|
414
|
+
# excel_processes.map{ |p| Excel.new(pid2excel[p.processid]) }
|
415
|
+
processes.select { |p| Excel.new(pid2excel[p.processid]) if p.name == 'EXCEL.EXE' && pid2excel.include?(p.processid) }
|
403
416
|
result = []
|
404
417
|
processes.each do |p|
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
# how to connect to an (interactively opened) Excel instance and get a WIN32OLE object?
|
411
|
-
# after that, lift it to an Excel object
|
418
|
+
next unless p.name == 'EXCEL.EXE'
|
419
|
+
|
420
|
+
if pid2excel.include?(p.processid)
|
421
|
+
excel = pid2excel[p.processid]
|
422
|
+
result << excel
|
412
423
|
end
|
424
|
+
# how to connect to an (interactively opened) Excel instance and get a WIN32OLE object?
|
425
|
+
# after that, lift it to an Excel object
|
413
426
|
end
|
414
427
|
result
|
415
428
|
end
|
416
429
|
|
417
|
-
def excel
|
430
|
+
def excel # :nodoc: #
|
418
431
|
self
|
419
432
|
end
|
420
433
|
|
421
|
-
def self.hwnd2excel(hwnd)
|
434
|
+
def self.hwnd2excel(hwnd) # :nodoc: #
|
422
435
|
excel_weakref = @@hwnd2excel[hwnd]
|
423
436
|
if excel_weakref
|
424
437
|
if excel_weakref.weakref_alive?
|
425
438
|
excel_weakref.__getobj__
|
426
439
|
else
|
427
|
-
trace
|
428
|
-
begin
|
440
|
+
trace 'dead reference to an Excel'
|
441
|
+
begin
|
429
442
|
@@hwnd2excel.delete(hwnd)
|
430
443
|
nil
|
431
444
|
rescue
|
@@ -435,13 +448,15 @@ module RobustExcelOle
|
|
435
448
|
end
|
436
449
|
end
|
437
450
|
|
438
|
-
def hwnd
|
439
|
-
self.Hwnd
|
451
|
+
def hwnd # :nodoc: #
|
452
|
+
self.Hwnd
|
453
|
+
rescue
|
454
|
+
nil
|
440
455
|
end
|
441
456
|
|
442
|
-
def self.print_hwnd2excel
|
457
|
+
def self.print_hwnd2excel # :nodoc: #
|
443
458
|
@@hwnd2excel.each do |hwnd,wr_excel|
|
444
|
-
excel_string = (wr_excel.weakref_alive? ? wr_excel.__getobj__.to_s :
|
459
|
+
excel_string = (wr_excel.weakref_alive? ? wr_excel.__getobj__.to_s : 'weakref not alive')
|
445
460
|
printf("hwnd: %8i => excel: %s\n", hwnd, excel_string)
|
446
461
|
end
|
447
462
|
@@hwnd2excel.size
|
@@ -449,7 +464,7 @@ module RobustExcelOle
|
|
449
464
|
|
450
465
|
# returns true, if the Excel instances are alive and identical, false otherwise
|
451
466
|
def == other_excel
|
452
|
-
self.Hwnd == other_excel.Hwnd
|
467
|
+
self.Hwnd == other_excel.Hwnd if other_excel.is_a?(Excel) && alive? && other_excel.alive?
|
453
468
|
end
|
454
469
|
|
455
470
|
# returns true, if the Excel instances responds to VBA methods, false otherwise
|
@@ -457,67 +472,67 @@ module RobustExcelOle
|
|
457
472
|
@ole_excel.Name
|
458
473
|
true
|
459
474
|
rescue
|
460
|
-
#trace $!.message
|
475
|
+
# trace $!.message
|
461
476
|
false
|
462
477
|
end
|
463
478
|
|
464
|
-
|
465
479
|
# returns unsaved workbooks in known (not opened by user) Excel instances
|
466
|
-
def self.unsaved_known_workbooks
|
480
|
+
def self.unsaved_known_workbooks # :nodoc: #
|
467
481
|
result = []
|
468
|
-
@@hwnd2excel.each do |
|
482
|
+
@@hwnd2excel.each do |_hwnd,wr_excel|
|
469
483
|
excel = wr_excel.__getobj__ if wr_excel.weakref_alive?
|
470
484
|
result << excel.unsaved_workbooks
|
471
485
|
end
|
472
486
|
result
|
473
487
|
end
|
474
488
|
|
475
|
-
def print_workbooks
|
476
|
-
self.Workbooks.each {|w| trace "#{w.Name} #{w}"}
|
489
|
+
def print_workbooks # :nodoc: #
|
490
|
+
self.Workbooks.each { |w| trace "#{w.Name} #{w}" }
|
477
491
|
end
|
478
492
|
|
479
493
|
# generates, saves, and closes empty workbook
|
480
|
-
def generate_workbook file_name
|
481
|
-
raise FileNameNotGiven,
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
494
|
+
def generate_workbook file_name # :nodoc: #
|
495
|
+
raise FileNameNotGiven, 'filename is nil' if file_name.nil?
|
496
|
+
|
497
|
+
self.Workbooks.Add
|
498
|
+
empty_workbook = self.Workbooks.Item(self.Workbooks.Count)
|
499
|
+
filename = General.absolute_path(file_name).tr('/','\\')
|
500
|
+
unless File.exist?(filename)
|
486
501
|
begin
|
487
|
-
empty_workbook.SaveAs(filename)
|
502
|
+
empty_workbook.SaveAs(filename)
|
488
503
|
rescue WIN32OLERuntimeError => msg
|
489
|
-
#if msg.message =~ /SaveAs/ and msg.message =~ /Workbook/ then
|
490
|
-
|
491
|
-
#else
|
492
|
-
# # todo some time: find out when this occurs :
|
504
|
+
# if msg.message =~ /SaveAs/ and msg.message =~ /Workbook/ then
|
505
|
+
raise FileNotFound, "could not save workbook with filename #{file_name.inspect}"
|
506
|
+
# else
|
507
|
+
# # todo some time: find out when this occurs :
|
493
508
|
# raise UnexpectedREOError, "unknown WIN32OLERuntimeError with filename #{file_name.inspect}: \n#{msg.message}"
|
494
|
-
#end
|
495
|
-
end
|
509
|
+
# end
|
510
|
+
end
|
496
511
|
end
|
497
|
-
empty_workbook
|
512
|
+
empty_workbook
|
498
513
|
end
|
499
514
|
|
500
515
|
# sets DisplayAlerts in a block
|
501
516
|
def with_displayalerts displayalerts_value
|
502
|
-
old_displayalerts =
|
517
|
+
old_displayalerts = displayalerts
|
503
518
|
self.displayalerts = displayalerts_value
|
504
519
|
begin
|
505
|
-
|
520
|
+
yield self
|
506
521
|
ensure
|
507
522
|
self.displayalerts = old_displayalerts if alive?
|
508
523
|
end
|
509
|
-
end
|
524
|
+
end
|
510
525
|
|
511
526
|
# makes the current Excel instance visible or invisible
|
512
527
|
def visible= visible_value
|
513
528
|
@ole_excel.Visible = @visible = visible_value
|
514
529
|
@ole_excel.DisplayAlerts = @visible if @displayalerts == :if_visible
|
515
|
-
end
|
530
|
+
end
|
516
531
|
|
517
532
|
# enables DisplayAlerts in the current Excel instance
|
518
533
|
def displayalerts= displayalerts_value
|
519
534
|
@displayalerts = displayalerts_value
|
520
|
-
@ole_excel.DisplayAlerts =
|
535
|
+
@ole_excel.DisplayAlerts = @displayalerts == :if_visible ? @ole_excel.Visible : displayalerts_value
|
521
536
|
end
|
522
537
|
|
523
538
|
# sets ScreenUpdating
|
@@ -529,20 +544,21 @@ module RobustExcelOle
|
|
529
544
|
# retains the saved-status of the workbooks when set to manual
|
530
545
|
def calculation= calculation_mode
|
531
546
|
return if calculation_mode.nil?
|
547
|
+
|
532
548
|
@calculation = calculation_mode
|
533
|
-
calc_mode_changable = @ole_excel.Workbooks.Count > 0 &&
|
549
|
+
calc_mode_changable = @ole_excel.Workbooks.Count > 0 && @ole_excel.Calculation.is_a?(Integer)
|
534
550
|
if calc_mode_changable
|
535
|
-
if calculation_mode == :manual
|
551
|
+
if calculation_mode == :manual
|
536
552
|
saved = []
|
537
|
-
(1..@ole_excel.Workbooks.Count).each {|i| saved << @ole_excel.Workbooks(i).Saved}
|
553
|
+
(1..@ole_excel.Workbooks.Count).each { |i| saved << @ole_excel.Workbooks(i).Saved }
|
538
554
|
end
|
539
555
|
@ole_excel.CalculateBeforeSave = false
|
540
|
-
@ole_excel.Calculation =
|
541
|
-
|
542
|
-
if calculation_mode == :manual
|
543
|
-
(1..@ole_excel.Workbooks.Count).each {|i| @ole_excel.Workbooks(i).Saved = true if saved[i-1]}
|
556
|
+
@ole_excel.Calculation =
|
557
|
+
calculation_mode == :automatic ? XlCalculationAutomatic : XlCalculationManual
|
558
|
+
if calculation_mode == :manual
|
559
|
+
(1..@ole_excel.Workbooks.Count).each { |i| @ole_excel.Workbooks(i).Saved = true if saved[i - 1] }
|
544
560
|
end
|
545
|
-
end
|
561
|
+
end
|
546
562
|
end
|
547
563
|
|
548
564
|
# VBA method overwritten
|
@@ -559,6 +575,7 @@ module RobustExcelOle
|
|
559
575
|
# sets calculation mode in a block
|
560
576
|
def with_calculation(calculation_mode)
|
561
577
|
return unless calculation_mode
|
578
|
+
|
562
579
|
old_calculation_mode = @ole_excel.Calculation
|
563
580
|
begin
|
564
581
|
self.calculation = calculation_mode
|
@@ -583,10 +600,10 @@ module RobustExcelOle
|
|
583
600
|
@ole_excel.Workbooks
|
584
601
|
rescue WIN32OLERuntimeError => msg
|
585
602
|
if msg.message =~ /failed to get Dispatch Interface/
|
586
|
-
raise ExcelDamaged,
|
603
|
+
raise ExcelDamaged, 'Excel instance not alive or damaged'
|
587
604
|
else
|
588
|
-
raise ExcelREOError,
|
589
|
-
end
|
605
|
+
raise ExcelREOError, 'workbooks could not be determined'
|
606
|
+
end
|
590
607
|
end
|
591
608
|
ole_workbooks.each do |ole_workbook|
|
592
609
|
workbook_class.open(ole_workbook).for_this_workbook(options)
|
@@ -595,11 +612,11 @@ module RobustExcelOle
|
|
595
612
|
|
596
613
|
def focus
|
597
614
|
self.visible = true
|
598
|
-
#if not Windows10 then
|
599
|
-
Win32API.new(
|
600
|
-
#else
|
601
|
-
#Win32API.new("user32","SetForegroundWindow","","I").call
|
602
|
-
#end
|
615
|
+
# if not Windows10 then
|
616
|
+
Win32API.new('user32','SetForegroundWindow','I','I').call(@ole_excel.Hwnd)
|
617
|
+
# else
|
618
|
+
# Win32API.new("user32","SetForegroundWindow","","I").call
|
619
|
+
# end
|
603
620
|
end
|
604
621
|
|
605
622
|
# returns the value of a range
|
@@ -612,21 +629,21 @@ module RobustExcelOle
|
|
612
629
|
# sets the value of a range
|
613
630
|
# @param [String] name the name of the range
|
614
631
|
# @param [Variant] value the contents of the range
|
615
|
-
def []=
|
632
|
+
def []=(name, value)
|
616
633
|
set_namevalue_glob(name,value, :color => 42) # 42 - aqua-marin, 7-green
|
617
634
|
end
|
618
635
|
|
619
636
|
def to_s # :nodoc: #
|
620
|
-
|
637
|
+
'#<Excel: ' + hwnd.to_s + ('not alive' unless alive?).to_s + '>'
|
621
638
|
end
|
622
639
|
|
623
640
|
def inspect # :nodoc: #
|
624
|
-
|
641
|
+
to_s
|
625
642
|
end
|
626
643
|
|
627
644
|
def self.workbook_class # :nodoc: #
|
628
645
|
@workbook_class ||= begin
|
629
|
-
module_name =
|
646
|
+
module_name = parent_name
|
630
647
|
"#{module_name}::Workbook".constantize
|
631
648
|
rescue NameError => e
|
632
649
|
Workbook
|
@@ -639,30 +656,30 @@ module RobustExcelOle
|
|
639
656
|
|
640
657
|
include MethodHelpers
|
641
658
|
|
642
|
-
|
659
|
+
private
|
660
|
+
|
661
|
+
def method_missing(name, *args) # :nodoc: #
|
662
|
+
if name.to_s[0,1] =~ /[A-Z]/
|
663
|
+
begin
|
664
|
+
raise ObjectNotAlive, 'method missing: Excel not alive' unless alive?
|
643
665
|
|
644
|
-
def method_missing(name, *args) # :nodoc: #
|
645
|
-
if name.to_s[0,1] =~ /[A-Z]/
|
646
|
-
begin
|
647
|
-
raise ObjectNotAlive, "method missing: Excel not alive" unless alive?
|
648
666
|
@ole_excel.send(name, *args)
|
649
667
|
rescue WIN32OLERuntimeError => msg
|
650
668
|
if msg.message =~ /unknown property or method/
|
651
669
|
raise VBAMethodMissingError, "unknown VBA property or method #{name.inspect}"
|
652
|
-
else
|
670
|
+
else
|
653
671
|
raise msg
|
654
672
|
end
|
655
673
|
end
|
656
|
-
else
|
657
|
-
super
|
674
|
+
else
|
675
|
+
super
|
658
676
|
end
|
659
677
|
end
|
660
|
-
|
661
678
|
end
|
662
679
|
|
663
680
|
public
|
664
681
|
|
665
|
-
|
682
|
+
Application = Excel
|
666
683
|
|
667
684
|
end
|
668
685
|
|