Jump to content

david_navigator

Members
  • Content Count

    151
  • Joined

  • Last visited

Posts posted by david_navigator


  1. 2 hours ago, Kas Ob. said:

    The logic seen in your code says count is either being calculated from previous received data or checked by some event or API, the first case is not hard to fix as it is can be classified as bug or corrupt data, the second even easier to fix once you understand that, many IO operation fail to estimate the data size that need to be processed, as example in socket operations checking the size of available data to receive is unreliable, means there is data hence may be an event had being fired, but the data length is in question, that event had been fired when something changed, you check for data length to receive and found it as 100 but if you do read/recv on 200 you might get 170 bytes, in not so rare cases the checked length might return 0 while there is >0 data length ready to be processed.

    @Kas Ob. Thanks. I think that makes sense. The code that calculates Count is

     

    function Tcomportserver.InQue : Integer;
     var
        Errors :  DWORD;
        ComStat : TComStat;
     begin
       if not FConnected then
       begin
       Result := 0;
       end
       else
       begin
        if not ClearCommError(ComHandle, Errors, @ComStat) then
           raise EComStatus.Create('Unable to read com status: ' + LastErr);
        Result := ComStat.cbInQue;
       end;
     end;

    so I think what you're saying is that at the time InQue runs (count) there might be 100 bytes waiting to be read, but by the time ReadString gets called, that might be 150 bytes ?

     

    It's probably never risen it's head as a problem because this code is simply processing short barcodes, so it's 10 bytes, then a pause whilst the human does something and then another 10 bytes etc,

     

    I'll refactor it though and check that it still works as the user expects.


  2. 41 minutes ago, David Heffernan said:

    Doesn't the original code have a race?

    I've no idea. It's one of those units found on the internet many years ago and seems to have been working fine up until now.


  3. @Remy Lebeau Thanks for that - seems to address quite a few issues the original developer overlooked.

     

    I noticed that in the original code the developer was using

     

       WaitForSingleObject(Overlapped.hEvent, INFINITE);
        if not GetOverlappedResult(ComHandle, Overlapped, BytesRead, False) then

    Whereas in your version you are using

     

        if not GetOverlappedResult(ComHandle, Overlapped, BytesRead, True) then

    Do these do the same thing ?


  4. This com port routine has started to throw a range check error for one customer, at line ReadFile(ComHandle, Str[1], Count, BytesRead, @Overlapped);

     

    It's old code which has worked for years, but I'm guessing something in D10.4.2 is doing something differently as this customer is testing a 10.4.2 compiled version.

    Are there any gotcha's screaming out - I have a feeling that it's probably something to do with the Str[1] parameter, but I'm not sure.

     

    function Tcomportserver.ReadString(var Str : AnsiString; Count : Integer) : Integer;
     var
        Overlapped : TOverlapped;
        BytesRead :  DWORD;
     begin
        SetLength(Str, Count);
        FillChar(Overlapped, SizeOf(Overlapped), 0);
        Overlapped.hEvent := CreateEvent(nil, True, True, nil);
        ReadFile(ComHandle, Str[1], Count, BytesRead, @Overlapped);
        WaitForSingleObject(Overlapped.hEvent, INFINITE);
        if not GetOverlappedResult(ComHandle, Overlapped, BytesRead, False) then
           raise EWriteError.Create('Unable to write to port: ' + LastErr);
        CloseHandle(Overlapped.hEvent);
        SetLength(Str, BytesRead);
        Result := BytesRead;
     end;

    Many thanks


  5. 55 minutes ago, Dany Marmur said:

    Fiddle with the DX PivotGrid some and then some and i cannot guarantee, but i think you should be able to produce the desired result.

    It was originally designed only to show rows/column values where a "sum" could be done (only numbers).

    Recently you can use Max/Min instead of only Sum (according to the ticketing) but the actual change (quite recent, iirc) has passed me by.

    If you are having a discussion with DX support, do have them realize that you are skilled enough to inherit from their code.

     

    Yes, got it working with the Pivot Grid. If I add some Custom Summary code, then it does what I want 🙂

     

    procedure TForm50.cxDBPivotGrid1Field3CalculateCustomSummary(Sender:
        TcxPivotGridField; ASummary: TcxPivotGridCrossCellSummary);
    begin
      with ASummary do
      begin
        if Records.Count >0 then
        begin
          Custom := GetValue(Records[0]);
        end
        else
          Custom := '';
      end;
    end;

     

    I was also hoping that the TcxPivotGridSummaryDataSet would create a dataset that reflects the grid e.g

     

    Fuel		Oil			Water		Temperature
    Level		Ok			Ok
    ==================================================
    10			True		False			Hot
    5			True		False			Warm
    100			False		True			Cold

    but is seems to just export the same dataset as the source of the Pivot grid. Will need to do some more playing with that.

     

    i.e

     

    Instance	Setting			Value
    ==========================================
    1			Fuel Level		10
    1			Oil OK			True
    1			Water OK		False
    1			Temperature		Hot
    

  6. 15 minutes ago, limelect said:

    Are there only 4 rows per Instance? If so do not put it in 1 database.

     

    No this was a simplification.
    There are also many data sets e.g the original sample shown is storing data about an engine, there maybe a similar dataset storing say electrical data.

    There are [user defined] rows per instance and actually the number of rows can vary between datasets

     

    As the table will be filtered by dataset, they're not really relevant to the solution.

     

    Since I posted the original Question I have got further with DexExpress's Pivot Grid, so it maybe that it is the prefered solution.

     

    Dataset     Instance	Setting			Value
    ==========================================
    1            1			Fuel Level		10
    1            1			Oil OK			True
    1            1			Water OK		False
    1            1			Temperature		Hot
    1            2			Fuel Level		5
    1            2			Oil OK			True
    1            2			Water OK		False
    1            2			Temperature		Warm
    1            3			Fuel Level		100
    1            3			Oil OK			false
    1            3			Water OK		true
    1            3			Temperature		Cold
    2            1			Voltage A		240
    2            1			Voltage B		380
    2            1			Current A		10
    2            1			Current B		30
    2            1			Warning Light	On
    2            1			Filter Colour	Red
    2            2			Voltage A		440
    2            2			Voltage B		120
    2            2			Current A		180
    2            2			Current B		30
    2            2			Warning Light	On
    2            2			Filter Colour	Blue

     


  7. I have some data that is stored in rows, but I need in columns e.g

     

    Instance	Setting			Value
    ==========================================
    1			Fuel Level		10
    1			Oil OK			True
    1			Water OK		False
    1			Temperature		Hot
    2			Fuel Level		5
    2			Oil OK			True
    2			Water OK		False
    2			Temperature		Warm
    3			Fuel Level		100
    3			Oil OK			false
    3			Water OK		true
    3			Temperature		Cold
    
    Fuel		Oil			Water		Temperature
    Level		Ok			Ok
    ==================================================
    10			True		False			Hot
    5			True		False			Warm
    100			False		True			Cold

     

    So the instance field groups the data together and the Setting field describes the Columns and the Value field the data for that intersection.

    Of course at design time I have no idea how big an instance might be. It could have as little as two settings or maybe as many as 20 (I doubt it would ever be larger than that)

     

    The database I'm using has no support for Pivoting data. I could write the transformation in SQL, but that'd be horribly slow to execute. 

    I need to be able to display the data to the end user in a grid format and so I thought a DevExpress Pivot grid might do the job, but that only seems to like numeric data at the intersection - unless I misunderstand how it works.

    Are there any other solutions available, Google didn't really help (maybe I'm searching on the wrong terms) or is this something that's fairly easy to code (to run efficiently) ?

     

    David


  8. On 4/7/2021 at 4:17 PM, Rollo62 said:

    @david_navigator

    That came to my mind first as well, but I never tried that out.

    I use VM's on a real Mac.

    From my "Apple-Experiences" I would expect such Hackintosh should be limited in so many ways, that it will be hard to make real work with it.

    It's certainly not robust enough for commercial use, but as a hobbyist it allowed me to get an experimental app to the apple store without any real apple device.

    I now have a powerful macbook and other than the speed and the lack of occasional unexplained crashes, the user experience is pretty much the same.


  9. If you're just playing and experimenting, then you could try a hackintosh - it's what I used until I had some real work that would justify buying a real mac - that said, it was slow and prone to crashing, but as it was just my own time being wasted, I didn't really mind.


  10. Depends how much you want to invest (time & money).

    When I on boarded a new (to programming) developer many years ago, I started off by giving him small project to play with, searching through books/Google gave him the info he needed to write the code, but it was sometime after that I realised that there were fundamentals about developing code missing from his knowledge e.g he had no idea that the concept of break points & watches existed, so was littering his code with showmessages when trying to debug.


  11. 20 minutes ago, Angus Robertson said:

    Your patches don't work on my working copy, I look for changes manually. 

     

    The samples were never designed or tested to build on Win64, only the components, although we do test the actively supported samples periodically. 

     

    Angus

     

    It's not just 64 bit

    -            smtpQuit : PostMessage(Form1.Handle, WM_REMOVEOBJ, Integer(Sender), 0);
    +            smtpQuit : PostMessage(Form1.Handle, WM_REMOVEOBJ, WPARAM(Sender), 0);

    as discussed here,

     


  12. 21 hours ago, Kas Ob. said:

     

    Before updating anything try to reproduce the error first.

     

    It is way easier than you think to reproduce, all what you need is to make sure the address are higher than MaxInt, so use FastMM4 from here https://github.com/pleriche/FastMM4

    and notice this option AlwaysAllocateTopDown here https://github.com/pleriche/FastMM4/blob/ca64b52ac6d918f4dbd06c20c28e8f961a7e450f/FastMM4Options.inc#L178

    leave it on, and you will catch them all red handed.

    Thanks. That did indeed reproduce the error and also proved that the fix worked. Many thanks 


  13. 5 minutes ago, Stefan Glienke said:

    Don't blame the developer - blame the poor hints - taken from Delphi XE and 10.4:

     

    image.thumb.png.4e4fd01b53691ea30ee667a53501a7f7.png

     

    image.thumb.png.eff755085cb152c3847a249e25b1095e.png

     

    The cast to Integer is indeed wrong - see the assembly code with Bounds checking enabled:

     

    With cast to WPARAM:

     

     

    Thanks. That makes sense. So now I need to update all of his code 🙂

     


  14. 1 minute ago, Attila Kovacs said:

    then why are you asking?

    If I was 100% certain that this was the reason for the RangeCheck error, then obviously I'd update the code and spend a load of time testing there were no side effects, but is it ?
    As I said the code's been like this for 10 years, it's code that executes around the world 1000's of times a day and I've only had a report from one user.


  15. 2 minutes ago, Remy Lebeau said:

    32bit vs 64bit?

    32bit

     

     

    Quote

    You really should not be casting to Integer at all.  Cast to WPARAM instead, which is what PostMessage() is expecting

    It's a colleagues code who's currently on furlough so I'm a bit hesitant to change the code, especially as 

    1. there are 44 instances where Sender is cast as an Integer and I don't know if they'll be any "gotchas" ?
    2. I don't even know if this is the reason for the ERangeCheck as I can't reproduce.


  16. The following code (which has been in my 32 bit app for about 10 years) has just started to throw a range check error for one tester.
    All I can think of is that the cast of TObject to an Integer is the issue, but in that case why would it only affect one user ?
    The only difference between this user and others is that he's running under WINE, but I don't know why that would make a difference ?

     

    procedure TEqlistFrm.VenueEditMainKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    begin
      PostMessage(Handle, CM_SEARCH, Integer(Sender), Key);
    end;

     

×