-
Content Count
2684 -
Joined
-
Last visited
-
Days Won
113
Everything posted by Remy Lebeau
-
why shortstring in Delphi cannot used in our Programs using New IDE?
Remy Lebeau replied to bravesofts's topic in Algorithms, Data Structures and Class Design
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. -
<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.
-
Using a memory-mapped file of a Delphi app in C#
Remy Lebeau replied to jaenicke's topic in Delphi IDE and APIs
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. -
Delphi 11 Windows XP compatibility tweak
Remy Lebeau replied to mitzi's topic in RTL and Delphi Object Pascal
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). -
Delphi 11 Windows XP compatibility tweak
Remy Lebeau replied to mitzi's topic in RTL and Delphi Object Pascal
From RSP-35459: -
Delphi 11 Windows XP compatibility tweak
Remy Lebeau replied to mitzi's topic in RTL and Delphi Object Pascal
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. -
Will getit work for C++ Builder
Remy Lebeau replied to alank2's topic in ICS - Internet Component Suite
Most likely, either Int8 or CSIDL_DESKTOP has already been #define'd to a value earlier, and that define is then interfering with these declarations. -
Delphi 11 Windows XP compatibility tweak
Remy Lebeau replied to mitzi's topic in RTL and Delphi Object Pascal
What about (in a loop) using TInterlocked to Read() the counter into a local variable, update the two halves of that variable as needed, and then CompareExchange() the result back into the counter until it takes effect for multi-threaded access? Looking at some other apps (Mozilla, etc), that is how they solved this problem years ago. How? Without using thread-local variables? Would still need a locking mechanism to avoid races across threads. Why? -
Delphi 11 Windows XP compatibility tweak
Remy Lebeau replied to mitzi's topic in RTL and Delphi Object Pascal
Here is an implementation of GetTickCount64() for Win2K and XP, it would be trivial to use the native GetTickCount64() on Vista+ and fallback to this version on pre-Vista systems: https://titanwolf.org/Network/Articles/Article?AID=7398e4d3-ddc2-42b0-ae21-d52654fe9287#gsc.tab=0 -
Look at the actual declaration more carefully: class procedure MessageDialog( const AMessage: string; const ADialogType: TMsgDlgType; const AButtons: TMsgDlgButtons; const ADefaultButton: TMsgDlgBtn; const AHelpCtx: THelpContext; const ACloseDialogProc: TInputCloseDialogProc); The 3rd parameter is a TMsgDlgButtons, which is a Set of TMsgDlgBtn. But you were originally trying to pass a single TMsgDlgBtn. Also, the 5th parameter is a THelpContext, which is an integer, not a pointer. So, you can't pass nil to it. Try this: TDialogService.MessageDialog( 'You want to ........ ', TMsgDlgType.mtConfirmation, mbYesNo, // or [TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo] TMsgDlgBtn.mbNo, 0, procedure(const aResult: TModalResult) begin ... end );
-
WinInet API 4095 How can I remove this limit?
Remy Lebeau replied to Turan Can's topic in Windows API
I can't answer that. I see nothing in your code that would limit the size of the download. But, I can address other problems I see with your code. For one thing, you are only downloading 11 bytes at a time, why so small a buffer? That is pretty inefficient for a network transfer. Also, when you are trying to decode the buffer, you are converting from AnsiChar[] to String, and then copying BufferLen characters. The conversion to String is wrong, as you don't take the BufferLen into account during that conversion. And there is no guarantee that the number of bytes in the buffer is the same as the number of characters in the String. You shouldn't even be using Copy() in this manner at all - use TEncoding.UTF.GetString() instead, which lets you pass in a byte array, starting index, and byte count. But most importantly, you simply can't UTF8-decode arbitrary byte buffers while you are downloading them. You should download all of the bytes first, then decode them as a whole. Otherwise, if you really want to decode on the fly, you must take codepoint boundaries into account properly, decoding only complete byte sequences, and saving incomplete sequences for future iterations to complete and decode. Otherwise you risk corrupting the decoded data. And all of this assumes the data is even encoded in UTF-8 to begin with, which your code is not checking for by looking at the HTTP Content-Type response header or the body content (in case of a <meta> charset tag in HTML, etc). -
Without seeing a trace log of what's going on over the wire, I honestly could not tell you what is going on. Can you get a Wireshark capture of the connect attempt?
-
Using a memory-mapped file of a Delphi app in C#
Remy Lebeau replied to jaenicke's topic in Delphi IDE and APIs
What is the actual value of MMFName on both sides? What error does OpenExisting() report when it fails? Is that call actually succeeding or failing? Also, why are you hard-coding $FFFFFFFF instead of using the INVALID_HANDLE_VALUE constant, like the documentation says to use? Are you compiling for 32bit or 64bit? For 64bit, $FFFFFFFF extended to $00000000FFFFFFFF would be the wrong value to use, it would need to be $FFFFFFFFFFFFFFFF instead. I don't think that is going to make a difference, since MemoryMappedFile.OpenExisting() just calls the Win32 OpenFileMapping() API (you can see the source code for yourself at https://referencesource.microsoft.com/#system.core/System/IO/MemoryMappedFiles/MemoryMappedFile.cs) Not enough information to diagnose that.. -
No, it was introduced in XE2.
-
I can't answer that. There simply has not been enough information provided yet to diagnose the root cause. You are just going to have to continue debugging deeper.
-
Did you do what Twilio said to do? Did you verify the TLS version and ciphers being used by your server during a failed connection? Have you tried sniffing the TLS handshake with Wireshark to see what is actually going on inside of it? The only time I have ever seen that happen is when OpenSSL decides to reject a handshake and just closes the TCP connection abruptly without first sending a TLS alert to explain why it is being rejected. That usually implies that something in the handshake is corrupted or incorrect, and OpenSSL is just being cautious about sending anything, but that is not always the case. I doubt it, since this is not really an Indy issue, it is more of an OpenSSL TLS issue, but whether it is on the client side or the server side is still TBD.
-
https://devblogs.microsoft.com/oldnewthing/20091125-00/?p=15923 https://devblogs.microsoft.com/oldnewthing/20090223-00/?p=19063 https://stackoverflow.com/a/14018468/65863
-
Technically, when double-clicking on a file, Explorer will ask the Shell to invoke the file's default action, and the Shell will execute the "open" action if that is the default action. Sure, this may be the case in 99% of the cases, but there is always that 1% that will be different. Double-clicking on a file, and calling ShellExecute/Ex("open") on the file, are NOT the same thing, even if they usually end up performing the same action on most systems, But they are still logically different operations.
-
Technically, the OP asked how to execute a specific command, so shouldn't be using ShellExecute/Ex() at all. Double-clicking a file in Explorer executes the default action. And 'open' is not always the default action. It depends on the file extension's actual registration in the Registry, whether the user or 3rd-party apps have customized it, etc (for instance, on my system, the default action of a PDF file is to pass the file to AVG for scanning before then opening it). Which is incorrect, because that is not what Explorer does. Maybe on YOUR system, perhaps. Not 100% guaranteed on every other system.
-
The correct way to invoke the default action is to set the verb parameter to nil, not 'open'.
-
How know interface GUID from generic anonymous function using RTTI
Remy Lebeau replied to jairgza's topic in Algorithms, Data Structures and Class Design
There is nothing in the RTTI system for that purpose, no. You would have to manually parse the TRttiField.FieldType.QualifiedName of the field in question (in this case, yielding 'TFunc<ITestA>') to extract what is between the brackets ('ITestA'), and then get the TRttiType of that type from TRttiContext and typecast it to TRttiInterfaceType to get its GUID. Except that you can't use Generic types for DFM-streamable classes. The DFM system doesn't handle Generic class types. -
It SHOULD NOT be decoding the unparsed param like that. The encoded hex shown is valid UTF-8, and I can decode it manually into the two Emojis (U+1F605 and U+1F923). But the parsed param you have shown is the result of Indy storing the raw UTF-8 bytes into the String rather than decoding the UTF-8 bytes into Unicode text. Like I said earlier, TIdHTTPServer decodes the params using UTF-8 by default, unless overridden by an explicit charset in the request. Oh, wait... (checks Indy's change history...) that was actually a recent fix made earlier this year. Prior to that fix, Indy would indeed decode the Param data using 8bit instead of UTF-8, unless the request explicitly stated UTF-8. So that would explain the behavior you are seeing, and why the IndyTextEncoding_UTF8.GetString() workaround was needed. You should update to the latest version of Indy. Then the param data should be decoded properly as UTF-8 by default and you won't need the IndyTextEncoding_UTF8.GetString() workaround anymore. No, it is not fine. It is broken, actually. But it was fix several months ago. Yes, but you shouldn't have had to resort to that if Indy were decoding the param data correctly to begin with. Which clearly your version is not.
-
Handlin the message and returning value to the caller
Remy Lebeau replied to Tommi Prami's topic in Windows API
Yes, that will work fine. The VCL's internal WndProc that will first receive the message (StdWndProc() in System.Classes.pas) copies the tagMSG values to a local TMessage, then dispatches that TMessage to handlers, and then returns the TMessage.Result value back to the original sender. -
Can you provide an example? And is the data coming from the URL querystring, or the request body? I assume the latter. It makes a difference to how HTTP behaves. The code you showed using UTF8.GetString() only makes sense if TIdHTTPServer were storing UTF-8 bytes as Chars in a String, which it should not be doing unless the request specifies a charset (in the Content-Type header) which Indy does not recognize/support. Otherwise, it should be using that charset properly, or if there is no charset specified then it uses UTF-8 (assuming you are using an up-to-date version of Indy). So, it is a little hard to imagine that if Twilio is sending UTF-8 data for the 'Body' text that TIdHTTPServer would not be decoding it properly by default. But, that goes back to my earlier comment about needing to see the raw HTTP requests. No. It will happily wait as long as it takes to read in the request data and send out the response data.