winexcel 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/README.md +156 -0
- data/Rakefile +7 -0
- data/examples/basic.rb +49 -0
- data/examples/extended.rb +73 -0
- data/examples/fixtures/a.xls +0 -0
- data/examples/fixtures/b.xlsx +0 -0
- data/examples/fixtures/template.xls +0 -0
- data/examples/my_basic_file.xls +0 -0
- data/examples/my_extended_file.xls +0 -0
- data/features/connect_to_open_excel_file.feature +32 -0
- data/features/create_excel_file_from_template_and_open.feature +35 -0
- data/features/fixtures/a.xls +0 -0
- data/features/fixtures/b.xlsx +0 -0
- data/features/open_excel_file.feature +41 -0
- data/features/step_definitions/excel_file_steps.rb +71 -0
- data/features/support/common.rb +37 -0
- data/features/support/env.rb +14 -0
- data/features/support/matchers.rb +9 -0
- data/lib/winexcel.rb +12 -0
- data/lib/winexcel/core_ext/object.rb +34 -0
- data/lib/winexcel/core_ext/ordered_hash.rb +100 -0
- data/lib/winexcel/excel/xl_file_format.rb +74 -0
- data/lib/winexcel/excel_file.rb +255 -0
- data/lib/winexcel/excel_file/common_methods.rb +422 -0
- data/lib/winexcel/excel_file/other_methods.rb +315 -0
- data/lib/winexcel/excel_file/write_2D_array.rb +169 -0
- data/lib/winexcel/fileutils_ext/backup_file.rb +25 -0
- data/lib/winexcel/fileutils_ext/create_dir_if_missing.rb +18 -0
- data/lib/winexcel/version.rb +3 -0
- data/lib/winexcel/win32olerot_ext/win32olerot.so +0 -0
- data/tasks/cucumber.rake +23 -0
- data/tasks/rspec.rake +9 -0
- data/winexcel.gemspec +26 -0
- metadata +163 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
module CommonHelpers
|
2
|
+
def get_command_output
|
3
|
+
strip_color_codes(File.read(@stdout)).chomp
|
4
|
+
end
|
5
|
+
|
6
|
+
def strip_color_codes(text)
|
7
|
+
text.gsub(/\e\[\d+m/, '')
|
8
|
+
end
|
9
|
+
|
10
|
+
def in_tmp_folder(&block)
|
11
|
+
FileUtils.chdir(@tmp_root, &block)
|
12
|
+
end
|
13
|
+
|
14
|
+
def in_project_folder(&block)
|
15
|
+
project_folder = @active_project_folder || @tmp_root
|
16
|
+
FileUtils.chdir(project_folder, &block)
|
17
|
+
end
|
18
|
+
|
19
|
+
def in_home_folder(&block)
|
20
|
+
FileUtils.chdir(@home_path, &block)
|
21
|
+
end
|
22
|
+
|
23
|
+
def force_local_lib_override(project_name = @project_name)
|
24
|
+
rakefile = File.read(File.join(project_name, 'Rakefile'))
|
25
|
+
File.open(File.join(project_name, 'Rakefile'), "w+") do |f|
|
26
|
+
f << "$:.unshift('#{@lib_path}')\n"
|
27
|
+
f << rakefile
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def setup_active_project_folder project_name
|
32
|
+
@active_project_folder = File.join(@tmp_root, project_name)
|
33
|
+
@project_name = project_name
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
World(CommonHelpers)
|
@@ -0,0 +1,14 @@
|
|
1
|
+
$:.unshift(File.expand_path(File.dirname(__FILE__) + "/../../lib"))
|
2
|
+
require 'winexcel.rb'
|
3
|
+
require 'bundler/setup'
|
4
|
+
|
5
|
+
Before do
|
6
|
+
@tmp_root = File.dirname(__FILE__) + "/../../tmp"
|
7
|
+
@home_path = File.expand_path(File.join(@tmp_root, "home"))
|
8
|
+
@lib_path = File.expand_path(File.dirname(__FILE__) + "/../../lib")
|
9
|
+
FileUtils.rm_rf @tmp_root
|
10
|
+
FileUtils.mkdir_p @home_path
|
11
|
+
ENV['HOME'] = @home_path
|
12
|
+
ENV['CUCUMBER_RUNNING'] = 'yes'
|
13
|
+
end
|
14
|
+
|
data/lib/winexcel.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
module WinExcel
|
2
|
+
|
3
|
+
require 'winexcel/core_ext/object'
|
4
|
+
require 'winexcel/core_ext/ordered_hash'
|
5
|
+
require 'fileutils'
|
6
|
+
require 'winexcel/fileutils_ext/create_dir_if_missing'
|
7
|
+
require 'winexcel/fileutils_ext/backup_file'
|
8
|
+
|
9
|
+
require 'winexcel/excel/xl_file_format'
|
10
|
+
require 'winexcel/version'
|
11
|
+
require 'winexcel/excel_file'
|
12
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class Object
|
2
|
+
# Returns true if the object is nil or empty. It works on most popular objects
|
3
|
+
# like hashes, arrays and strings. Main purpose is to avoid double checking statements
|
4
|
+
# (and to eliminate bugs caused by single checking) like in code below:
|
5
|
+
# if some_obj == nil or some_obj.empty?
|
6
|
+
# # do something
|
7
|
+
# end
|
8
|
+
# Remarks: When this funcion is applied to a String, false is returned when
|
9
|
+
# the string contains white space characters only.
|
10
|
+
def unempty?
|
11
|
+
if [nil, [], {}].include?(self) or (self.kind_of?(String) and self.strip == '')
|
12
|
+
return false
|
13
|
+
else
|
14
|
+
return true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def in?(arr)
|
19
|
+
return true if arr.unempty? and arr.include?(self)
|
20
|
+
end
|
21
|
+
|
22
|
+
def has?(obj)
|
23
|
+
if [nil].include?(self)
|
24
|
+
return false
|
25
|
+
else
|
26
|
+
return self.include?(obj)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def eq?(obj)
|
31
|
+
return self.to_s.upcase == obj.to_s.upcase
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module WinExcel
|
2
|
+
module CoreExt #:nodoc:
|
3
|
+
|
4
|
+
if RUBY_VERSION >= '1.9'
|
5
|
+
class OrderedHash < ::Hash
|
6
|
+
end
|
7
|
+
else
|
8
|
+
# This class is based on the Ruby 1.9 ordered hashes.
|
9
|
+
#
|
10
|
+
# It keeps the semantics and most of the efficiency of normal hashes
|
11
|
+
# while also keeping track of the order in which elements were set.
|
12
|
+
#
|
13
|
+
class OrderedHash #:nodoc:
|
14
|
+
include Enumerable
|
15
|
+
|
16
|
+
Node = Struct.new(:key, :value, :next, :prev)
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@hash = {}
|
20
|
+
end
|
21
|
+
|
22
|
+
def [](key)
|
23
|
+
@hash[key] && @hash[key].value
|
24
|
+
end
|
25
|
+
|
26
|
+
def []=(key, value)
|
27
|
+
if node = @hash[key]
|
28
|
+
node.value = value
|
29
|
+
else
|
30
|
+
node = Node.new(key, value)
|
31
|
+
|
32
|
+
if @first.nil?
|
33
|
+
@first = @last = node
|
34
|
+
else
|
35
|
+
node.prev = @last
|
36
|
+
@last.next = node
|
37
|
+
@last = node
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
@hash[key] = node
|
42
|
+
value
|
43
|
+
end
|
44
|
+
|
45
|
+
def delete(key)
|
46
|
+
if node = @hash[key]
|
47
|
+
prev_node = node.prev
|
48
|
+
next_node = node.next
|
49
|
+
|
50
|
+
next_node.prev = prev_node if next_node
|
51
|
+
prev_node.next = next_node if prev_node
|
52
|
+
|
53
|
+
@first = next_node if @first == node
|
54
|
+
@last = prev_node if @last == node
|
55
|
+
|
56
|
+
value = node.value
|
57
|
+
end
|
58
|
+
|
59
|
+
@hash.delete(key)
|
60
|
+
value
|
61
|
+
end
|
62
|
+
|
63
|
+
def keys
|
64
|
+
self.map { |k, v| k }
|
65
|
+
end
|
66
|
+
|
67
|
+
def values
|
68
|
+
self.map { |k, v| v }
|
69
|
+
end
|
70
|
+
|
71
|
+
def each
|
72
|
+
return unless @first
|
73
|
+
yield [@first.key, @first.value]
|
74
|
+
node = @first
|
75
|
+
yield [node.key, node.value] while node = node.next
|
76
|
+
self
|
77
|
+
end
|
78
|
+
|
79
|
+
def merge(other)
|
80
|
+
hash = self.class.new
|
81
|
+
|
82
|
+
self.each do |key, value|
|
83
|
+
hash[key] = value
|
84
|
+
end
|
85
|
+
|
86
|
+
other.each do |key, value|
|
87
|
+
hash[key] = value
|
88
|
+
end
|
89
|
+
|
90
|
+
hash
|
91
|
+
end
|
92
|
+
|
93
|
+
def empty?
|
94
|
+
@hash.empty?
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module WinExcel
|
2
|
+
module Excel
|
3
|
+
APPLICATION_NAME = 'Excel.Application'
|
4
|
+
LOAD_ALL_CONSTANTS = false # for performance reasons it's been disabled
|
5
|
+
|
6
|
+
#
|
7
|
+
# XlFileFormat is much more faster replacement for LOAD_ALL_CONSTANTS
|
8
|
+
#
|
9
|
+
module XlFileFormat
|
10
|
+
# Excel::XlFileFormat::
|
11
|
+
|
12
|
+
# Name = Value # Description
|
13
|
+
XlAddIn = 18 # Microsoft Excel 97-2003 Add-In
|
14
|
+
XlAddIn8 = 18 # Microsoft Excel 97-2003 Add-In
|
15
|
+
XlCSV = 6 # CSV
|
16
|
+
XlCSVMac = 22 # Macintosh CSV
|
17
|
+
XlCSVMSDOS = 24 # MSDOS CSV
|
18
|
+
XlCSVWindows = 23 # Windows CSV
|
19
|
+
XlCurrentPlatformText = -4158 # Current Platform Text
|
20
|
+
XlDBF2 = 7 # DBF2
|
21
|
+
XlDBF3 = 8 # DBF3
|
22
|
+
XlDBF4 = 11 # DBF4
|
23
|
+
XlDIF = 9 # DIF
|
24
|
+
XlExcel12 = 50 # Excel12
|
25
|
+
XlExcel2 = 16 # Excel2
|
26
|
+
XlExcel2FarEast = 27 # Excel2 FarEast
|
27
|
+
XlExcel3 = 29 # Excel3
|
28
|
+
XlExcel4 = 33 # Excel4
|
29
|
+
XlExcel4Workbook = 35 # Excel4 Workbook
|
30
|
+
XlExcel5 = 39 # Excel5
|
31
|
+
XlExcel7 = 39 # Excel7
|
32
|
+
XlExcel8 = 56 # Excel8
|
33
|
+
XlExcel9795 = 43 # Excel9795
|
34
|
+
XlHtml = 44 # HTML format
|
35
|
+
XlIntlAddIn = 26 # International Add-In
|
36
|
+
XlIntlMacro = 25 # International Macro
|
37
|
+
XlOpenDocumentSpreadsheet = 60 # OpenDocument Spreadsheet
|
38
|
+
XlOpenXMLAddIn = 55 # Open XML Add-In
|
39
|
+
XlOpenXMLTemplate = 54 # Open XML Template
|
40
|
+
XlOpenXMLTemplateMacroEnabled = 53 # Open XML Template Macro Enabled
|
41
|
+
XlOpenXMLWorkbook = 51 # Open XML Workbook
|
42
|
+
XlOpenXMLWorkbookMacroEnabled = 52 # Open XML Workbook Macro Enabled
|
43
|
+
XlSYLK = 2 # SYLK
|
44
|
+
XlTemplate = 17 # Template
|
45
|
+
XlTemplate8 = 17 # Template 8
|
46
|
+
XlTextMac = 19 # Macintosh Text
|
47
|
+
XlTextMSDOS = 21 # MSDOS Text
|
48
|
+
XlTextPrinter = 36 # Printer Text
|
49
|
+
XlTextWindows = 20 # Windows Text
|
50
|
+
XlUnicodeText = 42 # Unicode Text
|
51
|
+
XlWebArchive = 45 # Web Archive
|
52
|
+
XlWJ2WD1 = 14 # WJ2WD1
|
53
|
+
XlWJ3 = 40 # WJ3
|
54
|
+
XlWJ3FJ3 = 41 # WJ3FJ3
|
55
|
+
XlWK1 = 5 # WK1
|
56
|
+
XlWK1ALL = 31 # WK1ALL
|
57
|
+
XlWK1FMT = 30 # WK1FMT
|
58
|
+
XlWK3 = 15 # WK3
|
59
|
+
XlWK3FM3 = 32 # WK3FM3
|
60
|
+
XlWK4 = 38 # WK4
|
61
|
+
XlWKS = 4 # Worksheet
|
62
|
+
XlWorkbookDefault = 51 # Workbook default
|
63
|
+
XlWorkbookNormal = -4143 # Workbook normal
|
64
|
+
XlWorks2FarEast = 28 # Works2 FarEast
|
65
|
+
XlWQ1 = 34 # WQ1
|
66
|
+
XlXMLSpreadsheet = 46 # XML Spreadsheet
|
67
|
+
end
|
68
|
+
|
69
|
+
# not yet implemented
|
70
|
+
RunModes = {}
|
71
|
+
RunModes[:open_new_in_isolated_excel] = :open_new_in_isolated_excel
|
72
|
+
RunModes[:find_in_existing_not_isolated_workbooks] = :find_in_existing_not_isolated_workbooks
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,255 @@
|
|
1
|
+
# excel_file.rb
|
2
|
+
#
|
3
|
+
# File based on Xls.rb being part of 'wwatf' project
|
4
|
+
# Copyright (C) 2010-2011 Sobieraj Kamil <ksob@dslowl.com>.
|
5
|
+
#
|
6
|
+
# This file is published under New BSD License
|
7
|
+
# You can redistribute and/or
|
8
|
+
# modify it under the terms of the New BSD License.
|
9
|
+
#
|
10
|
+
# New BSD License claims:
|
11
|
+
# Redistribution and use in source and binary forms, with or without
|
12
|
+
# modification, are permitted provided that the following conditions
|
13
|
+
# are met:
|
14
|
+
#
|
15
|
+
# 1. Redistributions of source code must retain the above copyright notice,
|
16
|
+
# this list of conditions and the following disclaimer.
|
17
|
+
#
|
18
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
19
|
+
# this list of conditions and the following disclaimer in the documentation
|
20
|
+
# and/or other materials provided with the distribution.
|
21
|
+
#
|
22
|
+
# 3. Neither the name of Zend Technologies USA, Inc. nor the names of its
|
23
|
+
# contributors may be used to endorse or promote products derived from this
|
24
|
+
# software without specific prior written permission.
|
25
|
+
#
|
26
|
+
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
27
|
+
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
28
|
+
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
29
|
+
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
30
|
+
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
31
|
+
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
32
|
+
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
33
|
+
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
34
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
35
|
+
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
36
|
+
|
37
|
+
|
38
|
+
require 'logger'
|
39
|
+
require 'win32ole'
|
40
|
+
|
41
|
+
require 'rubygems'
|
42
|
+
if RUBY_VERSION >= '1.9'
|
43
|
+
require 'win32olerot'
|
44
|
+
else
|
45
|
+
require 'winexcel/win32olerot_ext/win32olerot'
|
46
|
+
end
|
47
|
+
|
48
|
+
require 'winexcel/excel_file/write_2D_array'
|
49
|
+
require 'winexcel/excel_file/common_methods'
|
50
|
+
require 'winexcel/excel_file/other_methods'
|
51
|
+
|
52
|
+
# Excel interface class.
|
53
|
+
# This class provides many simple methods for using Excel spreadsheets.
|
54
|
+
#
|
55
|
+
# Inner working:
|
56
|
+
# If the File is already open in excel, data is read from the open file
|
57
|
+
# and left open after the call to the close/finalize method.
|
58
|
+
# If the file is not open, It will be opened in the background
|
59
|
+
# and closed when the close/finalize method is called.
|
60
|
+
#
|
61
|
+
# For examples look at the examples folder as well as Cucumber/RSpec
|
62
|
+
# files in features and spec directories
|
63
|
+
#
|
64
|
+
# Information for developers:
|
65
|
+
# It is helpful to use COM/Win32OLE tracking tool like "oakland ActiveX Inspector"
|
66
|
+
# to clearly see what Excel instances are beeing created
|
67
|
+
#
|
68
|
+
module WinExcel
|
69
|
+
|
70
|
+
class ExcelFile
|
71
|
+
# Singleton Class to store Excel Constant Variables
|
72
|
+
class ExcelConst;
|
73
|
+
end
|
74
|
+
|
75
|
+
attr_accessor :excel
|
76
|
+
attr_accessor :workbook
|
77
|
+
attr_accessor :records
|
78
|
+
attr_accessor :fileName
|
79
|
+
|
80
|
+
@@automationInstance = nil
|
81
|
+
|
82
|
+
XlsAutomationSecurity = 3 # msoAutomationSecurityForceDisable
|
83
|
+
XlsDisplayAlerts = false
|
84
|
+
XlsVisible = false
|
85
|
+
XlsScreenUpdating = false
|
86
|
+
XlsInteractive = false
|
87
|
+
|
88
|
+
def setSettings excel
|
89
|
+
excel.Application.AutomationSecurity = XlsAutomationSecurity
|
90
|
+
excel.DisplayAlerts = XlsDisplayAlerts
|
91
|
+
excel.Visible = XlsVisible
|
92
|
+
excel.ScreenUpdating = XlsScreenUpdating
|
93
|
+
excel.Interactive = XlsInteractive
|
94
|
+
end
|
95
|
+
|
96
|
+
#
|
97
|
+
# initilize creates an ExcelFile instance for a given .xls file.
|
98
|
+
# If the File is already open in excel, data is read from the open file and left open after the call to the close/finalize method.
|
99
|
+
# If the file is not open, It will be opened in the background and closed when the close/finalize method is called.
|
100
|
+
#
|
101
|
+
# For examples look at the end of the file as well as Cucumber/RSpec files
|
102
|
+
#
|
103
|
+
# Information for developers:
|
104
|
+
# It is helpful to use Win32OLE tracking tool like "oakland ActiveX Inspector"
|
105
|
+
# to clearly see what Excel instances are beeing created
|
106
|
+
#
|
107
|
+
def initialize(file, debug = false, template = nil)
|
108
|
+
@excelOpen=false
|
109
|
+
@connectedToOpenWorkBook=false
|
110
|
+
@log = Logger.new(STDERR)
|
111
|
+
@log.level = Logger::WARN
|
112
|
+
@log.level = Logger::DEBUG if debug
|
113
|
+
|
114
|
+
if not @@automationInstance
|
115
|
+
ExcelFile.killExcelAutomationProcesses
|
116
|
+
end
|
117
|
+
|
118
|
+
connectToOpenWorkbook = lambda {
|
119
|
+
# open existing file in a traditional way connecting to running Excel instance
|
120
|
+
workbookObj = WIN32OLE.connect(file)
|
121
|
+
@excel = workbookObj.Application
|
122
|
+
@excelOpen = true
|
123
|
+
basename = File.basename(file)
|
124
|
+
@workbook = @excel.Workbooks(basename)
|
125
|
+
@connectedToOpenWorkBook=true
|
126
|
+
@log.info(self.class) { "Attached to open Workbook: #{basename}" }
|
127
|
+
}
|
128
|
+
|
129
|
+
openAutomationInstance = lambda {
|
130
|
+
if not @@automationInstance
|
131
|
+
@@automationInstance = WIN32OLE::new(Excel::APPLICATION_NAME)
|
132
|
+
setSettings @@automationInstance
|
133
|
+
@log.info(self.class) { "Excel Automation Instance Created" }
|
134
|
+
end
|
135
|
+
@excel = @@automationInstance
|
136
|
+
}
|
137
|
+
|
138
|
+
makeFileFromTemplateAndOpen = lambda {
|
139
|
+
# copy the template on place of the file (that's been just moved)
|
140
|
+
openAutomationInstance.call
|
141
|
+
@workbook = @@automationInstance.Workbooks.Add(template)
|
142
|
+
@workbook.SaveAs(file.gsub("/", "\\"), Excel::XlFileFormat::XlWorkbookNormal)
|
143
|
+
@log.info(self.class) { "File: '#{file}' created from template '#{template}'." }
|
144
|
+
}
|
145
|
+
|
146
|
+
openFileInAutomationInstance = lambda {
|
147
|
+
# create isolated Excel and open that workbook/file inside of it
|
148
|
+
openAutomationInstance.call
|
149
|
+
@excelOpen = true
|
150
|
+
begin
|
151
|
+
basename = File.basename(file)
|
152
|
+
@workbook = @excel.Workbooks(basename)
|
153
|
+
@log.info(self.class) { "Attached to open Workbook: '#{basename}'." }
|
154
|
+
rescue
|
155
|
+
if File.exists?(file)
|
156
|
+
@workbook = @excel.Workbooks.Open(file)
|
157
|
+
@log.info(self.class) { "File: '#{file}' opened." }
|
158
|
+
else
|
159
|
+
raise "File: '#{file}' does not exist."
|
160
|
+
end
|
161
|
+
end
|
162
|
+
}
|
163
|
+
|
164
|
+
# check in ROT if workbook is open if so use WIN32OLE::connect(file) otherwise open in isolation
|
165
|
+
rot = WIN32OLE::RunningObjectTable.new
|
166
|
+
if rot.nil? then
|
167
|
+
throw 'Cannot access WIN32OLE::RunningObjectTable'
|
168
|
+
end
|
169
|
+
begin
|
170
|
+
isFileRunning = rot.is_running?(file)
|
171
|
+
if isFileRunning and template
|
172
|
+
connectToOpenWorkbook.call
|
173
|
+
|
174
|
+
# save file, close it and move to backup
|
175
|
+
save
|
176
|
+
sleep 1
|
177
|
+
@workbook.close
|
178
|
+
while rot.is_running?(file) do
|
179
|
+
sleep 1
|
180
|
+
end
|
181
|
+
@excel.quit
|
182
|
+
@excel = nil
|
183
|
+
GC.start
|
184
|
+
FileUtils.moveFileToBackupDir file
|
185
|
+
@log.info(self.class) { "File: #{file} successfully saved, closed and moved to BACKUP folder." }
|
186
|
+
|
187
|
+
makeFileFromTemplateAndOpen.call
|
188
|
+
elsif isFileRunning and not template
|
189
|
+
connectToOpenWorkbook.call
|
190
|
+
elsif not isFileRunning and template
|
191
|
+
makeFileFromTemplateAndOpen.call
|
192
|
+
elsif not isFileRunning and not template
|
193
|
+
openFileInAutomationInstance.call
|
194
|
+
end
|
195
|
+
rescue
|
196
|
+
@log.error(self.class) { "Error attaching: wasFileOpenedByUser: #{@connectedToOpenWorkBook}, file: #{file}, error: #{$!}" }
|
197
|
+
raise
|
198
|
+
end
|
199
|
+
|
200
|
+
@records = {}
|
201
|
+
|
202
|
+
if Excel::LOAD_ALL_CONSTANTS
|
203
|
+
# Get the standard set of Excel constants
|
204
|
+
WIN32OLE.const_load(@excel, ExcelConst) if ExcelConst.constants == []
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def self.killExcelAutomationProcesses
|
209
|
+
begin
|
210
|
+
wmi = WIN32OLE.connect("winmgmts://")
|
211
|
+
processes = wmi.ExecQuery("select * from win32_process where commandline like '%excel.exe\"% /automation %'")
|
212
|
+
processes.each do |process|
|
213
|
+
Process.kill('KILL', process.ProcessID)
|
214
|
+
end
|
215
|
+
rescue
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
# not used
|
220
|
+
# do not work yet
|
221
|
+
def self.killInvisibleExcelProcesses
|
222
|
+
2.times do
|
223
|
+
excelObj = WIN32OLE::connect(Excel::APPLICATION_NAME)
|
224
|
+
if not excelObj.Visible
|
225
|
+
finalize(excelObj)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
def self.finalize()
|
231
|
+
if not @@automationInstance.nil?
|
232
|
+
begin
|
233
|
+
@@automationInstance.Workbooks.each do |wb|
|
234
|
+
begin
|
235
|
+
wb.Close(false)
|
236
|
+
rescue
|
237
|
+
end
|
238
|
+
wb = nil
|
239
|
+
end
|
240
|
+
GC.start
|
241
|
+
sleep(3)
|
242
|
+
rescue
|
243
|
+
end
|
244
|
+
@@automationInstance.quit
|
245
|
+
sleep 1
|
246
|
+
@@automationInstance = nil
|
247
|
+
GC.start
|
248
|
+
sleep(3)
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
|
253
|
+
end
|
254
|
+
|
255
|
+
end
|