Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
Home
Discussion GroupsFormsForms ProgrammingQueriesModules / DAO / VBAReports / PrintingMacrosDatabase DesignSecurityConversionImporting / LinkingSQL Server / ADPMultiuser / NetworkingReplicationSetup / ConfigurationDeveloper ToolkitsActiveX ControlsNew UsersGeneral 1General 2
Access DirectoryToolsTutorialsUser Groups
Related Topics
SQL ServerOther DB ProductsMS OfficeMore Topics ...

MS Access Forum / Forms Programming / June 2007

Tip: Looking for answers? Try searching our database.

Application.Quit / DoCmd.Quit Fails

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Keith - 04 Jun 2007 05:53 GMT
Greetings:

I was looking at the task manager and just noticed that Access isn't
really closing when I exit my application. One copy of Access shows up
in the processes list for each time I open and close the application.
(It doesn't appear in the applications list.)

I've read dozens of posts about the merits of DoCmd.Quit v.
Application.Quit, closing recordsets and setting their variables =
Nothing. No matter what I do, Access remains open in the background.
Here are the significant parts of my code:

Private Sub cmdQuit_Click()
   DoCmd.Close acForm, "frmMenuMain", acSaveYes
End Sub

   On Error Resume Next
   gstrSQL = "DELETE * FROM tblCurrUserProj" _
       & " WHERE strUserID = """ & fOSUserName() & """;"
   DoCmd.SetWarnings False
   DoCmd.RunSQL gstrSQL
   DoCmd.SetWarnings True
   Dim AnObj As Object

   'Close all forms
   For Each AnObj In Application.Forms
       DoCmd.Close acForm, AnObj.Name
   Next
   'Close all reports
   For Each AnObj In Application.Reports
       DoCmd.Close acReport, AnObj.Name
   Next
   'Close all modules
   For Each AnObj In Application.Modules
       DoCmd.Close acModule, AnObj.Name
   Next

   'Close any possible object variables.
   Set AnObj = Nothing
   Set rs = Nothing

'In case the OS needs to do something...
'Tried with and without
   DoEvents

   DoCmd.Quit acQuitSaveAll  'Tried prompt, too.

End Sub

Is there any way to tell programatically if I have any latent object
variables? If so, how? (Nothing shows up in the locals window.)

Is it possible to set object variables to Nothing outside their scope.
(I suspect not, but since they persist, I thought I'd ask.)

I have 3 hunks of code that I didn't write, and I'm reluctant to start
messing with them. (MouseHook changes scrolling behavior, GetWinUser
gets the currently logged in user, and QBSDK retrieves data from
QuickBooks.) I assumed they were well behaved, but maybe not.

Isn't there any way to just tell Access, "Whatever you think you're
doing, stop right now and exit?" TIA.

Keith

P.S. Did I mention the boss is expecting this at lunch time?
Allen Browne - 04 Jun 2007 06:26 GMT
Hi Keith. Some things to try:

What version of Access is this?

To close any open forms/reports, you need to loop *backwards* through the
collection, e.g.:
   For i = 0 to Forms.Count -1
       Docmd.Close acForm, Forms(i).Name
   Next

Do you have any class modules? Do you need to explicitly destroy any
instances of things you instantiated?

Does it make any difference if you temporarily remove those external
libraries? (Substitute a function in a standard module that takes the same
arguments. It doesn't have to do anything.)

If that doesn't work, you're down to the divide'n'conquor approach, where
you eliminate half the things that could be causing the problem, to see if
it still occurs. Continue do add/remove half at a time, until you pin down
the culprit.

Signature

Allen Browne - Microsoft MVP.  Perth, Western Australia
Tips for Access users - http://allenbrowne.com/tips.html
Reply to group, rather than allenbrowne at mvps dot org.

> Greetings:
>
[quoted text clipped - 62 lines]
>
> P.S. Did I mention the boss is expecting this at lunch time?
Keith - 04 Jun 2007 06:46 GMT
Hi Allen:

Thanks for the tips. I just finished commenting out all the external
code, one module at a time, and the problem persists. Here are some
things I'm considering:

1. If I create an object variable:

Dim ctrl as Control

and then loop through controls with:

For Each ctrl in Forms!TheForm

do I need to set ctrl = Nothing?

2. Am I wrong to assume that object variables only exist if the module
in which they exist is called? That is, if I have a recordset variable
on the Budget form, but I never load the Budget form, that recordset
variable is not created. (If that's true, then I should only have to
check global variables, and those on the initial form I load.)

3. You suggested using an index to loop through the forms. Will that
work differently than the For Each construct I posted originally?

Thanks

Keith

> Hi Keith. Some things to try:
>
[quoted text clipped - 17 lines]
> it still occurs. Continue do add/remove half at a time, until you pin down
> the culprit.
David W. Fenton - 04 Jun 2007 15:10 GMT
> 1. If I create an object variable:
>
[quoted text clipped - 5 lines]
>
> do I need to set ctrl = Nothing?

Michael Kaplan always recommended it, when the For Each loop has
completed.

> 2. Am I wrong to assume that object variables only exist if the
> module in which they exist is called? That is, if I have a
> recordset variable on the Budget form, but I never load the Budget
> form, that recordset variable is not created. (If that's true,
> then I should only have to check global variables, and those on
> the initial form I load.)

Yes, that's correct.

> 3. You suggested using an index to loop through the forms. Will
> that work differently than the For Each construct I posted
> originally?

Well, it's more work, but it doesn't run the danger of creating an
implicit reference, as in the For Each Control question above. But I
*always* use For Each constructs for any collection, and never a
counter, except in the case where I want to loop backwards or using
some interval other than 1.

Signature

David W. Fenton                  http://www.dfenton.com/
usenet at dfenton dot com    http://www.dfenton.com/DFA/

Marshall Barton - 04 Jun 2007 17:20 GMT
[snip]
>3. You suggested using an index to loop through the forms. Will that
>work differently than the For Each construct I posted originally?
[quoted text clipped - 3 lines]
>> To close any open forms/reports, you need to loop *backwards* through the
>> collection, e.g.:

When you are closing all forms (removing all items from a
collection), it is imperitive that you avoid removing the
items in a formward direction.  If you use For Each or For i
= 0 To Forms.Count-1 , you will remove an item, which
rearranges the collection so the next item is no longer in
the same position as it was, resulting in every other item
being removed.

I think Allen meant the code to be:

    For i = Forms.Count -1 To 0 Step -1
        Docmd.Close acForm, Forms(i).Name
    Next

Another way is to just remove (close) the first item in the
collection until the collection is empty:

    Do Until Forms.Count = 0
        Docmd.Close acForm, Forms(0).Name
    Loop

Signature

Marsh
MVP [MS Access]

Keith - 04 Jun 2007 06:54 GMT
Hi Again:

Forgot to mention, this is Access 2003.

As I continue to test, I've noticed that closing from the initial menu
form does completely close Access. However, any menu item I choose
from one of three list boxes cause Access not to close when I return
to the main menu and click exit. Is there anything about this code
that would cause that:

Private Sub lstBrowse_AfterUpdate()
   lstOverviews = Null
   lstCreateNew = Null
   LoadForm (Forms!frmMenuMain.lstBrowse)
End Sub

Public Sub LoadForm(MenuList As ListBox)
   Dim strArg As String
   Dim lngMode As Long

   Select Case CLng(MenuList.Column(2))
       Case 0  'Add mode
           strArg = "Add"
           lngMode = 0
       Case 1  'Edit mode
           strArg = "Edit"
           lngMode = 1
       Case 2  'Read only mode
           strArg = "Read"
           lngMode = 2
       Case Else
   End Select

   DoCmd.OpenForm MenuList.Column(1), acNormal, , , lngMode, , strArg

End Sub

> Hi Keith. Some things to try:
>
> What version of Access is this?
Allen Browne - 04 Jun 2007 08:42 GMT
You're right: I intended the loop to be Step -1.

For your example of:
   Dim ctl As Control
you should not have to explicitly use:
   Set ctl = Nothing
at the end of that procedure. Having said that, I do it anyway: guess I just
don't trust Access to release all objects.

You also asked:
   Am I wrong to assume that object variables only exist if the
   module in which they exist is called?
It's a bit more involved than that. Basically, if you never open a form,
then it's module is not loaded into memory, and so its objects are not
instantiated. However, there are cases where that may not be true. For
example, this could cause Form1's module to be loaded:
   Call Form_Form1.MyProcedure
Also, passing an object from one procedure to another can change its
lifetime. Using the Static keyword can change its lifetime.

Now to this reply. Good: you have isolated what triggers the problem. And
you are, in fact, passing an object to LoadForm(). If LoadForm() is in a
different module, that could be the issue.

Signature

Allen Browne - Microsoft MVP.  Perth, Western Australia
Tips for Access users - http://allenbrowne.com/tips.html
Reply to group, rather than allenbrowne at mvps dot org.

> Hi Again:
>
[quoted text clipped - 36 lines]
>>
>> What version of Access is this?
Keith - 04 Jun 2007 11:58 GMT
Hi Allen:

LoadForm is in the same module as the sub that calls it. What's
strange is that if in this sub:

Private Sub lstBrowse_AfterUpdate()
   lstOverviews = Null
   lstCreateNew = Null
   LoadForm (Forms!frmMenuMain.lstBrowse)           ...

I replace the LoadForm call with this:
   DoCmd.OpenForm "frmBudget", acNormal

I can exit cleanly from Access, even if the menu form and the budget
form are both open. But I obviously want to select from a number of
different forms to open. So why would hard coding a specific form
eliminate the error?

I tried to elminate the call buy copying the LoadForm code directly
into the AfterUpdate event and modifying it to work specificly with
lstBrowse:

...
   Dim strArg As String
   Dim lngMode As Long

   Select Case CLng(lstBrowse.Column(2))
       Case 0  'Add mode
           strArg = "Add"
           lngMode = 0
       Case 1  'Edit mode
           strArg = "Edit"
           lngMode = 1
       Case 2  'Read only mode
           strArg = "Read"
           lngMode = 2
       Case Else
   End Select

   DoCmd.OpenForm lstBrowse.Column(1), acNormal, , , lngMode, ,
strArg

Even so, when I exit after opening the budget form, the Access process
remains in memory. I don't get it.

Allen, thanks so much for your help with this. I really appreciate it.

Keith

> Now to this reply. Good: you have isolated what triggers the problem. And
> you are, in fact, passing an object to LoadForm(). If LoadForm() is in a
> different module, that could be the issue.
Allen Browne - 04 Jun 2007 14:02 GMT
Okay, I'm not clear about the connection between the current form and
frmMainMenu.

But in any case, you could try:
   Dim strDoc as String
   strDoc = lstBrowse.Column(1)
   Docmd.OpenForm strDoc, , , , lngMode, ,strArg

Signature

Allen Browne - Microsoft MVP.  Perth, Western Australia
Tips for Access users - http://allenbrowne.com/tips.html
Reply to group, rather than allenbrowne at mvps dot org.

> Hi Allen:
>
[quoted text clipped - 48 lines]
>> you are, in fact, passing an object to LoadForm(). If LoadForm() is in a
>> different module, that could be the issue.
David W. Fenton - 04 Jun 2007 15:13 GMT
> LoadForm is in the same module as the sub that calls it. What's
> strange is that if in this sub:
[quoted text clipped - 9 lines]
> I can exit cleanly from Access, even if the menu form and the
> budget form are both open.

Is the parameter for LoadForm defined as ByRef (or not declared,
which is implicitly ByRef)? Try doing it with ByVal, or with:

 LoadForm (Forms!frmMenuMain.lstBrowse.Value)

Signature

David W. Fenton                  http://www.dfenton.com/
usenet at dfenton dot com    http://www.dfenton.com/DFA/

Keith - 05 Jun 2007 00:36 GMT
Hi David:

I was getting ready to rewrite my code to hardwire all my forms in a
select case statement, something along the lines of what Allen and
Arvin suggested, but your ByVal suggestion was less work, so I thought
I'd try it first. Lo and behold ... it worked! I'm delighted,
confused, but delighted.

My boss commented today on what a supportive user community this is. I
agree. Thank you, and thanks to all who came to my aid in a time of
need.

Keith

On Jun 4, 10:13 am, "David W. Fenton" <XXXuse...@dfenton.com.invalid>
wrote:

> > LoadForm is in the same module as the sub that calls it. What's
> > strange is that if in this sub:
[quoted text clipped - 18 lines]
> David W. Fenton                  http://www.dfenton.com/
> usenet at dfenton dot com    http://www.dfenton.com/DFA/
David W. Fenton - 05 Jun 2007 19:33 GMT
> I was getting ready to rewrite my code to hardwire all my forms in
> a select case statement, something along the lines of what Allen
> and Arvin suggested, but your ByVal suggestion was less work, so I
> thought I'd try it first. Lo and behold ... it worked! I'm
> delighted, confused, but delighted.

It works because you're no longer passing a reference to the object,
but the value stored in that object. It's the difference between a
pointer to something else and the string value that the pointer
points to. In your case, the pointer was surviving beyond its
appropriate lifespan, and the solution was to avoid it by passing
the parameter by value instead of by reference. You could have done
the same thing by passing the .Value property of the listbox, but
then it could cause problems if you someday changed your OpenForm
code to assume it was operating on a reference (not likely, I
agree), so it's better to change your OpenForm code to take a value
instead of a reference.

Signature

David W. Fenton                  http://www.dfenton.com/
usenet at dfenton dot com    http://www.dfenton.com/DFA/

Arvin Meyer [MVP] - 04 Jun 2007 15:26 GMT
Keith,

You might try using a variable fed by the list box:

Dim strFormName As String
strFormName = Forms!frmMenuMain.lstBrowse
DoCmd.OpenForm strFormName

You can also use a friendly name for the form and the actual form name is a
second column where the width of that column is set to 0". The line of code
would then look like:

strFormName = Forms!frmMenuMain.lstBrowse.Column(1)
Signature

Arvin Meyer, MCP, MVP
http://www.datastrat.com
http://www.mvps.org/access
http://www.accessmvp.com

> Hi Allen:
>
[quoted text clipped - 48 lines]
>> you are, in fact, passing an object to LoadForm(). If LoadForm() is in a
>> different module, that could be the issue.
Dirk Goldgar - 05 Jun 2007 05:58 GMT
> Hi Allen:
>
[quoted text clipped - 5 lines]
>    lstCreateNew = Null
>    LoadForm (Forms!frmMenuMain.lstBrowse)           ...

Just out of curiosity -- and I see that you have resolved the problem
already -- would the problem go away if you changed this:

>    LoadForm (Forms!frmMenuMain.lstBrowse)

to this:

   LoadForm Forms!frmMenuMain.lstBrowse

?

Signature

Dirk Goldgar, MS Access MVP
www.datagnostics.com

(please reply to the newsgroup)

David W. Fenton - 04 Jun 2007 15:11 GMT
> For your example of:
>     Dim ctl As Control
> you should not have to explicitly use:
>     Set ctl = Nothing
> at the end of that procedure. Having said that, I do it anyway:
> guess I just don't trust Access to release all objects.

Michael Kaplan recommended it, just in case the implicit reference
to the last control was not released.

Signature

David W. Fenton                  http://www.dfenton.com/
usenet at dfenton dot com    http://www.dfenton.com/DFA/

Keith - 04 Jun 2007 07:10 GMT
Hi Allen:

Did you mean loop backwards, as in:

For i = Forms.Count-1 to 0 Step -1

K

> To close any open forms/reports, you need to loop *backwards* through the
> collection, e.g.:
>     For i = 0 to Forms.Count -1
>         Docmd.Close acForm, Forms(i).Name
>     Next
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.