Jump to content

Remy Lebeau

Members
  • Content Count

    2684
  • Joined

  • Last visited

  • Days Won

    113

Everything posted by Remy Lebeau

  1. Remy Lebeau

    Prevent Alt or Ctrl + Print Screen

    On Windows 7 and later, you can use SetWindowDisplayAffinity() to specify that you want your Form window to only appear on a monitor display. That will omit (black) it out in screen captures, etc.
  2. Remy Lebeau

    Show a FMX form inside a dll from a VCL application

    Not safely, no. Is it legal to have a cross-process parent/child or owner/owned window relationship?
  3. Remy Lebeau

    Find exception location from MAP file?

    The *preferred* base addresses are in the map file, as well as in exe/dll PE headers, but it is not guaranteed that exe/dll modules will actually use those base addresses at runtime (typically, they will, but the OS is free to move them somewhere else). You can use the Win32 GetModuleHandle() function, or the RTL's SysInti.HInstance, to get the actual base address at runtime.
  4. There are 3rd party Object Inspectors available, if you search around. Or, you could write your own editor using the VCL's TValueListEditor component and some manual RTTI logic.
  5. That article is written for saving a single component to a file, not for saving multiple components. I would suggest saving the TForm itself rather than each of its child components individually.
  6. Why? The C code clearly names the parameter "num_elements", so it stands to reason that it expects an "element count", not a "byte count". A dynamic array is already a pointer, so you don't need to index into the array, PInteger(data) will suffice.
  7. Remy Lebeau

    Choose a Folder dialog

    No. IFDEF your code to call the relevant OS APIs directly (SHBrowseForFolder()/IFileOpenDialog on Windows, etc). Or else just make your own dialog/Form that iterates the filesystem (ie, via the System.IOUtils.TDirectory class) and display the contents as needed.
  8. No, it is worse than that. TThread.Synchronize() puts the specified method pointer into a global thread-safe queue, along with a waitable event, then posts a signal to the main UI thread letting it know the queue is pending, and then waits on the queued event to be signaled. The main UI thread periodically iterates the queue (whenever it receives the posted signal, as well as whenever the main message loop enters an idle state, or user code calls Classes.CheckSynchronize() directly). All of the queued methods are called in order, and their events are signaled to unblock their waiting threads.
  9. Remy Lebeau

    TFileStream fmShare modes

    Sharing flags are used with the Mode parameter, not the Rights parameter. Creation and Sharing flags can be OR'ed together in the Mode parameter, eg: Result := TFileStream.Create(FileName, fmOpenReadWrite or fmShareDenyNone{, 0}); That was true in the old days when fmCreate was defined as $FFFF and thus could not be mixed with any other flags, but that is no longer the case. When the Rights parameter was introduced (which is not used on Windows when fmCreate is used), fmCreate was redefined as $FF00 so it can now be mixed with sharing flags, eg: fs := TFileStream.Create(FileName, fmCreate or fmShareDenyNone{, 0}); If no sharing mode is specified, fmShareCompat is the default, except in the specific case of the old fmCreate value ($FFFF) being used, in which case the default is fmShareExclusive instead for backwards compatibility. But either way, on Windows, fmShareCompat and fmShareExclusive mean the same thing - there is no sharing enabled on the file.
  10. No, when ABinding is bound to a wildcard IP like '::0'. Internally, TIdUDPServer uses recvfrom() to read packets, and the information you want is simply not available from recvfrom(). You would need to use recvmsg()/WSARecvMsg() instead (ie, via Indy's TIdStack.ReceiveMsg() method), which requires the IP_PKTINFO/IPV6_RECVPKINFO option be enabled on the socket for recvmsg() to report the receiving adapter's info on each packet read. TIdUDPServer does not support recvmsg(), though. You would have to alter its source code and recompile. Otherwise, you could use TIdUDPClient instead and run your own reading logic with it (despite their names, TIdUDPClient and TIdUDPServer are not true client/server components since UDP is connectionless, so their roles are a little more blurry than with TCP. You can use TIdUDPClient as a server, and TIdUDPServer as a client). Otherwise, you could simply enumerate the local IPs (ie via Indy's TIdStack.GetLocalAddressList() method) and create a separate Binding for each IP individually, and then ABinding.IP will have a meaningful value in the OnUDPRead event. This does mean that TIdUDPServer would need to allocate multiple sockets, though. No. Sending data out from a bound socket will use the IP of the adapter that the socket is bound to. If the socket is bound to a wildcard IP, then the OS will pick which adapter to use, based on its own routing tables for the destination IP. If you want to send out from a specific adapter, you need to either create and bind a separate socket (ie TIdUDPClient) to that adapter, and then send using that socket. use sendmsg()/WSASendMsg() (which Indy does not have a wrapper for), passing in a msghdr struct containing an IP_PKTINFO/IPV6_PKTINFO control message that specifies the desired source IP and interface index. See Setting the source IP for a UDP socket
  11. Almost. It would be more accurate to say that it binds to all local network adapters for the Binding's specified IPVersion. The IPVersion is set to IPv4 by default (see the ID_DEFAULT_IP_VERSION constant in IdGlobal.pas). You would need 2 separate Binding objects to bind to all IPv4 and IPv6 adapters at the same time, as TIdUDPServer would have to create separate IPv4 and IPv6 listening sockets (Indy does not support dual-stack sockets at this time: ticket #29). For example: IdUDPServer.DefaultPort := ...; with IdUDPServer.Bindings.Add do begin IP := ...; IPVersion := Id_IPv4; end; with IdUDPServer.Bindings.Add do begin IP := ...; IPVersion := Id_IPv6; end; If you don't create any Bindings at all, TIdUDPServer will create 1 or 2 default Binding objects for you, depending on whether the underlying platform allows separate IPv4+IPv6 sockets to be bound on all adapters on the same port at the same time (not all do, ie Linux and Android do not, but Windows does). The above IP is an IPv6 address, so I'm guessing you have not created an IPv6 Binding to listen on. You can't bind an IPv4-only socket to IPv6 adapters, and vice versa.
  12. Remy Lebeau

    Issues with Sleep(1) called in a loop

    And also: https://stackoverflow.com/questions/9518106/winapi-sleep-function-call-sleeps-for-longer-than-expected
  13. Remy Lebeau

    SetLength TBytes Memory Leak

    The call stack in that log also looks a little off. System._DynArraySetLength() does not call System._LStrFromPWCharLen(), and System._LStrFromPWCharLen() does not call System.DynArraySetLength(). System._DynArraySetLength() calls System.DynArraySetLength() directly. So, even though the code shown does call System._LStrFromPWCharLen() (on the RawByteString type-cast), that call should not be on the call stack anymore when System._ReallocMem() is called.
  14. Remy Lebeau

    Timer game delphi 7

    This would be easier: seconds:=seconds mod 60;
  15. Remy Lebeau

    GMail Inbox

    Sorry, I don't know what that means. UIDs are unique within a given folder, but not necessarily across folders. Multiple folders can refer to the same message. And UIDs are persistent only so long as the folder's UIDValidity value doesn't change. If you save a UID across sessions, you have to check if the folder's UIDValidity has changed before you can use the UID again. When you select a folder with TIdIMAP4.SelectMailBox(), its current UIDValidity value is stored in the TIdIMAP4.MailBox.UIDValidity property. Refer to RFC 3501 section 2.3.1.1 for more details. TIdIMAP4.SearchMailBox() returns message numbers, not UIDs. If you want UIDs, use TIdIMAP4.UIDSearchMailBox() instead. Otherwise, you can extract a UID from the result of TIdIMAP4.RetrieveHeader(), or pass message numbers from TIdIMAP4.SearchMailBox() to TIdIMAP4.GetUID().
  16. Remy Lebeau

    GMail Inbox

    Looks like you have extra spaces surrounding the 189. Do you get the same error if you remove them? Also, I found this, might be useful: How to remove a label from an email message from Gmail by using the IMAP protocol?
  17. Remy Lebeau

    Where I can find the SSL DLLs for Indy?

    What does Indy's WhichFailedToLoad() function report after the error occurs? Are you using 1.0.2u for BOTH DLLs? Do you have other versions of OpenSSL on your system? Try using SysInternals Process Monitor to make sure your app is actually attempting to load the correct DLLs you are expecting, and not some other DLLs. It should work, yes.
  18. Remy Lebeau

    GMail Inbox

    Have you tried using \Inbox instead, as shown in GMail's IMAP Extensions documentation? IdImap4.SendCmd('UID STORE ' + rMess.UID + ' -X-GM-LABELS (\Inbox)', ['OK','BAD','NO'], true); That being said, why are you using the SendCmd() method manually? TIdIMAP4 has a UIDStoreValue() method for sending a UID STORE command: IdImap4.UIDStoreValue(rMess.UID, sdRemove, 'X-GM-LABELS', '\Inbox');
  19. Remy Lebeau

    Build managed dll in Delphi

    That is what I would suggest, too. Granted, writing PInvoke wrappers is not always the easiest task, but it does work well if you get it right. I've written several DLLs (in C++) that are used in C# via PInvoke.
  20. Remy Lebeau

    caFree & ,Free??

    I don't need to read the help on it, I already know exactly what it is and how it works, thank you. That is written simpler as (frmSecondForm <> nil). But either way, checking for nil STILL won't solve the issue, because the frmSecondForm pointer is NOT being set to nil when the TfrmSecondForm object is destroyed, so ANY check for nil after destruction will NOT work in your example. The code you have shown earlier will STILL have undefined behavior even with the nil check added: procedure TfrmFormMain.btn_Calls_SecondFormClick(Sender: TObject); begin frmFormSecond := TfrmFormSecond.Create(nil); try frmFormSecond.ShowModal; Application.ProcessMessages; // <-- object destroyed here if TfrmFormSecond.rdgrpCloseOptions.ItemIndex = 0 finally // if object is destroyed above, UB happens below because frmFormSecond is a dangling pointer! if frmFormSecond.HandleAllocated then FreeAndNil(frmFormSecond); // or if (frmFormSecond <> nil) and frmFormSecond.HandleAllocated then FreeAndNil(frmFormSecond); end; end; And before you say it, yes you could fix that specific issue by setting the global frmSecondForm pointer to nil during destruction, like in the Form's OnDestroy event, eg: procedure TfrmSecondForm.FormDestroy(Sender: TObject); begin frmSecondForm := nil; end; procedure TfrmFormMain.btn_Calls_SecondFormClick(Sender: TObject); begin frmSecondForm := TfrmFormSecond.Create(nil); try frmSecondForm.ShowModal; Application.ProcessMessages; // <-- object destroyed here if TfrmFormSecond.rdgrpCloseOptions.ItemIndex = 0 finally if frmSecondForm.HandleAllocated then // <-- if object is destroyed above, UB here because frmSecondForm is now nil! FreeAndNil(frmSecondForm); // or if (frmSecondForm <> nil) and frmSecondForm.HandleAllocated then // <-- no more UB here! FreeAndNil(frmSecondForm); end; end; But, that won't solve the issue if someone decides NOT to use the global pointer to begin with, eg: procedure TfrmFormMain.btn_Calls_SecondFormClick(Sender: TObject); var frm: TfrmFormSecond; begin frm := TfrmFormSecond.Create(nil); try frm.ShowModal; Application.ProcessMessages; // <-- object destroyed here if TfrmFormSecond.rdgrpCloseOptions.ItemIndex = 0 finally // if object is destroyed above, UB happens below because frm is a dangling pointer! if frm.HandleAllocated then FreeAndNil(frm); // or if (frm <> nil) and frm.HandleAllocated then FreeAndNil(frm); end; end; To solve that, you would have to do something radical along the lines of the following: procedure TfrmSecondForm.FormDestroy(Sender: TObject); type PTfrmSecondForm = ^TfrmSecondForm; begin PTfrmSecondForm(Tag)^ := nil; end; procedure TfrmFormMain.btn_Calls_SecondFormClick(Sender: TObject); var frm: TfrmFormSecond; begin frm := TfrmFormSecond.Create(nil); try frm.Tag := NativeInt(@frm); frm.ShowModal; Application.ProcessMessages; // <-- object destroyed here if TfrmFormSecond.rdgrpCloseOptions.ItemIndex = 0 finally if frm.HandleAllocated then // <-- if object destroyed above, UB here because frm is nil! FreeAndNil(frm); // or if (frm <> nil) and frm.HandleAllocated then // <-- no more UB here! FreeAndNil(frm); end; end; But, no matter what, using HandleAllocated() to determine whether the Form object needs to be destroyed or not is just plain WRONG. Object lifetime and window lifetime are two completely different things. If you Create() a Form (or any object), you need to Free() it when you are done using it, if that is not already being done elsewhere (by an Owner, by an OnClose event, etc). No, because I don't need to run it (and besides, I can't run it, as I don't have a working compiler installed at the moment). Just by looking at the code, my many years of experience and deep understanding of the VCL's inner workings tell me EXACTLY how this code will behave.
  21. You likely copied an incompatible version of the OpenSSL DLLs. For instance, if you copied OpenSSL 1.1.x, as TIdSSLIOHandlerSocketOpenSSL supports only up to OpenSSL 1.0.2 (use this SSLIOHandler instead for 1.1.x). Or, if you copied 32bit DLLs for a 64bit app, or vice versa. What do Indy's OpenSSLVersion() and WhichFailToLoad() functions report?
  22. Remy Lebeau

    caFree & ,Free??

    This example is ABSOLUTELY WRONG and MUST NOT be used. Yes, you can use HandleAllocated() to check if a UI control's HWND exists without creating a new HWND, but you can't use HandleAllocated() to determine if the UI object itself exists. If a Form uses Action=caFree in its OnClose event to request itself be destroyed, and the resulting CM_RELEASE message gets processed (as this example is doing), the Form object will be destroyed, and any subsequent attempt to access its members, including HandleAllocated() (as this code is doing) will be undefined behavior, and likely will result in a crash.
  23. Remy Lebeau

    caFree & ,Free??

    This is only dangerous if the code is using BOTH Action=caFree with Free() together, which makes no sense to do. Use only one or the other, not both.
  24. Remy Lebeau

    caFree & ,Free??

    Delphi 10.4+ uses traditional object lifetime management on all platforms (no more ARC on Android/iOS). So, any object you Create(), that does not have an Owner assigned, must be Free()'d.
  25. Remy Lebeau

    Twsocket udp how to get the exact buffersize that received ? ?

    Those other libraries are likely either reading the UDP data for you and then giving you each datagram's actual data in the event, or they have peeked the socket to determine the available bytes and then telling you that size, ICS doesn't do either of those, it is just notifying you that datagrams have arrived, but is not doing anything to gleam information about them to present to you. For comparison, Indy's TIdUDPClient (which is not event-driven) requires you to provide it with a pre-allocated buffer for it to receive bytes into. But TIdUDPServer (which is event driven) will read each datagram into an internal buffer and then fire an event giving you the actual bytes that were read into that buffer. So, there is room for different mentalities, depending on your needs.
×