Manipulating taskbar right click application menu - c#

I need to remove Application launch and "Pin this application to taskbar" from the taskbar context menu for an application. Reason is that the application cannot start standalone, it must be fed with information from another application.
Does anyone know how?

According to this post, you can use the Windows API Code Pack but the required classes are internal. The OP said that they copied 50k lines of code to get it working. I'm not sure if it's improved since that post but here's a workaround I just thought of. Since you can only pin EXE files (and shortcuts as per comment) to the taskbar, you could rename your application to a non-exe extension (most non-exe extensions cannot be pinned).
When you want to call it from your other app, rename it to .exe, launch it, then rename it back again. For example:
Process p = new Process();
//fake extension so it can't be drag/dropped to taskbar
string fakeExtensionName = #"C:\MyFile\myProgram.test";
//what it's actually called
string exeExtensionName = #"C:\MyFile\myProgram.exe";
//rename the fake one to the real one
File.Move(fakeExtensionName, exeExtensionName);
p.StartInfo.FileName = exeExtensionName;
//launch the real one
p.Start();
//rename it back to the fake extension
File.Move(exeExtensionName, fakeExtensionName);
Anyone can rename it to an exe if they really wanted to, so your program should assume that a user can launch it directly and handle that scenario, but any file can be pinned to the taskbar by renaming it to an exe so there's no protection around that.

Ok, i found a ugly but easy solution here https://stackoverflow.com/a/3872503/1323570
apparantly the registry HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\FileAssociation\AddRemoveNames contains some words that may not exist in an executable if pinning should be possible.
you can also read more here: http://www.west-wind.com/weblog/posts/2009/Oct/08/Application-that-wont-Pin-to-Taskbar-in-Windows-7
Edit:
Found the way to do it properly:
Add the key:
HKEY_CLASSES_ROOT\Applications\Example.exe\NoStartPage
ref: http://msdn.microsoft.com/en-us/library/windows/desktop/hh127439(v=vs.85).aspx

Related

Application icon is blank when started from Process.Start

FileInfo fi = new FileInfo(fileToExcecute);
Directory.SetCurrentDirectory(fi.DirectoryName);
ProcessStartInfo pInfo = new ProcessStartInfo();
pInfo.FileName = fileToExcecute;
pInfo.RedirectStandardOutput = false;
pInfo.RedirectStandardError = false;
pInfo.CreateNoWindow = false;
pInfo.UseShellExecute = true;
pInfo.WorkingDirectory = fi.DirectoryName;
if (runas)
pInfo.Verb = "runas";
pInfo.WindowStyle = ProcessWindowStyle.Normal;
Process p = Process.Start(pInfo);
The application icon is missing from the taskbar. It's just a blank square!
The above code works fine for several projects however fails with one specific program - lets call it projectX.exe. I have re-written the Main as well as startup methods of projectX.exe so that they mimic another project that displays its icon fine.
I have tried for days to discover why but have failed dismally. I have tried various ideas including changing the icon, changing it at runtime, as well as toggling whether it should be displayed or not.
If I require that projectX.exe be run as administrator, the icon displays fine but that option is not available to my clients.
Edit 20 Oct 2017
If I change the name of 'projectX.exe' to something else for example 'test.exe', then the icon shows OK in the taskbar. Where are the icons for a program stored in the registry?
Edit 22nd October 2017
After refreshing the icons as suggested, when running the program from File Explorer or creating a shortcut, the icon is no longer displayed in the taskbar.
Edit 12th November 2017
Running the program 'As Administrator', the icon displays in the taskbar as expected.
If I change the name of 'projectX.exe' to something else ... then the icon shows OK.
This is definitely an icon cache induced problem. It is not very clear why resetting it did not help to solve this problem, but it looks like you did it by hand and that has ways of not panning out correctly.
Some background. This problem is pretty common on a dev machine, programmers tend to take care of the chrome only after getting their program debugged and tested. Explorer got to see their program.exe file with the wrong icon and copied that into its cache. Changing the .exe does not force it to refresh the cached copy, arguably a bug. The cache is otherwise pretty important for Explorer, digging the icons out of the files on a folder view full of files can take any easy handful of seconds on a spindle drive.
The cache is stored in a file, not the registry. You'll find it back in c:\users\yourname\appdata\local\iconcache.db, beware that it is a hidden file. Windows 8 and up use a much fancier caching scheme with multiple icon*.db files, stored in the c:\users\yourname\appdata\local\microsoft\windows\explorer directory.
Deleting these files is enough to force Explorer to re-create them. But that doesn't necessarily come a good end, you can only be 100% sure that Explorer creates a fresh copy by terminating it before you delete the files. And other processes may have a lock on these files if they have the cache file open while you are doing this, typically because they have a shell extension loaded.
I think the best way to reset the cache is by using Ramesh Srinivasan's cleariconcache.vbs script, available from this web page. His VBScript code looks convincingly right, taking care of all the corner-cases and dutifully reporting failure. Close all running programs to give it maximum odds for success.
The issue is very hard to diagnose without a full understanding of your environment.
This does however sound like it could well be an operating system issue rather than a problem with your code.
One option might be to programatically clear the icon cache whilst restarting explorer.exe the following code should do this:
foreach (Process exe in Process.GetProcesses())
{
if (exe.ProcessName.StartsWith("iexplore"))
exe.Kill();
}
// clear icon cache
strCmdText= "del %userprofile%\appdata\local\iconcache.db /a ";
Process.Start("CMD.exe",strCmdText);
Process.Start("explorer.exe");
}
Your icon should hopefully be visible now.
We had the exact same issue, but in our case it turns out our icon was too big (in kb). Once we made it smaller in kb, the issue was resolved!

(How to) Use Windows file explorer to find an application?

I would like to open programmaticaly an application.
First i used System.Diagnostics.Process.Start(#"C:\Program Files (x86)\Program1.exe") works fine, but the application always needs to be on the same path (not always true because different computer)
And a simple way to find it (with mouse & click, not programmaticaly though) is to use the windows file explorer, i enter the title of my application and i find it instantly.
I would like to code that.
I thought i could use the keyboard shortcut "Home + F" and simulate the word with SendKeys.Send("blabla") but the "Home key" doesn't seem to exist with c# (at least not here https://msdn.microsoft.com/fr-fr/library/ms127847(v=vs.110).aspx)
It's a little program for children i can't expect them to find manually the path (so forget the OpenFileDialog..)
Maybe thats a very bad idea and there are another solution to find a program without knowing his path, i don't know have you got better idea?!
You're trying to solve the problem the wrong way. What you're trying to "program" is the setting oft the working directory when the program is run using Explorer. The right way to do that is to use Process.Start by passing it all of the necessary info to start the process:
var startInfo = new ProcessStartInfo("Program1.exe");
startInfo.WorkingDirectory = #"C:\Program Files (x86)\";
Process proc = Process.Start(startInfo);

Opening particular version of Flash by process.start()

I am using the following code to open flash:
private Process flash = new Process();
flash.StartInfo.FileName = ("Flash.exe");
flash.Start();
The target machine has many version of flash like flash cs5,4,3. I want to open the newest version or let the user choose, how can I possibly do that?
Typically speaking, all other flash installations would be in different program folders, so you would just need to make sure you're running Flash.exe from the right folder. For instance, my current installation lies here: C:\Program Files (x86)\Adobe\Adobe Flash CS5\Flash.exe, but an alternate one could very well be in C:\Program Files (x86)\Adobe\Adobe Flash CS4\Flash.exe`.
An important thing to notice is that you can't assume the user installed flash CS* in its default directory! You should always query the Windows registry to find the list of installed products.
Also, another notice would be that you don't need parentheses around string literals. So you can just write:
string foo = "Hello!";
instead of
string foo = ("Hello!");
Edit 1:
Hey, I found a similar problem being treated in a forum thread here! I downloaded the code sample and ran it through a vb.net -> C# converter (like this one) and got it to work after a few minor syntax tweaks. Now it's able to output a list of the installed programs with their appropriate version numbers.
There will be a bunch of methods that get programs form e.g. certain users. All of these will then be placed in a common list, returned to the user. Now, this seems perfect, but there is just one flaw - no path is available... so far!
You can just query the UninstallString, and get a path to the uninstaller (which is IIRC in the same folder as Flash.exe). For instance, in GetUninstallKeyPrograms, after the
try
{
IsSystemComponent = Convert.ToInt32(CurrentSubKey.GetValue("SystemComponent", 0));
}
snippet, you can try to get the UninstallString value in order to obtain the path. Hope it helps!

How to execute an event of already launched application with file association?

After playing around with a new Windows Form project, I discovered that when you associate a file type with an executable in Windows, you can find the file path of the file that launched the application using args[0] from static void Main(string[] args)
Is it possible to launch an event on your application when you double click a file if your application is already open? (As obviously Main(string[] args) won't be triggered).
Example of an application with behavior I am attempting to replicate:
User Opens GIMP(in Windows)
User opens explorer and right clicks a .png file
User selects open with GIMP
Instead of creating a new application instance of GIMP, GIMP opens the picture in a new window within the instance of GIMP that was already opened.
In this case is GIMP employing multiple applications to accept files "opened" with file association? Or is it possible to do it with a single application "instance".
I'm having trouble with this as most of my searches tend to lead me towards file association as a Windows user (i.e. "How to associate .xls files with excel" articles).
There are a variety of options, but none of them come for free.
Your program's Main() can detect that there is another copy already running and hand the file name off to the already-running copy by some means you determine.
Your program can register as a DDE server and request that subsequent opens be performed via DDE. This is an old-fashioned technique from the 1990's that is generally not recommended for new programs.
You can register a custom drop target for your application, and have the drop target hand the file name to the already-running copy. This mechanism takes the form of a shell extension, and therefore is not suitable for C# due to CLR injection issues.
Given your constraints, option (1) appears to be the best option.
Raymond is right of course, but if you're looking for help with the implmentation of option (1) you should probably look at What is the correct way to create a single instance application? and .NET 4 single application instance and Switch to other instance of same application
You'll notice that detecting the application is pretty easy (use a mutex). Bringing the other application and sending it a filename can be more challenging.
There are three basic solutions presented in the answers to the previously linked questions
Use PostMessage to send a message to 1st instance. This uses HWND_BROADCAST which can have untended consequences.
Use Microsoft.VisualBasic.ApplicationServices.ApplicationBase Of course a reference to VisualBasic gives some C# devs the willies.
Use FindWindow which relies on a Windows Name.
Its also worth noting that if you want the existing application to be in the front you'll need to take special care because setting the foreground can only be given away not taken. See Foreground activation permission is like love: You can't steal it, it has to be given to you and AllowSetForegroundWindow and SetForegroundWindow
Microsoft created this functionality for Visual Basic .Net, and it can be used by C# too.
See the following post for a simple example in C#:
http://www.openwinforms.com/single_instance_application.html
This approach worked best for me: Enforcing Single Instance WPF Applications.
Especially, its solution for passing arguments also works in notify-icon only applications.

Forcing Winforms install to make application to start when windows starts

How do I force a windows application, with a setup project being added to it, to install so that it will start everytime someone logs into windows?
Edit: I'm aware of the registry settings, but specifically, I am looking for a solution which will allow for the installer to set the registry values.
Open your registry and find the key
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run].
For each program you want to start automatically create a new string value using a descriptive name, and set the value of the string to the program executable.
For example, to automatically start Notepad, add a new entry of
"Notepad"="c:\windows\notepad.exe".
Remove a startup application
If you're trying to remove a program and can not find it in the StartUp folder (usually C:\WINDOWS\Start Menu\Programs\StartUp), then it may be launching from one of the registry keys below. To remove it, delete the value associated with the program you want to remove.
[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run]
[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnce]
[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunServices]
[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunServicesOnce]
[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\Userinit]
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run]
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce]
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunServices]
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunServicesOnce]
[HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows]
Source: http://www.pctools.com/guides/registry/detail/109/
If you really need your application to start when Windows is started as opposed to when someone logs in you need to create it as service and on install set the service to "Automatic".
There are many places on the web that will give you information about this:
Microsoft Support Knowledge Base
Developer.com
C# Corner
are the first three I found, but do some research and find the resource that works for you.
UPDATE
I see from the updated question that the requirement is for the program to run when someone logs in so this answer is (to a certain degree) redundant. However, I will leave it here in case someone wants to go the service root.
You can add a shortcut to your winforms program in the Startup Folder. The setup project's File System is where you need to look.
Technically you can't make a WinForms app start when "windows is started"; however, you can start it when someone logs into Windows. To perform that you do one of the three:
Place a shortcut in the current user's startup folder.
Place a shortcut in the the "All Users" startup folder.
Write a registry key to HKLM/Software/Microsoft/Windows/CurrentVersion/Run
Update: as Chris points out I missed the HKCU path.
To run everytime Windows starts you should build your program as a Windows Service (or perhaps lauch it from a Service).

Categories

Resources