-
Content Count
2684 -
Joined
-
Last visited
-
Days Won
113
Everything posted by Remy Lebeau
-
What's New: Delphi RTL and Data Improvements - Delphi RTL - List, Arrays, and Collections Improvements
-
Send multiple attachments with smtp.office365/outlook.com
Remy Lebeau replied to weirdo12's topic in Indy
Indy doesn't send an email differently based on server, so if Microsoft is not processing an email the same way that other servers are, then you probably need to contact Microsoft for support, and send them examples of emails that are not displaying correctly. -
How do I get a Pointer to a generic type ?
Remy Lebeau replied to dormky's topic in Algorithms, Data Structures and Class Design
The 1st parameter of TRttiField.SetValue() expects a pointer to an object instance that the field belongs to, not a pointer to the field itself. Your function's Result is an array of T, is T an object type? If so, then you should constrain T with the 'class' constraint so that the compiler knows T is a class type, and thus Result is an array of object pointers. Can you provide a more complete example of what exactly you are trying to accomplish? Where are you getting the TRttiField from to begin with? -
Installing the wrong Delphi version on new tablet - RESOLVED
Remy Lebeau replied to JohnLM's topic in Delphi IDE and APIs
If it hasn't already started copying files onto your disk drive, ie because you didn't tell it where to install to yet, then I think you're fine.- 9 replies
-
- delphi
- installing
-
(and 2 more)
Tagged with:
-
Which post are you referring to? The code you have shown does not look like code I would have written. Note that the TFileOpenDialog.DefaultFolder applies only if there was no folder previously selected with the same dialog. You might want to prepare your initial IShellItem to your desired root folder before you open the dialog. That being said, you are setting the CanChange parameter to true only if the selected folder and the default folder are the same, which is not what you want. You need to check if the desired initial folder is a parent/ancestor of the selected folder. So, for that, you need to take the Dlg.ShellItem and walk its parent list comparing each one individually until you find a match or exhaust the list. Or, you could query each IShellItem for its ITEMIDLIST and use ILIsParent() or equivalent. For example (untested): var MyFolderShellItem: IShellItem; ... if Succeeded(SHCreateItemFromParsingName(PChar('C:\MyFolder'), nil, IShellItem, MyFolderShellItem)) then try FileOpenDialog1.Execute; finally MyFolderShellItem := nil; end; ... function IsParentOf(ARoot, AItem: IShellItem): Boolean; var iOrder: Integer; iParent: IShellItem; begin Result := (AItem.GetParent(iParent) = S_OK) and ((iParent.Compare(ARoot, SICHINT_ALLFIELDS or SICHINT_TEST_FILESYSPATH_IF_NOT_EQUAL, iOrder) = S_OK) or IsParentOf(ARoot, iParent)); end; { alternatively: function IsParentOf(ARoot, AItem: IShellItem): Boolean; var RootIdList, ItemIdList: PIDLIST_ABSOLUTE; begin Result := False; if SHGetIDListFromObject(ARoot, @RootIdList) = S_OK then try if SHGetIDListFromObject(AItem, @ItemIdList) = S_OK then try Result := ILIsParent(RootIdList, ItemIdList, FALSE); finally CoTaskMemFree(ItemIdList); end; finally CoTaskMemFree(RootIdList); end; end; } procedure TForm1.FileOpenDialog1FolderChanging(Sender: TObject; var CanChange: Boolean); begin CanChange := IsParentOf(MyFolderShellItem, (Sender as TFileOpenDialog).ShellItem); end;
-
Yes, your understanding is correct, but that wouldn't actually be a problem if each header handled its own alignment directives locally and made sure any alignment changes didn't bleed out into the caller's code.
-
I probably would have used a single port and delimited the 2 datas, but that's just me. Whatever works best for you. No, you need a separate client for each server port. But you can run the 2 clients in parallel, such as with threads.
-
I've recently updated Indy's GitHub repo to now tag the commits that have been bundled in the past few RAD Studio releases (including 12.0) since Indy switched from SVN to GitHub.
-
Still makes one wonder why Microsoft doesn't just force the alignment in its own headers where needed.
-
Not sure about Delphi, but the "What's New" page in the DocWiki says the following about C++, though:
-
Why? Can't you design your protocol to send your 2 sets of data over a single connection? That means the server is closing the connection on its end. Can you show your actual code that is managing your connections? Do you really need 2 separate connections to the same server, though? Not release specifically. However, if you are planning on re-connecting the same TIdTCPClient again, you should at least make sure its IOHandler.InputBuffer is cleared of any unread data after disconnecting, so Indy won't think the connection is still alive, eg: idTCPClientB.Disconnect; if idTCPClientB.IOHandler <> nil then idTCPClientB.IOHandler.InputBuffer.Clear;
-
Letting a user even see that another user's folder exists, even if it's not selectable, is just bad UI design and broken security waiting to be exploited.
-
That is literally exactly how Indy is designed to be used. Indy uses blocking sockets and synchronous I/O. Connect() will block the calling thread and not exit until the connection is established. Sends will block the calling thread and not exit until the data has been passed to the kernel. Etc. So, just do exactly what you said above, it will work fine. Just be sure to put the send in a try..finally to ensure the connection is closed even if the send raises an error, eg: IdTCPClient1.Connect; try // send whatever you need... finally IdTCPClient1.Disconnect; end; Most Indy clients are not event-driven. You do not need to wait for the OnConnect event. It is just a status event, not a logic-driving event.
-
TFileOpenDialog has OnFolderChanging and OnFileOkClick events that can be used to verify/reject the user's input so they can't use what you don't want them to use.
-
StringGrid: how to get the column number via right-click
Remy Lebeau replied to JohnLM's topic in VCL
Your 'c' variable is initialized to 0, which is likely why your column 0 gets highlighted at startup. Initialize the variable to -1 instead, and then update it on mouse clicks as needed. Also, you don't need to use the OnSelectCell event at all, just let the OnMouseDown code determine the column using the provided X/Y coordinates. Also, DO NOT call your OnDrawCell event handler direct!y. Let the system call it for you when the Grid actually needs to be painted naturally. Try something more like this instead: implementation var HighlightedColumn: Integer; ... procedure TForm1.FormCreate(Sender: TObject); begin HighlightedColumn := -1; end; procedure TForm1.sg1DrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState); begin if (ACol = HighlightedColumn) then begin sg1.Canvas.Brush.Color := clBlue; sg1.Canvas.FillRect(Rect); end; end; procedure TForm1.sg1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var c, r: Longint; begin sgl.MouseToCell(X, Y, c, r); if (r < sgl.FixedRows) then begin HighlightedColumn := c; sg1.Invalidate; end; end; -
Form still on display when property Visible = false
Remy Lebeau replied to Roger Cigol's topic in General Help
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. -
StringGrid: how to get the column number via right-click
Remy Lebeau replied to JohnLM's topic in VCL
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. -
Compiling code originally for VS in C++Builder
Remy Lebeau replied to Dave Nottage's topic in General Help
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. -
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.
-
Troubleshoot SSL/TLS connection with Indy
Remy Lebeau replied to dummzeuch's topic in Tips / Blogs / Tutorials / Videos
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. -
Form still on display when property Visible = false
Remy Lebeau replied to Roger Cigol's topic in General Help
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. -
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.
-
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?
-
PDF File Send as Base64 from c# to Delphi REST
Remy Lebeau replied to mazluta's topic in Network, Cloud and Web
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.