-
Content Count
1053 -
Joined
-
Last visited
-
Days Won
23
Everything posted by aehimself
-
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.
-
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.
-
Delphi 12.2 code editor blinks for every key I press
aehimself replied to Clément's topic in Delphi IDE and APIs
RSS-1824 was already open about this issue . No solutions, no workarounds yet. Just fyi. -
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:
-
DelphiLSP.Exe version 11.1 vs 12.2
aehimself replied to Gert Scholten's topic in Delphi IDE and APIs
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 🙂 -
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.
-
Delphi 12.2 code editor blinks for every key I press
aehimself replied to Clément's topic in Delphi IDE and APIs
That was my first guess. Flickering is still present even if it's off. -
Delphi 12.2 code editor blinks for every key I press
aehimself replied to Clément's topic in Delphi IDE and APIs
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. -
Delphi 12.2 code editor blinks for every key I press
aehimself replied to Clément's topic in Delphi IDE and APIs
@Clément Are you accessing Delphi through MsTSC? -
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.
-
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.
-
Seems to be like encoding. Make sure that encoding is set properly, and also if the text gets scrambled at logging or not (check .AsBytes property and verify if value is a valid UTF8 / UTF16 / ANSI string)
-
ANN: Better Translation Manager released
aehimself replied to Anders Melander's topic in Delphi Third-Party
@Anders Melander Is an auto-update feature planned for BTM in the future? That, and a filter to only show untranslated and/or changed entries would make BTM a perfect tool imo. Thank you very much for it! -
VCL or CLX? How do I know what type of application I'm designing in Delphi 7. I'm a beginner.
aehimself replied to Miguel Jr's topic in Delphi IDE and APIs
Unsupported definitely. But dead...? I hear it's the go-to version for lots of legacy codebases. -
Parsing Json to retrieve nested record
aehimself replied to bzwirs's topic in Network, Cloud and Web
recenum and tubeenum are initialized automatically by Delphi during the For .. In ... cycle. You don't need to "obtain" them. Similar to: Var stringarray: TArray<String>; stringenum: String; Begin [...] // stringenum is "uninitialized" at this moment For stringenum In stringarray Do // stringenum is now initialized and contains the next element in the array [...] In the original snipplet values are being assigned at: For recenum In records Do Begin [...] For tubeenum In tubes Do -
Is there a way to check is the "user Idle" (no interaction)
aehimself replied to Tommi Prami's topic in Windows API
Nice insights! I'll make some updates once I managed to set my dev VM up (I'm in the middle of switching to Linux on my daily driver atm...) -
Is there a way to check is the "user Idle" (no interaction)
aehimself replied to Tommi Prami's topic in Windows API
I have a component which detects and attempts to "break" the idle status. https://github.com/aehimself/AEFramework/blob/master/AE.Comp.KeepMeAwake.pas Works fine even in remote desktop connections.