A customer reported a crash of a VFP application while running under the new version of Windows: Vista. The customer code attempted to automate the configuration of the web server (See Automating Web Site Administration Using IIS).
Specifically, there was a scenario under which the user code calling GETOBJECT("IIS://LOCALHOST/W3SVC/1/ROOT") would crash. At the time, the app was displaying a wizard which was a Fox form with some controls on it.
So I wrote some sample code (requires IIS to be installed on WinXP, and IIS with IIS 6 Metabase compatibility on Vista, as well as “Run As Administrator”) to try to reproduce the bug on
FOR i = 1 TO 10000
Of course this worked flawlessly, so the customer sent me a zip file with a VFP runtime EXE that I could run on
Vista is shipping soon, so I need to figure out fast if this was a
After some debugging, I found why it was crashing. A ListBox on the form had the ColumnCount property set to 2, indicating to VFP that there should be 2 columns displayed. However, there was only one column defined in the RowSource property. In this case VFP wasn’t doing the right thing. Simple fix on the customer side: only one column was desired, so set the ColumnCount to 1. Simple fix on the VFP side: handle the case when the ColumnCount doesn’t match the number of items in the RowSource.
I came up with some code that repros the scenario in WinXP below. If you have 2 items in the RowSource, then it works fine. If not, it causes random behavior. In my case, I get “Variable '' is not found.”
Details: internally VFP maintains an Instruction Pointer (IP) that points to the next user code to execute. When executing the GETOBJECT line, it points to the code for that line. When evaluating a RowSource, the RowSource is compiled and the IP is pointed to the compiled code temporarily, then restored. The restoration was not happening if the number of items in the RowSource didn’t match the ColumnCount.
The reason it occurred on
CLOSE DATABASES all
DEFINE CLASS test as Form
ADD OBJECT lst as ListBox
ADD OBJECT tmr as timer WITH interval=1000,enabled=.t.
CREATE CURSOR customer (Company c(10))
INSERT INTO customer VALUES ("One")
INSERT INTO customer VALUES ("Two")
WITH this.lst as ListBox
.RowSourceType=2 && Alias
.RowSource="Customer.company+' asdf ' " && notice only 1 expression
* .RowSource="Customer.company+' asdf ',4 " && This is valid