├── .gitattributes ├── .gitignore ├── CHANGE-LOG.md ├── LICENSE.md ├── NOTICE.txt ├── README.md ├── Sheet1.cls ├── Simple Toolkit_DEV.xlam ├── Simple Toolkit_conf.bas ├── ThisWorkbook.cls ├── bootstrap.bas ├── dev_tools.bas ├── excel_ver.bas ├── file_utils.bas ├── loader.bas ├── menu.bas ├── menu_defn_in_code.bas ├── menu_lib.bas ├── toolkit.bas ├── tools.bas └── update_core.bas /.gitattributes: -------------------------------------------------------------------------------- 1 | # Class modules for VBA must have CRLF line endings in order for Excel on Mac 2 | # to correctly parse them. 3 | *.cls eol=crlf 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Temporary Excel files 2 | ~*.xlam 3 | 4 | # Production version of toolkit that are built 5 | *_PROD.xlam 6 | -------------------------------------------------------------------------------- /CHANGE-LOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project are documented in this file. 4 | This project adheres to [Semantic Versioning](http://semver.org/). 5 | 6 | 7 | v1.3.1 8 | ------ 9 | 2018-11-15 10 | 11 | This minor revision changes the cell in the hidden Sheet1 that is 12 | used to store version and date built information from A1 to Z1. 13 | This change does not change behavior in any way, was done to 14 | accommodate use of cell A1 by a different function outside this 15 | library. 16 | 17 | v1.3.0 18 | ------ 19 | 2018-09-06 20 | 21 | > Note: this release includes changes to the core modules. 22 | 23 | ### Added 24 | 25 | - Two new helper macros to the `bootstrap.bas` module along with a new 26 | special `update_core.bas` module. Together, they provide a mechanism for 27 | developers that use this add-in framework to [update the core modules][] 28 | in their toolkits when a new release of this framework contains changes 29 | to those core modules. 30 | 31 | ### Fixed 32 | 33 | - Fixed [issue #5][]. If a developer tries to save the Development edition 34 | of her toolkit in the VB Editor, she's informed that operation is not 35 | allowed, and instead, to use the "Export VBA code" item in the toolkit's 36 | "Developer Tools" menu. 37 | 38 | [update the core modules]: https://github.com/mnpopcenter/vba-libs/wiki/Updating-Your-Toolkit#updating-core-modules 39 | [issue #5]: https://github.com/mnpopcenter/vba-libs/issues/5 40 | 41 | 42 | v1.3.0 (release candidate 1) 43 | ---------------------------- 44 | 2016-10-31 45 | 46 | - Fixed [issue #4][], so the toolkit's menu should work with languages other 47 | than English. (Note: still needs verified with a non-English version of 48 | Excel.) 49 | 50 | [issue #4]: https://github.com/mnpopcenter/vba-libs/issues/4 51 | 52 | v1.2.0 53 | ------ 54 | 2016-09-30 55 | 56 | ### Added 57 | 58 | - The `CurrentEdition` variable to the `bootstrap.bas` module ([issue #2][]). 59 | - The `BaseFileName` variable to the `toolkit.bas` module ([issue #3][]). 60 | 61 | [issue #2]: https://github.com/mnpopcenter/vba-libs/issues/2 62 | [issue #3]: https://github.com/mnpopcenter/vba-libs/issues/3 63 | 64 | v1.1.1 65 | ------ 66 | 2016-09-27 67 | 68 | - Added v1.1.0 (and this version) to this Change Log. 69 | 70 | v1.1.0 71 | ------ 72 | 2016-09-26 73 | 74 | - Fixed [issue #1][], so file properties can be changed on a toolkit's 75 | add-in. 76 | 77 | [issue #1]: https://github.com/mnpopcenter/vba-libs/issues/1 78 | 79 | v1.0.0 80 | ------ 81 | 2016-05-12 82 | 83 | - Initial version with the Simple Toolkit add-in, which illustrates the 84 | dynamic bootstrapping of VBA modules. 85 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | [Mozilla Public License][] Version [2.0][] 2 | ================================== 3 | 4 | [Mozilla Public License]: https://www.mozilla.org/MPL/ 5 | [2.0]: https://www.mozilla.org/MPL/2.0/ 6 | 7 | 1. Definitions 8 | -------------- 9 | 10 | ### 1.1. "Contributor" 11 | 12 | means each individual or legal entity that creates, contributes to 13 | the creation of, or owns Covered Software. 14 | 15 | ### 1.2. "Contributor Version" 16 | 17 | means the combination of the Contributions of others (if any) used 18 | by a Contributor and that particular Contributor's Contribution. 19 | 20 | ### 1.3. "Contribution" 21 | 22 | means Covered Software of a particular Contributor. 23 | 24 | ### 1.4. "Covered Software" 25 | 26 | means Source Code Form to which the initial Contributor has attached 27 | the notice in Exhibit A, the Executable Form of such Source Code 28 | Form, and Modifications of such Source Code Form, in each case 29 | including portions thereof. 30 | 31 | ### 1.5. "Incompatible With Secondary Licenses" 32 | 33 | means 34 | 35 | __(a)__ that the initial Contributor has attached the notice described 36 | in Exhibit B to the Covered Software; or 37 | 38 | __(b)__ that the Covered Software was made available under the terms of 39 | version 1.1 or earlier of the License, but not also under the 40 | terms of a Secondary License. 41 | 42 | ### 1.6. "Executable Form" 43 | 44 | means any form of the work other than Source Code Form. 45 | 46 | ### 1.7. "Larger Work" 47 | 48 | means a work that combines Covered Software with other material, in 49 | a separate file or files, that is not Covered Software. 50 | 51 | ### 1.8. "License" 52 | 53 | means this document. 54 | 55 | ### 1.9. "Licensable" 56 | 57 | means having the right to grant, to the maximum extent possible, 58 | whether at the time of the initial grant or subsequently, any and 59 | all of the rights conveyed by this License. 60 | 61 | ### 1.10. "Modifications" 62 | 63 | means any of the following: 64 | 65 | __(a)__ any file in Source Code Form that results from an addition to, 66 | deletion from, or modification of the contents of Covered 67 | Software; or 68 | 69 | __(b)__ any new file in Source Code Form that contains any Covered 70 | Software. 71 | 72 | ### 1.11. "Patent Claims" of a Contributor 73 | 74 | means any patent claim(s), including without limitation, method, 75 | process, and apparatus claims, in any patent Licensable by such 76 | Contributor that would be infringed, but for the grant of the 77 | License, by the making, using, selling, offering for sale, having 78 | made, import, or transfer of either its Contributions or its 79 | Contributor Version. 80 | 81 | ### 1.12. "Secondary License" 82 | 83 | means either the GNU General Public License, Version 2.0, the GNU 84 | Lesser General Public License, Version 2.1, the GNU Affero General 85 | Public License, Version 3.0, or any later versions of those 86 | licenses. 87 | 88 | ### 1.13. "Source Code Form" 89 | 90 | means the form of the work preferred for making modifications. 91 | 92 | ### 1.14. "You" (or "Your") 93 | 94 | means an individual or a legal entity exercising rights under this 95 | License. For legal entities, "You" includes any entity that 96 | controls, is controlled by, or is under common control with You. For 97 | purposes of this definition, "control" means (a) the power, direct 98 | or indirect, to cause the direction or management of such entity, 99 | whether by contract or otherwise, or (b) ownership of more than 100 | fifty percent (50%) of the outstanding shares or beneficial 101 | ownership of such entity. 102 | 103 | 2. License Grants and Conditions 104 | -------------------------------- 105 | 106 | ### 2.1. Grants 107 | 108 | Each Contributor hereby grants You a world-wide, royalty-free, 109 | non-exclusive license: 110 | 111 | __(a)__ under intellectual property rights (other than patent or trademark) 112 | Licensable by such Contributor to use, reproduce, make available, 113 | modify, display, perform, distribute, and otherwise exploit its 114 | Contributions, either on an unmodified basis, with Modifications, or 115 | as part of a Larger Work; and 116 | 117 | __(b)__ under Patent Claims of such Contributor to make, use, sell, offer 118 | for sale, have made, import, and otherwise transfer either its 119 | Contributions or its Contributor Version. 120 | 121 | ### 2.2. Effective Date 122 | 123 | The licenses granted in Section 2.1 with respect to any Contribution 124 | become effective for each Contribution on the date the Contributor first 125 | distributes such Contribution. 126 | 127 | ### 2.3. Limitations on Grant Scope 128 | 129 | The licenses granted in this Section 2 are the only rights granted under 130 | this License. No additional rights or licenses will be implied from the 131 | distribution or licensing of Covered Software under this License. 132 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 133 | Contributor: 134 | 135 | __(a)__ for any code that a Contributor has removed from Covered Software; 136 | or 137 | 138 | __(b)__ for infringements caused by: (i) Your and any other third party's 139 | modifications of Covered Software, or (ii) the combination of its 140 | Contributions with other software (except as part of its Contributor 141 | Version); or 142 | 143 | __(c)__ under Patent Claims infringed by Covered Software in the absence of 144 | its Contributions. 145 | 146 | This License does not grant any rights in the trademarks, service marks, 147 | or logos of any Contributor (except as may be necessary to comply with 148 | the notice requirements in Section 3.4). 149 | 150 | ### 2.4. Subsequent Licenses 151 | 152 | No Contributor makes additional grants as a result of Your choice to 153 | distribute the Covered Software under a subsequent version of this 154 | License (see Section 10.2) or under the terms of a Secondary License (if 155 | permitted under the terms of Section 3.3). 156 | 157 | ### 2.5. Representation 158 | 159 | Each Contributor represents that the Contributor believes its 160 | Contributions are its original creation(s) or it has sufficient rights 161 | to grant the rights to its Contributions conveyed by this License. 162 | 163 | ### 2.6. Fair Use 164 | 165 | This License is not intended to limit any rights You have under 166 | applicable copyright doctrines of fair use, fair dealing, or other 167 | equivalents. 168 | 169 | ### 2.7. Conditions 170 | 171 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 172 | in Section 2.1. 173 | 174 | 3. Responsibilities 175 | ------------------- 176 | 177 | ### 3.1. Distribution of Source Form 178 | 179 | All distribution of Covered Software in Source Code Form, including any 180 | Modifications that You create or to which You contribute, must be under 181 | the terms of this License. You must inform recipients that the Source 182 | Code Form of the Covered Software is governed by the terms of this 183 | License, and how they can obtain a copy of this License. You may not 184 | attempt to alter or restrict the recipients' rights in the Source Code 185 | Form. 186 | 187 | ### 3.2. Distribution of Executable Form 188 | 189 | If You distribute Covered Software in Executable Form then: 190 | 191 | __(a)__ such Covered Software must also be made available in Source Code 192 | Form, as described in Section 3.1, and You must inform recipients of 193 | the Executable Form how they can obtain a copy of such Source Code 194 | Form by reasonable means in a timely manner, at a charge no more 195 | than the cost of distribution to the recipient; and 196 | 197 | __(b)__ You may distribute such Executable Form under the terms of this 198 | License, or sublicense it under different terms, provided that the 199 | license for the Executable Form does not attempt to limit or alter 200 | the recipients' rights in the Source Code Form under this License. 201 | 202 | ### 3.3. Distribution of a Larger Work 203 | 204 | You may create and distribute a Larger Work under terms of Your choice, 205 | provided that You also comply with the requirements of this License for 206 | the Covered Software. If the Larger Work is a combination of Covered 207 | Software with a work governed by one or more Secondary Licenses, and the 208 | Covered Software is not Incompatible With Secondary Licenses, this 209 | License permits You to additionally distribute such Covered Software 210 | under the terms of such Secondary License(s), so that the recipient of 211 | the Larger Work may, at their option, further distribute the Covered 212 | Software under the terms of either this License or such Secondary 213 | License(s). 214 | 215 | ### 3.4. Notices 216 | 217 | You may not remove or alter the substance of any license notices 218 | (including copyright notices, patent notices, disclaimers of warranty, 219 | or limitations of liability) contained within the Source Code Form of 220 | the Covered Software, except that You may alter any license notices to 221 | the extent required to remedy known factual inaccuracies. 222 | 223 | ### 3.5. Application of Additional Terms 224 | 225 | You may choose to offer, and to charge a fee for, warranty, support, 226 | indemnity or liability obligations to one or more recipients of Covered 227 | Software. However, You may do so only on Your own behalf, and not on 228 | behalf of any Contributor. You must make it absolutely clear that any 229 | such warranty, support, indemnity, or liability obligation is offered by 230 | You alone, and You hereby agree to indemnify every Contributor for any 231 | liability incurred by such Contributor as a result of warranty, support, 232 | indemnity or liability terms You offer. You may include additional 233 | disclaimers of warranty and limitations of liability specific to any 234 | jurisdiction. 235 | 236 | 4. Inability to Comply Due to Statute or Regulation 237 | --------------------------------------------------- 238 | 239 | If it is impossible for You to comply with any of the terms of this 240 | License with respect to some or all of the Covered Software due to 241 | statute, judicial order, or regulation then You must: (a) comply with 242 | the terms of this License to the maximum extent possible; and (b) 243 | describe the limitations and the code they affect. Such description must 244 | be placed in a text file included with all distributions of the Covered 245 | Software under this License. Except to the extent prohibited by statute 246 | or regulation, such description must be sufficiently detailed for a 247 | recipient of ordinary skill to be able to understand it. 248 | 249 | 5. Termination 250 | -------------- 251 | 252 | __5.1.__ The rights granted under this License will terminate automatically 253 | if You fail to comply with any of its terms. However, if You become 254 | compliant, then the rights granted under this License from a particular 255 | Contributor are reinstated (a) provisionally, unless and until such 256 | Contributor explicitly and finally terminates Your grants, and (b) on an 257 | ongoing basis, if such Contributor fails to notify You of the 258 | non-compliance by some reasonable means prior to 60 days after You have 259 | come back into compliance. Moreover, Your grants from a particular 260 | Contributor are reinstated on an ongoing basis if such Contributor 261 | notifies You of the non-compliance by some reasonable means, this is the 262 | first time You have received notice of non-compliance with this License 263 | from such Contributor, and You become compliant prior to 30 days after 264 | Your receipt of the notice. 265 | 266 | __5.2.__ If You initiate litigation against any entity by asserting a patent 267 | infringement claim (excluding declaratory judgment actions, 268 | counter-claims, and cross-claims) alleging that a Contributor Version 269 | directly or indirectly infringes any patent, then the rights granted to 270 | You by any and all Contributors for the Covered Software under Section 271 | 2.1 of this License shall terminate. 272 | 273 | __5.3.__ In the event of termination under Sections 5.1 or 5.2 above, all 274 | end user license agreements (excluding distributors and resellers) which 275 | have been validly granted by You or Your distributors under this License 276 | prior to termination shall survive termination. 277 | 278 | ************************************************************************ 279 | 280 | 6. Disclaimer of Warranty 281 | ------------------------- 282 | 283 | > __Covered Software is provided under this License on an "as is" 284 | > basis, without warranty of any kind, either expressed, implied, or 285 | > statutory, including, without limitation, warranties that the 286 | > Covered Software is free of defects, merchantable, fit for a 287 | > particular purpose or non-infringing. The entire risk as to the 288 | > quality and performance of the Covered Software is with You. 289 | > Should any Covered Software prove defective in any respect, You 290 | > (not any Contributor) assume the cost of any necessary servicing, 291 | > repair, or correction. This disclaimer of warranty constitutes an 292 | > essential part of this License. No use of any Covered Software is 293 | > authorized under this License except under this disclaimer.__ 294 | 295 | ************************************************************************ 296 | 297 | ************************************************************************ 298 | 299 | 7. Limitation of Liability 300 | -------------------------- 301 | 302 | > __Under no circumstances and under no legal theory, whether tort 303 | > (including negligence), contract, or otherwise, shall any 304 | > Contributor, or anyone who distributes Covered Software as 305 | > permitted above, be liable to You for any direct, indirect, 306 | > special, incidental, or consequential damages of any character 307 | > including, without limitation, damages for lost profits, loss of 308 | > goodwill, work stoppage, computer failure or malfunction, or any 309 | > and all other commercial damages or losses, even if such party 310 | > shall have been informed of the possibility of such damages. This 311 | > limitation of liability shall not apply to liability for death or 312 | > personal injury resulting from such party's negligence to the 313 | > extent applicable law prohibits such limitation. Some 314 | > jurisdictions do not allow the exclusion or limitation of 315 | > incidental or consequential damages, so this exclusion and 316 | > limitation may not apply to You.__ 317 | 318 | ************************************************************************ 319 | 320 | 8. Litigation 321 | ------------- 322 | 323 | Any litigation relating to this License may be brought only in the 324 | courts of a jurisdiction where the defendant maintains its principal 325 | place of business and such litigation shall be governed by laws of that 326 | jurisdiction, without reference to its conflict-of-law provisions. 327 | Nothing in this Section shall prevent a party's ability to bring 328 | cross-claims or counter-claims. 329 | 330 | 9. Miscellaneous 331 | ---------------- 332 | 333 | This License represents the complete agreement concerning the subject 334 | matter hereof. If any provision of this License is held to be 335 | unenforceable, such provision shall be reformed only to the extent 336 | necessary to make it enforceable. Any law or regulation which provides 337 | that the language of a contract shall be construed against the drafter 338 | shall not be used to construe this License against a Contributor. 339 | 340 | 10. Versions of the License 341 | --------------------------- 342 | 343 | ### 10.1. New Versions 344 | 345 | Mozilla Foundation is the license steward. Except as provided in Section 346 | 10.3, no one other than the license steward has the right to modify or 347 | publish new versions of this License. Each version will be given a 348 | distinguishing version number. 349 | 350 | ### 10.2. Effect of New Versions 351 | 352 | You may distribute the Covered Software under the terms of the version 353 | of the License under which You originally received the Covered Software, 354 | or under the terms of any subsequent version published by the license 355 | steward. 356 | 357 | ### 10.3. Modified Versions 358 | 359 | If you create software not governed by this License, and you want to 360 | create a new license for such software, you may create and use a 361 | modified version of this License if you rename the license and remove 362 | any references to the name of the license steward (except to note that 363 | such modified license differs from this License). 364 | 365 | ### 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses 366 | 367 | If You choose to distribute Source Code Form that is Incompatible With 368 | Secondary Licenses under the terms of this version of the License, the 369 | notice described in Exhibit B of this License must be attached. 370 | 371 | Exhibit A - Source Code Form License Notice 372 | ------------------------------------------- 373 | 374 | This Source Code Form is subject to the terms of the Mozilla Public 375 | License, v. 2.0. If a copy of the MPL was not distributed with this 376 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 377 | 378 | If it is not possible or desirable to put the notice in a particular 379 | file, then You may include the notice in a location (such as a LICENSE 380 | file in a relevant directory) where a recipient would be likely to look 381 | for such a notice. 382 | 383 | You may add additional accurate notices of copyright ownership. 384 | 385 | Exhibit B - "Incompatible With Secondary Licenses" Notice 386 | --------------------------------------------------------- 387 | 388 | This Source Code Form is "Incompatible With Secondary Licenses", as 389 | defined by the Mozilla Public License, v. 2.0. 390 | -------------------------------------------------------------------------------- /NOTICE.txt: -------------------------------------------------------------------------------- 1 | VBA libraries for Excel 2 | https://github.com/mnpopcenter/vba-libs 3 | 4 | Copyright 2015-2016 Regents of the University of Minnesota 5 | 6 | Contributors: 7 | Jimm Domingo, Minnesota Population Center, University of Minnesota 8 | 9 | This project is licensed under the Mozilla Public License, version 2.0 (the 10 | "License"). A copy of the License is in the project file "LICENSE.md", 11 | and is also available at https://www.mozilla.org/en-US/MPL/2.0/. 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VBA Libraries for Excel 2 | 3 | This series of articles in [MPC IT Tech Blog][] describes the code in this project: 4 | 5 | 1. [Improving Menu Creation in Excel with VBA][] 6 | 2. [Excel VBA and Version Control][] 7 | 8 | [MPC IT Tech Blog]: http://tech.popdata.org/ 9 | [Improving Menu Creation in Excel with VBA]: http://tech.popdata.org/unicorn-1-menu/ 10 | [Excel VBA and Version Control]: http://tech.popdata.org/unicorn-2-version-control/ 11 | 12 | See the [NOTICE.txt][] file for copyright and contributor information. 13 | See the [LICENSE.md][] file for the project's license. 14 | 15 | [NOTICE.txt]: https://github.com/mnpopcenter/vba-libs/blob/master/NOTICE.txt 16 | [LICENSE.md]: https://github.com/mnpopcenter/vba-libs/blob/master/LICENSE.md 17 | 18 | ## Releases 19 | 20 | The [Change Log][] lists the versions that have been released and 21 | describes the changes in each version. 22 | 23 | [Change Log]: https://github.com/mnpopcenter/vba-libs/blob/master/CHANGE-LOG.md 24 | -------------------------------------------------------------------------------- /Sheet1.cls: -------------------------------------------------------------------------------- 1 | VERSION 1.0 CLASS 2 | BEGIN 3 | MultiUse = -1 'True 4 | END 5 | Attribute VB_Name = "Sheet1" 6 | Attribute VB_GlobalNameSpace = False 7 | Attribute VB_Creatable = False 8 | Attribute VB_PredeclaredId = True 9 | Attribute VB_Exposed = True 10 | -------------------------------------------------------------------------------- /Simple Toolkit_DEV.xlam: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipums/excel-toolkit-framework/3420175692178fbc207a759016f46f15d8c7cd46/Simple Toolkit_DEV.xlam -------------------------------------------------------------------------------- /Simple Toolkit_conf.bas: -------------------------------------------------------------------------------- 1 | Attribute VB_Name = "conf" 2 | Option Explicit 3 | 4 | ' This file is part of the Minnesota Population Center's VBA libraries project. 5 | ' For copyright and licensing information, see the NOTICE and LICENSE files 6 | ' in this project's top-level directory, and also on-line at: 7 | ' https://github.com/mnpopcenter/vba-libs 8 | 9 | 10 | ' Used as the title of message boxes 11 | Public Const TOOLKIT_NAME = "Simple Tools" 12 | 13 | Public Const VERSION_STR = "1.3.1" 14 | 15 | Public Const MENU_NAME = "&Simple Tools" 16 | 17 | ' The name of the macro that performs additional initialization for the 18 | ' toolkit. If not blank, it is run before the toolkit's menu is created. 19 | Public Const ADDITIONAL_INIT_MACRO = "" 20 | 21 | ' The order of this list determines the order that the modules are imported. 22 | ' Therefore, if module FOO depends on modules BAR and QUX, then make sure 23 | ' FOO is after BAR and QUX in the list. 24 | Public Const MODULE_FILENAMES = _ 25 | "excel_ver.bas" _ 26 | & "|file_utils.bas" _ 27 | & "|menu_lib.bas" _ 28 | & "|menu_defn_in_code.bas" _ 29 | & "|menu.bas" _ 30 | & "|toolkit.bas" _ 31 | & "|tools.bas" _ 32 | & "|dev_tools.bas" 33 | -------------------------------------------------------------------------------- /ThisWorkbook.cls: -------------------------------------------------------------------------------- 1 | VERSION 1.0 CLASS 2 | BEGIN 3 | MultiUse = -1 'True 4 | END 5 | Attribute VB_Name = "ThisWorkbook" 6 | Attribute VB_GlobalNameSpace = False 7 | Attribute VB_Creatable = False 8 | Attribute VB_PredeclaredId = True 9 | Attribute VB_Exposed = True 10 | 11 | Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean) 12 | bootstrap.BeforeToolkitSave SaveAsUI, Cancel 13 | End Sub 14 | 15 | Private Sub Workbook_Open() 16 | bootstrap.InitializeAddIn 17 | End Sub 18 | -------------------------------------------------------------------------------- /bootstrap.bas: -------------------------------------------------------------------------------- 1 | Attribute VB_Name = "bootstrap" 2 | Option Explicit 3 | 4 | ' This file is part of the Minnesota Population Center's VBA libraries project. 5 | ' For copyright and licensing information, see the NOTICE and LICENSE files 6 | ' in this project's top-level directory, and also on-line at: 7 | ' https://github.com/mnpopcenter/vba-libs 8 | 9 | Public Const MODULE_FILENAME = "bootstrap.bas" 10 | 11 | ' The module that's used to update the toolkit's core modules 12 | Private Const MODULE_FOR_CORE_UPDATES = "update_core" 13 | 14 | Public Enum ToolkitMode 15 | Unknown = 0 ' So an uninitialized variable will have this value 16 | Development 17 | Production 18 | End Enum 19 | 20 | ' The mode that the add-in is currently running in. 21 | Public CurrentMode As ToolkitMode 22 | 23 | Public Enum ToolkitEdition 24 | Unknown = 0 ' So an uninitialized variable will have this value 25 | Development ' (toolkit base name)_DEV.xlam 26 | BuiltProduction ' (toolkit base name)_PROD.xlam 27 | InstalledProduction ' (toolkit base name).xlam 28 | End Enum 29 | 30 | ' The current edition that the add-in represents 31 | Public CurrentEdition As ToolkitEdition 32 | 33 | ' The name and file path for the configuration and loader modules that 34 | ' are imported in Development mode. 35 | Public ConfModule_Name As String 36 | Public ConfModule_Path As String 37 | Public LoaderModule_Name As String 38 | Public LoaderModule_Path As String 39 | 40 | ' Can this toolkit edition be saved? 41 | ' By default, no. Only the development edition can be saved when building 42 | ' the production edition. 43 | Public AllowToolkitSave As Boolean 44 | 45 | ' This module is NOT imported into the development version of the add-in. 46 | ' It is exported to MODULE_FILENAME so a copy of its code is under version 47 | ' control. Changes to its code must be made in the Visual Basic editor. To 48 | ' make those changes, the development add-in must be opened with 49 | ' macros disabled. That will allow the add-in to be saved with just this 50 | ' bootstrap module. 51 | 52 | ' Called by ThisWorkbook.Workbook_Open event procedure (as a workaround 53 | ' for this issue: http://stackoverflow.com/q/34498794/1258514) 54 | Public Sub InitializeAddIn() 55 | If ThisWorkbook.Name Like "*NO-LOAD*" Then 56 | AllowToolkitSave = True 57 | ' Do not import any modules so developer can change file properties. 58 | Exit Sub 59 | End If 60 | 61 | AllowToolkitSave = False 62 | If ThisWorkbook.Name Like "*DEV*" Then 63 | CurrentMode = ToolkitMode.Development 64 | CurrentEdition = ToolkitEdition.Development 65 | ConfModule_Path = Replace(ThisWorkbook.FullName, "DEV.xlam", _ 66 | "conf.bas") 67 | LoaderModule_Path = ThisWorkbook.Path & Application.PathSeparator _ 68 | & "loader.bas" 69 | With ThisWorkbook.VBProject.VBComponents 70 | ConfModule_Name = .Import(ConfModule_Path).Name 71 | LoaderModule_Name = .Import(LoaderModule_Path).Name 72 | End With 73 | Application.Run "loader.LoadToolkitModules" 74 | Else 75 | CurrentMode = ToolkitMode.Production 76 | If ThisWorkbook.Name Like "*PROD*" Then 77 | CurrentEdition = ToolkitEdition.BuiltProduction 78 | Else 79 | CurrentEdition = ToolkitEdition.InstalledProduction 80 | End If 81 | End If 82 | Application.Run "toolkit.Initialize" 83 | End Sub 84 | 85 | ' Determine whether to allow the current toolkit edition to be saved. 86 | ' 87 | ' Called from ThisWorkbook.Workbook_BeforeSave event handler. 88 | Public Sub BeforeToolkitSave(ByVal SaveAsUI As Boolean, Cancel As Boolean) 89 | ' Don't allow NO-LOAD edition to save if the module for updating the core 90 | ' modules hasn't been unloaded yet. 91 | If ThisWorkbook.Name Like "*_NO-LOAD.xlam" Then 92 | If IsModuleLoaded(MODULE_FOR_CORE_UPDATES) Then 93 | Cancel = True 94 | MsgBox "The toolkit cannot be saved with the " & _ 95 | MODULE_FOR_CORE_UPDATES & " module loaded. Please" & _ 96 | " run the macro to unload it first.", vbExclamation 97 | End If 98 | ' Don't check the AllowToolkitSave module variable because when the 99 | ' bootstrap module's source code is changed, that variable is reset 100 | ' (i.e., which for Boolean variables means it's = False). 101 | Exit Sub 102 | End If 103 | If Not AllowToolkitSave Then 104 | Cancel = True 105 | If CurrentMode = ToolkitEdition.Development Then 106 | TellUser_SavingDisabled 107 | End If 108 | End If 109 | End Sub 110 | 111 | Private Sub TellUser_SavingDisabled() 112 | MsgBox "Saving the Development edition of this toolkit" & vbCr & _ 113 | "(" & ThisWorkbook.Name & ") from the VB editor is not" & vbCr & _ 114 | "allowed. Instead, select this action in its menu:" & vbCr & _ 115 | vbCr & _ 116 | " Developer Tools --> Export VBA code", _ 117 | vbCritical 118 | End Sub 119 | 120 | ' --------------------------------------------------------------------------- 121 | ' Subprocedures for updating the toolkit's core modules when needed 122 | 123 | Private Sub LoadModuleForCoreUpdates() 124 | If Not ThisWorkbook.Name Like "*_NO-LOAD.xlam" Then 125 | MsgBox "Error: the LoadModuleForCoreUpdates macro should only be" _ 126 | & " run in a toolkit's NO-LOAD edition.", vbCritical 127 | Exit Sub 128 | End If 129 | 130 | If IsModuleLoaded(MODULE_FOR_CORE_UPDATES) Then 131 | ReportModuleStatus "is already loaded" 132 | Else 133 | Dim module_path As String 134 | module_path = ThisWorkbook.Path & Application.PathSeparator & _ 135 | MODULE_FOR_CORE_UPDATES & ".bas" 136 | ThisWorkbook.VBProject.VBComponents.Import (module_path) 137 | ReportModuleStatus "loaded" 138 | End If 139 | End Sub 140 | 141 | Private Sub UnloadModuleForCoreUpdates() 142 | If IsModuleLoaded(MODULE_FOR_CORE_UPDATES) Then 143 | With ThisWorkbook.VBProject 144 | .VBComponents.Remove .VBComponents(MODULE_FOR_CORE_UPDATES) 145 | End With 146 | ReportModuleStatus "unloaded" 147 | Else 148 | ReportModuleStatus "is not loaded" 149 | End If 150 | End Sub 151 | 152 | Private Sub ReportModuleStatus(mod_status As String) 153 | Debug.Print ThisWorkbook.Name & " -- " & MODULE_FOR_CORE_UPDATES & _ 154 | " module " & mod_status 155 | End Sub 156 | 157 | Private Function IsModuleLoaded(module_name) As Boolean 158 | On Error GoTo NoSuchModule 159 | With ThisWorkbook.VBProject.VBComponents(module_name) 160 | ' Do nothing 161 | End With 162 | IsModuleLoaded = True 163 | Exit Function 164 | NoSuchModule: 165 | IsModuleLoaded = False 166 | End Function 167 | -------------------------------------------------------------------------------- /dev_tools.bas: -------------------------------------------------------------------------------- 1 | Attribute VB_Name = "developer_tools" 2 | Option Explicit 3 | 4 | ' This file is part of the Minnesota Population Center's VBA libraries project. 5 | ' For copyright and licensing information, see the NOTICE and LICENSE files 6 | ' in this project's top-level directory, and also on-line at: 7 | ' https://github.com/mnpopcenter/vba-libs 8 | 9 | 10 | ' Module dependencies: 11 | ' bootstrap 12 | ' conf 13 | ' loader 14 | ' toolkit 15 | 16 | 17 | ' Full path to the production version of this add-in 18 | Private ProductionAddInPath As String 19 | 20 | ' Names of macros to run before and after building the production version 21 | ' (default = "", which is a no-op). 22 | Public PreBuildMacro As String ' Sub() 23 | Public PostBuildMacro As String ' Function(build_message As String) As String 24 | ' returns an updated build message or "" 25 | ' if an error occurred and was displayed 26 | ' to the developer. 27 | 28 | Public Sub ExportVbaCode() 29 | Dim message As String 30 | message = "Exported the VBA code into these files:" & vbCr 31 | 32 | Dim component 33 | For Each component In ThisWorkbook.VBProject.VBComponents 34 | Dim module_path As String 35 | If component.Name = "ThisWorkbook" Or component.Name = "Sheet1" Then 36 | module_path = PathInThisWorkbookDir(component.Name & ".cls") 37 | Else 38 | module_path = loader.ModulePaths(component.Name) 39 | End If 40 | component.Export module_path 41 | Dim file_name As String 42 | file_name = Replace(module_path, PathInThisWorkbookDir(""), "") 43 | message = message & vbCr & _ 44 | " " & component.Name & " --> " & file_name 45 | Next component 46 | 47 | MsgBox message & vbCr & _ 48 | vbCr & _ 49 | "The files are located in this directory:" & vbCr & _ 50 | vbCr & _ 51 | ThisWorkbook.Path, vbOKOnly, "Exported VBA Code" 52 | End Sub 53 | 54 | Public Sub BuildProductionVersion() 55 | Dim prod_add_in_name As String 56 | prod_add_in_name = Replace(ThisWorkbook.Name, "_DEV", "_PROD") 57 | ProductionAddInPath = PathInThisWorkbookDir(prod_add_in_name) 58 | 59 | Dim message As String 60 | Dim window_title As String 61 | If FileExists(ProductionAddInPath) Then 62 | message = "The add-in """ & prod_add_in_name & """ already exists in" & _ 63 | " the folder:" & _ 64 | vbCr & vbCr & _ 65 | ThisWorkbook.Path & _ 66 | vbCr & vbCr & _ 67 | "Do you want to rebuild it?" 68 | Dim Answer As Integer 69 | Answer = MsgBox(message, vbYesNo, "Rebuild the Add-in?") 70 | If Answer = vbNo Then 71 | Exit Sub 72 | End If 73 | Kill ProductionAddInPath 74 | window_title = "Rebuilt the Production Add-in" 75 | Else 76 | window_title = "Built the Production Add-in" 77 | End If 78 | 79 | If PreBuildMacro <> "" Then Application.Run PreBuildMacro 80 | MakeProductionAddIn 81 | message = "Created the add-in """ & prod_add_in_name & """ in the folder:" & _ 82 | vbCr & vbCr & _ 83 | ThisWorkbook.Path 84 | If PostBuildMacro <> "" Then 85 | message = Application.Run(PostBuildMacro, message) 86 | If message = "" Then 87 | ' Error occurred and the developer was notified, so just exit 88 | Exit Sub 89 | End If 90 | End If 91 | MsgBox message, vbOKOnly, window_title 92 | End Sub 93 | 94 | Private Sub MakeProductionAddIn() 95 | toolkit.StoreBuildDateTime Now() 96 | 97 | ' Set the add-in's Title and Comments (description) for the production 98 | ' version 99 | Dim titleDev As String 100 | titleDev = ThisWorkbook.Title 101 | Dim commentsDev As String 102 | commentsDev = ThisWorkbook.Comments 103 | 104 | bootstrap.AllowToolkitSave = True 105 | With ThisWorkbook 106 | .Title = Replace(titleDev, " (dev)", "") 107 | .Comments = Replace(commentsDev, "development version", _ 108 | "version " & conf.VERSION_STR) 109 | .SaveAs ProductionAddInPath, xlOpenXMLAddIn 110 | End With 111 | bootstrap.AllowToolkitSave = False 112 | 113 | ' Restore the development version of Title and Comments 114 | With ThisWorkbook 115 | .Title = titleDev 116 | .Comments = commentsDev 117 | End With 118 | End Sub 119 | -------------------------------------------------------------------------------- /excel_ver.bas: -------------------------------------------------------------------------------- 1 | Attribute VB_Name = "Excel_version" 2 | Option Explicit 3 | 4 | ' This file is part of the Minnesota Population Center's VBA libraries project. 5 | ' For copyright and licensing information, see the NOTICE and LICENSE files 6 | ' in this project's top-level directory, and also on-line at: 7 | ' https://github.com/mnpopcenter/vba-libs 8 | 9 | 10 | ' Constants for values returned by Application.Version 11 | 12 | Public Const EXCEL_WIN_2003 = 11 13 | Public Const EXCEL_WIN_2007 = 12 14 | Public Const EXCEL_WIN_2010 = 14 15 | Public Const EXCEL_WIN_2013 = 15 16 | Public Const EXCEL_WIN_2016 = 16 17 | 18 | Public Const EXCEL_MAC_2004 = 11 19 | Public Const EXCEL_MAC_2008 = 12 ' Note: did not have support for VBA 20 | Public Const EXCEL_MAC_2011 = 14 21 | Public Const EXCEL_MAC_2016 = 15 22 | 23 | ' Enumerated type for platform-specific Excel 24 | Public Enum ExcelPlatform 25 | ExcelUnknown 26 | ExcelWin 27 | ExcelMac 28 | End Enum 29 | 30 | ' How to compare versions 31 | Public Enum VersionComparison 32 | Exact ' only the specified version matches 33 | OrLater ' matches the specified version or a later (newer) one 34 | OrEarlier ' matches the specified version or an earlier (older) one 35 | End Enum 36 | 37 | ' Indicates that any year for a platform-specific Excel is acceptable 38 | Private Const ANY_YEAR = -999 39 | 40 | Public Function ExcelVersionIs( _ 41 | expected_platform As ExcelPlatform, _ 42 | Optional expected_year As Integer = ANY_YEAR, _ 43 | Optional version_compare As VersionComparison = Exact) _ 44 | As Boolean 45 | Dim platform_app As ExcelPlatform 46 | #If Mac Then 47 | platform_app = ExcelMac 48 | #Else 49 | platform_app = ExcelWin 50 | #End If 51 | If platform_app <> expected_platform Then 52 | ExcelVersionIs = False 53 | ElseIf expected_year = ANY_YEAR Then 54 | ExcelVersionIs = True 55 | Else 56 | Dim major_version As Integer 57 | major_version = Int(Val(Application.Version)) 58 | Dim expected_version As Integer 59 | expected_version = GetAppVersion(platform_app, expected_year) 60 | Select Case version_compare 61 | Case Exact 62 | ExcelVersionIs = (major_version = expected_version) 63 | Case OrLater 64 | ExcelVersionIs = (major_version >= expected_version) 65 | Case OrEarlier 66 | ExcelVersionIs = (major_version <= expected_version) 67 | Case Else 68 | ExcelVersionIs = False 69 | End Select 70 | End If 71 | End Function 72 | 73 | Public Function GetAppVersion(platform_app As ExcelPlatform, _ 74 | app_year As Integer) As Integer 75 | If platform_app = ExcelWin Then 76 | Select Case app_year 77 | Case 2003: GetAppVersion = EXCEL_WIN_2003 78 | Case 2007: GetAppVersion = EXCEL_WIN_2007 79 | Case 2010: GetAppVersion = EXCEL_WIN_2010 80 | Case 2013: GetAppVersion = EXCEL_WIN_2013 81 | Case 2016: GetAppVersion = EXCEL_WIN_2016 82 | Case Else: GetAppVersion = 0 83 | End Select 84 | ElseIf platform_app = ExcelMac Then 85 | Select Case app_year 86 | Case 2004: GetAppVersion = EXCEL_MAC_2004 87 | Case 2008: GetAppVersion = EXCEL_MAC_2008 88 | Case 2011: GetAppVersion = EXCEL_MAC_2011 89 | Case 2016: GetAppVersion = EXCEL_MAC_2016 90 | Case Else: GetAppVersion = 0 91 | End Select 92 | Else 93 | GetAppVersion = 0 94 | End If 95 | End Function 96 | -------------------------------------------------------------------------------- /file_utils.bas: -------------------------------------------------------------------------------- 1 | Attribute VB_Name = "file_utilities" 2 | Option Explicit 3 | 4 | ' This file is part of the Minnesota Population Center's VBA libraries project. 5 | ' For copyright and licensing information, see the NOTICE and LICENSE files 6 | ' in this project's top-level directory, and also on-line at: 7 | ' https://github.com/mnpopcenter/vba-libs 8 | 9 | 10 | Public Function FileExists(file_path As String) As Boolean 11 | If Application.OperatingSystem Like "*Mac*" Then 12 | On Error GoTo DirErr 13 | End If 14 | 15 | FileExists = Dir(file_path) <> "" 16 | Exit Function 17 | 18 | DirErr: 19 | ' Excel for Mac raises an error if Dir() function called with a path that 20 | ' does not exist. For details, see: 21 | ' http://answers.microsoft.com/en-us/mac/forum/macoffice2011-macexcel/lets-talk-about-mac-excel-2011-bugs/a3653864-e889-4413-aab0-ac118c03d65e 22 | If Err.Number = 68 Then 23 | FileExists = False 24 | Else 25 | MsgBox Err.Description & " (" & Err.Number & ")", , "Run-time Error" 26 | Stop 27 | End If 28 | End Function 29 | -------------------------------------------------------------------------------- /loader.bas: -------------------------------------------------------------------------------- 1 | Attribute VB_Name = "loader" 2 | Option Explicit 3 | 4 | ' This file is part of the Minnesota Population Center's VBA libraries project. 5 | ' For copyright and licensing information, see the NOTICE and LICENSE files 6 | ' in this project's top-level directory, and also on-line at: 7 | ' https://github.com/mnpopcenter/vba-libs 8 | 9 | 10 | ' Module dependencies: 11 | ' bootstrap 12 | ' conf 13 | 14 | ' The list of full paths to all the modules in the add-in. They are in the 15 | ' order that they are imported into the development version of the add-in. 16 | ' Each path is also indexed by the module's name (i.e., what's specified by 17 | ' its Attribute VB_Name). 18 | Public ModulePaths As Collection 19 | 20 | Public Sub LoadToolkitModules() 21 | InitializeModulePaths 22 | LoadModules 23 | End Sub 24 | 25 | ' Initialize ModulePaths with the 3 modules that are initially in the add-in 26 | Private Sub InitializeModulePaths() 27 | Set ModulePaths = New Collection 28 | Const STANDARD_MODULE_TYPE = 1 29 | Dim component 30 | For Each component In ThisWorkbook.VBProject.VBComponents 31 | If component.Type = STANDARD_MODULE_TYPE Then 32 | Dim module_path As String 33 | If component.Name = bootstrap.ConfModule_Name Then 34 | module_path = bootstrap.ConfModule_Path 35 | ElseIf component.Name = bootstrap.LoaderModule_Name Then 36 | module_path = bootstrap.LoaderModule_Path 37 | Else 38 | ' Only other module is the bootstrap one 39 | module_path = PathInThisWorkbookDir(bootstrap.MODULE_FILENAME) 40 | End If 41 | ModulePaths.Add module_path, component.Name 42 | End If 43 | Next component 44 | End Sub 45 | 46 | ' Import all the other modules in the toolkit 47 | Private Sub LoadModules() 48 | Dim module_file_names() As String 49 | module_file_names = Split(conf.MODULE_FILENAMES, "|") 50 | With ThisWorkbook.VBProject.VBComponents 51 | Dim i As Integer 52 | For i = LBound(module_file_names) To UBound(module_file_names) 53 | Dim module_path As String 54 | module_path = PathInThisWorkbookDir(module_file_names(i)) 55 | Dim imported_module 56 | Set imported_module = .Import(module_path) 57 | ModulePaths.Add module_path, imported_module.Name 58 | Next i 59 | End With 60 | End Sub 61 | 62 | Public Function PathInThisWorkbookDir(file_name As String) As String 63 | PathInThisWorkbookDir = ThisWorkbook.Path & Application.PathSeparator _ 64 | & file_name 65 | End Function 66 | -------------------------------------------------------------------------------- /menu.bas: -------------------------------------------------------------------------------- 1 | Attribute VB_Name = "menu" 2 | Option Explicit 3 | 4 | ' This file is part of the Minnesota Population Center's VBA libraries project. 5 | ' For copyright and licensing information, see the NOTICE and LICENSE files 6 | ' in this project's top-level directory, and also on-line at: 7 | ' https://github.com/mnpopcenter/vba-libs 8 | 9 | 10 | ' Module dependencies: 11 | ' bootstrap (CurrentMode, ToolkitMode, CurrentEdition, ToolkitEdition) 12 | ' conf 13 | ' Excel_version 14 | ' menu_library 15 | 16 | Private myMenuName As String 17 | 18 | Public Sub CreateToolkitMenu(ByRef definition() As String) 19 | myMenuName = conf.MENU_NAME 20 | If CurrentMode = ToolkitMode.Development Then 21 | myMenuName = myMenuName & " (dev)" 22 | ElseIf CurrentEdition = ToolkitEdition.BuiltProduction Then 23 | myMenuName = myMenuName & " (prod)" 24 | End If 25 | 26 | If CurrentMode = ToolkitMode.Development Then 27 | EnableDevelopersMenu definition 28 | End If 29 | 30 | ' Workaround for bug with menus not being removed when an add-in closes. 31 | ' https://support.microsoft.com/en-us/kb/2761240 32 | If ExcelVersionIs(ExcelWin, 2013) Then 33 | ' Remove any menus left over from the previous Excel session 34 | RemoveToolkitMenu 35 | End If 36 | AddCustomMenu myMenuName, definition 37 | End Sub 38 | 39 | Public Sub RemoveToolkitMenu() 40 | RemoveCustomMenu myMenuName 41 | End Sub 42 | 43 | Sub EnableDevelopersMenu(definition() As String) 44 | ' Remove any "#dev>" markers to enable the developers menu 45 | Dim i As Integer 46 | For i = LBound(definition) To UBound(definition) 47 | definition(i) = Replace(definition(i), "#dev>", "") 48 | Next i 49 | End Sub 50 | -------------------------------------------------------------------------------- /menu_defn_in_code.bas: -------------------------------------------------------------------------------- 1 | Attribute VB_Name = "menu_definition" 2 | Option Explicit 3 | 4 | ' This file is part of the Minnesota Population Center's VBA libraries project. 5 | ' For copyright and licensing information, see the NOTICE and LICENSE files 6 | ' in this project's top-level directory, and also on-line at: 7 | ' https://github.com/mnpopcenter/vba-libs 8 | 9 | 10 | Const MENU_DEFINITION_STR = _ 11 | "Foo | FooMacro" _ 12 | & vbLf & "Bar | BarMacro" _ 13 | & vbLf & "---------" _ 14 | & vbLf & "Compression ==>" _ 15 | & vbLf & " Normal | CompressData ""Normal""" _ 16 | & vbLf & " Fast | CompressData ""Fast""" _ 17 | & vbLf & " Best | CompressData ""Best""" _ 18 | & vbLf & "" _ 19 | & vbLf & "-------" _ 20 | & vbLf & "Version | DisplayVersion" _ 21 | & vbLf & "" _ 22 | & vbLf & "" _ 23 | & vbLf & "# (enabled only in Development mode)" _ 24 | & vbLf & "#dev>----------------------------------" _ 25 | & vbLf & "#dev>Developer Tools ==>" _ 26 | & vbLf & "#dev> Export VBA code | ExportVbaCode" _ 27 | & vbLf & "#dev> ------------------------" _ 28 | & vbLf & "#dev> Build Production version | BuildProductionVersion" 29 | 30 | Public Function LoadIntoArray(ByRef definition() As String) As Boolean 31 | definition = Split(MENU_DEFINITION_STR, vbLf) 32 | LoadIntoArray = True 33 | End Function 34 | -------------------------------------------------------------------------------- /menu_lib.bas: -------------------------------------------------------------------------------- 1 | Attribute VB_Name = "menu_library" 2 | Option Explicit 3 | 4 | ' This file is part of the Minnesota Population Center's VBA libraries project. 5 | ' For copyright and licensing information, see the NOTICE and LICENSE files 6 | ' in this project's top-level directory, and also on-line at: 7 | ' https://github.com/mnpopcenter/vba-libs 8 | 9 | ' Add a custom menu to the worksheet menu bar. The definition of the menu 10 | ' is a sequence of strings; for example: 11 | ' 12 | ' # Menu definition 13 | ' Foo | FooMacro 14 | ' Bar | BarMacro 15 | ' --------- 16 | ' Compression ==> 17 | ' Normal | CompressData "Normal" 18 | ' Fast | CompressData "Fast" 19 | ' Best | CompressData "Best" 20 | ' 21 | ' ------- 22 | ' Version | DisplayVersion 23 | ' 24 | ' Blank lines are ignored. A comment line has "#" as the first non-whitespace 25 | ' character. Comment lines are also ignored. A submenu of the custom menu is 26 | ' is denoted with a "==>" at the end of line. 27 | ' 28 | ' A menu item (for the cusotm menu or one of its submenus) has the format: 29 | ' 30 | ' menu item caption | action 31 | ' 32 | ' The action is the value assigned to the menu item's OnAction property. It 33 | ' is the name of the macro to execute, along with any necessary arguments. 34 | ' Menu items for the custom menu are not indented. The items for submenus 35 | ' must be indented at least 4 spaces. 36 | ' 37 | ' A separator in a menu (custom or submenu) is represented by a line with at 38 | ' least 4 "-" (hyphens). Extra hyphens can be used for readability. A 39 | ' submenu separator must be indented at least 4 spaces. 40 | ' 41 | Sub AddCustomMenu(menuName As String, definition() As String, _ 42 | Optional insertBefore As String = "") 43 | Dim helpMenu As CommandBarControl 44 | Dim customMenu As CommandBarControl 45 | Dim mainMenuBar As CommandBar 46 | 47 | Set mainMenuBar = Application.CommandBars("Worksheet Menu Bar") 48 | If insertBefore = "" Then 49 | ' By default, look up Help menu by its control id since its name 50 | ' is language-dependent 51 | Set helpMenu = mainMenuBar.FindControl(ID:=30010) 52 | Else 53 | Set helpMenu = mainMenuBar.Controls(insertBefore) 54 | End If 55 | Set customMenu = mainMenuBar.Controls.Add(Type:=msoControlPopup, _ 56 | Before:=helpMenu.Index) 57 | customMenu.Caption = menuName 58 | 59 | Dim line As String 60 | Dim i As Long 61 | Dim currentSubMenu As CommandBarControl 62 | Dim addSeparator As Boolean 63 | addSeparator = False 64 | 65 | For i = LBound(definition) To UBound(definition) 66 | line = definition(i) 67 | If IsBlank(line) Or IsComment(line) Then 68 | ' Ignore blank lines and comment lines 69 | ElseIf Right(line, 3) = "==>" Then 70 | ' Submenu ends with "==>" 71 | With customMenu.Controls 72 | Set currentSubMenu = .Add(Type:=msoControlPopup) 73 | End With 74 | With currentSubMenu 75 | .Caption = Trim(Replace(line, "==>", "")) 76 | .BeginGroup = addSeparator 77 | End With 78 | addSeparator = False 79 | ElseIf Left(LTrim(line), 4) = "----" Then 80 | ' Add separator above the next menu item in the definition 81 | addSeparator = True 82 | Else 83 | ' New menu item for either current submenu or the custom menu 84 | Dim isSubmenuItem As Boolean 85 | isSubmenuItem = StartsWith(line, " ") 86 | Dim menu As CommandBarControl 87 | Set menu = IIf(isSubmenuItem, currentSubMenu, customMenu) 88 | Dim menuItem As CommandBarControl 89 | Set menuItem = menu.Controls.Add(Type:=msoControlButton) 90 | 91 | ' line format = menu item caption | action 92 | Dim fields() As String 93 | fields = Split(Trim(line), "|") 94 | Dim itemCaption As String 95 | itemCaption = Trim(fields(0)) 96 | Dim itemAction As String 97 | itemAction = Trim(fields(1)) 98 | With menuItem 99 | .Caption = itemCaption 100 | .OnAction = "'" & itemAction & "'" 101 | .BeginGroup = addSeparator 102 | End With 103 | addSeparator = False 104 | End If 105 | Next 106 | End Sub 107 | 108 | Function StartsWith(str_ As String, prefix As String) As Boolean 109 | StartsWith = Left(str_, Len(prefix)) = prefix 110 | End Function 111 | 112 | Function IsBlank(line As String) As Boolean 113 | IsBlank = RTrim(line) = "" 114 | End Function 115 | 116 | Function IsComment(line As String) As Boolean 117 | IsComment = Left(LTrim(line), 1) = "#" 118 | End Function 119 | 120 | Public Sub RemoveCustomMenu(menuName As String) 121 | With Application.CommandBars("Worksheet Menu Bar") 122 | Dim ctrl As CommandBarControl 123 | For Each ctrl In .Controls 124 | If ctrl.Caption = menuName Then 125 | ctrl.Delete 126 | End If 127 | Next ctrl 128 | End With 129 | End Sub 130 | -------------------------------------------------------------------------------- /toolkit.bas: -------------------------------------------------------------------------------- 1 | Attribute VB_Name = "toolkit" 2 | Option Explicit 3 | 4 | ' This file is part of the Minnesota Population Center's VBA libraries project. 5 | ' For copyright and licensing information, see the NOTICE and LICENSE files 6 | ' in this project's top-level directory, and also on-line at: 7 | ' https://github.com/mnpopcenter/vba-libs 8 | 9 | 10 | ' Module dependencies: 11 | ' bootstrap (CurrentMode, ToolkitMode, CurrentEdition, ToolkitEdition) 12 | ' conf 13 | ' menu_definition 14 | ' menu 15 | 16 | ' Date when the production version was built 17 | Public Const BUILD_DATE_FORMAT = "mmmm d, yyyy" 18 | Public BuildDate As String 19 | 20 | ' Cell where build date & time of production version is stored. 21 | ' Even add-ins have at least 1 worksheet 22 | Public Const BUILT_WHEN_CELL = "$Z$1" 23 | 24 | ' Toolkit's base file name without edition marker (_DEV|_PROD) and extension 25 | Public BaseFileName As String 26 | 27 | Public Sub Initialize() 28 | If CurrentMode = ToolkitMode.Development Then 29 | toolkit.BuildDate = "Development version" 30 | toolkit.BaseFileName = Replace(ThisWorkbook.Name, "_DEV.xlam", "") 31 | Else 32 | Dim builtWhen As Date 33 | builtWhen = ThisWorkbook.Worksheets(1).Range(BUILT_WHEN_CELL).Value 34 | toolkit.BuildDate = Format(builtWhen, BUILD_DATE_FORMAT) 35 | If CurrentEdition = ToolkitEdition.BuiltProduction Then 36 | toolkit.BaseFileName = Replace(ThisWorkbook.Name, "_PROD.xlam", "") 37 | Else 38 | toolkit.BaseFileName = Replace(ThisWorkbook.Name, ".xlam", "") 39 | End If 40 | End If 41 | 42 | If conf.ADDITIONAL_INIT_MACRO <> "" Then 43 | Application.Run conf.ADDITIONAL_INIT_MACRO 44 | End If 45 | 46 | Dim menu_defn() As String 47 | If menu_definition.LoadIntoArray(menu_defn) Then 48 | CreateToolkitMenu menu_defn 49 | End If 50 | End Sub 51 | 52 | Public Sub Auto_Close() 53 | RemoveToolkitMenu 54 | End Sub 55 | 56 | Public Sub StoreBuildDateTime(date_time As Date) 57 | ThisWorkbook.Worksheets(1).Range(BUILT_WHEN_CELL).Value = date_time 58 | End Sub 59 | 60 | Public Sub DisplayVersion() 61 | MsgBox BuildDate & " (" & conf.VERSION_STR & ").", vbOKOnly, _ 62 | conf.TOOLKIT_NAME 63 | End Sub 64 | -------------------------------------------------------------------------------- /tools.bas: -------------------------------------------------------------------------------- 1 | Attribute VB_Name = "tools" 2 | Option Explicit 3 | 4 | ' Module dependencies: 5 | ' conf 6 | 7 | Public Sub FooMacro() 8 | ShowRunningToolMessage "FooMacro" 9 | End Sub 10 | 11 | Public Sub BarMacro() 12 | ShowRunningToolMessage "BarMacro" 13 | End Sub 14 | 15 | Public Sub CompressData(level As String) 16 | ShowRunningToolMessage "CompressData", "level = " & level 17 | End Sub 18 | 19 | Private Sub ShowRunningToolMessage(tool_name As String, _ 20 | Optional extra_info As String = "") 21 | Dim message As String 22 | message = "Running the " & tool_name & " tool..." 23 | If extra_info <> "" Then 24 | message = message & vbCr & _ 25 | extra_info 26 | End If 27 | MsgBox message, vbOKOnly, conf.TOOLKIT_NAME 28 | End Sub 29 | -------------------------------------------------------------------------------- /update_core.bas: -------------------------------------------------------------------------------- 1 | Attribute VB_Name = "update_core" 2 | Option Explicit 3 | 4 | ' This file is part of the Minnesota Population Center's VBA libraries project. 5 | ' For copyright and licensing information, see the NOTICE and LICENSE files 6 | ' in this project's top-level directory, and also on-line at: 7 | ' https://github.com/mnpopcenter/vba-libs 8 | 9 | ' Update the core modules in the current toolkit by loading revised source 10 | ' code from their corresponding code files: 11 | ' 12 | ' ThisWorkbook.cls 13 | ' bootstrap.bas 14 | ' 15 | Public Sub UpdateCoreModules() 16 | UpdateCoreModuleFrom "ThisWorkbook.cls", vbCrLf & "Private Sub" 17 | UpdateCoreModuleFrom "bootstrap.bas", "Option Explicit" 18 | 19 | Debug.Print ThisWorkbook.Name & " -- after reviewing the changes, " & _ 20 | "save the file" 21 | End Sub 22 | 23 | ' Update the source code of a core module from its corresponding code file. 24 | Private Sub UpdateCoreModuleFrom(source_file_name As String, _ 25 | initial_code_text As String) 26 | Dim source_file_path As String 27 | source_file_path = ThisWorkbook.Path & Application.PathSeparator & _ 28 | source_file_name 29 | 30 | Dim source_code As String 31 | Dim file_number As Integer 32 | file_number = FreeFile() 33 | Open source_file_path For Input As #file_number 34 | source_code = Input$(LOF(file_number), file_number) 35 | Close file_number 36 | 37 | ' Remove the leading non-code line(s) from the source code 38 | Dim code_len As Long 39 | code_len = Len(source_code) - InStr(source_code, initial_code_text) + 1 40 | source_code = Right(source_code, code_len) 41 | 42 | ' Trim the last line terminator so when the module is exported, the 43 | ' exported code will match the contents in the file. 44 | Dim line_terminator_len As Long 45 | If Right(source_code, 2) = vbCrLf Then 46 | line_terminator_len = 2 47 | Else 48 | line_terminator_len = 1 49 | End If 50 | source_code = Left(source_code, Len(source_code) - line_terminator_len) 51 | 52 | Dim module_name As String 53 | module_name = Split(source_file_name, ".")(0) 54 | 55 | With ThisWorkbook.VBProject.VBComponents(module_name).CodeModule 56 | .DeleteLines 1, .CountOfLines 57 | .InsertLines 1, source_code 58 | 59 | ' For an unknown reason (hey, it's VBA!), an extra blank line is 60 | ' appended onto the bootstrap module. Delete this last code line so 61 | ' that the module will round-trip correctly (i.e., exported code will 62 | ' match the file contents that were imported). 63 | If module_name = "bootstrap" Then 64 | If .Lines(.CountOfLines, 1) = "" Then 65 | .DeleteLines .CountOfLines, 1 66 | End If 67 | End If 68 | End With 69 | 70 | Debug.Print ThisWorkbook.Name & " -- core module updated: " & module_name 71 | End Sub 72 | --------------------------------------------------------------------------------