-
Content Count
2990 -
Joined
-
Last visited
-
Days Won
134
Everything posted by Remy Lebeau
-
Android. TDirectory.GetFiles('/storage/emulated/0/DCIM/Camera') returns an empty list
Remy Lebeau replied to dmitrybv's topic in Cross-platform
Have you tried TPath.GetCameraPath() yet? Does your app have permission to access the camera files? -
Learning to make my own classes
Remy Lebeau replied to Skrim's topic in Algorithms, Data Structures and Class Design
If they all have different names/types, then yes (provided you need getters/setters at all - see dummzeuch's examples). But, if they are all related, eg Name1, Name2, etc then you can use an indexed property instead, eg: Type TEmployee = class private FNames[0..49] : string; Function GetName(Index: Integer) : string; Procedure SetName(Index: Integer; const Value : string); public Property Names[Index: Integer] : string read GetName write SetName; end; implementation {$R *.dfm} Function TEmployee.GetName(Index: Integer): string; begin Result := FNames[Index]; end; Procedure TEmployee.SetName(Index: Integer; const Value: string); begin if Value = '' then raise Exception.Create('Value must not be empty'); FNames[Index] := Value; end; Alternatively, you could do something like this: const EmployeeNameIdx := 0; EmployeeEmailIdx := 1; ... Type TEmployee = class private FValues[0..49] : string; Function GetValue(Index: Integer) : string; Procedure SetValue(Index: Integer; const Value : string); public Property Name : string read GetValue write SetValue index EmployeeNameIdx; Property Email : string read GetValue write SetValue index EmployeeEmailIdx; end; implementation {$R *.dfm} Function TEmployee.GetValue(Index: Integer): string; begin Result := FValues[Index]; end; Procedure TEmployee.SetValue(Index: Integer; const Value: string); begin if Value = '' then raise Exception.Create('Value must not be empty'); FValues[Index] := Value; end; Yes, eg: Type TEmployee = class private ... public type TDetails = record ... end; ... end; -
Learning to make my own classes
Remy Lebeau replied to Skrim's topic in Algorithms, Data Structures and Class Design
In his example, nowhere. You would need a setter for that. -
TMultipartFormData issue with 12.3, but not 11.3
Remy Lebeau replied to alank2's topic in Network, Cloud and Web
@alank2 What you describe implies that either 1) TMultipartFormData is trying to free an invalid FStream object, or 2) you are trying to free an invalid TMultipartFormData object. Unfortunately, there is not enough detail provided to help you. You will have to debug the code for yourself, and double check the user of the pointers involved. -
You should be able to do that, as each Exception object in the chain is preserved as-is and would carry its own CallStack, which JCL can populate as each Exception is raised. https://blog.eurekalog.com/2010/05/new-exception-class-in-delphi-2009-and_05.html Not really, because you are still raising twice. Whether you raise and then re-raise 1 object, or raise 2 objects, is up to you.
-
I (relunctantly) agree with ChatGPT on this one - you should not modify the original exception, but instead you should raise a new exception that captures the original exception into the new exception's InnerException property. However, the way that ChatGPT demonstrates this is wrong: Firstly, SysUtils.Exception does not have a public SetInnerException() method. ChatGPT suggests defining a new class, but then doesn't use that class. And that class is just trying to replicate a feature that already exists natively in SysUtils.Exception. Second, ChatGPT's approach does not release ownership of the original Exception, so the try..except will still try to free it when the except block exits, leaving the new Exception holding a dangling InnerException pointer to a now-dead Exception. The correct way to capture an InnerException is to use the SysUtils.Exception.RaiseOuterException() method, eg: try sqhpartyroles.sql := fsqlhandle.buildsql; sqhpartyroles.executesql; except Exception.RaiseOuterException(Exception.CreateFmt('error from sql %s', [sqhpartyroles.sql])); end; (I don't like this syntax, but it is what it is...) Higher up the call chain, you can then catch the new Exception and traverse its InnerException chain if you want to report/log all of the individual error messages, eg procedure MyForm.Application1Exception(Sender: TObject; E: Exception); begin repeat // use E as needed, then... E := E.InnerException; until E = nil; end;
-
Really? They all look the same to me... weird...
-
Of course the dialog may be localized based on the user's language. Most OS dialogs are. Bu that doesn't mean the OS makes those localized strings available to apps. So, you'll likely need to provide your own localized strings if you want to honor the user's language in your own UI/logging. Those are all the same values that @Kas Ob. showed you earlier, which Microsoft already documents in several places of MSDN. So you didn't need to go to that effort.
-
TFontDialog is just a wrapper for the Win32 ChooseFont() API, so it displays whatever the OS wants to display.
-
There is no Win32 API to get the same text that appears in the dialog. You have to use your own logic, using the numeric values shown by @Kas Ob. with a lookup array such as shown by @dwrbudr. The EnumFontFamiliesEx() API gives you the numeric value, you have to convert it to text yourself.
-
Don't forgot to call 'inherited Create(aOwner);'
-
Except in this case, as the properties shown are not declared as published, so not streamed by the DFM at all.
-
That won’t work as you describe. You can't add parameters to the OnCreate event. What you are proposing requires defining a new constructor instead.
-
Is it possible to declare an identical type for a generic class?
Remy Lebeau replied to dmitrybv's topic in RTL and Delphi Object Pascal
https://stackoverflow.com/questions/16150218/is-it-possible-to-create-a-type-alias-to-a-generic-record-in-delphi https://stackoverflow.com/questions/10060009/is-it-possible-to-create-a-type-alias-to-a-generic-class -
Some questions about password input and TDialogService
Remy Lebeau replied to pquessev's topic in FMX
The OP asked about Android, and modal dialogs are not supported on Android. -
Some questions about password input and TDialogService
Remy Lebeau replied to pquessev's topic in FMX
I can't answer your question. But an alternative approach would be to create your own dialog however you want, and then write your own class that implements the IFMXDialogServiceAsync interface to show your dialog, and then register that class with FMX using TPlatformServices.Current.AddPlatformService() (be sure to unregister the default implementation using TPlatformServices.Current.RemovePlatformService() first). -
Embarcadero doesn't want your location. This warning is starting to show up for a lot of network-enabled apps. A recent Windows update is enforcing permission to Wifi info, as it CAN be used to reveal your location, which is a privacy concern. https://learn.microsoft.com/en-us/windows/whats-new/whats-new-windows-11-version-24h2#windows-location-improvements
-
FormatDateTime in Delphi 12
Remy Lebeau replied to Oscar Hernández's topic in Algorithms, Data Structures and Class Design
You are using the version of FormatDateTime() that relies on global variables initialized with your PC's locale settings. For instance, the '/' specifier is not a literal slash character, it is a placeholder that uses the global DateSeparator variable in the SysUtils unit. This is documented behavior. You can update those globals to customize things like the date/time separators, but this affects the whole app, and is not thread-safe. When you need custom formatting that is locale-agnostic, you should use the version of FormatDateTime() that takes a TFormatSettings parameter, eg: procedure TForm1.Button1Click(Sender: TObject); var lDate: TDateTime; lFmt: TFormatSettings; begin lFmt := TFormatSettings.Create; lFmt.DateSeparator := '/'; lDate := EncodeDate(2025, 3, 26); Edit1.Text := FormatDateTime('dd/mm/yyyy', lDate, lFmt); end; The alternative is to wrap desired literal text with quotes in your format string, eg: procedure TForm1.Button1Click(Sender: TObject); var lDate: TDateTime; begin lDate := EncodeDate(2025, 3, 26); Edit1.Text := FormatDateTime('dd"/"mm"/"yyyy', lDate); end; -
That is pretty trivial to implement, eg: procedure TMainForm.GoBtnClick(Sender: TObject); var url: string; idx: integer; begin { change this https://www.youtube.com/watch?v=ZJhJILyS388 to this https://www.youtube.com/embed/ZJhJILyS388 } url := StringReplace(addresscb.Text, 'watch?v=', 'embed/', [rfIgnoreCase]); addressCb.Text := url; WVBrowser1.Navigate(url); idx := ComboBox1.Items.IndexOf(url); if idx = -1 then ComboBox1.Items.Add(url); end;
- 12 replies
-
- delphi xe7
- youtube
-
(and 1 more)
Tagged with:
-
[dcc32 Error] Type parameter 'T' must be a non-nullable value type
Remy Lebeau replied to EugeneK's topic in RTL and Delphi Object Pascal
(Ansi|Unicode|Wide)String are managed types. String[n] (ShortString) is not. But switching to ShortString has its own share of compatibility issues not related to Generics. -
[dcc32 Error] Type parameter 'T' must be a non-nullable value type
Remy Lebeau replied to EugeneK's topic in RTL and Delphi Object Pascal
That has nothing to do with Generics (the topic of this discussion). Specifying an explicit length on a string at compile-time will produce an AnsiChar-based ShortString, and always has. That's nothing new. Assigning an Ansi string to a Unicode string (or vice versa) requires a data conversion at runtime, which can potentially lose data, hence the warning. -
[dcc32 Error] Type parameter 'T' must be a non-nullable value type
Remy Lebeau replied to EugeneK's topic in RTL and Delphi Object Pascal
That StackOverflow post is about the error on a Custom Managed Record, but the code shown above is not using a CMR. It is just a regular Managed Record due to the string field (has nothing to do with the custom Attribute). And according to RSS-3043 (which has been closed last week as "As Designed"): -
Calling ReadBytes() with an AByteCount value greater than 0 will wait until the specified number of bytes have arrived in the InputBuffer. So, if you are expecting 7000 bytes then just call ReadBytes() 1 time with AByteCount set to 7000. But, if you don't know ahead of time how many bytes are coming, then you can call ReadBytes() with an AByteCount value less than 0 and it will return however many bytes are currently available in the InputBuffer (if it is empty, ReadBytes() will wait until any bytes arrive first). If you don't want to change your current logic, then you can simply catch the EIdReadTimeout exception and call ReadBytes() again with the AByteCount value set to the IOHandler's current InputBuffer.Size.
-
deleting a form in a DLL DLL_PROCESS_DETACH causes 0x0eedfade
Remy Lebeau replied to alank2's topic in VCL
DLL_PROCESS_ATTACH should be in the same thread that calls LoadLibrary(), but DLL_PROCESS_DETACH is not guaranteed to be in that same thread. Raymond Chen even blogged about this issue back in 2009 (emphasis added by me): The thread that gets the DLL_PROCESS_DETACH notification is not necessarily the one that got the DLL_PROCESS_ATTACH notification