├── LICENSE.rst ├── README.md ├── requirements.txt └── safexl ├── __init__.py ├── colors.py ├── tests ├── __init__.py ├── test_app.py ├── test_app_tools.py └── test_psutil_wrappers.py ├── toolkit.py └── xl_constants.py /LICENSE.rst: -------------------------------------------------------------------------------- 1 | This software is under the MIT License 2 | ====================================== 3 | 4 | Copyright (c) 2020 Eric Smith 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a 7 | copy of this software and associated documentation files (the 8 | "Software"), to deal in the Software without restriction, including 9 | without limitation the rights to use, copy, modify, merge, publish, 10 | distribute, sublicense, and/or sell copies of the Software, and to 11 | permit persons to whom the Software is furnished to do so, subject to 12 | the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # safexl - The Safe Way to Excel 2 | ##### A wrapper around the pywin32 module for easier use and automated cleanup of Excel Application COM objects 3 | The pywin32 library grants extraordinary capabilities to interact with Windows applications, 4 | but includes many oddities usually learned through trial and error, as seen in Stack Overflow posts such as these: 5 | * [COM: excelApplication.Application.Quit() preserves the process](https://stackoverflow.com/questions/18421457/com-excelapplication-application-quit-preserves-the-process) 6 | * [Can't close Excel completely using win32com on Python](https://stackoverflow.com/questions/10221150/cant-close-excel-completely-using-win32com-on-python) 7 | * [Loading addins when Excel is instantiated programmatically](https://stackoverflow.com/questions/213375/loading-addins-when-excel-is-instantiated-programmatically) 8 | * [AutoFilter method of Range class failed (Dispatch vs EnsureDispatch)](https://stackoverflow.com/questions/22930751/autofilter-method-of-range-class-failed-dispatch-vs-ensuredispatch) 9 | 10 | My experience with automating Excel using pywin32 led me to create `safexl`, a pywin32 wrapper centered around easier use and 11 | automated cleanup of Excel Application COM objects in Python. The main functionality of this package is a context-managed 12 | `application` generator that you can use inside a `with` block, built with some pywin32 best practices in place and a few psutil 13 | tools focused on working with Excel. 14 | 15 | ---------------------------------------------------------------------------------------------------------------------------------- 16 | 17 | ## Install 18 | You can import the library with pip: 19 | ```cmd 20 | pip install safexl 21 | ``` 22 | Or you can download it [here](https://github.com/ThePoetCoder/safexl) at GitHub. 23 | 24 | This module requires: 25 | * [pywin32](https://pypi.org/project/pywin32/) 26 | * [psutil](https://pypi.org/project/psutil/) 27 | 28 | ---------------------------------------------------------------------------------------------------------------------------------- 29 | 30 | ## Usage 31 | This package makes writing pywin32 code in Python as simple as: 32 | ```python 33 | import safexl 34 | 35 | with safexl.application(kill_after=False, maximize=True, include_addins=True) as app: 36 | wb = app.Workbooks.Add() 37 | ws = wb.ActiveSheet 38 | rng = ws.Range("B1") 39 | rng.Value = "Hello, World!" 40 | rng.Interior.Color = safexl.colors.rgbRed # colors are included 41 | rng.EntireColumn.AutoFit() 42 | ws.Columns("A").Delete(Shift=safexl.xl_constants.xlToLeft) # constants are included 43 | 44 | # This results in Excel being opened to a Sheet where cell "A1" has 'Hello, World!' in it with a red background 45 | ``` 46 | 47 | If you've programmatically worked with Excel in a Win32 environment before, this code should look very familiar, 48 | as I am not altering the COM object itself before yielding it to you inside a `with` block; I am instead providing 49 | a means to create and delete it more easily. 50 | 51 | _If you would like to alter the COM object (for things like turning off ScreenUpdating 52 | while your code runs), then please see the **Performance** section near the bottom._ 53 | 54 | In this way, the following two code snippets will have the same effect: 55 | #### 1.) without safexl 56 | ```python 57 | import pythoncom 58 | import win32com.client 59 | 60 | pythoncom.CoInitialize() 61 | app = win32com.client.Dispatch("Excel.Application") 62 | try: 63 | ####################### 64 | # Your code goes here # 65 | ####################### 66 | finally: 67 | app.Quit() 68 | del app 69 | pythoncom.CoUninitialize() 70 | ``` 71 | 72 | #### 2.) with safexl 73 | ```python 74 | import safexl 75 | 76 | with safexl.application(kill_after=True) as app: 77 | ####################### 78 | # Your code goes here # 79 | ####################### 80 | ``` 81 | As you can see, using safexl results in a lot less boilerplate code, from 9 lines to 2. 82 | 83 | The `application` wrapper comes with 3 boolean parameters to indicate what you would like to do with the application once your 84 | `with` block is complete: 85 | 1. `kill_after` - kill the Excel process upon leaving the `with` block 86 | 2. `maximize` - Optional / Defaults to `True` - Will not be used if you set `kill_after=True`. Maximizes each Excel Window for 87 | each Workbook added during the `with` block. 88 | 3. `include_addins` - Optional / Defaults to `False` - Will not be used if you set `kill_after=True`. Loads your installed Excel 89 | Add-ins to the newly created instance (with a performance hit to do so). 90 | 91 | In the event of an error occuring inside your `with` block, the `safexl.application` cleanup process will carefully remove any new 92 | workbooks you've opened in Excel, leaving any workbooks you already had open prior to the `with` block untouched. The same goes 93 | for if you chose to set `kill_after=True`; only the Workbooks you create inside the `with` block will be closed. 94 | In addition to the `application` wrapper, I have included an handful of other tools to make working with Excel even easier, including: 95 | 96 | * is_excel_open() 97 | * kill_all_instances_of_excel() 98 | * close_workbooks(app, workbooks) 99 | * see_excel(app, window_state) 100 | * workbooks_currently_open(app) 101 | * last_row(worksheet) 102 | * last_column(worksheet) 103 | * worksheet_name_sanitization(worksheet_name) 104 | 105 | ---------------------------------------------------------------------------------------------------------------------------------- 106 | 107 | ## Performance 108 | A number of performance enhancing options can be set on Excel Application objects, and will come in handy most whenever you are 109 | working with large workbooks and amounts of data. In my balance between allowing you the most freedom to do what you wish with the 110 | application object and wrapping your object for safer error handling, I am yielding a bare pywin32 application object to you 111 | inside the `with` block. If you wish to take advantage of the various performance enhancing settings available natively in the 112 | Excel Application, I suggest using your own error handling inside the `with` block, to verify that the settings get switched back 113 | to normal when you're finished, even if you encounter an error during your work. Using safexl in this way would look something 114 | like this: 115 | ```python 116 | import safexl 117 | 118 | with safexl.application(kill_after=False) as app: 119 | try: 120 | app.ScreenUpdating = False 121 | app.DisplayStatusBar = False 122 | app.EnableEvents = False 123 | 124 | wb = app.Workbooks.Add() 125 | # can only set calculation once at least 1 workbook is open 126 | app.Calculation = safexl.xl_constants.xlCalculationManual 127 | 128 | ####################### 129 | # Your code goes here # 130 | ####################### 131 | 132 | except Exception as e: 133 | # if you don't re-raise the error here, you will not be warned that an error occured 134 | # or get the benefit of reading the error message 135 | raise e 136 | 137 | else: 138 | pass 139 | 140 | finally: 141 | app.ScreenUpdating = True 142 | app.DisplayStatusBar = True 143 | app.EnableEvents = True 144 | app.Calculation = safexl.xl_constants.xlCalculationAutomatic 145 | 146 | ``` 147 | 148 | ##### A note on setting the Calculation 149 | Unfortunately, due to an oddity in the Excel Application OOP design, even though the Calculation mode is set on the Application object 150 | (instead of the Workbook object) if no workbooks are open or visible in your instance of the Application, then the constant for 151 | an "#N/A" error is returned, as seen by code like this: 152 | ``` 153 | >>> import win32com.client 154 | >>> import pythoncom 155 | >>> pythoncom.CoInitialize() 156 | >>> app = win32com.client.Dispatch("Excel.Application") 157 | >>> app.Calculation # expect constant for #N/A 158 | -2146826246 159 | >>> wb = app.Workbooks.Add() 160 | >>> app.Calculation # expect XlCalculation constant 161 | -4105 162 | >>> wb.Close() 163 | >>> app.Calculation # expect constant for #N/A 164 | -2146826246 165 | ``` 166 | More can be read about how Excel handles Calculation modes at these links: 167 | * [How Excel determines the current mode of calculation](https://docs.microsoft.com/en-us/office/troubleshoot/excel/current-mode-of-calculation) 168 | * [Excel: 'Unable to set the Calculation property of the Application class'](https://stackoverflow.com/questions/275630/excel-unable-to-set-the-calculation-property-of-the-application-class) 169 | 170 | Suffice it to say, even though we think about the calculation mode being an attribute of each individual workbook, it is actually 171 | __set__ at the application level. I'm assuming this was for performance and/or sanity reasons, but the end result is that you are unable to 172 | get or set a proper Calculation mode for the application until you open a workbook first. 173 | 174 | ## Cookbook 175 | 176 | ##### Create & Save Workbook without viewing Application 177 | ```python 178 | import safexl 179 | 180 | with safexl.application(kill_after=True) as app: 181 | wb = app.Workbooks.Add() 182 | 183 | ####################### 184 | # Your code goes here # 185 | ####################### 186 | 187 | wb.SaveAs("Cookbook.xlsx") 188 | wb.Close() 189 | ``` 190 | 191 | ##### Create a Workbook & View it Without Saving 192 | ```python 193 | import safexl 194 | 195 | with safexl.application(kill_after=False, maximize=True, include_addins=True) as app: 196 | wb = app.Workbooks.Add() 197 | 198 | ####################### 199 | # Your code goes here # 200 | ####################### 201 | ``` 202 | 203 | ##### Minimize All Excel Windows that are Currently Open 204 | ```python 205 | import safexl 206 | 207 | with safexl.application(kill_after=True) as app: 208 | safexl.see_excel(app.Workbooks, safexl.xl_constants.xlMinimized) 209 | ``` 210 | 211 | ##### Send Pandas Dataframe to Excel Worksheet 212 | ```python 213 | import safexl 214 | import pandas as pd 215 | data = { 216 | 'A': [1, 2, 3], 217 | 'B': [4, 5, 6], 218 | 'C': [7, 8, 9] 219 | } 220 | df = pd.DataFrame(data) 221 | 222 | with safexl.application(kill_after=False) as app: 223 | wb = app.Workbooks.Add() 224 | ws = wb.ActiveSheet 225 | 226 | df.to_clipboard(excel=True) 227 | ws.Paste() 228 | ws.Range("A1").Select() # Otherwise entire dataframe range will be selected upon viewing 229 | ``` 230 | 231 | ---------------------------------------------------------------------------------------------------------------------------------- 232 | ## Similar Packages to Consider 233 | * [xlwings](https://docs.xlwings.org/en/stable/) 234 | * [OpenPyXL](https://openpyxl.readthedocs.io/en/stable/) 235 | * [XlsxWriter](https://xlsxwriter.readthedocs.io/) 236 | 237 | ## Contact Me 238 | * ThePoetCoder at gmail.com 239 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pywin32 >= 223 2 | psutil >= 5.6.2 -------------------------------------------------------------------------------- /safexl/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 safexl 2 | 3 | from safexl.toolkit import * 4 | import safexl.xl_constants as xl_constants 5 | import safexl.colors as colors 6 | 7 | 8 | __author__ = "Eric Smith" 9 | __email__ = "ThePoetCoder@gmail.com" 10 | __license__ = "MIT" 11 | __version__ = "0.0.7" 12 | -------------------------------------------------------------------------------- /safexl/colors.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 safexl 2 | 3 | # A config file to capture Excel defined colors for later use 4 | # in a format that plays nicely with autocomplete in IDEs. 5 | # Can be accessed like - `safexl.colors.rgbRed` 6 | 7 | # XlRgbColor 8 | rgbAliceBlue = 16775408 9 | rgbAntiqueWhite = 14150650 10 | rgbAqua = 16776960 11 | rgbAquamarine = 13959039 12 | rgbAzure = 16777200 13 | rgbBeige = 14480885 14 | rgbBisque = 12903679 15 | rgbBlack = 0 16 | rgbBlanchedAlmond = 13495295 17 | rgbBlue = 16711680 18 | rgbBlueViolet = 14822282 19 | rgbBrown = 2763429 20 | rgbBurlyWood = 8894686 21 | rgbCadetBlue = 10526303 22 | rgbChartreuse = 65407 23 | rgbCoral = 5275647 24 | rgbCornflowerBlue = 15570276 25 | rgbCornsilk = 14481663 26 | rgbCrimson = 3937500 27 | rgbDarkBlue = 9109504 28 | rgbDarkCyan = 9145088 29 | rgbDarkGoldenrod = 755384 30 | rgbDarkGray = 11119017 31 | rgbDarkGreen = 25600 32 | rgbDarkGrey = 11119017 33 | rgbDarkKhaki = 7059389 34 | rgbDarkMagenta = 9109643 35 | rgbDarkOliveGreen = 3107669 36 | rgbDarkOrange = 36095 37 | rgbDarkOrchid = 13382297 38 | rgbDarkRed = 139 39 | rgbDarkSalmon = 8034025 40 | rgbDarkSeaGreen = 9419919 41 | rgbDarkSlateBlue = 9125192 42 | rgbDarkSlateGray = 5197615 43 | rgbDarkSlateGrey = 5197615 44 | rgbDarkTurquoise = 13749760 45 | rgbDarkViolet = 13828244 46 | rgbDeepPink = 9639167 47 | rgbDeepSkyBlue = 16760576 48 | rgbDimGray = 6908265 49 | rgbDimGrey = 6908265 50 | rgbDodgerBlue = 16748574 51 | rgbFireBrick = 2237106 52 | rgbFloralWhite = 15792895 53 | rgbForestGreen = 2263842 54 | rgbFuchsia = 16711935 55 | rgbGainsboro = 14474460 56 | rgbGhostWhite = 16775416 57 | rgbGold = 55295 58 | rgbGoldenrod = 2139610 59 | rgbGray = 8421504 60 | rgbGreen = 32768 61 | rgbGreenYellow = 3145645 62 | rgbGrey = 8421504 63 | rgbHoneydew = 15794160 64 | rgbHotPink = 11823615 65 | rgbIndianRed = 6053069 66 | rgbIndigo = 8519755 67 | rgbIvory = 15794175 68 | rgbKhaki = 9234160 69 | rgbLavender = 16443110 70 | rgbLavenderBlush = 16118015 71 | rgbLawnGreen = 64636 72 | rgbLemonChiffon = 13499135 73 | rgbLightBlue = 15128749 74 | rgbLightCoral = 8421616 75 | rgbLightCyan = 9145088 76 | rgbLightGoldenrodYellow = 13826810 77 | rgbLightGray = 13882323 78 | rgbLightGreen = 9498256 79 | rgbLightGrey = 13882323 80 | rgbLightPink = 12695295 81 | rgbLightSalmon = 8036607 82 | rgbLightSeaGreen = 11186720 83 | rgbLightSkyBlue = 16436871 84 | rgbLightSlateGray = 10061943 85 | rgbLightSlateGrey = 10061943 86 | rgbLightSteelBlue = 14599344 87 | rgbLightYellow = 14745599 88 | rgbLime = 65280 89 | rgbLimeGreen = 3329330 90 | rgbLinen = 15134970 91 | rgbMaroon = 128 92 | rgbMediumAquamarine = 11206502 93 | rgbMediumBlue = 13434880 94 | rgbMediumOrchid = 13850042 95 | rgbMediumPurple = 14381203 96 | rgbMediumSeaGreen = 7451452 97 | rgbMediumSlateBlue = 15624315 98 | rgbMediumSpringGreen = 10156544 99 | rgbMediumTurquoise = 13422920 100 | rgbMediumVioletRed = 8721863 101 | rgbMidnightBlue = 7346457 102 | rgbMintCream = 16449525 103 | rgbMistyRose = 14804223 104 | rgbMoccasin = 11920639 105 | rgbNavajoWhite = 11394815 106 | rgbNavy = 8388608 107 | rgbNavyBlue = 8388608 108 | rgbOldLace = 15136253 109 | rgbOlive = 32896 110 | rgbOliveDrab = 2330219 111 | rgbOrange = 42495 112 | rgbOrangeRed = 17919 113 | rgbOrchid = 14053594 114 | rgbPaleGoldenrod = 7071982 115 | rgbPaleGreen = 10025880 116 | rgbPaleTurquoise = 15658671 117 | rgbPaleVioletRed = 9662683 118 | rgbPapayaWhip = 14020607 119 | rgbPeachPuff = 12180223 120 | rgbPeru = 4163021 121 | rgbPink = 13353215 122 | rgbPlum = 14524637 123 | rgbPowderBlue = 15130800 124 | rgbPurple = 8388736 125 | rgbRed = 255 126 | rgbRosyBrown = 9408444 127 | rgbRoyalBlue = 14772545 128 | rgbSalmon = 7504122 129 | rgbSandyBrown = 6333684 130 | rgbSeaGreen = 5737262 131 | rgbSeashell = 15660543 132 | rgbSienna = 2970272 133 | rgbSilver = 12632256 134 | rgbSkyBlue = 15453831 135 | rgbSlateBlue = 13458026 136 | rgbSlateGray = 9470064 137 | rgbSlateGrey = 9470064 138 | rgbSnow = 16448255 139 | rgbSpringGreen = 8388352 140 | rgbSteelBlue = 11829830 141 | rgbTan = 9221330 142 | rgbTeal = 8421376 143 | rgbThistle = 14204888 144 | rgbTomato = 4678655 145 | rgbTurquoise = 13688896 146 | rgbViolet = 15631086 147 | rgbWheat = 11788021 148 | rgbWhite = 16777215 149 | rgbWhiteSmoke = 16119285 150 | rgbYellow = 65535 151 | rgbYellowGreen = 3329434 152 | -------------------------------------------------------------------------------- /safexl/tests/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /safexl/tests/test_app.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 safexl 2 | import unittest 3 | import safexl 4 | 5 | 6 | class test_app_when_excel_is_not_running_at_onset(unittest.TestCase): 7 | def setUp(self): 8 | safexl.kill_all_instances_of_excel() 9 | self.assertFalse(safexl.is_excel_open()) 10 | 11 | def tearDown(self): 12 | # want to be sure that we start and end each app test with a clean slate 13 | safexl.kill_all_instances_of_excel() 14 | self.assertFalse(safexl.is_excel_open()) 15 | 16 | def test_no_error_kill_after(self): 17 | # No Error | Kill After - Excel not in proc @ end 18 | with safexl.application(kill_after=True, maximize=False, include_addins=False) as app: 19 | wb = app.Workbooks.Add() 20 | ws = wb.ActiveSheet 21 | ws.Range("A1").Value = 555 22 | self.assertTrue(safexl.is_excel_open()) 23 | self.assertEqual(wb.Name, "Book1") 24 | self.assertEqual(ws.Name, "Sheet1") 25 | self.assertEqual(ws.Range("A1").Value, 555) 26 | self.assertFalse(safexl.is_excel_open()) 27 | 28 | def test_error_kill_after(self): 29 | # Error | Kill After - Excel not in proc @ end 30 | with self.assertRaises(safexl.toolkit.ExcelError): 31 | with safexl.application(kill_after=True, maximize=False, include_addins=False) as app: 32 | wb = app.Workbooks.Add() 33 | ws = wb.ActiveSheet 34 | self.assertTrue(safexl.is_excel_open()) 35 | # Error on this line 36 | ws.Name = "a*b*c" 37 | # None of the following characters are allowed in sheet names 38 | # ["\\", "/", "*", "[", "]", ":", "?"] 39 | self.assertFalse(safexl.is_excel_open()) 40 | 41 | def test_no_error_alive_after(self): 42 | # No Error | Alive After - Excel in proc @ end 43 | with safexl.application(kill_after=False, maximize=False, include_addins=False) as app: 44 | wb = app.Workbooks.Add() 45 | ws = wb.ActiveSheet 46 | ws.Range("A1").Value = 555 47 | self.assertTrue(safexl.is_excel_open()) 48 | self.assertEqual(wb.Name, "Book1") 49 | self.assertEqual(ws.Name, "Sheet1") 50 | self.assertEqual(ws.Range("A1").Value, 555) 51 | self.assertTrue(safexl.is_excel_open()) 52 | 53 | def test_error_alive_after(self): 54 | # Error | Alive After - Excel not in proc @ end 55 | with self.assertRaises(safexl.toolkit.ExcelError): 56 | with safexl.application(kill_after=False, maximize=False, include_addins=False) as app: 57 | wb = app.Workbooks.Add() 58 | ws = wb.ActiveSheet 59 | self.assertTrue(safexl.is_excel_open()) 60 | # Error on this line 61 | ws.Name = "a*b*c" 62 | # None of the following characters are allowed in sheet names 63 | # ["\\", "/", "*", "[", "]", ":", "?"] 64 | self.assertFalse(safexl.is_excel_open()) 65 | 66 | 67 | class test_app_when_excel_is_running_at_onset(unittest.TestCase): 68 | def setUp(self): 69 | with safexl.application(kill_after=False, maximize=False, include_addins=False) as prev_app: 70 | wb = prev_app.Workbooks.Add() 71 | self.assertEqual("Book1", wb.Name) 72 | self.assertTrue(safexl.is_excel_open()) 73 | 74 | def tearDown(self): 75 | # want to be sure that we end each app test with a clean slate 76 | safexl.kill_all_instances_of_excel() 77 | self.assertFalse(safexl.is_excel_open()) 78 | 79 | def test_no_error_kill_after(self): 80 | # No Error | Kill After - prev Excel open after, new Excel gone 81 | current_openfile_count = len(safexl.toolkit.excel_open_files()) 82 | with safexl.application(kill_after=True, maximize=False, include_addins=False) as app: 83 | wb = app.Workbooks.Add() 84 | ws = wb.ActiveSheet 85 | ws.Range("A1").Value = 555 86 | self.assertTrue(safexl.is_excel_open()) 87 | self.assertEqual(len(safexl.toolkit.excel_open_files()), current_openfile_count + 1) 88 | self.assertEqual(wb.Name, "Book2") 89 | self.assertEqual(ws.Name, "Sheet1") 90 | self.assertEqual(ws.Range("A1").Value, 555) 91 | self.assertEqual(len(safexl.toolkit.excel_open_files()), current_openfile_count) 92 | self.assertTrue(safexl.is_excel_open()) 93 | 94 | def test_error_kill_after(self): 95 | # Error | Kill After - prev Excel open after, new Excel gone 96 | with self.assertRaises(safexl.toolkit.ExcelError): 97 | current_openfile_count = len(safexl.toolkit.excel_open_files()) 98 | with safexl.application(kill_after=True, maximize=False, include_addins=False) as app: 99 | wb = app.Workbooks.Add() 100 | ws = wb.ActiveSheet 101 | self.assertTrue(safexl.is_excel_open()) 102 | self.assertEqual(len(safexl.toolkit.excel_open_files()), current_openfile_count + 1) 103 | # Error on this line 104 | ws.Name = "a*b*c" 105 | # None of the following characters are allowed in sheet names 106 | # ["\\", "/", "*", "[", "]", ":", "?"] 107 | self.assertEqual(len(safexl.toolkit.excel_open_files()), current_openfile_count) 108 | self.assertTrue(safexl.is_excel_open()) 109 | 110 | def test_no_error_alive_after(self): 111 | # No Error | Alive After - prev Excel open after, new Excel open after 112 | current_openfile_count = len(safexl.toolkit.excel_open_files()) 113 | with safexl.application(kill_after=False, maximize=False, include_addins=False) as app: 114 | wb = app.Workbooks.Add() 115 | ws = wb.ActiveSheet 116 | ws.Range("A1").Value = 555 117 | self.assertTrue(safexl.is_excel_open()) 118 | self.assertEqual(len(safexl.toolkit.excel_open_files()), current_openfile_count + 1) 119 | self.assertEqual(wb.Name, "Book2") 120 | self.assertEqual(ws.Name, "Sheet1") 121 | self.assertEqual(ws.Range("A1").Value, 555) 122 | self.assertEqual(len(safexl.toolkit.excel_open_files()), current_openfile_count + 1) 123 | self.assertTrue(safexl.is_excel_open()) 124 | 125 | def test_error_alive_after(self): 126 | # Error | Alive After - prev Excel open after, new Excel gone 127 | with self.assertRaises(safexl.toolkit.ExcelError): 128 | current_openfile_count = len(safexl.toolkit.excel_open_files()) 129 | with safexl.application(kill_after=False, maximize=False, include_addins=False) as app: 130 | wb = app.Workbooks.Add() 131 | ws = wb.ActiveSheet 132 | self.assertTrue(safexl.is_excel_open()) 133 | self.assertEqual(len(safexl.toolkit.excel_open_files()), current_openfile_count + 1) 134 | # Error on this line 135 | ws.Name = "a*b*c" 136 | # None of the following characters are allowed in sheet names 137 | # ["\\", "/", "*", "[", "]", ":", "?"] 138 | self.assertEqual(len(safexl.toolkit.excel_open_files()), current_openfile_count) 139 | self.assertTrue(safexl.is_excel_open()) 140 | -------------------------------------------------------------------------------- /safexl/tests/test_app_tools.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 safexl 2 | import unittest 3 | import tempfile 4 | import pythoncom 5 | import pywintypes 6 | import win32com.client 7 | import safexl 8 | 9 | 10 | class test_close_workbooks(unittest.TestCase): 11 | def test_closing_one_new_workbook(self): 12 | pythoncom.CoInitialize() 13 | application = win32com.client.Dispatch("Excel.Application") 14 | wb = application.Workbooks.Add() 15 | 16 | self.assertEqual("Book1", wb.Name) 17 | safexl.close_workbooks(application, [wb]) 18 | with self.assertRaises(pywintypes.com_error): 19 | wb_name = wb.Name 20 | 21 | safexl.kill_all_instances_of_excel(application) 22 | del application 23 | pythoncom.CoUninitialize() 24 | 25 | def test_with_no_new_workbooks(self): 26 | pythoncom.CoInitialize() 27 | application = win32com.client.Dispatch("Excel.Application") 28 | wb = application.Workbooks.Add() 29 | 30 | self.assertEqual("Book1", wb.Name) 31 | safexl.close_workbooks(application, set()) 32 | self.assertEqual("Book1", wb.Name) 33 | 34 | safexl.kill_all_instances_of_excel(application) 35 | del application 36 | pythoncom.CoUninitialize() 37 | 38 | def test_with_many_new_workbooks(self): 39 | pythoncom.CoInitialize() 40 | application = win32com.client.Dispatch("Excel.Application") 41 | 42 | # Open 50 workbooks at one time 43 | wbs = [] 44 | for i in range(50): 45 | wb = application.Workbooks.Add() 46 | wbs.append(wb) 47 | self.assertEqual(50, application.Workbooks.Count) 48 | safexl.close_workbooks(application, wbs) 49 | self.assertEqual(0, application.Workbooks.Count) 50 | 51 | safexl.kill_all_instances_of_excel(application) 52 | del application 53 | pythoncom.CoUninitialize() 54 | 55 | 56 | class test_new_workbooks(unittest.TestCase): 57 | def test_new_workbook_is_returned_and_old_workbook_is_not(self): 58 | pythoncom.CoInitialize() 59 | application = win32com.client.Dispatch("Excel.Application") 60 | 61 | wb1 = application.Workbooks.Add() 62 | original_workbook_list = safexl.workbooks_currently_open(application) 63 | self.assertIn(wb1, original_workbook_list) 64 | 65 | wb2 = application.Workbooks.Add() 66 | new_workbook_list = safexl.toolkit.new_workbooks(application, original_workbook_list) 67 | self.assertNotIn(wb1, new_workbook_list) 68 | self.assertIn(wb2, new_workbook_list) 69 | self.assertEqual([wb2], new_workbook_list) 70 | 71 | safexl.kill_all_instances_of_excel(application) 72 | del application 73 | pythoncom.CoUninitialize() 74 | 75 | def test_only_currently_open_workbooks_can_be_found(self): 76 | pythoncom.CoInitialize() 77 | application = win32com.client.Dispatch("Excel.Application") 78 | 79 | wb1 = application.Workbooks.Add() 80 | original_workbook_list = safexl.workbooks_currently_open(application) 81 | self.assertIn(wb1, original_workbook_list) 82 | wb2 = application.Workbooks.Add() 83 | wb2.Close() 84 | new_workbook_list = safexl.toolkit.new_workbooks(application, original_workbook_list) 85 | self.assertNotIn(wb1, new_workbook_list) 86 | self.assertNotIn(wb2, new_workbook_list) 87 | self.assertEqual([], new_workbook_list) 88 | 89 | safexl.kill_all_instances_of_excel(application) 90 | del application 91 | pythoncom.CoUninitialize() 92 | 93 | def test_ref_to_workbook_remains_even_if_it_is_closed_after_being_added_to_list(self): 94 | """ 95 | pywin32 oddity, workbook COM object exists after closing, 96 | but cannot be used for anything without causing an error 97 | """ 98 | pythoncom.CoInitialize() 99 | application = win32com.client.Dispatch("Excel.Application") 100 | 101 | wb1 = application.Workbooks.Add() 102 | original_workbook_list = safexl.workbooks_currently_open(application) 103 | self.assertIn(wb1, original_workbook_list) 104 | wb2 = application.Workbooks.Add() 105 | new_workbook_list = safexl.toolkit.new_workbooks(application, original_workbook_list) 106 | wb2.Close() 107 | with self.assertRaises(pywintypes.com_error): 108 | wb_name = wb2.Name 109 | self.assertNotIn(wb1, new_workbook_list) 110 | self.assertIn(wb2, new_workbook_list) 111 | self.assertEqual([wb2], new_workbook_list) 112 | 113 | safexl.kill_all_instances_of_excel(application) 114 | del application 115 | pythoncom.CoUninitialize() 116 | 117 | 118 | class test_see_excel(unittest.TestCase): 119 | def test_ability_to_make_multiple_windows_visible(self): 120 | pythoncom.CoInitialize() 121 | application = win32com.client.Dispatch("Excel.Application") 122 | 123 | wb = application.Workbooks.Add() 124 | # Open 5 windows at one time 125 | original_window = wb.Windows(1) 126 | original_window.Visible = True 127 | self.assertEqual(wb.Name, original_window.Caption) 128 | for i in range(4): 129 | new_window = original_window.NewWindow() 130 | new_window.WindowState = safexl.xl_constants.xlMinimized 131 | new_window.Visible = False 132 | 133 | self.assertEqual(5, wb.Windows.Count) 134 | self.assertEqual(1, sum(1 for window in wb.Windows if window.Visible)) 135 | self.assertEqual(4, sum(1 for window in wb.Windows if not window.Visible)) 136 | safexl.see_excel([wb], safexl.xl_constants.xlMinimized) 137 | self.assertEqual(5, wb.Windows.Count) 138 | self.assertEqual(5, sum(1 for window in wb.Windows if window.Visible)) 139 | self.assertEqual(0, sum(1 for window in wb.Windows if not window.Visible)) 140 | 141 | # cleanup 142 | application.DisplayAlerts = False 143 | for window in wb.Windows: 144 | window.Close() 145 | application.DisplayAlerts = True 146 | safexl.kill_all_instances_of_excel(application) 147 | del application 148 | pythoncom.CoUninitialize() 149 | 150 | def test_error_occurs_when_a_workbook_has_no_windows_at_all(self): 151 | pythoncom.CoInitialize() 152 | application = win32com.client.Dispatch("Excel.Application") 153 | 154 | wb = application.Workbooks.Add() 155 | wb.Windows(1).Close() 156 | 157 | with self.assertRaises(pywintypes.com_error): 158 | window_caption = wb.Windows(1).Caption 159 | 160 | with self.assertRaises(pywintypes.com_error): 161 | # Once the final window of a workbook has closed, the workbook itself closes... 162 | wb_name = wb.Name 163 | 164 | with self.assertRaises(pywintypes.com_error): 165 | # So there is nothing to 'see' here anymore 166 | safexl.see_excel([wb], safexl.xl_constants.xlMinimized) 167 | 168 | application.DisplayAlerts = True 169 | safexl.kill_all_instances_of_excel(application) 170 | del application 171 | pythoncom.CoUninitialize() 172 | 173 | def test_PERSONAL_workbook_is_not_affected(self): 174 | with safexl.application(kill_after=True) as app: 175 | personal_wb_paths = [wb for wb in app.Workbooks if "PERSONAL.XLSB" in wb.FullName] 176 | if personal_wb_paths: 177 | personal_wb = personal_wb_paths[0] 178 | self.assertFalse(personal_wb.Windows(1).Visible) 179 | safexl.see_excel([personal_wb], safexl.xl_constants.xlMinimized) 180 | self.assertFalse(personal_wb.Windows(1).Visible) 181 | 182 | 183 | class test_workbooks_currently_open(unittest.TestCase): 184 | @staticmethod 185 | def count_tempfiles(app): 186 | return sum(1 for file in safexl.workbooks_currently_open(app) if file.FullName.startswith("Book")) 187 | 188 | def test_that_results_update_immediately(self): 189 | safexl.kill_all_instances_of_excel() 190 | self.assertFalse(safexl.is_excel_open()) 191 | 192 | pythoncom.CoInitialize() 193 | application = win32com.client.Dispatch("Excel.Application") 194 | 195 | # no workbooks have been added yet 196 | openfiles_1 = self.count_tempfiles(application) 197 | self.assertEqual(0, openfiles_1) 198 | 199 | # 1 workbook added, 1 more .tmp file than before 200 | wb1 = application.Workbooks.Add() 201 | openfiles_2 = self.count_tempfiles(application) 202 | self.assertEqual(1, openfiles_2) 203 | self.assertEqual(openfiles_1 + 1, openfiles_2) 204 | 205 | # 2 workbooks added, 1 more .tmp file than before 206 | wb2 = application.Workbooks.Add() 207 | openfiles_3 = self.count_tempfiles(application) 208 | self.assertEqual(2, openfiles_3) 209 | self.assertEqual(openfiles_2 + 1, openfiles_3) 210 | 211 | # 1 workbook removed, 1 less .tmp file than before 212 | application.DisplayAlerts = False 213 | wb2.Close(SaveChanges=False) 214 | application.DisplayAlerts = True 215 | openfiles_4 = self.count_tempfiles(application) 216 | self.assertEqual(1, openfiles_4) 217 | self.assertEqual(openfiles_3 - 1, openfiles_4) 218 | 219 | # 2 workbooks removed, 1 less .tmp file than before, back to beginning 220 | application.DisplayAlerts = False 221 | wb1.Close(SaveChanges=False) 222 | application.DisplayAlerts = True 223 | openfiles_5 = self.count_tempfiles(application) 224 | self.assertEqual(0, openfiles_5) 225 | self.assertEqual(openfiles_4 - 1, openfiles_5) 226 | self.assertEqual(openfiles_5, openfiles_1) 227 | 228 | safexl.kill_all_instances_of_excel(application) 229 | del application 230 | pythoncom.CoUninitialize() 231 | 232 | def test_that_newly_saved_file_is_noticed_and_then_lost_when_it_is_closed(self): 233 | pythoncom.CoInitialize() 234 | application = win32com.client.Dispatch("Excel.Application") 235 | 236 | wb1 = application.Workbooks.Add() 237 | with tempfile.TemporaryDirectory() as temp_dir: 238 | save_filepath = f"{temp_dir}\\temporary.xlsx" 239 | application.DisplayAlerts = False 240 | wb1.SaveAs(save_filepath) 241 | 242 | self.assertIn(save_filepath, [wb.FullName for wb in safexl.workbooks_currently_open(application)]) 243 | wb1.Close() 244 | self.assertNotIn(save_filepath, [wb.FullName for wb in safexl.workbooks_currently_open(application)]) 245 | 246 | application.DisplayAlerts = True 247 | 248 | safexl.kill_all_instances_of_excel(application) 249 | del application 250 | pythoncom.CoUninitialize() 251 | 252 | 253 | class test_last_row(unittest.TestCase): 254 | def test_row_count_increases_and_decreases(self): 255 | pythoncom.CoInitialize() 256 | application = win32com.client.Dispatch("Excel.Application") 257 | 258 | wb = application.Workbooks.Add() 259 | ws = wb.ActiveSheet 260 | ws.Range("A1").Value = 1 261 | self.assertEqual(1, safexl.last_row(ws)) 262 | ws.Range("A2").Value = 1 263 | self.assertEqual(2, safexl.last_row(ws)) 264 | ws.Range("A2").Value = "" 265 | self.assertEqual(1, safexl.last_row(ws)) 266 | 267 | safexl.kill_all_instances_of_excel(application) 268 | del application 269 | pythoncom.CoUninitialize() 270 | 271 | def test_if_highest_row_number_is_not_in_column_a(self): 272 | pythoncom.CoInitialize() 273 | application = win32com.client.Dispatch("Excel.Application") 274 | 275 | wb = application.Workbooks.Add() 276 | ws = wb.ActiveSheet 277 | ws.Range("A1").Value = 1 278 | self.assertEqual(1, safexl.last_row(ws)) 279 | ws.Range("B2").Value = 1 280 | self.assertEqual(2, safexl.last_row(ws)) 281 | 282 | safexl.kill_all_instances_of_excel(application) 283 | del application 284 | pythoncom.CoUninitialize() 285 | 286 | def test_stays_focused_on_currentregion(self): 287 | pythoncom.CoInitialize() 288 | application = win32com.client.Dispatch("Excel.Application") 289 | 290 | wb = application.Workbooks.Add() 291 | ws = wb.ActiveSheet 292 | ws.Range("A1").Value = 1 293 | self.assertEqual(1, safexl.last_row(ws)) 294 | ws.Range("A2").Value = "" 295 | ws.Range("A3").Value = 1 296 | self.assertEqual(1, safexl.last_row(ws)) 297 | 298 | safexl.kill_all_instances_of_excel(application) 299 | del application 300 | pythoncom.CoUninitialize() 301 | 302 | 303 | class test_last_column(unittest.TestCase): 304 | def test_column_count_increases_and_decreases(self): 305 | pythoncom.CoInitialize() 306 | application = win32com.client.Dispatch("Excel.Application") 307 | 308 | wb = application.Workbooks.Add() 309 | ws = wb.ActiveSheet 310 | ws.Range("A1").Value = 1 311 | self.assertEqual(1, safexl.last_column(ws)) 312 | ws.Range("B1").Value = 1 313 | self.assertEqual(2, safexl.last_column(ws)) 314 | ws.Range("B1").Value = "" 315 | self.assertEqual(1, safexl.last_column(ws)) 316 | 317 | safexl.kill_all_instances_of_excel(application) 318 | del application 319 | pythoncom.CoUninitialize() 320 | 321 | def test_if_highest_column_number_is_not_in_row_1(self): 322 | pythoncom.CoInitialize() 323 | application = win32com.client.Dispatch("Excel.Application") 324 | 325 | wb = application.Workbooks.Add() 326 | ws = wb.ActiveSheet 327 | ws.Range("A1").Value = 1 328 | self.assertEqual(1, safexl.last_column(ws)) 329 | ws.Range("B2").Value = 1 330 | self.assertEqual(2, safexl.last_column(ws)) 331 | 332 | safexl.kill_all_instances_of_excel(application) 333 | del application 334 | pythoncom.CoUninitialize() 335 | 336 | def test_stays_focused_on_currentregion(self): 337 | pythoncom.CoInitialize() 338 | application = win32com.client.Dispatch("Excel.Application") 339 | 340 | wb = application.Workbooks.Add() 341 | ws = wb.ActiveSheet 342 | ws.Range("A1").Value = 1 343 | self.assertEqual(1, safexl.last_column(ws)) 344 | ws.Range("B1").Value = "" 345 | ws.Range("C1").Value = 1 346 | self.assertEqual(1, safexl.last_column(ws)) 347 | 348 | safexl.kill_all_instances_of_excel(application) 349 | del application 350 | pythoncom.CoUninitialize() 351 | 352 | 353 | class test_worksheet_name_sanitization(unittest.TestCase): 354 | def test_len_limit_is_31(self): 355 | input_name = "0123456789012345678901234567890123456789" 356 | self.assertEqual(40, len(input_name)) 357 | expectation = "0123456789012345678901234567890" 358 | self.assertEqual(31, len(expectation)) 359 | result = safexl.worksheet_name_sanitization(input_name) 360 | self.assertEqual(expectation, result) 361 | 362 | def test_empty_string_causes_error(self): 363 | input_name = "" 364 | with self.assertRaises(safexl.toolkit.ExcelError): 365 | result = safexl.worksheet_name_sanitization(input_name) 366 | 367 | def test_invalid_characters(self): 368 | input_name = "\\/*[]:?a" 369 | expectation = "a" 370 | result = safexl.worksheet_name_sanitization(input_name) 371 | self.assertEqual(expectation, result) 372 | -------------------------------------------------------------------------------- /safexl/tests/test_psutil_wrappers.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 safexl 2 | import unittest 3 | import tempfile 4 | import pythoncom 5 | import pywintypes 6 | import win32com.client 7 | import safexl 8 | 9 | 10 | class test_is_excel_open(unittest.TestCase): 11 | def test_when_excel_is_open(self): 12 | pythoncom.CoInitialize() 13 | application = win32com.client.Dispatch("Excel.Application") 14 | self.assertTrue(safexl.is_excel_open()) 15 | safexl.kill_all_instances_of_excel(application) 16 | del application 17 | pythoncom.CoUninitialize() 18 | 19 | def test_when_excel_is_not_open(self): 20 | safexl.kill_all_instances_of_excel() 21 | self.assertFalse(safexl.is_excel_open()) 22 | 23 | 24 | class test_excel_open_files(unittest.TestCase): 25 | @staticmethod 26 | def count_tempfiles(): 27 | return sum(1 for file in safexl.toolkit.excel_open_files() if file.endswith(".tmp")) 28 | 29 | def test_that_results_update_immediately(self): 30 | safexl.kill_all_instances_of_excel() 31 | self.assertFalse(safexl.is_excel_open()) 32 | 33 | pythoncom.CoInitialize() 34 | application = win32com.client.Dispatch("Excel.Application") 35 | 36 | # no workbooks have been added yet 37 | open_files_1 = self.count_tempfiles() 38 | self.assertEqual(0, open_files_1) 39 | 40 | # 1 workbook added, 1 more .tmp file than before 41 | wb1 = application.Workbooks.Add() 42 | open_files_2 = self.count_tempfiles() 43 | self.assertEqual(1, open_files_2) 44 | self.assertEqual(open_files_1 + 1, open_files_2) 45 | 46 | # 2 workbooks added, 1 more .tmp file than before 47 | wb2 = application.Workbooks.Add() 48 | open_files_3 = self.count_tempfiles() 49 | self.assertEqual(2, open_files_3) 50 | self.assertEqual(open_files_2 + 1, open_files_3) 51 | 52 | # 1 workbook removed, 1 less .tmp file than before 53 | application.DisplayAlerts = False 54 | wb2.Close(SaveChanges=False) 55 | application.DisplayAlerts = True 56 | open_files_4 = self.count_tempfiles() 57 | self.assertEqual(1, open_files_4) 58 | self.assertEqual(open_files_3 - 1, open_files_4) 59 | 60 | # 2 workbooks removed, 1 less .tmp file than before, back to beginning 61 | application.DisplayAlerts = False 62 | wb1.Close(SaveChanges=False) 63 | application.DisplayAlerts = True 64 | open_files_5 = self.count_tempfiles() 65 | self.assertEqual(0, open_files_5) 66 | self.assertEqual(open_files_4 - 1, open_files_5) 67 | self.assertEqual(open_files_5, open_files_1) 68 | 69 | safexl.kill_all_instances_of_excel(application) 70 | del application 71 | pythoncom.CoUninitialize() 72 | 73 | def test_that_newly_saved_file_is_picked_up_and_lost_when_closed(self): 74 | pythoncom.CoInitialize() 75 | application = win32com.client.Dispatch("Excel.Application") 76 | 77 | wb1 = application.Workbooks.Add() 78 | with tempfile.TemporaryDirectory() as temp_dir: 79 | save_filepath = f"{temp_dir}\\temporary.xlsx" 80 | application.DisplayAlerts = False 81 | wb1.SaveAs(save_filepath) 82 | 83 | self.assertIn(save_filepath, safexl.toolkit.excel_open_files()) 84 | wb1.Close() 85 | self.assertNotIn(save_filepath, safexl.toolkit.excel_open_files()) 86 | 87 | application.DisplayAlerts = True 88 | 89 | safexl.kill_all_instances_of_excel(application) 90 | del application 91 | pythoncom.CoUninitialize() 92 | 93 | 94 | class test_kill_all_instances_of_excel(unittest.TestCase): 95 | def test_can_kill_excel_instance(self): 96 | pythoncom.CoInitialize() 97 | application = win32com.client.Dispatch("Excel.Application") 98 | 99 | self.assertEqual("Microsoft Excel", application.Name) 100 | safexl.kill_all_instances_of_excel() 101 | with self.assertRaises(pywintypes.com_error): 102 | app_name = application.Name 103 | 104 | del application 105 | pythoncom.CoUninitialize() 106 | 107 | def test_can_kill_excel_instance_when_passed_app(self): 108 | pythoncom.CoInitialize() 109 | application = win32com.client.Dispatch("Excel.Application") 110 | 111 | self.assertEqual("Microsoft Excel", application.Name) 112 | safexl.kill_all_instances_of_excel(application) 113 | with self.assertRaises(pywintypes.com_error): 114 | app_name = application.Name 115 | 116 | del application 117 | pythoncom.CoUninitialize() 118 | 119 | def test_can_kill_multiple_excel_instances(self): 120 | pythoncom.CoInitialize() 121 | 122 | # Using DispatchEx specifically here to create multiple instances of Excel open at once 123 | application1 = win32com.client.DispatchEx("Excel.Application") 124 | application2 = win32com.client.DispatchEx("Excel.Application") 125 | application3 = win32com.client.DispatchEx("Excel.Application") 126 | 127 | self.assertEqual("Microsoft Excel", application1.Name) 128 | self.assertEqual("Microsoft Excel", application2.Name) 129 | self.assertEqual("Microsoft Excel", application3.Name) 130 | 131 | safexl.kill_all_instances_of_excel() 132 | 133 | with self.assertRaises(pywintypes.com_error): 134 | app_name = application1.Name 135 | with self.assertRaises(pywintypes.com_error): 136 | app_name = application2.Name 137 | with self.assertRaises(pywintypes.com_error): 138 | app_name = application3.Name 139 | 140 | del application1 141 | del application2 142 | del application3 143 | pythoncom.CoUninitialize() 144 | -------------------------------------------------------------------------------- /safexl/toolkit.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 safexl 2 | from contextlib import contextmanager 3 | import psutil 4 | import pythoncom 5 | import win32com.client 6 | EXCEL_PROCESS_NAME = "EXCEL.EXE" 7 | 8 | __all__ = [ 9 | 'is_excel_open', 10 | 'kill_all_instances_of_excel', 11 | 'close_workbooks', 12 | 'see_excel', 13 | 'workbooks_currently_open', 14 | 'last_row', 15 | 'last_column', 16 | 'worksheet_name_sanitization', 17 | 'application', 18 | ] 19 | 20 | 21 | def is_excel_open() -> bool: 22 | """ 23 | Simple wrapper around `psutil.process_iter()` searching for individual processes of EXCEL.EXE 24 | :return: bool - Indicating whether or not Excel is open 25 | """ 26 | for proc in psutil.process_iter(): 27 | try: 28 | if proc.name() == EXCEL_PROCESS_NAME: 29 | return True 30 | except psutil.AccessDenied: 31 | pass 32 | return False 33 | 34 | 35 | def excel_open_files() -> list: 36 | """ 37 | Simple wrapper around `psutil.process_iter()` searching for individual processes of EXCEL.EXE and returning 38 | all the filepaths of the open files. Used here only for testing purposes, when an `app` object cannot 39 | necessarily be passed as well, as is the case with `workbooks_currently_open`. 40 | :return: list - Full of filepaths, including all open files, addin files, etc. Note that prior to saving a file it is 41 | given a .tmp filepath. 42 | """ 43 | result = [] 44 | for proc in psutil.process_iter(): 45 | try: 46 | if proc.name() == EXCEL_PROCESS_NAME: 47 | result.extend([popenfile.path for popenfile in proc.open_files()]) 48 | except psutil.AccessDenied: 49 | pass 50 | return result 51 | 52 | 53 | def kill_all_instances_of_excel(app: 'win32com.client.Dispatch("Excel.Application")' = None) -> None: 54 | """ 55 | Simple wrapper around `psutil.process_iter()` searching for individual processes of EXCEL.EXE, and killing each one it finds 56 | :param app: Optional win32com.client.Dispatch("Excel.Application") - Programmatic access to Excel application object 57 | :return: None 58 | """ 59 | if app: 60 | # If application is passed, try to shut it down peacefully first 61 | close_workbooks(app, app.Workbooks) 62 | app.Quit() 63 | del app 64 | 65 | for proc in psutil.process_iter(): 66 | try: 67 | if proc.name() == EXCEL_PROCESS_NAME: 68 | proc.kill() 69 | except (psutil.AccessDenied, psutil.NoSuchProcess): 70 | # passing on psutil.NoSuchProcess avoids erroring out if race conditions 71 | # close Excel *between* finding it and killing it with psutil 72 | pass 73 | 74 | 75 | def new_workbooks(app: 'win32com.client.Dispatch("Excel.Application")', workbooks_open_at_onset: iter) -> list: 76 | """ 77 | Determines which workbooks are open currently in comparison to list of `workbooks_open_at_onset`, returns the delta 78 | :param app: win32com.client.Dispatch("Excel.Application") - Programmatic access to Excel application object 79 | :param workbooks_open_at_onset: iterable - Full of workbook COM objects that you want to close without saving 80 | :return: iterable - Full of workbook COM objects that are both open currently and not present in your `workbooks_open_at_onset` 81 | """ 82 | paths_for_workbooks_open_at_onset = set(wb.FullName for wb in workbooks_open_at_onset) 83 | 84 | currently_open_workbooks = workbooks_currently_open(app) 85 | paths_for_currently_open_workbooks = set(wb.FullName for wb in currently_open_workbooks) 86 | 87 | paths_for_new_workbooks = paths_for_currently_open_workbooks - paths_for_workbooks_open_at_onset 88 | return [wb for wb in currently_open_workbooks if wb.FullName in paths_for_new_workbooks] 89 | 90 | 91 | def close_workbooks(app: 'win32com.client.Dispatch("Excel.Application")', workbooks: iter) -> None: 92 | """ 93 | Best practice pywin32 for close workbooks without saving 94 | :param app: win32com.client.Dispatch("Excel.Application") - Programmatic access to Excel application object 95 | :param workbooks: iterable - Full of workbook COM objects that you want to close without saving 96 | :return: None 97 | """ 98 | for wb in workbooks: 99 | app.DisplayAlerts = 0 100 | wb.Close(SaveChanges=False) 101 | app.DisplayAlerts = 1 102 | 103 | 104 | def see_excel(workbooks: iter, window_state: int) -> None: 105 | """ 106 | Makes every window of every workbook passed visible, will ignore the PERSONAL workbook and anything else in your StartupPath 107 | :param workbooks: iterable - Full of workbook COM objects whose windows you wish to maximize, minimize, or normalize 108 | :param window_state: int - xl_constant for Window.WindowState, available options include: 109 | * safexl.xl_constants.xlMaximized = -4137 110 | * safexl.xl_constants.xlMinimized = -4140 111 | * safexl.xl_constants.xlNormal = -4143 112 | :return: None 113 | """ 114 | for wb in workbooks: 115 | wb.Application.Visible = True 116 | 117 | # Ignore changing the visibility of any workbooks you have set to open in your StartupPath 118 | # such as the PERSONAL.XLSB 119 | if wb.Application.StartupPath in wb.FullName: 120 | continue 121 | 122 | for window in wb.Windows: 123 | window.Visible = True 124 | window.WindowState = window_state 125 | 126 | 127 | def workbooks_currently_open(app: 'win32com.client.Dispatch("Excel.Application")') -> list: 128 | """ 129 | Turns 'win32com.client.CDispatch' returned by `app.Workbooks` into Python list 130 | :param app: win32com.client.Dispatch("Excel.Application") - Programmatic access to Excel application object 131 | :return: list - Full of workbook COM objects currently open in Excel. Note that prior to saving a file it is given a generic 132 | non-path such as 'Book1', 'Book2', etc. 133 | """ 134 | return [wb for wb in app.Workbooks] 135 | 136 | 137 | def last_row(worksheet) -> int: 138 | """ 139 | Quick way to determine the number of rows in a worksheet. Assumes that data is within the `CurrentRegion` of cell A1. 140 | :param worksheet: Excel Worksheet COM object, such as the one created by code like: 141 | app = win32com.client.Dispatch("Excel.Application") 142 | wb = app.Workbooks.Add() 143 | ws = wb.ActiveSheet 144 | :return: int - indicating the number of rows a worksheet is using up 145 | """ 146 | return worksheet.Range("A1").CurrentRegion.Rows.Count 147 | 148 | 149 | def last_column(worksheet) -> int: 150 | """ 151 | Quick way to determine the number of columns in a worksheet. Assumes that data is within the `CurrentRegion` of cell A1. 152 | :param worksheet: Excel Worksheet COM object, such as the one created by code like: 153 | app = win32com.client.Dispatch("Excel.Application") 154 | wb = app.Workbooks.Add() 155 | ws = wb.ActiveSheet 156 | :return: int - indicating the number of columns a worksheet is using up 157 | """ 158 | return worksheet.Range("A1").CurrentRegion.Columns.Count 159 | 160 | 161 | def worksheet_name_sanitization(worksheet_name: str) -> str: 162 | """ 163 | Tool to cleanse worksheet names of common problems 164 | :param worksheet_name: str - String of name you're about to assign to a worksheet 165 | :return: str - String that won't cause an error when assigned to a worksheet. Note this function will throw an error 166 | itself if the result of removing the invalid worksheet name characters leaves you with an empty string only 167 | """ 168 | for char in ("\\", "/", "*", "[", "]", ":", "?"): 169 | worksheet_name = worksheet_name.replace(char, "") 170 | if not worksheet_name: 171 | raise ExcelError("Worksheet name cannot be empty string") 172 | return worksheet_name[:31] 173 | 174 | 175 | @contextmanager 176 | def application( 177 | kill_after: bool, 178 | maximize: bool = True, 179 | include_addins: bool = False, 180 | ) -> 'win32com.client.Dispatch("Excel.Application")': 181 | """ 182 | Wrapper for the pywin32 interface for handling programmatic access to the Excel Application from Python on Windows. 183 | This context-managed generator function will yield an Excel application COM object that is safer to use 184 | than a bare call to `win32com.client.Dispatch("Excel.Application")`. 185 | :param kill_after: bool - Programmatic access to Excel will be removed outside the `with` block, but this argument 186 | designates whether you wish to close the actual application as well, or to leave it running 187 | :param maximize: Optional bool - Defaults to `True`. Specifies what you would like to happen with your application windows, 188 | whether you want to maximize them or minimize them. This bool is contingent upon both 189 | your selection for `kill_after` and whether you run into an error during your `with` block. 190 | If `kill_after=True` then the code that maximizes or minimizes your windows will never 191 | be run, and the same goes for if Python encounters an error prior to reaching the end 192 | of your `with` block. In that way, the following 4 code snippets will have the same effect: 193 | 1.) with safexl.application(kill_after=True) as app: 194 | pass 195 | 2.) with safexl.application(kill_after=True, maximize=True) as app: 196 | pass 197 | 3.) with safexl.application(kill_after=True, maximize=False) as app: 198 | pass 199 | 3.) with safexl.application(kill_after=False) as app: 200 | raise 201 | :param include_addins: Optional bool - Defaults to `False`. As a feature (read "bug") Excel will not automatically 202 | load/open your *installed & active* Excel addins when an instance is called from code, 203 | neither Python nor VBA, as discussed in the following links: 204 | * https://stackoverflow.com/questions/213375/loading-addins-when-excel-is-instantiated-programmatically 205 | * https://www.mrexcel.com/board/threads/add-in-doesnt-load.849923/ 206 | The `include_addins` parameter indicates whether you would like to include the addins 207 | you have previously set to 'Installed' to show up in the Excel instance created. 208 | Similar to the `maximize` parameter, if an error occurs in your `with` block, or if you 209 | set `kill_after=True` it doesn't matter what value `include_addins` is, as that part of 210 | the code will not be executed. Please note there is a performance hit taken by setting 211 | this parameter to `True`, especially if you or your user has many addins installed. 212 | :return: win32com.client.Dispatch("Excel.Application") - Wrapped to follow best practices and clean up after itself 213 | Note, I specifically chose `Dispatch` over both `DispatchEx` and `EnsureDispatch` to avoid some odd bugs 214 | that can crop up with those methods, as discussed further on SO: 215 | * https://stackoverflow.com/questions/18648933/using-pywin32-what-is-the-difference-between-dispatch-and-dispatchex 216 | * https://stackoverflow.com/questions/22930751/autofilter-method-of-range-class-failed-dispatch-vs-ensuredispatch 217 | 218 | """ 219 | open_at_onset = is_excel_open() 220 | pythoncom.CoInitialize() 221 | _app = win32com.client.Dispatch("Excel.Application") 222 | if open_at_onset: 223 | workbooks_open_at_onset = workbooks_currently_open(_app) 224 | else: 225 | workbooks_open_at_onset = [] 226 | 227 | try: 228 | # For use inside a `with` block, with exceptions caught and cleaned up for you 229 | yield _app 230 | 231 | except Exception as e: 232 | err_msg = e 233 | 234 | else: 235 | err_msg = "" 236 | 237 | finally: 238 | workbooks_opened_during_with_block = new_workbooks(_app, workbooks_open_at_onset) 239 | if kill_after or err_msg: 240 | # If user wants to kill the app after the with block OR if an error occurs 241 | # close everything that was opened during this `with` block alone 242 | if workbooks_open_at_onset: 243 | # close newly created workbooks instead of killing the entire app 244 | close_workbooks(_app, workbooks_opened_during_with_block) 245 | else: 246 | # kill the app's entire presence on computer 247 | kill_all_instances_of_excel() 248 | else: 249 | # Excel Application oddity where addins are not visible on the ribbon even when installed 250 | # when app instance is created via code. Thankfully the `.Installed` attribute remains intact, 251 | # and to make your addins show up on the ribbon, you must turn the installed addins off and then on again... 252 | # See docstring for links describing the problem, this solution, and more details. 253 | if include_addins: 254 | for add_in in _app.AddIns: 255 | if add_in.Installed: 256 | add_in.Installed = False 257 | add_in.Installed = True 258 | 259 | # Running `see_excel` at the end here 260 | # makes sure that no Excel instances are left running in the background 261 | # as it is still easy to forget to make everything visible before leaving 262 | # a successful `with` block 263 | if maximize: 264 | see_excel(workbooks_opened_during_with_block, -4137) # xlMaximized 265 | else: 266 | see_excel(workbooks_opened_during_with_block, -4140) # xlMinimized 267 | 268 | del _app 269 | pythoncom.CoUninitialize() 270 | if err_msg: 271 | raise ExcelError(err_msg) 272 | 273 | 274 | class ExcelError(Exception): 275 | pass 276 | -------------------------------------------------------------------------------- /safexl/xl_constants.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 safexl 2 | 3 | # A config file to capture Excel constants for later use 4 | # these are also available from `win32com.client.constants` 5 | # though not in a format that plays nicely with autocomplete in IDEs 6 | # Can be accessed like - `safexl.xl_constants.xlToLeft` 7 | 8 | # Constants 9 | xlAll = -4104 10 | xlAutomatic = -4105 11 | xlBoth = 1 12 | xlCenter = -4108 13 | xlChecker = 9 14 | xlCircle = 8 15 | xlCorner = 2 16 | xlCrissCross = 16 17 | xlCross = 4 18 | xlDiamond = 2 19 | xlDistributed = -4117 20 | xlDoubleAccounting = 5 21 | xlFixedValue = 1 22 | xlFormats = -4122 23 | xlGray16 = 17 24 | xlGray8 = 18 25 | xlGrid = 15 26 | xlHigh = -4127 27 | xlInside = 2 28 | xlJustify = -4130 29 | xlLightDown = 13 30 | xlLightHorizontal = 11 31 | xlLightUp = 14 32 | xlLightVertical = 12 33 | xlLow = -4134 34 | xlManual = -4135 35 | xlMinusValues = 3 36 | xlModule = -4141 37 | xlNextToAxis = 4 38 | xlNone = -4142 39 | xlNotes = -4144 40 | xlOff = -4146 41 | xlOn = 1 42 | xlPercent = 2 43 | xlPlus = 9 44 | xlPlusValues = 2 45 | xlSemiGray75 = 10 46 | xlShowLabel = 4 47 | xlShowLabelAndPercent = 5 48 | xlShowPercent = 3 49 | xlShowValue = 2 50 | xlSimple = -4154 51 | xlSingle = 2 52 | xlSingleAccounting = 4 53 | xlSolid = 1 54 | xlSquare = 1 55 | xlStar = 5 56 | xlStError = 4 57 | xlToolbarButton = 2 58 | xlTriangle = 3 59 | xlGray25 = -4124 60 | xlGray50 = -4125 61 | xlGray75 = -4126 62 | xlBottom = -4107 63 | xlLeft = -4131 64 | xlRight = -4152 65 | xlTop = -4160 66 | xl3DBar = -4099 67 | xl3DSurface = -4103 68 | xlBar = 2 69 | xlColumn = 3 70 | xlCombination = -4111 71 | xlCustom = -4114 72 | xlDefaultAutoFormat = -1 73 | xlMaximum = 2 74 | xlMinimum = 4 75 | xlOpaque = 3 76 | xlTransparent = 2 77 | xlBidi = -5000 78 | xlLatin = -5001 79 | xlContext = -5002 80 | xlLTR = -5003 81 | xlRTL = -5004 82 | xlFullScript = 1 83 | xlPartialScript = 2 84 | xlMixedScript = 3 85 | xlMixedAuthorizedScript = 4 86 | xlVisualCursor = 2 87 | xlLogicalCursor = 1 88 | xlSystem = 1 89 | xlPartial = 3 90 | xlHindiNumerals = 3 91 | xlBidiCalendar = 3 92 | xlGregorian = 2 93 | xlComplete = 4 94 | xlScale = 3 95 | xlClosed = 3 96 | xlColor1 = 7 97 | xlColor2 = 8 98 | xlColor3 = 9 99 | xlConstants = 2 100 | xlContents = 2 101 | xlBelow = 1 102 | xlCascade = 7 103 | xlCenterAcrossSelection = 7 104 | xlChart4 = 2 105 | xlChartSeries = 17 106 | xlChartShort = 6 107 | xlChartTitles = 18 108 | xlClassic1 = 1 109 | xlClassic2 = 2 110 | xlClassic3 = 3 111 | xl3DEffects1 = 13 112 | xl3DEffects2 = 14 113 | xlAbove = 0 114 | xlAccounting1 = 4 115 | xlAccounting2 = 5 116 | xlAccounting3 = 6 117 | xlAccounting4 = 17 118 | xlAdd = 2 119 | xlDebugCodePane = 13 120 | xlDesktop = 9 121 | xlDirect = 1 122 | xlDivide = 5 123 | xlDoubleClosed = 5 124 | xlDoubleOpen = 4 125 | xlDoubleQuote = 1 126 | xlEntireChart = 20 127 | xlExcelMenus = 1 128 | xlExtended = 3 129 | xlFill = 5 130 | xlFirst = 0 131 | xlFloating = 5 132 | xlFormula = 5 133 | xlGeneral = 1 134 | xlGridline = 22 135 | xlIcons = 1 136 | xlImmediatePane = 12 137 | xlInteger = 2 138 | xlLast = 1 139 | xlLastCell = 11 140 | xlList1 = 10 141 | xlList2 = 11 142 | xlList3 = 12 143 | xlLocalFormat1 = 15 144 | xlLocalFormat2 = 16 145 | xlLong = 3 146 | xlLotusHelp = 2 147 | xlMacrosheetCell = 7 148 | xlMixed = 2 149 | xlMultiply = 4 150 | xlNarrow = 1 151 | xlNoDocuments = 3 152 | xlOpen = 2 153 | xlOutside = 3 154 | xlReference = 4 155 | xlSemiautomatic = 2 156 | xlShort = 1 157 | xlSingleQuote = 2 158 | xlStrict = 2 159 | xlSubtract = 3 160 | xlTextBox = 16 161 | xlTiled = 1 162 | xlTitleBar = 8 163 | xlToolbar = 1 164 | xlVisible = 12 165 | xlWatchPane = 11 166 | xlWide = 3 167 | xlWorkbookTab = 6 168 | xlWorksheet4 = 1 169 | xlWorksheetCell = 3 170 | xlWorksheetShort = 5 171 | xlAllExceptBorders = 7 172 | xlLeftToRight = 2 173 | xlTopToBottom = 1 174 | xlVeryHidden = 2 175 | xlDrawingObject = 14 176 | 177 | # XlCreator 178 | xlCreatorCode = 1480803660 179 | 180 | # XlChartGallery 181 | xlBuiltIn = 21 182 | xlUserDefined = 22 183 | xlAnyGallery = 23 184 | 185 | # XlColorIndex 186 | xlColorIndexAutomatic = -4105 187 | xlColorIndexNone = -4142 188 | 189 | # XlEndStyleCap 190 | xlCap = 1 191 | xlNoCap = 2 192 | 193 | # XlRowCol 194 | xlColumns = 2 195 | xlRows = 1 196 | 197 | # XlScaleType 198 | xlScaleLinear = -4132 199 | xlScaleLogarithmic = -4133 200 | 201 | # XlDataSeriesType 202 | xlAutoFill = 4 203 | xlChronological = 3 204 | xlGrowth = 2 205 | xlDataSeriesLinear = -4132 206 | 207 | # XlAxisCrosses 208 | xlAxisCrossesAutomatic = -4105 209 | xlAxisCrossesCustom = -4114 210 | xlAxisCrossesMaximum = 2 211 | xlAxisCrossesMinimum = 4 212 | 213 | # XlAxisGroup 214 | xlPrimary = 1 215 | xlSecondary = 2 216 | 217 | # XlBackground 218 | xlBackgroundAutomatic = -4105 219 | xlBackgroundOpaque = 3 220 | xlBackgroundTransparent = 2 221 | 222 | # XlWindowState 223 | xlMaximized = -4137 224 | xlMinimized = -4140 225 | xlNormal = -4143 226 | 227 | # XlAxisType 228 | xlCategory = 1 229 | xlSeriesAxis = 3 230 | xlValue = 2 231 | 232 | # XlArrowHeadLength 233 | xlArrowHeadLengthLong = 3 234 | xlArrowHeadLengthMedium = -4138 235 | xlArrowHeadLengthShort = 1 236 | 237 | # XlVAlign 238 | xlVAlignBottom = -4107 239 | xlVAlignCenter = -4108 240 | xlVAlignDistributed = -4117 241 | xlVAlignJustify = -4130 242 | xlVAlignTop = -4160 243 | 244 | # XlTickMark 245 | xlTickMarkCross = 4 246 | xlTickMarkInside = 2 247 | xlTickMarkNone = -4142 248 | xlTickMarkOutside = 3 249 | 250 | # XlErrorBarDirection 251 | xlX = -4168 252 | xlY = 1 253 | 254 | # XlErrorBarInclude 255 | xlErrorBarIncludeBoth = 1 256 | xlErrorBarIncludeMinusValues = 3 257 | xlErrorBarIncludeNone = -4142 258 | xlErrorBarIncludePlusValues = 2 259 | 260 | # XlDisplayBlanksAs 261 | xlInterpolated = 3 262 | xlNotPlotted = 1 263 | xlZero = 2 264 | 265 | # XlArrowHeadStyle 266 | xlArrowHeadStyleClosed = 3 267 | xlArrowHeadStyleDoubleClosed = 5 268 | xlArrowHeadStyleDoubleOpen = 4 269 | xlArrowHeadStyleNone = -4142 270 | xlArrowHeadStyleOpen = 2 271 | 272 | # XlArrowHeadWidth 273 | xlArrowHeadWidthMedium = -4138 274 | xlArrowHeadWidthNarrow = 1 275 | xlArrowHeadWidthWide = 3 276 | 277 | # XlHAlign 278 | xlHAlignCenter = -4108 279 | xlHAlignCenterAcrossSelection = 7 280 | xlHAlignDistributed = -4117 281 | xlHAlignFill = 5 282 | xlHAlignGeneral = 1 283 | xlHAlignJustify = -4130 284 | xlHAlignLeft = -4131 285 | xlHAlignRight = -4152 286 | 287 | # XlTickLabelPosition 288 | xlTickLabelPositionHigh = -4127 289 | xlTickLabelPositionLow = -4134 290 | xlTickLabelPositionNextToAxis = 4 291 | xlTickLabelPositionNone = -4142 292 | 293 | # XlLegendPosition 294 | xlLegendPositionBottom = -4107 295 | xlLegendPositionCorner = 2 296 | xlLegendPositionLeft = -4131 297 | xlLegendPositionRight = -4152 298 | xlLegendPositionTop = -4160 299 | 300 | # XlChartPictureType 301 | xlStackScale = 3 302 | xlStack = 2 303 | xlStretch = 1 304 | 305 | # XlChartPicturePlacement 306 | xlSides = 1 307 | xlEnd = 2 308 | xlEndSides = 3 309 | xlFront = 4 310 | xlFrontSides = 5 311 | xlFrontEnd = 6 312 | xlAllFaces = 7 313 | 314 | # XlOrientation 315 | xlDownward = -4170 316 | xlHorizontal = -4128 317 | xlUpward = -4171 318 | xlVertical = -4166 319 | 320 | # XlTickLabelOrientation 321 | xlTickLabelOrientationAutomatic = -4105 322 | xlTickLabelOrientationDownward = -4170 323 | xlTickLabelOrientationHorizontal = -4128 324 | xlTickLabelOrientationUpward = -4171 325 | xlTickLabelOrientationVertical = -4166 326 | 327 | # XlBorderWeight 328 | xlHairline = 1 329 | xlMedium = -4138 330 | xlThick = 4 331 | xlThin = 2 332 | 333 | # XlDataSeriesDate 334 | xlDay = 1 335 | xlMonth = 3 336 | xlWeekday = 2 337 | xlYear = 4 338 | 339 | # XlUnderlineStyle 340 | xlUnderlineStyleDouble = -4119 341 | xlUnderlineStyleDoubleAccounting = 5 342 | xlUnderlineStyleNone = -4142 343 | xlUnderlineStyleSingle = 2 344 | xlUnderlineStyleSingleAccounting = 4 345 | 346 | # XlErrorBarType 347 | xlErrorBarTypeCustom = -4114 348 | xlErrorBarTypeFixedValue = 1 349 | xlErrorBarTypePercent = 2 350 | xlErrorBarTypeStDev = -4155 351 | xlErrorBarTypeStError = 4 352 | 353 | # XlTrendlineType 354 | xlExponential = 5 355 | xlLinear = -4132 356 | xlLogarithmic = -4133 357 | xlMovingAvg = 6 358 | xlPolynomial = 3 359 | xlPower = 4 360 | 361 | # XlLineStyle 362 | xlContinuous = 1 363 | xlDash = -4115 364 | xlDashDot = 4 365 | xlDashDotDot = 5 366 | xlDot = -4118 367 | xlDouble = -4119 368 | xlSlantDashDot = 13 369 | xlLineStyleNone = -4142 370 | 371 | # XlDataLabelsType 372 | xlDataLabelsShowNone = -4142 373 | xlDataLabelsShowValue = 2 374 | xlDataLabelsShowPercent = 3 375 | xlDataLabelsShowLabel = 4 376 | xlDataLabelsShowLabelAndPercent = 5 377 | xlDataLabelsShowBubbleSizes = 6 378 | 379 | # XlMarkerStyle 380 | xlMarkerStyleAutomatic = -4105 381 | xlMarkerStyleCircle = 8 382 | xlMarkerStyleDash = -4115 383 | xlMarkerStyleDiamond = 2 384 | xlMarkerStyleDot = -4118 385 | xlMarkerStyleNone = -4142 386 | xlMarkerStylePicture = -4147 387 | xlMarkerStylePlus = 9 388 | xlMarkerStyleSquare = 1 389 | xlMarkerStyleStar = 5 390 | xlMarkerStyleTriangle = 3 391 | xlMarkerStyleX = -4168 392 | 393 | # XlPictureConvertorType 394 | xlBMP = 1 395 | xlCGM = 7 396 | xlDRW = 4 397 | xlDXF = 5 398 | xlEPS = 8 399 | xlHGL = 6 400 | xlPCT = 13 401 | xlPCX = 10 402 | xlPIC = 11 403 | xlPLT = 12 404 | xlTIF = 9 405 | xlWMF = 2 406 | xlWPG = 3 407 | 408 | # XlPattern 409 | xlPatternAutomatic = -4105 410 | xlPatternChecker = 9 411 | xlPatternCrissCross = 16 412 | xlPatternDown = -4121 413 | xlPatternGray16 = 17 414 | xlPatternGray25 = -4124 415 | xlPatternGray50 = -4125 416 | xlPatternGray75 = -4126 417 | xlPatternGray8 = 18 418 | xlPatternGrid = 15 419 | xlPatternHorizontal = -4128 420 | xlPatternLightDown = 13 421 | xlPatternLightHorizontal = 11 422 | xlPatternLightUp = 14 423 | xlPatternLightVertical = 12 424 | xlPatternNone = -4142 425 | xlPatternSemiGray75 = 10 426 | xlPatternSolid = 1 427 | xlPatternUp = -4162 428 | xlPatternVertical = -4166 429 | 430 | # XlChartSplitType 431 | xlSplitByPosition = 1 432 | xlSplitByPercentValue = 3 433 | xlSplitByCustomSplit = 4 434 | xlSplitByValue = 2 435 | 436 | # XlDisplayUnit 437 | xlHundreds = -2 438 | xlThousands = -3 439 | xlTenThousands = -4 440 | xlHundredThousands = -5 441 | xlMillions = -6 442 | xlTenMillions = -7 443 | xlHundredMillions = -8 444 | xlThousandMillions = -9 445 | xlMillionMillions = -10 446 | 447 | # XlDataLabelPosition 448 | xlLabelPositionCenter = -4108 449 | xlLabelPositionAbove = 0 450 | xlLabelPositionBelow = 1 451 | xlLabelPositionLeft = -4131 452 | xlLabelPositionRight = -4152 453 | xlLabelPositionOutsideEnd = 2 454 | xlLabelPositionInsideEnd = 3 455 | xlLabelPositionInsideBase = 4 456 | xlLabelPositionBestFit = 5 457 | xlLabelPositionMixed = 6 458 | xlLabelPositionCustom = 7 459 | 460 | # XlTimeUnit 461 | xlDays = 0 462 | xlMonths = 1 463 | xlYears = 2 464 | 465 | # XlCategoryType 466 | xlCategoryScale = 2 467 | xlTimeScale = 3 468 | xlAutomaticScale = -4105 469 | 470 | # XlBarShape 471 | xlBox = 0 472 | xlPyramidToPoint = 1 473 | xlPyramidToMax = 2 474 | xlCylinder = 3 475 | xlConeToPoint = 4 476 | xlConeToMax = 5 477 | 478 | # XlChartType 479 | xlColumnClustered = 51 480 | xlColumnStacked = 52 481 | xlColumnStacked100 = 53 482 | xl3DColumnClustered = 54 483 | xl3DColumnStacked = 55 484 | xl3DColumnStacked100 = 56 485 | xlBarClustered = 57 486 | xlBarStacked = 58 487 | xlBarStacked100 = 59 488 | xl3DBarClustered = 60 489 | xl3DBarStacked = 61 490 | xl3DBarStacked100 = 62 491 | xlLineStacked = 63 492 | xlLineStacked100 = 64 493 | xlLineMarkers = 65 494 | xlLineMarkersStacked = 66 495 | xlLineMarkersStacked100 = 67 496 | xlPieOfPie = 68 497 | xlPieExploded = 69 498 | xl3DPieExploded = 70 499 | xlBarOfPie = 71 500 | xlXYScatterSmooth = 72 501 | xlXYScatterSmoothNoMarkers = 73 502 | xlXYScatterLines = 74 503 | xlXYScatterLinesNoMarkers = 75 504 | xlAreaStacked = 76 505 | xlAreaStacked100 = 77 506 | xl3DAreaStacked = 78 507 | xl3DAreaStacked100 = 79 508 | xlDoughnutExploded = 80 509 | xlRadarMarkers = 81 510 | xlRadarFilled = 82 511 | xlSurface = 83 512 | xlSurfaceWireframe = 84 513 | xlSurfaceTopView = 85 514 | xlSurfaceTopViewWireframe = 86 515 | xlBubble = 15 516 | xlBubble3DEffect = 87 517 | xlStockHLC = 88 518 | xlStockOHLC = 89 519 | xlStockVHLC = 90 520 | xlStockVOHLC = 91 521 | xlCylinderColClustered = 92 522 | xlCylinderColStacked = 93 523 | xlCylinderColStacked100 = 94 524 | xlCylinderBarClustered = 95 525 | xlCylinderBarStacked = 96 526 | xlCylinderBarStacked100 = 97 527 | xlCylinderCol = 98 528 | xlConeColClustered = 99 529 | xlConeColStacked = 100 530 | xlConeColStacked100 = 101 531 | xlConeBarClustered = 102 532 | xlConeBarStacked = 103 533 | xlConeBarStacked100 = 104 534 | xlConeCol = 105 535 | xlPyramidColClustered = 106 536 | xlPyramidColStacked = 107 537 | xlPyramidColStacked100 = 108 538 | xlPyramidBarClustered = 109 539 | xlPyramidBarStacked = 110 540 | xlPyramidBarStacked100 = 111 541 | xlPyramidCol = 112 542 | xl3DColumn = -4100 543 | xlLine = 4 544 | xl3DLine = -4101 545 | xl3DPie = -4102 546 | xlPie = 5 547 | xlXYScatter = -4169 548 | xl3DArea = -4098 549 | xlArea = 1 550 | xlDoughnut = -4120 551 | xlRadar = -4151 552 | 553 | # XlChartItem 554 | xlDataLabel = 0 555 | xlChartArea = 2 556 | xlSeries = 3 557 | xlChartTitle = 4 558 | xlWalls = 5 559 | xlCorners = 6 560 | xlDataTable = 7 561 | xlTrendline = 8 562 | xlErrorBars = 9 563 | xlXErrorBars = 10 564 | xlYErrorBars = 11 565 | xlLegendEntry = 12 566 | xlLegendKey = 13 567 | xlShape = 14 568 | xlMajorGridlines = 15 569 | xlMinorGridlines = 16 570 | xlAxisTitle = 17 571 | xlUpBars = 18 572 | xlPlotArea = 19 573 | xlDownBars = 20 574 | xlAxis = 21 575 | xlSeriesLines = 22 576 | xlFloor = 23 577 | xlLegend = 24 578 | xlHiLoLines = 25 579 | xlDropLines = 26 580 | xlRadarAxisLabels = 27 581 | xlNothing = 28 582 | xlLeaderLines = 29 583 | xlDisplayUnitLabel = 30 584 | xlPivotChartFieldButton = 31 585 | xlPivotChartDropZone = 32 586 | 587 | # XlSizeRepresents 588 | xlSizeIsWidth = 2 589 | xlSizeIsArea = 1 590 | 591 | # XlInsertShiftDirection 592 | xlShiftDown = -4121 593 | xlShiftToRight = -4161 594 | 595 | # XlDeleteShiftDirection 596 | xlShiftToLeft = -4159 597 | xlShiftUp = -4162 598 | 599 | # XlDirection 600 | xlDown = -4121 601 | xlToLeft = -4159 602 | xlToRight = -4161 603 | xlUp = -4162 604 | 605 | # XlConsolidationFunction 606 | xlAverage = -4106 607 | xlCount = -4112 608 | xlCountNums = -4113 609 | xlMax = -4136 610 | xlMin = -4139 611 | xlProduct = -4149 612 | xlStDev = -4155 613 | xlStDevP = -4156 614 | xlSum = -4157 615 | xlVar = -4164 616 | xlVarP = -4165 617 | xlUnknown = 1000 618 | 619 | # XlSheetType 620 | xlChart = -4109 621 | xlDialogSheet = -4116 622 | xlExcel4IntlMacroSheet = 4 623 | xlExcel4MacroSheet = 3 624 | xlWorksheet = -4167 625 | 626 | # XlLocationInTable 627 | xlColumnHeader = -4110 628 | xlColumnItem = 5 629 | xlDataHeader = 3 630 | xlDataItem = 7 631 | xlPageHeader = 2 632 | xlPageItem = 6 633 | xlRowHeader = -4153 634 | xlRowItem = 4 635 | xlTableBody = 8 636 | 637 | # XlFindLookIn 638 | xlFormulas = -4123 639 | xlComments = -4144 640 | xlValues = -4163 641 | 642 | # XlWindowType 643 | xlChartAsWindow = 5 644 | xlChartInPlace = 4 645 | xlClipboard = 3 646 | xlInfo = -4129 647 | xlWorkbook = 1 648 | 649 | # XlPivotFieldDataType 650 | xlDate = 2 651 | xlNumber = -4145 652 | xlText = -4158 653 | 654 | # XlCopyPictureFormat 655 | xlBitmap = 2 656 | xlPicture = -4147 657 | 658 | # XlPivotTableSourceType 659 | xlScenario = 4 660 | xlConsolidation = 3 661 | xlDatabase = 1 662 | xlExternal = 2 663 | xlPivotTable = -4148 664 | 665 | # XlReferenceStyle 666 | xlA1 = 1 667 | xlR1C1 = -4150 668 | 669 | # XlMSApplication 670 | xlMicrosoftAccess = 4 671 | xlMicrosoftFoxPro = 5 672 | xlMicrosoftMail = 3 673 | xlMicrosoftPowerPoint = 2 674 | xlMicrosoftProject = 6 675 | xlMicrosoftSchedulePlus = 7 676 | xlMicrosoftWord = 1 677 | 678 | # XlMouseButton 679 | xlNoButton = 0 680 | xlPrimaryButton = 1 681 | xlSecondaryButton = 2 682 | 683 | # XlCutCopyMode 684 | xlCopy = 1 685 | xlCut = 2 686 | 687 | # XlFillWith 688 | xlFillWithAll = -4104 689 | xlFillWithContents = 2 690 | xlFillWithFormats = -4122 691 | 692 | # XlFilterAction 693 | xlFilterCopy = 2 694 | xlFilterInPlace = 1 695 | 696 | # XlOrder 697 | xlDownThenOver = 1 698 | xlOverThenDown = 2 699 | 700 | # XlLinkType 701 | xlLinkTypeExcelLinks = 1 702 | xlLinkTypeOLELinks = 2 703 | 704 | # XlApplyNamesOrder 705 | xlColumnThenRow = 2 706 | xlRowThenColumn = 1 707 | 708 | # XlEnableCancelKey 709 | xlDisabled = 0 710 | xlErrorHandler = 2 711 | xlInterrupt = 1 712 | 713 | # XlPageBreak 714 | xlPageBreakAutomatic = -4105 715 | xlPageBreakManual = -4135 716 | xlPageBreakNone = -4142 717 | 718 | # XlOLEType 719 | xlOLEControl = 2 720 | xlOLEEmbed = 1 721 | xlOLELink = 0 722 | 723 | # XlPageOrientation 724 | xlLandscape = 2 725 | xlPortrait = 1 726 | 727 | # XlLinkInfo 728 | xlEditionDate = 2 729 | xlUpdateState = 1 730 | xlLinkInfoStatus = 3 731 | 732 | # XlCommandUnderlines 733 | xlCommandUnderlinesAutomatic = -4105 734 | xlCommandUnderlinesOff = -4146 735 | xlCommandUnderlinesOn = 1 736 | 737 | # XlOLEVerb 738 | xlVerbOpen = 2 739 | xlVerbPrimary = 1 740 | 741 | # XlCalculation 742 | xlCalculationAutomatic = -4105 743 | xlCalculationManual = -4135 744 | xlCalculationSemiautomatic = 2 745 | 746 | # XlFileAccess 747 | xlReadOnly = 3 748 | xlReadWrite = 2 749 | 750 | # XlEditionType 751 | xlPublisher = 1 752 | xlSubscriber = 2 753 | 754 | # XlObjectSize 755 | xlFitToPage = 2 756 | xlFullPage = 3 757 | xlScreenSize = 1 758 | 759 | # XlLookAt 760 | xlPart = 2 761 | xlWhole = 1 762 | 763 | # XlMailSystem 764 | xlMAPI = 1 765 | xlNoMailSystem = 0 766 | xlPowerTalk = 2 767 | 768 | # XlLinkInfoType 769 | xlLinkInfoOLELinks = 2 770 | xlLinkInfoPublishers = 5 771 | xlLinkInfoSubscribers = 6 772 | 773 | # XlCVError 774 | xlErrDiv0 = 2007 775 | xlErrNA = 2042 776 | xlErrName = 2029 777 | xlErrNull = 2000 778 | xlErrNum = 2036 779 | xlErrRef = 2023 780 | xlErrValue = 2015 781 | 782 | # XlEditionFormat 783 | xlBIFF = 2 784 | xlPICT = 1 785 | xlRTF = 4 786 | xlVALU = 8 787 | 788 | # XlLink 789 | xlExcelLinks = 1 790 | xlOLELinks = 2 791 | xlPublishers = 5 792 | xlSubscribers = 6 793 | 794 | # XlCellType 795 | xlCellTypeBlanks = 4 796 | xlCellTypeConstants = 2 797 | xlCellTypeFormulas = -4123 798 | xlCellTypeLastCell = 11 799 | xlCellTypeComments = -4144 800 | xlCellTypeVisible = 12 801 | xlCellTypeAllFormatConditions = -4172 802 | xlCellTypeSameFormatConditions = -4173 803 | xlCellTypeAllValidation = -4174 804 | xlCellTypeSameValidation = -4175 805 | 806 | # XlArrangeStyle 807 | xlArrangeStyleCascade = 7 808 | xlArrangeStyleHorizontal = -4128 809 | xlArrangeStyleTiled = 1 810 | xlArrangeStyleVertical = -4166 811 | 812 | # XlMousePointer 813 | xlIBeam = 3 814 | xlDefault = -4143 815 | xlNorthwestArrow = 1 816 | xlWait = 2 817 | 818 | # XlEditionOptionsOption 819 | xlAutomaticUpdate = 4 820 | xlCancel = 1 821 | xlChangeAttributes = 6 822 | xlManualUpdate = 5 823 | xlOpenSource = 3 824 | xlSelect = 3 825 | xlSendPublisher = 2 826 | xlUpdateSubscriber = 2 827 | 828 | # XlAutoFillType 829 | xlFillCopy = 1 830 | xlFillDays = 5 831 | xlFillDefault = 0 832 | xlFillFormats = 3 833 | xlFillMonths = 7 834 | xlFillSeries = 2 835 | xlFillValues = 4 836 | xlFillWeekdays = 6 837 | xlFillYears = 8 838 | xlGrowthTrend = 10 839 | xlLinearTrend = 9 840 | 841 | # XlAutoFilterOperator 842 | xlAnd = 1 843 | xlBottom10Items = 4 844 | xlBottom10Percent = 6 845 | xlOr = 2 846 | xlTop10Items = 3 847 | xlTop10Percent = 5 848 | 849 | # XlClipboardFormat 850 | xlClipboardFormatBIFF = 8 851 | xlClipboardFormatBIFF2 = 18 852 | xlClipboardFormatBIFF3 = 20 853 | xlClipboardFormatBIFF4 = 30 854 | xlClipboardFormatBinary = 15 855 | xlClipboardFormatBitmap = 9 856 | xlClipboardFormatCGM = 13 857 | xlClipboardFormatCSV = 5 858 | xlClipboardFormatDIF = 4 859 | xlClipboardFormatDspText = 12 860 | xlClipboardFormatEmbeddedObject = 21 861 | xlClipboardFormatEmbedSource = 22 862 | xlClipboardFormatLink = 11 863 | xlClipboardFormatLinkSource = 23 864 | xlClipboardFormatLinkSourceDesc = 32 865 | xlClipboardFormatMovie = 24 866 | xlClipboardFormatNative = 14 867 | xlClipboardFormatObjectDesc = 31 868 | xlClipboardFormatObjectLink = 19 869 | xlClipboardFormatOwnerLink = 17 870 | xlClipboardFormatPICT = 2 871 | xlClipboardFormatPrintPICT = 3 872 | xlClipboardFormatRTF = 7 873 | xlClipboardFormatScreenPICT = 29 874 | xlClipboardFormatStandardFont = 28 875 | xlClipboardFormatStandardScale = 27 876 | xlClipboardFormatSYLK = 6 877 | xlClipboardFormatTable = 16 878 | xlClipboardFormatText = 0 879 | xlClipboardFormatToolFace = 25 880 | xlClipboardFormatToolFacePICT = 26 881 | xlClipboardFormatVALU = 1 882 | xlClipboardFormatWK1 = 10 883 | 884 | # XlFileFormat 885 | xlAddIn = 18 886 | xlCSV = 6 887 | xlCSVMac = 22 888 | xlCSVMSDOS = 24 889 | xlCSVWindows = 23 890 | xlDBF2 = 7 891 | xlDBF3 = 8 892 | xlDBF4 = 11 893 | xlDIF = 9 894 | xlExcel2 = 16 895 | xlExcel2FarEast = 27 896 | xlExcel3 = 29 897 | xlExcel4 = 33 898 | xlExcel5 = 39 899 | xlExcel7 = 39 900 | xlExcel9795 = 43 901 | xlExcel4Workbook = 35 902 | xlIntlAddIn = 26 903 | xlIntlMacro = 25 904 | xlWorkbookNormal = -4143 905 | xlSYLK = 2 906 | xlTemplate = 17 907 | xlCurrentPlatformText = -4158 908 | xlTextMac = 19 909 | xlTextMSDOS = 21 910 | xlTextPrinter = 36 911 | xlTextWindows = 20 912 | xlWJ2WD1 = 14 913 | xlWK1 = 5 914 | xlWK1ALL = 31 915 | xlWK1FMT = 30 916 | xlWK3 = 15 917 | xlWK4 = 38 918 | xlWK3FM3 = 32 919 | xlWKS = 4 920 | xlWorks2FarEast = 28 921 | xlWQ1 = 34 922 | xlWJ3 = 40 923 | xlWJ3FJ3 = 41 924 | xlUnicodeText = 42 925 | xlHtml = 44 926 | xlWebArchive = 45 927 | xlXMLSpreadsheet = 46 928 | 929 | # XlApplicationInternational 930 | xl24HourClock = 33 931 | xl4DigitYears = 43 932 | xlAlternateArraySeparator = 16 933 | xlColumnSeparator = 14 934 | xlCountryCode = 1 935 | xlCountrySetting = 2 936 | xlCurrencyBefore = 37 937 | xlCurrencyCode = 25 938 | xlCurrencyDigits = 27 939 | xlCurrencyLeadingZeros = 40 940 | xlCurrencyMinusSign = 38 941 | xlCurrencyNegative = 28 942 | xlCurrencySpaceBefore = 36 943 | xlCurrencyTrailingZeros = 39 944 | xlDateOrder = 32 945 | xlDateSeparator = 17 946 | xlDayCode = 21 947 | xlDayLeadingZero = 42 948 | xlDecimalSeparator = 3 949 | xlGeneralFormatName = 26 950 | xlHourCode = 22 951 | xlLeftBrace = 12 952 | xlLeftBracket = 10 953 | xlListSeparator = 5 954 | xlLowerCaseColumnLetter = 9 955 | xlLowerCaseRowLetter = 8 956 | xlMDY = 44 957 | xlMetric = 35 958 | xlMinuteCode = 23 959 | xlMonthCode = 20 960 | xlMonthLeadingZero = 41 961 | xlMonthNameChars = 30 962 | xlNoncurrencyDigits = 29 963 | xlNonEnglishFunctions = 34 964 | xlRightBrace = 13 965 | xlRightBracket = 11 966 | xlRowSeparator = 15 967 | xlSecondCode = 24 968 | xlThousandsSeparator = 4 969 | xlTimeLeadingZero = 45 970 | xlTimeSeparator = 18 971 | xlUpperCaseColumnLetter = 7 972 | xlUpperCaseRowLetter = 6 973 | xlWeekdayNameChars = 31 974 | xlYearCode = 19 975 | 976 | # XlPageBreakExtent 977 | xlPageBreakFull = 1 978 | xlPageBreakPartial = 2 979 | 980 | # XlCellInsertionMode 981 | xlOverwriteCells = 0 982 | xlInsertDeleteCells = 1 983 | xlInsertEntireRows = 2 984 | 985 | # XlFormulaLabel 986 | xlNoLabels = -4142 987 | xlRowLabels = 1 988 | xlColumnLabels = 2 989 | xlMixedLabels = 3 990 | 991 | # XlHighlightChangesTime 992 | xlSinceMyLastSave = 1 993 | xlAllChanges = 2 994 | xlNotYetReviewed = 3 995 | 996 | # XlCommentDisplayMode 997 | xlNoIndicator = 0 998 | xlCommentIndicatorOnly = -1 999 | xlCommentAndIndicator = 1 1000 | 1001 | # XlFormatConditionType 1002 | xlCellValue = 1 1003 | xlExpression = 2 1004 | 1005 | # XlFormatConditionOperator 1006 | xlBetween = 1 1007 | xlNotBetween = 2 1008 | xlEqual = 3 1009 | xlNotEqual = 4 1010 | xlGreater = 5 1011 | xlLess = 6 1012 | xlGreaterEqual = 7 1013 | xlLessEqual = 8 1014 | 1015 | # XlEnableSelection 1016 | xlNoRestrictions = 0 1017 | xlUnlockedCells = 1 1018 | xlNoSelection = -4142 1019 | 1020 | # XlDVType 1021 | xlValidateInputOnly = 0 1022 | xlValidateWholeNumber = 1 1023 | xlValidateDecimal = 2 1024 | xlValidateList = 3 1025 | xlValidateDate = 4 1026 | xlValidateTime = 5 1027 | xlValidateTextLength = 6 1028 | xlValidateCustom = 7 1029 | 1030 | # XlIMEMode 1031 | xlIMEModeNoControl = 0 1032 | xlIMEModeOn = 1 1033 | xlIMEModeOff = 2 1034 | xlIMEModeDisable = 3 1035 | xlIMEModeHiragana = 4 1036 | xlIMEModeKatakana = 5 1037 | xlIMEModeKatakanaHalf = 6 1038 | xlIMEModeAlphaFull = 7 1039 | xlIMEModeAlpha = 8 1040 | xlIMEModeHangulFull = 9 1041 | xlIMEModeHangul = 10 1042 | 1043 | # XlDVAlertStyle 1044 | xlValidAlertStop = 1 1045 | xlValidAlertWarning = 2 1046 | xlValidAlertInformation = 3 1047 | 1048 | # XlChartLocation 1049 | xlLocationAsNewSheet = 1 1050 | xlLocationAsObject = 2 1051 | xlLocationAutomatic = 3 1052 | 1053 | # XlPaperSize 1054 | xlPaper10x14 = 16 1055 | xlPaper11x17 = 17 1056 | xlPaperA3 = 8 1057 | xlPaperA4 = 9 1058 | xlPaperA4Small = 10 1059 | xlPaperA5 = 11 1060 | xlPaperB4 = 12 1061 | xlPaperB5 = 13 1062 | xlPaperCsheet = 24 1063 | xlPaperDsheet = 25 1064 | xlPaperEnvelope10 = 20 1065 | xlPaperEnvelope11 = 21 1066 | xlPaperEnvelope12 = 22 1067 | xlPaperEnvelope14 = 23 1068 | xlPaperEnvelope9 = 19 1069 | xlPaperEnvelopeB4 = 33 1070 | xlPaperEnvelopeB5 = 34 1071 | xlPaperEnvelopeB6 = 35 1072 | xlPaperEnvelopeC3 = 29 1073 | xlPaperEnvelopeC4 = 30 1074 | xlPaperEnvelopeC5 = 28 1075 | xlPaperEnvelopeC6 = 31 1076 | xlPaperEnvelopeC65 = 32 1077 | xlPaperEnvelopeDL = 27 1078 | xlPaperEnvelopeItaly = 36 1079 | xlPaperEnvelopeMonarch = 37 1080 | xlPaperEnvelopePersonal = 38 1081 | xlPaperEsheet = 26 1082 | xlPaperExecutive = 7 1083 | xlPaperFanfoldLegalGerman = 41 1084 | xlPaperFanfoldStdGerman = 40 1085 | xlPaperFanfoldUS = 39 1086 | xlPaperFolio = 14 1087 | xlPaperLedger = 4 1088 | xlPaperLegal = 5 1089 | xlPaperLetter = 1 1090 | xlPaperLetterSmall = 2 1091 | xlPaperNote = 18 1092 | xlPaperQuarto = 15 1093 | xlPaperStatement = 6 1094 | xlPaperTabloid = 3 1095 | xlPaperUser = 256 1096 | 1097 | # XlPasteSpecialOperation 1098 | xlPasteSpecialOperationAdd = 2 1099 | xlPasteSpecialOperationDivide = 5 1100 | xlPasteSpecialOperationMultiply = 4 1101 | xlPasteSpecialOperationNone = -4142 1102 | xlPasteSpecialOperationSubtract = 3 1103 | 1104 | # XlPasteType 1105 | xlPasteAll = -4104 1106 | xlPasteAllExceptBorders = 7 1107 | xlPasteFormats = -4122 1108 | xlPasteFormulas = -4123 1109 | xlPasteComments = -4144 1110 | xlPasteValues = -4163 1111 | xlPasteColumnWidths = 8 1112 | xlPasteValidation = 6 1113 | xlPasteFormulasAndNumberFormats = 11 1114 | xlPasteValuesAndNumberFormats = 12 1115 | 1116 | # XlPhoneticCharacterType 1117 | xlKatakanaHalf = 0 1118 | xlKatakana = 1 1119 | xlHiragana = 2 1120 | xlNoConversion = 3 1121 | 1122 | # XlPhoneticAlignment 1123 | xlPhoneticAlignNoControl = 0 1124 | xlPhoneticAlignLeft = 1 1125 | xlPhoneticAlignCenter = 2 1126 | xlPhoneticAlignDistributed = 3 1127 | 1128 | # XlPictureAppearance 1129 | xlPrinter = 2 1130 | xlScreen = 1 1131 | 1132 | # XlPivotFieldOrientation 1133 | xlColumnField = 2 1134 | xlDataField = 4 1135 | xlHidden = 0 1136 | xlPageField = 3 1137 | xlRowField = 1 1138 | 1139 | # XlPivotFieldCalculation 1140 | xlDifferenceFrom = 2 1141 | xlIndex = 9 1142 | xlNoAdditionalCalculation = -4143 1143 | xlPercentDifferenceFrom = 4 1144 | xlPercentOf = 3 1145 | xlPercentOfColumn = 7 1146 | xlPercentOfRow = 6 1147 | xlPercentOfTotal = 8 1148 | xlRunningTotal = 5 1149 | 1150 | # XlPlacement 1151 | xlFreeFloating = 3 1152 | xlMove = 2 1153 | xlMoveAndSize = 1 1154 | 1155 | # XlPlatform 1156 | xlMacintosh = 1 1157 | xlMSDOS = 3 1158 | xlWindows = 2 1159 | 1160 | # XlPrintLocation 1161 | xlPrintSheetEnd = 1 1162 | xlPrintInPlace = 16 1163 | xlPrintNoComments = -4142 1164 | 1165 | # XlPriority 1166 | xlPriorityHigh = -4127 1167 | xlPriorityLow = -4134 1168 | xlPriorityNormal = -4143 1169 | 1170 | # XlPTSelectionMode 1171 | xlLabelOnly = 1 1172 | xlDataAndLabel = 0 1173 | xlDataOnly = 2 1174 | xlOrigin = 3 1175 | xlButton = 15 1176 | xlBlanks = 4 1177 | xlFirstRow = 256 1178 | 1179 | # XlRangeAutoFormat 1180 | xlRangeAutoFormat3DEffects1 = 13 1181 | xlRangeAutoFormat3DEffects2 = 14 1182 | xlRangeAutoFormatAccounting1 = 4 1183 | xlRangeAutoFormatAccounting2 = 5 1184 | xlRangeAutoFormatAccounting3 = 6 1185 | xlRangeAutoFormatAccounting4 = 17 1186 | xlRangeAutoFormatClassic1 = 1 1187 | xlRangeAutoFormatClassic2 = 2 1188 | xlRangeAutoFormatClassic3 = 3 1189 | xlRangeAutoFormatColor1 = 7 1190 | xlRangeAutoFormatColor2 = 8 1191 | xlRangeAutoFormatColor3 = 9 1192 | xlRangeAutoFormatList1 = 10 1193 | xlRangeAutoFormatList2 = 11 1194 | xlRangeAutoFormatList3 = 12 1195 | xlRangeAutoFormatLocalFormat1 = 15 1196 | xlRangeAutoFormatLocalFormat2 = 16 1197 | xlRangeAutoFormatLocalFormat3 = 19 1198 | xlRangeAutoFormatLocalFormat4 = 20 1199 | xlRangeAutoFormatReport1 = 21 1200 | xlRangeAutoFormatReport2 = 22 1201 | xlRangeAutoFormatReport3 = 23 1202 | xlRangeAutoFormatReport4 = 24 1203 | xlRangeAutoFormatReport5 = 25 1204 | xlRangeAutoFormatReport6 = 26 1205 | xlRangeAutoFormatReport7 = 27 1206 | xlRangeAutoFormatReport8 = 28 1207 | xlRangeAutoFormatReport9 = 29 1208 | xlRangeAutoFormatReport10 = 30 1209 | xlRangeAutoFormatClassicPivotTable = 31 1210 | xlRangeAutoFormatTable1 = 32 1211 | xlRangeAutoFormatTable2 = 33 1212 | xlRangeAutoFormatTable3 = 34 1213 | xlRangeAutoFormatTable4 = 35 1214 | xlRangeAutoFormatTable5 = 36 1215 | xlRangeAutoFormatTable6 = 37 1216 | xlRangeAutoFormatTable7 = 38 1217 | xlRangeAutoFormatTable8 = 39 1218 | xlRangeAutoFormatTable9 = 40 1219 | xlRangeAutoFormatTable10 = 41 1220 | xlRangeAutoFormatPTNone = 42 1221 | xlRangeAutoFormatNone = -4142 1222 | xlRangeAutoFormatSimple = -4154 1223 | 1224 | # XlReferenceType 1225 | xlAbsolute = 1 1226 | xlAbsRowRelColumn = 2 1227 | xlRelative = 4 1228 | xlRelRowAbsColumn = 3 1229 | 1230 | # XlLayoutFormType 1231 | xlTabular = 0 1232 | xlOutline = 1 1233 | 1234 | # XlRoutingSlipDelivery 1235 | xlAllAtOnce = 2 1236 | xlOneAfterAnother = 1 1237 | 1238 | # XlRoutingSlipStatus 1239 | xlNotYetRouted = 0 1240 | xlRoutingComplete = 2 1241 | xlRoutingInProgress = 1 1242 | 1243 | # XlRunAutoMacro 1244 | xlAutoActivate = 3 1245 | xlAutoClose = 2 1246 | xlAutoDeactivate = 4 1247 | xlAutoOpen = 1 1248 | 1249 | # XlSaveAction 1250 | xlDoNotSaveChanges = 2 1251 | xlSaveChanges = 1 1252 | 1253 | # XlSaveAsAccessMode 1254 | xlExclusive = 3 1255 | xlNoChange = 1 1256 | xlShared = 2 1257 | 1258 | # XlSaveConflictResolution 1259 | xlLocalSessionChanges = 2 1260 | xlOtherSessionChanges = 3 1261 | xlUserResolution = 1 1262 | 1263 | # XlSearchDirection 1264 | xlNext = 1 1265 | xlPrevious = 2 1266 | 1267 | # XlSearchOrder 1268 | xlByColumns = 2 1269 | xlByRows = 1 1270 | 1271 | # XlSheetVisibility 1272 | xlSheetVisible = -1 1273 | xlSheetHidden = 0 1274 | xlSheetVeryHidden = 2 1275 | 1276 | # XlSortMethod 1277 | xlPinYin = 1 1278 | xlStroke = 2 1279 | 1280 | # XlSortMethodOld 1281 | xlCodePage = 2 1282 | xlSyllabary = 1 1283 | 1284 | # XlSortOrder 1285 | xlAscending = 1 1286 | xlDescending = 2 1287 | 1288 | # XlSortOrientation 1289 | xlSortRows = 2 1290 | xlSortColumns = 1 1291 | 1292 | # XlSortType 1293 | xlSortLabels = 2 1294 | xlSortValues = 1 1295 | 1296 | # XlSpecialCellsValue 1297 | xlErrors = 16 1298 | xlLogical = 4 1299 | xlNumbers = 1 1300 | xlTextValues = 2 1301 | 1302 | # XlSubscribeToFormat 1303 | xlSubscribeToPicture = -4147 1304 | xlSubscribeToText = -4158 1305 | 1306 | # XlSummaryRow 1307 | xlSummaryAbove = 0 1308 | xlSummaryBelow = 1 1309 | 1310 | # XlSummaryColumn 1311 | xlSummaryOnLeft = -4131 1312 | xlSummaryOnRight = -4152 1313 | 1314 | # XlSummaryReportType 1315 | xlSummaryPivotTable = -4148 1316 | xlStandardSummary = 1 1317 | 1318 | # XlTabPosition 1319 | xlTabPositionFirst = 0 1320 | xlTabPositionLast = 1 1321 | 1322 | # XlTextParsingType 1323 | xlDelimited = 1 1324 | xlFixedWidth = 2 1325 | 1326 | # XlTextQualifier 1327 | xlTextQualifierDoubleQuote = 1 1328 | xlTextQualifierNone = -4142 1329 | xlTextQualifierSingleQuote = 2 1330 | 1331 | # XlWBATemplate 1332 | xlWBATChart = -4109 1333 | xlWBATExcel4IntlMacroSheet = 4 1334 | xlWBATExcel4MacroSheet = 3 1335 | xlWBATWorksheet = -4167 1336 | 1337 | # XlWindowView 1338 | xlNormalView = 1 1339 | xlPageBreakPreview = 2 1340 | 1341 | # XlXLMMacroType 1342 | xlCommand = 2 1343 | xlFunction = 1 1344 | xlNotXLM = 3 1345 | 1346 | # XlYesNoGuess 1347 | xlGuess = 0 1348 | xlNo = 2 1349 | xlYes = 1 1350 | 1351 | # XlBordersIndex 1352 | xlInsideHorizontal = 12 1353 | xlInsideVertical = 11 1354 | xlDiagonalDown = 5 1355 | xlDiagonalUp = 6 1356 | xlEdgeBottom = 9 1357 | xlEdgeLeft = 7 1358 | xlEdgeRight = 10 1359 | xlEdgeTop = 8 1360 | 1361 | # XlToolbarProtection 1362 | xlNoButtonChanges = 1 1363 | xlNoChanges = 4 1364 | xlNoDockingChanges = 3 1365 | xlToolbarProtectionNone = -4143 1366 | xlNoShapeChanges = 2 1367 | 1368 | # XlBuiltInDialog 1369 | xlDialogOpen = 1 1370 | xlDialogOpenLinks = 2 1371 | xlDialogSaveAs = 5 1372 | xlDialogFileDelete = 6 1373 | xlDialogPageSetup = 7 1374 | xlDialogPrint = 8 1375 | xlDialogPrinterSetup = 9 1376 | xlDialogArrangeAll = 12 1377 | xlDialogWindowSize = 13 1378 | xlDialogWindowMove = 14 1379 | xlDialogRun = 17 1380 | xlDialogSetPrintTitles = 23 1381 | xlDialogFont = 26 1382 | xlDialogDisplay = 27 1383 | xlDialogProtectDocument = 28 1384 | xlDialogCalculation = 32 1385 | xlDialogExtract = 35 1386 | xlDialogDataDelete = 36 1387 | xlDialogSort = 39 1388 | xlDialogDataSeries = 40 1389 | xlDialogTable = 41 1390 | xlDialogFormatNumber = 42 1391 | xlDialogAlignment = 43 1392 | xlDialogStyle = 44 1393 | xlDialogBorder = 45 1394 | xlDialogCellProtection = 46 1395 | xlDialogColumnWidth = 47 1396 | xlDialogClear = 52 1397 | xlDialogPasteSpecial = 53 1398 | xlDialogEditDelete = 54 1399 | xlDialogInsert = 55 1400 | xlDialogPasteNames = 58 1401 | xlDialogDefineName = 61 1402 | xlDialogCreateNames = 62 1403 | xlDialogFormulaGoto = 63 1404 | xlDialogFormulaFind = 64 1405 | xlDialogGalleryArea = 67 1406 | xlDialogGalleryBar = 68 1407 | xlDialogGalleryColumn = 69 1408 | xlDialogGalleryLine = 70 1409 | xlDialogGalleryPie = 71 1410 | xlDialogGalleryScatter = 72 1411 | xlDialogCombination = 73 1412 | xlDialogGridlines = 76 1413 | xlDialogAxes = 78 1414 | xlDialogAttachText = 80 1415 | xlDialogPatterns = 84 1416 | xlDialogMainChart = 85 1417 | xlDialogOverlay = 86 1418 | xlDialogScale = 87 1419 | xlDialogFormatLegend = 88 1420 | xlDialogFormatText = 89 1421 | xlDialogParse = 91 1422 | xlDialogUnhide = 94 1423 | xlDialogWorkspace = 95 1424 | xlDialogActivate = 103 1425 | xlDialogCopyPicture = 108 1426 | xlDialogDeleteName = 110 1427 | xlDialogDeleteFormat = 111 1428 | xlDialogNew = 119 1429 | xlDialogRowHeight = 127 1430 | xlDialogFormatMove = 128 1431 | xlDialogFormatSize = 129 1432 | xlDialogFormulaReplace = 130 1433 | xlDialogSelectSpecial = 132 1434 | xlDialogApplyNames = 133 1435 | xlDialogReplaceFont = 134 1436 | xlDialogSplit = 137 1437 | xlDialogOutline = 142 1438 | xlDialogSaveWorkbook = 145 1439 | xlDialogCopyChart = 147 1440 | xlDialogFormatFont = 150 1441 | xlDialogNote = 154 1442 | xlDialogSetUpdateStatus = 159 1443 | xlDialogColorPalette = 161 1444 | xlDialogChangeLink = 166 1445 | xlDialogAppMove = 170 1446 | xlDialogAppSize = 171 1447 | xlDialogMainChartType = 185 1448 | xlDialogOverlayChartType = 186 1449 | xlDialogOpenMail = 188 1450 | xlDialogSendMail = 189 1451 | xlDialogStandardFont = 190 1452 | xlDialogConsolidate = 191 1453 | xlDialogSortSpecial = 192 1454 | xlDialogGallery3dArea = 193 1455 | xlDialogGallery3dColumn = 194 1456 | xlDialogGallery3dLine = 195 1457 | xlDialogGallery3dPie = 196 1458 | xlDialogView3d = 197 1459 | xlDialogGoalSeek = 198 1460 | xlDialogWorkgroup = 199 1461 | xlDialogFillGroup = 200 1462 | xlDialogUpdateLink = 201 1463 | xlDialogPromote = 202 1464 | xlDialogDemote = 203 1465 | xlDialogShowDetail = 204 1466 | xlDialogObjectProperties = 207 1467 | xlDialogSaveNewObject = 208 1468 | xlDialogApplyStyle = 212 1469 | xlDialogAssignToObject = 213 1470 | xlDialogObjectProtection = 214 1471 | xlDialogCreatePublisher = 217 1472 | xlDialogSubscribeTo = 218 1473 | xlDialogShowToolbar = 220 1474 | xlDialogPrintPreview = 222 1475 | xlDialogEditColor = 223 1476 | xlDialogFormatMain = 225 1477 | xlDialogFormatOverlay = 226 1478 | xlDialogEditSeries = 228 1479 | xlDialogDefineStyle = 229 1480 | xlDialogGalleryRadar = 249 1481 | xlDialogEditionOptions = 251 1482 | xlDialogZoom = 256 1483 | xlDialogInsertObject = 259 1484 | xlDialogSize = 261 1485 | xlDialogMove = 262 1486 | xlDialogFormatAuto = 269 1487 | xlDialogGallery3dBar = 272 1488 | xlDialogGallery3dSurface = 273 1489 | xlDialogCustomizeToolbar = 276 1490 | xlDialogWorkbookAdd = 281 1491 | xlDialogWorkbookMove = 282 1492 | xlDialogWorkbookCopy = 283 1493 | xlDialogWorkbookOptions = 284 1494 | xlDialogSaveWorkspace = 285 1495 | xlDialogChartWizard = 288 1496 | xlDialogAssignToTool = 293 1497 | xlDialogPlacement = 300 1498 | xlDialogFillWorkgroup = 301 1499 | xlDialogWorkbookNew = 302 1500 | xlDialogScenarioCells = 305 1501 | xlDialogScenarioAdd = 307 1502 | xlDialogScenarioEdit = 308 1503 | xlDialogScenarioSummary = 311 1504 | xlDialogPivotTableWizard = 312 1505 | xlDialogPivotFieldProperties = 313 1506 | xlDialogOptionsCalculation = 318 1507 | xlDialogOptionsEdit = 319 1508 | xlDialogOptionsView = 320 1509 | xlDialogAddinManager = 321 1510 | xlDialogMenuEditor = 322 1511 | xlDialogAttachToolbars = 323 1512 | xlDialogOptionsChart = 325 1513 | xlDialogVbaInsertFile = 328 1514 | xlDialogVbaProcedureDefinition = 330 1515 | xlDialogRoutingSlip = 336 1516 | xlDialogMailLogon = 339 1517 | xlDialogInsertPicture = 342 1518 | xlDialogGalleryDoughnut = 344 1519 | xlDialogChartTrend = 350 1520 | xlDialogWorkbookInsert = 354 1521 | xlDialogOptionsTransition = 355 1522 | xlDialogOptionsGeneral = 356 1523 | xlDialogFilterAdvanced = 370 1524 | xlDialogMailNextLetter = 378 1525 | xlDialogDataLabel = 379 1526 | xlDialogInsertTitle = 380 1527 | xlDialogFontProperties = 381 1528 | xlDialogMacroOptions = 382 1529 | xlDialogWorkbookUnhide = 384 1530 | xlDialogWorkbookName = 386 1531 | xlDialogGalleryCustom = 388 1532 | xlDialogAddChartAutoformat = 390 1533 | xlDialogChartAddData = 392 1534 | xlDialogTabOrder = 394 1535 | xlDialogSubtotalCreate = 398 1536 | xlDialogWorkbookTabSplit = 415 1537 | xlDialogWorkbookProtect = 417 1538 | xlDialogScrollbarProperties = 420 1539 | xlDialogPivotShowPages = 421 1540 | xlDialogTextToColumns = 422 1541 | xlDialogFormatCharttype = 423 1542 | xlDialogPivotFieldGroup = 433 1543 | xlDialogPivotFieldUngroup = 434 1544 | xlDialogCheckboxProperties = 435 1545 | xlDialogLabelProperties = 436 1546 | xlDialogListboxProperties = 437 1547 | xlDialogEditboxProperties = 438 1548 | xlDialogOpenText = 441 1549 | xlDialogPushbuttonProperties = 445 1550 | xlDialogFilter = 447 1551 | xlDialogFunctionWizard = 450 1552 | xlDialogSaveCopyAs = 456 1553 | xlDialogOptionsListsAdd = 458 1554 | xlDialogSeriesAxes = 460 1555 | xlDialogSeriesX = 461 1556 | xlDialogSeriesY = 462 1557 | xlDialogErrorbarX = 463 1558 | xlDialogErrorbarY = 464 1559 | xlDialogFormatChart = 465 1560 | xlDialogSeriesOrder = 466 1561 | xlDialogMailEditMailer = 470 1562 | xlDialogStandardWidth = 472 1563 | xlDialogScenarioMerge = 473 1564 | xlDialogProperties = 474 1565 | xlDialogSummaryInfo = 474 1566 | xlDialogFindFile = 475 1567 | xlDialogActiveCellFont = 476 1568 | xlDialogVbaMakeAddin = 478 1569 | xlDialogFileSharing = 481 1570 | xlDialogAutoCorrect = 485 1571 | xlDialogCustomViews = 493 1572 | xlDialogInsertNameLabel = 496 1573 | xlDialogSeriesShape = 504 1574 | xlDialogChartOptionsDataLabels = 505 1575 | xlDialogChartOptionsDataTable = 506 1576 | xlDialogSetBackgroundPicture = 509 1577 | xlDialogDataValidation = 525 1578 | xlDialogChartType = 526 1579 | xlDialogChartLocation = 527 1580 | _xlDialogPhonetic = 538 1581 | xlDialogChartSourceData = 540 1582 | _xlDialogChartSourceData = 541 1583 | xlDialogSeriesOptions = 557 1584 | xlDialogPivotTableOptions = 567 1585 | xlDialogPivotSolveOrder = 568 1586 | xlDialogPivotCalculatedField = 570 1587 | xlDialogPivotCalculatedItem = 572 1588 | xlDialogConditionalFormatting = 583 1589 | xlDialogInsertHyperlink = 596 1590 | xlDialogProtectSharing = 620 1591 | xlDialogOptionsME = 647 1592 | xlDialogPublishAsWebPage = 653 1593 | xlDialogPhonetic = 656 1594 | xlDialogNewWebQuery = 667 1595 | xlDialogImportTextFile = 666 1596 | xlDialogExternalDataProperties = 530 1597 | xlDialogWebOptionsGeneral = 683 1598 | xlDialogWebOptionsFiles = 684 1599 | xlDialogWebOptionsPictures = 685 1600 | xlDialogWebOptionsEncoding = 686 1601 | xlDialogWebOptionsFonts = 687 1602 | xlDialogPivotClientServerSet = 689 1603 | xlDialogPropertyFields = 754 1604 | xlDialogSearch = 731 1605 | xlDialogEvaluateFormula = 709 1606 | xlDialogDataLabelMultiple = 723 1607 | xlDialogChartOptionsDataLabelMultiple = 724 1608 | xlDialogErrorChecking = 732 1609 | xlDialogWebOptionsBrowsers = 773 1610 | xlDialogCreateList = 796 1611 | xlDialogPermission = 832 1612 | xlDialogMyPermission = 834 1613 | 1614 | # XlParameterType 1615 | xlPrompt = 0 1616 | xlConstant = 1 1617 | xlRange = 2 1618 | 1619 | # XlParameterDataType 1620 | xlParamTypeUnknown = 0 1621 | xlParamTypeChar = 1 1622 | xlParamTypeNumeric = 2 1623 | xlParamTypeDecimal = 3 1624 | xlParamTypeInteger = 4 1625 | xlParamTypeSmallInt = 5 1626 | xlParamTypeFloat = 6 1627 | xlParamTypeReal = 7 1628 | xlParamTypeDouble = 8 1629 | xlParamTypeVarChar = 12 1630 | xlParamTypeDate = 9 1631 | xlParamTypeTime = 10 1632 | xlParamTypeTimestamp = 11 1633 | xlParamTypeLongVarChar = -1 1634 | xlParamTypeBinary = -2 1635 | xlParamTypeVarBinary = -3 1636 | xlParamTypeLongVarBinary = -4 1637 | xlParamTypeBigInt = -5 1638 | xlParamTypeTinyInt = -6 1639 | xlParamTypeBit = -7 1640 | xlParamTypeWChar = -8 1641 | 1642 | # XlFormControl 1643 | xlButtonControl = 0 1644 | xlCheckBox = 1 1645 | xlDropDown = 2 1646 | xlEditBox = 3 1647 | xlGroupBox = 4 1648 | xlLabel = 5 1649 | xlListBox = 6 1650 | xlOptionButton = 7 1651 | xlScrollBar = 8 1652 | xlSpinner = 9 1653 | 1654 | # XlSourceType 1655 | xlSourceWorkbook = 0 1656 | xlSourceSheet = 1 1657 | xlSourcePrintArea = 2 1658 | xlSourceAutoFilter = 3 1659 | xlSourceRange = 4 1660 | xlSourceChart = 5 1661 | xlSourcePivotTable = 6 1662 | xlSourceQuery = 7 1663 | 1664 | # XlHtmlType 1665 | xlHtmlStatic = 0 1666 | xlHtmlCalc = 1 1667 | xlHtmlList = 2 1668 | xlHtmlChart = 3 1669 | 1670 | # XlPivotFormatType 1671 | xlReport1 = 0 1672 | xlReport2 = 1 1673 | xlReport3 = 2 1674 | xlReport4 = 3 1675 | xlReport5 = 4 1676 | xlReport6 = 5 1677 | xlReport7 = 6 1678 | xlReport8 = 7 1679 | xlReport9 = 8 1680 | xlReport10 = 9 1681 | xlTable1 = 10 1682 | xlTable2 = 11 1683 | xlTable3 = 12 1684 | xlTable4 = 13 1685 | xlTable5 = 14 1686 | xlTable6 = 15 1687 | xlTable7 = 16 1688 | xlTable8 = 17 1689 | xlTable9 = 18 1690 | xlTable10 = 19 1691 | xlPTClassic = 20 1692 | xlPTNone = 21 1693 | 1694 | # XlCmdType 1695 | xlCmdCube = 1 1696 | xlCmdSql = 2 1697 | xlCmdTable = 3 1698 | xlCmdDefault = 4 1699 | xlCmdList = 5 1700 | 1701 | # XlColumnDataType 1702 | xlGeneralFormat = 1 1703 | xlTextFormat = 2 1704 | xlMDYFormat = 3 1705 | xlDMYFormat = 4 1706 | xlYMDFormat = 5 1707 | xlMYDFormat = 6 1708 | xlDYMFormat = 7 1709 | xlYDMFormat = 8 1710 | xlSkipColumn = 9 1711 | xlEMDFormat = 10 1712 | 1713 | # XlQueryType 1714 | xlODBCQuery = 1 1715 | xlDAORecordset = 2 1716 | xlWebQuery = 4 1717 | xlOLEDBQuery = 5 1718 | xlTextImport = 6 1719 | xlADORecordset = 7 1720 | 1721 | # XlWebSelectionType 1722 | xlEntirePage = 1 1723 | xlAllTables = 2 1724 | xlSpecifiedTables = 3 1725 | 1726 | # XlCubeFieldType 1727 | xlHierarchy = 1 1728 | xlMeasure = 2 1729 | xlSet = 3 1730 | 1731 | # XlWebFormatting 1732 | xlWebFormattingAll = 1 1733 | xlWebFormattingRTF = 2 1734 | xlWebFormattingNone = 3 1735 | 1736 | # XlDisplayDrawingObjects 1737 | xlDisplayShapes = -4104 1738 | xlHide = 3 1739 | xlPlaceholders = 2 1740 | 1741 | # XlSubtototalLocationType 1742 | xlAtTop = 1 1743 | xlAtBottom = 2 1744 | 1745 | # XlPivotTableVersionList 1746 | xlPivotTableVersion2000 = 0 1747 | xlPivotTableVersion10 = 1 1748 | xlPivotTableVersionCurrent = -1 1749 | 1750 | # XlPrintErrors 1751 | xlPrintErrorsDisplayed = 0 1752 | xlPrintErrorsBlank = 1 1753 | xlPrintErrorsDash = 2 1754 | xlPrintErrorsNA = 3 1755 | 1756 | # XlPivotCellType 1757 | xlPivotCellValue = 0 1758 | xlPivotCellPivotItem = 1 1759 | xlPivotCellSubtotal = 2 1760 | xlPivotCellGrandTotal = 3 1761 | xlPivotCellDataField = 4 1762 | xlPivotCellPivotField = 5 1763 | xlPivotCellPageFieldItem = 6 1764 | xlPivotCellCustomSubtotal = 7 1765 | xlPivotCellDataPivotField = 8 1766 | xlPivotCellBlankCell = 9 1767 | 1768 | # XlPivotTableMissingItems 1769 | xlMissingItemsDefault = -1 1770 | xlMissingItemsNone = 0 1771 | xlMissingItemsMax = 32500 1772 | 1773 | # XlCalculationState 1774 | xlDone = 0 1775 | xlCalculating = 1 1776 | xlPending = 2 1777 | 1778 | # XlCalculationInterruptKey 1779 | xlNoKey = 0 1780 | xlEscKey = 1 1781 | xlAnyKey = 2 1782 | 1783 | # XlSortDataOption 1784 | xlSortNormal = 0 1785 | xlSortTextAsNumbers = 1 1786 | 1787 | # XlUpdateLinks 1788 | xlUpdateLinksUserSetting = 1 1789 | xlUpdateLinksNever = 2 1790 | xlUpdateLinksAlways = 3 1791 | 1792 | # XlLinkStatus 1793 | xlLinkStatusOK = 0 1794 | xlLinkStatusMissingFile = 1 1795 | xlLinkStatusMissingSheet = 2 1796 | xlLinkStatusOld = 3 1797 | xlLinkStatusSourceNotCalculated = 4 1798 | xlLinkStatusIndeterminate = 5 1799 | xlLinkStatusNotStarted = 6 1800 | xlLinkStatusInvalidName = 7 1801 | xlLinkStatusSourceNotOpen = 8 1802 | xlLinkStatusSourceOpen = 9 1803 | xlLinkStatusCopiedValues = 10 1804 | 1805 | # XlSearchWithin 1806 | xlWithinSheet = 1 1807 | xlWithinWorkbook = 2 1808 | 1809 | # XlCorruptLoad 1810 | xlNormalLoad = 0 1811 | xlRepairFile = 1 1812 | xlExtractData = 2 1813 | 1814 | # XlRobustConnect 1815 | xlAsRequired = 0 1816 | xlAlways = 1 1817 | xlNever = 2 1818 | 1819 | # XlErrorChecks 1820 | xlEvaluateToError = 1 1821 | xlTextDate = 2 1822 | xlNumberAsText = 3 1823 | xlInconsistentFormula = 4 1824 | xlOmittedCells = 5 1825 | xlUnlockedFormulaCells = 6 1826 | xlEmptyCellReferences = 7 1827 | xlListDataValidation = 8 1828 | 1829 | # XlDataLabelSeparator 1830 | xlDataLabelSeparatorDefault = 1 1831 | 1832 | # XlSmartTagDisplayMode 1833 | xlIndicatorAndButton = 0 1834 | xlDisplayNone = 1 1835 | xlButtonOnly = 2 1836 | 1837 | # XlRangeValueDataType 1838 | xlRangeValueDefault = 10 1839 | xlRangeValueXMLSpreadsheet = 11 1840 | xlRangeValueMSPersistXML = 12 1841 | 1842 | # XlSpeakDirection 1843 | xlSpeakByRows = 0 1844 | xlSpeakByColumns = 1 1845 | 1846 | # XlInsertFormatOrigin 1847 | xlFormatFromLeftOrAbove = 0 1848 | xlFormatFromRightOrBelow = 1 1849 | 1850 | # XlArabicModes 1851 | xlArabicNone = 0 1852 | xlArabicStrictAlefHamza = 1 1853 | xlArabicStrictFinalYaa = 2 1854 | xlArabicBothStrict = 3 1855 | 1856 | # XlImportDataAs 1857 | xlQueryTable = 0 1858 | xlPivotTableReport = 1 1859 | 1860 | # XlCalculatedMemberType 1861 | xlCalculatedMember = 0 1862 | xlCalculatedSet = 1 1863 | 1864 | # XlHebrewModes 1865 | xlHebrewFullScript = 0 1866 | xlHebrewPartialScript = 1 1867 | xlHebrewMixedScript = 2 1868 | xlHebrewMixedAuthorizedScript = 3 1869 | 1870 | # XlListObjectSourceType 1871 | xlSrcExternal = 0 1872 | xlSrcRange = 1 1873 | xlSrcXml = 2 1874 | 1875 | # XlTextVisualLayoutType 1876 | xlTextVisualLTR = 1 1877 | xlTextVisualRTL = 2 1878 | 1879 | # XlListDataType 1880 | xlListDataTypeNone = 0 1881 | xlListDataTypeText = 1 1882 | xlListDataTypeMultiLineText = 2 1883 | xlListDataTypeNumber = 3 1884 | xlListDataTypeCurrency = 4 1885 | xlListDataTypeDateTime = 5 1886 | xlListDataTypeChoice = 6 1887 | xlListDataTypeChoiceMulti = 7 1888 | xlListDataTypeListLookup = 8 1889 | xlListDataTypeCheckbox = 9 1890 | xlListDataTypeHyperLink = 10 1891 | xlListDataTypeCounter = 11 1892 | xlListDataTypeMultiLineRichText = 12 1893 | 1894 | # XlTotalsCalculation 1895 | xlTotalsCalculationNone = 0 1896 | xlTotalsCalculationSum = 1 1897 | xlTotalsCalculationAverage = 2 1898 | xlTotalsCalculationCount = 3 1899 | xlTotalsCalculationCountNums = 4 1900 | xlTotalsCalculationMin = 5 1901 | xlTotalsCalculationMax = 6 1902 | xlTotalsCalculationStdDev = 7 1903 | xlTotalsCalculationVar = 8 1904 | 1905 | # XlXmlLoadOption 1906 | xlXmlLoadPromptUser = 0 1907 | xlXmlLoadOpenXml = 1 1908 | xlXmlLoadImportToList = 2 1909 | xlXmlLoadMapXml = 3 1910 | 1911 | # XlSmartTagControlType 1912 | xlSmartTagControlSmartTag = 1 1913 | xlSmartTagControlLink = 2 1914 | xlSmartTagControlHelp = 3 1915 | xlSmartTagControlHelpURL = 4 1916 | xlSmartTagControlSeparator = 5 1917 | xlSmartTagControlButton = 6 1918 | xlSmartTagControlLabel = 7 1919 | xlSmartTagControlImage = 8 1920 | xlSmartTagControlCheckbox = 9 1921 | xlSmartTagControlTextbox = 10 1922 | xlSmartTagControlListbox = 11 1923 | xlSmartTagControlCombo = 12 1924 | xlSmartTagControlActiveX = 13 1925 | xlSmartTagControlRadioGroup = 14 1926 | 1927 | # XlListConflict 1928 | xlListConflictDialog = 0 1929 | xlListConflictRetryAllConflicts = 1 1930 | xlListConflictDiscardAllConflicts = 2 1931 | xlListConflictError = 3 1932 | 1933 | # XlXmlExportResult 1934 | xlXmlExportSuccess = 0 1935 | xlXmlExportValidationFailed = 1 1936 | 1937 | # XlXmlImportResult 1938 | xlXmlImportSuccess = 0 1939 | xlXmlImportElementsTruncated = 1 1940 | xlXmlImportValidationFailed = 2 1941 | --------------------------------------------------------------------------------