Closing a Shared, Secret File

Based on a previous thread, what I know about secret and shared databases, and Help, it would seem that synchronize would be an un-necessary command after opening the file, and that setactivedatabase might not be necessary, but would not be problematic to include.

In a procedure that opens a shared file, then a single user file, both as secret windows, followed by importdatabase to load the shared data into the unshared file, I’m getting inconsistent results and a wide variety of errors.

Sometimes it works. More often the error is a ‘field or variable does not exist’ error from Panorama but they vary: ActiveProcedure, loggingToServer, hostServer, localCoverage, asyncCallbackLabel… The error may or may not include dimmed menus that require a ForceQuit.

In the simplest code I could pare it down to it’s closing the shared file that sets up the error.

opensecret “SharedFile”
If Error rtn EndIf
opensecret “SingleFile”
If Error
    setactivedatabase “SharedFile” 
    closefile
    If Error nop EndIf
    Rtn
EndIf
setactivedatabase "SingleFile" 
importdatabase "SharedFile","ExistingData","Replace",“MatchingFields”,“YES”
Save
setactivedatabase "SharedFile"  
closefile            ; <- eliminate this and there’s no issue 
If Error nop EndIf

I don’t want the shared file to remain open so how can I close it without an issue?

Which brings up another question. Is there a way to determine what databases are open if they’ve been opened as Secret Windows?

Update: I’ve confirmed that by eliminating all references to CloseFile for the shared file, my full procedure runs over and over without issues. The single-user file can be closed without causing subsequent errors.

Jim, I reported the same issue over a year ago at the end of this thread, unfortunately without a proper fix:

My workaround is to open the datasheet and then close the database, like this:

setactivedatabase "SharedFile"
opensheet
closefile

Our applications heavily rely on secret shared files, and this solution works great.

The info(“files”) function is suppose to return a list of open files. I have found that often (always?) files I have closed from the File menu or procedurally are still listed as being open. Indeed, if I use:

setactivedatabse “My File”
opensheet

The data sheet for My File will pop open. How do I actually close those files. I don’t mind them remaining open secretly, but it does bother me to know that closefile is acting more like makesecret. Maybe it is only me or only certain files…don’t know for sure.

You’re right. That does work. Unfortunately it defeats the use of secret windows.

But thanks for leading me to that thread. With a bit more experimentation I have found an apparent solution to closing a shared secret file using CloseDatabase instead of CloseFile:

SetActiveDatabase "Contacts"  
Save
CloseDatabase "Contacts"

The Save is necessary.

The info(“files”) function that Gary suggested is not showing the secret file among the open files. All is good.

There must be something extra going on you are unaware of. There is no way the info(“files”) function could possibly list a file that is not currently open.

If the Always keep database open option is checked (in the Database Options window) then clicking on the window’s close box will make the database secret. But using the File>Close command would still close the database, as would doing so procedurally.

I probably was not clear on this point. By using info(“files”) I verified that the supposed closed files were still actually open secretly. My example of using opensheet to have the data sheet pop open also verified that the file was still in memory. And, no, the option to keep the file open even if the last window was closed was never checked on any of my files.

This was not a big issue for me and I only noted it in passing to see if anyone else had run across this situation. Since I seem to be the only one seeing this I can only assume it is something particular to my setup and files. Certainly not worth any more time on my part or yours.

Perhaps. But based on your original post where you said this often (or perhaps always) happens, it sounds like you can probably duplicate this on command. If that’s true, I’d like to know how you did it, and hopefully try to recreate it. Maybe it’s only happening with particular databases? I’ve provided some additional background below as to why I don’t understand how this could ever happen. But interacting with Apple’s NSDocument class is very complex so it’s always possible I’m not understanding some edge situation.


The closefile statement is really only three lines of code:

  1. Find out what the current database is.
  2. Unlock the current record in that database if it is unlocked.
  3. Call Apple’s code to close the document (which is what Apple calls a file)

If the database has any windows open, it’s actually Apple’s code that closes them, not code written by ProVUE.

If you use File>Close Database, there is one situation where that won’t close the database - if a procedure is already running. However, in that situation it also won’t close the windows, it won’t do anything other than just beep.

If there isn’t any procedure currently running, then again, the entire close operation is handled by Apple, including closing any windows.


You were completely clear, and I understood what you were getting at with opensheet. It sounds like you cannot ever close any database except by quitting Panorama? Is that correct?

I would ask you what the Memory Usage window shows, but that window uses info(“files”). If info(“files”) lists the file, then it is definitely open in memory. There is only one way to enumerate open databases, and that method is used by info(“files”) and any other code that needs to know about open databases.

Upon some further experimentation it seems that the problem is only with two files I use pretty much weekly. After restarting Panorama X and loading the other files I normally have open with my current project and then opening and closing those two problem files, they close properly. Sometime latter I reopened the two files and did a batch of data entries and then tried to close the files again. One file would not even close its only open window and the other would close its windows but stayed in memory. Closing the first file’s only open window did not close the file.

These are two files loaded with my personal financial info so I can not share them. I haven’t had the time or inclination to spend making copies and trying to strip the confidential info out and then testing again.

Exactly, they will not close until I quit Panorama. Since this only involves these two files, I prefer not to spend more time experimenting looking for other clues that may still not point to anything of value.

Jim, how is this solution working for you? I remember using this approach right at the beginning, however, I encountered that any additional code running after closing the target database had 50-50 rate of failure, with inconsistent error messages:

It’s been working fine.

Over the past many weeks I’ve done more with Secret windows than ever before. In the process I’ve learned a lot and found a few things that can make or break my success with them.

Among the things I encountered was that using CloseDatabase did have subsequent errors that simply made no sense. This was after opening a form within a Secret db in order to print PDFs.

I resorted to MakeSecret instead. There was no harm if the file was in memory as long as the it was otherwise out of the way. It would be very interesting to know if that makes a difference in your situation.

Time won’t permit it right now, but I was thinking about starting a thread on the topic to share what I’ve learned and to see what others can add, in the hope of building a useful knowledge base.

FWIW: I almost always use MakeSecret.

In my last post, I suggested that using CloseDatabase was causing subsequent errors for me. But in a lengthy procedure I continued to encounter random, whack-a-mole errors.

It seems that I may have finally eliminated them by purging the use of SetActiveDatabase

For the first time, two computers were able to run the timer based procedure for 12 hours each with no errors. If it is a bug in SetActiveDatabase, it actually makes sense. There were times I was finding that a window had the wrong menus, or printing a PDF was printing the wrong window. Once Panorama even reported a variable error regarding a variable from within a Python script. If there was such an error, it should have been a Python error.

My guess is that Panorama is losing track of all of the file’s elements.

Actually, this is not the case. Python doesn’t know anything about Panorama variables. The way this works is that Panorama creates the Python script on the fly. Any Panorama variables you have embedded are evaluated and the result is placed into the script as a Python constant. If there is a problem with a Panorama variable, the problem will be encountered at this point, before Python runs.

Sounds like there must be a bug, but it’s not in SetActiveDatabase. Or to put it another way, fixing the problem is not going to involve a change to the code in SetActiveDatabase. Let me see if I can explain this. Also, let me note in advance that the rest of this post is really just for educational purposes, it’s not intended to suggest any course of action for this particular problem.

When it is running, Panorama always keeps track of what the current database is. A reference to this database is kept in an Objective-C variable. Whenever you click on a different window (or change the current window via a procedure), Panorama updates this Objective-C variable so that the current database reflects the database associated with the current window.

The SetActiveDatabase statement changes this ObjC variable directly - independent of the current window. When you do that, the ObjC variable no longer reflects the current window (btw, Panorama has another internal ObjC variable that keeps track of the current window). To change the ObjC variable is only one line of code - I’m quite confident that there is no bug in that one line.

In this example after you’ve used SetActiveDatabase you’re doing all sorts of complicated things, especially involving printing. Apparently there is something in that complicated code that doesn’t like the fact the the ObjC variable for the current database doesn’t match the current window. I’ll bet the problem is in the printing code, because the form itself may reference the database so might be confused by a different database being active.

Note that the effect of the SetActiveDatabase statement is temporary. As soon as the procedure ends, or another window comes forward, Panorama goes back to automatically setting the ObjC variable for the current database automatically based on the current window. (One possible problem might be if there is NO visible window at all - is that the case?)

By the way, the old `window “database:secret” system did the exact same thing. When you used a “secret” window, what Panorama really would do had nothing to do with windows - it would actually simply directly set the ObjC variable for the current database to whatever database was specified. So what having a “secret” window open really meant was that “the current database does not match the current frontmost window”. There’s still a regular window open, but Panorama will not direct operations like assignments, sorting, selecting, etc to the database associated with the regular window, but instead to the specified alternate database. The newer setactivedatabase statement doesn’t give you any new or different capability than “secret windows” did, I just felt that the terminology “secret windows” was misleading since there actually isn’t any window involved, so new terminology was invented. But it does the same thing.

And by my understanding, Panorama doesn’t know about Python variables. In the case I’m citing, Panorama was claiming that msg does not exist. It does exist but it’s 100% contained within the Python script, a script that had run a dozen times or so as part of a LoopArray. A Python script that I’ve used many hundreds of times. Panorama should be ignorant about msg, whether it exists or not.

Similarly, creating the PDF to be emailed by the Python script would successfully several times, then would start printing the datasheet instead of the active form, or the window of another file, or the path being assigned for the PDF. Then it might resume with the correct form.

Running the same procedure on the same data was having different errors every time.

On one run I got a message for SetActiveDatabase that the database was not open even as it showed behind the dialog.

At that point I had eliminated all secret windows from the procedure and was redundantly making sure the right file and form were active.

The variety of errors and where they occurred lead me to believe that there was some sort of memory corruption taking place.

Maybe I was somehow misusing it but when I purged all occurrences of SetActiveDatabase the errors ended.

That’s correct, Panorama doesn’t know anything about Python variables.

You’ve referenced a specific variable named msg as if I should know what that is. There certainly could be a Panorama variable named msg. Also, if an error occurs in the Python code, that message will be returned to Panorama, and Panorama will report it. Python has no way to report an error (at least it doesn’t when run from Panorama).

Yes, I understood that. My point was that whatever the bug is, it isn’t in SetActiveDatabase itself, but in other code that apparently doesn’t like it when Panorama is running with an active database that doesn’t match the current window. But yes, the solution to that would be to not run in that mode, which means not using SetActiveDatabase.