Probleem met VBA in MSaccess MDE file

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Stefke
  • Registratie: December 2000
  • Laatst online: 19-09 19:48
Ik heb een wat vreemd probleem dat ik nooit eerder ben tegengekomen; ik ben een functie aan het maken die alle controls op een (gekozen) form en die een bepaalde eigenschap in een recordset zet, in VBA, maar als ik de db converteer naar een MDE krijg ik bij het aanroepen van één van de functies deze melding:

Eror 7802: deze opdracht is niet beschikbaar in een mde/ade-database

Mijn errorafhandeling geeft ook aan in welke functie het misgaat. Maar aangezien het een MDE is is het niet mogelijk om de error op te sporen met de debug. Ik zou de error kunnen ondervangen in de code, maar dan werkt de functie niet. Ik kan er niet achter komen welke onderdeel van de VBA deze error oplevert.

Wat deze code doet nogmaals: hij vult een recordset (in het geheugen) met records uit een tabel indien die aan bepaalde voorwaarden voldoen. Deze recordset wordt gekoppeld aan een listbox-control op een form. Deze specifieke code zit in het form zelf (dus geen module)

Dit is de code:
Visual Basic:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
If Not DisableErrorhandling Then On Error GoTo Err_Handler

Dim Ctl As Control
Dim frm As String
Dim obj As AccessObject
Set dbs = Application.CurrentProject
Dim RST_Autorisation As Recordset
Dim STR_Filter As String

Create_RST_Ctls

Dim Row As Variant

Set Ctl = Me!combo_forms
For Each Row In Ctl.ItemsSelected
    frm = Ctl.Column(1, Row)
Next Row

Set Ctl = Nothing

Set RST_Autorisation = CurrentDb.OpenRecordset("SELECT * FROM tbl_autorisation WHERE frmName='" & frm & "'")

For Each obj In dbs.AllForms
    If obj.Name = frm Then
        If Not obj.Name = Me.Name Then
        
        DoCmd.OpenForm obj.Name, acDesign, , , acFormReadOnly, acHidden
        End If
        For Each Ctl In Forms(obj.Name)
            Select Case Ctl.ControlType
            Case acListBox, acComboBox, acTextBox, acOptionGroup, acCheckBox, acCommandButton, acToggleButton, acSubform
                'Debug.Print obj.Name & " | " & Ctl.Name & " | " & Ctl.ControlType 'Debug.Print Ctl.Name
                
                If Ctl.tag Like "*Autorisation*" Then               'controls met een tag "Autorisation" worden opgenomen in de controlslijst
                    RST_Ctls.AddNew
                    
                    STR_Filter = "CtlName = '" & Ctl.Name & "'"     'afhankelijk van keuze group of user het filter samenstellen _
                                                                    dat gebruikt wordt om de lijst voor users of groups samen te stellen
                    If Me!OptionGroup = 1 Then
                        STR_Filter = STR_Filter & " and GroupID = '" & Me!Combo_Groups_Users & "'"
                    ElseIf Me!OptionGroup = 2 Then
                        STR_Filter = STR_Filter & " and UserID = '" & Me!Combo_Groups_Users & "'"
                    End If
                    
                    If Not RST_Autorisation.RecordCount = 0 Then
                        RST_Autorisation.FindFirst STR_Filter
                        If Not RST_Autorisation.NoMatch Then            'weergeven of de betreffende control gelocked is (X) vrijgegeven met Override (O) of niet gelocked (-)
                            'Debug.Print RST_Autorisation!AutorisationType
                            If RST_Autorisation!AutorisationType = "O" Then
                                RST_Ctls!ctl_Autorisation = "O"
                            Else
                                RST_Ctls!ctl_Autorisation = "X"
                            End If
                            RST_Ctls!AutorisationID = RST_Autorisation!AutorisationID
                        Else
                            RST_Ctls!ctl_Autorisation = "-"
                            RST_Ctls!AutorisationID = 0
                        End If
                    End If
                    
                    RST_Ctls!Ctl_Name = Ctl.Name
                    
                    
                    'ONDERSTAAND WERKT ALLEEN VOOR BUTTONS en andere controls met een CAPTION!!!
                    If Not Ctl.ControlTipText = "" And Len(Ctl.ControlTipText) < 25 Then           'de controltiptext van een control wordt overgenomen als _
                                                                'duidelijk leesbare naam (dus niet het controlnaam) van een control indien ingevuld
                        'Debug.Print Ctl.Name & " " & Ctl.ControlTipText
                        RST_Ctls!ctl_Controltiptext = Ctl.ControlTipText
                    ElseIf Ctl.ControlType = acCommandButton Or Ctl.ControlType = acToggleButton Then
                        If Not Ctl.Caption = "" And Len(Ctl.Caption) < 25 Then           'de caption van een control wordt overgenomen als _
                                                                'duidelijk leesbare naam (dus niet het controlnaam) van een control indien ingevuld
                            'Debug.Print Ctl.Name & " " & Ctl.Caption
                            RST_Ctls!ctl_Controltiptext = Ctl.Caption
                        End If
                    Else
                        RST_Ctls!ctl_Controltiptext = CStr(Ctl.Name)
                    End If
                    'RST_Ctls.Sort = "Ctl_name ASC"
                    RST_Ctls.Update
                    'Debug.Print ctl.Name
                End If
            
            Case Else
            
            End Select
        Next Ctl
    End If
Next obj

RST_Ctls.Sort = "Ctl_name ASC"
Set Me!combo_controls.Recordset = RST_Ctls

Exit_Handler:
RST_Ctls.Close
RST_Autorisation.Close

Exit Sub

Err_Handler:
        Call LogError(Err.Number, Err.Description, conMod & ".Show_FrmControls")
        Resume Exit_Handler
End Sub


De code die de recordset in het geheugen klaarzet:
Visual Basic:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Public Sub Create_RST_Ctls()

If Not DisableErrorhandling Then On Error GoTo Err_Handler
Dim Fld As ADODB.Field

Set RST_Ctls = New ADODB.Recordset

With RST_Ctls
    .Fields.Append "AutorisationID", adBigInt, 1, adFldIsNullable
    .Fields.Append "Ctl_Name", adVarChar, 25
    .Fields.Append "Ctl_ControlTipText", adVarChar, 50
    .Fields.Append "Ctl_Autorisation", adVarChar, 1
    .CursorLocation = adUseClient
    .LockType = adLockPessimistic
    .Open
End With

Exit_Handler:
Exit Sub

Err_Handler:
    Call LogError(Err.Number, Err.Description, conMod & ".Create_RST_Ctls")
    Resume Exit_Handler
   
End Sub


Het enige "exotische" aan deze code lijkt me het gebruik van een "virtuele" tabel en deze te koppelen aan een control, maar voor ik alles ga ombouwen is er misschien iemand die er iets zinnings over kan zeggen?


edit: als ik regel 19 en 91 uitschakel (roept de virtuele tabel aan en koppelt deze aan de control) krijg ik nog steeds exact dezelfde foutmelding. Natuurlijk werkt heel de functie dan niet meer, maar als ie misging op het gemis van die 2 regels zou ik toch een andere error mogen verwachten...
Lijkt dus niet hier in te zitten?

Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
stefijn schreef op vrijdag 17 september 2010 @ 21:55:
Eror 7802: deze opdracht is niet beschikbaar in een mde/ade-database
Oftewel: Design mode operaties zijn niet beschikbaar voor mde's. Oftwel: "DoCmd.OpenForm obj.Name, acDesign, , , acFormReadOnly, acHidden" kan niet. :p
edit: als ik regel 19 en 91 uitschakel (roept de virtuele tabel aan en koppelt deze aan de control) krijg ik nog steeds exact dezelfde foutmelding. Natuurlijk werkt heel de functie dan niet meer, maar als ie misging op het gemis van die 2 regels zou ik toch een andere error mogen verwachten...
Lijkt dus niet hier in te zitten?
Goed op weg: met de juiste regelnummer en functie kom je een stuk verder in dit soort gevallen. :)

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • Lustucru
  • Registratie: Januari 2004
  • Niet online

Lustucru

26 03 2016

Met ^^^^
En als ik zo door je code lees hoef je het formulier ook niet in ontwerpmodus te openen. :)

De oever waar we niet zijn noemen wij de overkant / Die wordt dan deze kant zodra we daar zijn aangeland


  • Stefke
  • Registratie: December 2000
  • Laatst online: 19-09 19:48
DoCmd.OpenForm obj.Name, acDesign, , , acFormReadOnly, acHidden

Nu bezien inderdaad logisch dat dit niet kan, tnx :) , maar voor zover ik momenteel weet is dit de enige manier waarop ik alle controls op een bepaald form kan doorlopen? (Namelijk door het in ontwerpweergave te openen, in dit geval niet zichtbaar)
Lustucru schreef op vrijdag 17 september 2010 @ 23:48:
Met ^^^^
En als ik zo door je code lees hoef je het formulier ook niet in ontwerpmodus te openen. :)
Hoe moet ik t dan doen?

Als ik die regel uitschakel (en dus het form niet open) dan krijg ik de volgende melding (niet in MDE)
Error 2450: Kan het formulier niet vinden waarnaar wordt verwezen in een VB-programmacode

For Each obj In dbs.AllForms
If obj.Name = frm Then
'DoCmd.OpenForm obj.Name, acDesign, , , acFormReadOnly, acHidden
For Each Ctl In Forms(obj.Name)

Het gaat mis op de vette regel. Het lijkt er dus op dat ctl in dbs.allforms alleen toegankelijk is voor geopende forms.

[ Voor 37% gewijzigd door Stefke op 18-09-2010 11:35 ]


  • Lustucru
  • Registratie: Januari 2004
  • Niet online

Lustucru

26 03 2016

Yep. Maar dat wil niet zeggen dat het in ontwerpmodus geopend moet zijn.

De oever waar we niet zijn noemen wij de overkant / Die wordt dan deze kant zodra we daar zijn aangeland


  • Stefke
  • Registratie: December 2000
  • Laatst online: 19-09 19:48
Lustucru schreef op zaterdag 18 september 2010 @ 11:52:
Yep. Maar dat wil niet zeggen dat het in ontwerpmodus geopend moet zijn.
Nee...maar dat levert andere problemen op nl. dat de forms hun functionaliteit gaan uitvoeren en dat is in deze situatie niet de bedoeling (bijv. als een form gebaseerd is op een of andere input of gelinked naar een ander form dan komt er een inputscherm, terwijl ik alleen de control moet listen), en bijkomende probleem is dat om autorisatie gaat; het formulier moet laten zien wie welke form mag openen, en welke controls beschikbaar zijn. Ik kan dus wel laten zien welke formulieren iemand mag openen, maar niet welke controls op dat forms te zien zijn en of die wel of niet beschikbaar zijn.

Maar misschien kan ik een of andere workaround verzinnen...bijv. om te voorkomen dat na het openen alle overige code uitgevoerd wordt indien het form door deze code "geopend" wordt. Ik weet in ieder geval wat ik in de MDE-versie niet kan gebruiken

  • Lustucru
  • Registratie: Januari 2004
  • Niet online

Lustucru

26 03 2016

mmm, klinkt ook een beetje als een architectuurprobleem. Anyways, elk formulier heeft een openargs variabele waarmee je vrij simpel uit kun lezen welke argumenten zijn meegegeven bij het openen.

Overigens kun je in een mde geen controls meer verwijderen of toevoegen, dus het nalopen van die controls zou een eenmalige exercitie zijn die je prima kunt uitvoeren in de ontwikkeldatabase. Waarom gebruik je trouwens niethet ingebouwde beveiligingsmodel? Is in de regel wat robuuster dan eigen oplossingen. :)

Verders is er nog de currentproject.allforms collectie die alle (ook ongeopende) formulieren enumereert. Hoever je daarme ekomt weet ik niet, nooit gebruikt.

[ Voor 13% gewijzigd door Lustucru op 18-09-2010 13:19 ]

De oever waar we niet zijn noemen wij de overkant / Die wordt dan deze kant zodra we daar zijn aangeland


  • Stefke
  • Registratie: December 2000
  • Laatst online: 19-09 19:48
Lustucru schreef op zaterdag 18 september 2010 @ 13:13:
mmm, klinkt ook een beetje als een architectuurprobleem. Anyways, elk formulier heeft een openargs variabele waarmee je vrij simpel uit kun lezen welke argumenten zijn meegegeven bij het openen.

Overigens kun je in een mde geen controls meer verwijderen of toevoegen, dus het nalopen van die controls zou een eenmalige exercitie zijn die je prima kunt uitvoeren in de ontwikkeldatabase. Waarom gebruik je trouwens niethet ingebouwde beveiligingsmodel? Is in de regel wat robuuster dan eigen oplossingen. :)

Verders is er nog de currentproject.allforms collectie die alle (ook ongeopende) formulieren enumereert. Hoever je daarme ekomt weet ik niet, nooit gebruikt.
Zoals ik al zei, het is vast niet de meest ideale oplossing :)

Ik ben bekend met het ingebouwde beveiligingsmodel, maar dat wil ik in dit geval bewust niet gebruiken. De reden is niet zo van belang en ik denk dat via VB het ook wel mogelijk moet zijn om datgene wat ik wil qua beveiling op het beveiligingsmodel uit te voeren, maar dat gaat mijn kennis te boven. Vandaar deze oplossing.

Het probleem zit een beetje in het feit dat ik met deze oplossing in de eigenschappen van controls (gewoon in de .tag eigenschap, aangeef dat deze in aanmerking komt voor autorisatie-instellingen. Daarom moet ik de controls nalopen en bij de betreffende controls kijken of er een autorisatierecord bestaat. Op het moment dat het form geopend wordt loop ik dan de controls na om ze een voor een al dan niet op slot te zetten.

Een oplossing zou zijn als ik de controls mét deze info in een tabel opsla. Dat doe ik nu in een virtuele tabel die altijd "onthefly" gemaakt wordt. En het probleem zit in het "onthefly" vullen van een tabel, virtueel of niet.

Nadeel van een echte tabel die gevuld blijft is dan alleen dat als de controls wijzigen dit ook in de tabel moet gebeuren, maar daar zou ik deze functie wellicht voor kunnen gebruiken. De virtuele tabel zorgt er voor dat het altijd bijgewerkt is, maar het nadeel dáárvan is dat ik de controls altijd na moet lopen en dan afhankelijk ben van de forms-collectie, en dat zorgt dus blijkbaar voor dit probleem.
Als ik een echte tabel ga gebruiken dan hoeft de functie in principe maar één keer te lopen, en opnieuw als het formulier gewijzigd is, wat normaliter niet gebeurd. Bij het doorlopen van de autorisaties kan ik dan de controls uit de tabel halen en ben ik niet afhankelijk van het openen van forms.
Op zich zou dat weinig wijzigingen met zich mee brengen.

Volgens mij gebruik is currentproject.allforms ook? Het is ook mogelijk om alle forms na te lopen, daar zit het probleem niet, alleen heb je blijkbaar geen toegang tot de controls op een form tenzij het op enige manier is geopend (al dan niet in designmodus).

[ Voor 4% gewijzigd door Stefke op 19-09-2010 10:20 ]


Acties:
  • 0 Henk 'm!

  • BertS
  • Registratie: September 2004
  • Laatst online: 14-04 17:14
Visual Basic:
1
For Each Ctl In Forms(obj.Name)

werkt inderdaad niet.
Visual Basic:
1
For Each Ctl In Forms(obj.Name).Controls

zou het beter moeten doen.

Houd er overigens rekening mee: als je de info in een werkelijke tabel zet, kan die worden gewijzigd door gebruikers (ook in MDE).

[ Voor 27% gewijzigd door BertS op 20-09-2010 08:05 ]

Pagina: 1