Run Code after any VBA (MS Access) error - vba

I am developing for an error logging application for data centers that use MS Access. In the test environment there are +- 200 MS Access MDBs. I at the point where my application will run on one MDB perfectly fine. I have achieved the MDB specific functionality by inserting code into each and every On_Error function, and by wrapping any function in such an On_Error catch statement.
My problem is that to alter each and every database and each and every function in each of those would be redundant.
Is there anyway to add some code/module to each MDB just in one place that would be run on any error? (Alternatively is there a way to open and alter the VBA behind the forms programmically, even if it involves ridiculous string-manipulation.)

You can link a centralized library mdb/mde as per DaveMac's link, but error handling ("On Error ...") needs to be local in each and every function. That's just how it is in VBA.
Using the VBIDE object library, you can access and modify VBA code in other databases. See
Import lines of code
https://christopherjmcclellan.wordpress.com/2014/11/06/meta-programming-in-vba-the-vbide-and-why-documentation-is-important/
It will be quite a bit of work though, I think. I only ever used this to copy modules from one (Word) file to a couple of other files, and it took some time to get it right.
Note that using http://www.mztools.com/v3/mztools3.aspx you can add a customizable error handler to a function with one click (or shortcut).
Doing it with VBIDE might not be the faster way in the end, but surely more fun. :)

Related

Dealing with SAS Sessions while running a Stored Process

Currently I am trying to run a SAS program using VBA. Using the SAS Add-In For Microsoft Office, I created a stored process that contains a generic code that creates a dummy table. Inside SAS EG, I am able to run the Stored Process normally, and also inside the Excel environment, using the InsertStoredProcess function of the SASExcelAddIn object. Regardless of the environment used to run my Stored Process, the behavior of the SAS Sessions are the same: one session is created when I start to run and another one is created during the process. However, that is where my problem comes. When the process finishes, I continue with the two sessions as active, and every time I try to run again my Stored Process, one new session is created over the ones that already existed. The sessions close only when I manually disconnect from the SAS Server I'm connected or when I close the Excel. Since my organization allows only three concurrent sessions, this is becoming a big problem for me.
I already tried to use the ABORT macro function inside my code, the rc=stpsrv_session('delete') command and delete the Stored Process from the Excel worksheet, and none of them solved my problem.
Any ideas of what I'm missing here? Is there a way to end the SAS Session after the Stored Process ends?
First of all, you shouldn't use VBA to do any of this. If in Office products, use VSTO and C#. I am in the throes of converting thousands of lines of VBA to C#/VSTO. VBA is very obsolete which is why the code is being converted.
Second, EG is built using C# so it is more natural to use. You can even create custom tasks using C# in EG.
You need to close out your sessions after they are started. See this post at SAS for how to close out your sessions in VBA: https://communities.sas.com/t5/SAS-Enterprise-Guide/Calling-SAS-through-VBA/td-p/79673
Again, you should stop using VBA and switch over. It will be much easier. VSTO is free and is made to interact with Office. Use Visual Studio to create your project. The C# code for working with SAS can be found using any of Chris Hemendinger's post (SAS community manager) or you can refer to links on my github repos here: https://github.com/savian-net

How to get rid of a ms-access "ghost modules" which are created with "Transferdatabase"

We got a ms-access database we use as a framework.
So we use a function we call "Update framework" where we transfer some modules from the framework to the target database with this code
db_fw.DoCmd.DeleteObject xxx_obj_t, rec_ref!REFR_NAME
...
db_fw.DoCmd.TransferDatabase acImport, "Microsoft Access", dCopiedFrameworkFile, xxx_obj_t, rec_ref!REFR_NAME, rec_ref!REFR_NAME
This works fine about 99% of the times.
But since some time I found out that sometimes - very rarely - instead of replacing the module, ms-access creates a module with the same name but a number at the end.
e.g. Module "ICanAfterStart" is not visible anymore. Instead a module "ICanAfterStart1" is visible. All the code works as before. So "implements ICanAfterStart" still compiles and seems to work.
When I update the framework once again, a module named: "ICanAfterStart2" (and so on) is created.
Until now this only happened with interface modules which we always name with an "I" at the beginning.
I already tried:
decompile the database
compress & repair the database
Application.SaveAsText; delete all visible "ICanAfterStart*" modules and try to use Application.LoadFromText to reimport the module. But Application.LoadFromText results in an "run-time-error 2950: reserved error"
I created a new module called "ICanAfterStart" where I copied the code as text into. But after the next framework update "ICanAfterStart" is not visible anymore and "ICanAfterStart1" is there.
As a "solution" for the moment I try backup files until I find one which does not have this error. As this is a lot of work and I have to recreate all the code I wrote until then, this is a bad solution.
So, does anyone know what the problem is and got a more practical solution for me?
You have to delete the original ones and the copie modules (ICanAfterStart, ICanAfterStart1, ICanAfterStart2,...) with the Project Explorer in the VBA-Development-Enviroment and reinport them.

What can make a macro run well when executed directly but fail when called from a form?

I have several macros I created in Access. The macro works well when executing it by double clicking on its name.
Recently, I have created several forms to act as a GUI for the database, with buttons that when click call the macros and execute them.
Most of the problems occur at the action EmailDatabaseObject. Before sending the mail, the macros delete a table and import data into it.
I insist, when double clicking them they work perfectly.
The two errors that have appeared so far are 3066 and 2306. They not always appear.
The two errors are very different - the first indicates that there is a query that isn't returning any data.
The second indicates that there are too many rows being returned to allow the creation of a output file. e.g over 16,000 if it's exporting to an old version of excel.
As these are in macro's they are pretty difficult to fault find - why don't you covert them to VBA and post up the code. Or maybe at least post up the number of records and or query SQL to see what's happening.

SSIS Package Not Populating Any Results

I'm trying to load data from my database into an excel file of a standard template. The package is ready and it's running, throwing a couple of validation warnings stating that truncation may occur because my template has fields of a slightly smaller size than the DB columns i've matched them to.
However, no data is getting populated to my excel sheet.
No errors are reported, and when I click preview for my OLE DB source, it's showing me rows of results. None of these are getting populated into my excel sheet though.
You should first make sure that you have data coming through the pipeline. In the arrow connecting your Source task to Destination task (I'm assuming you don't have any steps between), double click and you'll open the Data Flow Path Editor. Click on Data Viewer, then Add and click OK. That will allow you to see what is moving through the pipeline.
Something to consider with Excel is that is prefers Unicode data types to Non-Unicode. Chances are you have a database collation that is Non-Unicode, so you might have to convert the values in a Data Conversion task.
ALSO, you may need to force the package to execute in 32bit runtime. The VS application develops in a 32bit environment, so the drivers you have visibility to are 32bit. If there is no 64bit equivalent, it will break when you try and run the package. Right click on your project and click Properties and under the Debug menu you'll need to change the setting Run64BitRuntime to FALSE.
you dont provide much informatiom. Add a Data View between your source and your excel destination to see if data is passing through. Do do it, just double click the data flow path, select data view and then add a grid.
Run your app. If you see data, provide more details so we can help you
Couple of questions that may lead to an answer:
Have you checked that data is actually passed through the SSIS package at run time?
Have you double checked your mapping?
Try converting within the package so you don't have the truncation issue
If you add some more details about what you're running, I may be able do give a better answer.
EDIT: Considering what you wrote in your comment, I'd defiantly try the third option. Let us know if this doesn't solve the problem.
Just as an assist for anyone else running into this - I had a similar issue and beat my head against the wall for a long time before I found out what was going on. My export WAS writing data to the file, but because I was using a template file as the destination, and that template file had previous data that had been deleted, the process was appending the data BELOW the previously used rows. So, I was writing out three lines of data, for example, but the data did not start until row 344!!!
The solution was to select the entire spreadsheet in my template file, and delete every bit of it so that I had a completely clean sheet to begin with. I then added my header lines to the clean sheet and saved it. Then I ran the data flow task and...ta-daa!!! Perfect export!
Hopefully this will help some poor soul who runs into this same issue in the future!

Microsoft Access can't save design changes because another user has the file open... but I am the only user?

Just a little background: I am using Access 2010 to create forms and VBA code in an Access 2003 format database. For some reason, Access 2007 format databases always corrupt on me when I make changes and save them with a particular group of objects, but that's for another discussion.
When writing VBA code in this Access 2003 database, any time my code breaks (via breakpoint or an unhandled error) and I make a correction, Access tells me that it can't save back to the database because another user has it open. However, I am the only user working on the database; this is a local copy of the database and it's sitting on my desktop.
The LDB file can't be deleted because Access is using it. When I first load the database, I see my machine name and "Admin" when opening the LDB in a text or hex editor. After a break, I see that plus a duplicate entry, but this time around "admin" has a lower-case "A."
Closing the database and reopening it fixes the problem but makes it needlessly cumbersome to debug my code. Anyone else encounter this issue and/or have a fix for it?
It might be helpful to know what your code is doing when this happens. Certainly that's not normal behavior. For instance, are you opening another database with New Access.Application? Are you using ADO or DAO to access records in the database with a connection string?
There are no external connections to the database at all.
It may not matter if there are external connections to the database if you are using a connection string to connect to the open database; not sure but that may be seen as an external connection... you may want to use CurrentDB for DAO, or CurrentProject.Connection as your ActiveConnection for any ADO queries.
I am assuming that this problem persists through reboots; but for the sake of argument, try closing out Access and going to the task manager to make sure you have no other instances of MSAccess.exe running. You might even try closing all Office products and/or making sure that Access is the only Office product running. I have seen some weird conflicts between Microsoft Communicator and Outlook; so it's not entirely out of the question for Access to have issues with another MS product.
You may also want to check the size of the database to make sure it's not exceeded 2GB. That causes the infamous "Invalid parameter" error; perhaps it might be causing this as well.
With no other details about how your program works, we may only be able to offer generic advice like this.
I have discovered a way to cause the problem discussed above (and thereby to correct it). Turns out if you create a database object and set it to the current database, you get this problem.
That is,
dim cdb as database
set cdb = currentdb
From this point on, you're cooked.
Instead, figure a way around this by possibly using currentdb directly or not using it at all.
This worked for me.
In your VBA Try checking that all your open Connections to the database are closed. Until the connection is open the LDB fill will be there.
Same symptom of not being able to save form or code mods after application had started. I found a workaround today! In the startup of my first form of the app, I had issued a "DAO.DBEngine.SetOption dbMaxLocksPerFile, 20000". Commenting this statement removed the problem. I did no further testing, but FYI, the DBEngine call was before any reference or attempt to use CurrentDB(). Also the current default on my Access 16 install is 9,500.
I thought I might answer here, since I stumbled upon this question while having a similar issue. Essentially, it boiled down to this: I could either edit forms, VBA, etc. or edit information in the local database (which I'm using as a cache) with currentDB. I also have a backend database, but the locking was clearly on the frontend database.
The solution ended up being weird, but stupidly simple. When the frontend starts up, I have it immediately create a connection to the backend using OpenRecordset (and similarly to you, that backend was still on my own computer for testing purposes). I tried temporarily disabling that code, and suddenly it wasn't an issue anymore. And it turns out, once I call currentDB, I can then call OpenRecordset to open the connection to the backend, and suddenly it isn't a problem anymore.
Tl;Dr: if you're calling OpenRecordset somewhere in your code to connect to a backend, be sure to call something like set db = currentDB beforehand, then everything works. (That is, probably until I publish this answer and Access then decides it doesn't want to anymore).
Why this fixed it is beyond me, someone with more knowledge can maybe answer that.
The solution:
options > current database > click enable -track name auto correct info