joyfullservice / msaccess-vcs-addin

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

PrtMip Scrubbed from forms on export (discrepancy between joyfullservice and 'head' export) #115

Closed hecon5 closed 3 years ago

hecon5 commented 3 years ago

So, I FINALLY got this addin to work (thanks to RubberDuck VBA reference manager!).

I've begun the process of verifying exports from the two tools, and I've noticed that "

PrtMip = Begin  
...(key)...
End

Seems to be scrubbed during your sanitize routine. What is this attribute/value for, and should I ignore it?

(also, holy smokes, that's a lot faster!)

joyfullservice commented 3 years ago

The PrtMip section is a binary representation of the print margin settings. Since my version records this in a human-readable json file, it makes VCS a little cleaner to remove this from forms and reports.

Before: image

After: image

Importing a form or report from a text file without the PrtMip section works without errors, but in the latest version of the code I actually convert the json file back to the binary section and insert it in the text file just before import. This gives you the advantages of readable margin details to store in VCS, and still a very fast export/import process that is true to the original.

Hope that helps!

joyfullservice commented 3 years ago

Also, it sounds like you were initially having some difficulty getting the add-in to work... Let me know if there is something that should be improved with the documentation or installer process. The goal is for the add-in to be very simple to install and use, so feedback and contributions to that end are certainly welcome! 😄

hecon5 commented 3 years ago

Because I have a rather massive database, and I don't want my reviewers to yell at me (yet!), is there an option to select if I can turn this on/off?

I really like the human-readableness of it, but as we move into this, I'd rather not have to commit a ton of changes that will have to be rubber stamped to pass muster (at first).

If not...I'll deal. The speed is really nice.

As to the reference: that was a random click-happy find. I saw you'd updated the install mechanism, so thought I'd give it a try. It installed (and showed up where it should for a references in my Appdir/roaming/...), and showed in the "Addons dropdown"

image

, but Access said I was not able to open it.

Trick was to run your installer, then go to RubberDuck> AddRemove References, and it was shown in "Projects". Then I moved it over, and POOF!

image

Since I have some other references that are programmatically loaded for developers, I think getting this to load via that mechanism will be a simple one line add to my initialization routine. This will make it autoload, and if it dumps out for whatever reason, the reference load routine will snag it. When I get around to it, I'll write up some code that could be included in the referencing database's load routine to do this for me/others.

joyfullservice commented 3 years ago

@hecon5 - Thanks for filling in the additional details. In the past I used to add a copy of this add-in to the project folder, and link it as a reference, but after redoing the installer as a user-level add-in, it makes the tool available to any open database without needing to deal with any of the references or linking code.

If you are doing other work with development integration/pipelines, you might find the following links of interest: #88, #51

hecon5 commented 3 years ago

Thanks; I've commented there.

For now: since there doesn't appear to be an easy way to turn on/off the json file, we'll need to make some decisions on whether we want to add another 150 files to version control (json prtmip) or how to handle that. If there isn't and adding the capability would be is not planned, then you can close this issue. If there is, let me know and I'll use it (and then close the issue).

Otherwise, can leave this open. Perhaps I'll get around to it and add it in or someone else will.

joyfullservice commented 3 years ago

If you are trying to avoid the report .json files entirely, you can use the existing option to not save print settings:

image

However, this will not save any print/margin settings for reports, so if you later build them from source, they will come in with the default printer and print settings.

hecon5 commented 3 years ago

Hmm, I don't get a *.json file for forms in the output file (in either case). The PrtMip is scrubbed, though. (I do get one in the reports folders).

joyfullservice commented 3 years ago

Hmm, I don't get a *.json file for forms in the output file (in either case). The PrtMip is scrubbed, though. (I do get one in the reports folders).

Forms can store the same margin and print settings that reports do, although I would expect that in real life very few people actually use a custom printer assignment or margins on a form object...

At present this gets scrubbed because forms go through the same sanitize function as reports. I figured I would wait till someone actually needed print settings on a form before adding in the code to save those settings. But maybe it would be better to just leave the PrtMip untouched on the form objects, and address that down the road when we have an actual use case for saving these margin/print settings in a human-readable way for the form objects. 🤔

hecon5 commented 3 years ago

Since I inherited ours, I've found several Forms that are directly printed vice Reports, so I guess I'm special again. 🤔

I think (personally), if the same routine processes the form and report, that the outputs should match; especially since the goal is to recreate the same database upon import that you exported, this would ensure you don't inadvertently dump print configs.

Initial thoughts:

  1. Forms and Reports both output .json files (handle identically).
  2. Forms leave the PrtMip block alone as you suggested.
  3. Have this be part of an "aggressive sanitize" option for Forms. This obviously has the downside that it will plague reports (that have the .json separated), and may (will) cause collisions, so that'd have to be handled.
  4. Add a config option to handle form printing specially (I, personally, don't love this, as it adds the certainty to discover users didn't set it and now have lost data).

My Preference:

The more legible the code is to review, the better reviews are, and the less likely I'll approve a pull request from someone that changed print margins (or any setting) without knowing that's happening. I already have enough of a headache figuring out what changed on Conditional Formatting, the fewer the better (though, I am slowly removing statically defined formatting and adding it on form load, which has helped a lot).

Though, as I think about it, would "aggressive sanitize" be a valid way to determine if the .json file is created for Forms? This is less ideal, as there are other sanitized items that make no difference in the files, and the margin settings might actually change printing, but that's a whole edge case exploration.

hecon5 commented 3 years ago

As I go through this, would it be better to have those functions be outside the form/report (since they "should" be the same) to reduce code base, or do you think it best to keep the two separated in their own classes?

hecon5 commented 3 years ago

Was thinking something like this that would be called to import, but I also see it might be nice to have the import customized to the type. For now, I've just modified the import function on the forms class to match the reports (with the single change to the acForm vice acReport).

'---------------------------------------------------------------------------------------
' Procedure : Import Object
' Author    : Adam Waller / hecon5
' Date      : 4/23/2020 Updated 01/14/2021
' Purpose   : Import the individual database component from a file.
'---------------------------------------------------------------------------------------
'
Public Sub ImportDBOjbect (strFile As String, ObjType as AcObjectType)
    Dim strImportedObject As String
    Dim strTempFile As String
    Dim dFile As Dictionary

    strImportedObject = GetObjectNameFromFileName(strFile)
    Set dFile = ReadJsonFile(GetPrintVarsFileName(strImportedObject))

    ' Check to ensure dictionary was loaded
    If dFile Is Nothing Then
        ' Missing print vars file. (Could be legacy export)
        LoadComponentFromText ObjType, strImportedObject, strFile
    Else
        ' Insert DevMode structures into file before importing.
        With New clsDevMode
            ' Load default printer settings, then overlay
            ' settings saved with report.
            .ApplySettings dFile("Items")
            ' Insert the settings into a combined export file.
            strTempFile = .AddToExportFile(strFile)
            ' Load the report file with the DevMode settings
            LoadComponentFromText ObjType, strImportedObject, strTempFile
            DeleteFile strTempFile, True
        End With
    End If

End Sub
hecon5 commented 3 years ago

The other option, that may be easier, is to alter loadcomponentfromtext to process the import file? Since that function (also) has a temp file, not having to spool one up, delete it, then spool it up again to do the Ucs2 conversion might be advantageous. In that case, both reports and form importing would be single lines (like forms are now), and the import tool would handle the rest.

joyfullservice commented 3 years ago

Thank you for all the thought you have put into this! I really like the way you are forward thinking in wanting to take the more object-oriented approach, reduce and simplify the code base, and still keep things organized in a logical, intuitive way. 👍 😄

I have reviewed the PR #123 and I like what you have done there. I wrestled with how to best do that when I was initially implementing this for reports after discovering that forms carry some of the same properties when it comes to the print settings. Nice work!!

By the way, just to add a little background, toward the end of last year I was doing some significant work in collaboration with @mmzmusicnotes and started a new branch called git-integration. This will eventually be merged back into master, probably as version 3.3.0 and includes a lot of additional work in organizing the code base, improving error handling, and progress towards a tighter git integration for even better performance especially with large and complex databases.

I have just updated the dev branch from git-integration, so if you would like to work off the dev branch and submit your pull requests directly to dev, we can collaborate on the most up-to-date codebase. Right now I have it split from the master branch because I was doing some pretty significant refactoring and wanted to keep the master branch ready for bug fixes that needed to be rolled out before I finished the git integration. The dev branch is where we can actively develop on the code base that will eventually become version 3.3.0. Hopefully all that makes sense. 😄 Thanks again for your contributions to this project!

joyfullservice commented 3 years ago

FYI, I am porting over pr #123 to the dev branch so we should have that available soon...

hecon5 commented 3 years ago

Will definitely switch to dev; I wasn't certain which branch you liked to commit to, so just went with the most recent :)

My long term goals is to be more (or less, depending on outcomes) to be able to port my inherited applications away from Access (since they've said 2025 is the funeral date :( ), so anything to reduce re-re-rewrites will save me headaches in the future, especially if the architecture stays similar. In the interim, having something like this that cuts down on time spent waiting for exports and code reviews for feature adds makes my life a lot easier.

Thanks for managing this and being so responsive; makes me a lot more comfortable with abandoning the integrated VCS code base.

joyfullservice commented 3 years ago

I would be surprised if Microsoft retires Access... There are a huge number of companies and users that depend on this software for daily production use. (See this link) I personally love the way it provides a nice balance of rapid application development and tremendous flexibility. You can use a lot of OOP concepts within VBA and having version control with source-level editing and collaborative development through the VCS plugin, it is a perfect fit for the needs of the organization I work for. 😄

joyfullservice commented 3 years ago

Okay, I have finished integrating the changes into the dev branch. It seems to be working for me on both export and build, but feel free to do more testing in your environment.

I did make an additional change to only export print settings for forms and reports if they actually exist in the export file. (Export files for some forms may not contain any of the three print setting sections, in which case a json file will not be created.) I also added some handling to deal with orphaned json files if you toggle the Print Settings option on and off, or if changes to a form make it no longer require the json file.

When you are satisfied with how this is working, you may close this issue. Thanks again for your work!!

hecon5 commented 3 years ago

Will give it a roll this morning and update! I've pulled dev into my local instance, and it seems to be faster already.

I'll update with results a bit later!

joyfullservice commented 3 years ago

Just discovered an issue where saved print settings are lost on import. Working on a fix right now...

hecon5 commented 3 years ago

I'm getting crashes for import when a .json file exists for form importing forms/reports; trying to troubleshoot now, but it appears if the .json file is present it will crash reports/forms without .json will import fine.

hecon5 commented 3 years ago

This line seems to be giving fits: image

I don't see anything obvious that should be causing this, except that I don't have a physical printer as a default, and it's Windows 10/64bit, but that doesn't seem like it should cause issues, either.

hecon5 commented 3 years ago

So, as I look more into this, it looks like you try to grab printer settings for hte default printer (if there is one); this seems to hang up Access for me, as I don't have any physical printers, and I think the Acrobat PDF printer I do have doesn't always play nice.

Since the .JSON file is just a compilation of what was there, why is it getting this information from the OS?

joyfullservice commented 3 years ago

This has to do with the Windows DEVMODE structure. Access works with a buffer representation of the actual printer driver structure, but it does not necessarily store all the driver-specific information, which can well exceed the size of the buffer. Additionally, there are parts of the structure that are not stored in the json file because they are reserved values, or not values you can change without adding further complexity.

The approach I took was that when the report did not have a specific non-default printer assigned, I treated it as if it was using the default printer. (Which in fact, it does.) To ensure that I had the complete DEVMODE structure, I use the API to read this from the default printer, then overlay the relevant sections with my saved values from the json file. This structure is then converted back to the binary representation used in the Access objects, and written back to the source file before import.

There are a number of links at the top of clsDevMode that reference a lot of the technical background I was trying to take into account with all of this. It is a complicated topic, but so far I have been pleased with the result, which seems to work fine on the systems that I have used it with.

The OpenPrinter API call is a common and well documented API, so I am not sure why it would be having issues with the Acrobat printer.

hecon5 commented 3 years ago

@joyfullservice I'm still not able to figure out why this crashes my machine. The only other reference to this is from an eXperts exchange post that says "solved" for an "Open Printer on Office 365 64bit" but as I don't want to pay for it, I can't see the post. I also kind of wonder if it's just a ruse, as other posts on that site are exposed. There is an offhand reference to .Net as an interface to OpenPrinter, which is interesting, but it's the VBA component of Access that crashes, and not .Net like it was before.

In any case; I'm half tempted to just skip removing prtmip for the time being and shelve my search while I get some other stuff off my plate. One of the links in the clsDevMode shows them doing that. I think I'll leave the .json creation, as it does increase readability (and cuts down on code that has to be switched off), but this would avoid having to need the OpenPrinter command.

Thoughts/ideas?

Full error log:

Faulting application name: MSACCESS.EXE, version: 16.0.13127.21064, time stamp: 0x5ffa6bb2
Faulting module name: VBE7.DLL, version: 7.1.10.49, time stamp: 0x5f6d0b26
Exception code: 0xc0000005
Fault offset: 0x00000000000f071c
Faulting process id: 0x5d90
Faulting application start time: 0x01d6f31cd8256186
Faulting application path: C:\Program Files\Microsoft Office\Root\Office16\MSACCESS.EXE
Faulting module path: C:\Program Files\Common Files\Microsoft Shared\VBA\VBA7.1\VBE7.DLL
Report Id: 9b6a11b1-7e4c-4b8b-a427-eebf1164261b
Faulting package full name: 
Faulting package-relative application ID: 
joyfullservice commented 3 years ago

Sorry you are experiencing such challenges with the printer API call. Here are just a few ideas that won't take much time, but may help in narrowing down the issue...

First, I would try building the add-in from source to rule out any file corruption or other weird issues. In some case I have seen strange problems like this cleared up after a fresh build from source.

You might also try a very simple proof-of-concept call to this API in a VBA module in Excel to see if it causes the same crash. (Is it all Office programs, or just Access?) If it works in Excel, then try the same code in a new module in a blank database, independent from the add-in code base. If you are still having issues in Access, I would also make sure that all other add-ins are disabled to rule out any conflicts.

Finally, as I am sure you have probably seen, the technical error there points to an access violation. Since it sounds like you have a fairly secured environment, it may be that there is special security restrictions in place that might possibly be affecting the Acrobat printer or printer driver. It may be that we need to adjust the way we are querying the printer with .DesiredAccess to ensure we can actually read these settings before calling the OpenPrinter API. I know some of the code samples I was originally reviewing included more complex security handling than what I ultimately used in clsDevMode.

Hope that helps!!

hecon5 commented 3 years ago

I've built it from source ... a lot. I even re-wrote the definition with differing calls I found (PRINTER_ACCESS_USE, GENERIC_READ which says it's so you can use either local or network printers, etc.). I have found that PRINTER_ACCESS_USE will not crash, but sits there and hangs. If I pause execution, then it will crash.

I cannot get it to run in excel, either at any permission level; it crashes with even a call to the openPrinter.

joyfullservice commented 3 years ago

Hmm... To me that sounds like an issue with either the OS or the print driver. I know Microsoft had some print-related issues in some of the Windows 10 updates, but I don't know if this would be affected.

I assume the problem goes away if you set your default printer to the Microsoft Print to PDF? Are there any outstanding updates to the Adobe Acrobat printer? Are there security options in Adobe that might be affecting things?

Also, I would be curious as to what happens if you run Access or Excel as administrator, and then try the API call. Maybe that would yield some clues.

Do you still get the crash if you simply query the printer for a desired access level? (Passing Null for pDataType and pDevMode as described here.)

Hopefully you will get to the bottom of this eventually, but in the mean time perhaps a different default printer might bypass the issue for the moment and allow you to move on to other things.

hecon5 commented 3 years ago

I think it's the call, itself. Passing in null values doesn't help, neither does setting the default printer to another (I've tried every printer I have).

I'll try passing in null, and a few other things like this, which declare OpenPrinter a little differently; after that I will probably have to keep the prtmip for now.

hecon5 commented 3 years ago

Ok, so more: if I declare OpenPrinter like this:

Private Declare PtrSafe Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" _
    (ByVal pPrinterName As String, phPrinter As Long, pDefault As Any) As Long

    lngReturn = OpenPrinter(strPrinter, hPrinter, 0)
    debug.print lngreturn

will print 0 as lngReturn, and hPrinter also returns 0.

(actually, it prints " 0 ", which is interesting, but I think ultimately a red herring)

Private Declare PtrSafe Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" _
    (ByVal pPrinterName As String, phPrinter As Long, pDefault As Long) As Long

    lngReturn = OpenPrinter(strPrinter, hPrinter, 0)

will also return 0, and hPrinter also returns 0.

Private Declare PtrSafe Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" _
    (ByVal pPrinterName As String, phPrinter As Long, pDefault As Long) As Long

    lngReturn = OpenPrinter(strPrinter, hPrinter, PRINTER_ACCESS_USE )

will crash, as will any other variation of including udtDefaults, varptr(udtDefaults), etc.

hecon5 commented 3 years ago

Oooh! Got a non-zero return!

Private Declare PtrSafe Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" _
    (ByVal pPrinterName As String, phPrinter As Long, pDefault As Any) As Long

    lngReturn = OpenPrinter(strPrinter, hPrinter, ByVal 0&)
    Debug.Print lngReturn
    Debug.Print hPrinter

Return non-zero values!

hecon5 commented 3 years ago

ok, so this keeps being more interesting: some forms appear to load, but others do not; there do not appear to be anything else. When building from source, some forms appear to build fine with a .json, others do not. An Error 2128 pops up for that form; removing the .json file for that form will carry on its merry way. Obviously, this isn't ideal, but it does appear to be working.

I am not 100% positive on how to proceed with the revised openPrinter declarations / calls since it obviously might affect other instances; perhaps a compiler directive for Office 16/VBA7. This might be the way to go since I got the idea from a post that also migrated to Office 16/64bit and it stopped working for them.

joyfullservice commented 3 years ago

If you can provide me with the updated calls, I can test them in Access 2010 (32 bit/VBA 7) and see if we have any issues. I don't think we need to worry about supporting anything earlier than that.

The 2128 error might have something to do with the way the printer sections are inserted back into the files... Is there a way you could compare the before and after versions? Maybe it is just coming in at the wrong spot...

hecon5 commented 3 years ago

Updated code for clsDevMode.bas:

'Updated OpenPrinter Declaration:
Private Declare PtrSafe Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" _
    (ByVal pPrinterName As String, phPrinter As Long, pDefault As Any) As Long

    'updated openPrinter call (in sub LoadFromPrinter); line 350ish
    lngReturn = OpenPrinter(strPrinter, hPrinter,  ByVal 0&)
hecon5 commented 3 years ago

Also made PR #138 for same changes

joyfullservice commented 3 years ago

Nice! #138 is testing out just fine for me in my environment...

Public Sub TestDevModePrinterAccess()
    With New clsDevMode
        .LoadFromDefaultPrinter
        Debug.Print ConvertToJson(.GetDictionary, "  ")
        .LoadFromPrinter ("Microsoft Print to PDF")
        Debug.Print ConvertToJson(.GetDictionary, "  ")
    End With
End Sub
hecon5 commented 3 years ago

Sweet! I'm trying to figure out why some forms won't load and how to handle it, and I think that'll close out this issue!

hecon5 commented 3 years ago

Here may be a clue: the original integrated VCS export on the left side; the just before import file on the right.

image

I moved prtmip up to be in the same location and the second line doesn't match: image

On this one it imported fine; (note that I moved prtmip up to make comparison easier; on all of them it moves down on your version. image

This one also has errors (top is your inserted code, bottom is original); if I revert it to the original, there are no issues. image

hecon5 commented 3 years ago

I also notice that the temp files do not get deleted, and I also see that the ConvertUTF8ucs2 looks like it might overwrite the prtmip that's been inserted into the file, but I'm not certain as to how ConvertUtf8Ucs2 works

        strTempFile = GetTempFile
        ConvertUtf8Ucs2 strSourceFile, strTempFile, False
        Perf.OperationStart "App.LoadFromText()"
        Application.LoadFromText intType, strName, strTempFile
        Perf.OperationEnd
        DeleteFile strTempFile, True

One option for conditional delete (add below delete temp);

    If strSourceFile <> strFile Then DeleteFile strSourceFile, True
joyfullservice commented 3 years ago

If I am understanding the PrtMip structure correctly, would these correspond to the reserved flags for FastPrint and Datasheet?

image

image

Perhaps these values do need to be (saved and) added back to the rebuilt PrtMip structure...

hecon5 commented 3 years ago

Quite possibly: One (not all??) of these forms allow for datasheet view.

Stranger still: once I build (successfully) and export again, the .Json file is not created when I export (even with full export) for some of the forms.

joyfullservice commented 3 years ago

Stranger still: once I build (successfully) and export again, the .Json file is not created when I export (even with full export) for some of the forms.

This is actually by design. Print settings are not internally stored in a form until after you go to print preview, and then save changes to the form. At that point there is data in the PrtMip structure, which is what gets exported to the json file. During the export process, there is a check to see if we actually have data in the various print setting structures. If we don't then no export file is created. (Since it wouldn't have any meaningful data anyway.)

If you want to remove print settings from an object, you can simply delete the json file and build from source. The print settings will be empty till they are generated/modified by the user.

joyfullservice commented 3 years ago

If you want to do some testing with including the FastPrint and Datasheet values in the json files, it would only require a couple small code changes in clsDevMode. Uncomment the existing two lines in MipToDictionary, and add a couple lines to ApplySettings to write these properties back to the structure.

hecon5 commented 3 years ago

So, I went through a large sample of forms and reports, and in every case, the FastPrint and DataSheet was set to 1, but the output in the .json file is always "2097153" for Datasheet (if there, which it is). I'm putting together a test block to see if that works. Based on how I estimate this thing works, here's some code:


'Uncomment and adjust in "MipToDictionary"

        .Add "FastPrint", Cbool(cMip.fFastPrint)  ' Reserved
        .Add "Datasheet", Cbool(cMip.fDatasheet)  ' Reserved
'Insert into ApplySettings in "with m_tMIp" 
                    Case "FastPrint": .fFastPrint = dItems(varKey)
                    Case "Datasheet": .fDatasheet = dItems(varKey)

There's also setMipFromPrinter, but I don't know if I want to toy with that yet, since the goal is to insert the block, not to do anything fancy.

hecon5 commented 3 years ago

Ok, I'm about to show my ineptitude in this area: I'm trying to figure out how to address the creation now. When I do it like above (or if i use cint(dItems(varkey)) or cbool..., it inserts this

0x010000006801000000000000a1070000ffffffffffffffff

instead of 0x010000006801000000000000a10700000100000001000000

which is interesting, because on some forms, that seems to be accepted, and on others, it's no bueno. I'm kind of at a loss as to why some forms don't seem to care, and others do.

I cannot find anything that indicates the "failing" forms should fail in comparison between their import files and .json settings. The .json settings are identical, and the forms do not appear to have anything that should prevent them from being loaded. At first, I thought it was the width, but then I found several others that import fine that are the same width. Then I thought it was the modal state, but I can find instances of both that import fine. I cannot for the life of me figure out why some don't import and some do.

hecon5 commented 3 years ago

Oooh! Tunnel vision was obstructing me! I totally missed some error output files in the directory, opened one, and

Microsoft Access encountered an error while importing the object 'frmAddNewPCRemark'.

Error encountered at line 40.
Expected: 'End'.  Found: =.

was inside. Looked inside, and ... these forms have OnLoad macros! (well, so do a lot of others that work fine). and the prtmip is being inserted in the middle of the macro, instead of before it!

image

joyfullservice commented 3 years ago

Good catch!! The idea on the insertion was to put it in right before the main block for the form starts. In my testing, that seemed to be right before the first line that Trim(strLine) = "Begin". Evidently macros might impact that... Feel free to adjust the insertion logic to something that more accurately places the print settings section. (Keep in mind that not all objects contain all the different blocks and properties.)

Also, as to the Fast Print and Datasheet values, try wrapping the returned values in Abs() to convert -1 to 1.

Case "FastPrint": .fFastPrint = Abs(dItems(varKey))

joyfullservice commented 3 years ago

I think this might fix it... Do you want to give this a try?

image

hecon5 commented 3 years ago

Will try, the other one I was pondering is to put it directly below "Bottom=" because it's always there, but wasn't certain as to how best to cut off the bottom value. Perhaps Select Case Left$(strline,12) but that would also make it harder to handle the first case in there.

joyfullservice commented 3 years ago

The other consideration is that while forms have a Bottom property, reports do not. Since we use the same code for both objects, we want something that will consistently work for both object types. The other advantage with looking for Begin is that we will be sure that we have replaced any existing printer settings blocks, in case they already exist in the file.

hecon5 commented 3 years ago

That worked!

One other thing I notice is that you don't use .AppendOnAdd = vbCrLf; so I was wondering if doing the following would be easier to handle: (note I used negative logic cause I did), and would remove all the vbCrLf in it.

    With New clsConcat
        .AppendOnAdd = vbCrLf
    'Stuff here
                    Case "Begin"
                        'Verify indent level
                        If strLine <> "    Begin" Then

                            .Add strLine
                        Else
                            ' Insert our blocks before this line.
                            .Add GetPrtMipBlock, GetPrtDevModeBlock, GetPrtDevNamesBlock, strLine
                            blnFound = True
                        End If