Jump to content

dummzeuch

Members
  • Content Count

    2855
  • Joined

  • Last visited

  • Days Won

    101

Everything posted by dummzeuch

  1. dummzeuch

    Thread leaks report (FastMM4)

    Ouch, yes you are right! I chose the wrong example. But there are always more complex examples where this won't work. (Unfortunately I can't think of one right now. GetMem/FreeMem should also work fine.)
  2. dummzeuch

    Thread leaks report (FastMM4)

    I see no problem with raising an exception in a constructor, provided you write the destructor in a way that can handle a partly constructed instance. Since you can't prevent any system or RTL exception to be raised from within the constructor, you'll have to handle that case anyway. Always keep in mind that an exception in a constructor will cause the destructor being called immediately. So don't do this: constructor TBla.Create; begin inherited; FSomeHelperObject := TSomeClass.Create; end; destructor TBla.Destroy; begin FSomeHelperObject.Free; // <== this might cause an AV if FSomeHelperObject hasn't been assigend inherited; end; But do this instead: destructor TBla.Destroy; begin if Assigned(FSomeHelperObject) then FSomeHelperObject.Free; inherited; end; (Or use FreeAndNil, which basically does the same internally.) You can easily test if your destructor can handle this case by temporarily putting a raise exception.Create('test') as the first statement in your constructor (before even calling inherited Create). I'm sure we are all guilty of writing wrong destructors at some time though.
  3. I just had the need for a safer version of Delphi's GetEnumName, which checks whether the enum value passed to it is actually valid. This is what I came up with: // P must point to the length field (that is the first byte) of a ShortString function AfterShortString(const P: Pointer): Pointer; inline; begin Result := Pointer(IntPtr(P) + PByte(P)^ + 1); end; function SafeGetEnumName(TypeInfo: PTypeInfo; Value: Integer): string; var P: Pointer; T: PTypeData; begin if TypeInfo^.Kind = tkInteger then begin Result := IntToStr(Value); Exit; end; T := GetTypeData(GetTypeData(TypeInfo)^.BaseType^); if (TypeInfo = System.TypeInfo(Boolean)) or (T^.MinValue < 0) then begin // LongBool/WordBool/ByteBool have MinValue < 0 and // arbitrary content in Value; Boolean has Value // in [0, 1] } Result := BooleanIdents[Value <> 0]; if SameText(HexDisplayPrefix, '0x') then Result := LowerCase(Result); end else begin if (Value < T.MinValue) or (Value > T.MaxValue) then Result := Format('OutOfBounds(%d)', [Value]) else begin P := @T^.NameList; while Value <> 0 do begin P := AfterShortString(P); Dec(Value); end; {$IFDEF UNICODE} Result := _UTF8ToString(P); {$ELSE} Result := PShortString(P)^; {$ENDIF} end; end; end; (read on in the blog post)
  4. Hm, yes. But GetEnumName doesn't work for enums with explicitly assigned values. program Project1; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, System.TypInfo; type TBla = (a5 = 5, a7 = 7); TBlub = (b5, b7); begin WriteLn(GetEnumName(TypeInfo(TBlub), Ord(b5))); WriteLn(GetEnumName(TypeInfo(TBla), Ord(a5))); end [dcc32 Error] Project1.dpr(19): E2134 Type 'TBla' has no type info
  5. dummzeuch

    F1 context help to WinAPI ?

    I had totally forgotten about that. I also don't quite remember why I used this particular sort algorithm, probably because I was tired of Quicksort and Cocktail Sort sounded more interesting. Or maybe I just selected a random sort algorithm from my dzlib.
  6. dummzeuch

    F1 context help to WinAPI ?

    Delphi Help Expert
  7. dummzeuch

    Quality Portal going to be moved

    Maybe Embarcadero really care about the old bug reports so they stayed with JIRA in order to make it easier to import the old reports into the new system? Of course that's pure speculation.
  8. dummzeuch

    Variable might not have been initialized

    No. That line is only executed if the condition in the if statement three lines above it is true. Let me adapt the code to make this clear: if FWorkOrderManager.GetWorkOrderDataByIndex(WorkOrdersSelectedRow - 1, Data) then begin // evaluates file index FileIndex := ARow - 1; // <--- Here FileIndex is initialized, but only if the condition above was true end; if (FileIndex < 0) or (FileIndex >= TWorkOrderData.FILE_DATA_SIZE) then Exit; // <--- here FileIndex mith not have been initialized if the condition above was false. And that's what the compiler says.
  9. dummzeuch

    Variable might not have been initialized

    Which again highlights the value of a code formatter. I'm so used to that that I overlooked the if statement. 😞
  10. dummzeuch

    Variable might not have been initialized

    I usually solve this kind of warnings with a compiler specific ifdef that adds an assignment for the variable in question. In this case I'm not sure this is possible as there already is an unconditional assignment. {$IF CompilerVersion=nn} // Delphi xxx complains here about FileIndex not being initialized FileIndex := 0; {$IFEND} FileIndex := ARow - 1; I make it compiler version specific just in case a newer compiler does no longer complain. The downside is that it clutters the code with such workarounds, but I look at a specific code section a lot less than I see unnecessary hints and warnings.
  11. dummzeuch

    Variable might not have been initialized

    Looks like a compiler bug (but isn't, see Uwe's Answer!). I've seen similar warnings / hints. It's even worse when you use different Delphi versions: One complains about a variable not being initialized, so you fix that by adding a superfluous assignment, then the other complains about a value assigned to that variable not being used. The annoying bit is that I usually want my code to compile without hints and warnings so I can spot new problems right away.
  12. dummzeuch

    Essential Delphi Addins survey

    What's the purpose of this survey?
  13. dummzeuch

    Essential Delphi Addins survey

    Probably this: https://github.com/HashLoad/delphi-docker Never heard about it either.
  14. Delphi 12 creates an entry in the (Open Shell) start menu directly under programs. I don't want that entry that so I deleted it. But every time I start the Delphi 12 IDE that entry is added again. This is really annoying. Is there a setting somewhere that controls this?
  15. For creating csv files I wrote this a while ago: https://sourceforge.net/p/dzlib/code/HEAD/tree/dzlib/trunk/src/u_dzCsvWriter.pas I thought I also had a similiar unit/class for reading csv files, but I can't find it right now.
  16. TRegistry seems to be missing methods to read and write entries of the type REG_MULTI_SZ. I would expect ... procedure TRegistry.WriteMultiString(const AName: string; const Values: TStringDynArray); ... and ... function TRegistry.ReadMultiString(const AName: string): TStringDynArray; Am I overlooking something?
  17. OK, that explains it. I was looking at Delphi 10.2.
  18. dummzeuch

    rease ... at ReturnAddress

    Good to know. I just went through several versions in more detail and found exactly what you said: No stack frames in XE, but stack frames in XE3. Unfortunately my XE2 installation seems to be broken (it tries to open a codegear url with the word "tampering" in it, so I guess it's the bloody copy protection at work). So thanks for the confirmation. I will update my blog post and the conditional defines. I still don't understand what caused me to assume the change was with Delphi 10.2. I cannot reproduce that now.
  19. dummzeuch

    rease ... at ReturnAddress

    The difference seems to be the RTL code. In Delphi 2007 it does not create a stack frame, regardess if using debug dcus or not: @AbstractError: 00402EEC 833D28B0400000 cmp dword ptr [$0040b028],$00 00402EF3 7406 jz $00402efb 00402EF5 FF1528B04000 call dword ptr [$0040b028] In Delphi 12 it does, again regardless if using debug dcus or not: System.pas.11789: begin 00AD4A68 55 push ebp 00AD4A69 8BEC mov ebp,esp System.pas.11790: if Assigned(AbstractErrorProc) then 00AD4A6B 833D3840AF0000 cmp dword ptr [$00af4038],$00 00AD4A72 7406 jz $00ad4a7a System.pas.11791: AbstractErrorProc; 00AD4A74 FF153840AF00 call dword ptr [$00af4038] So, yes the difference seems to be the compiler settings for stack frames, but not in my code but in the System unit. Now the question is when this was changed.
  20. dummzeuch

    rease ... at ReturnAddress

    You caught me on that: I didn't verify the stack frame settings, but I have just done so. The (new) code works for Delphi 2007 and Delphi 12(.1) with or without stack frames. I didn't check the other versions. Can you think of any other compiler settings I'd need to check? My target platform is Win32 only. It doesn't even compile for anything else because of the asm syntax anyway. ... which would require me to add JclDebug and its dependencies to all programs that use this simple unit. For most of the programs at work this wouldn't make any difference because they use JclDebug anyway, but my personal projects don't. Hm, is JclDebug even compatible to X64? Or other target platforms? I have never checked.
  21. dummzeuch

    Problems closing IDE

    Exceptions on shutdown are particularly difficult to track down because lots of code gets executed at that time and not necessarily in the expected order. IDE plugins use the Open Tools API which consists of a set of interfaces which all go out of scope on shutdown. On top of that some plugins hack into the inner workings of the IDE to fix bugs, add functionality or change the UI (GExperts and cnwizards both do that). If you have several plugins installed they might also interfere with each other. You can always run the IDE itself in the debugger and hope that in the case of an exception the call stack might give you some clues. But don't hold your breath, I have tried that for years and it rarely helped. Having said that: I know that using the GExperts code formatter can cause access violations later on in the code editor or when exiting the IDE. This did not start when the code formatter was added to GExperts but already happened with the original DelFor expert from Egbert van Nes. Unfortunately these exceptions do not happen in the GExperts source code but somewhere in the IDE, so even in the debugger I can only see the assembly code in the CPU window. I could also create them sometimes by simply copying and pasting large amounts of code, so I think it is not actually the code formatting that causes the problem but replacing the text of the whole editor file multiple times. There might be some background processing that gets confused by this operation. But I found no reliable way to reproduce them.
  22. GetIt is the package manager built into the Delphi IDE. It can be used in Online and Offline mode. If you installed Delphi from an ISO, GetIt was left in Offline mode. That has some drawbacks: GetIt cannot notify you about new updates or patches as they become available. The “Manage Features” functionality of the IDE won’t work. Unfortunately there is no way to switch GetIt to Online mode in the configuration.The usual way is to run the GetItCmd tool with the switch -c (read on in the blog post)
  23. dummzeuch

    I'm on the Dark Side... no, really!

    Should be fixed now. Not just for this dialog but for all of them.
  24. I have been using 2007 for many years and found it quite stable. Later I switched to 10.2, with only a few projects with XE2 in between. Both were also fine. Since I have got an active subscription, I have tried everything in between and later. I wasn't impressed with 11 and 12. While one of those is necessary if you want to support per monitor DPI, I found the IDEs far from stable, and don't really like using them. So for me it's: Delphi 5 Delphi 7 Delphi 2007 Delphi 10.2 I wouldn't use the first two nowadays any more though.
×