Jump to content

Remy Lebeau

Members
  • Content Count

    2337
  • Joined

  • Last visited

  • Days Won

    95

Everything posted by Remy Lebeau

  1. Remy Lebeau

    Delphi, Python and Android

    https://wiki.python.org/moin/Android https://python-for-android.readthedocs.io/en/latest/ https://pythonspot.com/sl4a-android-python-scripting/
  2. Remy Lebeau

    TetheringManager refusing connection

    Sorry, no. I've never worked with App Tethering.
  3. Remy Lebeau

    Error is 10053 but StatusCode is 200

    By default, but that is not a requirement. You have to look at the response's Connection header to know for sure whether the server is leaving the connection open or not. If the connection is closed by the server, the response's Connection header will be set to "close", and the socket connection should be gracefully closed (but that depends on implementation) immediately after the last byte of the response has been sent. This kind of socket error can only happen if the client tries to read more bytes after the connection has been lost. Which means either the client is not detecting the end of the response correctly so it knows when to stop reading, or the server is not reporting the end of the response correctly. If the response's Content-Length header is missing, EOF is reported by socket connection closure (unless the response's Content-Type is a self-terminating media type, like MIME), so the server SHOULD close the connection gracefully, not abortively. If the Content-Length is present but has an invalid value, then the client may try to read more bytes than is actually being sent, which may lead to an abortive closure.
  4. Remy Lebeau

    TIdHTTP protocol transport safety

    In a word, no. That is simply not how TCP works, let alone HTTP. This is not limited to just TIdHTTP, but to any TCP/HTTP implementation. Only the low-level TCP stack has access to the ACKs that indicate data packets have actually reached their destination. Applications do not have access to that information.
  5. Remy Lebeau

    FormDestory call order

    That has NEVER been true, in ANY version... ... THAT is the correct behavior, in ALL versions. Auto-created Forms, like the MainForm, are owned by the Application object. They are not destroyed until the Application object is destroyed, which is after the main DPR code is done running and the VCL is being cleaned up. Nothing has changed. So the chance has to be something in your own code that is destroying the MainForm before the Application object is destroyed.
  6. Remy Lebeau

    Has $ELSEIF stopped working?

    The {$IF} and {$ELSEIF} directives have supported {$ENDIF} since Delphi XE4. See http://docwiki.embarcadero.com/RADStudio/en/Legacy_IFEND_(Delphi)
  7. Remy Lebeau

    Has $ELSEIF stopped working?

    You need to use {$ELSE}{$IFDEF ...}: {$DEFINE test2} ... Step := 0; {$IFDEF test1} Step := 1; {$ELSE} {$IFDEF test2} Step := 2; {$ENDIF} {$ENDIF} or {$ELSEIF Defined(...)}: {$DEFINE test2} ... Step := 0; {$IFDEF test1} // or: {$IF Defined(test1)} Step := 1; {$ELSEIF Defined(test2)} Step := 2; {$IFEND} // or: {$ENDIF} since XE4
  8. Remy Lebeau

    Enumeration Type as Parameter

    There are quite a few intrinsic functions that have been around for awhile but are still not documented by Embarcadero, but they are by 3rd parties. For instance, https://stackoverflow.com/questions/30417218/. See https://www.google.com/search?q=delphi+undocumented+intrinsics
  9. Remy Lebeau

    Updated Community Edition

    That is exactly what the Community Edition is.
  10. Remy Lebeau

    Updated Community Edition

    At my previous employer, we were stuck at v6.0, the PTBs would never let us upgrade beyond that. Personally, I never upgraded beyond XE2.
  11. Remy Lebeau

    IDGlobalProtocols GmtOffsetStrToDateTime

    I have added a new GetGMTOffsetStr() function to the IdGlobalProtocols unit.
  12. Remy Lebeau

    IPropertyStore MultiValue Strings

    Yes. And how to access the array of LPWSTR string pointers for any string-vector tag, like PKEY_Music_Artist. But that example makes the code very tag-specific, whereas my example should work for any tag generically.
  13. Remy Lebeau

    IPropertyStore MultiValue Strings

    Is there a reason why you seem to have completely ignored the code I gave you for this exact purpose?
  14. Remy Lebeau

    IDGlobalProtocols GmtOffsetStrToDateTime

    That is not likely to happen. Maybe add some overloads perhaps, but it would make more sense to simply make the declaration of RawStrInternetToDateTime() itself be public instead, and then you can call that. Or, to add a new function that parses a strong and just returns the GMT portion rather than the date portion. It is not as simple as you make it out to be. You are not just changing the declaration, you are changing the semantics of how the functions are to be called. That affects any code that calls the functions, not just in Indy itself, but in 3rd party code, too. And for that reason, I am not inclined to incorporate the change, at least in the way you have described it. If you submit a ticket to Indy’s issue tracker, alternatives may be considered.
  15. Remy Lebeau

    IPropertyStore MultiValue Strings

    PROPVARIANT has similarities to VARIANT, but they are actually separate types, so you should treat them that way. Why are you passing in MetaDataTagType as an input parameter? You should be looking at the vt member of the PROPVARIANT instead, which tells you the actual data type of the variant data, eg: procedure ExtractMediaTags(const FileName : String); var Store : IPropertyStore; function GetMetaDataValueAsString(const MetaDataTag : TPropertyKey): String; const VT_LPWSTR_VECTOR = VT_LPWSTR or VT_VECTOR; var v : PropVariant; i: UInt32; begin Result := ''; try OleCheck(store.GetValue(MetaDataTag, v)); try case v.vt of VT_BSTR: Result := v.bstrVal; VT_I2: Result := v.iVal.ToString; VT_I4: Result := v.lVal.ToString; VT_I8: Result := v.hVal.QuadPart.ToString; VT_FILETIME: Result := FileTimeToDateTimeStr(v.filetime); VT_LPWSTR: Result := v.pwszVal; // etc... VT_LPWSTR_VECTOR: begin if v.calpwstr.cElems > 0 then begin Result := v.calpwstr.pElems[0]; for i := 1 to v.calpwstr.cElems-1 do begin Result := ', ' + string(v.calpwstr.pElems[i]); end; end; end; // etc... end; finally PropVariantClear(v); end; except end; end; begin if SHGetPropertyStoreFromParsingName(PChar(FileName), nil, GPS_READWRITE, IPropertyStore, store) <> S_OK then Exit; AddMetaData(pd.DocProps, '70', GetMetaDataValueAsString(PKEY_Music_Artist)); AddMetaData(pd.DocProps, '74', GetMetaDataValueAsString(PKEY_Music_AlbumArtist)); end; Since you want to extract the PROPVARIANT data as a String, consider using functions like PropVariantToString() or PropVariantGetStringElem() instead, which handle these kind of details for you. See PROPVARIANT and VARIANT Functions for a more complete list of functions available. PKEY_MUSIC_ALBUMARTIST is the single primary artist. PKEY_MUSIC_ARTIST is a list of all of the artists. What is the actual numeric value of the PROPVARIANT.vt member? I'm guessing it is $101F (4127), which is an array of VT_LPWSTR strings. TVarType is meant for VARIANT, not for PROPVARIANT. Although they share many common types, PROPVARIANT has types that VARIANT does not, like VT_VECTOR (VARIANT uses VT_ARRAY instead).
  16. Remy Lebeau

    Office Assistant component..

    Simple - I never had a need for it in my production software. Oh sure, the technology was fun to work with, and all. I used it on my company's website for awhile to help new users navigate around the site, and in demo softwares to guide new users around screens and features, and in slideshows to explain to viewers what was being shown. But, in the end, it did not serve much practical use otherwise that couldn't be done in other simpler/more efficient ways. No. Microsoft itself used it in some of their released software. Look at the (negative) feedback they got from that. Not many people liked it. Of course, that was not the fault of the technology itself, but in the annoying ways in which Microsoft decided to use it.
  17. Remy Lebeau

    IDGlobalProtocols GmtOffsetStrToDateTime

    Yes. It strips off the UTC offset portion, and converts the remaining string as-is to TDateTime form. Yes. It is intended to convert UTC offset strings into TDateTime form, which are then added to/subtracted from TDateTime values returned by Raw/StrInternetToDateTime(). You can thank popular Internet protocols for that, with their long history of using non-standardized date/time formats. Much of which went away with standardized ISO 8601 formats. In your case, I would probably suggest simply parsing the date/time string backwards, token by token. If a token is in "(<timezone>)" format, you would have to manually convert it to the corresponding UTC offset (which sadly changes frequently in many timezones). Indy has a TimeZoneToGmtOffsetStr() function that does this, but it is private to the IdGlobalProtocols unit, it is used internally by GmtOffsetStrToDateTime(). If a token is in "±HHMM" format, then it is trivial to convert it as-is to a UTC offset. Sounds like it may be useful to add a new function to Indy, which takes in a date/time string as input and just splits it up into its various components as output. Maybe as a helper for RawStrInternetToDateTime() to call internally. Indy has TimeZoneBias() and OffsetFromUTC() functions, which return the current UTC offset in TDateTime form. Indy also has functions it is not a bug. As it should be.. Operating systems are not very good about keeping accurate history of past time zones. And in any case, date/time strings in this format as supposed to be self-contained, not relying on PC clock data at all. A string like "Sun, 8 Jul 2020 06:55:38 -0800 (PST)" literally claims to represent July 8 2020 at 6:55:38 AM in a timezone that is -8 hours from UTC, Period. Regardless of the fact that on July 8 2020 the Pacific time zone was actually operating in PDT and not in PST. So any competent software producing this date/time string at that time would have produced "Sun, 8 Jul 2020 06:55:38 -0700 (PDT)" instead, which is the correct string for that date/time. By lying to the parser, you are not going to get the result you want. And it is not fair to ask Indy to go digging through the OS or the Internet trying to verify if the date/time string is accurate or not. The string is taken at face value. Right, because your PC would be operating in the PDT time zone needed for July 8 2020, not in the PST time zone needed for Nov 8 2020. You would have needed to adjust the timezone info in the date/time string accordingly, not just the date. Yes, RawStrInternetToDateTime() converts and strips off the date/time portion of the string, modifying the string to leave the UTC offset portion, which can then be passed to GmtOffsetStrToDateTime(). You would have to parse the date/time string manually, none of Indy's existing public functions are designed for the specific task you are trying to accomplish. The private functions that would accomplish it are, well, private. And for one simple reason - because nobody ever asked for them to be made public before.
  18. Remy Lebeau

    Last ways to contact Embarcadero

    You can contact various higher-up individuals directly, like Marco Cantu, David Millington, Jim McKeeth, etc. They are generally good about helping users.
  19. Remy Lebeau

    Office Assistant component..

    Same here. Even though I was a Microsoft MVP for the MSAgent technology, I never actually used it in any of my production applications, only in things like guided tutorials and trade show presentations.
  20. Remy Lebeau

    Office Assistant component..

    Office Assistant was the predecessor to Microsoft Agent. Assistant started life in Microsoft Office 97, where 'Clippy' was just one of several animated characters you could choose from. The technology evolved into a standalone API that any application could utilize. Eventually the old Assistant tech was replaced with the newer MSAgent tech in Microsoft Office 2000. Though some features of Assistant didn't make it into MSAgent and remained specific to Office, and Office didn't utilize everything that MSAgent offered. Microsoft completely removed MSAgent from Windows in Win7. There is a separate install pack for MSAgent that you can download from Microsoft just for Win7, But from Win8 onwards, MSAgent is dead tech, you can't install it anymore, so if you want to use MSAgent in Win8 onwards then you have to use Double Agent instead. You mean, other than it relying on outdated technology? Or that creating custom characters for it is a PITA? Although, at its peak popularity, there were a lot of 3rd party characters you could download for MSAgent. I'm sure many of those downloads have dried up over the years, but there are quite a few still floating around. Back in the day, one of the main competitors to MSAgent was Living Actor. It had a similar concept as MSAgent, but with better graphics (ie, 3D vectored models instead of 2D bitmaps). It has continued to evolve over the years into something that is completely different than what it started out as. I'm sure there are plenty of other assistent-like alternatives nowadays, if you search around.
  21. Remy Lebeau

    Office Assistant component..

    LMAO 🤣 Never thought I would ever see the topic of MSAgent come up again. It has been so long since Microsoft killed it off (a decade!). And my earlier efforts to port MSAgent to other platforms was put on hold years ago (I still want to see Merlin flying around on my Android phone and iPad tablet ) Well, you don't NEED a component, but it can certain make things a little easier to work with. I wrote a full VCL wrapper for MSAgent: http://msagent.lebeausoftware.org, though it was written for C++Builder only at the time, I never got around to porting it to Delphi (I think I started that a long time ago, but I never finished it). Documentation for the MSAgent interfaces is on MSDN: https://docs.microsoft.com/en-us/windows/win32/lwef/microsoft-agent Microsoft Agent is actually broken up into two APIs - the MSAgent ActiveX Control, and the MSAgent Server Interface. The Control is primarily meant for scripting environments, whereas the Server Interface is meant for applications. So make sure you use the Server Interface for a better experience in Delphi.
  22. Note that this approach will only work if your app is compiled with the same compiler and RTL/VCL version as the target app, since you are reading the RTTI of your app, not the RTTI of the target app.
  23. Remy Lebeau

    Listener for TIdTcpClient

    Setting AByteCount=-1 will read however many bytes are currently available on the connection at that moment, waiting up to the ReadTimeout if the InputBuffer is empty. Setting AAppend=False will fill the TIdBytes with the requested number of bytes (for AByteCount=-1, that is the InputBuffer.Size), expanding the TIdBytes only if its length is less than the requested byte count. So, it makes sense that the length of the TIdBytes would not change if its current length (1+) is >= the requested byte count (0) so memory doesn't need to be reallocated. When using AAppend=False, you should either: pre-size the TIdBytes and then request a specific number of bytes (AByteCount > 0) set the TIdBytes to nil and let the read size it for you (AByteCount = -1) In your situation, you are mixing both together. To remedy that, just reset the TIdBytes to nil when you are done using it, before the next read. However, that being said, reading an arbitrary number of bytes will not work well with UTF-8 if there are non-ASCII characters present in the data, since the resulting bytes could straddle the middle of a multi-byte character, causing decoding to throw an error or corrupt the text. Is there a reason why you are using AByteCount=-1 in this manner? Do you not know the actual length of the UTF-8 text ahead of reading it? Why not? What protocol are you implementing that doesn't let you discover that length before reading+decoding the bytes? If the text is variable-length, the protocol needs to either specify the text length before the text bytes, or else terminate the text with a unique delimiter. Either way, you probably shouldn't be using ReadBytes() in this situation to begin with, there are other ways to handle these conditions, depending on the design of the protocol. Can you provide more information about the layout of the messages you are trying to read?
  24. That has nothing to do with the framework being used by the UI control. And certainly nothing to do with accessing offsets within that framework, unless you are trying to access the UI control's internal data members over the process boundary, which you should not be doing, especially just for using WM_GETTEXT. There are other, safer, ways to obtain a UI control's HWND from within another process, such as via UI Automation APIs. And once you do have a viable HWND, the only way to get an AV from using WM_GETTEXT is if you are passing in bad parameter values - either a bad buffer pointer, or an incorrect buffer length that allows a buffer overflow to happen. You don't need to worry about that just to fix an AV in your own code's use of WM_GETTEXT. Something else is going on. But that is what you have to resort to, if you are trying to access some other process's UI control internals. You can't access VCL objects across process boundaries.
  25. Thanks, I missed that part. In which case, this issue just got a whole lot more dangerous. Manipulating the RTL/VCL's data members directly, behind the RTL/VCL's back, is a HUGE risk. Without intimate and explicit knowledge of the exact version of Delphi the other process is using, you can't hope to access its private data SAFELY, for the very reason I stated earlier - data members can and do change between versions.
×