docmd.copyobject = runtime error 2501

plucnik

Registered User.
Local time
Today, 09:00
Joined
Nov 11, 2003
Messages
34
We recently upgraded from Access 97 to 2000. I found this post (pasted below) from last year that descibes the exact problem that we are having. No replies were posted so.....I'm hoping that resubmitting the question might bring an answer.
Thanks!
Peter

Hi,
My application uses a standard report as a template. Every time the user runs a report, a temporary copy of the standard report is made (using docmd.copyobject) with a unique name. This copy is then modified to that particular users needs. Each day, I have a clean-up function that deletes all those temporary reports.

This worked fine in Access 97. I am in the process of converting to Access 2002, and now find that copyobject fails if there is more than one person using the database. I get error #2501, 'The CopyObject action was canceled."

Yes, I have the database set for shared access.

Any ideas appreciated.
 
fails if there is more than one person using the database


This will fail if there is more then one person due to passive locking. Microsoft added passive locking as a "Feature" to Access 2000. If there is more then one person in the database then you cannot make changes and save forms or reports - this includes new objects.

If you are getting this error with just a single user in the database then I am experiencing the same issue. I think it may have something to do with opening up the database in code with a "God" level user. I hope that helps. Strangely enough answering your question, may have helped me to figure out my issue!

Thanks!

GumbyD
 
plucnik: Try This...

I can't guarantee that this will work for what you need...
BUT... it might...

Since you can't have more than one person in a database AND be able to make objects via code... Have you considered trying a front-end / back-end approach?

I use this on almost ALL of my databases...
HERE is what I do, that I think might help you...
(I am only explaining in case you don't know... or in case someone else could use this information... please don't get offended)

Put all your TABLES into one Database.
This will be called the "Back-End Database".
Put EVERYTHING ELSE into another Database.
This will be called the "Front-End Database.
In the Front-End Database, create LINKED tables to the Back-End Database.

Now what "I" do at this point is put the Back-End Database on a server... in a HIDDEN folder... This way the End-User never touches it directly... (I don't want my tables deleted by Mr. I-Know-What-I'm-Doing) Unfortunately, you can't set any security measures easily on this database or you run the risk of locking users out from being able to use your database.

Then, I put the Front-End Database on the DeskTop of the user who needs it... This way, for your problem, the user is the ONLY ONE IN THAT DATABASE... Sure, THAT DATABASE is linked to the Back-End, but you are creating REPORTS in the Front-End, and the Front-End is on THEIR DESKTOP so they can do whatever they want with it...

If you put a backup-copy on the Server you can even delete the Front-End and just grab a Fresh Copy from the server...

Now if you check -- click here -- with this post, you can see the code I use to facilitate Front-End Updates to make the WHOLE process easier...

Good Luck to ya...
 
Thanks for the replies and advice. In the meantime, I kinda figured out some of this. The databases are already set up as front end and back end so I didn't have to reconfigure anything. I guess I assumed that Access 2003 would act like 97 (but you know what assuming gets you!). I did run into a record locking issue on the back end. I had to uncheck the "open database using record - level locking" check box on the Tools/Options/Advanced tab on each users PC. I was getting sporatic locking issues from the users randomly accessing the same data in a table and getting the locking message. So far so good...again thanks for the assistance!
Peter
 
Jeez, I just thought of something else that I wanted to ask. The database is rather dynamic, meaning that I'm constantly doing little revisions to forms, queries etc. Having a separate copy on each PC is a real pain because I have to go to each PC and paste a revised front end on every revision. Is there a way to "syncronize" all of the copies on the PC's with a master copy of the front end that I can keep on the server? Thanks again.
 
chuckle

Jeez, YOU didn't read my post didja?
huh huh?

just kidding...
Check out this code:

Code:
Option Compare Database
Private Declare Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" (ByVal lpBuffer As String, nSize As Long) As Long

Public Const ERROR_SUCCESS As Long = 0
Public Const CSIDL_DESKTOP As Long = &H0
Public Const CSIDL_PROGRAMS As Long = &H2
Public Const CSIDL_STARTMENU As Long = &HB
Public Const CSIDL_DESKTOPDIRECTORY As Long = &H10

Public Const FO_COPY As Long = &H2
Public Const FOF_SILENT As Long = &H4
Public Const FOF_RENAMEONCOLLISION As Long = &H8
Public Const FOF_NOCONFIRMATION As Long = &H10

Public Type SHFILEOPSTRUCT
  hwnd      As Long
  wFunc      As Long
  pFrom      As String
  pTo        As String
  fFlags     As Integer
  fAborted   As Boolean
  hNameMaps  As Long
  sProgress  As String
End Type


Private Type BROWSEINFO
  hOwner As Long
  pidlRoot As Long
  pszDisplayName As String
  lpszTitle As String
  ulFlags As Long
  lpfn As Long
  lParam As Long
  iImage As Long
End Type


Private Declare Function SHBrowseForFolder Lib "shell32.dll" Alias "SHBrowseForFolderA" (lpBrowseInfo As BROWSEINFO) As Long
Public Declare Function SHFileOperation Lib "Shell32" Alias "SHFileOperationA" (lpFileOp As SHFILEOPSTRUCT) As Long
Declare Function SHGetPathFromIDList Lib "Shell32" Alias "SHGetPathFromIDListA" (ByVal pidl As Long, ByVal pszPath As String) As Long
Declare Function SHGetSpecialFolderLocation Lib "Shell32" (ByVal hwndOwner As Long, ByVal nFolder As Long, pidl As Long) As Long
Public Declare Sub CoTaskMemFree Lib "ole32" (ByVal pv As Long)
Private Declare Function apiShowWindow Lib "user32" Alias "ShowWindow" (ByVal hwnd As Long, ByVal nCmdShow As Long) As Long
Private Const BIF_RETURNONLYFSDIRS = &H1
Dim appAccess As Access.Application, BlankHolder

Public Function CompareVersion()
On Error GoTo Err_CompareVersion

Select Case GetMasterVersion
    Case GetCurrentVersion
    Case Else: CopySwap
End Select

Exit_CompareVersion:
    Exit Function
    
Err_CompareVersion:
    errMessage Err
    Resume Exit_CompareVersion

End Function

Public Function GetMasterVersion() As String
    Dim wrkJet As Workspace
    Dim dbs As DAO.Database, cnt As Container
    Dim doc As Document, prp As Property

    ' Property not found error.
    Const conPropertyNotFound = 3270
    On Error GoTo GetSummary_Err
    
    Set wrkJet = CreateWorkspace("", "User", "")
    Set dbs = wrkJet.OpenDatabase(" \\PW\engineering\wpdata\reports\Databases\Front_En
d_Databases\Template.mdb")
    Set doc = dbs.Containers("Databases")!UserDefined
        GetMasterVersion = doc.Properties("MasterVersion")
        dbs.Close
        wrkJet.Close
    Set doc = Nothing
    Set dbs = Nothing

GetSummary_Bye:
    Exit Function

GetSummary_Err:
    If Err = conPropertyNotFound Then
            MsgBox "There is no Master Version number assigned."
        Resume
    Else
        ' Unknown error.
        MsgBox Err.Description
        Resume GetSummary_Bye
    End If
End Function

Public Function GetCurrentVersion() As String
    Dim dbs As DAO.Database, cnt As Container, GetTemplateLocation As String
    Dim doc1 As Document, doc2 As Document, prp As Property
    
    ' Property not found error.
    Const conPropertyNotFound = 3270
    On Error GoTo GetSummary_Err
    
    Set dbs = CurrentDb
    Set cnt = dbs.Containers!Databases
    Set doc1 = cnt.Documents!UserDefined
    doc1.Properties.Refresh
    GetCurrentVersion = doc1.Properties("MasterVersion")

GetSummary_Bye:
    Exit Function

GetSummary_Err:
    If Err = conPropertyNotFound Then
            MsgBox "There is no Replica Version number assigned."
        Resume
    Else
        ' Unknown error.
        Resume GetSummary_Bye
    End If
End Function

Public Function CopySwap()
Dim fs
On Error GoTo Err_CopySwap

'   Create a target that points to where the new version should go.
'   TrgtLoc = "C:\WINNT\Profiles\" & GetNTUser & "\Desktop\ProjectStatus.mdb"
'   Start up the COPY FUNCTION.
    Set fs = CreateObject("Scripting.FileSystemObject")
'   Get the original Template and copy it to where new versions go. (True means to overwrite if a copy exists.)
    fs.CopyFile " \\PW\engineering\wpdata\reports\Databases\Front_En
d_Databases\Template.mdb", TNmLoc, True
'   Start up the OPEN DATABASE FUNCTION.
    Set appAccess = CreateObject("Access.Application")
'   Open the new database that was just copied from the Template.
    appAccess.OpenCurrentDatabase TNmLoc, False
'   Close the old version of the database.
    DoCmd.Quit acQuitSaveNone

Exit_CopySwap:
    Call CompareVersion
    Exit Function

Err_CopySwap:
    MsgBox Err.Description
    Resume Exit_CopySwap

End Function

Public Sub CreateDesktopLink(sSource As String, sDestination As String)
'working variables
Dim sFiles As String, SHFileOp As SHFILEOPSTRUCT

'terminate passed strings with a null
sSource = sSource & Chr$(0)
sDestination = sDestination & Chr$(0)

'set up the options
With SHFileOp
    .wFunc = FO_COPY
    .pFrom = sSource
    .pTo = sDestination
    .fFlags = FOF_SILENT Or FOF_NOCONFIRMATION
End With

'and perform the copy
Call SHFileOperation(SHFileOp)
  
End Sub


Public Function GetSpecialFolder(hwnd As Long, CSIDL As Long) As String
Dim pidl As Long, pos As Long, sPath As String

'fill the pidl with the specified folder item
If SHGetSpecialFolderLocation(hwnd, CSIDL, pidl) = ERROR_SUCCESS Then
'initialize & get the path
    sPath = Space$(260)
    If SHGetPathFromIDList(ByVal pidl, ByVal sPath) Then
        'has a null?
        pos = InStr(sPath, Chr$(0))
        'strip it
        If pos Then
            'return folder
            GetSpecialFolder = Left$(sPath, pos - 1)
        End If
    End If
End If
Call CoTaskMemFree(pidl)
End Function

Public Function TNmLoc() As String
On Error GoTo Err_TNmLoc

Dim DskTp As String, DbNm As String
DskTp = GetSpecialFolder(0&, CSIDL_DESKTOPDIRECTORY)
DbNm = "\Midwest Customer Application.mdb"

TNmLoc = DskTp & DbNm

Exit_TNmLoc:
Exit Function

Err_TNmLoc:
MsgBox Err.Description
Resume Exit_TNmLoc

End Function

Public Function GetNTUser() As String
On Error GoTo Err_GetNTUser
'Returns the network login name
Dim strUserName As String
'Create a buffer
strUserName = String(100, Chr$(0))
'Get user name
GetUserName strUserName, 100
'Strip the rest of the buffer
strUserName = Left$(strUserName, InStr(strUserName, Chr$(0)) - 1)
GetNTUser = LCase(strUserName)

Exit_GetNtUser:
Exit Function

Err_GetNTUser:
MsgBox Err.Description
Resume Exit_GetNtUser

' SAMPLE USAGE:
' Me!<insert field name here> = GetNTUser

End Function

I use this code to update my front-ends.
Whenever I make a change to the Master Template, all I have to do is change the Version Number under Database Properties and then whenever a user opens the front-end on the desktop it checks the master template, if they are different versions, it updates itself to their desktop...

I call this function through a Macro named autoexec...
That way it checks everytime they open the front-end...
But, it works on every system I have tried so far UNTIL I started using Access 2002... now I am having the devils time trying to get this to work... SO if you are NOT using Access 2002 or higher... I believe this code will work wonders for you...
I just drop it into it's own separate Module, and create a Macro called autoexec that calls the CompareVersion function AND change the file locations strings that I have setup for my server arrangement and you are set...

Any other questions... just ask...
You can view the post I posted about THIS code here: CLICK HERE FOR THE POST

GOOD LUCK!
 
Brian -

What happens if a user makes changes to their front-end database but does not give them to you to update the template and then you synconize to the master copy? Do they lose all of their individual changes?

Just wondering

GumbyD
 
Sorry - I have one more thought. Why not have both the table database and the other database on the server and let everyone access that through one Icon on the client machine. In additon to the "production" version of the database put a copy on the users desktop called the "design" or "test" version of the database (which is a copy of the "produciton" version but the data may be outdated - which of course becomes a training issue).If a user wants to make or change a form or report they make it on their "design" version. When they are happy with the new objects they contact you with the object name(s) and you copy it to the "production" version.

Just an idea!

GumbyD
 
Well, you see...

GumbyD said:
Brian -

What happens if a user makes changes to their front-end database but does not give them to you to update the template and then you synconize to the master copy? Do they lose all of their individual changes?

Just wondering

GumbyD

They lose it... ALL of their individual changes... Yes... Sorry...
I am stunned, my users are all Engineers... NONE of them know HOW to make changes... I have never had to deal with that issue... chuckle...

GumbyD said:
Sorry - I have one more thought. Why not have both the table database and the other database on the server and let everyone access that through one Icon on the client machine. In additon to the "production" version of the database put a copy on the users desktop called the "design" or "test" version of the database (which is a copy of the "produciton" version but the data may be outdated - which of course becomes a training issue).If a user wants to make or change a form or report they make it on their "design" version. When they are happy with the new objects they contact you with the object name(s) and you copy it to the "production" version.

Just an idea!
Well, the reason is...
See the Back-End has ONLY Tables...
The Front-End has Everything else...
IF you put your Front-End on the server so everyone can open it... You get the same problem as before... When more than one person has it open, you have connectivity issues with newer versions of Access...

For Me, if I had users who would be customizing their own stuff... I would offer a solution this way...
Setup the database using the code I referenced before... The Database Updating from the server...
BUT for those who want to customize their own reports... forms... whatever... Create FOR them ANOTHER DATABASE on their desktop... Link the Tables to the Back-End for them... and let THEM build ALL the forms and reports in it...

This way...
The end-user can either:
a) Open and use your Front-End Database and get all the updates with no sweat, no hassle...
b) Open their CUSTOM database and do all the magic they want...

Either way, they have a choice...
You could always request for custom items to add...

For instance, if user George has created the super-elite-access-report and he has perfected it in his CUSTOM database... He can send you a copy of the CUSTOM database, you can take that report and drop it into the working Front-End Template on the server and NOW EVERYONE CAN USE THE SUPER-ELITE REPORT...

THis way you get the OTHER USERS to do the hard-work for you...

That is my opinion on the whole thing at least...
 

Users who are viewing this thread

Back
Top Bottom