First, apologies for the generic title - if anyone can suggest a better one, I'd be happy to change it, but right now, I have no clue where to start.
I have a workbook utilizing a DLL to access a data provider (Bloomberg), and the requirements to get it to work correctly are quite tricky. Furthermore, deployment is a nightmare, since users might need to reference the DLL themselves.
Naturally, I first check wether the library is referenced, before testing the library itself.
Here's my code (which is working as intended) :
Public Sub TestBloomberg()
Dim ref As Object
Dim fRef As Boolean
fRef = False
For Each ref In ThisWorkbook.VBProject.References
If ref.GUID = "{4AC751C2-BB10-4702-BB05-791D93BB461C}" Then
If Not ref.IsBroken Then
fRef = True
End If
End If
Next
If fRef Then
' In separate Sub to get around User-defined type error
Call TestBloombergConnection
ElseIf Not fRef Then
' warn user about missing reference
End If
End Sub
As you can see, if the reference to the DLL is set, I proceed checking if the library works as intended (this has a lot of external factors at play, such as wether the server-application is running, the user is logged in, etc.) You can think of this as a simple ON-ERROR-GOTO-wrapped call to the dll.
I am forced to move the actual test of the functionality to another sub, as called from the second if-block. If I have no (or a broken) reference to the dll, even though the library will not be called itself, I will get a User-defined Error. If I move the exact same code to another sub, it will work perfectly.
Finally, my question:
What happens when I run my VBA code, why do I get a (i think) runtime error during compile time? How can my code be so dependend on external factors, that it can't even get to the point of failing?
What this behavior demonstrates is that VBA compiles separate subroutines separately and at different times. I had a similar situation when I was trying to resolve references on behalf of the users (solving a versioning problem, which I got to work, but then abandoned as not worth the trouble).
When you are ready to enter a subroutine, it interprets only as much as it needs to, and you could get a compile time error then, even though to you it seems like you are at run time.
The error you are actually getting is probably a 429 Automation error or something similar. You would get that if you have a broken link (dll moved, deleted, or not registered). What I remember from my project, is that I could reliably handle it if a good reference was saved in the file, or no reference was saved, but if a bad reference was saved, the code had to be isolated similar to what you found. I think I had mine in a separate class, but the principle is the same.
I think this "interpret only as much as necessary" is considered a feature of VBA. You can run a certain section of code, even if you have compile errors elsewhere. This can be useful when you only have a partially written functions or other half-finished stuff, or if you open the file on a computer without some referenced software installed. It lets at least some of the functionality still work.
Related
This is something I didn't think was even possible, but here goes. I was trying to learn how to use the Windows API in Visual Basic to use system calls, and this tutorial (yes, I had to type out the link manually to ask this question, more on that later) showed me how to use the clipboard to retrieve text that the user copied with Ctrl+C. Out of curiosity, and under the assumption that all user input is bad input, I tried pressing Print Screen and then running the code just to see what would happen. I got some error message (can't remember what) but what's very strange is, now the clipboard no longer works! Any attempt I make to paste after a cut or copy, no matter what program I'm using, either does nothing or returns an error message in the program I'm using it in. Yes, it's my fault for intentionally trying to break the code example, but let's be honest - there's no excuse for the OS to fall apart so easily. If it matters, I'm using a PC running Windows 10.
EDIT: Settings won't let me clear the clipboard, and when I try to view the clipboard history, it shows nothing is there. Unfortunately I wasn't able to screenshot the clipboard history because it closes by itself when I try to open Snipping Tool.
Sounds like you've missed a CloseClipboard(), keeping the clipboard locked since Windows thinks a program is reading to it or writing from it. This will prevent other programs from working with the clipboard, since only one program can access it at a time. If Access is still open, you can try running CloseClipboard in the immediate window, else, I recommend a reboot.
On code like this, always add an error handler that calls CloseClipboard() to prevent leaving the clipboard open if something unexpected happens. Note that when working with WinAPI, you might encounter hard crashes that may not call the error handler, so always triple-check your pointers and expect crashes and reboots.
The code you've found is also not adjusted for 64-bit use, so beware. If you've got it to work by just slapping PtrSafe on the functions, you may end up with invalid pointers which can crash Access, leaving the clipboard open and unusable.
The code you've found, while written by Microsoft, is not of particularly good quality. I recommend first checking if there's text on the clipboard using EnumClipboardFormats, then only requesting text if there actually is text on the clipboard.
Beware that using WinAPI through VBA is tough, it's not beginner stuff, especially regarding the clipboard.
Note that there's no excuse for the OS to fall apart so easily is not the attitude to have when working with WinAPI. You're directly interfacing with the OS without any of the securities that managed languages offer, and manually working with pointers. It can and will break if you do something invalid. There's a reason most people use libraries that abstract the dangerous stuff away, if you don't, all bets are off.
similar problem for me. I did not have a CloseClipboard() but when I looked in another module there was already a EmptyClipboard() so used that before the DupRec() call at each instance and no more problems with clipboard. just FYI
MS Access 2016 running on Windows 10.
I am debugging VBA changes to a MS Access application and am seeing some unexpected interactions between the VBA editor and running code. The steps are basically:
Open the application, which opens startup form.
The startup form_load instantiates an object used by other forms the user may subsequently open.
Open the VBA editor
Using the VBA editor, select a line in any code module and the instantiated objects are set to nothing.
An error is thrown when the other forms using the object are opened.
So basically, the VBA editor action has set the objects to nothing. I have added instrumenting code to confirm this.
Has anyone seen the behavior? Does anyone have thoughts about what may be happening and causing this?
Thanks in advance...
Additional information:
The code instantiating the object in the Form_Load method is:
Set musrInfo = New usrInfo
Where usrInfo is a class module containing user information.
Also, there is no problem with earlier versions of this - I have never experienced the described problem with any other MSA VBA application. The compiled version of this particular MSA file is a bit bigger than 20MB, with little in the way of data tables - only a few parameters, etc. - and more than 13MB in forms, reports, etc.
I hope this helps... Lindsay
And there's more...
- I tried this .accdb file on another PC with Win7/MSA2010 and this
behavior did not occur.
- I then tried it in a different folder on the original PC and it
did not occur.
Maybe these findings will allow a path forward, but I still wonder why this would ever happen - why would the folder choice make any difference?
This is usual behavior.
When making changes using the VBA editor, it may recompile the VB project behind your database. This can be the whole project, or parts of it, depending on the exact change.
Recompiles will clear any variables.
You can change this behaviour, by going to Tools -> Options, under the General tab. See the following screenshot.
However, even with Compile On Demand off, you will have to trigger a recompile for most changes, clearing any set variables.
For classes that need a single instance to be publicly available as long as the database is open, I recommend setting the VB_PredeclaredID to true. That will instantiate the object as soon as the database opens, or the code recompiles. See here how.
I'm new to VBA in Access. I have set up a query that uses some VBA to requery on a combo box selection. This works great however every so often Access will randomly crash.
Is there any "if error" statement I can put in my VBA code that will pop up a message rather than completely crashing?
Error handling in your application is a separate issue from Access crashing. Even if you reach the low limits of Access (https://support.office.com/en-us/article/Access-2010-specifications-1E521481-7F9A-46F7-8ED9-EA9DFF1FA854), it shouldn't be crashing, but giving you an error message. That's a bug not of your doing. I've used Access for a while, and sometimes you have to work around the bugs, as well as the limits.
Sometimes, the VBA compiler fails to get things right after you make a change. If you Cut and Paste the text of an entire Module, it seems to force the compiler to recompile that whole Module. Always use the Debug > Compile menu item to compile and check your code. Then save.
Sometimes, doing the Compact and Repair will resolve problems. In fact, you need to Compact and Repair, because it seems that the file will bloat non-stop otherwise, and it has a 2GB limit. Do a backup first, because the Compact and Repair sometimes fails, leaving you with garbage.
Magisch gave an example of error handling in VB, which is something you should do to write a robust application (see http://www.vb6.us/tutorials/error-handling).
First of all, your an ordinary error shouldn't cause access to crash. If it does, you probably need to clean up your file some, for instance by repairing or de/re compiling it.
Secondly, if you want to handle errors in a simple way you can do it roughly like this:
Public Function doStuff (myInput as Integer) as Integer
On Error GoTo Error_Handling
'something that may cause an error to occur
Exit Function 'Important so your error handling doesn't get executed every time the function runs regardless
Error_Handling:
'something that you want to happen when the error occurs
End Function
My firm's Access database has been having some serious problems recently. The errors we're getting seem like they indicate corruption -- here are the most common:
Error accessing file. Network connection may have been lost.
There was an error compiling this function.
No error, Access just crashes completely.
I've noticed that these errors only happen with a compiled database. If I decompile it, it works fine. If I take an uncompiled database and compile it, it works fine -- until the next time I try to open it. It appears that compiling the database into a .ACCDE file solves the problem, which is what I've been doing, but one person has reported that the issue returned for her, which has me very nervous.
I've tried exporting all of the objects in the database to text, starting with a brand new database, and importing them all again, but that doesn't solve the problem. Once I import all of the objects into the clean database, the problem comes back.
One last point that seems be related, but I don't understand how. The problem started right around the time that I added some class modules to the database. These class modules use the VBA Implements keyword, in an effort to clean up my code by introducing some polymorphism. I don't know why this would cause the problem, but the timing seems to indicate a relationship.
I've been searching for an explanation, but haven't found one yet. Does anyone have any suggestions?
EDIT: The database includes a few references in addition to the standard ones:
Microsoft ActiveX Data Objects 2.8
Microsoft Office 12.0
Microsoft Scripting Runtime
Microsoft VBScript Regular Expressions 5.5
Some of the things I do and use when debugging Access:
Test my app in a number of VM. You can use HyperV on Win8, VMWare or VirtualBox to set up various controlled test environments, like testing on WinXP, Win7, Win8, 32bit or 64 bits, just anything that matches the range of OS and bitness of your users.
I use vbWatchDog, a clever utility that only adds a few classes to your application (no external dependency) and allows you to trap errors at high level, and show you exactly where they happen. This is invaluable to catch and record strange errors, especially in the field.
If the issue appears isolated to one or a few users only, I would try to find out what is special about their config. If nothing seems out of place, I would completely unsintall all Office component and re-install it after scrubbing the registry for dangling keys and removing all traces of folders from the old install.
If your users do not need a complete version of Access, just use the free Access Runtime on their machine.
Make sure that you are using consistent versions of Access throughout: if you are using Access 2007, make sure your dev machine is also using that version and that all other users are also only using that version and that no components from Access 2010/2013 are present.
Try to ascertain if the crash is always happening around the same user-actions. I use a simple log file that I write to when a debugging flag is set. The log file is a simple text file that I open/write to/close everytime I log something (I don't keep it open to make sure the data is flushed to the file, otherwise when Access crashes, you may only have old data in the log file as the new one may still be in the buffer). Things I log are, for instance, sensitive function entry/exit, SQL queries that I execute from code, form open/close, etc.
As a generality, make sure your app compiles without issue (I mean when doing Debug > Compile from the IDE). Any issue at this stage must be solved.
Make absolutely sure you close all open recordsets, preferrably followed by setting their variables to Nothing. VBA is not as sensitive as it used to be about dangling references, but I found it good practice, especially when you cannot be absolutely sure that these references will be freed (especially when doing stuff at Module-level or Class-level for instance, where the scope may be longer-lived than expected).
Similarly, make sure you properly destroy any COM object you create in your classes (and subs/functions. The Class_Terminate destructor must explicitly clean up all. This is also valid when closing forms if you created COM objects (you mentioned using ADOX, scripting objects and regex). In general keeping track of created objects is paramount: make sure you explicitly free all your objects by resetting them (for instance using RemoveAll on a dictionary, then assigning their reference to Nothing.
Do not over-use On Error Resume or On Error Goto. I almost never use these except when absolutely necessary to recover from otherwise undetectable errors. Using these error trapping constructs can hide a lot of errors that would otherwise show you that something is wrong with your code. I prefer to program defensively than having to handle exceptions.
For testing, disable your error trapping to see if it isn't hiding the cause of your crashes.
Make sure that the front-end is local to the user machine, You mention they get their individual front-end from the network but I'm not sure if they run it from there or if it it copied on their local machine. At any rate, it should be local not on a remote folder.
You mention using SQL Server as a backend. Try to trace all the queries being executed. It's possible that the issue comes from communication with SQL Server, a corrupt driver, a security issue that prevents some queries from being run, a query returning unexpected data, etc. Watch the log files and event log on the server closely for strange errors, especially if they involve security.
Speaking of event log, look for the trace of the crash in the event log of your users. There may be information there, however cryptic.
If you use custom ribbon actions, make sure thy are not causing issues. I had strange problems over time with the ribbon. Log all all function calls made by the ribbon.
I have a Microsoft Word template with some code and some references, that has been working fine for months but has just started throwing up a spurious "User-defined type not defined" error whenever I open it or try to compile it.
I know it's a spurious error because I haven't made any significant changes to the code. In fact, I've rolled the code back to the last deployed version (which I know works fine) and I still get the error. I've also commented out all the code in the template and I still get the error. I've also removed and re-added all references (same error), and removed all the references and added them back, one by one, until the resultant compile errors are resolved, at which point I'm left with the spurious "User-defined type not defined" error. (I'm going to call this a UDTND error, from now, to avoid driving you all mad.) I think the error started popping up after I rebooted my PC. It only happens with this template, but I don't see how it can be anything to do with this template.
Interestingly, the error is subtly different from a genuine UDTND error in the following ways:
No code is highlighted when the error is displayed.
The dialog is titled "Microsoft Visual Basic", and contains the error message but, unlike a real UDTND error, doesn't contain the text "Compile error:";
It happens when the template is opened, not just when it's compiled (at least, I think that's different from a normal error).
I've tried Googling it but I just get a bazillion results from novice developers asking why they get this error, with responses telling them that they either need to declare the missing type, correct the spelling of the offending variable type, or add a reference to a missing library. I've been banging my head against my screen all afternoon, and that's helped about as much as all the other things I've tried (i.e. not at all). I have a feeling that this is something to do with a messed-up reference, but afaict they're all fine, and I've removed and re-added them, which I would expect to resolve that sort of problem.
Any ideas...?
Your trouble-shooting on References is sound. Once upon a time (and I don't recall the precise error) I was at the same point, and the reference ordering was the key. When you're designating References, you'll notice a "Priority" adjustment feature. Experiment with that and you may solve this.
I have had "User-defined type not defined" problem on several occasions when compiling Microsoft Visual Basic 6 (MSVB6) code that was compiling without a problem earlier. It seems to happen after I have had a long coding session without rebooting the computer. As you can guess, I have been using Microsoft operating systems. I currently am using Windows XP. Rebooting the computer usually fixes the problem as it so often does on Microsoft operating systems.
I have read that fully qualifying declarations also can help, e.g., "Dim oBar as Foo.Bar" instead of "Dim oBar as Bar". I have not tried this approach however.
I had a very similar problem.
My problem appeared (I think) just after I made a Search and Replace that I canceled (Ctrl+Z). There was not highligting of the problem, only the ""User-defined type not defined" error message when I compiled.
I tried:
1) restarting computer
2) changing reference ordering
3) removing functions/procedures, modules one at a time.
Didn't work. My project was written in Excel VBA and here was the solution I found.
THE SOLUTION:
I opened a new Excel file and opened the Visual Basic Editor. I then copied all Forms, Modules, and Class Modules one by one into the new file. I then Copied the Control Objects (3 Commandbuttons) from the old sheet into the new one. Now the new file was identical to the old project - only the ""User-defined type not defined" had gone and problem was solved.
Yea references would be the first step in troubleshooting this problem as already stated, but failing that id start commenting out the code in any event procedures running at start up (my experience is only with Access VBA though)
I had the same problem with Excel 2013.
It started when I did a search and replace on the name of a Custom Class.
I changed the name of the Class after I did the search and replace on all references to it and the spurious error started immediately after that.
I reverted to an earlier version ad confirmed that the problem was not there and then did the same search and replace and re-name and got the exact same behaviour again.
The Custom Class that I changed the name of only had one consumer and it was also a custom class.
I exported, removed and re-loaded the sole consumer class and the problem was fixed.
Check out this link for a Microsoft bug that might be related.
TLDR:
The reference to a package/addin/whatever probably needs to be re-referenced. Check Tools -> References in the Menu.
Also it appears that if you install Microsoft Security Advisory 960715, that certain controls are killed. There are fixes which may or may not work for you. A good article is on this blog:
VSOD Blog