Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Module objects need to be saved after importing #236

Closed
joyfullservice opened this issue Jun 8, 2021 · 39 comments
Closed

Module objects need to be saved after importing #236

joyfullservice opened this issue Jun 8, 2021 · 39 comments
Assignees
Milestone

Comments

@joyfullservice
Copy link
Owner

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.

@joyfullservice joyfullservice added this to the Release 3.4.0 milestone Jun 8, 2021
joyfullservice added a commit that referenced this issue Jun 8, 2021
Modules need to be saved before other properties can be added, such as custom descriptions and hidden attributes. Fixes #236
@hecon5
Copy link
Contributor

hecon5 commented Jun 9, 2021

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
Copy link
Contributor

hecon5 commented Jun 9, 2021

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
Copy link
Owner Author

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

@hecon5
Copy link
Contributor

hecon5 commented Jun 17, 2021

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

@joyfullservice
Copy link
Owner Author

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
Copy link
Contributor

hecon5 commented Jun 17, 2021

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
Copy link
Contributor

hecon5 commented Jun 17, 2021

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

@joyfullservice
Copy link
Owner Author

Does this happen when building the Testing database?

@hecon5
Copy link
Contributor

hecon5 commented Jun 17, 2021

Just checked, and yes, it does!

@hecon5
Copy link
Contributor

hecon5 commented Jun 17, 2021

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

@joyfullservice
Copy link
Owner Author

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

@hecon5
Copy link
Contributor

hecon5 commented Jun 17, 2021

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

@hecon5
Copy link
Contributor

hecon5 commented Jun 21, 2021

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
Copy link
Contributor

hecon5 commented Jun 21, 2021

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
Copy link
Owner Author

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
Copy link
Contributor

hecon5 commented Jun 21, 2021

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
Copy link
Contributor

hecon5 commented Jun 23, 2021

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
Copy link
Owner Author

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
Copy link
Contributor

hecon5 commented Jun 23, 2021

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

hecon5 referenced this issue in hecon5/msaccess-vcs-integration Jun 23, 2021
joyfullservice added a commit that referenced this issue Jul 10, 2021
If we don't specify the active project, we might be compiling and saving the add-in instead of the current database. This can cause the modules not to be listed as Access objects, causing further issues in the build process. This was a major breakthrough in resolving #236
@joyfullservice
Copy link
Owner Author

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
Copy link
Contributor

hecon5 commented Jul 12, 2021

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?

  • work meaning the prompt wasn't there.

@joyfullservice
Copy link
Owner Author

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.

  • Existing databases may have compile issues, but this should not be a blocker for exporting source code. If you are trying to fix an existing problem, you might start with a VCS dump so that you can track your changes from the very start, vs. having to get a compiling version working first.
  • Merged source code from multiple developers may very well contain VBA compiler issues that should be resolved after build. It doesn't make sense to have the build process fail or be incomplete if the code issues can only be fully resolved after a build.

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...

@joyfullservice joyfullservice self-assigned this Jul 12, 2021
@hecon5
Copy link
Contributor

hecon5 commented Jul 12, 2021

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 added a commit that referenced this issue Jul 13, 2021
This takes the approach of loading an initial stub as a class or module through LoadFromText so that the object is created on the Access side, then uses VBE to replace the actual code module so that it can support hidden VBE properties. #236
@joyfullservice joyfullservice added the pending resolved Possibly resolved, needs testing or confirmation label Jul 13, 2021
@joyfullservice
Copy link
Owner Author

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
Copy link
Contributor

hecon5 commented Jul 13, 2021

Will run this through, one moment

@joyfullservice
Copy link
Owner Author

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
Copy link
Contributor

hecon5 commented Jul 13, 2021

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 joyfullservice removed the pending resolved Possibly resolved, needs testing or confirmation label Jul 14, 2021
@joyfullservice
Copy link
Owner Author

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

image

@hecon5
Copy link
Contributor

hecon5 commented Jul 14, 2021

Weird, I did not run into that...

@joyfullservice
Copy link
Owner Author

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
Copy link
Contributor

hecon5 commented Jul 14, 2021

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
Copy link
Owner Author

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 added a commit that referenced this issue Jul 14, 2021
Reworked the module import to be able to import code that has compile issues, while still saving the code modules. This ended up being more difficult than I expected, but seems to work well now. #236
@joyfullservice
Copy link
Owner Author

joyfullservice commented Jul 14, 2021

@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:

  • SaveAndCompileAllModules should be avoided because it will fail if the code cannot compile. This can easily be the case when merging work at the source code level.
  • In order to set certain attributes such as Access's hidden property or object description, the module has to be saved on the database side, not just created in VBE.
  • To save a module on the Access side, it is necessary to import it using the LoadFromText. I do this in the add-in using a stub module that will later be replaced on the VBE side. It turns out that this was not necessary. Loading through VBE works just fine, including non-compiling code.
  • To include hidden attributes (such as default members, property descriptions, etc...), the module has to be loaded from a file using VBE.
  • All standard and class modules (but not object modules) are exported using VBE (rather than SaveAsText) to include the hidden attributes.
  • After importing or modifying (or importing) a standard or class module, it should be saved using DoCmd.Save This will help prevent a save prompt after import.
  • Running DoCmd.Save acModule, strName will fail if the active VBProject is the one for the current database. Before saving modules, you have to set the active project to the one from the CodeProject (add-in). Actually, you do want to set the active VB Project to the current database so you save the correct module. (The other errors probably stemmed from a VBComponent object reference that was no longer valid.)
  • You cannot save the code modules during an iteration of the VBComponents, presumably because VBE is reloaded after the Access database level save. Instead you collect the names on the iteration, then run a second loop to save the modules.

@joyfullservice joyfullservice added the pending resolved Possibly resolved, needs testing or confirmation label Jul 14, 2021
@hecon5
Copy link
Contributor

hecon5 commented Jul 14, 2021

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

@joyfullservice joyfullservice removed the pending resolved Possibly resolved, needs testing or confirmation label Jul 14, 2021
@joyfullservice
Copy link
Owner Author

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 added a commit that referenced this issue Jul 20, 2021
I am now able to successfully build the test database and the add-in from source. Fixes #236
@joyfullservice
Copy link
Owner Author

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.

  • Setting an object reference to the VBComponent for the class is not a good idea because this object may become unstable/invalid if the module is saved through Access. (DoCmd.Save) I have changed this to use the AccessObject for the module/class which should be much more stable.
  • Loading a "stub" for the module is unnecessary because the object is deleted anyway when we import using VBE. And the object is created on the Access side after importing through VBE and saving it.

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

@joyfullservice joyfullservice added the pending resolved Possibly resolved, needs testing or confirmation label Jul 20, 2021
@hecon5
Copy link
Contributor

hecon5 commented Jul 21, 2021

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

@hecon5
Copy link
Contributor

hecon5 commented Jul 21, 2021

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
Copy link
Owner Author

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.

@joyfullservice joyfullservice removed the pending resolved Possibly resolved, needs testing or confirmation label Jul 21, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants