2008-04Apr-28
REPLACE FOR ErrorIn(REPLACE)
REPLACE is one of those 174 commands in Visual FoxPro that looks easy at first glance. The only easy thing about REPLACE, though, is the easiness of introducing subtle errors in your code. A well known behavior of REPLACE is that a line like
REPLACE alias.field WITH value
Doesn't replace anything when the current work area is in EOF(); a description that doesn't do the actual behavior justice. In fact, the syntax above only happens to work correctly when there's a random record available in the current work area. When no table is open at all in the current work area, the REPLACE line causes an error 52: "No table is open in the current work area".
What makes this bug so hard to spot is that it's a context dependent error. All you need is one routine that changes the current work area but doesn't restore it properly combined with one routine that uses this REPLACE line without activating the correct work area. Suddenly you have the error, but only when the user triggers the code in a specific order.
Obviously that's not an error you want to have in a COM server or unattended application. Maybe that's a good time to point to the relatively new command
SET TABLEPROMPT OFF
Which doesn't fix the error, but at least doesn't hang your application with a file open dialog when you encounter the problem.
[UPDATE] As has correctly been pointed out: This issue can only become a problem if you omit the IN clause.
Once you switch to using
REPLACE field WITH value IN alias
or any other combination that includes the IN clause, the issue is non-existent. Well, you can still introduce errors
by specifying empty work areas, but those bugs are much easier to spot.
2008-04Apr-18
ActiveX generic fix
After reading my article on dealing with non-responding ActiveX controls, Carlos Alloatti came up with a generic fix for the problem:
*!* Enable ActiveX Windows
#Define GW_CHILD 5
#Define GW_HWNDNEXT 2
Declare Integer GetWindow In win32api As apiGetWindow ;
Integer nhWnd, ;
Integer uCmd
Declare Integer RealGetWindowClass In win32api ;
As apiRealGetWindowClass ;
Integer nhWnd, ;
String @pszType, ;
Integer cchType
Declare Integer EnableWindow In win32api As apiEnableWindow ;
Integer nhWnd, ;
Integer bEnable
Local ;
m.lnChildHWnd As Integer, ;
m.lnCmd As Integer, ;
m.lnEnable As Integer, ;
m.lcClassName As String, ;
m.lnBufferLen As Integer
*!* For testing, change m.lnEnable to 0 to
*!* disable OleControl windows
m.lnEnable = 1
If Thisform.ShowWindow = 2 Or Thisform.ScrollBars > 0 Then
m.lnChildHWnd = apiGetWindow(Thisform.HWnd, GW_CHILD)
Else
m.lnChildHWnd = Thisform.HWnd
Endif
m.lnCmd = GW_CHILD
Do While .T.
m.lnChildHWnd = apiGetWindow(m.lnChildHWnd, m.lnCmd)
If m.lnChildHWnd = 0 Then
Exit
Endif
m.lcClassName = Space(254)
m.lnBufferLen = apiRealGetWindowClass(m.lnChildHWnd, ;
@m.lcClassName, Len(m.lcClassName))
m.lcClassName = Left(m.lcClassName , m.lnBufferLen)
If m.lcClassName == "CtlFrameWork_ReflectWindow" Then
apiEnableWindow(m.lnChildHWnd, m.lnEnable)
Endif
m.lnCmd = GW_HWNDNEXT
Enddo