tags:

views:

208

answers:

2

I have Delphi application that has been in production for several years now and recently a specific piece of code has stopped working. In the OnClose event for the form I have the following:

procedure TfrmPublicEmpInfo.FormClose(Sender: TObject;var Action: TCloseAction);  
var
  i : integer;  
  strWorkDays : string;  
begin  
  If cbMonday.Checked then strWorkDays := strWorkDays + 'Mo';  
  If cbTuesday.Checked then strWorkdays := strWorkDays + 'Tu';  
  If cbWednesday.Checked then strWorkdays := strWorkDays + 'We';  
  If cbThursday.Checked then strWorkdays := strWorkDays + 'Th';  
  If cbFriday.Checked then strWorkdays := strWorkDays + 'Fr';  
  If cbSaturday.Checked then strWorkdays := strWorkDays + 'Sa';  
  If cbSunday.Checked then strWorkdays := strWorkDays + 'Su';  
  if strWorkDays <> '' then    
  begin  
    qryPubEmployees.Edit;  
    qryPubEmployees.FieldValues['OCCUPATION'] := strWorkDays;  
  end;  

  dtpPEEndTimeChange(self);   
  dtpPEStartTimeChange(self);  

  For i := 0 to ComponentCount - 1 do  
  begin  
    If Components[i] is TQuery Then  
      with Components[i] as TQuery do  
      begin  
        if State = dsEdit then  
        post;  
      end;  
  end;  
end;

It gets to the dtpPEEndTimeChange(self) call which is this:

procedure TfrmPublicEmpInfo.dtpPEEndTimeChange(Sender: TObject);  
begin  
  qryPubEmployees.Edit;  
  dbePEEndTime.Field.Value := StrToInt(FormatDateTime('HHMM', dtpPEEndTime.Time));  
end;  

while in this function the program calls Windows.pas and gets stuck in:

function GetTickCount; external kernel32 name 'GetTickCount';

it never posts the changes to the record.

Does anyone know if any Windows updates may have caused this malfunction? We are currently on Windows XP Professional Version 5.1 SP 3.

+1  A: 

GetTickCount returns Cardinal. If you are storing result to integer variable, it will result to integer overflow when your computer has been up for 25 days or so. I'm just guessing, but that once was problem in our application.

JP
From the Delphi help: 'The elapsed time is stored as a DWORD value. Therefore, the time will wrap around to zero if the system is run continuously for 49.7 days. To avoid this problem, use GetTickCount64.' For this reason, I would never use GetTickCount ...
Edelcom
@Edelcom: That is a bad idea in most cases, as using `GetTickCount64()` unconditionally will limit your software to Windows Vista, Server 2008 and later versions. See http://msdn.microsoft.com/en-us/library/ms724411%28VS.85%29.aspx
mghie
This is a good insight, but not likely to be her problem, as she says it is "freezing" inside a kernel api call. That sounds like stack corruption.
Warren P
A: 

Your code sends off alarm bells in my head.

Unrelated to your problem, I consider it very bad style to have directly executed code in my FormClose event that can cause a chain of other activity. In other words, good style would be that FormClose calls a "PostChanges" procedure, that validates and then posts data.

I also wonder why you have written a For Loop to search your form for TQuery typed objects and call post merely because they are in an Edit state. Shouldn't there be some validation logic?

Secondly, your "OnChange" events are tricky. Almost all OnChange events require code like this:

procedure TfrmPublicEmpInfo.dtpPEEndTimeChange(Sender: TObject);  
begin  
  if FUpdating then exit;  // safety!
  qryPubEmployees.Edit;  
  FUpdating := true; // this part might not be necessary, but you should try it and see if it is, somehow.
  try 
    dbePEEndTime.Field.Value := StrToInt(FormatDateTime('HHMM', dtpPEEndTime.Time));  
  finally
       FUpdating := false;
  end;
end;  

Then you have to set FUpdating to true in your FormClose event, and clear it at the end of FormClose, and prevent extra calls to this event from messing you up. Remember that OnChange gets called NOT ONLY when you type something, but also when you assign dtpPEEndTime.Field.Value by code, so you can get an endless recursion.

Warren P
-1 because, while you provided some good information, you made no effort to answer the original question (and knew you were doing so, as indicated by the first 4 words of your second paragraph).
Ken White
The short summary of my answer: If the code was more readable, the problem would be easier to find.
Warren P
If the original poster wants to solve this problem, I suggest disconnecting the code from the FormClose event, and firing it off separately, from a test-button or menu item.
Warren P