I try to save a Word 2010 document to PDF and then want to do something with the file(name) that the user selected for this purpose in the corresponding dialog.
Also, I would like to make a few preconfigurations of dialog settings.
However, the following macro (in Microsoft Visual basic for Aplications 7.0, i.e. the stuff you get when simply recording and then modifying macros) does not work:
Sub MyMacro()
dim retval as long
dim DidTheExportToPdfActuallyTakePlaceSuccessfully as Boolean
dim WhatWasThePdfFilenameTheUserChoseFinally as String
With Dialogs(wdDialogExportAsFixedFormat)
.ExportFormat = wdExportFormatPDF
.OpenAfterExport = True
.OptimizeFor = wdExportOptimizeForPrint
.Range = wdExportAllDocument
.Item = wdExportDocumentContent
.IncludeDocProps = True
.KeepIRM = True
.CreateBookmarks = wdExportCreateNoBookmarks
.DocStructureTags = True
.BitmapMissingFonts = True
.UseISO19005_1 = False
retval = .Show()
' DidTheExportToPdfActuallyTakePlaceSuccessfully = ???
' WhatWasThePdfFilenameTheUserChoseFinally = ???
end with
end sub
First of all, I get errors in all the lines .ExportFormat etc.
It appears these problems are caused by late binding.
To circumvent this problem I tried to add option strict off on top, but that immediately produces a compilation error ("Base or Compare or Explicit or Private expected").
I also read about reflection, but it seems that things necessary for that according to online findings (such as dim x as System.Type or y.gettype()) don't compile either ...
If I simply remove the offending lines, the dialog shows successfully and the pdf export takes places successfully. However, it seems that retval is always 0, no matter if the file is actually exported or the user hit cancel. Not to mention that extracting the actual pdf filename fails in the same way as does pre-filling the dialog options.
I'm a bit at a loss because all googling and searching through MS online help tends to take me only to almost compatible situations (especially, nothing found compiles, see above). What is the right way to achieve my goal?
Broadly speaking, only the older builtin dialogs in Word support "late bound" named parameters. Since around Word 2000, most (if not all) of them only recognise the early bound members of the Dialog class.
Possible workarounds include
try to use Sendkeys (IMO always difficult to get right at the best of
times)
try to control the Dialog window via WIN32+Windows messages (no idea
on feasibility there)
adapt one of the standard Application FileDialogs as best you can (in
this case, probably Application.FileDialog(msoFileDialogSaveAs) ),
then follow up with your own UserDialog that prompts for any other
options that you need, then call ExportAsFixedFormat to do the work.
(+variations on (c), e.g. do some of it in .NET with a WIndows form)
Related
I'm busy with some word automation and have run into an issue whereby a context menu within a document has items in, that I wish to remove.
Once the document is open, through vba I can remove these items by running the following code;
[VBA]
Dim oContextMenu As CommandBar
Dim oContextMenuItem As CommandBarControl
'Make changes to the ActiceDocument only (this is needed to make any changes to this document).
CustomizationContext = ActiveDocument
For Each oContextMenu In ActiveDocument.CommandBars
If oContextMenu.Type = MsoBarType.msoBarTypePopup Then 'Loop through all the context menus of type (msoBarTypePopup)
For Each oContextMenuItem In oContextMenu.Controls
If (InStr(oContextMenuItem.Caption, "Smokeball")) Then
oContextMenuItem.Delete
End If
Next
End If
Next
If I execute this code and check the document, all contextMenu sub items that contain the text "smokeball" are removed.
When I try move this code to my VB.NET solution (I have no choice of language, so VB it is), I get errors on the CustomizationContext = ActiveDocument line (this line has to be there for it to affect the current document).
The error I get is CustomizationContext' is not a by reference property.
Does anyone know how to get just that ONE line equivalent for vb.net?
Thanks in advance.
EDIT: In case you need to see the vb.net sub:
Private Sub RemoveUnwantedContextMenuItems()
Dim oContextMenu As CommandBar
Dim oContextMenuItem As CommandBarControl
'Make changes to the ActiceDocument only (this is needed to make any changes to this document).
WordApplication.CustomizationContext = WordApplication.ActiveDocument 'This is the error.
For Each oContextMenu In WordApplication.CommandBars
If oContextMenu.Type = MsoBarType.msoBarTypePopup Then 'Loop through all the context menus of type (msoBarTypePopup)
For Each oContextMenuItem In oContextMenu.Controls
If (InStr(oContextMenuItem.Caption, "Smokeball")) Then
oContextMenuItem.Delete()
End If
Next
End If
Next
End Sub
PS - I have also already tried using the .AttachedTemplate as well as .Normal / .NormalTemplate
Jules pointed me in the right direction with his sample code.
After lots of playing around I noticed that somewhere in the solution, the [TYPE] of WordApplication was getting changed to a dynamic type of sorts, hence, it couldn't use CustomizationContext.
My solution was this:
I changed this line;
WordApplication.CustomizationContext = WordApplication.ActiveDocument
To this:
CType(WordApplication, Microsoft.Office.Interop.Word.Application).CustomizationContext = WordApplication.ActiveDocument
Forcing the types to be correct.
Simple solution but took some time.
Thanks to Jules for pointing me in the right direction.
(Points should go to you).
In many compiled languages, calls to Debug.Assert, or their equivalent, are left out of the compiled production code for performance reasons. However, calls to Debug.Assert still appear to execute in the /runtime versions of MS Access applications.
To test this, I added the following to my startup form:
Private Sub Form_Load()
Debug.Assert UserOK()
End Sub
Function UserOK() As Boolean
UserOK = MsgBox("Is everything OK?", vbYesNo, "Test Debug.Assert") = vbYes
End Function
When I run this in a development environment and click [No] on the MsgBox, execution breaks at the Debug.Assert line (as I would expect).
When I run the same code with the /runtime switch (using a full version of MS Access 2002) I still see the MsgBox, but clicking on [No] does not halt program execution. It seems VBA executes the line but ignores the result. This is not surprising, but it is unfortunate.
I was hoping that Access would skip the Debug.Assert line completely. This means that one must take care not to use Debug.Assert lines that would hurt performance, for example:
Debug.Assert DCount("*", "SomeHugeTable", "NonIndexedField='prepare to wait!'") = 0
Is this behavior documented somewhere? The official documentation in Access appears to be pulled verbatim from VB6:
Assert invocations work only within the development environment. When the module is compiled into an executable, the method calls on the Debug object are omitted.
Obviously, MS Access apps cannot be compiled into an executable. Is there a better alternative than the following workaround?
Private Sub Form_Load()
If Not SysCmd(acSysCmdRuntime) Then Debug.Assert UserOK() 'check if Runtime
End Sub
Function UserOK() As Boolean
UserOK = MsgBox("Is everything OK?", vbYesNo, "Test Debug.Assert") = vbYes
End Function
I don't know if it's any better for your particular use case, but there is an alternative that is better, if you're looking to do this in application agnostic VBA code. VBA has Conditional Compilation. Conditional Complication constants can be declared at the module level, but in this case, it will be better to declare it at the project level.
On the menu bar, click Tools>>Project Properties and type a DEBUGMODE = 1 into the "Conditional Compilation Arguments:" field. (Note: DEBUG won't work as it's a keyword.)
Now you can wrap all of your Debug.Assert() statements in code like this.
#If DEBUGMODE Then
Debug.Assert False
#End If
When you're ready to deploy your project, just go back into the Project Properties dialog and change the argument to DEBUGMODE = 0.
Additional Information:
Utter Access has a fairly comprehensive article on Conditional Compilation.
Directives - MSDN VB 6.0 Language Reference.
I'd like to run a user form with status bar.
I show my form with code bolow.
How should I declare variables and assigning new values to those variables?
Very important: I have to use late binding in my project.
Sub RunMyUserForm()
With MyUserForm
.LabelProgress.Width = 0
.TextBox1 = 1
'to make the progress bar color match the workbook's current theme:
.LabelProgress.BackColor = ActiveWorkbook.Theme.ThemeColorScheme.Colors(msoThemeAccent1)
.Show vbModeless
End With
End Sub
Thank you in advance for your help!
Updated information:
When I try to run my macro with "Option Explicit", it doesn't work (Compile error: Variable not defined - part of code msoThemeAccent1 is marked as yellow color). That's why I asked for help in defining the variables.
When I try to run my macro without "Option Explicit", it dosen't work (Err.Description: "Value is out of range", Err.Number: -2147024809)
When I try to run my macro with early binding (reference to "MS Office Object Library" via Tools/References in VBE) everything works perfect with (and without) "Option Explicit".
Your compiler is seeing msoThemeAccent1 as a variable, and it is undeclared. This is why your code won't run with Option Explicit and also why your code raises an error when you disable Option Explicit. .Colors is a 1-based collection (?) so when you call:
ActiveWorkbook.Theme.ThemeColorScheme.Colors(msoThemeAccent1)
It is compiling to:
ActiveWorkbook.Theme.ThemeColorScheme.Colors(0)
Which raises an expected, albeit cryptic error.
I used some code to check the value of this constant, but in hindsight I should have just referred to the documentation:
http://office.microsoft.com/en-us/excel-help/HV080559557.aspx
This should fix it for you
ActiveWorkbook.Theme.ThemeColorScheme.Colors(5)
Alternatively, if you need to rely on this value in several places in your code, you could declare a variable (public or private, scope depends on what you need it for).
Public Const myAccentColor1 as Long = 5
And then, in your code you could:
ActiveWorkbook.Theme.ThemeColorScheme.Colors(myAccentColor1)
Revised
I understand now, without reference to MS Office Object Library this makes sense. This is one of the few libraries that I maintain a reference to in my XLSB file, so my confusion was a result of the fact that I thought I was using an appropriate late-binding, but I was really using early-binding.
For this question, I refer to the post below to clarify myself:
Why is my conditional format offset when added by VBA?
In many, many posts I see these days, OP's are silently allowed to use .Activate, .Select, .Offset, etc... while they are an open door to potential bugs (most often caused by the end users).
The code is sometimes even supported.
My question: Is there one valid situation where you would use any of these statements without direct alternatives being available that catch typical bugs resulting from these stmts?
I'm referring to dynamic solutions that in my opinion are a must when developing for Excel.
Personally, in more than 6 years I can't remember a single case where I needed it; it seems always to be one of the the worst options available. In my previous company, it was a silent rule never to use it and it only made my VBA life (and that of the end user) better.
Why I create this question is because I think that it is worthful to make newcomers into VBA aware of the risks they take when using these statements (by experience proven risks when the End Users do something unexpected - in the end they don't have any affection with VBA) and to propose direct alternatives (I won't state I always did that before myself, but I feel in my gut that there is something wrong with just offering quick solutions on already bug monsters).
I believe that when silently allowed (which it automatically enhances in this case), starting VBA developers will create a growing amount of tools the wrong way (and thus also newcomers will inherit the behaviour - which they will also learn from Stack Overflow since Google returns the results they look for (!)).
If the developer is not aware why he "can" use a "select" and in which situations it is a potential bug, (s)he should never use it imho. Personally I might use the select stmt in the immediate window to do some quick checks on dynamic range definition (bug mode), but not in written code.
The result makes VBA in the end even more unpopular than it is already; the language will be made the victim in case trouble appear (yet it is imho still the "best" programming support available for the Excel and Access applications). I've seen this happen too many times in a large company where VBA is always "shit".
This is only my own honest experience.
It is not a question of being right or wrong; I am interested in hearing your point of view on the question.
I agree about Select and Activate, but not ActiveWorkbook, ActiveSheet, and ActiveCell (I agree that they are abused, but not that they should be avoided, per se). There are definitely legitimate uses for those. I have a program that automates a "fill series" that does so from the ActiveCell. My program can't predict what cells will be used; it's up the user to select it. That's part of the user interface.
However, there are three situations where I have had to use Select (now four that I read about zoom, but I don't ever use it).
Conditional Formatting. There is a work around using Application.ConvertFormula, but it's worse than just storing the selection, selecting the right cell, doing the deed, and reselecting the previous selection.
Data Validation. Same reason.
Shapes. I wish I could remember the details, but it's been too long since I've worked with Shapes. There was something I couldn't do without selecting the shape first.
Ridding code of Select and Activate is a noble fight.
There are a few methods in Excel that require Activate or ActiveSheet/ActiveWorkbook etc as I've been caught with a gotchas on occasion. The only one I can remember at the moment is the zoom property. Zoom affects only the sheet that's currently active in the window so to zoom all sheets you would need something like
Sub SetZoom()
Dim ws As Worksheet
Application.screenupdating = false
For Each ws In Worksheets
ws.Select
ActiveWindow.Zoom = 80
Next ws
Application.screenupdating = true
End Sub
You can use .Select to determine what a user's view is after running code - for example if you create a new workbook in your code, without using Activate or Select your user may not know this happens.
I frequently end a long operation creating a new workbook or other largescale data manipulations with
FinalViewWorkbook.FinalViewSheet.Range("A1").Select
Just to inform the end user about something - "oh, this created a new workbook of reports!" etc.
I think it is important in this matter to distinguish some:
Active-something: Only use this if it is absolutely necessary to know what the user is handling right now. In my experience, this is usually Data Validation or Active Sheet Detection (e.g. "Update the Sheet where the user just pressed a button").
Selection: Somewhat the same as Active, only use readingly. Userful either for Data Validation, or for gimmicks like "Interpret the cell value as path and open it in a new Explorer Window".
Select, Activate: Imho different from Selection, as it actually changes the selected Cell, Sheet etc. Never ever use this to read or write data, since it enables a user to mess up your program by just clicking. Users love to click. Only use this to Zoom (see answer by #user3357963) or clean up a view after your code has finished working (see answer by #enderland). (I'm not sure, but I think handling the PageView also requires ActiveSheet).
Select, Activate the 2nd: If you are new to VBA and are learning via Macro Recorder, you will find a lot of code generated like this:
First Range("A5").Select, then Selection.Value="NewValue". Join this to Range("A5").Value="NewValue".
Offset: Personally, I don't have a problem using .Offset() - I never encountered problems with this command. Instead, I think it's a handy way of saying "The cell next to this" without having to go through "This cell's sheet at this cell's row and column+1" every time.
In many, many posts I see these days, OP's are silently allowed to use .Activate, .Select, .Offset, etc...
I agree with this. Even though it's easier to just give the necessary answer to make a piece of code work, the use of ActiveCell.Value and the like should be discouraged. This will be much easier if there's a well explained Thread to link to, as this here is hopefully becoming :-)
From my perspective, with few exceptions, the only time you should use Select is as a user input, and only then after careful consideration of alternative design/UI requirements.
For example, I'd say it's generally not advisable to rely on Selection to let user define a Range object when this method keeps execution within the code:
Dim myRange as Range
Set myRange = Application.InputBox("Select your range", Type:=8)
However, if you need to prompt users to select a particular shape or object on the worksheet, then maybe it's better to let them make a Selection (however, this can open up a Pandora's Box of problems without good error-handling and logic to prevent undesired user actions...).
Here is an example of one such exception that I have in PowerPoint. I have some RibbonUI XML and VBA that adds buttons to the Shapes right-click context menu in PowerPoint, and adds similar buttons to the Ribbon itself. These are seamless UI that give the end-user a more "native" experience with the application -- users want to be able to right-click the chart and then run some macro procedures against that selected chart or table, etc. They don't want to press a button to open up a user form and scroll through a listbox of generic shape names or GUIDs.
The procedure code needs to examine the Selection in order to handle it properly so I can use something like below, where
Sub UpdateOrEditSelection(update As Boolean)
'This procedure invoked when user edits/updates a chart.
Dim uid As Variant
Dim sel As Selection
Dim s As Integer
Dim chartsToUpdate As Object
Dim multipleShapes As Boolean
Dim sld As Slide
Set sel = ppPres.Windows(1).Selection
If update Then
Set chartsToUpdate = CreateObject("Scripting.Dictionary")
Select Case sel.Type
Case ppSelectionShapes
For s = 1 To sel.ShapeRange.count
uid = sel.ShapeRange(s).Name
'....
'...
'..
'.
Next
Case ppSelectionSlides
For Each sld In sel.SlideRange
For s = 1 To sld.Shapes.count
uid = sld.Shapes(s).Name
'....
'...
'..
'.
Next
Next
Case ppSelectionText
s = 1
If sel.ShapeRange(s).HasTable Or sel.ShapeRange(s).HasChart Then
uid = sel.ShapeRange(s).Name
'....
'...
'..
'.
End If
End Select
'....
'...
'..
'.
Where does it come from?
The Macro Recorder. Essentially, this feature records every literal user input: scrolling, selecting, viewing, activating, default properties, etc., to the point of overkill. While this is sometimes helpful, it does encourage bad code written by people who don't know that it's bad, but I will not belabor that point which has been made here:
How to avoid using Select in Excel VBA macros
What is better, conceptually?
Program to the objects directly. If you're merely using VBA to mimic keystrokes and mouseclicks, you're doing it wrong.
Exceptions:
I've found when applying formatting to series data in charts, where Select is occasionally necessary. This seems IMO to be a bug with Excel and not a design feature.
Other applications (because VBA is not only Excel):
Word is a different animal, which relies a lot more on Selection object
In PowerPoint there are some sort of operations that can only be performed when the application and slide/shape are visible or otherwise in view. While you don't usually need to "select" anything, it does require more cumbersome code.
I found this snippet in my App:
Set tb = cht.Shapes.AddTextbox(msoTextOrientationHorizontal, ptLeft, tBoxTop, ptWidth, ptHeight)
tb.Select '<--- KEEP THIS LINE OTHERWISE TEXTBOX ALIGNMENT WILL NOT WORK ## ## ##
And this:
'PPT requires selecting the slide in order to export an image preview/jpg
sld.Select
ppPres.Windows(1).View.GotoSlide sld.SlideIndex
sld.Shapes(1).Chart.Export imgPath, ppShapeFormatJPG
And this, dealing with individual Point objects:
pt.Select
pt.format.Line.Visible = msoTrue
pt.format.Line.Visible = msoFalse
pt.MarkerSize = pt.MarkerSize + 2
This is not an exhaustive list, just some examples of exceptions that I found. While these were from PowerPoint, the charts in PowerPoint use the same object model as Excel so I would not be surprised if some of these also need to be hacked in Excel, and Word, too.
Outlook: I don't do much with Outlook, it is a lot like Word and actually uses the Word object model in the Inspector, but what little I do with Outlook does rely on things like ActiveInspector, etc.
Neither Word or PowerPoint have a "macro recorder" anymore (actually, I think Word might but it's so damn impotent as to be useless) and by the time most people do any development in other applications, they've figured most of this out already.
I am supporting an application which was running for the past 3 years. It was developed completely in MS Access and written in VBA.
Suddenly the application is facing the mentioned error at the following lines:
DoCmd.OpenForm FormName:="frmNewPeerGroup", View:=acNormal, windowmode:=acWindowNormal, OpenArgs:=5
FrmNewPeerGroup code
Private Sub Form_Open(Cancel As Integer)
Dim lDept As Long, lDiv As Long
lType = OpenArgs 'Supplied by caller
lAssmtVer = 1 'Current
sName = ""
sDescription = ""
dtCreatedDate = Format(Now(), "dd/mm/yyyy")
sCreatedBy = UCase(userPerms.NTLoginName)
lSupervisorID = userPerms.userID
lTeam = 0
With cmbBxType
.RowSourceType = "Value List"
.RowSource = GetValueListDict(pgType)
.Value = lType
.Enabled = (OpenArgs = 1)
End With
With cmbBxVersion
.RowSourceType = "Value List"
.RowSource = GetValueListDict(pgAssmtType)
.Value = lAssmtVer
End With
mgLogoDesc.Visible = False
txtBxCreatedDate.Value = dtCreatedDate
txtBxCreatedBy.Value = sCreatedBy
If OpenArgs = 5 Then
lTeam = oActiveAssmt.TeamID
lDept = GetParentID(aTeams(), CInt(lTeam))
lDiv = GetParentID(aDepts(), CInt(lDept))
With cmbBxDivision
.RowSourceType = "Value List"
.RowSource = GetValueListArray(aDivs())
.Value = lDiv
.Enabled = False
End With
With cmbBxDepartment
.RowSourceType = "Value List"
.RowSource = GetValueListArray(aDepts())
.Value = lDept
.Enabled = False
End With
With cmbBxTeam
.RowSourceType = "Value List"
.RowSource = GetValueListArray(aTeams())
.Value = lTeam
.Enabled = False
End With
Else
With cmbBxDivision
.RowSourceType = "Value List"
.RowSource = GetValueListArray(aDivs())
.Enabled = False
End With
cmbBxDepartment.Enabled = False
cmbBxTeam.Enabled = False
End If
End Sub
Many instances of the DoCmd.OpenForm command are giving the error in a message box saying:
The expression On Click you entered as the event property setting
produced the following error: The OpenForm action was canceled.
- The expression may not result in the name of macro, the name of
a user-defined function, or [Event procedure].
- There may have been an error evaluating the function, event, or macro.
This is the error message I am receiving.
My problem is, the same code was running around 3 years, but suddenly some updates to Microsoft or Office might be giving trouble to this code.
Did anyone come across this error in the past weeks? Please let me know what else we can do to make this work again.
This thread is very old but I came across the same error and spent a few hours looking for an answer. I was able to find the cause after some time and thought of posting my answer as it may help someone in a similar situation. Creating a application using Access Forms is new to me, so the error message was not directly intuitive.
My forms were Master table data entry forms and configured to be Pop-up and Modal with Me.Form.Name sent as parameter in the DoCmd.OpenForm command using a button (OnClick event) placed next to the Combo controls on a transaction form to allow user to quickly add new records. This parameter value was picked up in the Form_Open(Cancel As Integer) event and used later to refresh the combo box (Forms!<formname>.Controls!<controlname>.Requery) once data was submitted to the master table using the pop-up form.
It appears that the Open event doesn't occur when you activate a form that's already open (ref: https://msdn.microsoft.com/en-us/library/office/aa211439(v=office.11).aspx). Each time I received the error, my data entry form was open in Design view in Access. So I closed the form in design mode, and repeated the steps. And Voila! no error!
Since I will have more than one forms open, I now need to test and try to use Form_Activate() as recommended in the above MSDN reference link.
I don't know if this qualifies as an answer, but the code in that OnOpen event is dependent on a lot of outside functions. Specifically, the code is assigning value lists for the RowSources of a bunch of combo boxes. The immediate red flag that occurs to me is that non-SQL Rowsources have a finite length, and in Access 97, that limit was 2048 characters (in Access 2003, it's 32,750 -- don't ask me why it's that number!).
So, the immediate thing I see is that perhaps what ever data drives the functions that create those value lists has begun to exceed 2048 characters in length.
If that's the actual answer, then you can write a callback function that will return the values in the arrays, and it won't have the limitation on the returned length. You'd set the RowsourceType to the name of your callback function and leave the Rowsource property blank.
An example of the callback function is found in the A97 help (though I can't find the same example in the A2K3 help). In A97 help, you get there by searching for RowsourceType, and then in the help window, click on the link in the sentence reading "You can also set the RowSourceType property with a ____user-defined function____."
To check this out, you just need to find out the length of the string returned from GetValueListArray() by each of the arrays referenced in the OnOpen event.
It also might be helpful to add an error handler to the OnOpen event, particularly given that there are so many outside dependencies in the code in that particular sub.
And last of all, let me say that it looks like horrible programming. Most of this ought to be settable with default properties, seems to me. I also question that kind of dependency on OpenArgs with such an undocumented input value. What does "5" mean? And what does "1" mean? Is that documented somewhere? It's just terrible, terrible code, in my opinion.
I'd likely do this with a standalone class module instead, because that will be self-documenting in terms of what does what. You'd set a particular named property to 5 and that would control what the form gets from the class module methods for populating the combo boxes. It would all be in one place, and you could use a meaningful property name to make it clear what the values 5 and 1 represent. It's particularly helpful to do this if you have the same kind of code in the OnOpen event of multiple forms. In that case, it's a no-brainer to move it out of the form modules, and the only question is whether you put it in a regular module or in a standalone class module (as I'm suggesting).
Anyway, perhaps none of this is on point, but it might give you some ideas.
Could it be the security settings is Access? All recent versions of Access has a security settings dialog where you can enable (or disable) macros in the application. I think you will get this error if macros are disabled.
Are you sure one of the required references (VBA IDE > Option > References) isn't missing?
If you're referencing Excel/Word or external objects, are you sure that the references to the type libraries are the right ones (if you're using specific versions instead of doing late binding)
Are you building the MDE on a 64 bit machine by any chance?
What is the code on the form frmNewPeerGroup? What version of Access are you using? If it is 2003, sp3 causes problems for which there is a hotfix. Have you tried decompile and / or compact and repair?
If you have an original mdb, check the references to make sure that none of them are marked MISSING. This is quite a likely reason for problem in that it has suddenly occurred.
To check the references, look at Tools->References on the menu for a code window.
If no references are missing, you could try stepping through the form code to get a more exact idea of where the error is occurring.