Jump to content

Remy Lebeau

Members
  • Content Count

    2337
  • Joined

  • Last visited

  • Days Won

    95

Everything posted by Remy Lebeau

  1. Remy Lebeau

    Uniqueness and Security of domain name

    What about requiring internal users to sign their EXEs with a company-issued certificate, and then having the DLL validate that when loaded?
  2. You could do that, but that is not a very good design choice. You would have to remember to always update BOTH references when updating EITHER reference. That risks the two references getting out of sync. If you absolutely need access to TMyFrame members that are not accessible via interface methods (which kind of defeats the purpose of using interfaces), you can always type-cast an interface back to TMyFrame when needed (D2010+), eg: var Intf: ISomeInterface; Intf := TMyFrame.Create; ... Use (Intf as TMyFrame).SomeMember as needed... ...
  3. I have checked in the code as a branch on GitHub (https://github.com/IndySockets/Indy/tree/TTimeZone). Overall, there were 22 files affected by adding this new feature.
  4. Remy Lebeau

    Is there codec for FMX, Android Bitmap ?

    No, FMX does not support the BMP format on Android by default. The documentation is quite clear on which formats are implemented on each platform: If you want to use BMP on Android, you can write your own class derived from TCustomBitmapCodec to handle that, and then register it with TBitmapCodecManager at runtime.
  5. In IdGlobalProtocols.TimeZoneBias(), correct? I'm thinking of updating IdGlobal.OffsetFromUTC() to use TTimeZone as well. And since most platform implementations of TimeZoneBias() are just returning -OffsetFromUTC(), that means OffsetFromUTC() should return (+1 * (TTimeZone.Local.UtcOffset.TotalMinutes / 1440)), and TimeZoneBias() should return (-1 * (TTimeZone.Local.UtcOffset.TotalMinutes / 1440)), is that correct? Ideally, I would like to simplify TimeZoneBias() to just returning -OffsetFromUTC() on all platforms. I don't know why it singles out Unix on Delphi but not FreePascal. In which case, since OffsetFromUTC() and TimeZoneBias() are basically doing the same thing, just returning the inverse of each other, and all uses of TimeZoneBias() are only being used to adjust TDateTime values between local and UTC times, I'm thinking of just deprecating TimeZoneBias() and introducing a couple of new LocalTime<->UTC conversion functions in IdGlobal.pas to make things easier. Then I can make better use of TTimeZone.Local.ToUniversalTime() and TTimeZone.Local.ToLocalTime() in Delphi, and LocalTimeToUniversal() and UniversalTimeToLocal() in FreePascal. That would eliminate TimeZoneBias() completely, and leave only 2 remaining uses of OffsetFromUTC() - in IdGlobal.LocalDateTimeToGMT() and IdFTPCommon.MinutesFromGMT().
  6. Which is perfectly fine. This is not a side effect of Supports() itself, but rather is due to your mismanagement of your interfaced object. Your TMyFrame class has reference counting enabled on it, but your fBaseClass member is not maintaining an active interface reference to the object, so the object has an initial reference count of 0 instead of 1, and then your cast to ISupportTask increments the reference count to 1 instead of 2, and then releasing that ISupportTask decrements the reference count to 0 instead of 1, freeing the object. As Dalija said, you need to change this line: fBaseFrame : TBaseFrame; To this instead: fBaseFrame : IInterface; And then this change this: procedure TForm22.FormDestroy(Sender: TObject); begin fBaseFrame.Free; end; To this instead: procedure TForm22.FormDestroy(Sender: TObject); begin fBaseFrame := nil; end; Or, simply get rid of the OnDestroy handler completely, since the fBaseFrame member will be finalized anyway then the TForm22 object is destroyed, releasing the reference for you. And, as David mentioned, you should change this: procedure TForm22.Button1Click(Sender: TObject); begin if Supports( fBaseFrameClass, ISupportTask ) then (fBaseFrame as ISupportTask).CheckTask; end; To this instead: procedure TForm22.Button1Click(Sender: TObject); var Task: ISupportTask; begin if Supports( fBaseFrame, ISupportTask, Task ) then Task.CheckTask; end;
  7. Remy Lebeau

    32bit bitmap

    Oh yeah, I keep forgetting that TBitmap does have some alpha-channel support built-in.
  8. Remy Lebeau

    working with new APIs

    You could use the library version of curl, libcurl, directly in your code. There is a Delphi language binding available for it. Or, you could simply convert the curl examples to equivalent HTTP/REST commands and then use whatever HTTP/REST client you want (ICS, Indy, TRESTClient, etc). Swagger is just a user-friendly HTML frontend for invoking REST commands. Any REST command the user can invoke on a Swagger page, an HTTP/REST client can also perform in code. Swagger is primarily meant for humans to use, not programs.
  9. Remy Lebeau

    32bit bitmap

    Because Windows doesn't have good support for 32bit alpha-channeled bitmaps to begin with. Good luck with that. What complications does PNG present to you? Are you working with VCL or FMX? The VCL's TPNGImage class is easy to use. FMX's TBitmap can be a bit difficult, depending on what you are trying to do with it. It would really help if you would explain the problem you are having exactly.
  10. Remy Lebeau

    TaskMessageDlg('.... behind form?

    Yes - if the dialog was not being assigned that Form's HWND as its owner window (in Win32 API terms, not VCL terms). A dialog can never appear behind its owner window, it stays on top of the owner. By default, VCL dialog components typically use the HWND of the currently active TForm that has focus, otherwise they may use the MainForm's HWND, or even the TApplication's hidden HWND. So, if the owner of the dialog is not the Form you are expecting, that would cause the symptom you describe. The main thing to know about TaskMessageDlg() is that it is just a wrapper. Internally, it performs a few system checks to decide whether to use the Win32 TaskDialogIndirect() function vs the VCL's own TMessageForm class. So, for instance, if you wanted to work around this issue, and you knew your app was always running on systems that support TaskDialogs, you could use the VCL's TTaskDialog component (or even TaskDialogIndirect() directly), explicitly passing it your intended Form's HWND as the dialog owner, eg: procedure TMyForm.DoSomething; begin // TaskMessageDlg(...); TaskDialog1.Title := ...; TaskDialog1.Text := ...; ... TaskDialog1.Execute(Self.Handle); end; procedure TMyForm.DoSomething; var config: TASKDIALOGCONFIG; begin // TaskMessageDlg(...); config.cbSize := sizeof(config); config.hwndParent := Self.Handle; config.pszWindowTitle := ...; config.pszMainInstruction := ...; config.pszContent := ...; ... TaskDialogIndirect(config, ...); end;
  11. Remy Lebeau

    Install recent Delphi versions on Windows XP

    Until recent years, I did all of my Delphi development work (for Indy, for beta testings, etc) solely in XP VMs. It wasn't until Embarcadero forced newer Delphi installers to fail on XP that I had to start using Win7 in new VMs. Even my day-job work (well, until my main projects reached EOL last month) included a physical XP box and an XP VM as my sole environment for all of my C++Builder work. XP is a fairly small, easily-installed, very stable OS to develop on, when you don't have to target new OS features (and even then, I still targeted new OS features while writing code on XP). And if an app runs good on XP, it is likely to run good on modern Windows, too.
  12. Remy Lebeau

    Hashing Street Addresses ?

    I can tell you from personal experience that parsing US addresses is not easy or fun. I have an application I worked on, which includes a feature to gather real-time address data from various PBX systems and then standardize the components of those addresses into a database table, similar to what you have shown above. That project has over 150 parsers for all kinds of different ways that PBXs format their address data. And when a customer happens to identify a new PBX/format that is not covered by the existing parsers, it usually takes me about 3 days to identify the new format (which is rarely documented), write a parser for it, and test it against not only the formatted data that is expected, but also all kinds of corner-case formatting variations that inevitably crop up in production. Because people can't seem to input similar addresses with any amount of reliable consistency. Or even stupid things, like putting the Town name in the Address1/2 field, or the County in the Town field, or even the whole address as a single text in the Address1 field. It happens.
  13. Actually, it can. When TIdIOHandler reads data from a socket, it reads everything that is available on the socket at that moment, and puts the data in its InputBuffer for read methods to then pull from. So, if there are multiple messages in flight on the connection, the IOHandler could read multiple messages at a time (or even portions of messages). Whether or not this causes problems for your code, I couldn't say for sure, since you did not show your actual code, only pseudo-code. IN THEORY, it should be OK, but I don't want to speculate without seeing your real code. But even with your pseudo-code, there is still potential for the Receive Thread to receive messages other than KeepAlives. If the main thread performs a read and it times out (network lag, etc), the message it was waiting on will not be read in the main thread, so it still will be waiting, and the Receive Thread could then pick it up. Depending on how the messages are formatted, and how you are reading them, there is even potential for the main thread to read only a portion of a message (it could receive some bytes, and then time out on others), and then the Receive Thread could read the remaining portion of the same message. It is really hard to diagnose your issue without actual details about your protocol, and seeing your actual code. If you happen to send that message near/exactly at the KeepAlive time, the server could send a KeepAlive message before it has a chance to see your new message. And then your main thread would end up reading the KeepAlive first, and if you unlock at that time then the Receive Thread would read the response that the main thread was expecting. To avoid that, you would need to have logic in the main thread that loops reading messages inside the lock until a non-KeepAlive message is received. That likely indicates the data the main thread is waiting for has actually being read and discarded by the Receive Thread, such as if you are getting your threads out of sync with each other, causing them to read each other's messages (or worse, partial messages). Unsolicited messaging and command/response messaging don't play well together in the kind of design you have chosen. That is why I suggest you re-write the logic to the kind of design I suggested earlier. No, you would receive the KeepAlive message. Why would you expect to receive garbage? Unless you mean the processing of the KeepAlive message as a response would be interpreted as garbage in the context of your requested operation. Then yes, that could happen. But you definitely don't want actual garbage appearing on your protocol, that would corrupt everything, and you would have to disconnect and start over. The only way that can happen is if either 1) nothing is being sent at all from the server (unlikely, but use a packet sniffer to verify), or 2) the data is being read and discarded somewhere else before you have a chance to read it in the main thread. Data doesn't just disappear unexpectedly. Yes, but then you would have to detect that KeepAlive message and perform another read to receive the actual response message you were expecting the first time. Again, please show your ACTUAL CODE in order to troubleshoot that. I can't answer that without seeing your ACTUAL PROTOCOL and your ACTUAL CODE.
  14. You have two threads that are wanting to read at the same time, and write at the same time. This is not a good design choice. It is a race between the threads, you don't know which thread will actually receive which message, so BOTH threads have to be ready to reply to KeepAlives, and BOTH threads have to be ready to handle non-KeepAlive replies. And worse, it is possible that one thread may read bytes that the other thread is expecting. It is just not a good situation to be in. I would suggest a completely different approach. Have 2 worker threads - 1 thread whose sole task is to read ALL incoming packets, and 1 thread whose sole task is to write ALL outgoing packets. When the reading thread receives a message, if the message is a KeepAlive then the reading thread can ask the writing thread to send a reply, otherwise the reading thread can dispatch the message for processing as needed (which probably shouldn't be done in the main thread, if you can avoid it). When the main thread (or any other thread) wants to send a message, it can ask the writing thread to send it. This way, you don't need to synchronize the reads and writes anymore. Only synchronize the requests for sending messages. Reading thread: Reader.Execute while not Terminated receive data (no timeout) if message type is keepalive create ack message Writer.Send(message) else dispatch message for processing Writing thread: Writer.Send(message) queue.lock try queue.add(message) signal.set finally queue.unlock end Writer.Execute while not Terminated if signal.wait(timeout) try queue.lock try make copy of queue queue.clear signal.reset finally queue.unlock end; send messages in copy finally copy.clear end; Main thread: Main.DoSomething create xml message Writer.Send(message) Main.DataReceived(data) parse data if should send next message create xml message Writer.Send(message)
  15. Remy Lebeau

    Android JInputStream wrapper?

    You don't need to know the file size for that. Simply stop reading when the stream's various read() methods return -1 indicating EOF has been reached. But, if you absolutely did need to know a file's size, then use the provided Uri to open a JFile to the file, and then you can call its length() method. You can create a JInputStream for a JFile using Android's FileInputStream class.
  16. Remy Lebeau

    Is this C++ builders new FORUM ???

    There is no longer an OFFICIAL forum provided by Embarcadero for Delphi/C++Builder. But, this is one of many UNOFFICIAL forums, yes. See https://blogs.embarcadero.com/community/ for other sites that Embarcadero has provided links to. The old old Delphi/C++Builder forums were migrated to Idera's community site awhile back ago, but just a couple of months ago Embarcadero shut down their forum on that site. They have decided that they don't want to compete with 3rd party forums anymore. They have had a long history of producing sub-par forum software, server failures/outages, etc, so they have finally given up trying to run their own forum. Gone for good, except for whatever may have been cached by 3rd party archiving sites.
  17. Sounds like an issue that needs to be reported to Embarcadero.
  18. Remy Lebeau

    Try-Finally-end; & Exit??

    No, see: http://docwiki.embarcadero.com/RADStudio/en/Exceptions_(Delphi)#Try...finally_Statements
  19. I can't answer that. And? Did you try using a newer version of OpenSSL? 1.0.2q is not the latest (I'm guessing you are using the libraries from Indy's GitHub repo?). The last version in the 1.0.2 series was 1.0.2u. I don't have Android binaries for that version, but I'm sure you can find them if you search around. For supporting the OpenSSL 1.1.x series, there is this SSLIOHandler instead, but I don't know if it works on Android or not. Do you have libssl.so in the same folder? Are they from the same OpenSSL version? Are you calling Indy's IdOpenSSLSetLibPath() function at program startup?
  20. Modern Android versions simply don't support OpenSSL anymore. They use BoringSSL instead, which Indy does not support. And on some (not all) Android devices, BoringSSL gets used even if the app tries to use OpenSSL dynamically. So, unless you statically build OpenSSL directly into your app binary, using OpenSSL on Android is a hit-or-miss endeavour. What does Indy's WhichFailedToLoad() function report when the error occurs? Also, does Indy's OpenSSLVersion() function report anything?
  21. Remy Lebeau

    Can the width of TaskMessageDlg be set?

    Not according to the documentation those links point to, they don’t. You can install a thread-local hook from SetWindowsHookEx() or SetWinEventHook() before calling TaskDialogIndirect()/TTaskDialog.Execute(), to intercept the dialog’s HWND when it is actually created, and then you can do whatever you want to it.
  22. Remy Lebeau

    How to completely hide application from taskbar (on launch)?

    It is for both: https://devblogs.microsoft.com/oldnewthing/20031229-00/?p=41283 Unlike VCL, FMX does not allow you to customize the creation of a Form’s HWND, so there is no option to remove the WS_EX_APPWINDOW style up front. Not without modifying FMX’s source code, as you have discovered. Is there a Unit1 already present in the source folder, if not in the Project? When creating a new unit, the IDE looks at existing units in the folder and chooses the highest unused sequential number. The best way to avoid creating the taskbar button at all is to not create any top-level HWNDs that have the WS_EX_APPWINDOW style. Something FMX tries to prevent you from doing.
  23. Remy Lebeau

    How to completely hide application from taskbar (on launch)?

    https://stackoverflow.com/questions/16768986/how-to-hide-firemonkey-application-button-from-taskbar-xe4 https://stackoverflow.com/questions/53765725/hide-taskbar-button-in-fmx-on-windows
  24. Remy Lebeau

    Internet time sync - with some timeout

    Starting a new elevated process can be done using the Win32 API ShellExecute/Ex() with the "runas" verb. Instantiating an elevated COM object can be done using the COM Elevation Moniker.
  25. Would one of these work for you (not sure whether UtcOffset returns positive or negative for, say, UTC-08:00)? Result := TTimeZone.Local.UtcOffset.TotalMinutes / 60 / 24; or: Result := -1 * (TTimeZone.Local.UtcOffset.TotalMinutes / 60 / 24); This would avoid having to query the system clock at all. I'm thinking of updating IdGlobal.OffsetFromUTC() to use TTimeZone internally when available, in which case TimeZoneBias() under Delphi UNIX can just be: Result := -OffsetFromUTC; Like it is on all other platforms.
×