Jump to content

Remy Lebeau

Members
  • Content Count

    2338
  • Joined

  • Last visited

  • Days Won

    95

Everything posted by Remy Lebeau

  1. Remy Lebeau

    Form still on display when property Visible = false

    That is not what Roger is saying. C++Builder can certainly step into the Delphi-written VCL source code under 32bit (I've done it countless times) - just apparently not when compiling for 64bit (which I never do) due to the different debuggers being used by C++ and Delphi under 64bit.
  2. Remy Lebeau

    StringGrid: how to get the column number via right-click

    That is the wrong approach. Do not perform business logic (like updating UI controls) inside a drawing event. In the OnMouse... event(s), take note of which column is being clicked on, and save that value somewhere, then invalidate the Grid to trigger a repaint before displaying the popup menu. When the popup menu is closed, clear the saved value and invalidate the grid again to trigger a new repaint. Then, inside the grid's OnDraw... event(s), check if the value is set, and if so then draw any cells belonging to that saved column as highlighted.
  3. Remy Lebeau

    Compiling code originally for VS in C++Builder

    I'm aware of what extern "C" is and what it does. In the context of THIS discussion, however, it ALSO has the side effect of removing name mangling on exported symbols.
  4. Remy Lebeau

    How to free TListView Objects (String)

    I updated my answer with a 3rd option, too
  5. Remy Lebeau

    How to free TListView Objects (String)

    As you already know, you need to use the TListView.OnDeletion event to dispose of the TListItem.Data memory that you are allocating. If you read the documentation for StrAlloc(), the correct way to free that memory is with StrDispose(), not FreeMem(): procedure TMainFrm.LV_DataDeletion(Sender: TObject; Item: TListItem); begin if Item.Data <> nil then begin StrDispose(PChar(Item.Data)); Item.Data := nil; end; end; Alternatively, a slightly easier way is to use a normal String and let the compiler manage it. A String is implemented as a pointer, and you can store that pointer in the TListItem.Data. You would just have to ensure its reference count is incremented while stored in TListItem.Data, and decremented when you are done using it: var i : Integer; ListItem : TListItem; PObject : Pointer; begin for i := 0 to 3 do begin ListItem := AList.Items.Add; ... PObject := nil; String(PObject) := '...'; ListItem.Data := PObject; end; procedure TMainFrm.LV_DataDeletion(Sender: TObject; Item: TListItem); var PObject: Pointer: begin if Item.Data <> nil then begin PObject := Item.Data; Item.Data := nil; String(PObject) := ''; end; end; var sPath : string; begin if (LV_Data.Items.Count > 0) AND (LV_Data.ItemIndex <> -1) then begin sPath := String(LV_Data.Items[LV_Data.ItemIndex].Data); end; That being said, a much safer and cleaner solution is to not use the TListItem.Data property at all. Instead, derive a new class from TListItem and add a String member to it, then use the TListView.OnCreateItemClass event to let TListView create instances of your derived class: type TMyListItem = class(TListItem) public Path: string; end; procedure TMainFrm.LV_DataCreateItemClass(Sender: TCustomListView; var ItemClass: TListItemClass); begin ItemClass := TMyListItem; end; var i : Integer; ListItem : TListItem; begin for i := 0 to 3 do begin ListItem := AList.Items.Add; ... TMyListItem(ListItem).Path := '...'; end; var sPath : string; begin if (LV_Data.Items.Count > 0) AND (LV_Data.ItemIndex <> -1) then begin sPath := TMyListItem(LV_Data.Items[LV_Data.ItemIndex]).Path; end; No mess, no fuss. The memory is managed for you, and will be cleaned up automatically, no OnDeletion handler needed.
  6. Which Indy does - the IdSSLOpenSSLHeaders.IdOpenSSLSetLibPath() function, as Lajos Juhász mentioned. By default, Indy loads the DLLs using the system search path, but if you call IdOpenSSLSetLibPath() first then Indy loads the DLLs using the specified path instead.
  7. Remy Lebeau

    Form still on display when property Visible = false

    Without a reproducible example, there is simply no way for anyone to diagnose your problem with the limited information provided so far. You might have to enable Debug DCUs and step into the VCL source code with the debugger to figure out what is actually going on internally when you are setting Visible = false. Clearly there is a step being skipped inside of it when updating the underlying Win32 window.
  8. Remy Lebeau

    Code using TIdIMAP4 driving me mad !!

    In that case, the "SSL" option is for implicit SSL/TLS (port 993), and the "STARTTLS" option is for explicit TLS (port 143), where "None/STARTTLS" makes TLS optional whereas the other "STARTTLS" option makes TLS required. So it looks like the server is using a typical IMAP setup, you just had a mismatch in your code.
  9. Remy Lebeau

    Code using TIdIMAP4 driving me mad !!

    That basically says to use implicit SSL on port 993, and use port 143 for everything else. Which matches up with what I described earlier. What are the other options provided in the "Encryption" field?
  10. I know, and that is technically wrong per the specs, even if it is being accepted as-is. Yes, that is the simplest way to go in this situation. I can't comment on that without seeing the code that was doing the sending/reading, and the raw data. Personally I would not have used "x-www-form-urlencoded" for this kind of data. "multipart/form-data" would have made more sense for posting a binary file with metadata. But JSON is also a common format to use in REST APIs. Either way would have avoided the url-encoding issue.
  11. The C# code is writing the base64 content as-is to the socket, it is not encoding the base64 to the "x-www-form-urlencoded" format. Base64 can use '+' and '=' characters, which are reserved in "x-www-form-urlencoded" and must be encoded as "%2B" and "%3D" in application data, respectively. The receiver must decode them back into '+' and '=' characters, respectively, before then decoding the base64. Per the HTML standards, which define the "x-www-form-urlencoded" format: HTML 4.01 Section 17.13.4 ("Form content types"): HTML 5 Section 4.10.16.4 ("URL-encoded form data"): In other words, in a "x-www-form-urlencoded" submission, any non-syntax characters (ie, field separators '=' and '&') that are not in "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789*-._" should be encoded in %HH format, except for space characters which are encoded as '+' instead. That means even your "DevApp" field should be transmitted as "C%23" instead of as "C#".
  12. Remy Lebeau

    Code using TIdIMAP4 driving me mad !!

    Can you please provide the actual configuration you are expected to use? This does not sound like a standard setup.
  13. Remy Lebeau

    Breakpoints do not work.

    That is not the vibe I get when reading his question. He likely just wants to debug his own source code, not Delphi's framework source code.
  14. Remy Lebeau

    TIdSNTP still providing daylight saving time

    Yes, and has been for several years now: https://www.indyproject.org/2019/11/28/indy-svn-retiring-long-live-github/ Yes, it will include an updated snapshot of Indy from about a month ago. However, you don't have to upgrade Delphi just to get a new Indy version. You can install the latest GitHub repo version manually: https://github.com/IndySockets/Indy/wiki/Updating-Indy
  15. Remy Lebeau

    Form still on display when property Visible = false

    This code is taken out of context, and hard to diagnose as-is. You are going to have to show a more complete example. But if I had to guess, you are likely seeing a completely different Form object onscreen than the one that is processing this code.
  16. Remy Lebeau

    Breakpoints do not work.

    Are you sure you are actually running in debug mode?
  17. Remy Lebeau

    Code using TIdIMAP4 driving me mad !!

    Are you sure you are supposed to be using implicit TLS on port 143, and not explicit TLS instead? Implicit TLS sends the TLS handshake as soon as the TCP connection is established, before exchanging any other data, thus all protocol data is encrypted. Explicit TLS (aka STARTTLS) sends the TLS handshake after first establishing an unencrypted TCP connection and greeting the server, and then asking the server for permission to start a TLS session (such as before authenticating). For IMAP, implicit TLS is typically used on port 993, and explicit TLS is used on port 143.
  18. Remy Lebeau

    DEC and FPC compatibility

    Can you be more specific? What is the actual issue? Indy uses a mix of IFDEF/ENDIF and IF/IFEND, and it works fine in both Delphi and FPC. You might consider turning on LEGACYIFEND in Delphi XE3+, if you are not already doing so.
  19. Why not? The user won't notice a difference, and your code/project will be easier to manage. You are loading the Dictionary at runtime anyway, so what does it matter where the data originates from at runtime? Make things easier on yourself.
  20. Remy Lebeau

    Code using TIdIMAP4 driving me mad !!

    It is not a bug, and it is not the SSLIOHandler that is changing the Port. It is actually the UseTLS property setter that does it. You are initializing the Port to the standard IMAP port 143, then setting UseTLS to utUseImplicitTLS, so the property setter changes the Port to the standard IMAP implicit TLS port 993. This is working as designed. If you need to use implicit TLS on port 143 (why?), then you need to set the Port after setting the UseTLS.
  21. Remy Lebeau

    communicate between 2 progs with sendmessage.

    Sorry, my bad. I left out the part where the overriden WndProc() needs to pass unhandled messages to the default handler. I have corrected my example. What I showed applies to all C++Builder versions. That won't work. That event is triggered only for messages that are posted to the main thread message queue. Which your example message is not. That likely won't work, either, because your MainForm's class name is TMainForm not TAstroclockMainForm (unless what you have shown is not your real code).
  22. Why are you hard-coding so much data directly in your source code to begin with? Why not simply store the data in an external file or database and then load it from there at runtime? If you absolutely need the data to be present statically in your app's executable, I would suggest having the auto-generator store the data in a separate file that is then linked into the app's resources at compile time, and then you can load the data from that resource at runtime. This much data really DOES NOT belong in the source code directly at all. Another benefit of this approach (using either a file, database, resource, etc) is that you can update the data on the user's machine without having to deliver a new executable from your dev machine every time (in the case of using a resource, there are plenty of 3rd party tools available to update an app's resources directly). You can, of course, also update the data on your dev machine and recompile if you really want to.
  23. That should only happen if you are sending the data in the URL query string, or in the HTTP body in 'application/x-www-webform-urlencoded' format. You need to show your actual C# and Delphi codes for the REST request, you are clearly not setting up and/or processing the request correctly. DO NOT employ the workaround you have described, that is the wrong solution. You need to fix the underlying bug in your code that is messing up the data in the first place.
  24. Remy Lebeau

    communicate between 2 progs with sendmessage.

    Is "myprog" the title for your program's TApplication window or TForm window? It makes a big difference. I'm suspecting the latter. You are installing a message handler for the TApplication window. To handle messages for the TForm window, override the TForm's virtual WndProc() method instead: void __fastcall TMainForm::WndProc(TMessage &Message) { if (Message.Msg == WM_USER) { Application->MessageBox("", "", MB_OK); Message.Result = 1; } else TForm::WndProc(Message); } That being said, WM_USER is not a good choice for inter-process communications. Use WM_APP or RegisterWindowMessage() instead.
  25. Remy Lebeau

    Thread and free

    TThread.Queue() runs asynchrously - it returns to the caller immediately and its passed procedure is executed in the main thread at some future time. So, your first example is mostly correct - the anonymous procedure will have to transfer ownership of the TStringList to the main thread so it can free the TStringList after updating the UI. However, be sure to move your try..finally into the procedure as well to ensure the TStringList is actually freed even if something goes wrong, eg: procedure TForm16.ShowComputedDetail; begin TTask.Run( procedure var lTstrings: TStrings; begin lTstrings := TStringList.create; try ComputeDetail(lTstrings); TThread.Queue(nil, procedure begin try MyTMemo.BeginUpdate; try MyTMemo.Lines.Assign(lTstrings); finally MyTMemo.EndUpdate; end; finally lTstrings.Free; end; end); except lTstrings.Free; raise; end; end); end; In your 2nd example, you will need to change TThread.Queue() to TThread.Synchronize() to ensure the TStringList is not freed before the main thread has a chance to use it, eg: procedure TForm16.ShowComputedDetail; begin TTask.Run( procedure var lTstrings: TStrings; begin lTstrings := TStringList.create; try ComputeDetail(lTstrings); TThread.Synchronize(nil, procedure begin MyTMemo.BeginUpdate; try MyTMemo.Lines.Assign(lTstrings); finally MyTMemo.EndUpdate; end; end); finally lTstrings.Free; end; end); end;
×