Jump to content

aehimself

Members
  • Content Count

    1059
  • Joined

  • Last visited

  • Days Won

    23

Everything posted by aehimself

  1. aehimself

    Component property disappears from DFM

    Hello all, I have an issue with some of our components in the application we support where an event handler simply disappears (gets unlinked, code stays in .pas) when a frame is opened. The main container is a frame which is the 3rd or 4th descendant of a simple TFrame (with 2-3 levels of visual inheritance included). The event handler is the OnDataChange event of a custom TDataSource descendant component. This frame has ~50 of these datasources, but only 2 are affected. No other datasources / frames have the same issue (which we have hundreds, if not thousands). When you open the file in Delphi, the tab indicator already shows that it is modified and can be saved. Upon saving the event handler is simply unlinked, leaving the actual code in the .pas file. Restoration is easy, just double-click the handler in object inspector so it gets linked back which you can save perfectly... until next time someone forgets to check the modifications and roll back the removals; which already happened at least 5 times in the past half a year. inherited frmCustom: TfrmCustom [...] object dtsMyDTS: TCustomDataSource [...] OnDataChange = dtsMyDTSDataChange <-- this line disappears [...] end [...] end I bet it will be some rare edge case but it already caused lots of headaches and it would be a blessing if it could be fixed. I am not able to share the sources as they are proprietary plus you'd need the whole custom component package as well to be able to open it 🙂 I'm simply looking for indicators, what I can try, what I can check to find the root cause. Anyone saw something like this? Cheers!
  2. aehimself

    Component property disappears from DFM

    Long story short, the issue was in the custom component itself. Someone wanted to have a constant OnDataChange code to run every single time and - as TDataSource is an INSANELY bad component with no overridable methods whatsoever - this is how they solved it: TCustomDataSource = class(TDataSource) protected procedure Loaded; override; private FOnDataChangeDesigned: TDataChangeEvent; end; procedure TCustomDataSource.Loaded; begin inherited; FOnDataChangeDesigned := OnDataChange; OnDataChange := DataChangeDef; end; In the moment the component was successfully streamed (run- or design time) the event handler was "saved" and reset, only to be called from the internal method. But since it's a private method the Object Inspector could not access it, therefore clearing the event handler alltogether. Saving only wrote this inconsistent state back to the disk. And yes, it seems all of the TCustomDataSources were affected, the event handler just disappeared so long ago that noone seemed to realize it. After fixing it and relinking all DataChange events found in the entire application... it seems to be working properly now.
  3. aehimself

    Component property disappears from DFM

    The datasource is on the last frame not on an ascendant (object dtsMyDTS instead of inherited dtsMyDTS). Inheritance only plays a role here if Delphi bugs out due to the long frame chain I think.
  4. aehimself

    Component property disappears from DFM

    By the first look... nothing seems different, that's my issue. The create order is an excellent idea, I'll doublecheck that tomorrow!
  5. aehimself

    Component property disappears from DFM

    Unfortunately I do not remember the 10.4 era, but this definitely happened under Delphi 11.2 and now Delphi 12. The project (and probably this frame) originally was created with Delphi 7 but was slowly upgraded to the most recent version. The source of said component is in Browsing path, Library path points to the precompiled DCU. All frame files (including the first one inherited from TFrame) is a part of the project. We have ~1500 frames with at least 20-50 of these custom datasources on each and this problem only occures on one frame, two datasources (always the same 2). This makes me believe that fixing it won't be something generic - e.g. on component or project level.
  6. Hello everyone, While keeping an eye on other mediums I decided that a post here wouldn't hurt either. As the company I currently work for is going through a leadership change - as the title mentions - I am currently looking for new (remote) opportunities home or abroad. I'm aiming for something long-term in the EU-region and while others are not excluded, some agreement will be needed due to time zone differences. The first time I met Pascal was about 29 years ago. As time progressed I upgraded that knowledge to Delphi and it quickly became the go-to solution for repetative tasks at work. Currently on Delphi 12 but I have hands-on experience with 7 and every minor and major release since Seattle. Currently maintaining a big codebase (~1,5M LOC) plus custom components mostly derived from DevExpress. After getting rid of all the memory leaks I alone converted all this to a 64-bit compatible source and - probably due to my affection towards the language - Delphi version updates became my responsibility as well. Right next to Delphi I'm also using C# and have additional knowledge in T-SQL, C, C++, HTML, JS, CSS, Perl, Assembly and PHP. Being a sysadmin for 13 years I welcome windows batch as an old friend with Bash gaining traction lately. I'm not native but English is not an issue. If anyone knows someone looking for a reliable and passionate Delphi dev just forward the posting to me 🙂
  7. aehimself

    Do not show drag image immediately?

    Hello, I have a pagecontrol descendant, where I overridden the DoDrag method to show the picture of the dragged tab: Procedure TPageControl.DoStartDrag(Var DragObject: TDragObject); Var tab: TRect; bmp, tabbmp: TBitMap; Begin inherited; If DragObject <> nil Then Exit; // Create a bitmap of the tab button under cursor tab := Self.TabRect(Self.ActivePage.TabIndex); bmp := TBitmap.Create; bmp.Canvas.Lock; tabbmp := TBitmap.Create; Try bmp.Height := Self.Height; bmp.Width := Self.Width; tabbmp.Height := tab.Height; tabbmp.Width := tab.Width; Self.PaintTo(bmp.Canvas.Handle, 0, 0); tabbmp.Canvas.CopyRect(tabbmp.Canvas.ClipRect, bmp.Canvas, tab); DragObject := TPageControlExtraDragObject.Create(tabbmp); Finally bmp.Canvas.Unlock; FreeAndNil(tabbmp); FreeAndNil(bmp); End; End; When the user clicks on one of the tabs I'm manually initiating the dragging process by Self.BeginDrag(False);. When I went into BeginDrag, I saw that if you do not specify a dragging threshold, it takes this value from Mouse.DragThreshold, which is 5 pixels. This - to me - means that the dragging is NOT initiated unless the button is still down, and the cursor went at least 5 pixels away from the initiating position. What happens now is that the DoStartDrag event fires immediately, the bitmap is taken and is drawn as a fly-out immediately. Even it I am just switching tabs, which is kind of annoying. So the question is... if my logic is right (and the DoStartDrag should be fired based on distance) why it is firing immediately? If not, is there a simple setting I forgot to add or I manually have to handle this by MouseMove? I'm using Delphi 10.4.1, but the "issue" was present in 10.4 and 10.3 as well.
  8. aehimself

    Adding RecNo/RecCount TPanel to DBGrid

    DataEvent is a method of the link, not the grid itself: Type TMyGridDataLink = Class(TGridDataLink) protected Procedure DataEvent(Event: TDataEvent; Info: NativeInt); Override; End; TDBGrid = Class(Vcl.DBGrids.TDBGrid) protected Function CreateDataLink: TGridDataLink; Override; End; implementation Procedure TMyGridDataLink.DataEvent(Event: TDataEvent; Info: NativeInt); Begin inherited; // Call your public method of (Self.Grid As TDBGrid) to update it's captions // Use Event and Info to make conditions if necessary End; Function TDBGrid.CreateDataLink: TGridDataLink; Begin Result := TMyGridDataLink.Create(Self); End; As for alignment I used a different approach: _ownerpanel := TPanel.Create(Self.Parent); _ownerpanel.Top := Self.Top; _ownerpanel.Left := Self.Left; _ownerpanel.Height := Self.Height; _ownerpanel.Width := Self.Width; _ownerpanel.Anchors := Self.Anchors; _ownerpanel.Align := Self.Align; _ownerpanel.BevelOuter := bvNone; _ownerpanel.Parent := Self.Parent; _ownerpanel.Constraints.Assign(Self.Constraints); _statusbar := TStatusBar.Create(_ownerpanel); _statusbar.Parent := _ownerpanel; _statusbar.SimplePanel := True; _statusbar.ShowHint := True; Self.Constraints.MaxHeight := 0; Self.Constraints.MaxWidth := 0; Self.Constraints.MinHeight := 0; Self.Constraints.MinWidth := 0; Self.Align := alClient; Self.Parent := _ownerpanel; Correct. You can play around your component in runtime but to reflect your changes in design time you will need a component installed in the Delphi IDE itself.
  9. aehimself

    Adding RecNo/RecCount TPanel to DBGrid

    TPanel.Create(TDBGrid(AOwner)); The owner of the grid is usually the container (form, frame, etc). Typecasting to the wrong type might cause access violations - simply leave it out. It's unnecessary. The main difference is how the object will be freed. When passing nil as the owner the object has to be freed up manually. Otherwise, it's automatically freed when the owner is freed. I'd suggest using Self (the grid) as the owner of the panel so you can leave out .Free in the destructor. P.s.: When I made a similar component I think I ended up putting the count update logic to the DataChange event but I have to doublecheck...
  10. That's exactly what I meant. If no exceptions are thrown, the string was successfully converted and the return value will initialize the variable correctly. As the snipplet above contained no Try..Except or Try...Finally blocks it doesn't matter what would use the variable in question afterwards as it never gets executed.
  11. That is correct. All local variables are uninitialized and might contain complete garbage until the first assignment. Without checking the source, StrToFloat has two options: either throw an exception or to return a value. The line after this assignment is only executed if no exception was thrown, therefore the local variable holds an actual value. Therefore, the variable := 0 is unnecessary in this case.
  12. Found it! The code I used could not be more simple... program Project1; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils; function GetTickCount64Emu: UInt64; const KUSER_BASE_ADDRESS = $7FFE0000; //KUSER_BASE_ADDRESS_KERNEL_MODE =$FFFFF78000000000; //in case it is needed begin Result := (PUInt64(KUSER_BASE_ADDRESS + $320)^ * PCardinal(KUSER_BASE_ADDRESS + $4)^) shr 24; end; begin try WriteLn(GetTickCount64Emu); ReadLn; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; end. And it resulted 5283539281 with 61 days, 3.5 hours of uptime on a 32-bit Windows Server 2003 R2:
  13. @Kas Ob. The VM is now at 61 days of uptime. I'm having a bit of trouble compiling an EXE which actually executes on Windows 2003... I remember having to change something somewhere in the IDE / project options. If you know the solution let me know - it might be quicker than me attempting to research.
  14. aehimself

    Need help please..

    This is the unit I use before my application will be updated. It lists the PIDs of instances of the same executable. It's not exactly what you need but with a small modification you can get it to work. CommandLineParameters (in uCommandLineParameters) is a singleton with easy access to general command line information... you safely can throw it out from your version. Unit uOtherInstances; Interface Uses System.SysUtils; Procedure TerminateOtherInstances; Function OtherInstances: TArray<Cardinal>; Implementation Uses WinApi.Windows, WinApi.TlHelp32, uCommandLineParameters; Type PTOKEN_USER = ^TOKEN_USER; Function GetUserAndDomainFromPID(inPID: Cardinal; Var User, Domain: String): Boolean; Var phandle, hToken: THandle; cbBuf: Cardinal; ptiUser: PTOKEN_USER; snu: SID_NAME_USE; UserSize, DomainSize: DWORD; bSuccess: Boolean; Begin Result := False; phandle := OpenProcess(PROCESS_QUERY_INFORMATION, False, inPID); If phandle = 0 Then Exit; // EnableProcessPrivilege(ProcessHandle, 'SeSecurityPrivilege', True); Try If Not OpenProcessToken(phandle, TOKEN_QUERY, hToken) Then Exit; Try bSuccess := GetTokenInformation(hToken, TokenUser, nil, 0, cbBuf); ptiUser := nil; While Not bSuccess And (GetLastError = ERROR_INSUFFICIENT_BUFFER) Do Begin ReallocMem(ptiUser, cbBuf); bSuccess := GetTokenInformation(hToken, TokenUser, ptiUser, cbBuf, cbBuf); End; Finally CloseHandle(hToken); End; If Not bSuccess Then Exit; Try UserSize := 0; DomainSize := 0; LookupAccountSid(nil, ptiUser.User.Sid, nil, UserSize, nil, DomainSize, snu); If (UserSize = 0) Or (DomainSize = 0) Then Exit; SetLength(User, UserSize); SetLength(Domain, DomainSize); If Not LookupAccountSid(nil, ptiUser.User.Sid, PChar(User), UserSize, PChar(Domain), DomainSize, snu) Then Exit; Result := True; User := StrPas(PChar(User)); Domain := StrPas(PChar(Domain)); Finally FreeMem(ptiUser); End; Finally CloseHandle(phandle); End; End; Function ProcessBelongsToUser(Const inPID: Cardinal; Const inUser: String): Boolean; Var domain, user: String; Begin Result := GetUserAndDomainFromPID(inPid, user, domain) And (user = inUser); End; Function OtherInstances: TArray<Cardinal>; Var len: DWord; user, exe: String; success: Boolean; psnapshot: THandle; pe: TProcessEntry32; currentpid: Cardinal; Begin exe := CommandLineParameters.ExeName.ToLower; currentpid := GetCurrentProcessId; len := 256; SetLength(user, len); If Not GetUserName(PChar(user), len) Then RaiseLastOSError; SetLength(user, len - 1); user := user.ToLower; SetLength(Result, 0); psnapshot := CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0); Try pe.dwSize := SizeOf(pe); success := Process32First(psnapshot, pe); While success Do Begin If (pe.th32ProcessID <> currentpid) And (String(pe.szExeFile).ToLower = exe) And (CommandLineParameters.Portable Or ProcessBelongsToUser(pe.th32ProcessID, user)) Then Begin SetLength(Result, Length(Result) + 1); Result[High(Result)] := pe.th32ProcessID; End; success := Process32Next(psnapshot, pe); End; Finally CloseHandle(psnapshot); End; End; Procedure TerminateOtherInstances; Var pid: Cardinal; phandle: THandle; Begin For pid In OtherInstances Do Begin phandle := OpenProcess(PROCESS_TERMINATE, False, pid); If phandle = 0 Then RaiseLastOSError; Try TerminateProcess(phandle, 1); Finally CloseHandle(phandle); End; End; End; End.
  15. Give me a couple of days: I'll let the admin know NOT to touch either this one or the host 🙂
  16. aehimself

    Issue With TForm.AlphaBlend and AlphaBlendValue

    You also can use TDimPanel: Blocking the access would simply require you to set .Visible to True, plus you can cover only parts of your window as well.
  17. RSS-1824 was already open about this issue . No solutions, no workarounds yet. Just fyi.
  18. aehimself

    Parsing a json file

    I had to fire up my dev machine so I did a small test for you. The following code can be simplified a lot but at least it's easy to see what's going on: procedure TForm1.Button1Click(Sender: TObject); Var fulljson, group1, items: TJSONObject; enumpair: TJSONPair; begin fulljson := TJSONObject(TJSONObject.ParseJSONValue(Memo1.Lines.Text)); If Not Assigned(fulljson) Then Exit; Memo2.Lines.Add('JSON parsed successfully.'); group1 := TJSONObject(fulljson.GetValue('Group1')); If Not Assigned(group1) Then Exit; Memo2.Lines.Add('Group1 found!'); For enumpair In group1 Do Begin Memo2.Lines.Add('Found ' + enumpair.JsonString.Value + ' under Group1'); items := TJSONObject(enumpair.JsonValue); Memo2.Lines.Add('ImgHot: ' + items.GetValue<String>('ImgHot')); Memo2.Lines.Add('ImgNormal: ' + items.GetValue<String>('ImgNormal')); Memo2.Lines.Add('ImgChannel: ' + items.GetValue<String>('ImgChannel')); Memo2.Lines.Add('Caption: ' + items.GetValue<String>('Caption')); End; It successfully walks through your JSON file:
  19. aehimself

    DelphiLSP.Exe version 11.1 vs 12.2

    The 64 bit DelphiLSP simply hangs on my mid-sized project, just spins the progress bar over and over again, still saying 0% is done. 32 bit works fine on the same project, performance feels about the same as in 12.1. This is from the 12.2 document, fyi work on most symbols, sometimes resolves 🙂 Unfortunately yes, LSP needs some work to be actually good. Ctrl-click often doesn't work, jiggly lines at wrong places, errors in editor but project compiles... It can be lived together with if you already got used to Delphi's quirks 🙂
  20. aehimself

    Parsing a json file

    I don't know if it was included in Delphi 10.1 or it came later, but you can use TJSONObject in the System.JSON unit. You'll find plenty of examples to get you started on how to process your specific document.
  21. That was my first guess. Flickering is still present even if it's off.
  22. I'm only asking because the quick peek I took at Delphi 12.2 until now showed the same symptom. And I'm using RDP to access the machine Delphi is installed on, too.
  23. @Clément Are you accessing Delphi through MsTSC?
  24. aehimself

    Up-to-date 32 bit libmysql.dll?

    In the prehistoric times, you could download the MySQL C library from their website. Then they changed to the installer-type (download installer, select Connector-C, install 32 bit, copy file, uninstall 32 bit, install 64 bit copy file, uninstall everything). Now it's even worse. The installer now offers only 6.1.11, but you still can have the latest by downloading MySQL server and copying the file from the Lib folder. My 64 bit Delphi apps are using it happily; but that's only 64 bit, and there's no 32 bit version of MySQL anymore. The question is: is there a way to get the latest (currently 8.0.18) libmysql.dll in 32 bits? P.s.: I know that libmariadb is a drop-in replacement but I'd prefer the original if possible somehow / somewhere.
  25. aehimself

    Up-to-date 32 bit libmysql.dll?

    Both of libmysql.dll-s in HeidiSQL's bundle seems to have the PE L header, suggesting they are indeed 32-bit: I'll check on them later if they work properly. It would be nice to know the source of these but I have doubts they are official.
×