joyfullservice / msaccess-vcs-addin

Synchronize your Access Forms, Macros, Modules, Queries, Reports, and more with a version control system.
Other
215 stars 40 forks source link

Module objects need to be saved after importing #236

Closed joyfullservice closed 3 years ago

joyfullservice commented 3 years ago

When importing standard and class modules through VBE, the corresponding Access objects are not created until the compile and save command is issued after the build. This causes problems if Access properties relating to these modules are imported at the same time. (Such as a custom object description or hidden flag.)

This can be replicated using the Testing.accdb database, and should be resolved before the 3.4 release.

hecon5 commented 3 years ago

Also, I have noticed classes exported from pre 3.4.x versions do not (always??) import as classes, especially if they still have a .bas extension. I'll try to upload a sample class later that exhibits the behavior.

hecon5 commented 3 years ago

Update: this appears to work after I removed a rouge commit! Huzzah! But like you mentioned, the classes prompt me to save upon building; so we'll probably need to address this.

joyfullservice commented 3 years ago

I am not seeing this issue with the latest dev build... let me know if you are still seeing issues on your end.

hecon5 commented 3 years ago

Still doing it for me; trying to figure out where/why.

joyfullservice commented 3 years ago

The DoCmd.RunCmd [compile and save all modules] is what should be saving all the modules for you. You could try breaking at that point and confirming that your project will compile.

hecon5 commented 3 years ago

It does; as soon as I click save, it asks if I want to save the modules, then takes me through numerous prompts to save each module/class separately. All I have to do is click "save" and the name is correct. I think it has to do with a property error (#197) that is throwing an error early on and not clearing properly.

hecon5 commented 3 years ago

Even after a manual DoCmd.RunCmd [compile and save all modules], I'm presented with a save dialog. Project compiles just fine. image

joyfullservice commented 3 years ago

Does this happen when building the Testing database?

hecon5 commented 3 years ago

Just checked, and yes, it does!

hecon5 commented 3 years ago

Does not happen when building the VCS, though, which is interesting.

joyfullservice commented 3 years ago

I will see if I can test this again on my end when I get back to my computer.

hecon5 commented 3 years ago

See #226, I think they're related to this. After implementing PR #244, it seems to work ok; will do some more testing.

hecon5 commented 3 years ago

Still being prompted to save the class/modules in certain circumstances. If I save them, they save ok, and I can close/reopen and they appear to function.

  1. If a form has a late-bound datasource, and a field is called from the VBA, but doesn't exist (yet, because the table isn't linked yet), it will prompt.
  2. If the VBE doesn't compile for some reason.

Which makes me wonder: should we run docmd.RunCommand acCmdSaveAllModules first, and then DoCmd.RunCommand acCmdCompileAndSaveAllModules, so that preferentially they're saved, but then compile them?

This avoids the popup, and compiles them when possible, but doesn't introduce odd behavior that doesn't indicate /why/? If there was a prompt that stated there's something blocking them from compiling, then that'd be different, but seems to me we'd want the prompt to not be there when it's caused by something totally unrelated.

hecon5 commented 3 years ago

Never mind; that doesn't work. Get error "Error 2046: The command or action 'SaveAllModules' isn't available now. Source: modImportExport.Build" when trying to save them.

Out of curiosity, modules are imported last, is there a way to import them first, before other items? I see you moved the Module down in import order in 86e2b41, but it's not clear why. Especially if your forms use classes in them, I noticed some odd behavior. I'll toy around with that and see what happens.

joyfullservice commented 3 years ago

I see you moved the Module down in import order in 86e2b41, but it's not clear why.

Great question. I did this because it seemed like the code modules needed to be compiled and saved immediately after import, and code modules may contain early-bound references to forms or reports. (I.e. Form_frmMain.txtVersion) This wouldn't be able to compile without the form object already in the database.

But you bring up a good point that you can also have the opposite issue, where forms and reports may reference functions and classes that have not yet been imported either.

Added to this challenge is that when importing code modules through VBE, (which is needed to support hidden properties) they are created on the VBE side, but do not actually exist in the database till they are saved using acCmdCompileAndSaveAllModules.

One approach which would probably work (although I don't really like it) would be to import the modules twice. First through LoadFromText which would create the database object and avoid the save issue, and then a second time through VBE to bring in any hidden VBE properties. I suppose we could even scan the incoming source file and only do the VBE import if it contains hidden VBE properties which are not supported in LoadFromText, but that seems more complex and potentially risky because we have to try to determine whether or not hidden properties or attributes exist in the code module/class.

If we can solve it through the correct sequence of import and save operations, that seems like it would be the ideal solution, but we will just have to do some testing to see what will work across the various scenarios.

hecon5 commented 3 years ago

Hmm. I'll toy around with this some.

I think the "correct" way to deal with this is to fix late-bound name recall issues that were inherited, and instead use either ! or refer to the control, and / or remove directly calling fields that exist but not always.

Of course, this means I have to change things, and I don't like that ;)

hecon5 commented 3 years ago

Question: is there a way (that you know of) to detect if a recently VBE imported module is "in" Access, especially after DoCmd.RunCommand acCmdCompileAndSaveAllModules? If we could detect that it didn't compile, we could then handle those cases, and if it loads fine, we needn't do anything.

Effectively, I'm looking to hijack the Save Changes Dialog that pops up after building when you close/reopen Access, so users don't see that. Other than that, I think that's the only limiting factor to deploying 3.4.x.

joyfullservice commented 3 years ago

You could check the CurrentProject.AllModules collection... I was also thinking of testing DoCmd.Save on the module to see if that would work, but I just haven't had the time to do further testing on it.

hecon5 commented 3 years ago

docmd.RunCommand acCmdSaveAllModules will encounter an error, at least it has whenever I added it to the end.

joyfullservice commented 3 years ago

I think the underlying problem here was that you need to ensure that the VBE.ActiveVBProject is set to the current database VBProject before running DoCmd.RunCommand acCmdCompileAndSaveAllModules. After adding a line of code to enforce this, it is working great for me on the testing database.

@hecon5 and @A9G-Data-Droid - Does this resolve the module import issue with your projects? If so, we may be able to keep this simpler approach of exclusively importing modules through VBE rather than having to take the hybrid approach described above.

hecon5 commented 3 years ago

Still getting a nag to save modules/classes.

Note that this particular version has an error where the code can't compile (due to missing field on a backend table). Since I think this is a decently common occurance, any thoughts on how best to handle this?

Best way I think is to not directly call fields on tables that may disappear, obviously, but since this "used" to work* previously, perhaps we should take a different tack?

joyfullservice commented 3 years ago

I think this comes down to the following key question:

Should we should support the full build of a non-compiling database project?

My leaning is that yes, we probably should support this, for a couple reasons.

Based on this, I think we should go ahead and shift to the hybrid approach of using LoadFromText to load the modules, then overlay the code through VBE only if attributes are detected in the source code. This may even allow us to use the DoCmd.Save on the modules since Access will be able to see the module objects.

Let me know if anyone has additional input on this, but I think I will start heading that direction...

hecon5 commented 3 years ago

I think this is the right approach. While it will cost compile time, I think it will in the end save a huge amount of headache for users that are just starting out, or users that had a buildable version (if not compliable). To me, I often find version control most useful especially when it won't compile, because I can say "hey, this isn't working, can someone else see why" in my dev team.

Like I mentioned earlier, I'm at 200+ seconds compile time due to table linking alone, this won't break my stride at all, even if it adds a second or two per module.

joyfullservice commented 3 years ago

In the most recent update, I took the approach of importing a "stub" module or class to create the object on the database side using LoadFromText(), then use VBE to replace the code module with the one loaded from the source file. This allows us to ensure that the object has been fully created in Microsoft Access (avoiding the save-as prompt) then load the VBA code through VBE to support hidden attributes. This also allows us to bring in non-compiling code.

hecon5 commented 3 years ago

Will run this through, one moment

joyfullservice commented 3 years ago

It still has the code to compile and save the modules, so you can feel free to try commenting that out and see how it handles non-compiling code. I didn't have a chance to work through that aspect yet...

hecon5 commented 3 years ago

It appears to be significantly improved! Modules saved and I didn't get a prompt. I did get a prompt for ?some? classes, but not all, and all I had to do was to hit enter a bunch (name and the like were automatically filled out).

To me, that's acceptable.

joyfullservice commented 3 years ago

Doing more testing on this, but running into an issue the first time I attempt to save a module object.

image

hecon5 commented 3 years ago

Weird, I did not run into that...

joyfullservice commented 3 years ago

It relates to some code I am adding that runs DoCmd.Save acModule, strName after importing the stub, and after updating the VBE. (Otherwise the new objects still don't show up on the Access side.)

hecon5 commented 3 years ago

Does this mean you get an error the first time, but the second it works? I wonder if this means we should ignore the first error (possibly because it doesn't exist yet?), and then the second if there's still an error then can continue.

joyfullservice commented 3 years ago

I think I might have finally figured it out... The DoCmd.Save acModule may/will fail if the VBE.ActiveVBProject is the current database. If you switch the active VBE project to the CodeDB project, then saving the module works.

Set VBE.ActiveVBProject = GetCodeVBProject

Now I just need to clean things up and remove the test code. I will let you know when this is ready, and you can give it a whirl...

joyfullservice commented 3 years ago

@hecon5 - Okay, give this a try now. Using the testing database, I was able to import code with a compile error and it fully imported everything. Obviously it couldn't run the AfterBuild function due to the compiler error, but it was able to successfully import all the objects and properties.

While it does seem pretty complex for importing code modules, it seems that all of these complexities are necessary to successfully achieve the goal of importing non-compiling code with hidden attributes. For future reference, here are a few notes that I observed while working through this:

hecon5 commented 3 years ago

This appears to work for me, no prompts upon close; opens up fine again.

joyfullservice commented 3 years ago

It looks like this issue is back when trying to build the add-in from source. (Works fine when building the testing database.) Doing some troubleshooting now to see if I can figure out why we are unable to build the add-in...

joyfullservice commented 3 years ago

Well, I feel like I have come full circle on some of this, but in my testing this afternoon I made a couple important observations.

This allows us to go back to the simpler approach of importing directly through VBE and saving each object as it is imported. After making these changes I was able to successfully build both the testing database and the add-in.

@hecon5 and @A9G-Data-Droid - Would you be able to make sure this works well in your environments? It seems to have resolved the problem for me, but I wanted to double-check before rolling out the public release. 😄 I have attached a copy of the pre-release v3.4.15 just in case you have any issues with older dev builds.

Version_Control_v3.4.15.zip

hecon5 commented 3 years ago

Will check this shortly. VCS Built ok for me; long project compiling now

hecon5 commented 3 years ago

Rebuilt ok, far as I can tell, it functioned...and, it didn't prompt me to save anything, either! This was on my "non-compiling" version.

joyfullservice commented 3 years ago

Rebuilt ok, far as I can tell, it functioned...and, it didn't prompt me to save anything, either! This was on my "non-compiling" version.

Awesome!! I am thinking we should be pretty much ready to go with pushing out the release then. Thanks again for all your help on the testing side. I feel a lot better with pushing it out after resolving the save-as prompt and non-compiling code issues. This should make the tool much more robust out in production.