Jump to content

Remy Lebeau

Members
  • Content Count

    2929
  • Joined

  • Last visited

  • Days Won

    131

Posts posted by Remy Lebeau


  1. 1 hour ago, chkaufmann said:

    What I don't understand, how I can verify that it is really the original certificate from my server.

    You have to analyze the certificate provided, and check whether or not its attributes match your desired criteria.

    1 hour ago, chkaufmann said:

    The Url is https://www.swimrankings.net/. The event is called two times. Both times AOk=False, once AError is 20, the second time it is 21.

    Error 20 is X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:

    Quote

    unable to get local issuer certificate

    the issuer certificate of a locally looked up certificate could not be found. This normally means the list of trusted certificates is not complete.

    Error 21 is X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:

    Quote

    unable to verify the first certificate

    no signatures could be verified because the chain contains only one certificate and it is not self signed.

    See:

    https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_verify.html

    https://www.openssl.org/docs/man1.0.2/man3/X509_STORE_CTX_get_error.html

    1 hour ago, chkaufmann said:

    When I set AOk to true, the request works

    Sure, because you are telling OpenSSL that you deemed the certificate OK to use, even if OpenSSL thinks otherwise.

    1 hour ago, chkaufmann said:

    if I do nothing in the event, the request doesn't work at all.

    Because OpenSSL pre-checks the certificate before letting you do your own checks on it.  So, if OpenSSL doesn't think the certificate is OK, and you do nothing to override that decision, then the certificate is not usable and the handshake fails.

    1 hour ago, chkaufmann said:

    With my limited knowledge about encryption I'm a bit lost here.

    Verifying the peer's identity is a separate operation from encryption.  The peers have to trust each other before they exchange encryption keys with each other.


  2. 58 minutes ago, alphac said:

    If i install indy, (Succesfully compiles and installs), multiple other components seem to lose their bpl files in the Packages window and say cannot be found.

    What are the actual error messages?  Changes are, those components are linked to the version of Indy that is pre-installed with the IDE, and will need to be recompiled if you install a different version of Indy, as a few method signatures did change to accommodate the OAuth SASL.

    1 hour ago, alphac said:

    Then vice versa when i reinstall those components...indy gets unregistered from the package list.

    That is odd, not sure what to make of that.


  3. 1 hour ago, KodeZwerg said:

    I can not answer if it is implemented in your Delphi 7 installation

    Extended RTTI via the System.Rtti unit was introduced in Delphi 2010.

    1 hour ago, KodeZwerg said:
    
    if ((LRttiProperty <> nil) and (LRttiProperty.Visibility in [mvPrivate, mvProtected, mvPublic, mvPublished])) then 

     

    Why filter by visibility rather than by writability?

    if (LRttiProperty <> nil) and LRttiProperty.IsWritable then 

     


  4. 2 hours ago, PizzaProgram said:

    If I understand it right, I will need :

    GetPropValue() and SetPropValue() functions

    I tend to stay away from those functions since they use Variant, which is usually unnecessary overhead.  But it depends on your particular needs.

    2 hours ago, PizzaProgram said:

    or rather: GetInt64Prop() ?

    interesting is I could not find any GetInt32Prop() nor GetIntProp() ...

    Integral properties are handled by GetOrdProp() and SetOrdProp() (as in, Ordinal)

    • Thanks 1

  5. It's been a long time since I tried this, but it used to be that if you simply didn't have any project loaded in the IDE and then edited the Project Options, they would save as defaults.  Not sure if that is still the case nowadays.

     

    Another approach would be to create Option Sets that contain your desired settings, and then you can apply those Sets to new projects as needed.

     

    https://docwiki.embarcadero.com/RADStudio/en/Option_Sets_Overview


  6. 5 hours ago, Sherlock said:

    Quoting is indeed rather tedious.

    Didn't used to be 😞  Used to be able to just quote an entire message and then break it up as I address each part of it.  I can still accomplish that, but it's several more steps now, so more tedious, but I'm getting the hang of it.  Still has some ugly quirks, though.

    5 hours ago, Sherlock said:

    But a workaround for this might be the possibility to write an answer and select blocks from the original post and then click quote selection.

    I suppose so.  Other forums have that option.  Would like the original functionality back, though.  But this added as a new separate feature could be useful, too.

    5 hours ago, Sherlock said:

    Works pretty good, and will give you the result you wanted, without all the Copypasta.

    Depends on how big the selections are.  Quoting a few sentences, sure.  Quoting paragraphs/code snippets, maybe not so much, if you have to scroll to make the selection.


  7. 2 hours ago, WalkingAway said:

    But anyway, is it possible to achieve something like this (I mean totally in IDE, design time):

    Yes, certainly.  And very much as you described it.

     

    You have a base component class named TSQLBuilderProvider, which has virtual/abstract methods as needed.  Then you derive several DB-specific classes from it, which implement those methods.  Each class can have its own DB-specific properties as needed.

     

    Then you have a TSQLBuilder component, which has a published property of type TSQLBuilderProvider.

     

    Now, you can drop a TSQLBuilder component and a DB-specific TSQLBuilderProvider component onto your Form, and assign the Provider to the Builder.  And then the Builder can use the abstract/virtual methods to interact with the Provider.

    2 hours ago, WalkingAway said:

    For every of them then can be setted up Query + Connection: for FD - TFDQuery and TFDConnection, for UniDAC - TUniConnection and TUniQuery and so one

    For that, it would make sense to expose additional properties on each DB-specific Provider component.  TSQLBuilderProviderFD could have published properties to assign TFDConnection and TFDQuery components to.  TSQLBuilderProviderUni could have published properties to assign TUniConnection and TUniQuery components to.  And so on.  Then the implemented methods can use those properties as needed.

    2 hours ago, WalkingAway said:

    Something similar to this - drop TSQLBuilder to the form and then there is some abstract property TSQLBuilderProvider, but if on form on f.e. TSQLBuilderProviderFD or TSQLBuilderProviderUniDac, it was possible to set it in design time.

    Yes.  That is basically what I described above.

    2 hours ago, WalkingAway said:

    2) Second thing: property that makes sence for one TSQLBuilder, but not usable / posible for other.

    That is why they should be exposed by the individual Provider components, not by the Builder component.


  8. Has anyone else noticed that lately, when quoting a message in a reply, then placing the cursor inside the quote and pressing Enter a few times, no longer splits up the quote into 2 quotes with editable whitespace between them?  It used to do this, and it was a very handy feature, but lately it hasn't been working for me, and it makes replying to quotes much more difficult.  Now I have to do a lot of copy/pasting and dragging around of quotes to get the same result that inserting Enters used to accomplish.


  9. 11 hours ago, JackT said:

    I didn't realise I had to use smart pointers for interfaces

    Next time, read the documentation, and also just look at the declarations (ie, the DocumentElement property returns an _di_IXMLNode, not an IXMLNode*).

    11 hours ago, JackT said:

    should I be setting dynamic arrays to NULL to destroy them

    Typically no, although you can do so manually if you want to, ie, to free the array's memory when you want to reuse the variable for a new array.

    11 hours ago, JackT said:

    or does the C++ Compiler handle it

    Yes.  The array's memory is freed when the object goes out of scope, or is reassigned.  Just any any other good RAII-style class does.

    11 hours ago, JackT said:

    For example will WSA get destroyed correctly when it goes out of scope

    Yes

    11 hours ago, JackT said:

    or do I need to do something else ?

    No


  10. 21 hours ago, JackT said:

    I am also having trouble with TXMLDocument and IXMLNODE. I can use TXMLDocument in a VCL builder application and Delphi without a problem but as soon as I try to use it in a C++ Builder command line program I get silent failures

    Did you read the documentation?

    https://docwiki.embarcadero.com/Libraries/en/Xml.XMLDoc.TXMLDocument

    Quote

    When TXMLDocument is created without an Owner, it behaves like an interfaced object. That is, when all references to its interface are released, the TXMLDocument instance is automatically freed. When TXMLDocument is created with an Owner, however, it behaves like any other component, and is freed by its Owner. When you add a TXMLDocument component from the component palette to a form or data module, it is automatically created with an Owner. When the TXMLDocument component is created using the global LoadXMLDocument function (or by a function that the XML Data Binding wizard generates to return the root node of the document), the function creates a TXMLDocument instance without an Owner.

    You are creating the TXMLDocument without an Owner, so it behaves like an interfaced object, but you are not treating it as an interfaced object.  You need to change your pMEGConfig variable from being a TXMLDocument* raw pointer to being a _di_IXMLDocument smart pointer that manages the interface's reference count.

     

    You need to do the same for your IXMLNode* raw pointers, too.  Use _di_IXMLNode instead.

     

    Also, because they are reference counted objects, make sure they go out of scope (or are explicitly Release() 'ed) before you call CoUninitialize().

     

    Also, do not 'new' an Exception that you are going to 'throw'.  Throw it by value rather than by pointer.  This is the one and only place where Delphi-style classes (ie, classes derived from TObject) are allowed to be created without 'new' in C++Builder.

     

    Try this:

    if (FAILED(CoInitializeEx(0, COINIT_SPEED_OVER_MEMORY))) {
        return;
    }
    try {
        TDOMVendor *vendor = DOMVendors->Find(_D("MSXML"));
        if (vendor == NULL) {
            throw Exception(_D("vendor MSXML XML wasn't found'"));
        }
    
        _di_IXMLDocument pMEGConfig = new TXMLDocument(NULL);
        // or: _di_IXMLDocument pMEGConfig = NewXMLDocument();
    
        pMEGConfig->DOMVendor = vendor;
        pMEGConfig->LoadFromFile(_D("An XML FILE"));
        pMEGConfig->Active = true;
    
        _di_IXMLNode ROOT = pMEGConfig->DocumentElement;
        ...
    }
    __finally {
        CoUninitialize();
    }

    Alternatively:

    if (FAILED(CoInitializeEx(0, COINIT_SPEED_OVER_MEMORY))) {
        return;
    }
    try {
        DefaultDOMVendor = _D("MSXML");
        _di_IXMLDocument pMEGConfig = LoadXMLDocument(_D("An XML FILE"));
        _di_IXMLNode ROOT = pMEGConfig->DocumentElement;
        ...
    }
    __finally {
        CoUninitialize();
    }

     


  11. You are storing custom allocated data in the TTreeNode.Data property.  To free that memory, you can override the TreeView's virtual Delete() method, which is called for every TTreeNode object that gets destroyed at runtime, eg:

    type
      TmyDBTreeView = class(TTreeView)
      protected
        procedure Delete(Node: TTreeNode); override;
      end;
    
    procedure TmyDBTreeView.Delete(Node: TTreeNode);
    begin
      inherited Delete(Node); // fires the OnDeletion event handler
      Dispose(PNodeRec(Node.Data));
      Node.Data := nil;
    end;

    However, a better way to handle this is to not use the TTreeNode.Data property at all.  Leave that untouched so users of your component can use it for their own application data.  Instead, you should create a custom descendant of TTreeNode to hold your component's extra data, and then you can override the TreeView's virtual CreateNode() method to return new instances of your custom Node class, eg:

    type
      TmyDBTreeNode = class(TTreeNode)
      public
        IdNode: integer;
        IdParent : integer;
      end;
    
      TmyDBTreeView = class(TTreeView)
      protected
        function CreateNode: TTreeNode; override;
      end;
      
    function TmyDBTreeView.CreateNode: TTreeNode;
    begin
      Result := TmyDBTreeNode.Create(Items);
    end;

    Then, any place that you were accessing PNodeRec(Node.Data)^ before, you can instead access TmyDBTreeNode(Node), for example:

    // if DataSource.DataSet.FieldByName(IDParentNode).AsInteger = PNodeRec(Node.Data)^.IdNode then
    if DataSource.DataSet.FieldByName(IDParentNode).AsInteger = TmyDBTreeNode(Node).IdNode then
    function TmyDBTreeView.GetNodeIdParent(Node: TTreeNode): integer;
    begin
      //Result := PNodeRec(Node)^.IdParent;
      Result := TmyDBTreeNode(Node).IdParent;
    end;
    
    function TmyDBTreeView.GetNodeId(Node: TTreeNode): integer;
    begin
      //Result := PNodeRec(Node)^.IdNode;
      Result := TmyDBTreeNode(Node).IdNode;
    end;

    And when adding new nodes to the TreeView, you don't need to use Add...Object() methods anymore, you can just use the normal Add...() methods instead, eg:

    //New(NRec);
    //NRec^.IdNode := DataSource.DataSet.FieldByName(IDNode).AsInteger;
    //NRec^.IdParent := DataSource.DataSet.FieldByName(IDParentNode).AsInteger;
    //Node := Items.AddObject(nil, DataSource.DataSet.FieldByName(DataField).AsString, NRec);
    Node := Items.Add(nil, DataSource.DataSet.FieldByName(DataField).AsString);
    TmyDBTreeNode(Node).IdNode := DataSource.DataSet.FieldByName(IDNode).AsInteger;
    TmyDBTreeNode(Node).IdParent := DataSource.DataSet.FieldByName(IDParentNode).AsInteger;
    // New(DNode);
    // DNode^.IdNode := DataSource.DataSet.FieldByName(FIDNode).AsInteger;
    // DNode^.IdParent := DataSource.DataSet.FieldByName(FIDParentNode).AsInteger;
    // NewNode := Items.AddChildObject(Node, Field.AsString, DNode);
    NewNode := Items.AddChild(Node, Field.AsString);
    TmyDBTreeNode(NewNode).IdNode := DataSource.DataSet.FieldByName(FIDNode).AsInteger;
    TmyDBTreeNode(NewNode).IdParent := DataSource.DataSet.FieldByName(FIDParentNode).AsInteger;

    ---

     

    That being said, I notice a number of other issues with your code, that are unrelated to node management.

     

    1. Why do you have a Sleep() loop inside of your TmyDBTreeView destructor?  Not only is a loop redundant when you could simply calculate the wanted duration in a single call, but calling Sleep() during destruction really doesn't belong there to begin with.

     

    2. Any use of Items.(Begin|End)Update() should be protected with a try..finally block.

     

    3. This code is wrong:

    procedure TmyDBTreeView.CMGetDataLink(var Message: TMessage);
    begin
      Message.Result := Integer(FDataLink);
    end;

    If you ever try to use your component in 64bit, this will fail as it will truncate the returned pointer.  The Message.Result is a NativeInt, not an Integer, so cast accordingly.

     

    4. Inside of TmyDBTreeView.SetDataSource(), since you are calling FreeNotification() on a new DataSource, you should call RemoveFreeNotification() on any DataSource that was previously assigned.  Although, I think this is completely redundant since you are not actually storing a reference to the DataSource, you are just assigning it to your DataLink, so you could just remove use of FreeNotification() altogether and let the DataLink handle that for you.

     

    Also, SetDataSource() is assigning the new DataSource to your DataLink only if csLoading is enabled, which means it is being assigned only during DFM streaming. But if a user of your component decides to change the DataSource at runtime after the DFM is loaded, you are not updating your DataLink.

     

    5. in TmyDBTreeView.DeleteNodeFromTreeOnly(), you are looping incorrectly.  Since you are looping forwards, if a node is deleted then your loop counter will get out of sync and end up skipping the next node.  To account for that, you need to either:

     

    a. loop backwards instead of forwards, eg:

    procedure TmyDBTreeView.DeleteNodeFromTreeOnly(id_node: integer);
    var
      i: integer;
    begin
      for i := Items.Count - 1 downto 0 do begin
        //if PNodeRec(Items[i])^.IdNode = id_node then Items[i].Delete;
        if TmyDBTreeNode(Items[i]).IdNode = id_node then Items[i].Delete;
      end;
    end;

    b. change the loop so your 'i' variable is incremented only when a node is NOT deleted, eg:

    procedure TmyDBTreeView.DeleteNodeFromTreeOnly(id_node: integer);
    var
      i, cnt: integer;
    begin
      i := 0;
      cnt := Items.Count;
      while i < cnt do begin
        //if PNodeRec(Items[i])^.IdNode = id_node then Items[i].Delete then
        if TmyDBTreeNode(Items[i]).IdNode = id_node then Items[i].Delete then
          Dec(cnt)
        else
          Inc(i);
      end;
    end;

     

    • Like 1

  12. 13 hours ago, AlanScottAgain said:

    I'm trying to compile FB4D for ios. FB4D is dependent the JOSE library.

    I'm not familiar with those libraries.  In fact, I've never even heard of them before.

    13 hours ago, AlanScottAgain said:

    On ios I get: [DCC Error] JOSE.OpenSSL.Headers.pas(168): E2003 Undeclared identifier: 'GetCryptLibHandle' and the relevant code is IFDEFed out due to - {$IFNDEF STATICLOAD_OPENSSL}

    Indy uses static linking on iOS devices.  It uses dynamic loading on every other platform, including iOS Simulator.

     

    https://docwiki.embarcadero.com/RADStudio/en/OpenSSL

     

    At the time when iOS support was first added to Indy, Apple supported only static libraries on iOS.  I think that has changed in recent years, but Indy has not been updated to support that yet.

    13 hours ago, AlanScottAgain said:

    How can I get this to work on iOS, please.

    Contact the author of those other libraries and find out why they are trying to access an Indy function that doesn't exist on iOS devices.


  13. 4 hours ago, CoMPi74 said:

    I am afraid such a form can be activated (gets focus) when clicked. I want to avoid such behaviour.

    Override the Form's CreateParams() method to enable the WS_EX_NOACTIVATE extended style:

    procedure CreateParams(var Params: TCreateParams); override;
    ...
    procedure TMyForm.CreateParams(var Params: TCreateParams);
    begin
      inherited;
      Params.WindowClass.ExStyle := Params.WindowClass.ExStyle or WS_EX_NOACTIVATE;
    end;

     


  14. 9 minutes ago, Mike Warren said:

    That's what I'm going to have to do. It just means I'll have to manually move the TImage whenever the TRectangle is moved.

    Yes, but that is not a big deal at all.

×