How to add multiple tray icons in the same application (winapi)? - c++

It is possible for an application to have more than one tray icon? (kind of like thunderbird does: one for the main application and another when you receive an email and there's an envelope in the notification area)
I tried using ShellNotify_Icon twice in a row but simply return FALSE the second time.
I've also tried using two different NOTIFYICONDATA structures but still nothing. It just adds one.
I haven't been able to find anything in the documentation or on google saying if this is possible or not.
Any ideas?

Related

SHGetFileInfo performance issues

Here is an excerpt from the Windows documentation about the SHGetFileInfo() function:
You should call this function from a background thread. Failure to do so could cause the UI to stop responding.
Does this apply to extracting the folder icons as well?
One of our applications resembles Windows Explorer, and we pursue two antagonistic goals: to support as many Windows Explorer's features as possible, and to be as fast as possible. Having the latter in mind, I assigned to each folder the default icon (obtained with the help of the SHGFI_USEFILEATTRIBUTES flag). But after some time it turned out, that a few of our customers use custom folder icons.
So, should I create new threads to calculate the icon for each folder, or is there a way to quickly extract a folder icon in the main thread, given the fact that the number of custom folder icons is negligible?
For example, a way to retrieve only cached icons could be a solution, I think. There is a function IShellItemImageFactory::GetImage(), which allows to obtain only cached icons, but it unfortunately returns HBITMAP instead of HICON.
It seems that I found an appropriate solution.
First of all, I prepare and store a pair containing the default folder icon and its index in the system image list. Then, when the request for a folder icon arrives, I immediately return the default icon, and launch a thread from the Windows thread pool.
In the launched thread I calculate the actual folder icon and its index with the help of the SHGetFileInfo API. If the index is the same as index of the default icon, I destroy the icon. Only if the obtained index differs from the default icon index, I post notification to the control in the main thread.
In this way the control is notified only about folders that really have custom icons, and the main thread is not overburdened with redundant notifications.

Sending a message between two separate applications

Hi,
I'm relatively new to c++ and software development in general, so I hope I can explain clearly my question.
I need two apps, one that listens the keyboard for a combo key press, and one that executes a function when that combo was pressed. I can't make them in a single app, because I'm trying to build something that resembles a kyosk, that when launched, starts a new desktop with limited functionality, and when a combo is detected, the original desktop is switched back. So, what I did, is launch this keyboard hook in the new desktop using CreateProcess, launch a new explorer.exe using the same function and switch to the new desktop.
I was doing some reading about Messages and Message Queues and I found out that this is a way to communicate between threads. So I was wondering if I could create my own Queue, put a message there at the combo key press, and periodically interogate this queue from another process, to make the necessary changes. If possible, could you post a link, or a code sample.
Thanks

Multiple consoles for a single application C++

Is it possible to create two console windows (one being the main) and the secondary being a pop-up like a message box in Windows Forms?
I only want the secondary console window to hold IDs (that will be hard coded into the application) So the user does not have to keep returning to the main menu to check available IDs
If so how would you go about it?
Many Thanks
Yes, you can do it.
The solution is actually very simple - our process can start a new helper child-process, so the helper process will display whatever our process sends it. We can easily implement such a solution with pipes: for each new console (that I'll call logger), we'll open a pipe, and execute a Console-Helper application - the role of this application is very simple, it will print everything sent through the pipe. Check out this article Multiple consoles for a single application for details (contains the source code).
In the code, it implement a console class CConsoleLogger, then you can create multiple console windows like:
CConsoleLogger another_console;
another_console.Create("This is the first console");
another_console.printf("WOW !!! COOLL !!! another console ???");
And you will get something like:
Take a look at http://msdn.microsoft.com/en-us/library/windows/desktop/ms682528(v=vs.85).aspx for instructions for creating a console window.
Nop
A process can be associated with only one console.
AllocConsole

can I set the AppUserModelID of an arbitrary process launched through a jumplist?

I have a simple console application written in C++ that acts as a stub for launching another application through it's jumplist. Purpose is to add jumplist abilities to applications that do not support this. Call it stub.exe. When running stub.exe it creates a custom jumplist using these steps (taken right form the MS samples):
create an ICustomDestinationList
ICustomDestinationList::BeginList()
create an IObjectCollection
for_each item_to_add
create an IShellLink, set its path/arguments/title/icon
add IShellLink to the IObjectCollection
get the IObjectArray interface from the IObjectCollection
call ICustomDestinationList::AddUserTasks( IObjectArray interface )
ICustomDestinationList::CommitList()
When pinning stub.exe to the taskbar and right-clicking it, the jumpilst appears and it contains all IShellLinks added. When clicking an item, it will launch the corresponding process.
Now I'd like a process launched through this jumplist have it's window(s) grouped under stub.exe's taskbar icon, instead of having it's own group. They key to get this working seems to be the AppUsermodelID. This is what I tried so far:
just for testing, create a couple of shortcuts and set the id through IPropertyStore->SetValue( PKEY_AppUserModel_ID, "id" ). Indeed, when launching these shortcuts, they will all group under the same taskbar icon.
since the shortcuts do what I want, I tried adding shortcuts to stub.exe's jumplist: no effect. The shortcuts don't even show up in the jumplist (maybe one cannot have a shortcut to a shortcut?), yet all methods return S_OK
setting the PKEY_AppUserModel_ID on each of the IShellLinks that get added to the jumplist: no effect
calling ICustomDestinationList->SetAppID(): no effect
instead of using SubTasks, tried with SHAddToRecentDocs: no effect. The recent doc list does not show up. But now things get messy. After setting the AppUserModelID on the shortcut that is responsible for the pinned taskbar item (the one in %APPDATA%/Roaming/Microsoft/Internet Explorer/Quick Launch/User Pinned/TaskBar), the jumplist changed: it does not show the 'Tasks' item anymore, but does show 'Recent' and the items I added using SHAddToRecentDocs. Now when clicking them I get a dialog box with a title that starts with 'd:\desktop' followed by Chinese characters. Hovering the items in the jumplist also shows Chinese characters instead of the descirption I set.
Questions:
What's with the Chinese characters in the jumplist?
How come setting the app id on the taskbar shortcut toggles between 'Tasks' and 'Recent' sections, why are they not both there?
What would be the way, if even possible, to achive what I actually want: a custom jump list of which the items launched will group under it's taskbar icon? (note that the processes I plan to laucnh their do not have their app id set currently)
not much reactions here ;]
In the meantime I managed to solve the main problem myself; it's not quite a straightforward solution but it fullfills the requirements: a program runs in the backround and installs a CBT hook. Each time an application creates a window (HookProc code = HCBT_CREATEWND), the hook checks the application's path against a map containing paths and desired application ids. If a match is found, the application id of the HWND is set. Since this occurs before the window is actually shown and is combined with the custom task list, from a user's point of view the application behaves just like one that does support a recent/pinned document list.

Closing a MessageBox automatically

I have a third party encryption library, which may create a MessageBox if key creation fails. The failure can be caused by bad random number generation or other rarities, and in most cases, trying again will result in success. My code will attempt key creation up to three times before deciding it failed.
Now, the issue is that the program may be used with automation. If a MessageBox is created during automation, it will block the process forever, because there's nobody to click the 'OK' button.
Does anyone know of a way to catch when this message box is created and automatically close it?
Anything is fair game, as long as it's not something that will make security suites angry. This means no hooking or code tunneling.
In summary, I need to catch when a MessageBox is created and close it. The MessageBox's creation is outside of my control. Modifying the code at runtime is not acceptable.
Also, I've noticed there are some other similar questions, but they don't have the same requirements.
EDIT: Additional note, I can find the message box via searching through all windows until I find one with a matching title and then send it a WM_CLOSE message, but I don't think this is a great solution. I also have no guarantee that the message box has been/will be displayed, or how long after my call it will be displayed. It could display instantly, it could display 1200 ms later, or it could not display at all.
Just before you begin the encryption process, install a WH_CBT hook, and in its callback watch for an nCode of HCBT_CREATEWND. If you get a matching class name ('#32770 (Dialog)' ?) and a matching title either return a nonzero value from the callback, or if that doesn't work post a WM_CLOSE (or a BM_CLICK to a relevant button if selecting an option is necessary). Uninstall the hook after the process for not messing with every possible dialog your application pops up.
That sounds like bad design on the part of that library. Generally any sort of utility library (like encryption) has no business invoking any kind of GUI (unless you explicitly ask it to).
Is there possibly some configuration or setting in this library that could disable its use of message boxes?
If not, I'd suggest that you might want to investigate using a different library. After all, if the designers of this library have already made this kind of poor design decision once, then there may be other unfortunate surprises lurking in there.
You can hope that it will be found by GetForegroundWindow, but this may catch other applications. The more brute force way is to iterate over all windows with EnumWindows looking for something that has a caption or text equal to this shown by the library.
I have once "remote controlled" an application by sending mouse click events to some controls. I guess you would have to do this in a separate thread that is watching for Events if a window is opened. Pretty ugly but working...
Create a new thread. If your function fails and a Message Box is opened, obtain a handle to the message box by looping through the windows (GetTopWindow, GetNextWindow) and comparing the window's process id to the one returned from GetCurrentProcessId().
Or, you can avoid all the hard work and just hook the MessageBox API with detours. It's not very hard, and if you don't want to pay for detours, you can do it manually.
Call VirtualProtect and set the memory protection at MessageBox at PAGE_EXECUTE_READWRITE
Create a naked function, and use it as a trampoline.
Create a function identical in parameters to MessageBox (this will be your hook)
Create a jump from MessageBox to your hook function.