Solved

Stack Overflow and $MAXSTACKSIZE

Posted on 2003-12-08
21
891 Views
Last Modified: 2010-04-05
Hi

I am a very experienced database programmer in VB with Access and SQLServer.

I have built a database program in Delphi7. I have a data object which supplies the data to a form.  On the form there are basically two grids with two different record sets.

I sort the data on the grids and add and remove data - nothing out of the ordinary.When I close the form I do quite a lot of processing in the query unload to update another table.

Now heres the thing - when I just open the form and close it there are no problems - the data is processed fine - so far so good - I can open and close the form 100 times.

It appears that after sorting the records on the form several of times (it can be ten times or 50 times) - when I close the form (and do the processing) I get a stack overflow error. There is no error in the Code - the data and Code in the query close event are unchanged.

I am absolutley not making recursive calls (looping etc) and it is impossible to pinpoint the problem - it appears random.

How can I find the problem/view/monitor the stack - what would be the effect of increasing the $MAXSTACKSIZE ?

Points for good answers onlty please - I have searched the Web High and Low - so
0
Comment
Question by:Voodooman
  • 10
  • 7
  • 3
  • +1
21 Comments
 
LVL 27

Expert Comment

by:kretzschmar
Comment Utility
do you have assigned any event-methods?
if yes which?
0
 
LVL 5

Author Comment

by:Voodooman
Comment Utility
Hi kretzschmar

This is the code that seems to build the stack - but I cant see how it can - the stack error occurrs later when I run Code under the CloseQuery.  Running the Close query without using the code below seems to be OK.

T

procedure TF_AreasMain.CBO_SortJobsClick(Sender: TObject);
var sql:TStrings;
  filterStr:string;

  Begin



    //Filter the recordset - use sql - cus the filter is rubbish
    //**********************************************************

    Try

      wait(True);
      sql:=TStringList.Create;


      case CBO_SortJobs.ItemIndex of

        1: filterStr:=' and Status Like ' + quotedstr('Completed%');
        2: filterStr:=' and Status Not Like ' + quotedstr('Completed%');
        3: filterStr:=' and OverEstimate > 0 and Status Like ' + quotedstr('Completed%');
        4: filterStr:=' and UnderEstimate <> 0 and Status Like ' + quotedstr('Completed%');
        5: filterStr:=' and Status=' + quotedstr('In Progress');
        6: filterStr:=' and Status=' + quotedstr('Cancelled');
        7: filterStr:=' and Planned<>True';
        8: filterStr:=' and Planned=True';


      end;

        sql.Add('Select * from Labour where Area=' + quotedstr(data.Area));
        sql.Add(' and ProjectID=' + IntToStr(data.ProjectID));
        sql.Add(filterStr);
        sql.Add(' order by Trade,Workman,Description');
        dataobj.EQ_Labour.SQL:=sql;
        dataobj.EQ_Labour.Active:=False;
        dataobj.EQ_Labour.Active:=True;

        Grid_Labour.SetFocus;
        sql.Free;
        wait(False);

    Except

    On E: Exception do

     Imessage('Error filtering Jobs - ' + E.Message);

    end;

  end;
0
 
LVL 27

Expert Comment

by:kretzschmar
Comment Utility
well, i see also no problem yet.

what does wait()?
any event-methods on dataobj.EQ_Labour?
0
 
LVL 5

Author Comment

by:Voodooman
Comment Utility
Hi kretzschmar

Thank you.

Wait() just shows/hides the mouse pointer hourglass - it doesnt actually stop or do anything.

There are no events on EQ_Labour.  The code I have shown doesnt in itself cause the 'Out of Stack'.

It just seems that doing this x times contributes to it.  I have code under the close query that appears to cause it.  The Code itself does not actually cause the 'Stack Overflow' as the Code never even runs!

The Code runs fine (with no changes in the data other than the filtering 90% of the time.
Voodooman
0
 
LVL 27

Accepted Solution

by:
kretzschmar earned 100 total points
Comment Utility
well, digging in the dark as you ;-)

how looks your close-qeury-code?
0
 
LVL 12

Expert Comment

by:andrewjb
Comment Utility
Doesn't running in the debugger help you? When the stack overflow occurs, look at the stack..! Are you _sure_ you're not accidentally calling recursivley. Interconnected events are an obvious possibility, as has been mentioned.
0
 
LVL 5

Author Comment

by:Voodooman
Comment Utility
Hi

I am certainly digging in the dark!  The stack overlflow is completley unpredicatable.  I have tried very hard to reproduce it on demand.  I have worked on software testing in the past and have documented everything.

As far as the close query is concerned putting a breakpoint on the first line doesnt help - it doesnt even get there!

I can test for 10-15 minutes with no problems whatsoever.  I can close the program down and when I re-open it after working for only a minute - BANG! overflow.  Does anyone know of anytool that can show how much of the stack has been consumed/free?

I have increased the stack to 2mb and I dont seem to be having any problems at the moment - here is the close query - it does not call recursively.

//*******************************************//
//  Procedure: TF_AreasMain.FormCloseQuery
//*******************************************//
procedure TF_AreasMain.FormCloseQuery(Sender: TObject;
  var CanClose: Boolean);

  var sql:TStrings;
        countCosts:Integer;
        countLabour:Integer;
        totalCount:Integer;
        recCountCosts:Integer;
        recCountLabour:Integer;

        //Fields
        //******
        Completed:Boolean;
        Budget:Single;
        CurrentEstimate:Single;
        Spent:Single;
        ToSpend:Single;
        OverBudget:Single;
        UnderBudget:Single;
        EstimatedHours:Single;
        CurrentEstimatedHours:Single;
        ToDoHours:Single;
        ActualHours:Single;
        OverEstimateHrs:Single;
        UnderEstimateHrs:Single;
        CompletedJobs:Boolean;
        CompletedCosts:Boolean;
        BalanceCosts:Single;
        BalanceHours:Single;





  begin

  Try

  if askquestion('Finish Updating ' +data.Area +'?')=False  then
    begin
      canClose:=False;
      Exit;
    end;

  Wait(True);



  //Need to update the Areas table with the totals
  //**********************************************
  //A bit of SQL should do it! - get the totals
  //*******************************************

  //Totals - not the Estimates - these are logically not just the totals
  //********************************************************************
  sql:= TStringList.Create;
  sql.add('Select sum(ActualCost) as ');
  sql.Add('ActualCost,sum(OverEstimate) as OverEstimate,sum(UnderEstimate) as ');
  sql.Add('UnderEstimate from Costs  ');
  sql.Add('where ProjectID='+ intToStr(data.ProjectID) + ' and Area=' + quotedstr(data.area));

  dataobj.EQ_General.Active:=False;
  dataobj.EQ_General.sql:=sql;
  dataobj.EQ_General.Active:=True;


  if dataobj.EQ_General.FieldValues['ActualCost']=null then
     spent:=0
     else
     Spent:= dataobj.EQ_General.FieldValues['ActualCost'];

  if dataobj.EQ_General.FieldValues['OverEstimate']=null then
     overBudget:=0
     else
     OverBudget:=dataobj.EQ_General.FieldValues['OverEstimate'];

  if dataobj.EQ_General.FieldValues['UnderEstimate']=null then
     UnderBudget:=0
     else
     UnderBudget:=dataobj.EQ_General.FieldValues['UnderEstimate'];


  //Labour
  //******
  sql.Clear;
  sql.add('Select sum(ActualHours) as ');
  sql.Add('ActualHours,sum(OverEstimate) as OverEstimate,sum(UnderEstimate) as ');
  sql.Add('UnderEstimate from Labour  ');
  sql.Add('where ProjectID='+ intToStr(data.ProjectID) + ' and Area=' + quotedstr(data.area));

  dataobj.EQ_General.Active:=False;
  dataobj.EQ_General.sql:=sql;
  dataobj.EQ_General.Active:=True;


  if dataobj.EQ_General.FieldValues['ActualHours']=null then
     ActualHours:=0
     else
     ActualHours:= dataobj.EQ_General.FieldValues['ActualHours'];

  if dataobj.EQ_General.FieldValues['OverEstimate']=null then
     OverEstimateHrs:=0
     else
     OverEstimateHrs:=dataobj.EQ_General.FieldValues['OverEstimate'];

  if dataobj.EQ_General.FieldValues['UnderEstimate']=null then
     UnderEstimateHrs:=0
     else
     UnderEstimateHrs:=dataobj.EQ_General.FieldValues['UnderEstimate'];


  //Flag the Completed flag
  //***********************
  //get the number of incomplete Costs
  //**********************************
  sql.Clear;
  sql.add('Select count(*) as Total from Costs where Completed=False and Status<>' +quotedstr('Cancelled'));
  sql.Add(' and ProjectID='+ intToStr(data.ProjectID) + ' and Area=' + quotedstr(data.area));

  dataobj.EQ_General.Active:=False;
  dataobj.EQ_General.sql:=sql;
  dataobj.EQ_General.Active:=True;

  countCosts:=dataobj.EQ_General.FieldValues['Total'];

  //get the number of incomplete Labour Items
  //*****************************************
  sql.Clear;
  sql.add('Select count(*) as Total from Labour where Completed=False and Status<>'+quotedstr('Cancelled'));
  sql.Add(' and ProjectID='+ intToStr(data.ProjectID) + ' and Area=' + quotedstr(data.area));

  dataobj.EQ_General.Active:=False;
  dataobj.EQ_General.sql:=sql;
  dataobj.EQ_General.Active:=True;

  countLabour:=dataobj.EQ_General.FieldValues['Total'];



  if CountLabour=0 then

      CompletedJobs:=True
      else
      CompletedJobs:=False;

  if CountCosts=0 then
        CompletedCosts:=True
        else
        CompletedCosts:=False;


  //Add the totals together >0 its not complete
  //*******************************************
  totalCount:=countLabour+countCosts;


  if totalCount=0 then
      Completed:=True
      else
      Completed:=False;



  recCountCosts:=dataobj.EQ_Costs.RecordCount;
  recCountLabour:=dataobj.EQ_Labour.RecordCount;



  //No Recs at all - mark it incomplete
  //**********************************
  totalCount:=recCountCosts+recCountLabour;


  if totalCount=0 then
    Begin
    Completed:=False;
    CompletedCosts:=False;
    CompletedJobs:=False;
    end;


    //Get the To Spend Amount
    //These do not include cancelled or completed Items
    //**************************************************
    sql.Clear;
    sql.add('Select sum([EstimatedCost]) as ToSpend ');
    sql.Add('from Costs  ');
    sql.Add('where ProjectID='+ intToStr(data.ProjectID) + ' and Area=' + quotedstr(data.area));
    sql.Add(' and Status<>' + quotedstr('Cancelled') + ' and Status Not Like ' + quotedstr('Completed%'));
    dataobj.EQ_General.Active:=False;
    dataobj.EQ_General.sql:=sql;
    dataobj.EQ_General.Active:=True;

   if dataobj.EQ_General.FieldValues['ToSpend']=null then
      ToSpend:=0
      else
      ToSpend:=dataobj.EQ_General.FieldValues['ToSpend'];




    //Get the ToDo Hours
    //These do not include cancelled or completed Items
    //**************************************************
    sql.Clear;
    sql.add('Select sum([EstimatedHours]) as ToDo ');
    sql.Add('from Labour  ');
    sql.Add('where ProjectID='+ intToStr(data.ProjectID) + ' and Area=' + quotedstr(data.area));
    sql.Add(' and Status<>' + quotedstr('Cancelled') + ' and Status Not Like ' + quotedstr('Completed%'));
    dataobj.EQ_General.Active:=False;
    dataobj.EQ_General.sql:=sql;
    dataobj.EQ_General.Active:=True;



    if dataobj.EQ_General.FieldValues['ToDo']=null then
       ToDoHours:=0
       else
       ToDoHours:=dataobj.EQ_General.FieldValues['ToDo'];


    //Get the Planned Cost
    //********************
    sql.Clear;
    sql.add('Select sum(EstimatedCost) as EstimatedCost from costs ');
    sql.Add('where ProjectID='+ intToStr(data.ProjectID) + ' and Area=' + quotedstr(data.area));
    sql.Add(' and Planned=True');
    dataobj.EQ_General.Active:=False;
    dataobj.EQ_General.sql:=sql;
    dataobj.EQ_General.Active:=True;

    if dataobj.EQ_General.FieldValues['EstimatedCost']=null then
       Budget:=0
       else
       Budget:=dataobj.EQ_General.FieldValues['EstimatedCost'];




    //Get the Planned Estimate of the Hours
    //These do not include cancelled
    //**************************************
    sql.Clear;
    sql.add('Select sum([EstimatedHours]) as EstimatedHours ');
    sql.Add('from Labour  ');
    sql.Add('where ProjectID='+ intToStr(data.ProjectID) + ' and Area=' + quotedstr(data.area));
    sql.Add(' and Planned=True');
    dataobj.EQ_General.Active:=False;
    dataobj.EQ_General.sql:=sql;
    dataobj.EQ_General.Active:=True;


    if dataobj.EQ_General.FieldValues['EstimatedHours']=null then
       EstimatedHours:=0
       else
       EstimatedHours:=dataobj.EQ_General.FieldValues['EstimatedHours'];


    //************************
    //Get the Current Estimate
    //************************
    sql.Clear;
    sql.add('Select sum(EstimatedCost) as CurrentEstimate from costs ');
    sql.Add('where ProjectID='+ intToStr(data.ProjectID) + ' and Area=' + quotedstr(data.area));
    sql.Add(' and Status<>' + QuotedStr('Cancelled'));
    dataobj.EQ_General.Active:=False;
    dataobj.EQ_General.sql:=sql;
    dataobj.EQ_General.Active:=True;

    if dataobj.EQ_General.FieldValues['CurrentEstimate']=null then
       CurrentEstimate:=0
       else
       CurrentEstimate:=dataobj.EQ_General.FieldValues['CurrentEstimate'];

    //Get the Current Estimate of the Hours
    //These do not include cancelled
    //**************************************
    sql.Clear;
    sql.add('Select sum([EstimatedHours]) as CurrentEstimatedHours ');
    sql.Add('from Labour  ');
    sql.Add('where ProjectID='+ intToStr(data.ProjectID) + ' and Area=' + quotedstr(data.area));
    sql.Add(' and Status<>' + QuotedStr('Cancelled'));
    dataobj.EQ_General.Active:=False;
    dataobj.EQ_General.sql:=sql;
    dataobj.EQ_General.Active:=True;

    if dataobj.EQ_General.FieldValues['CurrentEstimatedHours']=null then
       CurrentEstimatedHours:=0
       else
       CurrentEstimatedHours:=dataobj.EQ_General.FieldValues['CurrentEstimatedHours'];



    //Balance
    //*******

    if dataobj.EQ_Costs.RecordCount>0 then
       begin
       BalanceCosts:=OverBudget + UnderBudget
       end;


    if dataobj.EQ_Labour.RecordCount>0 then
         begin
         BalanceHours:=OverEstimateHrs + UnderEstimateHrs;
         end;



    sql.Free;

    //Now post the values
    //*******************
    dataObj.EQ_Areas.Edit;

    dataObj.EQ_Areas.FieldValues['Completed']:=Completed;
    dataObj.EQ_Areas.FieldValues['Budget']:=Budget;
    dataObj.EQ_Areas.FieldValues['CurrentEstimate']:=CurrentEstimate;
    dataObj.EQ_Areas.FieldValues['Spent']:=Spent;
    dataObj.EQ_Areas.FieldValues['To Spend']:=ToSpend;
    dataObj.EQ_Areas.FieldValues['Over Budget']:=OverBudget;
    dataObj.EQ_Areas.FieldValues['Under Budget']:=UnderBudget;
    dataObj.EQ_Areas.FieldValues['EstimatedHours']:=EstimatedHours;
    dataObj.EQ_Areas.FieldValues['CurrentEstimatedHours']:=CurrentEstimatedHours;
    dataObj.EQ_Areas.FieldValues['ToDo Hours']:=ToDoHours;
    dataObj.EQ_Areas.FieldValues['ActualHours']:=ActualHours;
    dataObj.EQ_Areas.FieldValues['OverEstimateHrs']:=OverEstimateHrs;
    dataObj.EQ_Areas.FieldValues['BalanceCosts']:=BalanceCosts;
    dataObj.EQ_Areas.FieldValues['BalanceHours']:=BalanceHours;
    dataObj.EQ_Areas.FieldValues['CompletedCosts']:=CompletedCosts;
    dataObj.EQ_Areas.FieldValues['CompletedJobs']:=CompletedJobs;


    dataObj.EQ_Areas.post;


    Application.CreateForm(TF_ProjectMain,F_ProjectMain);
    F_ProjectMain.show;


    Except

    On E: Exception do
        Begin
        EMessage('Error Updating Project Areas - ' + E.Message);
        canclose:=False;
        end;

    end;

    wait(False);

  end;

0
 
LVL 27

Expert Comment

by:kretzschmar
Comment Utility
>Does anyone know of anytool that can show how much
>of the stack has been consumed/free?

not really, but
i would advice you to use madExcept from madshi
see www.madshi.net

now looking at your code ;-)

meikl ;-)
0
 
LVL 27

Expert Comment

by:kretzschmar
Comment Utility
just wondering about this part

....
  Application.CreateForm(TF_ProjectMain,F_ProjectMain);
  F_ProjectMain.show;
....

guessing F_ProjectMain is not the app-mainform,
and there is no instance already present

guessing also TF_AreasMain is not the app-mainform

is this correct?

meikl ;-)


   
0
 
LVL 5

Author Comment

by:Voodooman
Comment Utility
Hi meikl ;-)

Correct F_ProjectMain is not the app-mainform - the main form is the Splash which is hidden.

The code doesnt even get there - it doesnt even seem to run at all when the stack error occurrs.

Strangely I can add recs to the record sets and scroll around them - allsorts of things and can safely exit.  However if I do the sorting I sometimes get the error - I could not absoulutely say whether this is causing it.

The error is totally unpredicable - I have tried changing the controls for others etc in case there is some recursive calling in the VCL somewhere.

The only thing I cant change is the TQueries - they are EasyTable controls - I am trying to identify if the problem is there.

Voodooman
0
Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 27

Expert Comment

by:kretzschmar
Comment Utility
well, just download madExcept at
www.madshi.net

a little description can be found
http://help.madshi.net/madExcept.htm

i use it also, if i had problems like yours

meikl ;-)

0
 
LVL 12

Expert Comment

by:andrewjb
Comment Utility
You didn't reply - are you running in the debugger or as a standalone. Doesn't running under the debugger trap the stack overflow and let you look at the stack trace?
0
 
LVL 5

Author Comment

by:Voodooman
Comment Utility
Hi andrewjb

Sorry not to reply to you directly - I have been out to a client whose ISP (a big Telco) has decided to ditch its named SMTP Server today without telling its millions of customers who have been using it....they forgot to tell anyone...

I am running in the debugger. It doesnt help - I can run thru the same code a hundred times and nothing happens.  

Also I cant seem to find the execution point. The 'Show execution Point' menu is permanently greyed out.

When I put the breakpoint on the first available line of the close query - it doesnt  even get there.

I am still trying to figure out this Delphi Debugging stuff - its more 'Under the Hood' than I am used to! I found the Stack Call window in the Delphi Bible last night about 2.30am but I havent had the probel today!

Voodooman

0
 
LVL 5

Author Comment

by:Voodooman
Comment Utility
Hi meikl ;-)

Thanks for the input I have downloaded MadExcept and Installed it - guess I have some learning to do about Delphi Exceptions....

Thanks Everybody who has helped so far

Voodooman
0
 
LVL 12

Assisted Solution

by:andrewjb
andrewjb earned 100 total points
Comment Utility
Just to make sure...

Your project options have got optimisation turned OFF, all the bits under debugging turned ON, build with runtime packages OFF, then a full rebuild of the whole project.

When you put in the breakpoint, you do get a red dot, don't you. It remains red whilst you're running?


Hope I'm not being rude - it sound like you haven't used Delphi much, so you might be buliding with duff options for debugging...
0
 
LVL 17

Assisted Solution

by:Wim ten Brink
Wim ten Brink earned 50 total points
Comment Utility
Increasing the MAXSTACKSIZE might just make the system wait longer before it crashes. In my experience, a stack overflow is often (almost always) caused because of an endless loop or a recursive method that never ends. The last thing is more likely.
Maybe you're just walking through the table without moving to the next record. (Forgetting to call Table.next in a loop is quite a common error.)

So, check your loops, check to make sure you're not calling a method recursively. That last thing might be a bit difficult in an event-driven environment because event1 could trigger event2 which triggers event1 again, thus resulting in an endless loop.
0
 
LVL 5

Author Comment

by:Voodooman
Comment Utility
Hi andrejb

Of course you are not being rude - if I cant take the answer I wouldnt ask the question!!

I have turned off optimisation (it was on) - why should I turn it off?

All the debug options are turned on apart from debug DCU's which the help says are for CLX and so I guess I shouldnt use them.

As far as the Runtime Options are concerned I have to use runtime packages as I didnt buy the source for some of the tools I am using.

You are correct I havent used Delphi much since 94/95 (Ver 1 and 2).  I have been working as a contractor with VB and SQL Server as an Analyst Programmer and SQLServer DBA (20 million+ records and 500+ seats).

Delphi looks better, runs faster, has some brilliant tools that are unbelievably cheap (try buying tools for VB) and makes small programs + choice of database.

The downside of Delphi is that you never get under the hood in VB and 'Just in Time Debugging' in VB is a massive advantage with big programs (120k plus lines).  I cant imagine building a massive business critical sytem in Delphi - it would seem impossible.

I have built a great looking commercial program (resolution independent etc).  I would like it to be 'Bullet Proof' when I sell it.

Thanks Again

Voodooman
0
 
LVL 5

Author Comment

by:Voodooman
Comment Utility
Hi Workshop_Alex

You are of course 100% right when you say that it might just take longer to crash the program.

However

I am 99.9999% confident I am not doing any recursive calling and I am doing no looping at all.

Interestingly I have been trying to find the max stack size in VB - but cant find anything definitive.

Of Course various controls could be making recursive calls that I have no knowledge of....

Voodooman
0
 
LVL 5

Author Comment

by:Voodooman
Comment Utility
Dear Experts

I am somehow getting to the bottom of this!

It is not helped by the erratic nature of the errors.  I have traced the problems to erratic behaviour concerning the use of a data module and the TQuery components (in my case TEasyQuery).

Problems are occurring when I use this (I got this from a book - dont blame me!).

Application.CreateForm(TF_AreasMain,F_AreasMain);
F_AreasMain.show;

procedure TF_AreasMain.FormClose(Sender: TObject; var Action: TCloseAction);

  begin

  Release;

  end;

Its the 'Release' that appears to be somehow attempting to free the recordsets in the datamodule - the data module appears to be attempting to re-instate them - recursively - causing a stack overflow. It might be because I have the recordsets in the data modules and some (not all) datasources on the forms.

I guess if my data controls were on the form I would not be having these problems - trying to hard to do the right thing seems like a bad idea!

Its looking like using Auto Create and just Closing the forms may be the answer. I will be out allday - I will allocate the points tomorrow after reading any comments.

I dont think Auto Creating all the forms matters today with 128mb memory being common - VB never unloads a form once its been loaded (apparently unload never frees the resources in VB) and I have a product with 140 forms that runs no problems.

Thanks all you Delphi Experts

Voodooman
0
 
LVL 27

Expert Comment

by:kretzschmar
Comment Utility
instead of
procedure TF_AreasMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Release;
end;

use

procedure TF_AreasMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end;

meikl ;-)
0
 
LVL 5

Author Comment

by:Voodooman
Comment Utility
Hi Experts

Your help has given me the answer I am going to split the points if thats OK.

My problems seem to be solved at last.  They began after I did a big 'Tidy up' operation on the Code and moved most of my recordsets and some but not all of the datasources to my data object - I like to compartmentalise as much as possible - it helps maintain it later.

Since then I have had bizarre unreliability problems such as 'unable to update a read only recordset' - that was not a read only recordset a minute ago, random Exceptions in the IDE,  radom stack overflow errors. All very random and not reproduceable on demand.

Cause - Use of 'Release' Keyword in the Close method of Data Centric Forms where datasets and sources are remotely located in the 'data object'.

Workshop_Alex - on the money - there is only one way to get a stack overflow - recursive calls- 50.

AndrewJ - changing the debug settings made tracing the problem possible - 100

Kretzschamar - focussed my attention on the Events - Close and Query Unload - 100

Thank you all very, very much - this has been driving me crazy - at least 80 hours wasted and my project 2 weeks behind.

Merry Xmas

Voodooman

0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…
When you create an app prototype with Adobe XD, you can insert system screens -- sharing or Control Center, for example -- with just a few clicks. This video shows you how. You can take the full course on Experts Exchange at http://bit.ly/XDcourse.

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now