-
Content Count
2684 -
Joined
-
Last visited
-
Days Won
113
Everything posted by Remy Lebeau
-
The Installer Detector looks at a lot of different things, not just the filename: https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-vista/cc709628(v=ws.10) Hmm... Right, because the Elevation error occurs while the process is being created, before it starts executing.
-
In what way? Did you verify that ALL of the server events stopped (OnConnect, OnHeadersAvailable, etc)? Or is it just the OnCommandGet event? Do you have a capture of the requests that don't respond? Then it can't be a deadlock issue, since the server is still responsive to shutdown and restart, and thus the socket threads are not blocking. So there has to be an issue in the request handling. But there is WAY too much code provided with no explanation or context, so it is very difficult to diagnose your issue. Your OnCommandGet handler is pretty massive (also, there are a lot of places where Exit statements are missing that would avoid unnecessary processing). Have you considered breaking up the code and then unit-testing the pieces individually? That MIGHT be part of the problem. You really should not be catching unhandled exceptions, but if you do, make sure to RE-RAISE any Indy exceptions you happen to catch (they all derive from EIdException). The server needs to handle those internally in order to close the socket and stop its owning thread (unless you close the socket manually in your except block). Why are you doing that? The Params have already been decoded before OnCommandGet is called (assuming TIdHTTPServer.ParseParams is true, which it is by default), and UTF-8 is the default charset used for that decode (unless the request specifies a charset in its Content-Type header). Why can't you use the Body text as-is? Text := aRequestInfo.Params.Values['Body']; Since the text was already pre-decoded, re-encoding it and decoding it as a potentially different charset is just asking for trouble. This is a good way to corrupt the text. If you absolutely need custom decoding, then you should instead parse the ARequestInfo.UnparsedParams, ARequestInfo.QueryParams, and/or ARequestInfo.FormParams properties as needed. That is the raw data where TIdHTTPServer decodes the ARequestInfo.Params data from. Are you sure all of your Engine code is thread-safe and non-blocking? What is that supposed to mean? You can absolutely have a space after the ';' character, that will work just fine: AResponseInfo.ContentType := 'text/html; charset="UTF-8"'; Alternatively, simply use the separate AResponseInfo.CharSet property instead: AResponseInfo.ContentType := 'text/html'; AResponseInfo.CharSet := 'UTF-8'; This is wrong. One, because the LoadFromFile() is a potential exception waiting to happen, since you appear to be loading files using relative paths. ALWAYS use absolute paths instead! But more importantly, you are freeing the TMemoryStream that is assigned to the AResponseInfo.ContentStream property. Indy DOES NOT make a copy of that stream, so you are leaving behind a dangling pointer that will crash when the server tries to write the stream data to the client after the OnCommandGet handler exits. The AResponseInfo object will free the ContentStream for you when it is no longer needed, so DO NOT free it manually. Unless you really need to free the stream manually (which you don't in this cae), in which case you would have to call AResponseInfo.WriteHeader() and AResponseInfo.WriteContent() manually before freeing the stream. You should consider using Indy's TextIsSame() function for case-insensitive string comparisons. Same here. Also, is the SMS and Twilio code thread-safe and non-blocking? This is NOT thread-safe! You CANNOT access UI controls from outside of the context of the main UI thread. The OnCommandGet event is fired in the context of a worker thread, so you MUST synchronize with the main UI thread here. Otherwise, I would suggest storing the CheckBox value in a global Boolean variable at server startup, and then you can read that variable without synchronizing it (as long as you don't alter the vaiable's value while the server is running, otherwise you do need to synchronize it). If your OnCommandGet code encounters an unhandled exception, you are catching it to send a response to the client, but you are not setting an appropriate ResponseCode, like 500. So the default 200 will likely be sent instead. Is that what you really want? By default, TIdHTTPServer already sends a 500 response to the client for unhandled exceptions, so this code is largely unnecessary. But since you are customizing the ContextText, then at the very least I would suggest getting rid of the outer try/except altogether and move this code into the OnCommandError event instead.
-
What is the actual project name? Sounds like UAC's "Installer Detection" feature kicking in. You absolutely should have a UAC manifest in the project to avoid that, not relying on the persistence of the "Run as Administrator" option on the EXE properties.
-
Why compiler allows this difference in declaration?
Remy Lebeau replied to Mike Torrettinni's topic in RTL and Delphi Object Pascal
No, it is not a flaw. This is how Delphi (probably even Pascal in general) has always worked. A parameter's default value is required only in the function's declaration. At any site where the function is called, the compiler needs to know what the default value is, if the calling code decides to omit the parameter. Duplicating the default value in the function's implementation is optional. The implementation doesn't care whether the caller omitted parameters or not, because the compiler will have filled in any missing values on the call stack before the implementation is entered. -
TCustomInifile.ReadSubSections in older Delphi versions
Remy Lebeau replied to dummzeuch's topic in RTL and Delphi Object Pascal
Actually, maybe you could try something like this: type ICanReadSubSections = interface ['{...}'] procedure ReadSubSections(const Section: string; Strings: TStrings; Recurse: Boolean = False); end; TdzMemIniFile = class(TMemIniFile, ICanReadSubSections) public {$IF CompilerVersion < 14} procedure ReadSubSections(const Section: string; Strings: TStrings; Recurse: Boolean = False); {$IFEND} end; TdzRegistryIniFile = class(TRegistryIniFile, ICanReadSubSections) public {$IF CompilerVersion < 14} procedure ReadSubSections(const Section: string; Strings: TStrings; Recurse: Boolean = False); {$IFEND} end; {$IF CompilerVersion < 14} procedure TdzMemIniFile.ReadSubSections(const Section: string; Strings: TStrings; Recurse: Boolean = False); begin // add to Strings as needed... end; procedure TdzRegistryIniFile.ReadSubSections(const Section: string; Strings: TStrings; Recurse: Boolean = False); begin // add to Strings as needed... end; {$IFEND} And then you can do this: procedure doSomething(_Ini: TCustomIniFile); var Intf: ICanReadSubSections; sl: TStringList; begin if not Supports(_Ini, ICanReadSubSections, Intf) then raise Exception.Create('ICanReadSubSections not implemented'); sl := TStringList.Create; try Intf.ReadSubSections('Section', sl); for i := 0 to sl.Count - 1 do begin doSomethingWith(sl[i]); end; finally sl.Free; end; end; -
TCustomInifile.ReadSubSections in older Delphi versions
Remy Lebeau replied to dummzeuch's topic in RTL and Delphi Object Pascal
I really don't think you are going to be able to avoid that if you want to support different versions with varying implementations, eg: procedure doSomething(_Ini: TCustomIniFile); var sl: TStringList; {$IF CompilerVersion >= 14} procedure ReadSubSections(const Section: string; Strings: TStrings; Recurse: Boolean = False); begin _Ini.ReadSubSections(Section, Strings, Recurse); end; {$ELSE} procedure ReadMemSubSections(_MIni: TMemIniFile; const Section: string; Strings: TStrings; Recurse: Boolean = False); begin // add to Strings as needed... end; procedure ReadRegistrySubSections(_RIni: TRegistryIniFile; const Section: string; Strings: TStrings; Recurse: Boolean = False); begin // add to Strings as needed... end; procedure ReadSubSections(const Section: string; Strings: TStrings; Recurse: Boolean = False); begin if (_Ini is TMemIniFile) then ReadMemSubSections(TMemIniFile(_Ini), Section, Strings, Recurse) else if (_Ini is TRegistryIniFile) then ReadRegistrySubSections(TRegistryIniFile(_Ini), Section, Strings, Recurse) else raise Exception.Create('Only TMemIniFile or TRegistryIniFile are supported'); end; {$IFEND} begin sl := TStringList.Create; try ReadSubSections('Section', sl); for i := 0 to sl.Count - 1 do begin doSomethingWith(sl[i]); end; finally sl.Free; end; end; -
No StringHelper for saving to file?
Remy Lebeau replied to PeterPanettone's topic in RTL and Delphi Object Pascal
A "collection of strings" and a single "basic string type" are two completely different concepts. -
No StringHelper for saving to file?
Remy Lebeau replied to PeterPanettone's topic in RTL and Delphi Object Pascal
No, it is a collection of strings. It is not itself a string. Period. A basic string type would be just a sequence of characters, maybe a length, encoding, etc but certainly not more than that. Because it simply doesn't make sense for something like that to exist, since 99% of people won't be using it. It is a waste of coding, when the same task is easily accomplished using other readily-available code. So, I repeat my earlier question again. -
Enums always start at 0 implicitly, unless explicitly stated otherwise. Nothing wrong with using an enum for array indexes, provided the enum elements start at 0 and are sequential, which is the default behavior. type myEnum = (meFirst, meSecond, meThird); myUnitExternalButCompiledArray[meFirst] myUnitExternalButCompiledArray[meSecond] myUnitExternalButCompiledArray[meThird] var e: myEnum; e := ...; myUnitExternalButCompiledArray[Ord(e)]
-
That does not produce the requested effect. That is used for creating multi-column menus, not multi-group menus. This is the correct solution. Menus simply have no concept of groups, so "group headers" is accomplished by custom-drawing those menu items differently.
-
upcoming language enhancements?
Remy Lebeau replied to David Schwartz's topic in RTL and Delphi Object Pascal
Please, please, please, with sugar and cherries on top!! I remember way back in the day when Borland actually did release things "when they are ready". I miss those days. -
No StringHelper for saving to file?
Remy Lebeau replied to PeterPanettone's topic in RTL and Delphi Object Pascal
Why should it? Do you know ANY framework where a basic string type has such a method? -
upcoming language enhancements?
Remy Lebeau replied to David Schwartz's topic in RTL and Delphi Object Pascal
Of course they do. But nothing that can be talked about publicly at this time. -
upcoming language enhancements?
Remy Lebeau replied to David Schwartz's topic in RTL and Delphi Object Pascal
Which enhancements are you referring to exactly? The only new language enhancements added recently were Managed Records in 10.4, and Inline Variables and Type Inference in 10.3. If there are any other new language enhancements pending on the horizon, they are not public knowledge. If you want to know if there is anything new coming up, then you should join the Delphi 11 beta. IIRC, Embarcadero has already gone on record stating Nullable Types are not being added to the language anytime soon. But, they can be implemented manually using managed records now (well, more efficiently then the original approach from years past, anyway). -
OK. Makes sense, if Twilio sends a request to ProjectOne, which sends a request to your server, which fails, then ProjectOne would send an error back to Twilio. Are you sure it is Twilio and not ProjectOne? In any case, a connection reset during a TLS handshake usually means the server did not like something in the client's (Twilio/ProjectOne) handshake data, so it simply chose to abort the connection rather than send a TLS alert back to the client explaining the reason. Hang/deadlock rather than timeout, but yes, if you are not careful with it.
-
Which specific release of 10.6.2 exactly? Are you using a stock version that shipped pre-installed in a specific IDE version? Or have you updated to the latest trunk version from Indy's GitHub repo? Indy's versioning has been broken since Indy switched from SVN to GitHub, so 10.6.2.0 does not accurately reflect the real version. That should be OK. Any specific details about the errors? OK. Any synchronization between threads being done?
-
That has nothing to do with the ports you are using, unless you have a firewall that is blocking them. Which version of Indy and OpenSSL DLLs are you using? Yes. Though, you don't need to set the DefaultPort at all if you are just going to set each Binding.Port explicitly. If you are going to bind to multiple ports, then the DefaultPort should be 0. Just make sure you are handling the OnQuerySSLPort event correctly, especially for non-standard ports, like 8080. Also, make sure you are using an up-to-date version of Indy, since the behavior of default HTTPS handling did change a few years ago. No, that is perfectly fine, even expected and intentionally designed for. You SHOULD be throwing exceptions on unexpected failures. The server will catch and process uncaught exceptions internally. For socket I/O errors, it will close the socket and stop the socket's owning thread, triggering OnDisconnect and OnException events. For most other exceptions, it will instead trigger the OnCommandError event, then send an error response to the client if a response has not already been sent, and then carry on with normal HTTP KeepAlive handling - closing the socket or waiting for the next HTTP request, as needed. If an exception is raised and not caught, the server will catch it, and in most cases will overwrite those values with its own error values. There is no way to answer that with the limited information you have provided. Do you have KeepAlive enabled or disabled on the server? Once the server stops responding, are you getting OnConnect events for new connections, and getting OnHeadersAvailable events for new requests, at least? What do your OnCommand... events actually look like? Have you verified with a packet sniffer like Wireshark that your server machine is still receiving new HTTP requests from the network?
-
Should be easy to replicate that in a custom-drawn TDrawGrid/TStringGrid with its grid lines turned off, and an OnDrawCell event handler to draw the rounded blobs and text inside each cell.
-
There isn't one, at least not natively. You would have to write your own wrappers, either to wrap a myStream inside of an IStream and then call myIStream.CopyTo(), or else wrap myIStream inside of a System.IO.Stream and then call myStream.CopyTo(). A simpler way is to just call myIStream.Read() and myStream.Write() in a loop until there is nothing left to read from myIStream. No wrappers needed, just a local byte[] array.
-
Can I use the TidHTTP component for this?
Remy Lebeau replied to alank2's topic in Network, Cloud and Web
Well.... ultimately, the goal is to actually get Indy out of the IDE installation and into GetIt. It would still be available if you needed it, but wouldn't be forcibly installed and wasting space if you didn't need it. But, that dream is likely not to be realized anytime in the near future... Yes. And it doesn't rely on OpenSSL DLLs to do it, either. It uses OS-native APIs to handle that. -
Can I use the TidHTTP component for this?
Remy Lebeau replied to alank2's topic in Network, Cloud and Web
You could use TIdHTTP, but you would merely be substituting one library dependency for another. Indy is not a "built-in" library, it is a 3rd party library that just happens to be pre-installed in the IDE by default. A true native built-in solution would be to use Embarcadero's own THTTPClient/TNetHTTPClient instead, see Using an HTTP Client and What is the difference between THTTPClient and TNetHTTPClient?. Technically yes, for example: #include <IdAuthenticationNTLM.hpp> ... //set properties IdHTTP->ConnectTimeout = ...; IdHTTP->ReadTimeout = ...; IdHTTP->IOHandler = IdSSLIOHandlerSocketOpenSSL; IdHTTP->Request->ContentType = L"application/json"; IdHTTP->Request->Username = parms->Username; IdHTTP->Request->Password = parms->Password; try { IdHTTP->Post(parms->URL, parms->senddata, parms->recvdata); } catch (const Exception &exception) { ExceptionErrorMessage(const_cast<Exception*>(&exception), NULL, parms->exmsg, 1024); delete IdHTTP; goto fail2; } -
Check port in use exception
Remy Lebeau replied to Hafedh TRIMECHE's topic in Network, Cloud and Web
Under normal conditions, that particular exception class should not be getting raised in this code, as a connect attempt should never report a WSAENOTSOCK error. On the other hand, 200ms is a fairly short timeout, and Indy does use a worker thread internally to implement a timed connect, so it is likely that the timeout is elapsing and closing the socket before the thread even has a chance to attempt to connect. However, in that scenario, the code that is calling TIdTCPClient.Connect() would receive an EIdConnectTimeout exception instead of an EIdNotASocket, The thread would raise EIdNotASocket internally and swallow it, but your JCL debugging does not appear to be taking that into account. -
That is wrong. Don't assign the new TFormatSettings instance to the global FormatSettings variable at all (in fact, pretend that global variable doesn't even exist). Pass the new TFormatSettings instance directly to FormatFloat() instead, eg: fs := TFormatSettings.Create(SysLocale.DefaultLCID); // customize fs as needed... ShowMessage(FormatFloat('###,###.00', 1234.25, fs));
-
Indy's TIdFTP component has a similar option. Except that, rather than attempt the reply IP first then fallback to the connected IP, it has a PassiveUseControlHost property to control whether it should just ignore the reply IP altogether and use the connected IP only. Not quite the same thing. I'm thinking now that I should add FileZilla's behavior to TIdFTP if PassiveUseControlHost is false.
-
Will getit work for C++ Builder
Remy Lebeau replied to alank2's topic in ICS - Internet Component Suite
Has CodeGuard EVER worked? I stopped using it many years ago, and I've seen plenty of users reporting in the various forums over the years about problems with it.