

PeterBelow
Members-
Content Count
549 -
Joined
-
Last visited
-
Days Won
13
Everything posted by PeterBelow
-
I don't think that ever existed. If it did it would be completely useless since the actual variables you pass to a function call are rarely (in my case never ) named the same as the parameters in the function declaration.
-
You never told us which Delphi version you are using. If it has a System.Ansistrings unit: that contains a number of routines to work with ansistrings. Use the AnsiPos function to search for a character or substring; it returns the index of the found item. Use AnsiMidStr to extract a range of characters from an Ansistring (or the good old Copy function, it has an overload for Ansistrings).
-
Routine to check if set of dates match
PeterBelow replied to david_navigator's topic in Algorithms, Data Structures and Class Design
Since you only need to be precise to the minute do not store TDatetimes but multiply the values by 60*24 and truncate the result to give an integer (perhaps an int64, you could reduce the range necessary by subtracting a suitable reference date first, e.g. EncodeDate(2020,1,1)). This gives you the number of minutes from the reference date. Store these into a TList<integer>. To calculate a hash use the list's ToArray method to get an array you can feed to a suitable hash algorithm from the System.Hash unit. -
Am I using threads correctly?
PeterBelow replied to AlexQc's topic in Algorithms, Data Structures and Class Design
It is working in this case since TListboxStrings.Add (TListboxStrings is the TStrings descendant behind TListbox.Items) does indeed send a message (LB_ADDSTRING) to the control, and the control is visible on the form. But you should not rely on such implementation details when working in a background thread. Using Synchronize the pattern would be something like this: Synchronize( procedure begin Buffer.Add(LCurrentFile); end); where LCurrentfile is the local variable holding the filename to add to the listbox. The code goes inside your find loop. -
Am I using threads correctly?
PeterBelow replied to AlexQc's topic in Algorithms, Data Structures and Class Design
I see a few problems with your code. In general you cannot access UI controls from a background thread, but you pass ListBoxPrograms.Items as the Buffer parameter to the thread's constructor. This can work if the Add method of ListBoxPrograms.Items is implemented by sending a message to the listbox control, since the OS makes sure a message is delivered in the thread that created the control's window handle. On the other hand the VCL creates a control handle on an as needed basis, and if the ListBoxPrograms.Handle has not been created yet when the thread tries to add the first item the handle would be created in the background thread context, which would not work since this thread has no message loop. So: Always access UI controls only in a Synchronized or Queued method! You did not show code for the ListFilesDir method, so perhaps you are doing that already. The second point to investigate is how to safely interrupt the thread's work if it has to be killed before it has completed its work. The TThread Destructor calls Terminate and then waits for the thread to die gracefully (by leaving the Ececute method). For this to work as expected the thread's work loop has to check the Terminated property on each round and exit directly if it is true. Again this is something you would do in ListFilesDir. Then there is the question of error handling in the thread's work loop. The usual pattern is to wrap the whole body of the Execute method in a try except block and either pass a trapped exception to the main thread for reporting to the user via a Synchronized method (not a queued one!), or use the Windows.MessageBox function to report it directly. That API is thread-safe, while the VCL.Dialogs methods are not. -
Debugging Issues in D11 64Bit with Packages
PeterBelow replied to MathewV's topic in Delphi IDE and APIs
I have not been working with DLL projects much in the past and never with 64 bit DLLs, but usually one had to debug the DLL project, set the host application to use in the Run -> Parameters dialog, set a breakpoint in the DLL funtion of interest, and then just run. Do the required actions in the host to end up in the DLL at the breakpoint. If you end up in the CPU view this means that the debugger cannot find the debug information for the code you stepped into. Make sure you build the DLL with debug information. 64-bit apps are debugged in a kind of remote debugger session since the IDE is a 32 bit process. So make sure you have enabled "include remote debug symbols" in the linker options. -
Using translations in unit Consts with Delphi 10.4 VCL
PeterBelow replied to Dirk Janssens's topic in VCL
-
If I only could; McAfee rermoved that ability some years ago, one can only exempt specific EXEs now, and that is automatically removed if the EXE changes. I would not recomment McAfee for developer PCs for this reason, although it is a good product otherwise, IMO (a bit pricey, though). I can live with it since I don't program for a living and these false detections are rare.
-
Using translations in unit Consts with Delphi 10.4 VCL
PeterBelow replied to Dirk Janssens's topic in VCL
Definitely. It will also not work if you build your project with runtime packages. -
Can't you read it one byte at a time? I'm not familiar with the component you use.
-
I had a similar problem with Delphi Alexandria, McAfee would detect a freshly build Win32 debug EXE as virus and quarantine it before I could debug it under the IDE, but it would not flag the 32 bit release version of the same program and neither 64 bit debug or release versions. By the way: to send an EXE through a mail server put it into a ZIP file and password-protect that. The encryption done will make a virus scanner ignore it since it cannot identify the zipped file as executable. Some particularly paranoid mail servers will reject password-protected zip files for this reason, though.
-
You can use the OnDrawCell event to draw the cell content yourself any way you like. The stringgrid.Canvas has a TextRect method that supports aligning the text in the way you want.
-
Async await with blocking mode using Application.ProcessMessage(var Msg: TMsg)
PeterBelow replied to Nasreddine's topic in VCL
Here is an example from my old threading library code. FSignal is a TSimpleEvent the thread will signal when it has finished its work. {! Wait for the call to complete. Optionally we can process a subset of messages during the wait. That complicates the timeout handling, though, since the wait can be interrupted by messages.} function TAsyncCall.WaitForCompletion(TimeoutMSecs: Cardinal; ProcessMessages: Boolean): TWaitResult; var TargetTime, CurrentTime: int64; H: THandle; Ret: DWORD; function TimeRemaining: DWORD; begin if TimeoutMSecs = INFINITE then Result := INFINITE else begin CurrentTime := ToInt64(GetTickCount()); if CurrentTime > TargetTime then Result := 0 else begin Result := TargetTime - CurrentTime; if Result > TimeoutMSecs then Result := 0; // GetTickCount rolled over end; end; end; {! We want to block most user input here but allow paint messages to be processed and also non-client messages that relate to moving or minimizing the window to be acted upon. Timer messages are also processed! } procedure ProcessPendingMessages; var Msg: TMsg; const NSCMask = $FFF0; begin while PeekMessage(Msg, 0, 0, 0, PM_REMOVE) do case Msg.message of WM_KEYFIRST..WM_KEYLAST, WM_MOUSEFIRST..WM_MOUSELAST: ; // swallow WM_NCMOUSEMOVE..WM_NCLBUTTONDBLCLK: case Msg.wParam of HTCAPTION, HTMINBUTTON: DispatchMessage(Msg); end; {case} WM_SYSCOMMAND: case Msg.wParam and NSCMask of SC_MINIMIZE, SC_RESTORE: DispatchMessage(Msg); end; {case} else DispatchMessage(Msg); end; {case} end; begin EnsureSignalIsCreated; if FCompleted then Result := wrSignaled else if ProcessMessages then begin TargetTime := ToInt64(GetTickCount()) + TimeoutMSecs; H:= FSignal.Handle; Result := wrAbandoned; repeat Ret := MsgWaitForMultipleObjectsEx( 1, H, TimeRemaining, QS_ALLINPUT, 0); case Ret of WAIT_ABANDONED : Exit; WAIT_FAILED : Result := wrError; WAIT_TIMEOUT : Result := wrTimeout; WAIT_OBJECT_0 : Result := wrSignaled; WAIT_OBJECT_0+1: ProcessPendingMessages; end; {case } until Result <> wrAbandoned; end {if} else Result := FSignal.WaitFor(TimeoutMSecs); end; -
If the OnScroll event of the control is not sufficient for your need you have to subclass the control using its WindowProc property. Here is a short example using a TListbox filled with enough items to show a scrollbar as victim. The form also needs a TMemo to show the message traced. Note a few things regarding VCL subclassing: You need to find a place where the control you want to subclass has been created and that will only execute once during form creation. I used an overloaded Loaded method. The subclassing should be undone before the form is destroyed. A good place for that is an overloaded BeforeDestruction method. The replacement windowproc must pass all unhandeled messages to the original or the control will stop working. Usually one also passes the message one wants to handle to the original proc, perhaps with modified message parameters. type TMainform = class(Tform) ListBox1: TListBox; Memo1: TMemo; private FListWndProc: TWndMethod; procedure NewListboxProc(var Message: TMessage); protected procedure Loaded; override; public procedure BeforeDestruction; override; end; .... function GetScrollCodeAsText(aScrollcode: Smallint): string; begin case aScrollcode of SB_LINEUP: Result := 'SB_LINEUP'; SB_LINEDOWN: Result := 'SB_LINEDOWN'; SB_BOTTOM: Result := 'SB_BOTTOM'; SB_ENDSCROLL: Result := 'SB_ENDSCROLL'; SB_PAGEUP: Result := 'SB_PAGEUP'; SB_PAGEDOWN: Result := 'SB_PAGEDOWN'; SB_THUMBPOSITION: Result := 'SB_THUMBPOSITION'; SB_THUMBTRACK: Result := 'SB_THUMBTRACK'; SB_TOP: Result := 'SB_TOP'; else Result := 'unknown'; end; end; procedure TMainform.BeforeDestruction; begin if Assigned(FListWndProc) and Assigned(ListBox1) then Listbox1.WindowProc := FListWndProc; inherited; end; procedure TMainform.Loaded; begin inherited; if Assigned(ListBox1) then begin FListWndProc := Listbox1.WindowProc; Listbox1.WindowProc := NewListboxProc; end; end; procedure TMainform.NewListboxProc(var Message: TMessage); begin try if Message.Msg = WM_VSCROLL then begin memo1.Lines.Add( Format('Scroll code: %d (%s), position: %d', [TWMVScroll(Message).ScrollCode, GetScrollCodeAsText(TWMVScroll(Message).ScrollCode), TWMVScroll(Message).Pos ])); end; finally FListWndProc(Message); end; end; A click on the scrollbar thump (still in the top position) results in three messages: Scroll code: 5 (SB_THUMBTRACK), position: 0 Scroll code: 4 (SB_THUMBPOSITION), position: 0 Scroll code: 8 (SB_ENDSCROLL), position: 0
-
OnMessage only triggers for posted messages (PostMessage), but WM_VSCROLL is send (SendMessage). Using an OnSCroll event, if the control offers one, is the preferred way, though.
-
Yes, in a VCL control, at least. The control wll receive WM_VSCROLL messages when the user manipulates the scrollbar. The message parameters tell you what has happened.
-
Have you tried to check "Select shortest matching symbol"?
-
The position of the submenus is controlled by Windows (assuming we are talking about a VCL app), by default it pops up on the right side, unless there is insufficient space available on the screen on that side. I don't know of a way to control that. What you could do is to implement each submenu as a separate TPopupMenu and pop it up manually from the OnClick event of the "parent" menu item. Unfortunately it is not trivial to determine the screen position of an open menu item...
-
With my Delphi 10.4 Version 27.0.37889.9797 (Professional) it is found under File->New->Others, Delphi projects, Web:
- 6 replies
-
- delphi 10.4 ide
- xml data binding
-
(and 1 more)
Tagged with:
-
Class properties: Wins prettyness over functionality ?
PeterBelow replied to Rollo62's topic in Algorithms, Data Structures and Class Design
Modelmaker CodeExplorer (MMX) offers that, and a lot of similar stuff for quickly adding methods etc. And it's free now. Could not live without it... -
Windows is not a real-.time OS, so you don't have any guarantee for defined thread execution times, and your program has to share the CPU resources with a few dozen OS processes. Anyway, your problem sounds like you flood your UI thread's message queue with update requests (you do Synchronize these request, I hope, and do not execute the background task's work in a syncronized method). These requests have a higher priority than the paint messages your changes to the UI cause to be added to the queue. If adding calls to a method like procedure ProcessPaintrequests; var Msg: TMsg; begin while PeekMessage(Msg, 0, WM_PAINT, WM_PAINT, PM_REMOVE) do DispatchMessage(Msg); while PeekMessage(Msg, 0, WM_NULL, WM_NULL, PM_REMOVE) do DispatchMessage(Msg); end; does not fix the problem you have to lower the priority of your worker threads to give the main thread more time to update the UI.
-
Is there any "standard protocol" for recovery from a failure in non atomic operations?
PeterBelow replied to roPopa's topic in Algorithms, Data Structures and Class Design
A kind of transaction log saved to local storage (a file) may serve your purpose. You can write entries to a file using a write followed by a flush operation (or a full open - write - close cycle) . While not very fast it will ensure the entry is either written completely or not all (if the PC suffers a power failure, for example). Your operation would then follow this scheme: Write the intent to print, with the ID of the item to print, to the log print the item write the success of the operation to the log save it to the database write an end of transactio to the log or delete the log On (re)start the program can then look for a transaction log and analyse it to see how far it got on the last run. -
At least one of the examples is on github: https://github.com/gustavomenabarreto/delphicon2021 Perhaps you can find more in the replays on Youtube: DelphiCon 2021 Playlist It's probably up to the speakers to make the code for their talk available somewhere...
-
Presednce of operations...
PeterBelow replied to Mark-'s topic in Algorithms, Data Structures and Class Design
In this case it is, but one should never make assumptions about in which order the parts of a complex expressions are evaluated. It may even change depending on compiler flags, e.g. optimization on or off, stack frames on or of, range and overflow checks. -
Set the Capacity property of your list objects to a suitably high value before you start adding objects, that can greatly improve performance since it cuts down cases where the list has to grow its internal array.