We have a project with components written in Excel/VBA. We use Git on Azure Devops for source control.
The other components are written in C++ and we use Visual Studio 2017 as IDE. We use the VS Team explorer for the git operations. The VBA code is exported and imported from Excel using vbaDeveloper tool. The diff and merge tool is the internal vsDiffMerge.exe.
After a colleague recently rebased his development branch on master, the VBA code got corrupted on seemingly random places.
Some of the corruption seems to indicate that something tried to parse the text according to a syntax, for example:
"Option Explicit" was changed to "Option Explicit On" on alot of places (VBA doesn't have that syntax, but VB6 does)
Added parenthesis after calls to subroutines (VBA doesn't allow these for subroutines, only for functions)
Other kinds of corruption was just random:
Missing declarations of parameters and variables, and functions
Missing parts of code
Random characters in code (e.g. chinese letters)
Is it possible that vsDiffMerge.exe has tried to be too smart here and interpret the VBA source code files (.cls, .bas, .frm) as VB6/VB.NET and done some own modifications?
Related
If someone have to carry on working on an Excel VBA project/module after the previous developer left the company, how do they safely change a global variable name?
These global variable names can be problematic if they are misleading, misspelled, look like another variable, don't follow the chosen convention, etc.
Changing them with a Search/Replace is a problem because sometimes it's a word that appears in comments.
Changing them by Copy/Pasting is a problem because it's long and you can miss some, especially if there are a lot of occurrences or if you change it to something similar.
Is there a way to do this safely via the Excel "IDE", or via another tool?
What you need to do here is called a refactoring - you need to make a possibly dangerous change to the code, without affecting its behavior. Do it wrong and the code breaks!
Renaming an identifier that's used in one or more places, is a rename refactoring.
Most modern IDE's have such a feature (and several other refactorings). However the VBE was at the height of its glory well before Visual Studio was the full-featured tool it has become since then - heck, the VBE was Visual Studio (6.0) in 1998!
So you really have two options:
Do the refactoring manually - the IDE's search & replace functionality (Ctrl+H) can be dangerous here, because it treats code as simple text, without semantic understanding: you need to review every single occurrence individually, or risk renaming an identifier that was not referring to the variable you're trying to rename.
Use a 3rd-party tool - I don't know any VBIDE add-ins that understand the code deeply enough to allow safely refactoring VBA code, other than the open-source Rubberduck project, which I've managed since October 2014). This add-in parses your entire project, builds a symbol table, and lets you navigate and, yes, refactor/rename any identifier, automatically updating all call sites.
Note that Rubberduck is a very active open-source project, constantly improving. Parsing VBA is hard, and getting the VBE functionally on par with modern-day IDEs isn't a small undertaking, nor is it easy... but it's fun, and yep, it works.
So I'm having to run someone else's excel app on my PC, and I'm getting "Can't find Project or Library" on standard functions such as date, format, hex, mid, etc.
Some research indicates that if I prefix these functions with "VBA." as in "VBA.Date" then it'll work fine.
Webpages suggest it has to do with my project references on my system, whereas they must be ok on the developer's system. I'm going to be dealing with this for some time from others, and will be distributing these applications to many others, so I need to understand what's wrong with my excel setup that I need to fix, or what needs to be changed in the xls file so that it'll run on a variety of systems. I'd like to avoid making everyone use "VBA." as an explicit reference, but if there's no ideal solution I suppose that's what we'll have to do.
How do I make "VBA." implicit in my project properties/references/etc?
-Adam
I have seen errors on standard functions if there was a reference to a totally different library missing.
In the VBA editor launch the Compile command from the menu and then check the References dialog to see if there is anything missing and if so try to add these libraries.
In general it seems to be good practice to compile the complete VBA code and then saving the document before distribution.
I had the same problem. This worked for me:
In VB go to Tools ยป References
Uncheck the library "Crystal Analysis Common Controls 1.0". Or any library.
Just leave these 5 references:
Visual Basic For Applications (This is the library that defines the VBA language.)
Microsoft Excel Object Library (This defines all of the elements of Excel.)
OLE Automation (This specifies the types for linking and embedding documents and for automation of other applications and the "plumbing" of the COM system that Excel uses to communicate with the outside world.)
Microsoft Office (This defines things that are common to all Office programs such as Command Bars and Command Bar controls.)
Microsoft Forms 2.0 This is required if you are using a User Form. This library defines things like the user form and the controls that you can place on a form.
Then Save.
I have experienced this exact problem and found, on the users machine, one of the libraries I depended on was marked as "MISSING" in the references dialog. In that case it was some office font library that was available in my version of Office 2007, but not on the client desktop.
The error you get is a complete red herring (as pointed out by divo).
Fortunately I wasn't using anything from the library, so I was able to remove it from the XLA references entirely. I guess, an extension of divo' suggested best practice would be for testing to check the XLA on all the target Office versions (not a bad idea in any case).
In my case, it was that the function was AMBIGUOUS as it was defined in the VBA library (present in my references), and also in the Microsoft Office Object Library (also present). I removed the Microsoft Office Object Library, and voila! No need to use the VBA. prefix.
In my case, I could not even open "References" in the Visual Basic window. I even tried reinstalling Office 365 and that didn't work. Finally, I tried disabling macros in the "Trust Center" settings. When I restarted Excel, I got the warning message that macros were disabled, and when I clicked on "enable" I no longer got the error message.
Later I re-enabled all macros in the "Trust Center" settings, and the error message didn't show up!
Hey, if nothing else works for you, try the above; it worked for me! :)
Update:
The issue returned, and this is how I "fixed" it the second time:
I opened my workbook in Excel online (Office 365, in the browser, which doesn't support macros anyway), saved it with a new file name (still using .xlsm file extension), and reopened in the desktop software. It worked.
Even when all references are fine the prefix problem causes compile errors.
What about creating a find and replace sub for all 'built-in VBA functions' in all modules,
like this:
replace text in code module
e.g. "= Date" will be replaced with "= VBA.Date".
e.g. " Date(" will be replaced with " VBA.Date(" .
(excluding "dim t As Date" or "mydate")
All vba functions for find and replace are written here :
vba functions list
For those of you who haven't found any of the other answers work for you.
Try this:
Close out of the file, email it to yourself or if you're at work, paste it from the network drive to your desktop, anything to get it to open in "protected mode".
Now open the file
DON'T CLICK ANY ENABLE EDITING OR THE YELLOW RIBBON
Go to the VBA Editor
Go to Debug - - Compile VBA Project, if "Compile VBA Project" is greyed out, then you may need to click the yellow ribbon one time to enable the content, but DO NOT enable macros.
After you click Compile, save, close out of the file. Reopen it, enable everything and it should be OK. This has worked for me 100% of the time.
In my case I was checking work done on my office computer (with Visio installed) at home (no Visio). Even though VBA appeared to be getting hung up on simple default functions, the problem was that I had references to the Visio libraries still active.
I found references to an AVAYA/CMS programme file? Totally random, this was in MS Access, nothing to do with AVAYA. I do have AVAYA on my PC, and others don't, so this explains why it worked on my machine and not others - but not how Access got linked to AVAYA. Anyway - I just unchecked the reference and that seems to have fixed the problem
I've had this error on and off for around two years in a several XLSM files (which is most annoying as when it occurs there is nothing wrong with the file! - I suspect orphaned Excel processes are part of the problem)
The most efficient solution I had found has been to use Python with oletools
https://github.com/decalage2/oletools/wiki/Install and extract the VBA code all the modules and save in a text file.
Then I simply rename the file to zip file (backup just in case!), open up this zip file and delete the xl/vbaProject.bin file. Rename back to XLSX and should be good to go.
Copy in the saved VBA code (which will need cleaning of line breaks, comments and other stuff. Will also need to add in missing libraries.
This has saved me when other methods haven't.
YMMV.
Is it possible to have modules be external to the actual Excel file and call the functions/subs within them externally?
My thinking is if there are multiple Excel files that use the same module, instead of updating each one of those files separately when I make a change, can I just update the one module stored on a server or something?
I have doing something like you describe for years. You can move your VBA code to a VB6 ActiveX dll, organize it into classes, and load that dll as a reference from Excel VBA.
This is a good way to reuse non-workbook specific code. For instance, I have code that queries a mainframe. I like to call it from Excel, but the details of the connection and how data is passed are contained in a dll that I can load from Excel, VB6, Word, .NET, wherever. I have a similar dll for reading data from AutoCAD drawings, one for interfacing with a product DB on a MySQL server, etc.
The code that remains in Excel tends to be simple formatting stuff. Say I return a variant array of strings (technically a COM SAFEARRAY) from some library that I wrote. I would then output it into Excel, maybe do a text-to-columns, and have a list of results returned to the user.
You can also pass and return more complex data structures. The beauty of VB6/COM Automation (and I didn't appreciate this until I learned to do it the harder way in VB.NET or C#) is that the data will flow in and out of your components seamlessly and all the necessary interfaces will be created for you.
The main change to your code will be replacing things like ThisWorkbook or ActiveSheet with explicit parameters like (Byval sht as Excel.Worksheet). These will be caught at compile time in VB6 (since it doesn't know what ThisWorkbook is), so you cannot overlook them; you are forced to pass an explicit reference.
I also notice that my code inside the dll becomes more paranoid if it receives a Worksheet or other Excel object as a parameter. In VBA you might have had more assurance that you were passing a good object since it was private to a given workbook. The dll does not know who is calling it, so I view the passed-in object with more suspicion (check if Nothing, sheet name, formatting clues to ensure I am using what I think I am using).
The only downside I see is that you will have to get a copy of Visual Basic 6.0. I bought mine in 1998. It is no longer available from Microsoft, but surely there is someone out there who will sell it to you. The latest service pack is SP6.
You will also have to become familiar with "regsvr32" and "regsvr32 /u" to deal with the "ActiveX can't create component" errors as you open your workbooks on various computers. I just publish my dlls to a mapped network drive and re-register them on the user's computers whenever there is a significant change. Obviously this is a intranet/single company solution. Publishing the updated versions is much more of a pain the farther you are distributed.
Not sure if this would satisfy your needs, but you could create your common module as an "add-in" and so install it so that all files that you open in the same instance of excel would have access to the add-in code.
It would not be my recommended way of doing it because I would be worried about suitable testing of all the excel files that use it, when you make a change, plus the added complexity of getting users to install your add-in (this may not be an issue for you). I have a "developersToolkit" module I use across 8 different Workbooks, but I import the module into each workbook so its stand alone and I can also test changes for compatibility with each of the 8 workbooks.
Part of my job right now is to build some dynamic functionalities into Microsoft Office documents. The only means I've found to do this is through VBA - and thus, the VBA editor which comes built in to Office docs.
The VBA editor is awful. It's missing a million different functionalities that modern development environments need to support. But the worst part is that I'm a hard-core Vim lover, and the VBA editor is barely any better than notepad.
So: Is there any way I can effectively use Vim to do VBA programming? Short of copy-pasting my code into the VBA editor from a different window when I want to try it?
I've never used the VBA editor, but here's something I've done with MS Visual Studio. (MSVS's editor does have some nice features, but I still prefer vim for most editing.)
I open or create the source file in MSVS. I then get the full path to the file (by right-clicking on the tab and selecting "Copy Full Path"), and open the same file in vim in a different window.
I use alt-tab to bounce back and forth between vim and MSVS. When I make a change in vim, I use :w to write the change, then alt-tab back to MSVS. The MSVS editor notices that the file has changed on disk and offers to read the updated version.
Alternatively, if I change the file in MSVS, I write the file (File > Save ...), then alt-tab to vim and use :e! to read the updated file into the vim buffer.
There's no need to copy-paste the code, since both editors are operating on the same disk file. I just have to be very careful not to make changes in both vim and MSVS without writing the file to disk.
It's ugly, and it's not for everyone, but it works for me. Maybe it will work for you.
I use Cygwin, so it's actually a little more complicated; Cygwin programs, including vim, don't recognize Windows-style paths. I can do this:
vi $(cygpath 'WINDOWS_PATH')
where WINDOWS_PATH is pasted from the full path I get from MSVS. The single quotes are necessary to keep the shell from interpreting the \ characters. If you're using a Windows native vim, this step isn't necessary.
That's an interesting opinion. I used VI briefly about fifteen years ago and based on that I contend that the VBA editor is far more suited to its purpose than VI (or VIM?) would be. Is there one particular piece of functionality that it is missing from the VBA editor that precludes you effectively using it for its purpose (editing VBA)? VBA has not been enhanced for many many years, but the fact is it can't be killed off because everyone finds it so easy to use.
If you wish you can write some piece of code in your preferred language that manipulates your word document via COM objects (if it supports that). Then you can call your external piece of code from a simple stub within your Word document. You need to get around some security constraints though in your Word document.
For example I could write some code in VBScript or VBA or Powershell or .Net that manipulates a word doc. I can call that from a small piece of VBA (that might be attached to a button or something in the standard word toolbar)
I am working on this project (an AddIn) for Excel 2007. It use aspose cells for this purpose as well as C#. I didn't write the code, but took over the project from somebody else. So I am still learning the excel portion as I know only C#. I did notice there is some code for creating workbook/worksheet. How do I know if its written in VB or VBA so that i can learn it?The file extensions are like .cls, .frm, .bas etc. I am using Visual Studio 2010.
Also the workbook/worksheets are password protected after creation.When I tried to change the password through VB/VBA code(whatever it is), it creates errors during build such as identifier expected, declaration expected etc.But when I undid the changes, all the errors disappeared. The only change I made was change the string that stored the password. (string "password" was changed to "password1") and suddenly other lines of code started getting errors.The errors are identifier expected, declaration expected etc. and that doesn't make sense to me. So i had to change the password through C# after it was password protected through VB/VBA.
Also, how do I debug VB/VBA code. I tried putting breakpoints through VS2010 , but it's not hitting them when I run the project.I am sure the worksheets are created using VB/VBA and so its getting inside those codes, but cant debug.
I open the AddIn using Visual Studio2010 and that's how work with the code,both C# and VB/VBA.I dont modify anything using Alt+F11.
.cls, .frm, and .bas are VBA files. I suggest you try debugging the code in Excel using the VBE (the Visual Studio equivillent for VBA). It's quite easy to debug in that enviornment.
The difference between VB (VB.Net) and VBA is quite big. That being said, VBA is a rather simple language, so if you have managed to grasp C#, I'm sure you can learn VBA with a little bit of reading and experimentation.
If you have a question about the actual code, I suggest you post it as a seperate question. :)
How do you get to the code? If through Excel by using the VBE, for instance by pressing Alt+F11, then it is VBA. If you open a project, then it is probably VB (VB6). Note that VB.NET use the .vb extension. Moreover, since VBA is a subset of VB then if you export VBA from a VBE project, the exported files default to their VB cousin's file extensions.
We really need to know how you get to the code.
Like I said, VBA (6.x) is a subset of VB6. The Excel part is just an object model that uses VBA. VB.NET is different and is not the case because the file extensions are wrong.
Therefore, concentrate on learning on VBA and Excel 2007 Object Model
MSDN Search for VBA at http://social.msdn.microsoft.com/Search/en-US?query=VBA&ac=8.
Creating VBA Macros to Manipulate Worksheets in Excel 2007 at http://msdn.microsoft.com/en-us/library/dd553655(v=office.12).aspx.
This article VBA Interoperability with Visual Studio Tools for the Office System (3.0) at http://msdn.microsoft.com/en-us/library/bb931201(v=office.12).aspx should help.