Jump to content

Remy Lebeau

Members
  • Content Count

    2347
  • Joined

  • Last visited

  • Days Won

    95

Everything posted by Remy Lebeau

  1. Remy Lebeau

    Warning on depreciated symbol, Delphi 11

    Actually, several new ComponentPlatform enum values were introduced and old values were deprecated:
  2. Remy Lebeau

    update indy to use tls 1.2 in c++builder 6?

    That means the DLL itself failed to load into memory, before Indy could even try to access any of its functions. Such a failure is most commonly because the DLL itself, or one of its dependent DLLs or imports, can't be found by the OS. OpenSSL build numbers are represented as letters in the English alphabet. So, 1.0.2q is build 1.0.2.17, 1.0.2u is build 1.0.2.21, etc.
  3. Remy Lebeau

    Cyrillic characters in URL

    Yes. Delphi 11 shipped with the latest Indy that was available 3 months ago.
  4. Remy Lebeau

    Cyrillic characters in URL

    Actually, about 8 months ago, TIdHTTPServer was updated to now default to parsing input parameters using UTF-8 if no charset is specified in the Content-Type header. I have added that note to the StackOverflow post you linked to.
  5. I have no idea, I don't use CrossVcl myself. I'm just going off of what the website say:
  6. Sure, by basically providing a compatibility layer that simulates the Win32 API on OSX/Linux.
  7. Remy Lebeau

    Best way to replace D11 distributed Indy with latest Git Indy?

    Not yet, because I don't have D11 installed to generate them. But anyone is more than welcome to submit a Pull Request to contribute them. Agreed (or at least rename the folder, in case you need to recover it later). That is usually the first thing I do when I install a new IDE version, and then have my projects point to the latest Indy repo source.
  8. Borland tried that once, with Kylix in Delphi 6. It was basically VCL for Linux, and it was a big failure, so it got dropped. VCL is just too dependent on Windows to go cross-platform. Hence why we have FireMonkey now for that task, which has no real relation to VCL, other than a few shared class names and public interfaces, but ultimately based on different architectures.
  9. Remy Lebeau

    update indy to use tls 1.2 in c++builder 6?

    The latest version of Indy 10 (https://github.com/IndySockets/Indy/) supports back to C++Builder 5, and can officially use OpenSSL DLLs up to 1.0.2u (for OpenSSL 1.1.x+, use this WIP code). TLS 1.2 has been available in OpenSSL since 1.0.1, and Indy 10 has supported TLS 1.2 for a long time. OpenSSL DLLs are available at https://github.com/IndySockets/OpenSSL-Binaries (https://indy.fulgan.com/SSL/ is retired). If you are getting errors from Indy's standard TIdSSLIOHandlerSocketOpenSSL component when it tries to load the DLLs, then you are likely using DLLs that are not compatible with your version of Indy. You can call Indy's WhichFailedToLoad() function in the IdSSLOpenSSLHeaders unit to find out why the DLLs are failing to load.
  10. Remy Lebeau

    ExtractHeaderFields with special characters

    Which version of Delphi is that other app written in, and what version of Indy is it using? TIdMultipartFormDataStream encodes non-ASCII characters in all field names and filenames according to RFC 2047, which your earlier example is NOT encoded as, so I doubt the example is coming from Indy, unless maybe it is a really old version. On Windows, depending on what the OS system language is set to, TIdMultipartFormDataStream uses either UTF-8 or the OS language as the charset to encode characters to bytes. And then depending on the charset used, it uses either Quoted-Printable or Base64 to encode those bytes in the Content-Disposition header. These values are reflected in the HeaderCharSet and HeaderEncoding properties of each TIdFormDataField object that the TIdMultipartFormDataStream.Add(...) methods create. Double-check what these values are actually being set to on your system, but you can also set them yourself as needed. I would suggest using HeaderCharSet='utf-8' and HeaderEncoding='B', eg: var mPartStream := TIdMultiPartFormDataStream; field: TIdFormDataField; ... mPartStream := TIdMultiPartFormDataStream.Create; FHttp.Request.ContentType := mPartStream.RequestContentType; for ix := 0 to FPostNames.Count -1 do begin if FPostFiles[ix].IsNull then begin field := mPartStream.AddFormField(FPostNames[ix], FPostValues[ix], 'UTF-8'); field.ContentTransfer := '8bit'; end else begin field := mPartStream.AddFile(FPostNames[ix], FPostFiles[ix].PathName, FPostContentTypes[ix]); end; field.HeaderCharSet := 'UTF-8'; field.HeaderEncoding := 'B'; end; Though, I suspect even this will not give you the end result you are looking for with ExtractHeaderFields(), if it is really trying to url-decode fields that are not url-encoded to begin with. HTTP does not use url-encoding in header content, so what you are experiencing really sounds like a logic bug in the HttpApp framework. But at least this should give your code access to the stream's encoded Base64 data, which you can then decode manually to a Unicode string, such as with Indy's DecodeHeader() function in the IdCoderHeader unit.
  11. Remy Lebeau

    Interfaces defined in base classes

    No, it is not a valid cast, in this case. Obj is declared as IInterface, so it is pointing at the IInterface portion of the TMyClass object. But the object also has other portions in it, for TMyBaseClass, TInterfacedObject, IMyInterface, etc (not drawn exactly as the compiler lays it out, but you should get the idea): ------------------- | TMyClass | | ---------------- | <- Obj points here | | IInterface | | | ---------------- | | ---------------- | | | IMyInterface | | | ---------------- | | ... | ------------------- You are type-casting Obj AS-IS from IInterface to IMyInterface, which tells the compiler to MIS-interpret Obj as pointing to the IMyInterface portion of the object EVEN-THOUGH it is actually pointing at the IInterface portion of the object. Whereas the 'as' operator and Support() function, which use QueryInterface() internally, will return a pointer that properly points to the IMyInterface portion of the object, eg: ------------------- | TMyClass | | ---------------- | <- IMyInterface(Obj) points here | | IInterface | | | ---------------- | | ---------------- | <- (Obj as IMyInterface) points here! | | IMyInterface | | | ---------------- | | ... | ------------------- So, when you call IMyInterface(Obj).DoesNothing(), you are calling DoesNothing() on an invalid IMyInterface, so it does not access the correct area of the TMyClass object. In order for the compiler to access the members of a TMyClass object through an IInterface pointer, an IMyInterface pointer, a TMyBaseClass pointer, etc, the pointer has to be ADJUSTED according to the offset of the pointer's dereferenced type in relation to the implementation class. The compiler knows the offset of the IInterface portion of TMyClass, so given an IInterface pointer it knows how to adjust that pointer to reach TMyClass. Same with IMyInterface, etc. Thus, it adjusts a pointer according to the pointer's DECLARED type. So, if you start out with an invalid pointer to begin with, those adjustments are not performed correctly, and you end up with bad behaviors, such as crashes, corrupted data, etc. That works only if SomeVariable is pointing at the memory address where a valid IWhatever exists. Because you altered the layout of the object in memory, but didn't update your pointer usage accordingly.
  12. Remy Lebeau

    EIdConnClosedGracefully error..

    The only way that can happen is if the HTTP server is closing its end of the TCP connection prematurely before the end of the response has been sent. If the server wants to use a disconnect to signal end-of-response (which is a valid use-case), it has to indicate that up-front in the HTTP response headers, in which case TIdHTTP would simply handle the disconnect internally and your code would not see this error. So, the only way this error can reach your code is if the disconnect is unexpected. No, you don't need to do that in this case, since you are destroying the TIdHTTP object after sending a single HTTP request. That earlier advice only applies if you were reusing the TIdHTTP object for sending multiple HTTP requests. And even then, under ideal conditions, you still should not need to manually disconnect and clear the buffer, TIdHTTP should be handling that internally for you. Also, your CheckUrl() appears to be unnecessary. Just request the URL unconditionally, and handle any errors it may raise.
  13. Remy Lebeau

    ExtractHeaderFields with special characters

    That header is malformed. HTTP headers simply can't have un-encoded non-ASCII characters like that. There are competing standards for how they need to be encoded, though. There is RFC 2183, RFC 2047, RFC 7578, RFC 8187, HTML5, etc. TURLEncoding decodes %HH sequences into bytes, and then charset-decodes those bytes into Unicode. IIRC, it expects the bytes to be UTF-8 encoded by default.
  14. Remy Lebeau

    FMX in VCL app - working natively ?

    Mixing of VCL and FMX together in the same project is NOT officially supported. There are 3rd party solutions to make it work, but out of the box this is a fluke if it actually works.
  15. Remy Lebeau

    Form Creation difference??

    Calling a Form's constructor directly will just create the object immediately, and lets you specify the desired Owner. That is al it does. In VCL, there is not much difference to that. Calling TApplication.CreateForm() merely creates the specified class type, hard-coding the TApplication object as its Owner. But it also sets the TApplication.MainForm if it is not already assigned and a TForm is being created. Calling Create() directly does not do that. In FMX, there is little bit more of a difference. It also creates requested objects with TApplication as the Owner, but it also caches those requests until TApplication.CreateRealForms() is called, at which time all requested (and subsequent) objects are then physically created. It also does not set the TApplication.MainForm at all, there is a separate TApplication.CreateMainForm() call for that.
  16. Self.Name will never work in this situation, since it has not been assigned a value yet while the constructor is still running. The Name property is assigned a value after the constructor exits, whether that be at design-time or run-time. The only way around that is to pass in the desired value as a parameter to the constructor (but that will obviously not work for objects created at desing-time), eg: constructor TConcrete.New(aValue: string; aName: string; aOwner: TComponent); begin inherited Create(aOwner); Self.Name := aName; // <-- fReadOnlyProperty := aValue + Self.ClassName +' ] '+ sLineBreak + 'Object Instance Name is: [' + aName +' ]'; end;
  17. Remy Lebeau

    FYI: D11 SMTP IdSSLIOHandlerSocketOpenSSL win32

    There are no "Indy DLLs". If you mean the "OpenSSL DLLs", I wouldn't expect Embarcadero to distribute them, you have to download them yourself from online. Indy has a GitHub repo for that purpose: https://github.com/IndySockets/OpenSSL-Binaries
  18. Remy Lebeau

    Missing The Old Forums

    ♫ Into the Unknooo-ooo-ooo-own... ♫ (sorry, couldn't help myself )
  19. That notice has been in the documentation since XE4. All ANSI types (P/AnsiChar, AnsiString/(N), ShortString) were disabled in the NEXTGEN mobile compilers in XE3. Under NEXTGEN, UTF8String and RawByteString were re-enabled in 10.1 Berlin, and then the rest of the ANSI types were re-enabled in 10.4 Sydney when NEXTGEN was dropped completely so mobile platforms now match desktop platforms in terms of language features. Looks like the ShortString documentation has not been updated yet to reflect that. Yes. Only in XE3 through 10.3. In 10.4 onward, ShortString can be used on mobile. No. Because ALL ANSI types were initially eliminated, as mobile platforms are Unicode-based. Then the types slowly started being re-introduced as needs arose, until eventually Embarcadero decided that having separate compiler architectures just wasn't working out. Hardly.
  20. Remy Lebeau

    How to connect to office 365 using proxy server

    <ARG!> I just now noticed that you are connecting to Office 365 on port 993. That is an IMPLICIT TLS port. But, you are not using any TLS settings on your TIdIMAP4 at all! Rather than assigning a TIdIOHandlerStack component to the TIdIMAP4.IOHandler property, you need to assign a TIdSSLIOHandlerSocketBase-derived component instead, like TIdSSLIOHandlerSocketOpenSSL (TIdSSLIOHandlerSocketBase derives from TIdIOHandlerStack and thus also has the TransparentProxy property). And then set the TIdIMAP4.UseTLS property to utUseImplicitTLS.
  21. As you can see in the source code I linked to earlier, that simply calls this: return OpenExisting(mapName, MemoryMappedFileRights.ReadWrite, HandleInheritability.None); That simply calls this: return OpenExisting(mapName, desiredAccessRights, HandleInheritability.None); Which ultimately just calls OpenFileMapping() with the specified name, access/inheritance rights as-is, and then wraps the HANDLE in a MemoryMappedFile object.
  22. The problem with using QueryPerformanceCounter()/QueryPerformanceFrequency() is that it is not consistent on all systems, especially on multi-core systems, or systems without a stable TSC (Mozilla had to write code to work around that for https://bugzilla.mozilla.org/show_bug.cgi?id=784859). That is the main reason Indy stopped using QPC/QPF over a decade ago for the implementation of its Ticks/64() functions, now favoring GetTickCount64() instead (use of QPC/QPF can be re-enabed with a compiler define).
  23. I'm not sure this can be solved truly lock-free. Even if you make the low-part of the counter thread-local to avoid a lock, you still have the high-part of the counter to deal with to track rollovers, and that will have to be protected from concurrent access, either with a lock, or atomic access, etc. I really don't know if that will work or not. I think the entire counter needs to be global, so that new threads will start with the latest accumulated value properly. I'm thinking something like the following, based on ideas I've seen in other implementations: var TickCount64: UInt64 = 0; function GetTickCount64Emu: UInt64; var OrigValue, NewValue, TmpValue: UInt64; CurrTicks: UInt32; begin OrigValue := TInterlocked.Read(TickCount64); repeat CurrTicks := Windows.GetTickCount; NewValue := (OldValue and $FFFFFFFF00000000) + CurrTicks; if CurrTicks < UInt32(OrigValue and $FFFFFFFF) then Inc(NewValue, $100000000); TmpValue := TInterlocked.CompareExchange(TickCount64, NewValue, OrigValue); if OrigValue = TmpValue then Break; if TmpValue > NewValue then Exit(TmpValue); OrigValue := TmpValue; until False; Result := NewValue; end; Yes, that would be required no matter what. Oh yeah, I forgot about that. Well, then just call GetProcAddress() manually at startup (or first call) instead of using 'delayed'. This is what Indy does.
×