Application icon is blank when started from Process.Start - c#

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!

Related

(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);

Manipulating taskbar right click application menu

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

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!

Creating a shared folder using C#

I've spent the last few days scouring the site looking for an answer to this problem,
i need to create a folder and then make it a shared networked folder, I've tried several different sample code snippets from different sites
http://www.sarampalis.org/articles/dotnet/dotnet0002.shtml (this link is dead)
but none seem to allow the folder to be shared
If anyone could be of help it'd be much aprriciated
If you don't find the real Windows API that does this, and you can settle for a dirty solution, you can do it by executing the command "net share".
For example, like this:
ProcessStartInfo info = new ProcessStartInfo("net", "share MyNewShare=c:\\folder");
info.CreateNoWindow = true;
Process.Start(info);
Note that in any case, in order to create a share you need administrative rights, so your code will have to run elevated if you're running on Win7/Vista with UAC enabled.
I did follow the link that you have in your question.
I have a Win 7 Professional + VS.NET 2010 Professional as my dev environment on my laptop.
I took the code from the article and quickly fired up a devenv and executed the code. The code executed perfectly without any error. When i looked at the created directory you dont see a share icon on the folder but it is indeed shared. How can you check that:
open a command prompt
type "net share" and press enter
you will see that it will list the folder c:\MyTestShare with a share name "My Test Share"
One more way to find out whether it is shared or not is to right click on the folder and look at the sharing tab. Check the Network Path label. It will clearly show the shared path.
Hope this helps you.
Lohith
See
http://www.sarampalis.org/articles/dotnet/dotnet0002.shtml
http://www.codeproject.com/KB/system/Share-Folder-c_.aspx

.NET FileInfo.LastWriteTime & FileInfo.LastAccessTime are wrong

When I call FileInfo(path).LastAccessTime or FileInfo(path).LastWriteTime on a file that is in the process of being written it returns the time that the file was created, not the last time it was written to (ie. now).
Is there a way to get this information?
Edit: To all the responses so far. I hadn't tried Refresh() but that does not do it either. I am returned the time that the file was started to be written to. The same goes for the static method, and creating a new instance of FileInfo.
Codymanix might have the answer, but I'm not running Windows Server (using Windows 7), and I don't know where the setting is to test.
Edit 2: Nobody finds it interesting that this function doesn't seem to work?
The FileInfo values are only loaded once and then cached. To get the current value, call Refresh() before getting a property:
f.Refresh();
t = f.LastAccessTime;
Another way to get the current value is by using the static methods on the File class:
t = File.GetLastAccessTime(path);
Starting in Windows Vista, last access time is not updated by default. This is to improve file system performance. You can find details here:
http://blogs.technet.com/b/filecab/archive/2006/11/07/disabling-last-access-time-in-windows-vista-to-improve-ntfs-performance.aspx
To reenable last access time on the computer, you can run the following command:
fsutil behavior set disablelastaccess 0
As James has pointed out LastAccessTime is not updated.
The LastWriteTime has also undergone a twist since Vista. When the process has the file still open and another process checks the LastWriteTime it will not see the new write time for a long time -- until the process has closed the file.
As a workaround you can open and close the file from your external process. After you have done that you can try to read the LastWriteTime again which is then the up to date value.
File System Tunneling:
If an application implements something like a rolling logger which closes the file and then renames it to a different file name you will also run into issues since the creation time and file size of the "old" file is remembered by the OS although you did create a new file. This includes wrong reports of the file size even if you did recreate log.txt from scratch which is still 0 bytes in size. This feature is called OS File System Tunneling which is still present on Windows 8.1 . An example how to work around this issue check out RollingFlatFileTracelistener from Enterprise Library.
You can see the effects of file system tunneling on your own machine from the cmd shell.
echo test > file1.txt
ren file1.txt file2.txt
Wait one minute
echo test > file1.txt
dir /tc file*.txt
...
05.07.2015 19:26 7 file1.txt
05.07.2015 19:26 7 file2.txt
The file system is a state machine. Keeping states correctly synchronized is hard if you care about performance and correctness.
This strange tunneling syndrome is obviously still used by application which do e.g. autosave a file and move it to a save location and then recreate the file again at the same location. For these applications it makes to sense to give the file a new creation date because it was only copied around. Some installers do also such tricks to move files temporarily to a different location and write the contents back later to get past some file exists check for some install hooks.
Have you tried calling Refresh() just before accessing the property (to avoid getting a cached value)? If that doesn't work, have you looked at what Explorer shows at the same time? If Explorer is showing the wrong information, then it's probably something you can't really address - it might be that the information is only updated when the file handle is closed, for example.
There is a setting in windows which is sometimes set especially on server systems so that modified and accessed times for files are not set for better performance.
From MSDN:
When first called, FileSystemInfo
calls Refresh and returns the
cached information on APIs to get
attributes and so on. On subsequent
calls, you must call Refresh to get
the latest copy of the information.
FileSystemInfo.Refresh()
If you're application is the one doing the writing, I think you are going to have to "touch" the file by setting the LastWriteTime property your self between each buffer of data you write. Some psuedocode:
while(bytesWritten < totalBytes)
{
bytesWritten += br.Write(buffer);
myFileInfo.LastWriteTime = DateTime.Now;
}
I'm not sure how severely this will affect write performance.
Tommy Carlier's answer got me thinking....
A good way to visualise the differences is seperately running the two snippets (I just used LinqPAD) simliar to below while also running sysinternals Process Monitor.
while(true)
File.GetLastAccessTime([file path here]);
and
FileInfo bob = new FileInfo(path);
while(true){
string accessed = bob.LastAccessTime.ToString();
}
If you look at Process Monitor while running the first snippet you will see repeated and constant access attempts to the file for the LinqPAD process. The second snippet will do an initial access of the file, for which you will see activity in process monitor, and then very little afterwards.
However if you go and modify the file (I just opened the text file I was monitoring using FileInfo and added a character and saved) you will see a series of access attempts by the LinqPAD process to the file in process monitor.
This illustrates the non-cached and cached behaviour of the two different approachs respectively.
Will the non-cached approach wear a hole in the hard drive?!
EDIT
I went away feeling all clever over my testing and then used the caching behaviour of FileInfo in my windows service (basically to sit in a loop and say 'Has-file-changed-has-file-changed...' before doing processing)
While this approach worked on my dev box, it did not work in the production environment, ie the process just kept running regardless if the file had changed or not. I ended up changing my approach to checking and just used GetLastAccessTime as part of it. Don't know why it would behave differently on production server....but I am not too concerned at this point.

Categories

Resources