-
Content Count
2982 -
Joined
-
Last visited
-
Days Won
134
Everything posted by Remy Lebeau
-
No (plus, that would require changing and recompiling the code, in which case you may as well just take out the offending code to begin with). But, you can accomplish something similar using breakpoints instead. Put a breakpoint at the beginning of the function, go into its properties, and disable the 'Break' option, and enable the 'Ignore subsequent exceptions' option. Then, put another breakpoint at the end of the function, go into its properties, and disable the 'Break' option, and enable the 'Handle subsequent exceptions' option.
-
You have the call to ShowDialogAfterTaskFinishes() in the wrong place. TTask runs asynchronously, but you are calling ShowDialogAfterTaskFinishes() immediately after the TTask object is created (and possibly before the TTask even begins to run). You need to move the call to ShowDialogAfterTaskFinishes() inside of the TTask procedure itself, similar to what you have for the call to UpdateMainWindow(), eg: procedure TfQBDailyInvoices.TransferEvent; begin TTask.Run( procedure var x: Integer; begin try for x := 0 to qInvoice.RecordCount - 1 do begin DidWorkorderTransfer := ProcessInvoice; TThread.Synchronize(nil, procedure begin { Update User Interface } UpdateMainWindow; end ); qInvoice.Next; end; finally TThread.Queue(nil, ShowDialogAfterTaskFinishes); end; end ); end; Alternatively, you can use TThread.CreateAnonymousThread() instead, so you can use the TThread.OnTerminate event (which is Synchronize()'d with the main UI thread), eg: procedure TfQBDailyInvoices.TransferEvent; var Thread: TThread; begin Thread := TThread.CreateAnonymousThread( procedure var x: Integer; begin for x := 0 to qInvoice.RecordCount - 1 do begin DidWorkorderTransfer := ProcessInvoice; TThread.Synchronize(nil, procedure begin { Update User Interface } UpdateMainWindow; end ); qInvoice.Next; end; end ); Thread.OnTerminate := TransferEventThreadTerminated; Thread.Start; end; procedure TfQBDailyInvoices.TransferEventThreadTerminated; begin ShowDialogAfterTaskFinishes; end; :
-
exceptions and static storage duration objects
Remy Lebeau replied to Fraser's topic in General Help
That is not what you described originally: Two different things. So, which one are you actually working with? Can you provide a code example that is crashing for you? -
Is it possible to see how compiler defines parameters?
Remy Lebeau replied to Mike Torrettinni's topic in RTL and Delphi Object Pascal
It shouldn't work, though. This is just straight up undefined behavior, since the TMemo.Lines property does not point at a TStringList object, it points at a TMemoStrings object instead. And TSStringList overrides Add() whereas TMemoStrings does not, so even the vtable contents are different. Don't write code like this. The correct solution is to make FillStrings() take a TStrings instead: function FillStrings(aStrings: TStrings): boolean; begin aStrings.Add('a'); aStrings.Add('b'); end; ... FillStrings(Memo1.Lines); Correct, because FillStrings() expects a TStringList specifically, not a TStrings generally. Nope. Nope. -
If only there was a system where component authors could update their GetIt submissions whenever they wanted..... oh wait, we were promised that years ago, but it never materialized.....
-
Community Edition expiring again, no new keys
Remy Lebeau replied to Nigel Thomas's topic in Delphi IDE and APIs
They are only just now working on this? When CE was first introduced several years ago, they didn't think this might be a problem down the line? They've had 3 years to fix it, what are they hoping to do in a few days? -
The type of sublist is the plain Pointer-based TList, so it makes sense that these hoops have to be done manually to store strings in it, but it is really not optimal. If the code were updated to use TStringList or TList<String> instead, then you wouldn't have to worry about manually managing the string memory at all.
-
Types incompatibles : 'string' et 'Extended'
Remy Lebeau replied to abdellahmehdi's topic in Algorithms, Data Structures and Class Design
On the other hand, depending on the situation, it would probably be better not to perform the calculation at all if the input is invalid, in which case TryStrToFloat() would make more sense if you want to avoid the exception and skip the calculation at the same time. -
How does CurrentControlSet differ from HKEY_CURRENT_USER
Remy Lebeau replied to Tom F's topic in Windows API
I still think it is likely a bug in the program, not in Windows itself. Like if the program had opened the StorageDevicePolicies key for some unrelated purpose, and then accidentally used that opened HKEY handle as a base when writing its settings to its own subkey rather than using the predefined base HKLM handle. -
Types incompatibles : 'string' et 'Extended'
Remy Lebeau replied to abdellahmehdi's topic in Algorithms, Data Structures and Class Design
You can't perform arithmetic with a Double and a String as operands. You have to first convert the String to a Double/Extended first. Use StrToFloat() or equivalent for that. And then you can convert the result back to a String using FloatToStr() or equivalent. Try something more like this: DBEdit43.Text := FloatToStr(0.000844 * StrToFloat(scGPDBEdit82.Text)); -
Yeah, like not using a TEdit for date/time input in the first place. Use a UI control that is specifically designed for date/time input (ie, TDateTimePicker, TDatePicker, TTimePicker). Same with integers, for instance (ie, TSpinEdit).
-
How does CurrentControlSet differ from HKEY_CURRENT_USER
Remy Lebeau replied to Tom F's topic in Windows API
Yes, that is where I would expect them, too. That is absolutely wrong. Application settings do not belong there. That is likely a bug in the program. It is a system-managed key, and it holds system settings, hardware configurations, service setups, etc. Note that HKLM\SYSTEM likely contains other keys ControlSet001, ControlSet002, etc. Those are like backups/previous versions of CurrentControlSet. If something goes wrong with the current settings, Windows has something it can roll back to. Every computer has a CurrentControlSet key. But not every computer has a StorageDevicePolicies key (mine doesn't). Absolutely not. You should contact the program author and explain the issue so they can fix it. -
You have 2 StrToDate() calls in that highlighted code (presumably more offscreen?), both are converting scGPDBDateEdit11.Text. Your earlier screenshot show the Text is ' / / ', which is obviously NOT a valid date string, which is why StrToDate() raises EConvertError. It should work just fine, eg: if TryStrToDate(scGPDBDateEdit11.Text, mydate) then begin // use mydate as needed... end else begin // do something else... end; Though, like I said, TDateTimePicker makes a lot more sense then a TEdit for date inputs, eg: mydate := IncYear(DateTimePicker11.Date, a); ... mydate := IncDay(DatePicker11.Date, a); ...
-
You can use the 'is' operator for that purpose, eg: procedure GetString(param1: string; param2: string; myControl: TControl); begin if myControl is TLabel then TLabel(myControl).Caption := GetDescription() else if myControl is TMemo then TMemo(myControl).Lines.Add(GetDescription()) else ...; end; Alternatively, every TControl has a Caption (and Text) property, even if it is not published. You can take advantage of that, eg: type TControlAccess = class(TControl) end; procedure GetString(param1: string; param2: string; myControl: TControl); begin if myControl is TMemo then TMemo(myControl).Lines.Add(GetDescription()) else TControlAccess(myControl).Caption := GetDescription(); end; Or, you can use RTTI instead, eg: procedure GetString(param1: string; param2: string; myControl: TControl); var Ctx: TRttiContext; Typ: TRttiType; Prop: TRttiProperty; begin Ctx := TRttiContext.Create; try Typ := Ctx.GetType(myControl.ClassType); Prop := Typ.GetProperty('Caption'); if (Prop <> nil) and (Prop.Visibility = mvPublished) then begin Prop.SetValue(myControl, GetDescription()); Exit; end; Prop := Typ.GetProperty('Text'); if (Prop <> nil) and (Prop.Visibility = mvPublished) then begin Prop.SetValue(myControl, GetDescription()); Exit; end; Prop := Typ.GetProperty('Lines'); if (Prop <> nil) and (Prop.Visibility = mvPublished) then begin (Prop.GetValue(myControl).AsObject() as TStrings).Add(GetDescription()); Exit; end; ... finally Ctx.Free; end; end;
-
If you are converting the Text of the "né" control to a TDate/TDateTime using StrToDate(), consider using TryStrToDate() instead. That would avoid the EConvertError being raised. Just make sure you pay attention to its return value to know if the conversion was successful or not. Personally, I would use a TDateTimePicker or TDatePicker instead. For instance, TDateTimePicker as a built-in CheckBox that can be used to indicate whether a date has been entered.
-
Indy comes pre-installed in the IDE. If you want to use your own compiled version of Indy, you should remove the pre-installed one to avoid conflicts.
-
Then you are likely not building with the DCUs you just compiled. Did you remove Indy from the IDE first? Did you update the IDE's search paths? https://github.com/IndySockets/Indy/wiki/Updating-Indy Also, which platform are you running your code on? The leaks you have showed are the intentional Indy leaks that should not be appearing on Windows, as they are "registered by pointer", as the dialog says.
-
You did not explain what kind of leaks you are actually experiencing (can you provide the actual leak report?), but I suspect the leaks have nothing to do with the TIdHTTP object itself. Are you referring to the intentional leaks in Indy's IdStack.pas and IdThread.pas units? If so, that is a completely separate matter, and one that is not affected by the Owner you assign to the TIdHTTP object.
-
And? The problem is ...? Wow, that is a really dirty and ugly hack. That code is reading the machine instructions of TIdStack.DecUsage() at runtime trying to find where it accesses the global GStackCriticalSection variable, and then it dereferences that variable to get the address of the TIdCriticalSection object, and then register it with FastMM so it won't appear in leak reports. I don't see why that hack is necessary at all when Indy already does that registration during unit initialization when REGISTER_EXPECTED_MEMORY_LEAK is defined, which it is by default when FREE_ON_FINAL is not defined, and either HAS_System_RegisterExpectedMemoryLeak or USE_FASTMM4 are defined. Yes, that is the correct solution. You have to recompile Indy for it to take effect. The simplest way would be to have your project refer to Indy's source files directly so they compile directly into the executable. If you have installed Indy into the IDE, you will have to recompile the installed BPLs instead.
-
Why jpg image is not created?
Remy Lebeau replied to neumimnemecky's topic in Algorithms, Data Structures and Class Design
That is a bad idea in general. It prevents users from being able to set their own working directory when running your app from a command-line window or a shortcut. -
Why jpg image is not created?
Remy Lebeau replied to neumimnemecky's topic in Algorithms, Data Structures and Class Design
Check with TDirectory.GetCurrentDirectory() or equivalent to make sure that '.' refers to the folder you think it does. -
Can not login to FTP server without password
Remy Lebeau replied to DMX78's topic in ICS - Internet Component Suite
A read timeout error has nothing to do with authentication. Sounds more like the data connection is probably being blocked. Remember, FTP uses multiple TCP connections. I notice in your earlier log that a PORT command is being issued. That means your FTP client is acting in ACTIVE mode, where the server opens a data connection to the client. That is not very friendly to routers/proxies. You should use PASSIVE mode instead, where the client opens a data connection to the server instead. That is less likely to cause problems. -
TidHTTP [SSL], SSL errors is production, not in developement
Remy Lebeau replied to mvanrijnen's topic in Network, Cloud and Web
Which version of the DLLs are you using, though? TIdSSLIOHandlerSocketOpenSSL supports OpenSSL 1.0.2 or earlier. If you are trying to use OpenSSL 1.1.x or later, you need to use this SSLIOHandler instead: https://github.com/IndySockets/Indy/pulls/299 The only issue I see with that code is you are creating the SSLIOHandler conditionally. You don't need to do that, you can access non-secure HTTP urls even with the SSLIOHandler assigned. TIdHTTP will handle the underlying TCP connection and SSLIOHandler.PassThrough property for you on a per-request basis, (re)connecting and toggling between TLS/non-TLS as needed. Because of that management, when you do create the SSLIOHandler, you don't need to set its PassThrough property manually at all. The SSLIOHandler will also handle loading the OpenSSL DLLs dynamically only when they are actually needed, so if you never request an HTTPS url then the DLLs won't ever get loaded, and PassThrough will always be True. So, I would suggest just getting rid of your UseSSL config option altogether, it is really not necessary. In fact, it will actually cause a runtime error if it is set to False and then you request a non-secure HTTP url that redirects to a secure HTTPS url. So, best to just have the SSLIOHandler assigned unconditionally instead, so it is always ready to go in case it is needed. procedure THSJSonApiClient.InitHTTP; begin fhttp := TIdHTTP.Create(nil); fopenssl := TIdSSLIOHandlerSocketOpenSSL.Create(fhttp); fopenssl.SSLOptions.VerifyMode := []; fopenssl.SSLOptions.VerifyDepth := 0; fopenssl.SSLOptions.SSLVersions := [sslvTLSv1_2, sslvTLSv1_1, sslvTLSv1]; fhttp.IOHandler := fopenssl; fhttp.handleredirects := True; {$IFDEF DEBUG} flog := TIdLogEvent.Create(nil); flog.ReplaceCRLF := False; flog.LogTime := False; flog.Active := True; flog.OnReceived := CatchLogReceived; flog.OnSent := CatchLogSent; flog.OnStatus := CatchLogStatus; fhttp.Intercept := flog; {$ENDIF} end; -
Use the Value() method instead of the ToString() method: OrderNoRESTResp.RootElement := 'OrderNo'; Result := OrderNoRESTResp.JSONValue.Value; In this example, the JSONValue will point at a TJSONString, which overrides Value() to return the plain content. As it should be, since ToString() is meant for obtaining JSON formatted data, not plain data. You don't need to resort to accessing the JSON pairs directly in this case. Besides, if you are setting the RootElement to 'OrderNo', that code won't work, because the JSONValue will be pointing at a TJSONString not a TJSONObject, so the 'as' operator would raise an exception. But, if you are leaving the RootElement blank, then the JSONValue will be pointing at the whole TJSONObject, yes, and then you are effectively just accessing TJSONObject(JSONValue).Get('OrderNo').Value() in a round-about way. But, notice that you are using Value() instead of ToString() to read the string data? Same solution as above, ultimately.
-
I think they gave up on incremental updates. IIRC, everything in recent years has always required a full uninstall and reinstall.