-
Content Count
1059 -
Joined
-
Last visited
-
Days Won
23
aehimself last won the day on June 10
aehimself had the most liked content!
Community Reputation
399 ExcellentTechnical Information
-
Delphi-Version
Delphi 12 Athens
Recent Profile Visitors
The recent visitors block is disabled and is not being shown to other users.
-
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.
-
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.
-
By the first look... nothing seems different, that's my issue. The create order is an excellent idea, I'll doublecheck that tomorrow!
-
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.
-
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!
-
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 🙂
-
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.
-
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...
-
Double, default value
aehimself replied to Skrim's topic in Algorithms, Data Structures and Class Design
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. -
Double, default value
aehimself replied to Skrim's topic in Algorithms, Data Structures and Class Design
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. -
Help needed in testing emulated GetTickCount32/64
aehimself replied to Kas Ob.'s topic in Algorithms, Data Structures and Class Design
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: -
Help needed in testing emulated GetTickCount32/64
aehimself replied to Kas Ob.'s topic in Algorithms, Data Structures and Class Design
@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. -
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.
-
Help needed in testing emulated GetTickCount32/64
aehimself replied to Kas Ob.'s topic in Algorithms, Data Structures and Class Design
Give me a couple of days: I'll let the admin know NOT to touch either this one or the host 🙂 -
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.