Jump to content

ChrisChuah

Members
  • Content Count

    121
  • Joined

  • Last visited

Posts posted by ChrisChuah


  1. I just found out that i can use the dataset to refresh rather than Open and close.

    The dbgrid will refresh with updated content.

     

    Now i have another problem is when i open the dataset, the dbgrid is filled to the bottom and it will somehow stop there..

    i need to scroll down to request it to draw again.

    anyone have this problem?

    is there a way to scroll all the way down the grid automatically once the drawing is completed?

    please see this video on the problem.. anyone can advise?

     

    source

    procedure TfrmMain.dbgABNDrawColumnCell(Sender: TObject; const Rect: TRect;
      DataCol: Integer; Column: TColumn; State: TGridDrawState);
    var
      l_bitmap : TBitmap;
      l_rect : TRect;
      l_bmpWidth, l_width : integer;
      l_str : string;
    begin
      if ( (dbgABN.DataSource.Dataset as TClientDataset).RecNo mod 2 = 0) then begin
        if dbgABN.Canvas.Brush.Color = dbgABN.Color then begin
          dbgABN.Canvas.Brush.Color := clSkyBlue;
        end;

      end;
      l_rect := Rect;
      l_str := Column.Field.DisplayText;
      if Column.FieldName = 'ROW_ID' then begin
        l_bitmap := TBitmap.create;
        try
          ImageList2.GetBitmap(0, l_bitmap);
          l_bmpWidth := (Rect.bottom - Rect.Top);
          l_rect.Right := Rect.Left + l_bmpWidth;
          dbgABN.Canvas.StretchDraw(l_rect, l_bitmap);
        finally
          l_bitmap.Free;
        end;
        // cc : reset the output rectangle
        l_rect := Rect;
        l_rect.Left := l_rect.Left + l_bmpWidth;
      end;
      l_width := 5 + dbgABN.Canvas.TextExtent(l_str).cx;
      if (l_width > Column.Width) then
          Column.Width := l_width;
      dbgABN.DefaultDrawColumnCell(l_rect, DataCol, (Column as TTntColumn), State);
    end;

     


  2. Hi

    I am using TSQLQuery, TClientDataSet and TDataSetProvider with DBGrid

    I will click on the record row in the middle of the grid and the grid shows that it is highlighted

    HOwever, when i close and open the ClientDataSet to refresh the data, 

    i would use the bookmark to go back to the last bookmark before the Client dataset is Close

     

      l_bookmark := TntDBGrid1.Datasource.DataSet.GetBookmark;
      TntDBGrid1.DataSource.DataSet.Close;
      TntDBGrid1.DataSource.Dataset.Open;
      TntDBGrid1.DataSource.DataSet.GotoBookmark(l_bookmark);
      TntDBGrid1.DataSource.Dataset.FreeBookmark(l_bookmark);
     

    After open, the indicator is shown correctly on the dbgrid but the highlighted row is on the first row.

    see pic 

     

    please advise

     

    regards

    chris

    1389271130_Record100selected.thumb.png.408121fb4857ce6087f7d9f241aa7059.png386449203_RefreshRecord100notselected.thumb.png.78cf37b4a3cf962806c55618cb2ef4ee.png


  3. Hi

    I am using TSQLQuery, TClientDataSet and TDataSetProvider with DBGrid

    If i want to sort the DBGrid based on title column click, i can use the event OnTitleClick on DBGrid

     

    ClientDataSet.IndexFieldsName := Column.FieldName

     

    However, this will sort the Field in ascending order.

     

    How can i sort it in descending order?

    please advise

     

    regards

    chris

     


  4. 9 hours ago, Remy Lebeau said:

    On some platforms, you might be able to just set the TIdUDPClient.BoundIP property to the IP of the network adapter you are sending broadcasts from.  On other platforms, you might have to resort to using TIdUDPClient.Binding.SetSockOpt(SO_BINDTODEVICE) to bind to a network interface by name instead of IP.  But either way, this should prevent your outgoing network adapter from receiving duplicates of its own broadcasts.

    Not quite sure I understand what you are asking.

     

    If you are asking how to ignore the IP of the broadcaster, then whenever you receive a packet, you are also given the sender's IP (and port).  You can just ignore packets that come from your own IP.

     

    If you are asking what a broadcast IP is in general, then it is a network IP that is masked by its subnet mask, and then OR'ed with the inverse of the subnet mask.  So, for example, if you have an IP of 192.168.100.5 and a subnet mask of 255.255.255.0, then the broadcast IP is 192.168.100.255:

     

    192.168.100.5 & 255.255.255.0 = 192.168.100.0

    ~255.255.255.0 = 0.0.0.255

    192.168.100.0 | 0.0.0.255 = 192.168.100.255

    Hi Remy

    Yes. As i send a UDP packet to a 192.168.100.255, the IP address that returns to me is also 192.168.100.255 as well as a reply from other servers.

    Is there a function to say isBroadcastAddress(aIPAddress: string) that i can use so as to know its a broadcast address?

    Does Indy library has such function?

     

    regards

    chris

     


  5. Hi

    On my mac, it seems that i have many network interfaces.

    I used Indy GStack.GetLocalAddressList to obtain all these interface name and IP address.

     

    Stack Local Address 0: en0: FE80:0:0:0:102B:BAE3:A50E:FEDA
    Stack Local Address 1: en0: 192.168.1.10
    Stack Local Address 2: en1: FE80:0:0:0:C55:FF1F:977A:4ECD
    Stack Local Address 3: en1: 192.168.1.11
    Stack Local Address 4: awdl0: FE80:0:0:0:380D:36FF:FE0A:D127
    Stack Local Address 5: llw0: FE80:0:0:0:380D:36FF:FE0A:D127
    Stack Local Address 6: utun0: FE80:0:0:0:FE2C:6391:70B1:32E5
    Stack Local Address 7: utun1: FE80:0:0:0:D512:288C:E8D7:52E1
    Stack Local Address 8: utun2: FE80:0:0:0:CE81:B1C:BD2C:69E
    Stack Local Address 9: bridge100: 172.16.90.1
    Stack Local Address 10: bridge100: FE80:0:0:0:787B:8AFF:FE3C:7864
    Stack Local Address 11: bridge101: 192.168.83.1
    Stack Local Address 12: bridge101: FE80:0:0:0:787B:8AFF:FE3C:7865
    Stack Local Address 13: bridge102: 192.168.84.1
    Stack Local Address 14: bridge102: FE80:0:0:0:787B:8AFF:FE3C:7866
    Stack Local Address 15: bridge103: 192.168.85.1
    Stack Local Address 16: bridge103: FE80:0:0:0:787B:8AFF:FE3C:7867
    Stack Local Address 17: bridge104: 172.16.49.1
    Stack Local Address 18: bridge104: FE80:0:0:0:787B:8AFF:FE3C:7868

     

    If i want to send a broadcast packet onto 192.168.84.255 (Bridge102), How can i specify it in idUDPClient?

    Or will idUDPClient able to automatically send it out via that interface?

     

    Please advise

     

    regards

    chris

     

     

     


  6. Hi

    When i use the IdUDPClient inside the thread object, the idUDPClient does not get any messages back even though it can be seen from the Wireshark that the message was sent back.

    However, if i place the IdUDPClient on a Form, i am able to get the message.

     

    Something funny is that when i use the IdUDPClient on the Form to send out the message, 

    the first response message header is SOREQ <== this header is request header

    Checking on the Wireshark, the server returned SORE

    I tried to initialise the l_buf to $0 before retrieving from idUDPClient.

    However, its only the first message sent that will be always SOREQ and the rest will be SORE

    And the IP address returned in the message should be 192.168.84.128 which indicate the server address itself.

    seems like the first message is the same message that i sent out.

     

     

    please advise

     

    regards

    chris

     

    ===== Code for IdUDPClient on Form =====

    procedure TForm1.Button2Click(Sender: TObject);
    var
      l_port : UInt32;
      l_memStream : TMemoryStream;
      l_len : integer;
      l_buf, l_buf1 : TIdBytes;
      l_ilUDPData : Tt_BootReqMsg;
      l_ip : string;
      l_ipBytes : array[0..15] of byte;
      FMsg : string;
      FRepliedClientIP : string;
      FRepliedClientPort : Uint32;
      l_index : integer;
    begin
      l_ip := getOwnIP;
      if l_ip = '' then begin
        writeLog('Cannot find own IP address');
        exit;
      end;
      IdUDPClient1.Host := '192.168.84.255';
      IdUDPClient1.Port := 55510;
      IdUDPClient1.BoundPort  := 55510;
      try
    //    FUDP.Active := true;
        l_memStream := TMemoryStream.create;

        l_buf := ToBytes('SOREQ'#0, IndyTextEncoding_ASCII);
        l_memStream.Write(l_buf[0], 6);

        l_port := 55510;
        l_port := GStack.HostToNetwork(l_port);
        l_memStream.write(l_port, 4);

        getArrayBytes(l_ip, l_ipBytes);
        l_memStream.Write(l_ipBytes, SizeOf(l_ipBytes));

        l_len := l_memStream.size;
        setLength(l_buf, l_len);
        l_memStream.position := 0;
        l_memStream.Read(l_buf[0], l_len );
        l_memStream.Clear;
        try
          IdUDPClient1.ReceiveTimeout := 3000;
          IdUDPClient1.BroadcastEnabled := true;
          IdUDPClient1.SendBuffer(l_buf);
          FMsg := 'Send To Address: ' + IdUDPClient1.Host + ' Port: ' + Inttostr(IdUDPClient1.Port) + ' using IP: ' + l_ip;
          WriteLog(FMsg);
          setLength(l_buf, sizeOf(l_ilUDPData));
          for l_index := 0 to length(l_buf) - 1 do. <== initialise the buffer but i still receive SOREQ only on 1st time.
            l_buf[l_index] := byte($0);

          l_len := IdUDPClient1.ReceiveBuffer(l_buf, 2000);
          if l_len <= 0 then begin
            FMsg:='No Data received in UDP';
            FRepliedClientIP := '';
            FRepliedClientPort := 0;
            WriteLog(FMsg);
          end
          else begin
            l_memStream.Clear;
            l_memStream.Position := 0;
            l_memStream.Write(l_buf[0], l_len);
            l_memStream.Position := 0;
            setlength(l_buf1, 6);
            l_memStream.Read(l_buf1[0], length(l_buf1));
            WriteLog('Op Code: ' + getStringFromBytes(l_buf1));
            l_memStream.Read(FRepliedClientPort, sizeof(FRepliedClientPort));
            WriteLog('Port value: ' + Inttostr(FRepliedClientPort));
            l_memStream.Read(l_ilUDPData.hid, sizeof(l_ilUDPData.hid));
            FRepliedClientIP := getStringFromBytes(l_ilUDPData.hid);
            FRepliedClientPort := GStack.NetworkToHost(FRepliedClientPort);
            WriteLog('Replied. IP: ' + FRepliedClientIP + ' Port: ' + Inttostr(FRepliedClientPort));
          end;
        except
          on E:Exception do begin
            FMsg := 'Error in Recv Data in UDP: ' + e.message;
            FRepliedClientIP := '';
            FRepliedClientPort := 0;
            WriteLog(FMsg);
          end;
        end;
        l_memStream.Free;
      except
        on E:exception do begin
          FMsg := 'Exception in SoFind: ' + e.Message;
          FRepliedClientIP := '';
          FRepliedClientPort := 0;
          WriteLog(FMsg);
        end;
      end;

    end;
     

    ==== End =====

     

    380883448_ScreenShot2022-05-27at2_10_12PM.png.dc0c76981140d9c153e1f801f4d6a775.png1796901076_ScreenShot2022-05-27at2_10_23PM.thumb.png.b1f074d6598bfb7c485260a2c9e6190b.png1689686418_ScreenShot2022-05-27at2_10_39PM.thumb.png.f912e46f3fbc1778b6e59875d53f76b9.png


  7. Hi Remy

    Would like to ask why the UDPClient did not receive any data.

    Attached is the screen capture of the Wireshark.

    The first pic shows the server received the message sent from the delphi client

    The second pic shows the server sends out the SORE (response) message to the delphi client IP address.

    However, the client reported that there is no data received

     

    <27/5/2022 11:14:02 am> Send To Address: 192.168.84.255 Port: 55510 using IP: 192.168.84.129
    <27/5/2022 11:14:05 am> IP:  Port: 0 replied
    <27/5/2022 11:14:05 am> No Data received in UDP

     

    Did i do something not right?

    please advise

     

    regards

    chris

     

     183309202_ScreenShot2022-05-27at11_16_32AM.thumb.png.9233321f3c92cc86f555d794e4c622e5.png21642686_ScreenShot2022-05-27at11_16_55AM.thumb.png.8de6716efc5ad415666e4a9a05e97504.png1504326953_ScreenShot2022-05-27at11_18_33AM.png.f6734a8a20bfedfff7b1312bf86acc90.png


  8. Thanks Remy

    The only problem that i have with strings in delphi is that I dont know if they are Windows widechar or UTF8 char or ansi value

     

    Edit1.text := 'MET';

     

    ShowMe(Edit1.text);

     

    Function showMe(aValue : string);

    var

      l_value : string;

    begin

      l_value := aValue + 'A';

      UDPClient.Write(l_value);

    end;

     

    So when the edit1 value is pass into ShowMe function, what is the length of l_value? 

    As my server only accepts ANSI type of characters, the data sent may be Windows WideChar.

    Hence to be on the safe side, i would have to translate it to idBytes.

     

    What is the general rule on how you would send data when the server only accepts ANSI characters.

     

    Please advise

    regards

    chris

     

    BTW, After 20 years of using Delphi, i still remembered you were helping me last time when i was using Delphi 5, 6 in one of the forum.

    Now, its hard to find help for delphi.


     

     


  9. Hi

    I am trying to create a thread that will send out UDP message and when it receive the UDP message from the server, it will send a Reply as event back to the caller.

    I create the UDPClient in the Execute function and of course i would need to free it when the thread ends.

    But why do i get access violation when i free it?

    The call stack is

    --IdSocketHandle.CloseSocket.

    --IdSocketHandle.Destroy

    -- System.TObject.free;

    --IdUDPBase.CloseBinding

    --IdUDPBase.Destroy

    --IdUDPClient.Destroy

     -- System.TObject.Free

    --FUDP.Free;

     

    please help to guide me what is the best way to send out UDP message and wait for reply?

    Should i use UDPServer rather than UDPClient?

     

    === Code ===

    procedure ilUDPClientThd.Execute;
    var
      l_port : UInt32;
      l_memStream : TMemoryStream;
      l_len : integer;
      l_buf : TIdBytes;
      l_ilUDPData : Tt_BootReqMsg;
      l_ip : string;
      l_ipBytes : array[0..15] of byte;
      FUDP: TIdUDPClient;
    begin
      { Place thread code here }
      l_ip := getOwnIP;
      if l_ip = '' then begin
        DoOnLog('Cannot find own IP address');
        exit;
      end;
      FUDP := TIdUDPClient.Create(nil);
      FUDP.Host := FBroadcastIP;
      FUDP.Port := FBroadcastPort;
    //  FUDP.Binding.Port := FBroadcastPort;
      try
        l_port := FBroadcastPort;
        l_memStream := TMemoryStream.create;

        l_buf := ToBytes('SOREQ', IndyTextEncoding_ASCII);
        l_memStream.Write(l_buf[0], 6);

        l_port := GStack.HostToNetwork(l_port);
        l_memStream.write(l_port, 4);

        getArrayBytes(l_ip, l_ipBytes);
        l_memStream.Write(l_ipBytes, SizeOf(l_ipBytes));

        l_len := l_memStream.size;
        setLength(l_buf, l_len);
        l_memStream.position := 0;
        l_memStream.Read(l_buf[0], l_len );
        l_memStream.Clear;
        try
          FUDP.ReceiveTimeout := 3000;
          FUDP.BroadcastEnabled := true;
    //      FUDP.Active := true;
          FUDP.SendBuffer(l_buf);
    //      FUDP.SendBuffer(l_buf[0], l_len);
          FMsg := 'Send To Address: ' + FUDP.Host + ' Port: ' + Inttostr(FUDP.Port) + ' using IP: ' + l_ip;
          Synchronize(WriteToLog);
    //      l_len := FUDP.ReceiveBuffer(l_ilUDPData, sizeof(l_ilUDPData), FUDP.ReceiveTimeout);
          setLength(l_buf, sizeof(l_ilUDPData));
          l_len := FUDP.ReceiveBuffer(l_buf);
          if l_len <= 0 then begin
            FMsg:='No Data received in UDP';
            FRepliedClientIP := '';
            FRepliedClientPort := 0;
            Synchronize(ReplyToClient);
            Synchronize(WriteToLog);
          end
          else begin
            l_ilUDPData.Port := GStack.NetworkToHost(l_ilUDPData.Port);
            FRepliedClientIP := getStringFromBytes(l_ilUDPData.hid);
            FRepliedClientPort := l_ilUDPData.port;
            Synchronize(ReplyToClient);
          end;
        except
          on E:Exception do begin
            FMsg := 'Error in Recv Data in UDP: ' + e.message;
            FRepliedClientIP := '';
            FRepliedClientPort := 0;
            Synchronize(ReplyToClient);
            Synchronize(WriteToLog);
          end;
        end;
        l_memStream.Free;
        FUDP.Binding.Destroy;
      except
        on E:exception do begin
          FMsg := 'Exception in SoFind: ' + e.Message;
          FRepliedClientIP := '';
          FRepliedClientPort := 0;
          Synchronize(ReplyToClient);
          Synchronize(WriteToLog);
        end;
      end;
      FUDP.Disconnect;
      FUDP.Free; <<==== Access violation when i tried to free UDP Client 
    end;


  10. 20 hours ago, PeterBelow said:

    Create a COM dll, Delphi has a wizard for that. Google for "C# com interop" to find examples for how to use such a thing from the .NET side.

    Hi

    Actually I want to use delphi to create a DLL with functions or procedures containing a callback.

    How can i create such functions in delphi so that the project can be compiled to a dll for C Sharp programmer to use

    Previously all DLL functions does not have function pointer or callback functions when i was using Delphi 6 era.

    Also my C sharp programmers said they cannot use COM because their program will be running in Docker for linux

     

     

    please advise

     

    regards

    chris

     


  11. Hi

    I have an existing component that communicates with a server via TCP.

    However, this component can only be used in delphi.

    When i call a function in this component, it will send out a TCP message.

    After some time, it will return back data and it will trigger an event back in the component.

    So, anytime i want to use this component, i can drop the component into the form.

    I can double click on the event and write codes to handle the result from the event.

     

    Now, if i want to make this component into a DLL for C sharp programmer to use

    How can i create events into the dll for C Sharp programmer to use?

     

    Is there any example that i can use or follow

     

    please help

     

    regards

    chris

     


  12. Actually, its not easy to find components written for Delphi

    For example, component to read ePassport whereby it need to capture the image of the MRZ portion of the passport and then read the NFC chip from the passport.

    These are quite specialised components which you can find libraries for swift, java, c sharp etc. 

    However, cant find for delphi.

     

×