Jump to content

Remy Lebeau

Members
  • Content Count

    2874
  • Joined

  • Last visited

  • Days Won

    126

Everything posted by Remy Lebeau

  1. Show off 😉 Thanks, I have added it to the bug report.
  2. That is not what I would call a MINIMAL example, but at least it compiles this time. There is still a lot of IRRELEVANT code that has nothing at all to do with demonstrating the issue at hand. But so be it. Your TBaseConnectionParams and TSqliteParams classes are duplicating similar code because THEY ARE RETURNING DIFFERENT THINGS, so how to do you expect one to just inherit the behavior of the other? They can't. If you really want to make use of class inheritance then you need to simplify the design of the common elements so they are coherent and overridable across descendants. You are not even override'ing the base methods, you are reintroduce'ing them. That is not how inheritance works.
  3. Remy Lebeau

    filenames with unicode chars

    @David Heffernan who are you directing that to?
  4. Remy Lebeau

    Should I just dive in to GUI programs?

    You don't need to change the AppType to use WriteLn(). A GUI app can simply call AllocConsole() or AttachConsole() and then WriteLn() will automatically work. That being said, another way to debug would be to use OutputDebugString() instead, and then you can see the messages in the IDE's debugger, or in SysInternals DebugView when running outside of the debugger.
  5. I can reproduce the problem in a simple example that doesn't involve Spring4D (however, I get an "E2010 Incompatible types" error instead of an E2250) : type IShared<T> = reference to function: T; Shared = class class function Make<T: class>(AObj: T): IShared<T>; end; TSharedImpl<T: class> = class(TInterfacedObject, IShared<T>) FObj: T; constructor Create(AObj: T); destructor Destroy; override; function Invoke: T; end; TTest = class end; TTester = class procedure DoTest(AObj: TTest); end; class function Shared.Make<T>(AObj: T): IShared<T>; begin Result := TSharedImpl<T>.Create(AObj) as IShared<T>; end; constructor TSharedImpl<T>.Create(AObj: T); begin inherited Create; FObj := AObj; end; destructor TSharedImpl<T>.Destroy; begin FObj.Free; inherited Destroy; end; function TSharedImpl<T>.Invoke: T; begin Result := FObj; end; procedure TTester.DoTest(AObj: TTest); begin //... end; procedure Foo1; var Tester : IShared<TTester>; TestObj : IShared<TTest>; begin Tester := Shared.Make(TTester.Create); TestObj := Shared.Make(TTest.Create); Tester.DoTest(TestObj); // <-- Compiles OK! end; procedure Foo2; begin var Tester: IShared<TTester>; var TestObj: IShared<TTest>; Tester := Shared.Make(TTester.Create); TestObj := Shared.Make(TTest.Create); Tester.DoTest(TestObj); // <-- E2010 Incompatible types: 'TTest' and 'IShared<TTest>' Tester.DoTest(TestObj()); // <-- Compiles OK! end; I have now reported this issue to Embarcadero: RSS-2613: Anonymous Method is called differently depending on whether it is declared as an Inline Variable or not
  6. Remy Lebeau

    filenames with unicode chars

    Just like in the example I gave you in my last reply, in this case I'm guessing that R.Name[10] is 0x0065 (Latin Small Letter E) and R.Name[11] is 0x0301 (Combining Acute Accent), whereas you are expecting R.Name[10] to be 0x00E9 (Latin Small Letter E with Acute) instead. To accomplish what you want, you should normalize the Unicode characters, probably to form NFC, before you can then process and replace them. Read the following for more details: Unicode Standard Annex #15: Unicode Normalization Forms Using Unicode Normalization to Represent Strings NormalizeString function I realize that. But that is reserved for markup language in plain text. You need to actually click on the '</>' button in the toolbar and put your code in the resulting popup dialog.
  7. I'm sorry, but the code you have provided is full of errors, I can't even attempt to compile it as-is, and I'm not going to waste my time trying to fix it all. When you can provide an example that can be COPY/PASTED as-is (or better, provide the actual files as attachments), and it can compile and produce a specific compiler error that you are trying to fix, then I will be happy to look at it again.
  8. Remy Lebeau

    filenames with unicode chars

    One issue I see is you are not taking into account either UTF-16 surrogates, or Unicode combining codepoints. Not all Unicode characters take up 1 WideChar, sometimes they require 2+ WideChars, especially if they are not in a normalized form. For example, the character 'á' may be 1 WideChar 0x00E1 (Latin Small Letter A with Acute), or it may be 2 WideChars 0x0061 (Latin Small Letter A) and 0x0301 (Combining Acute Accent) working together. What are the actual numeric values of the WideChars that you are actually receiving for the filename you are having trouble with? That is because you are posting the code as plain text. Put it inside of a code block instead (the '</>' button on the editor toolbar). For example: void sayHi() { cout << "This is in a code block!"; }
  9. Can you trim that down to a MINIMAL example that actually exhibits the problem? Most of that code is irrelevant to the issue. Are you getting a compiler error? If so, what is it? What EXACTLY are you trying to implement that you think is missing?
  10. Any class that derives from TBaseFoo inherits the methods that TBaseFoo implements. Why do you think any workaround is needed? What is the actual PROBLEM you are having with your code in the first place?
  11. Remy Lebeau

    filenames with unicode chars

    Feel free to step into the RTL source code for yourself with the debugger (see the code below). On Windows, the RTL's Find(First|Next)() functions simply call the API Find(First|Next)FileW() functions and then copy the WIN32_FIND_DATA fields into the TSearchRec fields: function FindFirstFile; external kernelbase name 'FindFirstFileW'; function FindNextFile; external kernelbase name 'FindNextFileW'; ... function FindMatchingFile(var F: TSearchRec): Integer; ... begin while F.FindData.dwFileAttributes and F.ExcludeAttr <> 0 do if not FindNextFile(F.FindHandle, F.FindData) then begin Result := GetLastError; Exit; end; ... F.Name := F.FindData.cFileName; // <-- HERE Result := 0; end; function FindFirst(const Path: string; Attr: Integer; var F: TSearchRec): Integer; const faSpecial = faHidden or faSysFile or faDirectory; begin F.ExcludeAttr := not Attr and faSpecial; F.FindHandle := FindFirstFile(PChar(Path), F.FindData); if F.FindHandle <> INVALID_HANDLE_VALUE then begin Result := FindMatchingFile(F); // <-- HERE if Result <> 0 then FindClose(F); end else Result := GetLastError; end; function FindNext(var F: TSearchRec): Integer; begin if FindNextFile(F.FindHandle, F.FindData) then Result := FindMatchingFile(F) // <-- HERE else Result := GetLastError; end; As you can see, the API's WIN32_FIND_DATA::cFileName is assign as-is to the RTL's TSearchRec::Name field, and since both field are based on WideChar (WIN32_FIND_DATA::cFileName is a WideChar[] array and TSearchRec::Name is a UnicodeString) then there is no manipulation of the reported characters in any way, they are copied as-is. What you get back in your code SHOULD be exactly what Windows actually reported. The TSearchRec::FindData field is the raw WIN32_FIND_DATA data that Find(First|Next)File() actually reported.
  12. The TTestFoo class inherits all of the implemented methods of the TBaseFoo class. This is literally how class inheritance works. I don't understand the question. However, interface inheritance works a little different. Sometimes you have to make sure that a derived class explicitly declares all of the interfaces it supports - even the base ones - and not rely on inheritance alone to do that for you, eg: TTestFoo = class(TBaseFoo, IBaseFoo, ITestFoo) // automatically inherits the methods of TBaseFoo... procedure TestFooMethod; end;
  13. Remy Lebeau

    filenames with unicode chars

    The RTL's Find(First|Next)() functions use the Win32 Find(First|Next)FileW() APIs internally, and have done so since 2009. That might be related to the removal of the Form's OldCreateOrder property in RAD Studio 11. But, you should never have been using the OnCreate (and OnDestroy) event(s) in C++ anyway, as that has always had the potential of introducing Undefined Behavior in user C++ code due to the different creation models between Delphi vs C++. Use the Form's constructor (and destructor) instead, that is always safe. And streamed property values are available in the constructor.
  14. Remy Lebeau

    How to solve System Out of Resources in TScrollBox

    For my custom log viewer, I used a standard TListView in virtual mode with owner-drawn items, and it handles millions of items (GB-sized log files) just fine with low overhead. The hardest part was implementing a caching mechanism for the on-screen items, as I also filter and search items so don't want to keep the whole file in memory at one time.
  15. Remy Lebeau

    One line of code not quite right

    What are you talking about? There are no "function headers" in Delphi. Are you trying to reply to me or to Pat Foley? I'm so lost now were this discussion is going...
  16. Remy Lebeau

    One line of code not quite right

    Really? You've shown enough code that demonstrates you know how to CALL functions. So, per the documentation, simply change BoolToStr(a) to BoolToStr(a, True), etc.
  17. Remy Lebeau

    One line of code not quite right

    Because they really are incompatible types. The '+' operator is not defined for Booleans. Read the documentation: https://docwiki.embarcadero.com/RADStudio/en/Expressions_(Delphi)#Operators So, you would have to convert the Booleans to Integer before using the '+' operator, then convert the result back to Boolean before using the 'not' operator, eg: MemoResult.Text := MemoResult.Text + ('not a: ' + BoolToStr(not Boolean(Ord(a) + Ord(b)))) + sLineBreak; Alternatively: MemoResult.Text := MemoResult.Text + ('not a: ' + BoolToStr(not ((Ord(a) + Ord(b)) <> 0))) + sLineBreak; On the other hand, your input expression does not match what your text says, which would be just this instead: MemoResult.Text := MemoResult.Text + ('not a: ' + BoolToStr(not a)) + sLineBreak; On a side note: you don't need all the extra parenthesis around your strings: MemoResult.Text := 'a: ' + BoolToStr(a) + sLineBreak; MemoResult.Text := MemoResult.Text + 'b: ' + BoolToStr(b) + sLineBreak; MemoResult.Text := MemoResult.Text + 'a and b: ' + BoolToStr(a and b) + sLineBreak; MemoResult.Text := MemoResult.Text + 'a or b: ' + BoolToStr(a or b) + sLineBreak; MemoResult.Text := MemoResult.Text + 'not a: ' + BoolToStr(not a) + sLineBreak; Yes. Read the documentation: https://docwiki.embarcadero.com/Libraries/en/System.SysUtils.BoolToStr There is an optional UseBoolStrs parameter that defaults to false. Simple set it to true instead. Yes, I did, eg: MemoResult.Lines.Add('a: ' + BoolToStr(a)); MemoResult.Lines.Add('b: ' + BoolToStr(b)); MemoResult.Lines.Add('a and b: ' + BoolToStr(a and b)); MemoResult.Lines.Add('a or b: ' + BoolToStr(a or b)); MemoResult.Lines.Add('not a: ' + BoolToStr(not a));
  18. Remy Lebeau

    Application Loading incorrect bpl

    Actually, that doesn't answer my question at all, so let me rephrase it... When the application begins, is the BPL being loaded automatically by Windows (are you seeing a standard system error message?), or is the BPL being loaded by the application's code using Delphi's LoadPackage() function and then displaying its own error message? Can you provide a screenshot of the error message? Did you check Windows' PATH environment to see if the Desktop folder is present in it and is before the BPL folder? The best way to ensure that the BPLs are being loaded only from the app's BPL subfolder is to load them manually in code using LoadPackage() specifying the absolute path to each BPL. If that is not an option, then the next best option is to make sure the BPLs are marked for delay-loading in the app's config and then call SetDllDirectory() or AddDllDirectory() at app startup to add the BPL subfolder to the DLL search path before the standard system search path.
  19. Remy Lebeau

    My sLineBreak is not working

    In your example, it would be better to use the Lines.Add() method rather than the Text property, then you don't have to worry about using sLineBreak at all, or wasting time and resources to read the Text, append to it, and assign it back. procedure TFormIncrementAndDecrement.ButtonShowValuesClick(Sender: TObject); var x, y: integer; begin x := 6; y := 7; MemoResult.Clear; MemoResult.Lines.Add('The value of x is: ' + IntToStr(x)); MemoResult.Lines.Add('The value of y is: ' + IntToStr(y)); end;
  20. Remy Lebeau

    Application Loading incorrect bpl

    Are you linking statically to the BPL at compile-time, or are you loading the BPL dynamically at runtime?
  21. Remy Lebeau

    Looking for a certain component

    You can use a standard TPanel, simply adjust its BevelInner and BevelOuter properties to mimic the sunken look you want. And, you can assign text to a TPanel like you can with a TLabel (or, just put a TLabel on the TPanel).
  22. Remy Lebeau

    TStringgrid how to automatically set the column widths

    Did you try debugging the code? Probably the global EditSeriesForm variable is nil. Since the code is inside of a method of the Form class, it should be using the method's own Self pointer instead of using the global Form pointer: Col_Width := Self.Canvas.TextWidth(Grid.Cells[Acol,i]); But, the code really should be using the StringGrid's Canvas instead of the Form's Canvas: Col_Width := Grid.Canvas.TextWidth(Grid.Cells[Acol,i]); Also, there is no reason for the Grid parameter to be marked as var, since the code is not changing which object the variable points at. Objects are passed around by pointer, and passing that pointer into the method by value instead of by var reference will work just fine in this situation.
  23. Remy Lebeau

    Should I just dive in to GUI programs?

    Maybe because the majority of end users are not console users, and the books want you to reach a larger userbase more quickly? Just speculating...
  24. Remy Lebeau

    What is this flashing message doing there?

    What about a short screen capture video? Well, they could search their source code for the word "calculating"...
  25. Remy Lebeau

    What is this flashing message doing there?

    Which version of the IDE are you using? Are you seeing the flash appear in the code editor, or in your program's UI? Can you get a screenshot of the flash?
×