Dynamically insert number on Delphi app's icon - windows

I'm on Delphi 10.4.
I'm looking for a way to dynamically insert a number on the app's icon on the taskbar, so the user can know about how many tasks the apps has done so far. This would be dynamically, as soon as the app does a new task, it will increase the icon's number.
Something like the image below.
Is this possible ?
I don't have any code to post here because i don't have any idea how to do this.

You might not be aware of the TTaskbar taskbar-configuration component and its OverlayIcon property.
Example:
with a very straightforward implementation:
procedure TForm1.btnInfoClick(Sender: TObject);
var
io: TIcon;
begin
io := TIcon.Create;
try
io.Handle := LoadIcon(0, IDI_INFORMATION);
Taskbar1.OverlayIcon := io
finally
io.Free;
end;
end;
In your case, you can either create icons 1.png, 2.png, ... non-programmatically and use those, or you can create icons programmatically (create a CreateOverlayIcon(ANumber: Integer): TIcon function).
I should warn you, however, that the TTaskbar component used to be (very) buggy. Therefore I would not use that one; instead, I would use the ITaskbarList3::SetOverlayIcon API directly.
In any case, my suggestion is to split your problem into two parts:
Create overlay icons.
Use the Windows 7 taskbar overlay icon feature to display these on top of your original icon.

Related

How to manage disable/enable Minimize,Resize and Close button in oracle forms?

i need to manage disable/enable Minimize,Resize and Close button by programming in oracle mdi parent forms in 10g. Please give me solution of this problems. enter image description here
There are plenty of reasons why you might want to prevent a user from being able to resize or close an application's MDI window. A perfect example would be if all the objects in the application are of a fixed size. Being able to resize the parent window would do nothing more than expose unused space. Try running Microsoft Calculator. Notice you cannot resize its window. Preventing users from not resizing certainly isn't uncommon.
So to a solution...
If you were using Forms 12.2.1+, this would be easy. In v12, Forms offers two new parameters; "isResizable" and "alwaysOnTop". Hopefully each are obvious in what they do. Simple set to TRUE or FALSE and your done.
For v11 and older, it becomes a little ugly. I will assume you are using separateFrame=true. For resizing or closing you could create a Java Bean, but that likely would be more effort than it's worth.
In PL/SQL, users attempting to close the parent window (separateFrame window) doing something like the following:
Create an Alert object and name it "PAUSE_EXIT". The alert should include two buttons (e.g. Yes/No).
Create a form level WHEN-WINDOW-CLOSED trigger and add this:
do_key('EXIT');
Create a form level KEY-EXIT trigger and add something like the following. You will have to adapt it to do the right thing in your app. You will need to account for all the "windows" in your module.
DECLARE
al_id Alert;
al_button NUMBER;
BEGIN
IF :System.Event_Window = 'FORMS_MDI_WINDOW' THEN
al_button := Show_Alert('PAUSE_EXIT');
IF al_button = ALERT_BUTTON1 THEN
-- User selected YES, so exit.
EXIT_FORM;
ELSE
-- User selected NO, so don't exit.
RAISE Form_Trigger_Failure;
END IF;
ELSE
-- User attempted to close a form window and not the MDI window
-- Remove NULL and do something else if not the MDI window
NULL;
END IF;
END;
A similar approach could be used to detect if the MDI window has been minimized or resized. Look in the Builder Help for these: SYSTEM.EVENT_WINDOW, GET_WINDOW_STATE, WHEN-WINDOW-RESIZE

How to draw on a TTrayIcon

I'm trying to draw on the canvas of a TTrayIcon but have no success.
I'm programming with Lazarus V1.6.2 on windows 10.
What I tried so far is:
procedure TForm1.TrayIcon1Paint(Sender: TObject);
var
tmpcanvas: TCanvas;
begin
tmpcanvas := TrayIcon1.Canvas;
tmpcanvas := TrayIcon1.Icon.Canvas; // also not working
tmpcanvas.Font.Size := 22;
tmpcanvas.Brush.Color := RGBToColor(255,255,255);
tmpcanvas.FillRect(1,1,200,200);
tmpcanvas.Font.Color := RGBToColor(0,0,0);
tmpcanvas.TextOut(1,1, 'TEST');
end;
I tried this code in the event Form1.OnPaint with the Form1.Canvas and there it works as expected.
But I have no luck with painting on the TTrayIcon.Canvas.
It seems, that drawing on canvas of TTrayIcon is different from drawing on other canvases...
After some debuging I realized, that the TTrayIcon.OnPaint event is never triggered. But even when I force to execute TrayIcon1Paint(..) nothing happens.
Now I am out of ideas. Any help is highly appreciated.
The Windows notification icons do not offer any interface that would match an OnPaint event. I can only imagine that the OnPaint event is intended for use on different platforms.
On Windows notification icons are provided to the system in the form of Windows icon objects. If you wish to change the appearance of your notification icon, you need to provide a new icon object. I'm not familiar with this particular wrapper of the Windows API function, but I would expect that you could write code like this to update the notification icon's appearance:
TrayIcon1.Icon := MyNewIcon;

How to ungroup popup window from the application on the taskbar?

Is it possible to instruct the shell taskbar to exclude a certain hwnd popup window from the main application's button "group"?
I have a "stopwatch" popup window. On my machine, with taskbar button combining disabled, the windows appears exactly as i'd like it: a separate item on the taskbar:
But if the user uses (the default, and most corporations prevent users from altering their personal preferences), the separate window is not visible:
Now, i am using ITaskbarList3.SetOverlayIcon to specify an overlay icon for my popup window:
list: ITaskbarList3;
list := CoTaskbarList3.Create;
list.SetOverlayIcon(windowHandle, ico, '');
so Windows will at least do me the favour of picking the most recent overlay icon, and applying it to the combined visual group - which is nice.
But i'd still prefer to have this separate action in a separate item on the taskbar.
One horrible workaround would be to ship another executable with my application; one just to fool the grouper into putting this other hwnd in its own group. But that's not something i want to do.
Why would i think i'm allowed to do this?
I was surprised to learn that you are allowed to prevent the user from pinning an application to the taskbar.
And while the MSDN page on shell programming doesn't give an example specifically for what i want, that doesn't mean it's not out there. It just might mean that it's all poorly documented.
In my case, the "operator" has a stopwatch. When they start the stopwatch, i pop out the form of the application group by giving it a different User Model Application ID:
SetWindowAppModelUserID('Contoso.Frobber.Stopwatch');
and immediately the form pops out:
When the user stops (or pauses) the stopwatch, i let the window coalesce back into the application:
SetWindowAppModelUserID('');
Caveats
You don't actually set the AppModelUserID to an empty string; that is not a valid application identifer. Instead you set it to VT_EMPTY. My helpful wrapper function checks for '', and converts it into a VT_EMPTY value.
Another warning comes from the SDK:
A window's properties must be removed before the window is closed. If this is not done, the resources used by those properties are not returned to the system. A property is removed by setting it to the PROPVARIANT type VT_EMPTY.
This means that care needs to be taken to remove a custom property applied to an HWND before i destroy it. A somewhat daunting task; one that i will almost certainly screw up.
The Code
function TFormEx.SetWindowAppModelUserID(const AppModelUserID: WideString): HRESULT;
var
ps: IPropertyStore;
value: OleVariant;
const
PKEY_AppUserModel_ID: TPropertyKey = ( fmtid: '{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}'; pid: 5);
begin
Result := SHGetPropertyStoreForWindow(Self.Handle, IPropertyStore, {out}ps);
if Failed(Result) then Exit;
if (ps = nil) then
begin
Result := E_FAIL;
Exit;
end;
if AppModelUserID <> '' then
begin
value := AppModelUserID;
Result := ps.SetValue(PKEY_AppUserModel_ID, PROPVARIANT(value));
end
else
begin
{
A window's properties must be removed before the window is closed.
If this is not done, the resources used by those properties are not returned to the system.
A property is removed by setting it to the PROPVARIANT type VT_EMPTY.
}
value := Unassigned; //the VT_EMPTY type
Result := ps.SetValue(PKEY_AppUserModel_ID, PROPVARIANT(value));
end;
end;
Bonus Reading
What if my application is really two applications bundled into a single file, and I want them collected into two groups on the taskbar in Windows 7?
How do I prevent users from pinning my program to the taskbar?
SHGetPropertyStoreForWindow function
Note: Any code released into public domain. No attribution required.

Windows Vista and 7 motion effects are applied only once when my form is shown. Why?

I created an application with two forms. First one is the main form and second one is hidden.
I placed a button on Form1 and I made it ShowModal the second form. On Win7 the form appears with an animation. Then I close the appeared form (Form2) and I click the button once again. Form2 appears without the animation. I want the animation every time. What should I do?
The only thing I can think of right now is to create the form manually each time you want to display it modally. To do this, go to the project options and make sure that the form isn't automatically created. Then do
procedure TForm1.Button1Click(Sender: TObject);
begin
with TForm2.Create(self) do
try
ShowModal;
finally
Free;
end;
end;
In my opinion, most often modal forms should in fact be created manually.
Well, you could just elect not to worry about it! Alternatively a very quick hack would be to free the form each time it closes since the animation appears to run only on the first time the form is shown.
EDIT: Another approach would be to call DestroyHandle on your form whenever it closes. I'm guessing now, but I imagine that Windows records somewhere in the window a flag indicating that the animation has been shown. Once this flag has been set the animation is never shown again.
As an alternative way it's possible to fool windows by sending a notification that form's style has been changed, that will make windows reset "secret flag" for current form's handle. Thus, on showing already created form the cool show effect animation will be applied again. However, I can't say what negative effects can be caused by doing this way.
uses
Winapi.Windows, Vcl.Controls;
type
TFormHelper = class helper for TForm
public
procedure Show;
end;
implementation
procedure TFormHelper.Show;
begin
SendMessage(Handle,CM_CUSTOMSTYLECHANGED,0,0);
inherited Show;
end;
Note: code featured with a class helper, this feature/keyword might be not available in older IDEs.

Multiple mouse/mice/cursor?

How can I show another cursor for multiple mice?
I have two TMemos, two keyboards which can type into their respective TMemo, 2 mice and I need 2 cursors those.
If hypothetically, I can already detect which mouse is which. How can I make my own cursor to go along with it. (using Delphi)
Possibly along the lines of Multipoint
as an alternative, is there any software which can render more that one cursor. Like CPNMouse?
EDIT:
I found that I can use the mouse_event Function in windows, but I still don't have the visual representation of the cursor.
Cursors are just resources. Here is a good list of the standard cursors that can be used. TControl Defines a cursor property that can be set to the cursor that should be used when over a given control. You can also use Screen.Cursor to control the entire application cursor.
To define a custom cursor you use the following code.
{$R MyCustomCursors.RES}
const
crCustom1 = 1;
crCustom2 = 2;
...
Screen.Cursors[crCustom1] := LoadCursor(hInstance, 'CUSTOM1');
Screen.Cursors[crCustom2] := LoadCursor(hInstance, 'CUSTOM2');
...
Delphi was not designed by default to deal with multiple mouse pointers, but the I suspect most environments are not. The SDK you mention is the only source of information I have seen on using multiple mice at the same time in a single application. It however is .NET only, so using it would require Delphi Prism.
If you want to roll your own support for multiple mice the same trick of using WM_INPUT can can be used. Windows will treat both mice as the same. You will have to do custom painting of the mouse cursor by hand for the second mouse.
Windows doesn't support multiple mouse or keyboards. Since each process have only 1 input queue, Windows treats all similar input devices as the same single device. This can't be changed. End of story. Period.
But even if you can't do this on system wide scale - you still can do this in one particular application. You need to write a special driver and install it for the second mouse only. This driver should not pass mouse movements to usual consumer (input queue), but rather redirect input directly to your application.
You can use a already written drivers - for example, this one or the one, that you've already mentioned.
It can be simulated its action virtually from the original cursor by doing something seamingly fast

Resources