Jump to content

Remy Lebeau

Members
  • Content Count

    2333
  • Joined

  • Last visited

  • Days Won

    94

Posts posted by Remy Lebeau


  1. 18 hours ago, Adam said:

    I then tried adding the paths to Protocols, Core and System, it compiles past this point, however I end up with a compile error of "Ambiguous overloaded call to LocaleCharsFromUnicode'" in idglobal.pas.

    ...

    Edit: Please disregard. I managed to get this to work by prefixing the calls with "idGlobal." to specify to use the function contained in it's own unit.

    It should not be ambiguous.  Indy uses the LocaleCharsFromUnicode() function that Delphi provides in the System unit.  The IdGlobal unit defines its own version of that function only if Delphi's version doesn't exist.  So there should be no such function defined in the IdGlobal unit in Delphi 12.  If there is, then something is wrong.

    18 hours ago, Adam said:

    I'm now also going through this in a few other places, as well as getting rid of some IFDEFS and forcing the code for my version of Delphi to try and get it to compile. I'm guessing there's some conditional defines that work themselves out automatically if I was to compile the dpk's but of course that's what we're bypassing to have a dual install.

    The DPKs don't provide the conditionals that Indy uses.  They are all defined in IdCompilerDefines.inc which is included by the individual .pas files....  OH, yeah, the branch wasn't up-to-date with the latest .inc file yet.

    13 hours ago, Adam said:

    Looks like trying to install it seperately is failing too. I'm hitting the same problem again with ambiguous overloaded call to LocaleCharsFromUnicode, so I'm thinking the SASL branch may not be XE12 compatible. 

     

    @Remy Lebeau - are you able to advise please whether or not the SASL-OAuth branch at https://github.com/IndySockets/Indy/tree/sasl-oauth is compatible with Delphi XE14 at this time? I'm only seeing up to Indy280.groupproj, and I believe Delphi 12 should be Indy290?

    I have updated the branch with the latest master code for Delphi 12.

    • Thanks 1

  2. 11 hours ago, Adam said:

    Thanks for the clarification. I guess it's a spelling mistake on the Github website. "Can" probably was supposed to be typed in as "Can't"?  😉

    No, the spelling is correct. If you remove the preinstalled version of Indy then LivePreview/EMSEdge projects will break, but "you CAN use a SEPARATE installation of Indy 10 for non-LivePreview/EMSEdge projects" if you need to use multiple Indy versions.

    11 hours ago, Adam said:

    On a separate note, do you know if the sasl-oauth branch will be merged prior to the next Delphi release?

    I don't have an ETA on that.  The code is pretty much done for now, but it is an interface change as there is an extra parameter added to the SASL login procedures.  And also, I don't have palette icons for the new OAuth SASL components yet.


  3. 1 hour ago, David P said:

    In the interim I thought I'd detect the column widths changing and then enforce the min width, but there doesn't appear to be any event that fires when a colmn has changed size.

    Correct, there is no event published for this.  You would have to subclass the ListView to handle the HDN_ITEMCHANGING notification directly.  Alternatively, if you are building with Runtime Packages disabled, you can make a copy of Vcl.ComCtrls.pas and add it to your project, and then make the code change I mentioned earlier to fix the bug.

    1 hour ago, David P said:

    Never mind, found a solution you wrote in 2012.

    :classic_biggrin:


  4. 20 hours ago, alogrep said:
    When I do
      records:=Nil, does it free all "names" (and fname, lname) of all recs as well as the recods array itself?

    In this example, yes. Like strings, dynamic arrays are also reference-counted. When you nil a reference to a dynamic array, its refcount is decremented. When its refcount falls to 0, its contents are finalized as needed (to release their references, etc), and the array is freed from memory.

    • Thanks 1

  5.  Multiple versions of Indy can't be installed in the IDE at the same time. You would have to maintain separate copies and switch between them on a per-project basis as needed.


    Also, TIdSASLXOAuth2 is not in the master code,  it is still in a sasl-oath branch that hasn't been merged yet.

     

     


  6. On 3/4/2024 at 7:55 AM, gioma said:

    in reality that data can be a UTF8 string or a UNICODE string or a file.
    The first character of the data tells me what type of data I have to work with.

    That is not a good idea.  Such an indicator should not be in the data payload itself, it should precede the payload, ie in a separate message header. Also, to differentiate between UTF8 or UTF16, you could use standard Unicode BOMs.  So, for instance, have a message header that indicates whether the payload is text bytes or file bytes, and the total byte size.  Then in the payload itself, if it is text then have it start with a BOM before the actual text bytes.  Although, in reality, it is generally not a good idea to use UTF16 in data transmissions. Better to stick with just UTF8.  Convert to/from UTF16 in memory only, if needed.


  7. 11 hours ago, DelphiUdIT said:

    Do not use THE AUTOMATIC PROCEDURE in the instructions indicated in the previous link. It deletes files that do not belong to the Indy environment.

    Which files does it delete that it shouldn't?

    11 hours ago, DelphiUdIT said:

    The procedure indicated in the link (Update Indy) would have deleted these last 8 files.

    Oh. Nevermind.


  8. Your getUSBDeviceInfo() function requires a symbolic name containing at least 2 '#' chars in it, but the ports you are testing with don't have any '#' chars in their names at all.

     

    When your TButton.OnClick handler calls FindPorts(), it gets the device list and checks each device name with ContainsMediaTekPort().  You are recording the result of that check to the log file, which is why you see the device being found.  And then, if a matching name is found then the subsequent call to getUSBDeviceInfo() fails to parse the device name, thus skipping the retrieval of that device's info from the Registry.

     

    Your OnClick handler is then looping through the returned device array, checking each device's PortName for the device name (which in of itself is wrong since the PortName is different than the device name), and since the PortName was never being populated, that is why you see the "not found" error.

     

    You should have been able to discover this problem for yourself if you had stepped through your code with the debugger line-by-line and noticed that getUSBDeviceInfo() was never reading from the Registry.

     

    You need to fix this parsing problem so that getUSBDeviceInfo() actually returns the data you are expecting.

     

    Aside from that, just from a design perspective, I would strongly recommend changing FindPorts() to NOT include 'default' entries in the returned array.  When you are filtering for a specific type of port, that is all you should be returning, eg:

    Function FindPorts(Filter: string = ''): TUSBDeviceList;
    var
      sub: TStringList;
      i: integer;
    begin
      sub := TStringList.Create;
      try
        FindAvailableCOM(sub);
        if Filter <> '' then
        begin
          for i := sub.Count - 1 downto 0 do
          begin
            if Pos(Filter, sub[i]) = 0 then
              sub.Delete(i);
          end;
        end;
        SetLength(Result, sub.Count);
        for i := 0 to sub.Count - 1 do
          Result[i] := getUSBDeviceInfo(sub[i]);
      finally
        sub.Free;
      end;
    end;
    
    ...
    
    procedure TForm13.Button3Click(Sender: TObject);
    var
      Ports: TUSBDeviceList;
    begin
      Ports := FindPorts('MediaTek USB Port_V1633');
      if Length(Ports) > 0 then
      begin
        LogPortCheckingInfo('MediaTek port found: ' + Ports[0].DeviceParameters.PortName);
        ShowMessage('MediaTek port found.');
      end else
      begin
        LogPortCheckingInfo('MediaTek port not found.');
        ShowMessage('MediaTek port not found.');
      end;
    end;

    Now, all of that being said, I do also notice a number of other mistakes and general problems with the code you have provided, such as lack of adequate error handling, use of incorrect data types, etc.  It could really benefit from a good code review and cleanup in general.


  9. 1 hour ago, David Robb said:

    In case anybody had trouble getting the Indy packages to compile...

    I'm guessing you didn't see https://github.com/IndySockets/Indy/pull/517 yet?

     

    In any case, I'm also working on my own update to Indy for D12, but that update also includes bringing Indy's Package Generator up-to-date, which is why I haven't merged the above PR yet, as I want to see how the generated files compare to the PR's files.

     

    Although, I guess at this point, I should just merge the PR and then merge in any generator diffs later...

    • Like 1

  10. TListItem does not have a MinWidth property, you meant TListColumn instead.

     

    In any case, what version of Delphi are you using?  I can reproduce the problem in Delphi 12 w/ Patch 1 installed.  When dragging a column divider in the header, the TListColumn.MinWidth and TListColumn.MaxWidth values get ignored when the TListView is processing an HDN_ITEMCHANGING notification from the header.  TListView looks for HDN_ITEMCHANGING to trigger a redraw of the active TListItem, but there is an 'else' that skips the MinWidth/MaxWidth processing:

    if (Mask and HDI_WIDTH) <> 0 then
      begin
        if code = HDN_ITEMCHANGING then
          EnsureItemRedrawn(nil)
        else // <-- HERE!!
        begin
          Col := GetColumnFromTag(Item);
          if Col.MinWidth >= cxy then
            cxy := Col.MinWidth
          else
            if (Col.MaxWidth > 0) and (Col.MaxWidth <= cxy) then
              cxy := Col.MaxWidth;
            Col.Width := cxy;
        end;
      end;

    When I take that 'else' out, the MinWidth/MaxWidth values work properly as expected:

    if (Mask and HDI_WIDTH) <> 0 then
      begin
        if code = HDN_ITEMCHANGING then
          EnsureItemRedrawn(nil);
        //else // <-- HERE!!!
        begin
          Col := GetColumnFromTag(Item);
          if Col.MinWidth >= cxy then
            cxy := Col.MinWidth
          else
            if (Col.MaxWidth > 0) and (Col.MaxWidth <= cxy) then
              cxy := Col.MaxWidth;
            Col.Width := cxy;
        end;
      end;

    This bug does not exist in Delphi 10.3, so it was introduced sometime after that version:

    if (Mask and HDI_WIDTH) <> 0 then
      begin
        // NO redraw LOGIC HERE!!!
        Col := GetColumnFromTag(Item);
        if Col.MinWidth >= cxy then
          cxy := Col.MinWidth
        else
          if (Col.MaxWidth > 0) and (Col.MaxWidth <= cxy) then
            cxy := Col.MaxWidth;
          Col.Width := cxy;
      end;

    I would suggest filing a bug report with Embarcadero, but Quality Portal is still down.  I'll report it privately.

    • Like 1

  11. That is a LOT of code to go through, I'm betting most of it is irrelevant to the problem at hand.  And it doesn't even include your UI code that is displaying the "not found" error, so I don't even know which portions of this code are actually being exercised.


  12. Why does your device manager keep refreshing and showing the port disappearing? Are you perhaps opening the port during the time it has disappeared? What does your code look like that is opening the port?


  13. Look for the tfVerificationFlagChecked flag in the TTaskDialog.Flags property after TTaskDialog.Execute() returns true:

    if TaskDialog.Execute then
    begin
      ...
      Result.DoNotShowAgain := tfVerificationFlagChecked in TaskDialog.Flags;
      ...
    end

    And, if you want the checkbox to be initially checked when you display the dialog, enable the tfVerificationFlagChecked flag before calling TTaskDialog.Execute():

    TaskDialog.Flags := [tfUseCommandLinks, tfAllowDialogCancellation, tfExpandFooterArea];
    if DoNotShowAgainIsChecked then
      TaskDialog.Flags := TaskDialog.Flags + [tfVerificationFlagChecked];

     

    • Like 1
    • Thanks 3

  14. 8 hours ago, dummzeuch said:

    Any kind of exception will stop the program while running in the debugger, even if there is a handler for it, and bring the IDE to the foreground.

    You can configure the IDE to not break on exceptions.

    8 hours ago, dummzeuch said:

    I then have to check whether I am interested in it or not.

    I usually use breakpoints to tell the debugger to not break on exceptions that occur within specific sections of code I don't want to break on.


  15. 14 hours ago, dummzeuch said:

    That depends on the use case. If you want to show the error in order to then connect the debugger to the running executable, that's a good way to do it.

    If the code is expecting a debugger to attach, I would just call IsDebuggerPresent() in a sleep loop until it returns true or times out.


  16. 7 hours ago, PeterPanettone said:

    How can I get the boundaries of the displayed menu from the MenuHandle?

    You can't, as there is no way to get from the MenuHandle/HMENU to its dialog window.

     

    However, there can only be 1 menu active at a time, so you should be able to use FindWindow/Ex() to find the HWND of the active menu whose window class name is "#32768"/MAKEINTATOM(0x8000),

     

    Once you have the menu's HWND, you should be able to use GetWindowRect() to get its position and size.

    • Thanks 1

  17. 5 hours ago, Fudley said:

    Will installing the full (non-CE) 11.3 full version cause any problems with my current IDE settings, installed components etc?

    You can't have the 11.3 CE and 11.3 full versions installed on the same machine at the same time.  This is stated in the FAQs. So you will have to uninstall 11.3 CE before installing 11.3 full.  Otherwise, you can install the 12.x full version alongside the 11.3 CE version.


  18. You did not show the code that receives the file path from the file chooser and puts it into the TEdit, or show what the file path actually looks like.  But ACTION_GET_CONTENT is documented as returning a "content:" uri, which requires you to use the ContentResolver class to access the file data.

     

    But TIdMultipartFormDataStream.AddFile() uses TFileStream, which wants direct access to the file, which will not work with a "content:" uri on modern Android versions.

     

    So you will likely have to either:

    • access the file yourself via Android APIs and read its byte data into a TMemoryStream or TByteStream, or
    • create a custom TStream that wraps an Android InputStream from the ContentResolver.openInputStream() method

    And then use TIdMultipartFormDataStream.AddFormField() instead of TIdMultipartFormDataStream.AddFile() to send whichever TStream you end up using.

     

    Alternatively, you can use ContentResolver to extract the underlying "file:" uri from a "content:" uri, and then you should be able to open the file using a normal TFileStream (provided you have permissions to the file).

     

    Also, when using ACTION_GET_CONTENT, the ACTION_GET_CONTENT documentation says to wrap your Intent with Intent.createChooser(), and also include CATEGORY_OPENABLE and FLAG_GRANT_READ_URI_PERMISSION on your Intent.

    • Like 3

  19. Can to elaborate further?  What is the actual error that you are getting?  Note that TApplication.MessageBox() is generally just a wrapper for Winapi.MessageBox().  Although it is not entirely thread-safe, as it manipulates a global TaskActiveWindow list.   So yes, using Winapi.MessageBox() directly is generally safer when displaying a message box in a worker thread.

×