Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations TouchToneTommy on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Combining signed and unsigned types -widened both operands 3

Status
Not open for further replies.

pierrotsc

Programmer
Nov 25, 2007
358
US
I get this warning when I compile. What do i need to do with the code below to get rid od it?
Thanks.
P

procedure TFrm_Main.Delay(msecs: Integer);
var
FirstTickCount: LongInt;
begin
FirstTickCount := GetTickCount;
repeat
Application.ProcessMessages;
until ((GetTickCount - FirstTickCount) >= LongInt(msecs));
end;
 
Here's an article that describes why you are getting this warning and how to avoid it


Also, you may want to look here also on writing your Delay procedure which also tests to make sure the tickcount hasn't overflowed making your (GetTickCount-FirsttickCount) produce negative values..


(From the article:

Also, as the result is stored in a LongInt, its value will overflow after about 49 days (although I've never found anyone who had been able to get Windows up and running that long to verify). Still, to prepare for the theoretical overflow, we need to include the check )
 
Code:
  repeat
    Application.ProcessMessages;
  until ((GetTickCount - FirstTickCount) >= LongInt(msecs));
Those 3 lines scare the crap outta me. Specifically the second line, I always wrap this. Declare a bool in the class (like fProcessing). Make sure it's false upon that class' creation. In this loop, do it this way...
Code:
  repeat
    if not fProcessing then begin
      fProcessing:= True;
      try
        Application.ProcessMessages;
      finally
        fProcessing:= False;
      end;
    end;
  until ((GetTickCount - FirstTickCount) >= LongInt(msecs));
This will ensure things will not process in the incorrect order. If it's not done doing one process, and you start another, it will MAJORLY screw up all of your code. As mentioned above, basically this procedure could overlap its self (as I've tested thoroughly in the past) and possibly run hundreds even thousands of times at once (thus causing errors such as out of memory or stack overflow)


JD Solutions
 
Get this hint though..
[DCC Hint] UMain.pas(2466): H2077 Value assigned to 'fProcessing' never used

Can i get rid of that?
Thanks.
P
 
JD, I'm not sure I understand your logic on how you wrap Application.ProcessMessages.

When Application.ProcessMessage is executed, fProcessing will always be true..no matter what, but what effect does that have? Application.ProcessMessages doesn't care what value fProcessing has, it simply handles all waiting messages in the message queue.

The compiler hint is complaining about this line:

fProcessing:= True;

This value assigned to fProcessing (TRUE) is never used anywhere, so you'd get the same effect if you set it to False, or not have the line there at all at that point. Obviously the value assigned within the finally block does have an effect since it needs to be false to have the if statement evaluate TRUE.

If this action where as a result of a button click, clicking that button again would still send a message to the queue that would be picked up with the next iteration of Application.ProcessMessages, and cause the same problems you mentioned. That is unless there's more to fProcessing that I don't see?
 
That said, it is important to understand the "dangers" of Application.ProcessMessages. For example, clicking a button that starts a lengthy processes, that would otherwise cause your application to lock up, can be helped by adding Application.ProcessMessages within the process. Your application would seem to still be responsive, you would be able to drag the app windows, hints would still pop up etc. But if you click the same button again, while the first iteration is still working, your going to kick off the same process again.

A good article on the subject can be found here:


An easy way to protect against this kind of action is to disable the button after you click it, and re-enable it after the process completes.
Code:
procedure TForm1.BitBtn1Click(Sender:TObject);
begin
   BitBtn1.Enabled := False;
   try
      ...
      ...
   finally
      BitBtn1.Enabled := True;
   end;
end;
Or Another option would be to add a global boolean field (like fProcessing) and have as a first check to see if the process is already running, to guard against a 2nd iteration starting.
Code:
TForm1 = class(TForm)
...

private
   fProcessing:  Boolean;
end;

Procedure TForm1.FormCreate(Sender:TObject);
begin
   fProcessing := False;
   ...
end;

procedure TForm1.BitBtn1Click(Sender:TObject);
if Not fProcessing then
begin
  fProcessing := True;
  try
     ...
     ...
  finally
    fProcessing := False;
  end;
end;
or another option would be to "disconnect" the event handler associated with the action, that way if it is clicked again, no event handler is called.
Code:
procedure TForm1.BitBtn1Click(Sender:TObject);
begin
   BitBtn1.OnClick := nil;
   try
      ...
      ...
   finally
      BitBtn1.OnClick := BitBtn1Click;
   end;
end;
 
You'll indulge me, but I figure that I should add yet one more point about Application.ProcessMessages.

Since you'd most probably use Application.ProcessMessage on a lengthy process, you may want to allow the user to exit that process, if they feel that it's just taking too long.

Adding a Stop button would allow the lengthy process to stop, but of course it's Application.ProcessMessages itself that allows it to work at all.

By adding a global boolean variable, you can incorporate the current value of Stop to ensure any processing should continue.

Code:
TForm1 = class(TObject)
...

private
   Stop: Boolean;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
   Stop := False;
   StopBtn.Visible := False;
   StartProcessBtn.Visible := True;
   ...
end;

procedure TForm1.StopBtnClick(Sender: TObject);
begin
   Stop := True;
end;

procedure TForm1.StartProcessBtnClick(Sender: TObject);
var
   I:  Integer;
begin
   Stop := False;
   StopBtn.Visible := True;
   try
      StartProcessBtn.Enabled := False;
      try
         While (not Stop) and (<exit condition>) do
         begin
            ....
            Application.ProcessMessages;
         end;

         //or

         For I := 0 to List.Count -1 do
         begin
            ...
            Application.ProcessMessages;
            if Stop then
               Break;
         end;

         //or 

         repeat
            ...
            Application.ProcessMessages;
         until (Stop) or (<exit condition>);
      finally
         StartProcessBtn.Enabled := True;
      end;
   finally
      StopBtn.Visible := False;
   end;
end;
 
majlumbo, that's exactly what I did. If you declare fProcessing inside the method, of course it won't work. It has to be declared in the class. You practically just re-wrote the same thing I mentioned but with a little more detail. The whole point is the fact that it's in a loop. If there were no loop, there would be no problem and therefore no need for this protection. But in a loop, it can and will overlap its self if it's a lengthy process.


JD Solutions
 
ok, what i am not getting is that fprocessing has to be declared in the class. where is that?
i just added a:
var
fprocessing:boolean;

inside the procedure, so i guess i am doing it wrong. could you explain to me about the class? it looks like i am going to learn something today.
thanks
p
 
Inside the class means wherever the method is being declared. Unless it's a standalone method. So if it's within a form, declare fProcessing inside the form's class, not inside the method.

Code:
type
  TForm1 = class(TForm)
  //This is "inside the class"
  ...
  private
    fProcessing: Bool;
  public
    ...
  end;


JD Solutions
 
And don't forget to initialize it by setting it to False on the form's creation.

Code:
procedure TForm1.Create(Sender: TObject);
begin
  fProcessing:= False;
end;

And also don't be surprised if Whosrdaddy comes in and tells you to completely get rid of Application.ProcessMessages. He seems to have a thing against it, and I don't blame him. It's very sensitive.


JD Solutions
 
Also, I assume the purpose of this method is to have an alternative to the "Sleep" procedure. It essentially does the same thing, but will make the program respond. Sleep will make it not respond. If possible, use Sleep instead, unless you depend on the program responding.

And sorry, we've seemed to have moved away from your original issue. I don't think this warning will be much of an issue, unless you expect to call this procedure with a very very high number of milliseconds. Otherwise, I think it has to do with the use of "LongInt()". Try using ALL "DWORD" types instead, that's what I do for things like this.

JD Solutions
 
it looks like i am going to learn something today.

A class is any Type which has to be created/free'd and contains many other internal variables, methods, objects, and such. A form is a class. If you haven't already before, you should experiment with making your own classes. That's what Delphi is all about and most popular for. I've become extremely familiar with building my own classes, as well as custom components. Another definition of a Class is just simply an Object.

Code:
type
  TMyObject = class(TObject)
  private
    //Anything which you don't want external code to access - only from inside this unit
  public
    //Anything which you want to be shared with anything accessing this object
  published
    //ONLY for TComponent or TPersistent descendents. 
    //Provides ability to put properties in your object inspector for components.
    //(such as TLabel.Caption or TEdit.Text)
  end;

See this FAQ for more information:


JD Solutions
 
Ok, i got it...Now I am getting a hint and a warning:
H2077 Value assigned to 'fProcessing' never used
warning W1036: W1036 Variable 'fProcessing' might not have been initialized

I have the fprocessing variable declared in the class form and it is assigned false in the oncreate event.

Thanks.
P
 
When you double-click on this warning, where in the code does it take you? If you are using fProcessing from within this Delay procedure of yours, you shouldn't be getting this warning. Unless you never even call Delay, then of course it will never be used.

Did you try converting all your numbers to DWORD? This was your original question, I'm hoping you at least got that part solved.


JD Solutions
 
The rational behind making fProcessing a variable of the class (global - to the class) rather than a variable of the method (local - to the method) has to do with scoping.

For variables declared within a method, they are created when the method is kicked off, and destroyed after the method ends.

So for variables declared within a method, that variable does not "remember" its value from the last time the method executed and needs to be given an initial value when the method starts.

As opposed to when it is declared within the class. There, the variable exists when the class is created and destroyed when the class is destroyed. So within your method, no matter how many times it executes, it will remember it's value. But, to compensate, the variable must be given an initial value before it is used, which is why the initialization should happens in your form's OnCreate or in the OnShow method.
 
Everything is fine...I had left the fprocessing variable under var in the procedure...No errors now...
Thanks for everything..
P
 
its value will overflow after about 49 days (although I've never found anyone who had been able to get Windows up and running that long to verify).

My PC is running day and night - it used to act as a domain controller / DNS / DHCP / HTTP / SQL server with Win Server '08. It would go months without restarting at times ... I've never had any overflow problems after 7 weeks of running.

JD Solutions
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top