Proper Way of Handling GUID used by Windows NotificationIcons - winapi

The Microsoft Documentation reads:
Notification icons specified with a GUID are protected against spoofing by validating that only a single application registers them. This registration is performed the first time you call Shell_NotifyIcon(NIM_ADD, ...) and the full path name of the calling application is stored. If you later move your binary file to a different location, the system will not allow the icon to be added again. Please see Shell_NotifyIcon for more information.
Since the documentation on Shell_NotificyIcon is rather sparse on how to unregister the GUID again, the following question arises: How do I properly remove the NotificationIcon again when I uninstall the corresponding app again?
There is the brute force approach which is described here, which deletes all system icons and the process explorer.exe must be restarted again. However I'm wondering if there exists more punctual approach.
Another option would be to just create a new GUID, every time a user installs the application or moves it to a new location. Is this considered best practice?

10 year old answer from a Microsoft employee speaks of a possible workaround when changing the path and at the same time claims there is no way to unregister:
There is no way provided to unregister that. If your binaries are Authenticode signed then the registration can move with the application. See the Troubleshooting section in the NOTIFYICONDATA documentation.
Note The only exception to a moved file occurs when both the original and moved binary files are Authenticode-signed by the same company. In that case, settings are preserved through the move.
Both binaries would need to be present simultaneously when the icon is created for the path to be updated.
I personally never use a GUID, I just use the classic ID mode from Win95.

Related

Updated MATLAB app installs as a new unique app

Some time ago, we distributed a toolbox to our users via the MATLAB App Packager, to make it easier to provide future updates, without users having to handle search paths. Now, we wish to distribute an updated version. Usually, re-packaging the toolbox should make a new .mlappinstall file, which asks the user to upgrade. Instead, MATLAB now considers the new version of the app as a unique new app, and installs it again rather than upgrading. Thus, the user will then have the app twice in the Apps pane, one in an outdated version, and one in the new version.
We have been unable to find an explanation for this in the MATLAB documentation nor online. When we install the updated app (so that both versions are present in the Apps pane), further changing it will upgrade it as expected, so unfortunately, we cannot provide a minimal working example, as we cannot reproduce the issue.
The question is this: How does MATLAB establish app uniqueness? The app name and author fields are identical to the original values, and the version number is incremented, so why might MATLAB not recognize that the app is already installed?
When you had that discontinuity, were you re-packaging using the original .prj file by clicking on it in the file browser in Matlab, or did you run "Package App" again and fill in the same properties?
I think the thing that determines the unique identity of the app is a GUID that is generated behind the scenes by the "Package App" wizard. If you open an existing .prj in the Matlab GUI, it re-uses that GUID. If you run "Package App" again you'll get a fresh GUID regardless of what you put in for the various developer-visible app properties.
You can dig around in the .prj and .mlappinstall files to see this yourself. (I couldn't find it documented anywhere either; I just poked around the files and did some trial and error.) The .prj is just XML, and the .mlappinstall file is a zip file with an "Open Packaging Convention" layout. In the .prj, there's a param.guid element containing the GUID. In the .mlappinstall, its in metadata/appProperties.xml in a GUID element.
If you end up with the same problem again, make sure to re-package using the existing .prj file. Or if you don't have it, once you create your new .prj file, dig the old GUID out of the metadata/appProperties.xml from the old .mlappinstall file and copy it in to your new .prj file and I think it'll behave as the "same" app. This will even let you change the name and contact info for your app, and it'll still install on top of older versions.

Windows installer is too clever, tries to repair when tester deletes config file

Our application is deployed to the target machine with an msi file. All works nicely. Our tester has gone through his plan, and one of the tests requires deleting the application's configuration file. The application is designed to alert the user with a dialog on startup saying "missing config". However, what happens is that - somehow! - the software starts the installer again and retrieves the missing file from the msi! Which is nice, but not what we want. How do we disable that behaviour?
without going into much depth of the windows installer mechanics (if you interested in that there a plenty of articles about this), the shortcut of the software is probably advertised, which means the windows installer checks if everything is in its place before the software is started.
if you can edit the msi, make the shortcut non advertised.
if you can't, install it with DISABLEADVTSHORTCUTS
e.g. msiexec /i myMsi.msi DISABLEADVTSHORTCUTS=1
please note that this is only a quick (and dirty) workaround,
to fix this proper you need to understand the whole windows installer advertising (also called repair or self resiliency) mechanism.
but explaining all the causes and the mechanism of the repair is far beyond this answer and there are quite some articles and posts about that on the internet (and especially on MSDN and stackoverflow)
There is a more correct answer to this, and it is NOT DISABLEADVTSHORTCUTS. You set the component id to null in the MSI file to prevent repair of that individual file. See ComponentId comments here:
http://msdn.microsoft.com/en-us/library/aa368007(v=vs.85).aspx
Edit the MSI file with Orca to delete the Componenty ID, and write an uninstall custom action to delete the file at uninstall if it's there.
In addition, that's a redundant test. Windows will restore that file for you if it's missing, so the idea that you need a test to notify that it's missing is pointless. The true test should be that Windows will restore the file if it's lost, and your app needs to do potentially nothing about the missing file.
You don't mention what tool you are using to make your MSI but I'm going to go out on a limb and guess Visual Studio Deployment Projects (.VDRPOJ).
One of the (many) horrible things about this tool was that it fails to expose the foundational concept of components. Instead it makes every file a key file of it's own component and hides the existence of the component from you. I say 'was' because Microsoft killed this project type in VS. There are around 50k people complaining on UserVoice to bring this tool back and I'm guessing that 49,990 of them don't know what a key path is.
Windows Installer has a concept called the component rules and each component has a keypath. The keypath teaches MSI how to handle repair scenarios. But your tool has to allow you to be able to control this to make it work.
Windows Installer is functioning exactly the way it's supposed to function. You just aren't up to speed on what that is.
However, if you want to ignore Windows Installer best practices and continue using the tool you use today, the trick is to install the app.config file as a different file. Then have the application copy the file to the real file name on run. Windows Installer won't service what it didn't install.
Several answers have been provided that can work:
You can install the file with a blank guid. Then you need to remove it on uninstall using the RemoveFile feature. You will also run into issues if you want to replace it during an upgrade. Could be tricky at times.
You can disable the advertised shortcut(s), but this affects too much in my opinion.
Finally you can use my suggestion to install a separate non-advertised shortcut to use to launch the application. Such a shortcut bypasses the self-repair check. It may still be invoked by other means such as missing file associations, COM registration or similar, but those are exception states.
However, my preference is that an application can start without a config file present, if at all possible. I always suggest a good startup routine with "internal defaults" available. The startup routine should also degrade gracefully if faced with any file system access denied conditions.
Most importantly you should place this config file in the userprofile so you can generate the file on first launch for the user in question. It can even be copied from a read-only copy in the main installation directory.
When you generate a file from internal defaults and put it in a userprofile location, the file will have no interference with Windows Installer at all. The issues that results is how to clean up user data on uninstall. I discussed this with Stefan Kruger (MSI MVP) at one point, and I agree with his notion that user data is indeed user data and should not be automatically dealt with by your installer at all. Leave it installed, and clean it up via system administrator tools if necessary - for example logon scripts.

Where should a WinForm app keep its logs?

I am working on a WinForm application, that allows working to work with "projects" (think about the application as Visual Studio, and projects as VS Solutions).
My question is - where should the application keep its logging files?
Some requirements include:
the application might not be running as an administrator (so saving in the %ProgramFiles% installation folder is not a good option)
The logs should be accessible to end-users (either for review, or for sending to the support team). (This means that hard to find folders, like %AppData%\Company\Application\Version\ProjectName... are not a good solution either)
The application might generate logs even when there are no open projects (so saving the logs in the project's folder is good only when there's a project, but not a final solution).
I was thinking of creating a "working folder" when the application is installed - something along the lines of C:\Application\, and then save the logs in a subfolder, like %WorkingFolder%\Logs\ProjectName
Thanks for the input.
Somewhere in the user's directory is actually the correct place to store them if they are specific to the current running user.
Some programs create folders at the top level of the User's directory, next to Documents and Desktop, others do it in Documents.
Creating it in C:\ might cause issues if the user doesn't have write access to the root directory. You can pretty much guarantee the user will have write access to the Home directory.
The other option is to look for an environment variable, and if its set use the value as the location, if not default to the User's home directory.
If the logs are user only you should store them at %AppData%\Company\Application Name.
If the logs are shared (any user can see any log) you should store them at:
%ProgramData%\Company\Application Name (for Vista+)
or
%AllUsersProfile%\Application Data\Company\Application Name (for XP-)
As for user access, you can add a shortcut to the start menu to the appropriate location or have a link within the program.
Another option in Vista+ is the Public folder (%Public%) which has links throughout Explorer for easy access to.
Where should I write program data instead of Program Files is a good blog entry by Chris Jackson from Microsoft. While it isn't an "official stance" it holds some excellent information.
You can always ask the user to configure this. Set a default path, maybe the application directory. During installation or while setting up the application you may prompt the user to input the path they want to use for logs. That's fair, right. If they're advanced enough to use logs they're good enough to configure a path too.
What do you plan to do with the logs. Are they technical, of for financial/security audits?
The EventLog is a nice place for technical logs, because you can access it remotely (within the Domain) and it is cleaned up automatically.
The %AppData% is also a good place for technical logs, specially if you are unable to connect to the eventlog. You can find the log files, and you can direct the end-user to them, but they are not "in the face" of the end-user. You can include a "send log to the maker" button to receive them.
For logs that needs be accessed by end-users, the My Documents (or a subfolder) looks good.
You can just to add button / menu item to easy open folder with logs.
Best place fo logs are %AppData%\AppName or %temp%\AppName.
Never use %MyDocs% or %Program Files%.
I'd suggest adding that question to the installer so that the user that installs the software can decide where best to put the logs. Though C:\[AppName\ sounds like a reasonable default for your requirements.
Edit: Just thought off, it would probably be worth warning the user if the select a bad location (in Program Files or in the root of the system drive etc) and if they choose to create a new directory, automatically give that directory correct permissions during the installation.
I think %APPDATA%\YourCompanyName\YourAppName is the preferred location. To overcome your stated objection of this location being hard to find, you could pretty easily and quickly implement a simple support screen in your app to allow the end user the ability to access and email these logs without too much trouble, so that the user will not have to remember or manually navigate to the long path name to get to the logs.
I don't really like the idea of the user being able to set this location via the installer because of possible naming and permission issues.
If the app needs to maintain the log only for the users current logged in timespan, then you could keep it in c:/temp.
Most of my winapps, i leave it there, so automatically it gets deleted once the user logs off..
Ofcourse, this primarily depends on your requirement.

Using Inno Setup to patch an Install Shield Application

Hi I have a problem and I need some direction.
I have an old application that have an install shield installer, for which I don't have the installer scripts. Now I want to do a simple patch for that application using Inno Setup.
I was reading the documentation and if I knew the appId I could just append to the same installation the new files. However I don't now what Id that application have. I tried a simple script using the same name but it didn't work either.
Is it anyway of finding the appId to append to that installation?
Can someone point me in the right direction, or is not possible to do it?
The short answer is no, you cannot create an update package that is 100% seamless to the previous Install Shield package. The reason being, whether you know the AppId or not, InnoSetup appends a _is to the end of any AppId given for adding to the registry. Quite a funky action if you ask me but it's the way of the world and let's not forget you're dealing with a free application. They had their reasoning and it is sound, just doesn't make sense for your needs at this point.
You can always do what I did when faced with the same situation:
Find the AppId of the original installation.
a. Under the Control Panel open Add/Remove Programs.
b. Find your application in the list and make a note of the name.
c. Open RegEdit.
*DISCLAIMER: THIS COULD ADVERSELY AFFECT YOUR SYSTEM SO BE CAREFUL
d. Open the following registry key: HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
e. Click on the first GUID you come to and check the value of DisplayName in the right pane against the name you took note of earlier. If this value matches you've found the AppId - it is the GUID you have selected.
f. Select the next GUID and go back to step 1e until you have a match.
Use this AppId as the AppId you use in InnoSetup but add the word "Update" to your title.
Build and run your installation.
Now you will have two entries in Add/Remove Programs for your application but one is clearly marked update. You've also done the additional leg work to ensure that the AppId is as much a match as possible making it easier for other programs to determine that they're related.
Best of luck in your endeavors!

Getting VB6 to reveal which component doesn't have a design time license installed

I've inherited a VB6 project that I'm trying to "Make".
The build fails on the "Making EXE" step with a licensing error:
License information for this component not found.
You do not have an appropriate license to use this functionality
in the design environment.
How can I figure out which component is missing the license?
The project has about 15 references; a mixture between commercial and Microsoft. I've installed development versions / licenses for all the obvious references - and checked that I can compile their sample apps successfully.
Of the remaining 13 odd references; how I can get more information as to which component is throwing the licensing error?
Any tips / techniques on how to get a more verbose error message would be greatly appreciated!
It's worth trying both the Microsoft fixes - one and two - for this error, in case you've run into one of the known issues.
If that doesn't work, open the form designer for every single form in the VB6 IDE. Look out for an error message box on displaying a form. When this error is displayed, the IDE writes a log file formname.log that gives more information on which control caused the problem.
Create a new, empty application with all the same references
Confirm that you still have the same problem
Delete the second half of the references
If you still have the same problem, then the problem is with the references which remain. Go to 3
If not, then the problem is with the references you deleted. Put them back. Delete one half of those you put back. Go to 2.
Basically, just a binary search, except it's really "binary delete".
All of the links of all of the answers are broken... And, some of us are still trying to either maintain or convert old VB6 applications (or both).
A somewhat useful tool was Process Monitor by Mark Mark Russinovich of Microsoft (it is sourced directly off of Microsoft.com and has been around for years). It allows you to monitor all resources used by the computer system wide, and allows you to filter that down to individual resources, processes, etc.
The useful bit is to start the program, and click the "Filter" button from the toolbar (Ctrl-L). From there, you need to add a rule. Select Path that begins with and that should be to the value "HKCR\Licenses". That is in the HKEY_CLASSES_ROOT section, where the Active-X components licensing information is. These should be set to Include.
Click Ok, and then click Clear on the toolbar (Ctrl-X) to clear all current events to reset the state. Events should already be populating that match that rule.
Then, invoke your build. To cut down on clutter, I used the command:
"C:\Program Files (x86)\Microsoft Visual Studio\VB98\vb6.exe" /make <project file> /outdir <exe dest dir>
Once the compile runs, the build should fail with the same message, but simply open the Process Monitor, and you can see that last key that tried to read and failed. The UUID that says not found is the UUID where the license should reside.
From there, you can:
If your license allows, copy that value from a working PC and install it into the failing PC.
Google that ID, to see if there are instructions on how to obtain the correct
license (such as install it from one of the .REG files from the installation media)
Obtain and install the license some other way
While it doesn't tell you exactly what component corresponds to that UUID, it at least lets you get the specific UUID that is failing, which is further than any of the other current answers can do in their current state.
Try This
http://support.microsoft.com/kb/194751/EN-US
It will fixed VB6.0 Design Time License

Resources