Jak używać kontroli wersji w programowaniu w programie Access?

163

Jestem zaangażowany w aktualizację rozwiązania Access. Ma dużą liczbę VBA, wiele zapytań, niewielką liczbę tabel i kilka formularzy do wprowadzania danych i generowania raportów. To idealny kandydat do programu Access.

Chcę wprowadzić zmiany w projekcie tabeli, języku VBA, zapytaniach i formularzach. Jak mogę śledzić moje zmiany za pomocą kontroli wersji? (używamy Subversion, ale to dotyczy dowolnego smaku) Mogę umieścić cały plik mdb w Subversion, ale będzie to przechowywanie pliku binarnego i nie będę w stanie stwierdzić, że zmieniłem tylko jedną linię kodu VBA.

Myślałem o skopiowaniu kodu VBA do oddzielnych plików i zapisaniu ich, ale zauważyłem, że szybko tracą synchronizację z tym, co jest w bazie danych.

Nathan DeWitt
źródło
1
Crossposting tego rozwiązania w powiązanej kwestii eksportowania schematu bazy danych Access.
Eric G
1
Access obsługuje interfejs SCC, więc każda kontrola wersji zgodna z tym interfejsem jest gotowa do Access. Zastrzeżenie: pracuję dla plasticscm.com i mamy kilku klientów korzystających z niej w programie Access.
pablo
8
Wypróbuj ten moduł VBA github.com/timabell/msaccess-vcs-integration
Tim Abell

Odpowiedzi:

180

Napisaliśmy własny skrypt w języku VBScript, który używa nieudokumentowanej Application.SaveAsText () w programie Access do eksportowania całego kodu, formularzy, makr i modułów raportów. Oto on, powinien dać ci kilka wskazówek. (Uwaga: niektóre wiadomości są w języku niemieckim, ale możesz to łatwo zmienić).

EDYCJA: podsumowanie różnych komentarzy poniżej: Nasz projekt zakłada plik .adp. Aby uzyskać tę pracę z .mdb / .accdb, musisz zmienić OpenAccessProject () na OpenCurrentDatabase (). (Zaktualizowano do użycia, OpenAccessProject()jeśli widzi rozszerzenie .adp, w przeciwnym razie użyj OpenCurrentDatabase().)

decompose.vbs:

' Usage:
'  CScript decompose.vbs <input file> <path>

' Converts all modules, classes, forms and macros from an Access Project file (.adp) <input file> to
' text and saves the results in separate files to <path>.  Requires Microsoft Access.
'

Option Explicit

const acForm = 2
const acModule = 5
const acMacro = 4
const acReport = 3

' BEGIN CODE
Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")

dim sADPFilename
If (WScript.Arguments.Count = 0) then
    MsgBox "Bitte den Dateinamen angeben!", vbExclamation, "Error"
    Wscript.Quit()
End if
sADPFilename = fso.GetAbsolutePathName(WScript.Arguments(0))

Dim sExportpath
If (WScript.Arguments.Count = 1) then
    sExportpath = ""
else
    sExportpath = WScript.Arguments(1)
End If


exportModulesTxt sADPFilename, sExportpath

If (Err <> 0) and (Err.Description <> NULL) Then
    MsgBox Err.Description, vbExclamation, "Error"
    Err.Clear
End If

Function exportModulesTxt(sADPFilename, sExportpath)
    Dim myComponent
    Dim sModuleType
    Dim sTempname
    Dim sOutstring

    dim myType, myName, myPath, sStubADPFilename
    myType = fso.GetExtensionName(sADPFilename)
    myName = fso.GetBaseName(sADPFilename)
    myPath = fso.GetParentFolderName(sADPFilename)

    If (sExportpath = "") then
        sExportpath = myPath & "\Source\"
    End If
    sStubADPFilename = sExportpath & myName & "_stub." & myType

    WScript.Echo "copy stub to " & sStubADPFilename & "..."
    On Error Resume Next
        fso.CreateFolder(sExportpath)
    On Error Goto 0
    fso.CopyFile sADPFilename, sStubADPFilename

    WScript.Echo "starting Access..."
    Dim oApplication
    Set oApplication = CreateObject("Access.Application")
    WScript.Echo "opening " & sStubADPFilename & " ..."
    If (Right(sStubADPFilename,4) = ".adp") Then
        oApplication.OpenAccessProject sStubADPFilename
    Else
        oApplication.OpenCurrentDatabase sStubADPFilename
    End If

    oApplication.Visible = false

    dim dctDelete
    Set dctDelete = CreateObject("Scripting.Dictionary")
    WScript.Echo "exporting..."
    Dim myObj
    For Each myObj In oApplication.CurrentProject.AllForms
        WScript.Echo "  " & myObj.fullname
        oApplication.SaveAsText acForm, myObj.fullname, sExportpath & "\" & myObj.fullname & ".form"
        oApplication.DoCmd.Close acForm, myObj.fullname
        dctDelete.Add "FO" & myObj.fullname, acForm
    Next
    For Each myObj In oApplication.CurrentProject.AllModules
        WScript.Echo "  " & myObj.fullname
        oApplication.SaveAsText acModule, myObj.fullname, sExportpath & "\" & myObj.fullname & ".bas"
        dctDelete.Add "MO" & myObj.fullname, acModule
    Next
    For Each myObj In oApplication.CurrentProject.AllMacros
        WScript.Echo "  " & myObj.fullname
        oApplication.SaveAsText acMacro, myObj.fullname, sExportpath & "\" & myObj.fullname & ".mac"
        dctDelete.Add "MA" & myObj.fullname, acMacro
    Next
    For Each myObj In oApplication.CurrentProject.AllReports
        WScript.Echo "  " & myObj.fullname
        oApplication.SaveAsText acReport, myObj.fullname, sExportpath & "\" & myObj.fullname & ".report"
        dctDelete.Add "RE" & myObj.fullname, acReport
    Next

    WScript.Echo "deleting..."
    dim sObjectname
    For Each sObjectname In dctDelete
        WScript.Echo "  " & Mid(sObjectname, 3)
        oApplication.DoCmd.DeleteObject dctDelete(sObjectname), Mid(sObjectname, 3)
    Next

    oApplication.CloseCurrentDatabase
    oApplication.CompactRepair sStubADPFilename, sStubADPFilename & "_"
    oApplication.Quit

    fso.CopyFile sStubADPFilename & "_", sStubADPFilename
    fso.DeleteFile sStubADPFilename & "_"


End Function

Public Function getErr()
    Dim strError
    strError = vbCrLf & "----------------------------------------------------------------------------------------------------------------------------------------" & vbCrLf & _
               "From " & Err.source & ":" & vbCrLf & _
               "    Description: " & Err.Description & vbCrLf & _
               "    Code: " & Err.Number & vbCrLf
    getErr = strError
End Function

Jeśli potrzebujesz polecenia, które można kliknąć, zamiast używać wiersza poleceń, utwórz plik o nazwie „decompose.cmd” z

cscript decompose.vbs youraccessapplication.adp

Domyślnie wszystkie wyeksportowane pliki trafiają do podfolderu „Skrypty” aplikacji Access. Plik .adp / mdb jest również kopiowany do tej lokalizacji (z przyrostkiem „stub”) i usuwany ze wszystkich wyeksportowanych modułów, dzięki czemu jest naprawdę mały.

MUSISZ sprawdzić ten kod w plikach źródłowych, ponieważ większości ustawień dostępu i niestandardowych pasków menu nie można wyeksportować w żaden inny sposób. Tylko pamiętaj, aby zatwierdzić zmiany w tym pliku tylko wtedy, gdy naprawdę zmieniłeś jakieś ustawienie lub menu.

Uwaga: Jeśli masz zdefiniowane Autoexec-Makros w swojej Aplikacji, być może będziesz musiał przytrzymać klawisz Shift podczas wywoływania dekompozycji, aby zapobiec jej wykonywaniu i zakłócaniu eksportu!

Oczywiście istnieje również skrypt odwrotny do zbudowania Aplikacji z katalogu "Source":

compose.vbs:

' Usage:
'  WScript compose.vbs <file> <path>

' Converts all modules, classes, forms and macros in a directory created by "decompose.vbs"
' and composes then into an Access Project file (.adp). This overwrites any existing Modules with the
' same names without warning!!!
' Requires Microsoft Access.

Option Explicit

const acForm = 2
const acModule = 5
const acMacro = 4
const acReport = 3

Const acCmdCompileAndSaveAllModules = &H7E

' BEGIN CODE
Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")

dim sADPFilename
If (WScript.Arguments.Count = 0) then
    MsgBox "Please enter the file name!", vbExclamation, "Error"
    Wscript.Quit()
End if
sADPFilename = fso.GetAbsolutePathName(WScript.Arguments(0))

Dim sPath
If (WScript.Arguments.Count = 1) then
    sPath = ""
else
    sPath = WScript.Arguments(1)
End If


importModulesTxt sADPFilename, sPath

If (Err <> 0) and (Err.Description <> NULL) Then
    MsgBox Err.Description, vbExclamation, "Error"
    Err.Clear
End If

Function importModulesTxt(sADPFilename, sImportpath)
    Dim myComponent
    Dim sModuleType
    Dim sTempname
    Dim sOutstring

    ' Build file and pathnames
    dim myType, myName, myPath, sStubADPFilename
    myType = fso.GetExtensionName(sADPFilename)
    myName = fso.GetBaseName(sADPFilename)
    myPath = fso.GetParentFolderName(sADPFilename)

    ' if no path was given as argument, use a relative directory
    If (sImportpath = "") then
        sImportpath = myPath & "\Source\"
    End If
    sStubADPFilename = sImportpath & myName & "_stub." & myType

    ' check for existing file and ask to overwrite with the stub
    if (fso.FileExists(sADPFilename)) Then
        WScript.StdOut.Write sADPFilename & " exists. Overwrite? (y/n) "
        dim sInput
        sInput = WScript.StdIn.Read(1)
        if (sInput <> "y") Then
            WScript.Quit
        end if

        fso.CopyFile sADPFilename, sADPFilename & ".bak"
    end if

    fso.CopyFile sStubADPFilename, sADPFilename

    ' launch MSAccess
    WScript.Echo "starting Access..."
    Dim oApplication
    Set oApplication = CreateObject("Access.Application")
    WScript.Echo "opening " & sADPFilename & " ..."
    If (Right(sStubADPFilename,4) = ".adp") Then
        oApplication.OpenAccessProject sADPFilename
    Else
        oApplication.OpenCurrentDatabase sADPFilename
    End If
    oApplication.Visible = false

    Dim folder
    Set folder = fso.GetFolder(sImportpath)

    ' load each file from the import path into the stub
    Dim myFile, objectname, objecttype
    for each myFile in folder.Files
        objecttype = fso.GetExtensionName(myFile.Name)
        objectname = fso.GetBaseName(myFile.Name)
        WScript.Echo "  " & objectname & " (" & objecttype & ")"

        if (objecttype = "form") then
            oApplication.LoadFromText acForm, objectname, myFile.Path
        elseif (objecttype = "bas") then
            oApplication.LoadFromText acModule, objectname, myFile.Path
        elseif (objecttype = "mac") then
            oApplication.LoadFromText acMacro, objectname, myFile.Path
        elseif (objecttype = "report") then
            oApplication.LoadFromText acReport, objectname, myFile.Path
        end if

    next

    oApplication.RunCommand acCmdCompileAndSaveAllModules
    oApplication.Quit
End Function

Public Function getErr()
    Dim strError
    strError = vbCrLf & "----------------------------------------------------------------------------------------------------------------------------------------" & vbCrLf & _
               "From " & Err.source & ":" & vbCrLf & _
               "    Description: " & Err.Description & vbCrLf & _
               "    Code: " & Err.Number & vbCrLf
    getErr = strError
End Function

Ponownie dotyczy to towarzyszącego pliku „compose.cmd” zawierającego:

cscript compose.vbs youraccessapplication.adp

Prosi o potwierdzenie zastąpienia bieżącej aplikacji i najpierw tworzy kopię zapasową, jeśli to zrobisz. Następnie zbiera wszystkie pliki źródłowe w katalogu źródłowym i ponownie wstawia je do kodu pośredniczącego.

Baw się dobrze!

Oliver
źródło
1
Uwielbiam ten kod. Okazało się, że oApplication.OpenAccessProject nie działa na pliku accdb (a może jest to sprawa Access 2007) i zamiast tego musiałem użyć oApplication.OpenCurrentDatabase.
hughdbrown
1
Robię coś podobnego (SaveAsText, ale w VBA i z plikiem MDB zamiast ADP), ale został mi jeden duży problem: po każdym eksporcie Subversion rozpoznaje około 100 plików jako zmienione (nawet jeśli zmieniłem tylko jeden lub dwa ). kiedy patrzę na zmiany, widzę, że niektóre nazwy zmiennych lub nazwy elementów sterujących zmieniły pisownię na duże / małe litery. Na przykład: każdy plik, który kiedyś zawierał „Numer zamówienia”, zawiera teraz „Numer zamówienia” w eksporcie i dlatego jest oznaczony jako „zmieniony” (przynajmniej przez SVN, nie wypróbował jeszcze innego SCM). Masz jakiś pomysł, jak mogę tego uniknąć? Wielkie dzięki!
Christian Specht
3
Tak, jest to również ciągła irytacja w naszym projekcie. O ile ustaliliśmy, problem polega na tym, że zmienne w twoim projekcie mają takie same nazwy jak kontrolki, tylko w różnych przypadkach (góra / dół). Teraz, w zależności od kolejności komponowanych modułów, Access wydaje się przyjmować jedną pisownię i „korelować” wszystkie inne, ponieważ VBA ma nie uwzględniać wielkości liter. Program Access to robi, mimo że kontrolki mają różne formy! Problem staje się większy, jeśli masz nawet wiele kontrolek o tej samej nazwie w różnych przypadkach w różnych formularzach.
Oliver
3
Jedynym rozwiązaniem jest wytropienie każdej zmiennej / nazwy kontrolnej i zmiana pisowni na zwykłą formę. Po wyeksportowaniu i zatwierdzeniu zmian nazwy powinny być stabilne. Przedrostki nazw kontrolek ich typami prawie zapewniają, dzięki konwencji nazewnictwa, że ​​nazwy nie kolidują ze zmiennymi. (np. txtTitle dla pola tekstowego zawierającego pole Tytuł lub cmbUsers dla pola combo itd.)
Oliver
Zapomniałem dodać, że aby uzyskać tę pracę z mdb, musiałem zmienić OpenAccessProject na OpenCurrentDatabase .
DaveParillo
19

Wydaje się, że jest to coś całkiem dostępnego w programie Access:

To łącze z witryny msdn wyjaśnia, jak zainstalować dodatek kontroli źródła dla programu Microsoft Access. Jest to dostarczane bezpłatnie jako część rozszerzeń Access Developer dla programu Access 2007 oraz jako oddzielny bezpłatny dodatek do programu Access 2003.

Cieszę się, że zadałeś to pytanie i poświęciłem czas, aby je sprawdzić, ponieważ ta umiejętność też mi się spodobała. Powyższy link zawiera więcej informacji na ten temat i linki do dodatków.

Aktualizacja:
Zainstalowałem dodatek dla Access 2003. Będzie działał tylko z VSS, ale pozwala mi umieszczać obiekty Access (formularze, kwerendy, tabele, moduły itp.) W repozytorium. Kiedy idziesz edytować dowolny element w repozytorium, zostaniesz poproszony o jego sprawdzenie, ale nie musisz. Następnie sprawdzę, jak radzi sobie z otwieraniem i zmianą w systemach bez dodatku. Nie jestem fanem VSS, ale bardzo podoba mi się myśl o przechowywaniu obiektów dostępu w repozytorium.

Aktualizacja2:
Maszyny bez dodatku nie mogą wprowadzać żadnych zmian w strukturze bazy danych (dodawać pola tabeli, parametry zapytań itp.). Na początku pomyślałem, że może to być problem, jeśli ktoś będzie musiał, ponieważ nie było widocznego sposobu usunięcia bazy danych Access z kontroli źródła, jeśli Access nie miał załadowanego dodatku.

Odkryłem, że uruchomiona baza danych „Kompaktuj i napraw” wyświetla monit, czy chcesz usunąć bazę danych z kontroli źródła. Zdecydowałem się tak i mogłem edytować bazę danych bez dodatku. Artykuł w powyższym łączu zawiera również instrukcje dotyczące konfigurowania programu Access 2003 i 2007 do korzystania z systemu Team System. Jeśli możesz znaleźć dostawcę MSSCCI dla SVN, istnieje duża szansa, że ​​zadziała.

Brettski
źródło
Zwróć uwagę, że mieliśmy sporo problemów z niemożliwością pobrania ADP z VSS, jeśli edytowała go więcej niż jedna osoba. Skończyło się na tym, że musieliśmy mieć do tego oddzielną kopię zapasową!
Simon
Bawiłem się tym podejściem (używając Vault, ponieważ nie znam żadnych darmowych dostawców MSSCCI dla SVN ... TortoiseSVNSCC nie jest konserwowany i nie działa dla mnie, a pozostałe dwie lub trzy opcje są komercyjne). Działa, ale zmusza cię do korzystania z archaicznego podejścia polegającego na blokowaniu na wyłączność do kontroli źródła iz tego powodu planuję porzucić to i użyć rozwiązania @ Oliver.
Todd Owen
14

Rozwiązanie Compose / Decompose opublikowane przez Olivera jest świetne, ale ma pewne problemy:

  • Pliki są zakodowane jako UCS-2 (UTF-16), co może spowodować, że systemy / narzędzia kontroli wersji będą traktować pliki jako binarne.
  • Pliki zawierają wiele okruchów, które często się zmieniają - sumy kontrolne, informacje o drukarce i nie tylko. Jest to poważny problem, jeśli chcesz wyczyścić różnice lub musisz współpracować przy projekcie.

Planowałem to naprawić samodzielnie, ale odkryłem, że jest już dostępne dobre rozwiązanie: integracja timabell / msaccess-vcs- on GitHub. Przetestowałem integrację msaccess-vcs i działa świetnie.

Zaktualizowano 3 marca 2015 : Projekt był pierwotnie utrzymywany / należał do bkidwell na Github, ale został przeniesiony do timabell - powyższy link do projektu jest odpowiednio aktualizowany. Istnieje kilka wideł z oryginalnego projektu bkidwell, na przykład ArminBra i matonb , których AFAICT nie powinien być używany.

Wadą korzystania z integracji msaccess-vcs-w porównaniu z rozwiązaniem Oliversa decompose:

  • Jest znacznie wolniejszy. Jestem pewien, że problem z szybkością można naprawić, ale nie muszę tak często eksportować projektu do tekstu ...
  • Nie tworzy projektu dostępu do kodu źródłowego z usuniętymi wyeksportowanymi elementami. Można to również naprawić (adoptując kod ze skryptu dekompozycji), ale znowu - nie jest to takie ważne.

W każdym razie moje wyraźne zalecenie to integracja msaccess-vcs. Rozwiązał wszystkie problemy, jakie miałem z używaniem Gita na eksportowanych plikach.

hansfn
źródło
Wygląda na to, że widelec ArminBra jest teraz do przodu (wynika z wykresu sieci ). Matonb nie odpowiedział na jedyne żądanie ściągnięcia, więc myślę, że przynajmniej na razie go porzucili.
Tim Abell
1
A teraz jest też mój widelec github.com/timabell/msaccess-vcs-integration - naprawia błąd eksportu tabeli kluczy złożonych. Pozostałe dwa wyglądają na nieco opuszczone, więc z przyjemnością przyjmuję raporty o błędach itp. Na moim rozwidleniu.
Tim Abell,
Grzecznie zasugerowałbym edycję tej odpowiedzi, aby wskazać mój fork, ponieważ jest to obecnie najbardziej aktywnie zarządzana wersja.
Tim Abell
2
@TimAbell: Zaktualizowałem swoją odpowiedź, aby odzwierciedlić fakt, że projekt został Ci przekazany. PS! Mam nadzieję, że uda nam się zdobyć kilka głosów, ponieważ uważam, że to najlepsze rozwiązanie.
hansfn
2
fajny, poruszanie się po rozwidleniach projektu github wydaje się być ostatnim problemem, jaki sobie wymyśliliśmy :-)
Tim Abell
14

Olivers odpowiada, że CurrentProjectdziała , ale odniesienie nie działa dla mnie. Skończyło się na tym, że wyrwałem wnętrzności ze środka jego eksportu i zastąpiłem je tym, w oparciu o podobne rozwiązanie Arvina Meyera . Ma tę zaletę, że eksportuje zapytania, jeśli używasz mdb zamiast adp.

' Writes database componenets to a series of text files
' @author  Arvin Meyer
' @date    June 02, 1999
Function DocDatabase(oApp)
    Dim dbs 
    Dim cnt 
    Dim doc 
    Dim i
    Dim prefix
    Dim dctDelete
    Dim docName

    Const acQuery = 1

    Set dctDelete = CreateObject("Scripting.Dictionary")

    Set dbs = oApp.CurrentDb() ' use CurrentDb() to refresh Collections
    Set cnt = dbs.Containers("Forms")
    prefix = oApp.CurrentProject.Path & "\"
    For Each doc In cnt.Documents
        oApp.SaveAsText acForm, doc.Name, prefix & doc.Name & ".frm"
        dctDelete.Add "frm_" & doc.Name, acForm
    Next

    Set cnt = dbs.Containers("Reports")
    For Each doc In cnt.Documents
        oApp.SaveAsText acReport, doc.Name, prefix & doc.Name & ".rpt"
        dctDelete.Add "rpt_" & doc.Name, acReport
    Next

    Set cnt = dbs.Containers("Scripts")
    For Each doc In cnt.Documents
        oApp.SaveAsText acMacro, doc.Name, prefix & doc.Name & ".vbs"
        dctDelete.Add "vbs_" & doc.Name, acMacro
    Next

    Set cnt = dbs.Containers("Modules")
    For Each doc In cnt.Documents
        oApp.SaveAsText acModule, doc.Name, prefix & doc.Name & ".bas"
        dctDelete.Add "bas_" & doc.Name, acModule
    Next

    For i = 0 To dbs.QueryDefs.Count - 1
        oApp.SaveAsText acQuery, dbs.QueryDefs(i).Name, prefix & dbs.QueryDefs(i).Name & ".txt"
        dctDelete.Add "qry_" & dbs.QueryDefs(i).Name, acQuery
    Next

    WScript.Echo "deleting " & dctDelete.Count & " objects."
    For Each docName In dctDelete
        WScript.Echo "  " & Mid(docName, 5)
        oApp.DoCmd.DeleteObject dctDelete(docName), Mid(docName, 5)
    Next

    Set doc = Nothing
    Set cnt = Nothing
    Set dbs = Nothing
    Set dctDelete = Nothing

End Function
DaveParillo
źródło
1
+1 za dołączanie zapytań. Teraz wystarczy dołączyć schematy tabeli.
Marc Stober
Zatwierdzona odpowiedź nie działa w programie Access 97, ale ta odpowiedź pomogła mi zmodyfikować ją do własnych celów. Dziękuję za wysłanie tego!
CTristan
2
Gorąco zachęcam do umieszczenia zapisywania zapytania przed zapisaniem formularzy, aby później zmienić kolejność usuwania. Miałem problemy z DeleteObject w ostatniej instrukcji For Each, kiedy próbowałem usunąć zapytania, które zostały już automatycznie usunięte, gdy odpowiadające im formularze zostały wcześniej usunięte. Ponadto, jeśli masz jakieś formularze otwierające się podczas uruchamiania i nie chcesz trzymać klawisza F11 (lub mieć go dezaktywowany), po prostu wstaw oApp.DoCmd.Close acForm, „formName” po uruchomieniu przez cnt.Documents
Anton Kaiser
@Cunso Proszę, czy możesz opublikować swój kod, który jest zgodny z Access 97. Więc nie muszę go przebudowywać.
Lorenz Meyer,
jak tego używam? Zadzwonić z łodzi podwodnej?
kevinykuo
11

Opracowaliśmy własne narzędzie wewnętrzne, w którym:

  1. Moduły: są eksportowane jako pliki txt, a następnie porównywane z „narzędziem do porównywania plików” (bezpłatne)
  2. Formularze: są eksportowane za pomocą polecenia undocument application.saveAsText. Następnie można zobaczyć różnice między 2 różnymi wersjami (ponownie „narzędzie porównywania plików”).
  3. Makra: nie mamy żadnego makra do porównania, ponieważ mamy tylko makro „autoexec” z jedną linią uruchamiającą główną procedurę VBA
  4. Zapytania: to po prostu ciągi tekstowe przechowywane w tabeli: patrz poniżej
  5. tabele: napisaliśmy własną funkcję porównującą tabele, wymieniając różnice w rekordach ORAZ strukturze tabeli.

Cały system jest na tyle inteligentny, że pozwala nam tworzyć wersje „runtime” naszej aplikacji Access, automatycznie generowane z plików txt (moduły i formularze odtwarzane za pomocą polecenia undocument application.loadFromText) oraz plików mdb (tabel).

Może to zabrzmieć dziwnie, ale działa.

Philippe Grondier
źródło
8
Chciałbym zobaczyć to narzędzie z otwartym kodem źródłowym!
Todd Owen,
Czy dobrym pomysłem będzie przesłanie tych wyeksportowanych plików tekstowych na GitHub?
Santosh
9

Opierając się na pomysłach z tego postu i podobnych wpisów na niektórych blogach napisałem aplikację, która działa z formatami plików mdb i adp. Importuje / eksportuje wszystkie obiekty bazy danych (w tym tabele, odniesienia, relacje i właściwości bazy danych) do zwykłych plików tekstowych. Dzięki tym plikom możesz pracować z dowolną kontrolą wersji źródła. Następna wersja pozwoli zaimportować z powrotem zwykłe pliki tekstowe do bazy danych. Będzie też narzędzie wiersza poleceń

Aplikację lub kod źródłowy możesz pobrać ze strony: http://accesssvn.codeplex.com/

pozdrowienia

mnieto
źródło
Używamy tego od prawie dwóch lat i jest świetny. Dziękuję Ci!
mcfea
5

Wskrzeszenie starego wątku, ale ten jest dobry. Zaimplementowałem dwa skrypty (compose.vbs / decompose.vbs) dla własnego projektu i napotkałem problem ze starymi plikami .mdb:

Zatrzymuje się, gdy przechodzi do formularza zawierającego kod:

NoSaveCTIWhenDisabled =1

Access twierdzi, że ma problem i to koniec historii. Przeprowadziłem kilka testów i pobawiłem się, próbując obejść ten problem, i znalazłem ten wątek z obejściem na końcu:

Nie można utworzyć bazy danych

Zasadniczo (na wypadek, gdyby wątek przestał działać), bierzemy plik .mdb i robimy „Zapisz jako” w nowym formacie .accdb. Wtedy źródło bezpieczne lub komponuj / dekomponuj będzie działać. Musiałem też bawić się przez 10 minut, aby uzyskać odpowiednią składnię wiersza poleceń, aby skrypty (de) komponowania działały poprawnie, więc oto również te informacje:

Aby komponować (powiedzmy, że twoje rzeczy znajdują się w C: \ SControl (utwórz podfolder o nazwie Source, aby przechowywać rozpakowane pliki):

'(to extract for importing to source control)
cscript compose.vbs database.accdb     

'(to rebuild from extracted files saved from an earlier date)
cscript decompose.vbs database.accdb C:\SControl\Source\

Otóż ​​to!

Wersje programu Access, w których wystąpił powyższy problem, obejmują bazy danych Access 2000-2003 „.mdb” i rozwiązały problem, zapisując je w formatach „.accdb” 2007–2010 przed uruchomieniem skryptów tworzenia / dekompozycji. Po konwersji skrypty działają dobrze!

JKK
źródło
Czy możesz to edytować, aby uwzględnić wersje programu Access, w których napotkasz ten problem?
Nathan DeWitt,
Nie ma problemu, czy nadal pracujesz nad rozwojem dostępu, Nathan? Jeśli tak, to jakiś sukces w integracji go z kontrolą wersji?
JKK
Nie zajmuję się już programowaniem Access. Miałem jeden projekt, którego użyłem w przeszłości, kiedy zadawałem pytanie, i nigdy nie musiałem z nim robić nic więcej.
Nathan DeWitt,
Fajnie, myślę, że większość firm używa jakiegoś dedykowanego serwera SQL. Sytuacja, w której się teraz znajduję, jest połączeniem MS SQL Server, Oracle i wielu baz danych Access, które ściągają dane z serwerów do lokalnych tabel i eksportują do programu Excel. To dość skomplikowana mieszanka. Myślę, że zacznę nowe pytanie na temat sugestii dotyczących utworzenia nowego projektu. Wkrótce zobaczę, co ludzie mogą zasugerować, aby zmniejszyć złożoność
JKK
4

Rozwiązanie oparte wyłącznie na plikach tekstowych (w tym zapytania, tabele i relacje)

Zmieniłem parę skryptów Olivera tak, aby oprócz modułów, klas, formularzy i makr eksportowały / importowały relacje, tabele i zapytania . Wszystko jest zapisywane w zwykłych plikach tekstowych, więc nie ma utworzonego pliku bazy danych do przechowywania z plikami tekstowymi w kontroli wersji.

Eksport do plików tekstowych (decompose.vbs)

' Usage:
'  cscript decompose.vbs <input file> <path>

' Converts all modules, classes, forms and macros from an Access Project file (.adp) <input file> to
' text and saves the results in separate files to <path>.  Requires Microsoft Access.
Option Explicit

Const acForm = 2
Const acModule = 5
Const acMacro = 4
Const acReport = 3
Const acQuery = 1
Const acExportTable = 0

' BEGIN CODE
Dim fso, relDoc, ACCDBFilename, sExportpath
Set fso = CreateObject("Scripting.FileSystemObject")
Set relDoc = CreateObject("Microsoft.XMLDOM")

If (Wscript.Arguments.Count = 0) Then
    MsgBox "Please provide the .accdb database file", vbExclamation, "Error"
    Wscript.Quit()
End If
ACCDBFilename = fso.GetAbsolutePathName(Wscript.Arguments(0))

If (Wscript.Arguments.Count = 1) Then
 sExportpath = ""
Else
 sExportpath = Wscript.Arguments(1)
End If


exportModulesTxt ACCDBFilename, sExportpath

If (Err <> 0) And (Err.Description <> Null) Then
    MsgBox Err.Description, vbExclamation, "Error"
    Err.Clear
End If

Function exportModulesTxt(ACCDBFilename, sExportpath)
    Dim myComponent, sModuleType, sTempname, sOutstring
    Dim myType, myName, myPath, hasRelations
    myType = fso.GetExtensionName(ACCDBFilename)
    myName = fso.GetBaseName(ACCDBFilename)
    myPath = fso.GetParentFolderName(ACCDBFilename)

    'if no path was given as argument, use a relative directory
    If (sExportpath = "") Then
        sExportpath = myPath & "\Source"
    End If
    'On Error Resume Next
    fso.DeleteFolder (sExportpath)
    fso.CreateFolder (sExportpath)
    On Error GoTo 0

    Wscript.Echo "starting Access..."
    Dim oApplication
    Set oApplication = CreateObject("Access.Application")
    Wscript.Echo "Opening " & ACCDBFilename & " ..."
    If (Right(ACCDBFilename, 4) = ".adp") Then
     oApplication.OpenAccessProject ACCDBFilename
    Else
     oApplication.OpenCurrentDatabase ACCDBFilename
    End If
    oApplication.Visible = False

    Wscript.Echo "exporting..."
    Dim myObj
    For Each myObj In oApplication.CurrentProject.AllForms
        Wscript.Echo "Exporting FORM " & myObj.FullName
        oApplication.SaveAsText acForm, myObj.FullName, sExportpath & "\" & myObj.FullName & ".form.txt"
        oApplication.DoCmd.Close acForm, myObj.FullName
    Next
    For Each myObj In oApplication.CurrentProject.AllModules
        Wscript.Echo "Exporting MODULE " & myObj.FullName
        oApplication.SaveAsText acModule, myObj.FullName, sExportpath & "\" & myObj.FullName & ".module.txt"
    Next
    For Each myObj In oApplication.CurrentProject.AllMacros
        Wscript.Echo "Exporting MACRO " & myObj.FullName
        oApplication.SaveAsText acMacro, myObj.FullName, sExportpath & "\" & myObj.FullName & ".macro.txt"
    Next
    For Each myObj In oApplication.CurrentProject.AllReports
        Wscript.Echo "Exporting REPORT " & myObj.FullName
        oApplication.SaveAsText acReport, myObj.FullName, sExportpath & "\" & myObj.FullName & ".report.txt"
    Next
    For Each myObj In oApplication.CurrentDb.QueryDefs
        Wscript.Echo "Exporting QUERY " & myObj.Name
        oApplication.SaveAsText acQuery, myObj.Name, sExportpath & "\" & myObj.Name & ".query.txt"
    Next
    For Each myObj In oApplication.CurrentDb.TableDefs
     If Not Left(myObj.Name, 4) = "MSys" Then
      Wscript.Echo "Exporting TABLE " & myObj.Name
      oApplication.ExportXml acExportTable, myObj.Name, , sExportpath & "\" & myObj.Name & ".table.txt"
      'put the file path as a second parameter if you want to export the table data as well, instead of ommiting it and passing it into a third parameter for structure only
     End If
    Next

    hasRelations = False
    relDoc.appendChild relDoc.createElement("Relations")
    For Each myObj In oApplication.CurrentDb.Relations  'loop though all the relations
    If Not Left(myObj.Name, 4) = "MSys" Then
     Dim relName, relAttrib, relTable, relFoTable, fld
     hasRelations = True

     relDoc.ChildNodes(0).appendChild relDoc.createElement("Relation")
     Set relName = relDoc.createElement("Name")
     relName.Text = myObj.Name
     relDoc.ChildNodes(0).LastChild.appendChild relName

     Set relAttrib = relDoc.createElement("Attributes")
     relAttrib.Text = myObj.Attributes
     relDoc.ChildNodes(0).LastChild.appendChild relAttrib

     Set relTable = relDoc.createElement("Table")
     relTable.Text = myObj.Table
     relDoc.ChildNodes(0).LastChild.appendChild relTable

     Set relFoTable = relDoc.createElement("ForeignTable")
     relFoTable.Text = myObj.ForeignTable
     relDoc.ChildNodes(0).LastChild.appendChild relFoTable

     Wscript.Echo "Exporting relation " & myObj.Name & " between tables " & myObj.Table & " -> " & myObj.ForeignTable

     For Each fld In myObj.Fields   'in case the relationship works with more fields
      Dim lf, ff
      relDoc.ChildNodes(0).LastChild.appendChild relDoc.createElement("Field")

      Set lf = relDoc.createElement("Name")
      lf.Text = fld.Name
      relDoc.ChildNodes(0).LastChild.LastChild.appendChild lf

      Set ff = relDoc.createElement("ForeignName")
      ff.Text = fld.ForeignName
      relDoc.ChildNodes(0).LastChild.LastChild.appendChild ff

      Wscript.Echo "  Involving fields " & fld.Name & " -> " & fld.ForeignName
     Next
    End If
    Next
    If hasRelations Then
     relDoc.InsertBefore relDoc.createProcessingInstruction("xml", "version='1.0'"), relDoc.ChildNodes(0)
     relDoc.Save sExportpath & "\relations.rel.txt"
     Wscript.Echo "Relations successfuly saved in file relations.rel.txt"
    End If

    oApplication.CloseCurrentDatabase
    oApplication.Quit

End Function

Możesz wykonać ten skrypt, wywołując cscript decompose.vbs <path to file to decompose> <folder to store text files>. Jeśli pominiesz drugi parametr, utworzy on folder „Source”, w którym znajduje się baza danych. Należy pamiętać, że folder docelowy zostanie wyczyszczony, jeśli już istnieje.

Uwzględnij dane w wyeksportowanych tabelach

Zastąp wiersz 93: oApplication.ExportXML acExportTable, myObj.Name, , sExportpath & "\" & myObj.Name & ".table.txt"

z linią oApplication.ExportXML acExportTable, myObj.Name, sExportpath & "\" & myObj.Name & ".table.txt"

Importuj do pliku Utwórz bazę danych (compose.vbs)

' Usage:
'  cscript compose.vbs <file> <path>

' Reads all modules, classes, forms, macros, queries, tables and their relationships in a directory created by "decompose.vbs"
' and composes then into an Access Database file (.accdb).
' Requires Microsoft Access.
Option Explicit

Const acForm = 2
Const acModule = 5
Const acMacro = 4
Const acReport = 3
Const acQuery = 1
Const acStructureOnly = 0   'change 0 to 1 if you want import StructureAndData instead of StructureOnly
Const acCmdCompileAndSaveAllModules = &H7E

Dim fso, relDoc, ACCDBFilename, sPath
Set fso = CreateObject("Scripting.FileSystemObject")
Set relDoc = CreateObject("Microsoft.XMLDOM")

If (Wscript.Arguments.Count = 0) Then
 MsgBox "Please provide the .accdb database file", vbExclamation, "Error"
 Wscript.Quit()
End If

ACCDBFilename = fso.GetAbsolutePathName(Wscript.Arguments(0))
If (Wscript.Arguments.Count = 1) Then
 sPath = ""
Else
 sPath = Wscript.Arguments(1)
End If


importModulesTxt ACCDBFilename, sPath

If (Err <> 0) And (Err.Description <> Null) Then
    MsgBox Err.Description, vbExclamation, "Error"
    Err.Clear
End If


Function importModulesTxt(ACCDBFilename, sImportpath)
    Dim myComponent, sModuleType, sTempname, sOutstring

    ' Build file and pathnames
    Dim myType, myName, myPath
    myType = fso.GetExtensionName(ACCDBFilename)
    myName = fso.GetBaseName(ACCDBFilename)
    myPath = fso.GetParentFolderName(ACCDBFilename)

    ' if no path was given as argument, use a relative directory
    If (sImportpath = "") Then
        sImportpath = myPath & "\Source\"
    End If

    ' check for existing file and ask to overwrite with the stub
    If fso.FileExists(ACCDBFilename) Then
     Wscript.StdOut.Write ACCDBFilename & " already exists. Overwrite? (y/n) "
     Dim sInput
     sInput = Wscript.StdIn.Read(1)
     If (sInput <> "y") Then
      Wscript.Quit
     Else
      If fso.FileExists(ACCDBFilename & ".bak") Then
       fso.DeleteFile (ACCDBFilename & ".bak")
      End If
      fso.MoveFile ACCDBFilename, ACCDBFilename & ".bak"
     End If
    End If

    Wscript.Echo "starting Access..."
    Dim oApplication
    Set oApplication = CreateObject("Access.Application")
    Wscript.Echo "Opening " & ACCDBFilename
    If (Right(ACCDBFilename, 4) = ".adp") Then
        oApplication.CreateAccessProject ACCDBFilename
    Else
        oApplication.NewCurrentDatabase ACCDBFilename
    End If
    oApplication.Visible = False

    Dim folder
    Set folder = fso.GetFolder(sImportpath)

    'load each file from the import path into the stub
    Dim myFile, objectname, objecttype
    For Each myFile In folder.Files
     objectname = fso.GetBaseName(myFile.Name)  'get rid of .txt extension
     objecttype = fso.GetExtensionName(objectname)
     objectname = fso.GetBaseName(objectname)

     Select Case objecttype
      Case "form"
       Wscript.Echo "Importing FORM from file " & myFile.Name
       oApplication.LoadFromText acForm, objectname, myFile.Path
      Case "module"
       Wscript.Echo "Importing MODULE from file " & myFile.Name
       oApplication.LoadFromText acModule, objectname, myFile.Path
      Case "macro"
       Wscript.Echo "Importing MACRO from file " & myFile.Name
       oApplication.LoadFromText acMacro, objectname, myFile.Path
      Case "report"
       Wscript.Echo "Importing REPORT from file " & myFile.Name
       oApplication.LoadFromText acReport, objectname, myFile.Path
      Case "query"
       Wscript.Echo "Importing QUERY from file " & myFile.Name
       oApplication.LoadFromText acQuery, objectname, myFile.Path
      Case "table"
       Wscript.Echo "Importing TABLE from file " & myFile.Name
       oApplication.ImportXml myFile.Path, acStructureOnly
      Case "rel"
       Wscript.Echo "Found RELATIONSHIPS file " & myFile.Name & " ... opening, it will be processed after everything else has been imported"
       relDoc.Load (myFile.Path)
     End Select
    Next

    If relDoc.readyState Then
     Wscript.Echo "Preparing to build table dependencies..."
     Dim xmlRel, xmlField, accessRel, relTable, relName, relFTable, relAttr, i
     For Each xmlRel In relDoc.SelectNodes("/Relations/Relation")   'loop through every Relation node inside .xml file
      relName = xmlRel.SelectSingleNode("Name").Text
      relTable = xmlRel.SelectSingleNode("Table").Text
      relFTable = xmlRel.SelectSingleNode("ForeignTable").Text
      relAttr = xmlRel.SelectSingleNode("Attributes").Text

      'remove any possible conflicting relations or indexes
      On Error Resume Next
      oApplication.CurrentDb.Relations.Delete (relName)
      oApplication.CurrentDb.TableDefs(relTable).Indexes.Delete (relName)
      oApplication.CurrentDb.TableDefs(relFTable).Indexes.Delete (relName)
      On Error GoTo 0

      Wscript.Echo "Creating relation " & relName & " between tables " & relTable & " -> " & relFTable
      Set accessRel = oApplication.CurrentDb.CreateRelation(relName, relTable, relFTable, relAttr)  'create the relationship object

      For Each xmlField In xmlRel.SelectNodes("Field")  'in case the relationship works with more fields
       accessRel.Fields.Append accessRel.CreateField(xmlField.SelectSingleNode("Name").Text)
       accessRel.Fields(xmlField.SelectSingleNode("Name").Text).ForeignName = xmlField.SelectSingleNode("ForeignName").Text
       Wscript.Echo "  Involving fields " & xmlField.SelectSingleNode("Name").Text & " -> " & xmlField.SelectSingleNode("ForeignName").Text
      Next

      oApplication.CurrentDb.Relations.Append accessRel 'append the newly created relationship to the database
      Wscript.Echo "  Relationship added"
     Next
    End If

    oApplication.RunCommand acCmdCompileAndSaveAllModules
    oApplication.Quit
End Function

Możesz wykonać ten skrypt, wywołując cscript compose.vbs <path to file which should be created> <folder with text files>. Jeśli pominiesz drugi parametr, zajrzy on do folderu „Source”, w którym powinna zostać utworzona baza danych.

Importuj dane z pliku tekstowego

Zastąpić linię 14, const acStructureOnly = 0z const acStructureOnly = 1. To zadziała tylko wtedy, gdy umieścisz dane w eksportowanej tabeli.

Rzeczy, które nie są objęte gwarancją

  1. Testowałem to tylko z plikami accdb, więc w przypadku czegokolwiek innego mogą występować błędy.
  2. Ustawienia nie są eksportowane, polecam utworzenie makra, które zastosuje ustawienie na początku bazy danych.
  3. Czasami eksportowane są nieznane zapytania poprzedzone znakiem „~”. Nie wiem, czy są potrzebne.
  4. Nazwy obiektów MSAccess mogą zawierać znaki, które są nieprawidłowe dla nazw plików - skrypt zakończy się niepowodzeniem podczas próby ich zapisania. Możesz znormalizować wszystkie nazwy plików , ale wtedy nie możesz ich zaimportować z powrotem.

Jednym z moich innych zasobów podczas pracy nad tym skryptem była ta odpowiedź , która pomogła mi dowiedzieć się, jak eksportować relacje.

Jakub M.
źródło
Wydaje się, że to działa, ale nie rozumie tabel połączonych
Lord Darth Vader
2

Jest pewien problem - VSS 6.0 może akceptować MDB tylko przy użyciu dodatku w ramach określonej liczby obiektów, która obejmuje wszystkie lokalne tabele, zapytania, moduły i formularze. Nie znam dokładnego limitu obiektów.

Aby zbudować naszą 10-letnią aplikację do produkcji podłóg, która jest ogromna, jesteśmy zmuszeni połączyć 3 lub 4 oddzielne MDB z SS w jeden MDB, co komplikuje automatyczne kompilacje do tego stopnia, że ​​nie tracimy czasu na robienie tego.

Myślę, że spróbuję powyższego skryptu, aby wypluć ten MDb do SVN i uprościć kompilacje dla wszystkich.

ChuckB
źródło
2

Dla osób korzystających z Access 2010 SaveAsText nie jest widoczną metodą w Intellisense, ale wydaje się, że jest to poprawna metoda, ponieważ wspomniany wcześniej skrypt Arvina Meyera działał dobrze.

Co ciekawe, SaveAsAXL jest nowością w 2010 roku i ma taką samą sygnaturę jak SaveAsText, chociaż wygląda na to, że będzie działać tylko z internetowymi bazami danych, które wymagają SharePoint Server 2010.

Cory
źródło
Opcja SaveAsText nie jest również widoczna w A2003, chyba że w przeglądarce obiektów włączono opcję Pokaż ukrytych członków. Dobre informacje o SaveAsAXL.
David-W-Fenton
2

Niedawno mieliśmy ten sam problem.

Naszą pierwszą próbą było narzędzie innej firmy, które oferuje proxy SourceSafe API dla Subversion do użytku z MS Access i VB 6. Narzędzie można znaleźć tutaj .

Ponieważ nie byliśmy zadowoleni z tego narzędzia, przerzuciliśmy się na Visual SourceSafe i wtyczkę VSS Acces.

Benjamin Brauer
źródło
2

Używam Oasis-Svn http://dev2dev.de/

Mogę tylko powiedzieć, że przynajmniej raz mnie to uratowało. Moje mdb rosło powyżej 2 GB i to go zepsuło. Mógłbym wrócić do starej wersji i zaimportować Formularze i po prostu stracić dzień pracy.

Friedrich
źródło
1

Znalazłem to narzędzie na SourceForge: http://sourceforge.net/projects/avc/

Nie korzystałem z tego, ale może to być dla ciebie początek. Mogą istnieć inne narzędzia innych firm, które integrują się z VSS lub SVN i robią to, czego potrzebujesz.

Osobiście po prostu trzymam pod ręką zwykły plik tekstowy, aby prowadzić dziennik zmian. Kiedy zatwierdzam binarną bazę MDB, używam wpisów w dzienniku zmian jako mojego komentarza do zatwierdzenia.

Patrick Cuff
źródło
Masz link do pobrania? Czy jestem ślepy? Nie mogę tego znaleźć.
BIBD
sourceforge.net/project/showfiles.php?group_id=115226 Brak zdefiniowanych pakietów plików. Yay.
Nathan DeWitt
1

Dla pełności...

Zawsze istnieje „Visual Studio [YEAR] Tools for the Microsoft Office System” ( http://msdn.microsoft.com/en-us/vs2005/aa718673.aspx ), ale wydaje się, że wymaga to VSS. Dla mnie VSS (automatyczne uszkodzenie) jest gorsze niż moje 347 punktów zapisu na moim udziale sieciowym z kopią zapasową Uber.

BIBD
źródło
1

Używam dodatku Access 2003: kontrola kodu źródłowego . To działa dobrze. Jednym z problemów są nieprawidłowe znaki, takie jak „:”.

Melduję się i wychodzę. Wewnętrznie dodatek robi to samo, co kod tam na górze, ale z większą obsługą narzędzi. Mogę sprawdzić, czy obiekt jest wyrejestrowany i odświeżyć obiekty.

Czas letni
źródło
1

Odpowiedź Olivera działa świetnie. Poniżej znajduje się moja rozszerzona wersja, która dodaje obsługę zapytań programu Access.

(proszę zobaczyć odpowiedź od Olivera, aby uzyskać więcej informacji / użytkowania)

decompose.vbs:

' Usage:
'  CScript decompose.vbs <input file> <path>

' Converts all modules, classes, forms and macros from an Access Project file (.adp) <input file> to
' text and saves the results in separate files to <path>.  Requires Microsoft Access.
'
Option Explicit

const acForm = 2
const acModule = 5
const acMacro = 4
const acReport = 3
const acQuery = 1

' BEGIN CODE
Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")

dim sADPFilename
If (WScript.Arguments.Count = 0) then
    MsgBox "Bitte den Dateinamen angeben!", vbExclamation, "Error"
    Wscript.Quit()
End if
sADPFilename = fso.GetAbsolutePathName(WScript.Arguments(0))

Dim sExportpath
If (WScript.Arguments.Count = 1) then
    sExportpath = ""
else
    sExportpath = WScript.Arguments(1)
End If


exportModulesTxt sADPFilename, sExportpath

If (Err <> 0) and (Err.Description <> NULL) Then
    MsgBox Err.Description, vbExclamation, "Error"
    Err.Clear
End If

Function exportModulesTxt(sADPFilename, sExportpath)
    Dim myComponent
    Dim sModuleType
    Dim sTempname
    Dim sOutstring

    dim myType, myName, myPath, sStubADPFilename
    myType = fso.GetExtensionName(sADPFilename)
    myName = fso.GetBaseName(sADPFilename)
    myPath = fso.GetParentFolderName(sADPFilename)

    If (sExportpath = "") then
        sExportpath = myPath & "\Source\"
    End If
    sStubADPFilename = sExportpath & myName & "_stub." & myType

    WScript.Echo "copy stub to " & sStubADPFilename & "..."
    On Error Resume Next
        fso.CreateFolder(sExportpath)
    On Error Goto 0
    fso.CopyFile sADPFilename, sStubADPFilename

    WScript.Echo "starting Access..."
    Dim oApplication
    Set oApplication = CreateObject("Access.Application")
    WScript.Echo "opening " & sStubADPFilename & " ..."
    If (Right(sStubADPFilename,4) = ".adp") Then
        oApplication.OpenAccessProject sStubADPFilename
    Else
        oApplication.OpenCurrentDatabase sStubADPFilename
    End If

    oApplication.Visible = false

    dim dctDelete
    Set dctDelete = CreateObject("Scripting.Dictionary")
    WScript.Echo "exporting..."
    Dim myObj

    For Each myObj In oApplication.CurrentProject.AllForms
        WScript.Echo "  " & myObj.fullname
        oApplication.SaveAsText acForm, myObj.fullname, sExportpath & "\" & myObj.fullname & ".form"
        oApplication.DoCmd.Close acForm, myObj.fullname
        dctDelete.Add "FO" & myObj.fullname, acForm
    Next
    For Each myObj In oApplication.CurrentProject.AllModules
        WScript.Echo "  " & myObj.fullname
        oApplication.SaveAsText acModule, myObj.fullname, sExportpath & "\" & myObj.fullname & ".bas"
        dctDelete.Add "MO" & myObj.fullname, acModule
    Next
    For Each myObj In oApplication.CurrentProject.AllMacros
        WScript.Echo "  " & myObj.fullname
        oApplication.SaveAsText acMacro, myObj.fullname, sExportpath & "\" & myObj.fullname & ".mac"
        dctDelete.Add "MA" & myObj.fullname, acMacro
    Next
    For Each myObj In oApplication.CurrentProject.AllReports
        WScript.Echo "  " & myObj.fullname
        oApplication.SaveAsText acReport, myObj.fullname, sExportpath & "\" & myObj.fullname & ".report"
        dctDelete.Add "RE" & myObj.fullname, acReport
    Next
    For Each myObj In oApplication.CurrentDb.QueryDefs
        if not left(myObj.name,3) = "~sq" then 'exclude queries defined by the forms. Already included in the form itself
            WScript.Echo "  " & myObj.name
            oApplication.SaveAsText acQuery, myObj.name, sExportpath & "\" & myObj.name & ".query"
            oApplication.DoCmd.Close acQuery, myObj.name
            dctDelete.Add "FO" & myObj.name, acQuery
        end if
    Next

    WScript.Echo "deleting..."
    dim sObjectname
    For Each sObjectname In dctDelete
        WScript.Echo "  " & Mid(sObjectname, 3)
        oApplication.DoCmd.DeleteObject dctDelete(sObjectname), Mid(sObjectname, 3)
    Next

    oApplication.CloseCurrentDatabase
    oApplication.CompactRepair sStubADPFilename, sStubADPFilename & "_"
    oApplication.Quit

    fso.CopyFile sStubADPFilename & "_", sStubADPFilename
    fso.DeleteFile sStubADPFilename & "_"


End Function

Public Function getErr()
    Dim strError
    strError = vbCrLf & "----------------------------------------------------------------------------------------------------------------------------------------" & vbCrLf & _
               "From " & Err.source & ":" & vbCrLf & _
               "    Description: " & Err.Description & vbCrLf & _
               "    Code: " & Err.Number & vbCrLf
    getErr = strError
End Function

compose.vbs:

' Usage:
'  WScript compose.vbs <file> <path>

' Converts all modules, classes, forms and macros in a directory created by "decompose.vbs"
' and composes then into an Access Project file (.adp). This overwrites any existing Modules with the
' same names without warning!!!
' Requires Microsoft Access.

Option Explicit

const acForm = 2
const acModule = 5
const acMacro = 4
const acReport = 3
const acQuery = 1

Const acCmdCompileAndSaveAllModules = &H7E

' BEGIN CODE
Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")

dim sADPFilename
If (WScript.Arguments.Count = 0) then
    MsgBox "Bitte den Dateinamen angeben!", vbExclamation, "Error"
    Wscript.Quit()
End if
sADPFilename = fso.GetAbsolutePathName(WScript.Arguments(0))

Dim sPath
If (WScript.Arguments.Count = 1) then
    sPath = ""
else
    sPath = WScript.Arguments(1)
End If


importModulesTxt sADPFilename, sPath

If (Err <> 0) and (Err.Description <> NULL) Then
    MsgBox Err.Description, vbExclamation, "Error"
    Err.Clear
End If

Function importModulesTxt(sADPFilename, sImportpath)
    Dim myComponent
    Dim sModuleType
    Dim sTempname
    Dim sOutstring

    ' Build file and pathnames
    dim myType, myName, myPath, sStubADPFilename
    myType = fso.GetExtensionName(sADPFilename)
    myName = fso.GetBaseName(sADPFilename)
    myPath = fso.GetParentFolderName(sADPFilename)

    ' if no path was given as argument, use a relative directory
    If (sImportpath = "") then
        sImportpath = myPath & "\Source\"
    End If
    sStubADPFilename = sImportpath & myName & "_stub." & myType

    ' check for existing file and ask to overwrite with the stub
    if (fso.FileExists(sADPFilename)) Then
        WScript.StdOut.Write sADPFilename & " existiert bereits. Überschreiben? (j/n) "
        dim sInput
        sInput = WScript.StdIn.Read(1)
        if (sInput <> "j") Then
            WScript.Quit
        end if

        fso.CopyFile sADPFilename, sADPFilename & ".bak"
    end if

    fso.CopyFile sStubADPFilename, sADPFilename

    ' launch MSAccess
    WScript.Echo "starting Access..."
    Dim oApplication
    Set oApplication = CreateObject("Access.Application")
    WScript.Echo "opening " & sADPFilename & " ..."
    If (Right(sStubADPFilename,4) = ".adp") Then
        oApplication.OpenAccessProject sADPFilename
    Else
        oApplication.OpenCurrentDatabase sADPFilename
    End If
    oApplication.Visible = false

    Dim folder
    Set folder = fso.GetFolder(sImportpath)

    ' load each file from the import path into the stub
    Dim myFile, objectname, objecttype
    for each myFile in folder.Files
        objecttype = fso.GetExtensionName(myFile.Name)
        objectname = fso.GetBaseName(myFile.Name)
        WScript.Echo "  " & objectname & " (" & objecttype & ")"

        if (objecttype = "form") then
            oApplication.LoadFromText acForm, objectname, myFile.Path
        elseif (objecttype = "bas") then
            oApplication.LoadFromText acModule, objectname, myFile.Path
        elseif (objecttype = "mac") then
            oApplication.LoadFromText acMacro, objectname, myFile.Path
        elseif (objecttype = "report") then
            oApplication.LoadFromText acReport, objectname, myFile.Path
        elseif (objecttype = "query") then
           oApplication.LoadFromText acQuery, objectname, myFile.Path
        end if

    next

    oApplication.RunCommand acCmdCompileAndSaveAllModules
    oApplication.Quit
End Function

Public Function getErr()
    Dim strError
    strError = vbCrLf & "----------------------------------------------------------------------------------------------------------------------------------------" & vbCrLf & _
               "From " & Err.source & ":" & vbCrLf & _
               "    Description: " & Err.Description & vbCrLf & _
               "    Code: " & Err.Number & vbCrLf
    getErr = strError
End Function
Daniel Hillebrand
źródło
0

Próbowałem przyczynić się do jego odpowiedzi, dodając opcję eksportu zapytań w bazie danych dostępu. (Z dużą pomocą innych odpowiedzi SO )

Dim def
Set stream = fso.CreateTextFile(sExportpath & "\" & myName & ".queries.txt")
  For Each def In oApplication.CurrentDb.QueryDefs

    WScript.Echo "  Exporting Queries to Text..."
    stream.WriteLine("Name: " & def.Name)
    stream.WriteLine(def.SQL)
    stream.writeline "--------------------------"
    stream.writeline " "

  Next
stream.Close

Nie mogłem włożyć tego z powrotem w funkcję „tworzenia”, ale nie potrzebuję tego teraz.

Uwaga: dodałem również „.txt” do każdej z wyeksportowanych nazw plików w decompose.vbs, aby kontrola źródła natychmiast pokazała mi różnice między plikami.

Mam nadzieję, że to pomoże!


JBickford
źródło
0

Ten wpis opisuje zupełnie inne podejście od innych wpisów i może nie być tym, czego szukasz. Więc nie obrażę się, jeśli to zignorujesz. Ale przynajmniej daje do myślenia.

W niektórych profesjonalnych komercyjnych środowiskach programistycznych zarządzanie konfiguracją (CM) elementów oprogramowania nie jest zwykle wykonywane w samej aplikacji lub w samym projekcie oprogramowania. CM nakłada się na końcowe produkty dostarczane, zapisując oprogramowanie w specjalnym folderze CM, w którym zarówno plik, jak i jego folder są oznaczone identyfikacją wersji. Na przykład Clearcase umożliwia menedżerowi danych „zaewidencjonowanie” pliku oprogramowania, przypisanie mu „gałęzi”, przypisanie mu „dymka” i zastosowanie „etykiet”. Jeśli chcesz zobaczyć i pobrać plik, musisz skonfigurować swoją "specyfikację konfiguracyjną", aby wskazywała żądaną wersję, a następnie cd do folderu i tam jest.

Tylko pomysł.

VolleyballAddictSandiego
źródło
0

Dla każdego, kto utknął w Access 97, nie udało mi się uzyskać innych odpowiedzi. Korzystając z kombinacji doskonałych odpowiedzi Olivera i DaveParillo oraz wprowadzając pewne modyfikacje, udało mi się sprawić, by skrypty działały z naszymi bazami danych Access 97. Jest też nieco bardziej przyjazny dla użytkownika, ponieważ pyta, w którym folderze umieścić pliki.

AccessExport.vbs:

' Converts all modules, classes, forms and macros from an Access file (.mdb) <input file> to
' text and saves the results in separate files to <path>.  Requires Microsoft Access.
Option Explicit

Const acQuery = 1
Const acForm = 2
Const acModule = 5
Const acMacro = 4
Const acReport = 3
Const acCmdCompactDatabase = 4
Const TemporaryFolder = 2

Dim strMDBFileName : strMDBFileName = SelectDatabaseFile
Dim strExportPath : strExportPath = SelectExportFolder
CreateExportFolders(strExportPath)
Dim objProgressWindow
Dim strOverallProgress
CreateProgressWindow objProgressWindow
Dim strTempMDBFileName
CopyToTempDatabase strMDBFileName, strTempMDBFileName, strOverallProgress
Dim objAccess
Dim objDatabase
OpenAccessDatabase objAccess, objDatabase, strTempMDBFileName, strOverallProgress
ExportQueries objAccess, objDatabase, objProgressWindow, strExportPath, strOverallProgress
ExportForms objAccess, objDatabase, objProgressWindow, strExportPath, strOverallProgress
ExportReports objAccess, objDatabase, objProgressWindow, strExportPath, strOverallProgress
ExportMacros objAccess, objDatabase, objProgressWindow, strExportPath, strOverallProgress
ExportModules objAccess, objDatabase, objProgressWindow, strExportPath, strOverallProgress
objAccess.CloseCurrentDatabase
objAccess.Quit
DeleteTempDatabase strTempMDBFileName, strOverallProgress
objProgressWindow.Quit
MsgBox "Successfully exported database."

Private Function SelectDatabaseFile()
    MsgBox "Please select the Access database to export."
    Dim objFileOpen : Set objFileOpen = CreateObject("SAFRCFileDlg.FileOpen")
    If objFileOpen.OpenFileOpenDlg Then
        SelectDatabaseFile = objFileOpen.FileName
    Else
        WScript.Quit()
    End If
End Function

Private Function SelectExportFolder()
    Dim objShell : Set objShell = CreateObject("Shell.Application")
    SelectExportFolder = objShell.BrowseForFolder(0, "Select folder to export the database to:", 0, "").self.path & "\"
End Function

Private Sub CreateExportFolders(strExportPath)
    Dim objFileSystem : Set objFileSystem = CreateObject("Scripting.FileSystemObject")
    MsgBox "Existing folders from a previous Access export under " & strExportPath & " will be deleted!"
    If objFileSystem.FolderExists(strExportPath & "Queries\") Then
        objFileSystem.DeleteFolder strExportPath & "Queries", true
    End If
    objFileSystem.CreateFolder(strExportPath & "Queries\")
    If objFileSystem.FolderExists(strExportPath & "Forms\") Then
        objFileSystem.DeleteFolder strExportPath & "Forms", true
    End If
    objFileSystem.CreateFolder(strExportPath & "Forms\")
    If objFileSystem.FolderExists(strExportPath & "Reports\") Then
        objFileSystem.DeleteFolder strExportPath & "Reports", true
    End If
    objFileSystem.CreateFolder(strExportPath & "Reports\")
    If objFileSystem.FolderExists(strExportPath & "Macros\") Then
        objFileSystem.DeleteFolder strExportPath & "Macros", true
    End If
    objFileSystem.CreateFolder(strExportPath & "Macros\")
    If objFileSystem.FolderExists(strExportPath & "Modules\") Then
        objFileSystem.DeleteFolder strExportPath & "Modules", true
    End If
    objFileSystem.CreateFolder(strExportPath & "Modules\")
End Sub

Private Sub CreateProgressWindow(objProgressWindow)
    Set objProgressWindow = CreateObject ("InternetExplorer.Application")
    objProgressWindow.Navigate "about:blank"
    objProgressWindow.ToolBar = 0
    objProgressWindow.StatusBar = 0
    objProgressWindow.Width = 320
    objProgressWindow.Height = 240
    objProgressWindow.Visible = 1
    objProgressWindow.Document.Title = "Access export in progress"
End Sub

Private Sub CopyToTempDatabase(strMDBFileName, strTempMDBFileName, strOverallProgress)
    strOverallProgress = strOverallProgress & "Copying to temporary database...<br/>"
    Dim objFileSystem : Set objFileSystem = CreateObject("Scripting.FileSystemObject")
    strTempMDBFileName = objFileSystem.GetSpecialFolder(TemporaryFolder) & "\" & objFileSystem.GetBaseName(strMDBFileName) & "_temp.mdb"
    objFileSystem.CopyFile strMDBFileName, strTempMDBFileName
End Sub

Private Sub OpenAccessDatabase(objAccess, objDatabase, strTempMDBFileName, strOverallProgress)
    strOverallProgress = strOverallProgress & "Compacting temporary database...<br/>"
    Set objAccess = CreateObject("Access.Application")
    objAccess.Visible = false
    CompactAccessDatabase objAccess, strTempMDBFileName
    strOverallProgress = strOverallProgress & "Opening temporary database...<br/>"
    objAccess.OpenCurrentDatabase strTempMDBFileName
    Set objDatabase = objAccess.CurrentDb
End Sub

' Sometimes the Compact Database command errors out, and it's not serious if the database isn't compacted first.
Private Sub CompactAccessDatabase(objAccess, strTempMDBFileName)
    On Error Resume Next
    Dim objFileSystem : Set objFileSystem = CreateObject("Scripting.FileSystemObject")
    objAccess.DbEngine.CompactDatabase strTempMDBFileName, strTempMDBFileName & "_"
    objFileSystem.CopyFile strTempMDBFileName & "_", strTempMDBFileName
    objFileSystem.DeleteFile strTempMDBFileName & "_"
End Sub

Private Sub ExportQueries(objAccess, objDatabase, objProgressWindow, strExportPath, strOverallProgress)
    strOverallProgress = strOverallProgress & "Exporting Queries (Step 1 of 5)...<br/>"
    Dim counter
    For counter = 0 To objDatabase.QueryDefs.Count - 1
        objProgressWindow.Document.Body.InnerHTML = strOverallProgress & counter + 1 & " of " & objDatabase.QueryDefs.Count
        objAccess.SaveAsText acQuery, objDatabase.QueryDefs(counter).Name, strExportPath & "Queries\" & Clean(objDatabase.QueryDefs(counter).Name) & ".sql"
    Next
End Sub

Private Sub ExportForms(objAccess, objDatabase, objProgressWindow, strExportPath, strOverallProgress)
    strOverallProgress = strOverallProgress & "Exporting Forms (Step 2 of 5)...<br/>"
    Dim counter : counter = 1
    Dim objContainer : Set objContainer = objDatabase.Containers("Forms")
    Dim objDocument
    For Each objDocument In objContainer.Documents
        objProgressWindow.Document.Body.InnerHTML = strOverallProgress & counter & " of " & objContainer.Documents.Count
        counter = counter + 1
        objAccess.SaveAsText acForm, objDocument.Name, strExportPath & "Forms\" & Clean(objDocument.Name) & ".form"
        objAccess.DoCmd.Close acForm, objDocument.Name
    Next
End Sub

Private Sub ExportReports(objAccess, objDatabase, objProgressWindow, strExportPath, strOverallProgress)
    strOverallProgress = strOverallProgress & "Exporting Reports (Step 3 of 5)...<br/>"
    Dim counter : counter = 1
    Dim objContainer : Set objContainer = objDatabase.Containers("Reports")
    Dim objDocument
    For Each objDocument In objContainer.Documents
        objProgressWindow.Document.Body.InnerHTML = strOverallProgress & counter & " of " & objContainer.Documents.Count
        counter = counter + 1
        objAccess.SaveAsText acReport, objDocument.Name, strExportPath & "Reports\" & Clean(objDocument.Name) & ".report"
    Next
End Sub

Private Sub ExportMacros(objAccess, objDatabase, objProgressWindow, strExportPath, strOverallProgress)
    strOverallProgress = strOverallProgress & "Exporting Macros (Step 4 of 5)...<br/>"
    Dim counter : counter = 1
    Dim objContainer : Set objContainer = objDatabase.Containers("Scripts")
    Dim objDocument
    For Each objDocument In objContainer.Documents
        objProgressWindow.Document.Body.InnerHTML = strOverallProgress & counter & " of " & objContainer.Documents.Count
        counter = counter + 1
        objAccess.SaveAsText acMacro, objDocument.Name, strExportPath & "Macros\" & Clean(objDocument.Name) & ".macro"
    Next
End Sub

Private Sub ExportModules(objAccess, objDatabase, objProgressWindow, strExportPath, strOverallProgress)
    strOverallProgress = strOverallProgress & "Exporting Modules (Step 5 of 5)...<br/>"
    Dim counter : counter = 1
    Dim objContainer : Set objContainer = objDatabase.Containers("Modules")
    Dim objDocument
    For Each objDocument In objContainer.Documents
        objProgressWindow.Document.Body.InnerHTML = strOverallProgress & counter & " of " & objContainer.Documents.Count
        counter = counter + 1
        objAccess.SaveAsText acModule, objDocument.Name, strExportPath & "Modules\" & Clean(objDocument.Name) & ".module"
    Next
End Sub

Private Sub DeleteTempDatabase(strTempMDBFileName, strOverallProgress)
    On Error Resume Next
    strOverallProgress = strOverallProgress & "Deleting temporary database...<br/>"
    Dim objFileSystem : Set objFileSystem = CreateObject("Scripting.FileSystemObject")
    objFileSystem.DeleteFile strTempMDBFileName, true
End Sub

' Windows doesn't like certain characters, so we have to filter those out of the name when exporting
Private Function Clean(strInput)
    Dim objRegexp : Set objRegexp = New RegExp
    objRegexp.IgnoreCase = True
    objRegexp.Global = True
    objRegexp.Pattern = "[\\/:*?""<>|]"
    Dim strOutput
    If objRegexp.Test(strInput) Then
        strOutput = objRegexp.Replace(strInput, "")
        MsgBox strInput & " is being exported as " & strOutput
    Else
        strOutput = strInput
    End If
    Clean = strOutput
End Function

W przypadku importowania plików do bazy danych, jeśli trzeba będzie ponownie utworzyć bazę danych od podstaw lub z jakiegoś powodu chcesz zmodyfikować pliki poza programem Access.

AccessImport.vbs:

' Imports all of the queries, forms, reports, macros, and modules from text
' files to an Access file (.mdb).  Requires Microsoft Access.
Option Explicit

const acQuery = 1
const acForm = 2
const acModule = 5
const acMacro = 4
const acReport = 3
const acCmdCompileAndSaveAllModules = &H7E

Dim strMDBFilename : strMDBFilename = SelectDatabaseFile
CreateBackup strMDBFilename
Dim strImportPath : strImportPath = SelectImportFolder
Dim objAccess
Dim objDatabase
OpenAccessDatabase objAccess, objDatabase, strMDBFilename
Dim objProgressWindow
Dim strOverallProgress
CreateProgressWindow objProgressWindow
ImportQueries objAccess, objDatabase, objProgressWindow, strImportPath, strOverallProgress
ImportForms objAccess, objDatabase, objProgressWindow, strImportPath, strOverallProgress
ImportReports objAccess, objDatabase, objProgressWindow, strImportPath, strOverallProgress
ImportMacros objAccess, objDatabase, objProgressWindow, strImportPath, strOverallProgress
ImportModules objAccess, objDatabase, objProgressWindow, strImportPath, strOverallProgress
objAccess.CloseCurrentDatabase
objAccess.Quit
objProgressWindow.Quit
MsgBox "Successfully imported objects into the database."

Private Function SelectDatabaseFile()
    MsgBox "Please select the Access database to import the objects from.  ALL EXISTING OBJECTS WITH THE SAME NAME WILL BE OVERWRITTEN!"
    Dim objFileOpen : Set objFileOpen = CreateObject( "SAFRCFileDlg.FileOpen" )
    If objFileOpen.OpenFileOpenDlg Then
        SelectDatabaseFile = objFileOpen.FileName
    Else
        WScript.Quit()
    End If
End Function

Private Function SelectImportFolder()
    Dim objShell : Set objShell = WScript.CreateObject("Shell.Application")
    SelectImportFolder = objShell.BrowseForFolder(0, "Select folder to import the database objects from:", 0, "").self.path & "\"
End Function

Private Sub CreateBackup(strMDBFilename)
    Dim objFileSystem : Set objFileSystem = CreateObject("Scripting.FileSystemObject")
    objFileSystem.CopyFile strMDBFilename, strMDBFilename & ".bak"
End Sub

Private Sub OpenAccessDatabase(objAccess, objDatabase, strMDBFileName)
    Set objAccess = CreateObject("Access.Application")
    objAccess.OpenCurrentDatabase strMDBFilename
    objAccess.Visible = false
    Set objDatabase = objAccess.CurrentDb
End Sub

Private Sub CreateProgressWindow(ByRef objProgressWindow)
    Set objProgressWindow = CreateObject ("InternetExplorer.Application")
    objProgressWindow.Navigate "about:blank"
    objProgressWindow.ToolBar = 0
    objProgressWindow.StatusBar = 0
    objProgressWindow.Width = 320
    objProgressWindow.Height = 240
    objProgressWindow.Visible = 1
    objProgressWindow.Document.Title = "Access import in progress"
End Sub

Private Sub ImportQueries(objAccess, objDatabase, objProgressWindow, strImportPath, strOverallProgress)
    strOverallProgress = "Importing Queries (Step 1 of 5)...<br/>"
    Dim counter : counter = 0
    Dim folder : Set folder = objFileSystem.GetFolder(strImportPath & "Queries\")
    Dim objFileSystem : Set objFileSystem = CreateObject("Scripting.FileSystemObject")
    Dim file
    Dim strQueryName
    For Each file in folder.Files
        objProgressWindow.Document.Body.InnerHTML = strOverallProgress & counter + 1 & " of " & folder.Files.Count
        strQueryName = objFileSystem.GetBaseName(file.Name)
        objAccess.LoadFromText acQuery, strQueryName, file.Path
        counter = counter + 1
    Next
End Sub

Private Sub ImportForms(objAccess, objDatabase, objProgressWindow, strImportPath, strOverallProgress)
    strOverallProgress = strOverallProgress & "Importing Forms (Step 2 of 5)...<br/>"
    Dim counter : counter = 0
    Dim folder : Set folder = objFileSystem.GetFolder(strImportPath & "Forms\")
    Dim objFileSystem : Set objFileSystem = CreateObject("Scripting.FileSystemObject")
    Dim file
    Dim strFormName
    For Each file in folder.Files
        objProgressWindow.Document.Body.InnerHTML = strOverallProgress & counter + 1 & " of " & folder.Files.Count
        strFormName = objFileSystem.GetBaseName(file.Name)
        objAccess.LoadFromText acForm, strFormName, file.Path
        counter = counter + 1
    Next
End Sub

Private Sub ImportReports(objAccess, objDatabase, objProgressWindow, strImportPath, strOverallProgress)
    strOverallProgress = strOverallProgress & "Importing Reports (Step 3 of 5)...<br/>"
    Dim counter : counter = 0
    Dim folder : Set folder = objFileSystem.GetFolder(strImportPath & "Reports\")
    Dim objFileSystem : Set objFileSystem = CreateObject("Scripting.FileSystemObject")
    Dim file
    Dim strReportName
    For Each file in folder.Files
        objProgressWindow.Document.Body.InnerHTML = strOverallProgress & counter + 1 & " of " & folder.Files.Count
        strReportName = objFileSystem.GetBaseName(file.Name)
        objAccess.LoadFromText acReport, strReportName, file.Path
        counter = counter + 1
    Next
End Sub

Private Sub ImportMacros(objAccess, objDatabase, objProgressWindow, strImportPath, strOverallProgress)
    strOverallProgress = strOverallProgress & "Importing Macros (Step 4 of 5)...<br/>"
    Dim counter : counter = 0
    Dim folder : Set folder = objFileSystem.GetFolder(strImportPath & "Macros\")
    Dim objFileSystem : Set objFileSystem = CreateObject("Scripting.FileSystemObject")
    Dim file
    Dim strMacroName
    For Each file in folder.Files
        objProgressWindow.Document.Body.InnerHTML = strOverallProgress & counter + 1 & " of " & folder.Files.Count
        strMacroName = objFileSystem.GetBaseName(file.Name)
        objAccess.LoadFromText acMacro, strMacroName, file.Path
        counter = counter + 1
    Next
End Sub

Private Sub ImportModules(objAccess, objDatabase, objProgressWindow, strImportPath, strOverallProgress)
    strOverallProgress = strOverallProgress & "Importing Modules (Step 5 of 5)...<br/>"
    Dim counter : counter = 0
    Dim folder : Set folder = objFileSystem.GetFolder(strImportPath & "Modules\")
    Dim objFileSystem : Set objFileSystem = CreateObject("Scripting.FileSystemObject")
    Dim file
    Dim strModuleName
    For Each file in folder.Files
        objProgressWindow.Document.Body.InnerHTML = strOverallProgress & counter + 1 & " of " & folder.Files.Count
        strModuleName = objFileSystem.GetBaseName(file.Name)
        objAccess.LoadFromText acModule, strModuleName, file.Path
        counter = counter + 1
    Next

    ' We need to compile the database whenever any module code changes.
    If Not objAccess.IsCompiled Then
        objAccess.RunCommand acCmdCompileAndSaveAllModules
    End If
End Sub
CTristan
źródło